1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrResourceProvider.h"
9 #include "../private/GrSingleOwner.h"
10 #include "GrBackendSemaphore.h"
11 #include "GrCaps.h"
12 #include "GrContext.h"
13 #include "GrContextPriv.h"
14 #include "GrGpu.h"
15 #include "GrGpuBuffer.h"
16 #include "GrPath.h"
17 #include "GrPathRendering.h"
18 #include "GrProxyProvider.h"
19 #include "GrRenderTargetPriv.h"
20 #include "GrResourceCache.h"
21 #include "GrResourceKey.h"
22 #include "GrSemaphore.h"
23 #include "GrStencilAttachment.h"
24 #include "GrTexturePriv.h"
25 #include "SkGr.h"
26 #include "SkMathPriv.h"
27 
28 const uint32_t GrResourceProvider::kMinScratchTextureSize = 16;
29 
30 #define ASSERT_SINGLE_OWNER \
31     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
32 
GrResourceProvider(GrGpu * gpu,GrResourceCache * cache,GrSingleOwner * owner,bool explicitlyAllocateGPUResources)33 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner,
34                                        bool explicitlyAllocateGPUResources)
35         : fCache(cache)
36         , fGpu(gpu)
37         , fExplicitlyAllocateGPUResources(explicitlyAllocateGPUResources)
38 #ifdef SK_DEBUG
39         , fSingleOwner(owner)
40 #endif
41 {
42     fCaps = sk_ref_sp(fGpu->caps());
43 }
44 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel texels[],int mipLevelCount)45 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
46                                                    const GrMipLevel texels[], int mipLevelCount) {
47     ASSERT_SINGLE_OWNER
48 
49     SkASSERT(mipLevelCount > 0);
50 
51     if (this->isAbandoned()) {
52         return nullptr;
53     }
54 
55     GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
56     if (!fCaps->validateSurfaceDesc(desc, mipMapped)) {
57         return nullptr;
58     }
59 
60     return fGpu->createTexture(desc, budgeted, texels, mipLevelCount);
61 }
62 
getExactScratch(const GrSurfaceDesc & desc,SkBudgeted budgeted,Flags flags)63 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc,
64                                                      SkBudgeted budgeted, Flags flags) {
65     sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags));
66     if (tex && SkBudgeted::kNo == budgeted) {
67         tex->resourcePriv().makeUnbudgeted();
68     }
69 
70     return tex;
71 }
72 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,SkBackingFit fit,const GrMipLevel & mipLevel,Flags flags)73 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
74                                                    SkBudgeted budgeted,
75                                                    SkBackingFit fit,
76                                                    const GrMipLevel& mipLevel,
77                                                    Flags flags) {
78     ASSERT_SINGLE_OWNER
79 
80     if (this->isAbandoned()) {
81         return nullptr;
82     }
83 
84     if (!mipLevel.fPixels) {
85         return nullptr;
86     }
87 
88     if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
89         return nullptr;
90     }
91 
92     GrContext* context = fGpu->getContext();
93     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
94 
95     SkColorType colorType;
96     if (GrPixelConfigToColorType(desc.fConfig, &colorType)) {
97         sk_sp<GrTexture> tex = (SkBackingFit::kApprox == fit)
98                 ? this->createApproxTexture(desc, flags)
99                 : this->createTexture(desc, budgeted, flags);
100         if (!tex) {
101             return nullptr;
102         }
103 
104         sk_sp<GrTextureProxy> proxy = proxyProvider->createWrapped(std::move(tex),
105                                                                    kTopLeft_GrSurfaceOrigin);
106         if (!proxy) {
107             return nullptr;
108         }
109         auto srcInfo = SkImageInfo::Make(desc.fWidth, desc.fHeight, colorType,
110                                          kUnknown_SkAlphaType);
111         sk_sp<GrSurfaceContext> sContext = context->priv().makeWrappedSurfaceContext(
112                 std::move(proxy));
113         if (!sContext) {
114             return nullptr;
115         }
116         SkAssertResult(sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0));
117         return sk_ref_sp(sContext->asTextureProxy()->peekTexture());
118     } else {
119         return fGpu->createTexture(desc, budgeted, &mipLevel, 1);
120     }
121 }
122 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,Flags flags)123 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
124                                                    Flags flags) {
125     ASSERT_SINGLE_OWNER
126     if (this->isAbandoned()) {
127         return nullptr;
128     }
129 
130     if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
131         return nullptr;
132     }
133 
134     // Compressed textures are read-only so they don't support re-use for scratch.
135     if (!GrPixelConfigIsCompressed(desc.fConfig)) {
136         sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags);
137         if (tex) {
138             return tex;
139         }
140     }
141 
142     return fGpu->createTexture(desc, budgeted);
143 }
144 
createApproxTexture(const GrSurfaceDesc & desc,Flags flags)145 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc,
146                                                          Flags flags) {
147     ASSERT_SINGLE_OWNER
148     SkASSERT(Flags::kNone == flags || Flags::kNoPendingIO == flags);
149 
150     if (this->isAbandoned()) {
151         return nullptr;
152     }
153 
154     // Currently we don't recycle compressed textures as scratch.
155     if (GrPixelConfigIsCompressed(desc.fConfig)) {
156         return nullptr;
157     }
158 
159     if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
160         return nullptr;
161     }
162 
163     if (auto tex = this->refScratchTexture(desc, flags)) {
164         return tex;
165     }
166 
167     SkTCopyOnFirstWrite<GrSurfaceDesc> copyDesc(desc);
168 
169     // bin by pow2 with a reasonable min
170     if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
171         (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
172         GrSurfaceDesc* wdesc = copyDesc.writable();
173         wdesc->fWidth  = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fWidth));
174         wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fHeight));
175     }
176 
177     if (auto tex = this->refScratchTexture(*copyDesc, flags)) {
178         return tex;
179     }
180 
181     return fGpu->createTexture(*copyDesc, SkBudgeted::kYes);
182 }
183 
refScratchTexture(const GrSurfaceDesc & desc,Flags flags)184 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc, Flags flags) {
185     ASSERT_SINGLE_OWNER
186     SkASSERT(!this->isAbandoned());
187     SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
188     SkASSERT(fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo));
189 
190     // We could make initial clears work with scratch textures but it is a rare case so we just opt
191     // to fall back to making a new texture.
192     if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
193         (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
194 
195         GrScratchKey key;
196         GrTexturePriv::ComputeScratchKey(desc, &key);
197         auto scratchFlags = GrResourceCache::ScratchFlags::kNone;
198         if (Flags::kNoPendingIO & flags) {
199             scratchFlags |= GrResourceCache::ScratchFlags::kRequireNoPendingIO;
200         } else  if (!(desc.fFlags & kRenderTarget_GrSurfaceFlag)) {
201             // If it is not a render target then it will most likely be populated by
202             // writePixels() which will trigger a flush if the texture has pending IO.
203             scratchFlags |= GrResourceCache::ScratchFlags::kPreferNoPendingIO;
204         }
205         GrGpuResource* resource = fCache->findAndRefScratchResource(key,
206                                                                     GrSurface::WorstCaseSize(desc),
207                                                                     scratchFlags);
208         if (resource) {
209             GrSurface* surface = static_cast<GrSurface*>(resource);
210             return sk_sp<GrTexture>(surface->asTexture());
211         }
212     }
213 
214     return nullptr;
215 }
216 
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)217 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
218                                                         GrWrapOwnership ownership,
219                                                         GrWrapCacheable cacheable,
220                                                         GrIOType ioType) {
221     ASSERT_SINGLE_OWNER
222     if (this->isAbandoned()) {
223         return nullptr;
224     }
225     return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType);
226 }
227 
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)228 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
229                                                                   int sampleCnt,
230                                                                   GrWrapOwnership ownership,
231                                                                   GrWrapCacheable cacheable) {
232     ASSERT_SINGLE_OWNER
233     if (this->isAbandoned()) {
234         return nullptr;
235     }
236     return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable);
237 }
238 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)239 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
240         const GrBackendRenderTarget& backendRT)
241 {
242     ASSERT_SINGLE_OWNER
243     return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
244 }
245 
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)246 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
247         const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
248     ASSERT_SINGLE_OWNER
249     return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
250                                                                                      vkInfo);
251 
252 }
253 
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)254 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
255                                                    GrGpuResource* resource) {
256     ASSERT_SINGLE_OWNER
257     if (this->isAbandoned() || !resource) {
258         return;
259     }
260     resource->resourcePriv().setUniqueKey(key);
261 }
262 
findResourceByUniqueKey(const GrUniqueKey & key)263 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
264     ASSERT_SINGLE_OWNER
265     return this->isAbandoned() ? nullptr
266                                : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
267 }
268 
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)269 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
270                                                                     size_t size,
271                                                                     const void* data,
272                                                                     const GrUniqueKey& key) {
273     if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
274         return std::move(buffer);
275     }
276     if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
277         // We shouldn't bin and/or cache static buffers.
278         SkASSERT(buffer->size() == size);
279         SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
280         SkASSERT(!buffer->resourcePriv().hasPendingIO_debugOnly());
281         buffer->resourcePriv().setUniqueKey(key);
282         return sk_sp<const GrGpuBuffer>(buffer);
283     }
284     return nullptr;
285 }
286 
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey * key)287 sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
288                                                                         int patternSize,
289                                                                         int reps,
290                                                                         int vertCount,
291                                                                         const GrUniqueKey* key) {
292     size_t bufferSize = patternSize * reps * sizeof(uint16_t);
293 
294     // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO.
295     sk_sp<GrGpuBuffer> buffer(
296             this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
297     if (!buffer) {
298         return nullptr;
299     }
300     uint16_t* data = (uint16_t*) buffer->map();
301     SkAutoTArray<uint16_t> temp;
302     if (!data) {
303         temp.reset(reps * patternSize);
304         data = temp.get();
305     }
306     for (int i = 0; i < reps; ++i) {
307         int baseIdx = i * patternSize;
308         uint16_t baseVert = (uint16_t)(i * vertCount);
309         for (int j = 0; j < patternSize; ++j) {
310             data[baseIdx+j] = baseVert + pattern[j];
311         }
312     }
313     if (temp.get()) {
314         if (!buffer->updateData(data, bufferSize)) {
315             return nullptr;
316         }
317     } else {
318         buffer->unmap();
319     }
320     if (key) {
321         SkASSERT(key->isValid());
322         this->assignUniqueKeyToResource(*key, buffer.get());
323     }
324     return std::move(buffer);
325 }
326 
327 static constexpr int kMaxQuads = 1 << 12;  // max possible: (1 << 14) - 1;
328 
createQuadIndexBuffer()329 sk_sp<const GrGpuBuffer> GrResourceProvider::createQuadIndexBuffer() {
330     GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
331     static const uint16_t kPattern[] = { 0, 1, 2, 2, 1, 3 };
332     return this->createPatternedIndexBuffer(kPattern, 6, kMaxQuads, 4, nullptr);
333 }
334 
QuadCountOfQuadBuffer()335 int GrResourceProvider::QuadCountOfQuadBuffer() { return kMaxQuads; }
336 
createPath(const SkPath & path,const GrStyle & style)337 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
338     if (this->isAbandoned()) {
339         return nullptr;
340     }
341 
342     SkASSERT(this->gpu()->pathRendering());
343     return this->gpu()->pathRendering()->createPath(path, style);
344 }
345 
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)346 sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
347                                                     GrAccessPattern accessPattern,
348                                                     const void* data) {
349     if (this->isAbandoned()) {
350         return nullptr;
351     }
352     if (kDynamic_GrAccessPattern != accessPattern) {
353         return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
354     }
355     // bin by pow2 with a reasonable min
356     static const size_t MIN_SIZE = 1 << 12;
357     size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
358 
359     GrScratchKey key;
360     GrGpuBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
361     auto buffer =
362             sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
363                     key, allocSize, GrResourceCache::ScratchFlags::kNone)));
364     if (!buffer) {
365         buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
366         if (!buffer) {
367             return nullptr;
368         }
369     }
370     if (data) {
371         buffer->updateData(data, size);
372     }
373     return buffer;
374 }
375 
attachStencilAttachment(GrRenderTarget * rt)376 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
377     SkASSERT(rt);
378     if (rt->renderTargetPriv().getStencilAttachment()) {
379         return true;
380     }
381 
382     if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
383         GrUniqueKey sbKey;
384 
385         int width = rt->width();
386         int height = rt->height();
387 #if 0
388         if (this->caps()->oversizedStencilSupport()) {
389             width  = SkNextPow2(width);
390             height = SkNextPow2(height);
391         }
392 #endif
393         GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
394                                                                rt->numStencilSamples(), &sbKey);
395         auto stencil = this->findByUniqueKey<GrStencilAttachment>(sbKey);
396         if (!stencil) {
397             // Need to try and create a new stencil
398             stencil.reset(this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height));
399             if (!stencil) {
400                 return false;
401             }
402             this->assignUniqueKeyToResource(sbKey, stencil.get());
403         }
404         rt->renderTargetPriv().attachStencilAttachment(std::move(stencil));
405     }
406     return SkToBool(rt->renderTargetPriv().getStencilAttachment());
407 }
408 
wrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,int sampleCnt)409 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
410         const GrBackendTexture& tex, int sampleCnt)
411 {
412     if (this->isAbandoned()) {
413         return nullptr;
414     }
415     return fGpu->wrapBackendTextureAsRenderTarget(tex, sampleCnt);
416 }
417 
makeSemaphore(bool isOwned)418 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) {
419     return fGpu->makeSemaphore(isOwned);
420 }
421 
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)422 sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
423                                                             SemaphoreWrapType wrapType,
424                                                             GrWrapOwnership ownership) {
425     ASSERT_SINGLE_OWNER
426     return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
427                                                                       wrapType,
428                                                                       ownership);
429 }
430