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