• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
10 #include "GrBackendSemaphore.h"
11 #include "GrBuffer.h"
12 #include "GrCaps.h"
13 #include "GrContext.h"
14 #include "GrContextPriv.h"
15 #include "GrGpu.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 "../private/GrSingleOwner.h"
26 #include "SkGr.h"
27 #include "SkMathPriv.h"
28 
29 GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
30 
31 const uint32_t GrResourceProvider::kMinScratchTextureSize = 16;
32 
33 #define ASSERT_SINGLE_OWNER \
34     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
35 
GrResourceProvider(GrGpu * gpu,GrResourceCache * cache,GrSingleOwner * owner)36 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner)
37         : fCache(cache)
38         , fGpu(gpu)
39 #ifdef SK_DEBUG
40         , fSingleOwner(owner)
41 #endif
42         {
43     fCaps = sk_ref_sp(fGpu->caps());
44 
45     GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
46     fQuadIndexBufferKey = gQuadIndexBufferKey;
47 }
48 
validate_desc(const GrSurfaceDesc & desc,const GrCaps & caps,int levelCount=0)49 bool validate_desc(const GrSurfaceDesc& desc, const GrCaps& caps, int levelCount = 0) {
50     if (desc.fSampleCnt < 1) {
51         return false;
52     }
53 
54     if (desc.fWidth <= 0 || desc.fHeight <= 0) {
55         return false;
56     }
57     if (!caps.isConfigTexturable(desc.fConfig)) {
58         return false;
59     }
60     if (desc.fFlags & kRenderTarget_GrSurfaceFlag) {
61         if (!caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 1)) {
62             return false;
63         }
64     } else {
65         if (desc.fSampleCnt > 1) {
66             return false;
67         }
68     }
69     if (levelCount > 1 && (GrPixelConfigIsSint(desc.fConfig) || !caps.mipMapSupport())) {
70         return false;
71     }
72     return true;
73 }
74 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel texels[],int mipLevelCount,SkDestinationSurfaceColorMode mipColorMode)75 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
76                                                    const GrMipLevel texels[], int mipLevelCount,
77                                                    SkDestinationSurfaceColorMode mipColorMode) {
78     ASSERT_SINGLE_OWNER
79 
80     SkASSERT(mipLevelCount > 0);
81 
82     if (this->isAbandoned()) {
83         return nullptr;
84     }
85 
86     if (!validate_desc(desc, *fCaps, mipLevelCount)) {
87         return nullptr;
88     }
89 
90     sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted, texels, mipLevelCount));
91     if (tex) {
92         tex->texturePriv().setMipColorMode(mipColorMode);
93     }
94 
95     return tex;
96 }
97 
getExactScratch(const GrSurfaceDesc & desc,SkBudgeted budgeted,uint32_t flags)98 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc,
99                                                      SkBudgeted budgeted, uint32_t flags) {
100     sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags));
101     if (tex && SkBudgeted::kNo == budgeted) {
102         tex->resourcePriv().makeUnbudgeted();
103     }
104 
105     return tex;
106 }
107 
make_info(int w,int h,GrPixelConfig config,SkImageInfo * ii)108 static bool make_info(int w, int h, GrPixelConfig config, SkImageInfo* ii) {
109     SkColorType colorType;
110     if (!GrPixelConfigToColorType(config, &colorType)) {
111         return false;
112     }
113 
114     *ii = SkImageInfo::Make(w, h, colorType, kUnknown_SkAlphaType, nullptr);
115     return true;
116 }
117 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel & mipLevel)118 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
119                                                    SkBudgeted budgeted,
120                                                    const GrMipLevel& mipLevel) {
121     ASSERT_SINGLE_OWNER
122 
123     if (this->isAbandoned()) {
124         return nullptr;
125     }
126 
127     if (!mipLevel.fPixels) {
128         return nullptr;
129     }
130 
131     if (!validate_desc(desc, *fCaps)) {
132         return nullptr;
133     }
134 
135     GrContext* context = fGpu->getContext();
136     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
137 
138     SkImageInfo srcInfo;
139 
140     if (make_info(desc.fWidth, desc.fHeight, desc.fConfig, &srcInfo)) {
141         // DDL TODO: remove this use of createInstantiatedProxy and convert it to a testing-only
142         // method.
143         sk_sp<GrTextureProxy> proxy = proxyProvider->createInstantiatedProxy(desc,
144                                                                              SkBackingFit::kExact,
145                                                                              budgeted);
146         if (proxy) {
147             sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext(
148                                                                                 std::move(proxy));
149             if (sContext) {
150                 if (sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0)) {
151                     return sk_ref_sp(sContext->asTextureProxy()->priv().peekTexture());
152                 }
153             }
154         }
155     }
156 
157     return fGpu->createTexture(desc, budgeted, &mipLevel, 1);
158 }
159 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,uint32_t flags)160 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
161                                                    uint32_t flags) {
162     ASSERT_SINGLE_OWNER
163     if (this->isAbandoned()) {
164         return nullptr;
165     }
166 
167     if (!validate_desc(desc, *fCaps)) {
168         return nullptr;
169     }
170 
171     sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags);
172     if (tex) {
173         return tex;
174     }
175 
176     return fGpu->createTexture(desc, budgeted);
177 }
178 
createApproxTexture(const GrSurfaceDesc & desc,uint32_t flags)179 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc,
180                                                          uint32_t flags) {
181     ASSERT_SINGLE_OWNER
182     SkASSERT(0 == flags || kNoPendingIO_Flag == flags);
183 
184     if (this->isAbandoned()) {
185         return nullptr;
186     }
187 
188     if (!validate_desc(desc, *fCaps)) {
189         return nullptr;
190     }
191 
192     if (auto tex = this->refScratchTexture(desc, flags)) {
193         return tex;
194     }
195 
196     SkTCopyOnFirstWrite<GrSurfaceDesc> copyDesc(desc);
197 
198     // bin by pow2 with a reasonable min
199     if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
200         (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
201         GrSurfaceDesc* wdesc = copyDesc.writable();
202         wdesc->fWidth  = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fWidth));
203         wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fHeight));
204     }
205 
206     if (auto tex = this->refScratchTexture(*copyDesc, flags)) {
207         return tex;
208     }
209 
210     return fGpu->createTexture(*copyDesc, SkBudgeted::kYes);
211 }
212 
refScratchTexture(const GrSurfaceDesc & desc,uint32_t flags)213 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc,
214                                                        uint32_t flags) {
215     ASSERT_SINGLE_OWNER
216     SkASSERT(!this->isAbandoned());
217     SkASSERT(validate_desc(desc, *fCaps));
218 
219     // We could make initial clears work with scratch textures but it is a rare case so we just opt
220     // to fall back to making a new texture.
221     if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
222         (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
223 
224         GrScratchKey key;
225         GrTexturePriv::ComputeScratchKey(desc, &key);
226         uint32_t scratchFlags = 0;
227         if (kNoPendingIO_Flag & flags) {
228             scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
229         } else  if (!(desc.fFlags & kRenderTarget_GrSurfaceFlag)) {
230             // If it is not a render target then it will most likely be populated by
231             // writePixels() which will trigger a flush if the texture has pending IO.
232             scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
233         }
234         GrGpuResource* resource = fCache->findAndRefScratchResource(key,
235                                                                     GrSurface::WorstCaseSize(desc),
236                                                                     scratchFlags);
237         if (resource) {
238             GrSurface* surface = static_cast<GrSurface*>(resource);
239             return sk_sp<GrTexture>(surface->asTexture());
240         }
241     }
242 
243     return nullptr;
244 }
245 
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership)246 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
247                                                         GrWrapOwnership ownership) {
248     ASSERT_SINGLE_OWNER
249     if (this->isAbandoned()) {
250         return nullptr;
251     }
252     return fGpu->wrapBackendTexture(tex, ownership);
253 }
254 
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership)255 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
256                                                                   int sampleCnt,
257                                                                   GrWrapOwnership ownership) {
258     ASSERT_SINGLE_OWNER
259     if (this->isAbandoned()) {
260         return nullptr;
261     }
262     return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership);
263 }
264 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)265 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
266         const GrBackendRenderTarget& backendRT)
267 {
268     ASSERT_SINGLE_OWNER
269     return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
270 }
271 
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)272 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
273                                                    GrGpuResource* resource) {
274     ASSERT_SINGLE_OWNER
275     if (this->isAbandoned() || !resource) {
276         return;
277     }
278     resource->resourcePriv().setUniqueKey(key);
279 }
280 
findResourceByUniqueKey(const GrUniqueKey & key)281 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
282     ASSERT_SINGLE_OWNER
283     return this->isAbandoned() ? nullptr
284                                : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
285 }
286 
findOrMakeStaticBuffer(GrBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)287 sk_sp<const GrBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrBufferType intendedType,
288                                                                  size_t size,
289                                                                  const void* data,
290                                                                  const GrUniqueKey& key) {
291     if (auto buffer = this->findByUniqueKey<GrBuffer>(key)) {
292         return buffer;
293     }
294     if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, 0,
295                                          data)) {
296         // We shouldn't bin and/or cachestatic buffers.
297         SkASSERT(buffer->sizeInBytes() == size);
298         SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
299         SkASSERT(!buffer->resourcePriv().hasPendingIO_debugOnly());
300         buffer->resourcePriv().setUniqueKey(key);
301         return sk_sp<const GrBuffer>(buffer);
302     }
303     return nullptr;
304 }
305 
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey & key)306 sk_sp<const GrBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
307                                                                      int patternSize,
308                                                                      int reps,
309                                                                      int vertCount,
310                                                                      const GrUniqueKey& key) {
311     size_t bufferSize = patternSize * reps * sizeof(uint16_t);
312 
313     // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO.
314     sk_sp<GrBuffer> buffer(this->createBuffer(bufferSize, kIndex_GrBufferType,
315                                               kStatic_GrAccessPattern, kNoPendingIO_Flag));
316     if (!buffer) {
317         return nullptr;
318     }
319     uint16_t* data = (uint16_t*) buffer->map();
320     SkAutoTArray<uint16_t> temp;
321     if (!data) {
322         temp.reset(reps * patternSize);
323         data = temp.get();
324     }
325     for (int i = 0; i < reps; ++i) {
326         int baseIdx = i * patternSize;
327         uint16_t baseVert = (uint16_t)(i * vertCount);
328         for (int j = 0; j < patternSize; ++j) {
329             data[baseIdx+j] = baseVert + pattern[j];
330         }
331     }
332     if (temp.get()) {
333         if (!buffer->updateData(data, bufferSize)) {
334             return nullptr;
335         }
336     } else {
337         buffer->unmap();
338     }
339     this->assignUniqueKeyToResource(key, buffer.get());
340     return std::move(buffer);
341 }
342 
343 static constexpr int kMaxQuads = 1 << 12;  // max possible: (1 << 14) - 1;
344 
createQuadIndexBuffer()345 sk_sp<const GrBuffer> GrResourceProvider::createQuadIndexBuffer() {
346     GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
347     static const uint16_t kPattern[] = { 0, 1, 2, 2, 1, 3 };
348     return this->createPatternedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
349 }
350 
QuadCountOfQuadBuffer()351 int GrResourceProvider::QuadCountOfQuadBuffer() { return kMaxQuads; }
352 
createPath(const SkPath & path,const GrStyle & style)353 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
354     if (this->isAbandoned()) {
355         return nullptr;
356     }
357 
358     SkASSERT(this->gpu()->pathRendering());
359     return this->gpu()->pathRendering()->createPath(path, style);
360 }
361 
createPathRange(GrPathRange::PathGenerator * gen,const GrStyle & style)362 sk_sp<GrPathRange> GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
363                                                        const GrStyle& style) {
364     if (this->isAbandoned()) {
365         return nullptr;
366     }
367 
368     SkASSERT(this->gpu()->pathRendering());
369     return this->gpu()->pathRendering()->createPathRange(gen, style);
370 }
371 
createGlyphs(const SkTypeface * tf,const SkScalerContextEffects & effects,const SkDescriptor * desc,const GrStyle & style)372 sk_sp<GrPathRange> GrResourceProvider::createGlyphs(const SkTypeface* tf,
373                                                     const SkScalerContextEffects& effects,
374                                                     const SkDescriptor* desc,
375                                                     const GrStyle& style) {
376 
377     SkASSERT(this->gpu()->pathRendering());
378     return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style);
379 }
380 
createBuffer(size_t size,GrBufferType intendedType,GrAccessPattern accessPattern,uint32_t flags,const void * data)381 GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
382                                            GrAccessPattern accessPattern, uint32_t flags,
383                                            const void* data) {
384     if (this->isAbandoned()) {
385         return nullptr;
386     }
387     if (kDynamic_GrAccessPattern != accessPattern) {
388         return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
389     }
390     if (!(flags & kRequireGpuMemory_Flag) &&
391         this->gpu()->caps()->preferClientSideDynamicBuffers() &&
392         GrBufferTypeIsVertexOrIndex(intendedType) &&
393         kDynamic_GrAccessPattern == accessPattern) {
394         return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data);
395     }
396 
397     // bin by pow2 with a reasonable min
398     static const size_t MIN_SIZE = 1 << 12;
399     size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
400 
401     GrScratchKey key;
402     GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
403     uint32_t scratchFlags = 0;
404     if (flags & kNoPendingIO_Flag) {
405         scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
406     } else {
407         scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
408     }
409     GrBuffer* buffer = static_cast<GrBuffer*>(
410         this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags));
411     if (!buffer) {
412         buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
413         if (!buffer) {
414             return nullptr;
415         }
416     }
417     if (data) {
418         buffer->updateData(data, size);
419     }
420     SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs.
421     return buffer;
422 }
423 
attachStencilAttachment(GrRenderTarget * rt)424 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
425     SkASSERT(rt);
426     if (rt->renderTargetPriv().getStencilAttachment()) {
427         return true;
428     }
429 
430     if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
431         GrUniqueKey sbKey;
432 
433         int width = rt->width();
434         int height = rt->height();
435 #if 0
436         if (this->caps()->oversizedStencilSupport()) {
437             width  = SkNextPow2(width);
438             height = SkNextPow2(height);
439         }
440 #endif
441         SkDEBUGCODE(bool newStencil = false;)
442         GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
443                                                                rt->numStencilSamples(), &sbKey);
444         auto stencil = this->findByUniqueKey<GrStencilAttachment>(sbKey);
445         if (!stencil) {
446             // Need to try and create a new stencil
447             stencil.reset(this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height));
448             if (stencil) {
449                 this->assignUniqueKeyToResource(sbKey, stencil.get());
450                 SkDEBUGCODE(newStencil = true;)
451             }
452         }
453         if (rt->renderTargetPriv().attachStencilAttachment(std::move(stencil))) {
454 #ifdef SK_DEBUG
455             // Fill the SB with an inappropriate value. opLists that use the
456             // SB should clear it properly.
457             if (newStencil) {
458                 SkASSERT(rt->renderTargetPriv().getStencilAttachment()->isDirty());
459                 this->gpu()->clearStencil(rt, 0xFFFF);
460                 SkASSERT(rt->renderTargetPriv().getStencilAttachment()->isDirty());
461             }
462 #endif
463         }
464     }
465     return SkToBool(rt->renderTargetPriv().getStencilAttachment());
466 }
467 
wrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,int sampleCnt)468 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
469         const GrBackendTexture& tex, int sampleCnt)
470 {
471     if (this->isAbandoned()) {
472         return nullptr;
473     }
474     return fGpu->wrapBackendTextureAsRenderTarget(tex, sampleCnt);
475 }
476 
makeSemaphore(bool isOwned)477 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) {
478     return fGpu->makeSemaphore(isOwned);
479 }
480 
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)481 sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
482                                                             SemaphoreWrapType wrapType,
483                                                             GrWrapOwnership ownership) {
484     ASSERT_SINGLE_OWNER
485     return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
486                                                                       wrapType,
487                                                                       ownership);
488 }
489 
takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore)490 void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
491     semaphore->resetGpu(fGpu);
492 }
493 
releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore)494 void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
495     semaphore->resetGpu(nullptr);
496 }
497