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 "GrBuffer.h"
11 #include "GrCaps.h"
12 #include "GrContext.h"
13 #include "GrGpu.h"
14 #include "GrPathRendering.h"
15 #include "GrRenderTarget.h"
16 #include "GrRenderTargetPriv.h"
17 #include "GrResourceCache.h"
18 #include "GrResourceKey.h"
19 #include "GrSemaphore.h"
20 #include "GrStencilAttachment.h"
21 #include "GrSurfaceProxyPriv.h"
22 #include "GrTexturePriv.h"
23 #include "../private/GrSingleOwner.h"
24 #include "SkMathPriv.h"
25 
26 GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
27 
28 const int GrResourceProvider::kMinScratchTextureSize = 16;
29 
30 #define ASSERT_SINGLE_OWNER \
31     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
32 
GrResourceProvider(GrGpu * gpu,GrResourceCache * cache,GrSingleOwner * owner)33 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner)
34         : fCache(cache)
35         , fGpu(gpu)
36 #ifdef SK_DEBUG
37         , fSingleOwner(owner)
38 #endif
39         {
40     fCaps = sk_ref_sp(fGpu->caps());
41 
42     GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
43     fQuadIndexBufferKey = gQuadIndexBufferKey;
44 }
45 
IsFunctionallyExact(GrTextureProxy * proxy)46 bool GrResourceProvider::IsFunctionallyExact(GrTextureProxy* proxy) {
47     return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height()));
48 }
49 
createMipMappedTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel * texels,int mipLevelCount,uint32_t flags,SkDestinationSurfaceColorMode mipColorMode)50 GrTexture* GrResourceProvider::createMipMappedTexture(const GrSurfaceDesc& desc,
51                                                       SkBudgeted budgeted, const GrMipLevel* texels,
52                                                       int mipLevelCount, uint32_t flags,
53                                                       SkDestinationSurfaceColorMode mipColorMode) {
54     ASSERT_SINGLE_OWNER
55 
56     if (this->isAbandoned()) {
57         return nullptr;
58     }
59     if (mipLevelCount && !texels) {
60         return nullptr;
61     }
62     for (int i = 0; i < mipLevelCount; ++i) {
63         if (!texels[i].fPixels) {
64             return nullptr;
65         }
66     }
67     if (mipLevelCount > 1 && GrPixelConfigIsSint(desc.fConfig)) {
68         return nullptr;
69     }
70     if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
71         !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
72         return nullptr;
73     }
74     if (!GrPixelConfigIsCompressed(desc.fConfig)) {
75         if (mipLevelCount < 2) {
76             flags |= kExact_Flag | kNoCreate_Flag;
77             if (GrTexture* texture = this->refScratchTexture(desc, flags)) {
78                 if (!mipLevelCount ||
79                     texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
80                                          texels[0].fPixels, texels[0].fRowBytes)) {
81                     if (SkBudgeted::kNo == budgeted) {
82                         texture->resourcePriv().makeUnbudgeted();
83                     }
84                     texture->texturePriv().setMipColorMode(mipColorMode);
85                     return texture;
86                 }
87                 texture->unref();
88             }
89         }
90     }
91 
92     SkTArray<GrMipLevel> texelsShallowCopy(mipLevelCount);
93     for (int i = 0; i < mipLevelCount; ++i) {
94         texelsShallowCopy.push_back(texels[i]);
95     }
96     GrTexture* texture = fGpu->createTexture(desc, budgeted, texelsShallowCopy);
97     if (texture) {
98         texture->texturePriv().setMipColorMode(mipColorMode);
99     }
100     return texture;
101 }
102 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const void * srcData,size_t rowBytes,uint32_t flags)103 GrTexture* GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
104                                              const void* srcData, size_t rowBytes, uint32_t flags) {
105     GrMipLevel tempTexels;
106     GrMipLevel* texels = nullptr;
107     int levelCount = 0;
108     if (srcData) {
109         tempTexels.fPixels = srcData;
110         tempTexels.fRowBytes = rowBytes;
111         texels = &tempTexels;
112         levelCount = 1;
113     }
114     return this->createMipMappedTexture(desc, budgeted, texels, levelCount, flags);
115 }
116 
createApproxTexture(const GrSurfaceDesc & desc,uint32_t flags)117 GrTexture* GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, uint32_t flags) {
118     ASSERT_SINGLE_OWNER
119     SkASSERT(0 == flags || kNoPendingIO_Flag == flags);
120     return this->internalCreateApproxTexture(desc, flags);
121 }
122 
internalCreateApproxTexture(const GrSurfaceDesc & desc,uint32_t scratchFlags)123 GrTexture* GrResourceProvider::internalCreateApproxTexture(const GrSurfaceDesc& desc,
124                                                            uint32_t scratchFlags) {
125     ASSERT_SINGLE_OWNER
126     if (this->isAbandoned()) {
127         return nullptr;
128     }
129     // Currently we don't recycle compressed textures as scratch.
130     if (GrPixelConfigIsCompressed(desc.fConfig)) {
131         return nullptr;
132     } else {
133         return this->refScratchTexture(desc, scratchFlags);
134     }
135 }
136 
refScratchTexture(const GrSurfaceDesc & inDesc,uint32_t flags)137 GrTexture* GrResourceProvider::refScratchTexture(const GrSurfaceDesc& inDesc,
138                                                  uint32_t flags) {
139     ASSERT_SINGLE_OWNER
140     SkASSERT(!this->isAbandoned());
141     SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
142 
143     SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
144 
145     if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
146         if (!(kExact_Flag & flags)) {
147             // bin by pow2 with a reasonable min
148             GrSurfaceDesc* wdesc = desc.writable();
149             wdesc->fWidth  = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fWidth));
150             wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fHeight));
151         }
152 
153         GrScratchKey key;
154         GrTexturePriv::ComputeScratchKey(*desc, &key);
155         uint32_t scratchFlags = 0;
156         if (kNoPendingIO_Flag & flags) {
157             scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
158         } else  if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
159             // If it is not a render target then it will most likely be populated by
160             // writePixels() which will trigger a flush if the texture has pending IO.
161             scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
162         }
163         GrGpuResource* resource = fCache->findAndRefScratchResource(key,
164                                                                    GrSurface::WorstCaseSize(*desc),
165                                                                    scratchFlags);
166         if (resource) {
167             GrSurface* surface = static_cast<GrSurface*>(resource);
168             GrRenderTarget* rt = surface->asRenderTarget();
169             if (rt && fGpu->caps()->discardRenderTargetSupport()) {
170                 rt->discard();
171             }
172             return surface->asTexture();
173         }
174     }
175 
176     if (!(kNoCreate_Flag & flags)) {
177         return fGpu->createTexture(*desc, SkBudgeted::kYes);
178     }
179 
180     return nullptr;
181 }
182 
wrapBackendTexture(const GrBackendTextureDesc & desc,GrWrapOwnership ownership)183 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTextureDesc& desc,
184                                                         GrWrapOwnership ownership) {
185     ASSERT_SINGLE_OWNER
186     if (this->isAbandoned()) {
187         return nullptr;
188     }
189     return fGpu->wrapBackendTexture(desc, ownership);
190 }
191 
wrapBackendRenderTarget(const GrBackendRenderTargetDesc & desc)192 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
193         const GrBackendRenderTargetDesc& desc)
194 {
195     ASSERT_SINGLE_OWNER
196     return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(desc);
197 }
198 
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)199 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
200                                                    GrGpuResource* resource) {
201     ASSERT_SINGLE_OWNER
202     if (this->isAbandoned() || !resource) {
203         return;
204     }
205     resource->resourcePriv().setUniqueKey(key);
206 }
207 
findAndRefResourceByUniqueKey(const GrUniqueKey & key)208 GrGpuResource* GrResourceProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) {
209     ASSERT_SINGLE_OWNER
210     return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key);
211 }
212 
findAndRefTextureByUniqueKey(const GrUniqueKey & key)213 GrTexture* GrResourceProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) {
214     ASSERT_SINGLE_OWNER
215     GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key);
216     if (resource) {
217         GrTexture* texture = static_cast<GrSurface*>(resource)->asTexture();
218         SkASSERT(texture);
219         return texture;
220     }
221     return NULL;
222 }
223 
224 // MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
assignUniqueKeyToProxy(const GrUniqueKey & key,GrTextureProxy * proxy)225 void GrResourceProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
226     ASSERT_SINGLE_OWNER
227     SkASSERT(key.isValid());
228     if (this->isAbandoned() || !proxy) {
229         return;
230     }
231 
232     GrTexture* texture = proxy->instantiate(this);
233     if (!texture) {
234         return;
235     }
236 
237     this->assignUniqueKeyToResource(key, texture);
238 }
239 
240 // MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
findProxyByUniqueKey(const GrUniqueKey & key)241 sk_sp<GrTextureProxy> GrResourceProvider::findProxyByUniqueKey(const GrUniqueKey& key) {
242     ASSERT_SINGLE_OWNER
243 
244     sk_sp<GrTexture> texture(this->findAndRefTextureByUniqueKey(key));
245     if (!texture) {
246         return nullptr;
247     }
248 
249     return GrSurfaceProxy::MakeWrapped(std::move(texture));
250 }
251 
createInstancedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey & key)252 const GrBuffer* GrResourceProvider::createInstancedIndexBuffer(const uint16_t* pattern,
253                                                                int patternSize,
254                                                                int reps,
255                                                                int vertCount,
256                                                                const GrUniqueKey& key) {
257     size_t bufferSize = patternSize * reps * sizeof(uint16_t);
258 
259     // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO.
260     GrBuffer* buffer = this->createBuffer(bufferSize, kIndex_GrBufferType, kStatic_GrAccessPattern,
261                                           kNoPendingIO_Flag);
262     if (!buffer) {
263         return nullptr;
264     }
265     uint16_t* data = (uint16_t*) buffer->map();
266     bool useTempData = (nullptr == data);
267     if (useTempData) {
268         data = new uint16_t[reps * patternSize];
269     }
270     for (int i = 0; i < reps; ++i) {
271         int baseIdx = i * patternSize;
272         uint16_t baseVert = (uint16_t)(i * vertCount);
273         for (int j = 0; j < patternSize; ++j) {
274             data[baseIdx+j] = baseVert + pattern[j];
275         }
276     }
277     if (useTempData) {
278         if (!buffer->updateData(data, bufferSize)) {
279             buffer->unref();
280             return nullptr;
281         }
282         delete[] data;
283     } else {
284         buffer->unmap();
285     }
286     this->assignUniqueKeyToResource(key, buffer);
287     return buffer;
288 }
289 
createQuadIndexBuffer()290 const GrBuffer* GrResourceProvider::createQuadIndexBuffer() {
291     static const int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1;
292     GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
293     static const uint16_t kPattern[] = { 0, 1, 2, 0, 2, 3 };
294 
295     return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
296 }
297 
createPath(const SkPath & path,const GrStyle & style)298 GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
299     SkASSERT(this->gpu()->pathRendering());
300     return this->gpu()->pathRendering()->createPath(path, style);
301 }
302 
createPathRange(GrPathRange::PathGenerator * gen,const GrStyle & style)303 GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
304                                                  const GrStyle& style) {
305     SkASSERT(this->gpu()->pathRendering());
306     return this->gpu()->pathRendering()->createPathRange(gen, style);
307 }
308 
createGlyphs(const SkTypeface * tf,const SkScalerContextEffects & effects,const SkDescriptor * desc,const GrStyle & style)309 GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf,
310                                               const SkScalerContextEffects& effects,
311                                               const SkDescriptor* desc,
312                                               const GrStyle& style) {
313 
314     SkASSERT(this->gpu()->pathRendering());
315     return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style);
316 }
317 
createBuffer(size_t size,GrBufferType intendedType,GrAccessPattern accessPattern,uint32_t flags,const void * data)318 GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
319                                            GrAccessPattern accessPattern, uint32_t flags,
320                                            const void* data) {
321     if (this->isAbandoned()) {
322         return nullptr;
323     }
324     if (kDynamic_GrAccessPattern != accessPattern) {
325         return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
326     }
327     if (!(flags & kRequireGpuMemory_Flag) &&
328         this->gpu()->caps()->preferClientSideDynamicBuffers() &&
329         GrBufferTypeIsVertexOrIndex(intendedType) &&
330         kDynamic_GrAccessPattern == accessPattern) {
331         return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data);
332     }
333 
334     // bin by pow2 with a reasonable min
335     static const size_t MIN_SIZE = 1 << 12;
336     size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
337 
338     GrScratchKey key;
339     GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
340     uint32_t scratchFlags = 0;
341     if (flags & kNoPendingIO_Flag) {
342         scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
343     } else {
344         scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
345     }
346     GrBuffer* buffer = static_cast<GrBuffer*>(
347         this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags));
348     if (!buffer) {
349         buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
350         if (!buffer) {
351             return nullptr;
352         }
353     }
354     if (data) {
355         buffer->updateData(data, size);
356     }
357     SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs.
358     return buffer;
359 }
360 
attachStencilAttachment(GrRenderTarget * rt)361 GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
362     SkASSERT(rt);
363     if (rt->renderTargetPriv().getStencilAttachment()) {
364         return rt->renderTargetPriv().getStencilAttachment();
365     }
366 
367     if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
368         GrUniqueKey sbKey;
369 
370         int width = rt->width();
371         int height = rt->height();
372 #if 0
373         if (this->caps()->oversizedStencilSupport()) {
374             width  = SkNextPow2(width);
375             height = SkNextPow2(height);
376         }
377 #endif
378         bool newStencil = false;
379         GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
380                                                                rt->numStencilSamples(), &sbKey);
381         GrStencilAttachment* stencil = static_cast<GrStencilAttachment*>(
382             this->findAndRefResourceByUniqueKey(sbKey));
383         if (!stencil) {
384             // Need to try and create a new stencil
385             stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height);
386             if (stencil) {
387                 this->assignUniqueKeyToResource(sbKey, stencil);
388                 newStencil = true;
389             }
390         }
391         if (rt->renderTargetPriv().attachStencilAttachment(stencil)) {
392             if (newStencil) {
393                 // Right now we're clearing the stencil attachment here after it is
394                 // attached to a RT for the first time. When we start matching
395                 // stencil buffers with smaller color targets this will no longer
396                 // be correct because it won't be guaranteed to clear the entire
397                 // sb.
398                 // We used to clear down in the GL subclass using a special purpose
399                 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
400                 // FBO status.
401                 this->gpu()->clearStencil(rt);
402             }
403         }
404     }
405     return rt->renderTargetPriv().getStencilAttachment();
406 }
407 
wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc & desc)408 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
409         const GrBackendTextureDesc& desc)
410 {
411     if (this->isAbandoned()) {
412         return nullptr;
413     }
414     return this->gpu()->wrapBackendTextureAsRenderTarget(desc);
415 }
416 
makeSemaphore()417 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore() {
418     return fGpu->makeSemaphore();
419 }
420 
takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore)421 void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
422     semaphore->resetGpu(fGpu);
423 }
424 
releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore)425 void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
426     semaphore->resetGpu(nullptr);
427 }
428