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 "src/gpu/GrResourceProvider.h"
9 
10 #include "include/gpu/GrBackendSemaphore.h"
11 #include "include/private/GrResourceKey.h"
12 #include "include/private/GrSingleOwner.h"
13 #include "src/core/SkConvertPixels.h"
14 #include "src/core/SkMathPriv.h"
15 #include "src/gpu/GrAttachment.h"
16 #include "src/gpu/GrCaps.h"
17 #include "src/gpu/GrDataUtils.h"
18 #include "src/gpu/GrGpu.h"
19 #include "src/gpu/GrGpuBuffer.h"
20 #include "src/gpu/GrImageInfo.h"
21 #include "src/gpu/GrPath.h"
22 #include "src/gpu/GrPathRendering.h"
23 #include "src/gpu/GrProxyProvider.h"
24 #include "src/gpu/GrRenderTarget.h"
25 #include "src/gpu/GrResourceCache.h"
26 #include "src/gpu/GrSemaphore.h"
27 #include "src/gpu/GrTexture.h"
28 #include "src/gpu/SkGr.h"
29 
30 const int GrResourceProvider::kMinScratchTextureSize = 16;
31 
32 #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fSingleOwner)
33 
GrResourceProvider(GrGpu * gpu,GrResourceCache * cache,GrSingleOwner * owner)34 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner)
35         : fCache(cache)
36         , fGpu(gpu)
37 #ifdef SK_DEBUG
38         , fSingleOwner(owner)
39 #endif
40 {
41     fCaps = sk_ref_sp(fGpu->caps());
42 }
43 
createTexture(SkISize dimensions,const GrBackendFormat & format,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,const GrMipLevel texels[],int mipLevelCount)44 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
45                                                    const GrBackendFormat& format,
46                                                    GrColorType colorType,
47                                                    GrRenderable renderable,
48                                                    int renderTargetSampleCnt,
49                                                    SkBudgeted budgeted,
50                                                    GrProtected isProtected,
51                                                    const GrMipLevel texels[],
52                                                    int mipLevelCount) {
53     ASSERT_SINGLE_OWNER
54 
55     SkASSERT(mipLevelCount > 0);
56 
57     if (this->isAbandoned()) {
58         return nullptr;
59     }
60 
61     GrMipmapped mipMapped = mipLevelCount > 1 ? GrMipmapped::kYes : GrMipmapped::kNo;
62     if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
63                                       mipMapped)) {
64         return nullptr;
65     }
66     // Current rule is that you can provide no level data, just the base, or all the levels.
67     bool hasPixels = mipLevelCount && texels[0].fPixels;
68     auto scratch = this->getExactScratch(dimensions, format, renderable, renderTargetSampleCnt,
69                                          budgeted, mipMapped, isProtected);
70     if (scratch) {
71         if (!hasPixels) {
72             return scratch;
73         }
74         return this->writePixels(std::move(scratch), colorType, dimensions, texels, mipLevelCount);
75     }
76     SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
77     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
78     GrColorType tempColorType = GrColorType::kUnknown;
79     if (hasPixels) {
80         tempColorType = this->prepareLevels(format, colorType, dimensions, texels, mipLevelCount,
81                                             &tmpTexels, &tmpDatas);
82         if (tempColorType == GrColorType::kUnknown) {
83             return nullptr;
84         }
85     }
86     return fGpu->createTexture(dimensions, format, renderable, renderTargetSampleCnt, budgeted,
87                                isProtected, colorType, tempColorType, tmpTexels.get(),
88                                mipLevelCount);
89 }
90 
getExactScratch(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipmapped mipMapped,GrProtected isProtected)91 sk_sp<GrTexture> GrResourceProvider::getExactScratch(SkISize dimensions,
92                                                      const GrBackendFormat& format,
93                                                      GrRenderable renderable,
94                                                      int renderTargetSampleCnt,
95                                                      SkBudgeted budgeted,
96                                                      GrMipmapped mipMapped,
97                                                      GrProtected isProtected) {
98     sk_sp<GrTexture> tex(this->refScratchTexture(dimensions, format, renderable,
99                                                  renderTargetSampleCnt, mipMapped, isProtected));
100     if (tex && SkBudgeted::kNo == budgeted) {
101         tex->resourcePriv().makeUnbudgeted();
102     }
103 
104     return tex;
105 }
106 
createTexture(SkISize dimensions,const GrBackendFormat & format,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,SkBackingFit fit,GrProtected isProtected,const GrMipLevel & mipLevel)107 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
108                                                    const GrBackendFormat& format,
109                                                    GrColorType colorType,
110                                                    GrRenderable renderable,
111                                                    int renderTargetSampleCnt,
112                                                    SkBudgeted budgeted,
113                                                    SkBackingFit fit,
114                                                    GrProtected isProtected,
115                                                    const GrMipLevel& mipLevel) {
116     ASSERT_SINGLE_OWNER
117 
118     if (!mipLevel.fPixels) {
119         return nullptr;
120     }
121 
122     if (SkBackingFit::kApprox == fit) {
123         if (this->isAbandoned()) {
124             return nullptr;
125         }
126         if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
127                                           GrMipmapped::kNo)) {
128             return nullptr;
129         }
130 
131         auto tex = this->createApproxTexture(dimensions, format, renderable, renderTargetSampleCnt,
132                                              isProtected);
133         if (!tex) {
134             return nullptr;
135         }
136         return this->writePixels(std::move(tex), colorType, dimensions, &mipLevel, 1);
137     } else {
138         return this->createTexture(dimensions, format, colorType, renderable, renderTargetSampleCnt,
139                                    budgeted, isProtected, &mipLevel, 1);
140     }
141 }
142 
createCompressedTexture(SkISize dimensions,const GrBackendFormat & format,SkBudgeted budgeted,GrMipmapped mipMapped,GrProtected isProtected,SkData * data)143 sk_sp<GrTexture> GrResourceProvider::createCompressedTexture(SkISize dimensions,
144                                                              const GrBackendFormat& format,
145                                                              SkBudgeted budgeted,
146                                                              GrMipmapped mipMapped,
147                                                              GrProtected isProtected,
148                                                              SkData* data) {
149     ASSERT_SINGLE_OWNER
150     if (this->isAbandoned()) {
151         return nullptr;
152     }
153     return fGpu->createCompressedTexture(dimensions, format, budgeted, mipMapped,
154                                          isProtected, data->data(), data->size());
155 }
156 
createTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipMapped,SkBudgeted budgeted,GrProtected isProtected)157 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
158                                                    const GrBackendFormat& format,
159                                                    GrRenderable renderable,
160                                                    int renderTargetSampleCnt,
161                                                    GrMipmapped mipMapped,
162                                                    SkBudgeted budgeted,
163                                                    GrProtected isProtected) {
164     ASSERT_SINGLE_OWNER
165     if (this->isAbandoned()) {
166         return nullptr;
167     }
168 
169     if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
170                                       mipMapped)) {
171         return nullptr;
172     }
173 
174     // Currently we don't recycle compressed textures as scratch. Additionally all compressed
175     // textures should be created through the createCompressedTexture function.
176     SkASSERT(!this->caps()->isFormatCompressed(format));
177 
178     // TODO: Support GrMipmapped::kYes in scratch texture lookup here.
179     sk_sp<GrTexture> tex =
180             this->getExactScratch(dimensions, format, renderable, renderTargetSampleCnt, budgeted,
181                                   mipMapped, isProtected);
182     if (tex) {
183         return tex;
184     }
185 
186     return fGpu->createTexture(dimensions, format, renderable, renderTargetSampleCnt, mipMapped,
187                                budgeted, isProtected);
188 }
189 
190 // Map 'value' to a larger multiple of 2. Values <= 'kMagicTol' will pop up to
191 // the next power of 2. Those above 'kMagicTol' will only go up half the floor power of 2.
MakeApprox(SkISize dimensions)192 SkISize GrResourceProvider::MakeApprox(SkISize dimensions) {
193     auto adjust = [](int value) {
194         static const int kMagicTol = 1024;
195 
196         value = std::max(kMinScratchTextureSize, value);
197 
198         if (SkIsPow2(value)) {
199             return value;
200         }
201 
202         int ceilPow2 = SkNextPow2(value);
203         if (value <= kMagicTol) {
204             return ceilPow2;
205         }
206 
207         int floorPow2 = ceilPow2 >> 1;
208         int mid = floorPow2 + (floorPow2 >> 1);
209 
210         if (value <= mid) {
211             return mid;
212         }
213         return ceilPow2;
214     };
215 
216     return {adjust(dimensions.width()), adjust(dimensions.height())};
217 }
218 
createApproxTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrProtected isProtected)219 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(SkISize dimensions,
220                                                          const GrBackendFormat& format,
221                                                          GrRenderable renderable,
222                                                          int renderTargetSampleCnt,
223                                                          GrProtected isProtected) {
224     ASSERT_SINGLE_OWNER
225 
226     if (this->isAbandoned()) {
227         return nullptr;
228     }
229 
230     // Currently we don't recycle compressed textures as scratch. Additionally all compressed
231     // textures should be created through the createCompressedTexture function.
232     SkASSERT(!this->caps()->isFormatCompressed(format));
233 
234     if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
235                                       GrMipmapped::kNo)) {
236         return nullptr;
237     }
238 
239     auto copyDimensions = MakeApprox(dimensions);
240 
241     if (auto tex = this->refScratchTexture(copyDimensions, format, renderable,
242                                            renderTargetSampleCnt, GrMipmapped::kNo, isProtected)) {
243         return tex;
244     }
245 
246     return fGpu->createTexture(copyDimensions, format, renderable, renderTargetSampleCnt,
247                                GrMipmapped::kNo, SkBudgeted::kYes, isProtected);
248 }
249 
refScratchTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipMapped,GrProtected isProtected)250 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(SkISize dimensions,
251                                                        const GrBackendFormat& format,
252                                                        GrRenderable renderable,
253                                                        int renderTargetSampleCnt,
254                                                        GrMipmapped mipMapped,
255                                                        GrProtected isProtected) {
256     ASSERT_SINGLE_OWNER
257     SkASSERT(!this->isAbandoned());
258     SkASSERT(!this->caps()->isFormatCompressed(format));
259     SkASSERT(fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
260                                           GrMipmapped::kNo));
261 
262     // We could make initial clears work with scratch textures but it is a rare case so we just opt
263     // to fall back to making a new texture.
264     if (fGpu->caps()->reuseScratchTextures() || renderable == GrRenderable::kYes) {
265         GrScratchKey key;
266         GrTexture::ComputeScratchKey(*this->caps(), format, dimensions, renderable,
267                                      renderTargetSampleCnt, mipMapped, isProtected, &key);
268         GrGpuResource* resource = fCache->findAndRefScratchResource(key);
269         if (resource) {
270             fGpu->stats()->incNumScratchTexturesReused();
271             GrSurface* surface = static_cast<GrSurface*>(resource);
272             return sk_sp<GrTexture>(surface->asTexture());
273         }
274     }
275 
276     return nullptr;
277 }
278 
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)279 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
280                                                         GrWrapOwnership ownership,
281                                                         GrWrapCacheable cacheable,
282                                                         GrIOType ioType) {
283     ASSERT_SINGLE_OWNER
284     if (this->isAbandoned()) {
285         return nullptr;
286     }
287     return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType);
288 }
289 
wrapCompressedBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable)290 sk_sp<GrTexture> GrResourceProvider::wrapCompressedBackendTexture(const GrBackendTexture& tex,
291                                                                   GrWrapOwnership ownership,
292                                                                   GrWrapCacheable cacheable) {
293     ASSERT_SINGLE_OWNER
294     if (this->isAbandoned()) {
295         return nullptr;
296     }
297 
298     return fGpu->wrapCompressedBackendTexture(tex, ownership, cacheable);
299 }
300 
301 
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)302 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
303                                                                   int sampleCnt,
304                                                                   GrWrapOwnership ownership,
305                                                                   GrWrapCacheable cacheable) {
306     ASSERT_SINGLE_OWNER
307     if (this->isAbandoned()) {
308         return nullptr;
309     }
310     return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable);
311 }
312 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)313 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
314         const GrBackendRenderTarget& backendRT) {
315     ASSERT_SINGLE_OWNER
316     return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
317 }
318 
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)319 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
320         const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
321     ASSERT_SINGLE_OWNER
322     return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
323                                                                                      vkInfo);
324 
325 }
326 
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)327 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
328                                                    GrGpuResource* resource) {
329     ASSERT_SINGLE_OWNER
330     if (this->isAbandoned() || !resource) {
331         return;
332     }
333     resource->resourcePriv().setUniqueKey(key);
334 }
335 
findResourceByUniqueKey(const GrUniqueKey & key)336 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
337     ASSERT_SINGLE_OWNER
338     return this->isAbandoned() ? nullptr
339                                : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
340 }
341 
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)342 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
343                                                                     size_t size,
344                                                                     const void* data,
345                                                                     const GrUniqueKey& key) {
346     if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
347         return std::move(buffer);
348     }
349     if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
350         // We shouldn't bin and/or cache static buffers.
351         SkASSERT(buffer->size() == size);
352         SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
353         buffer->resourcePriv().setUniqueKey(key);
354         return sk_sp<const GrGpuBuffer>(buffer);
355     }
356     return nullptr;
357 }
358 
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey * key)359 sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
360                                                                         int patternSize,
361                                                                         int reps,
362                                                                         int vertCount,
363                                                                         const GrUniqueKey* key) {
364     size_t bufferSize = patternSize * reps * sizeof(uint16_t);
365 
366     sk_sp<GrGpuBuffer> buffer(
367             this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
368     if (!buffer) {
369         return nullptr;
370     }
371     uint16_t* data = (uint16_t*) buffer->map();
372     SkAutoTArray<uint16_t> temp;
373     if (!data) {
374         temp.reset(reps * patternSize);
375         data = temp.get();
376     }
377     for (int i = 0; i < reps; ++i) {
378         int baseIdx = i * patternSize;
379         uint16_t baseVert = (uint16_t)(i * vertCount);
380         for (int j = 0; j < patternSize; ++j) {
381             data[baseIdx+j] = baseVert + pattern[j];
382         }
383     }
384     if (temp.get()) {
385         if (!buffer->updateData(data, bufferSize)) {
386             return nullptr;
387         }
388     } else {
389         buffer->unmap();
390     }
391     if (key) {
392         SkASSERT(key->isValid());
393         this->assignUniqueKeyToResource(*key, buffer.get());
394     }
395     return std::move(buffer);
396 }
397 
398 ///////////////////////////////////////////////////////////////////////////////////////////////////
399 static constexpr int kMaxNumNonAAQuads = 1 << 12;  // max possible: (1 << 14) - 1;
400 static const int kVertsPerNonAAQuad = 4;
401 static const int kIndicesPerNonAAQuad = 6;
402 
createNonAAQuadIndexBuffer()403 sk_sp<const GrGpuBuffer> GrResourceProvider::createNonAAQuadIndexBuffer() {
404     static_assert(kVertsPerNonAAQuad * kMaxNumNonAAQuads <= 65535);  // indices fit in a uint16_t
405 
406     static const uint16_t kNonAAQuadIndexPattern[] = {
407         0, 1, 2, 2, 1, 3
408     };
409 
410     static_assert(SK_ARRAY_COUNT(kNonAAQuadIndexPattern) == kIndicesPerNonAAQuad);
411 
412     return this->createPatternedIndexBuffer(kNonAAQuadIndexPattern, kIndicesPerNonAAQuad,
413                                             kMaxNumNonAAQuads, kVertsPerNonAAQuad, nullptr);
414 }
415 
MaxNumNonAAQuads()416 int GrResourceProvider::MaxNumNonAAQuads() { return kMaxNumNonAAQuads; }
NumVertsPerNonAAQuad()417 int GrResourceProvider::NumVertsPerNonAAQuad() { return kVertsPerNonAAQuad; }
NumIndicesPerNonAAQuad()418 int GrResourceProvider::NumIndicesPerNonAAQuad() { return kIndicesPerNonAAQuad; }
419 
420 ///////////////////////////////////////////////////////////////////////////////////////////////////
421 static constexpr int kMaxNumAAQuads = 1 << 9;  // max possible: (1 << 13) - 1;
422 static const int kVertsPerAAQuad = 8;
423 static const int kIndicesPerAAQuad = 30;
424 
createAAQuadIndexBuffer()425 sk_sp<const GrGpuBuffer> GrResourceProvider::createAAQuadIndexBuffer() {
426     static_assert(kVertsPerAAQuad * kMaxNumAAQuads <= 65535);  // indices fit in a uint16_t
427 
428     // clang-format off
429     static const uint16_t kAAQuadIndexPattern[] = {
430         0, 1, 2, 1, 3, 2,
431         0, 4, 1, 4, 5, 1,
432         0, 6, 4, 0, 2, 6,
433         2, 3, 6, 3, 7, 6,
434         1, 5, 3, 3, 5, 7,
435     };
436     // clang-format on
437 
438     static_assert(SK_ARRAY_COUNT(kAAQuadIndexPattern) == kIndicesPerAAQuad);
439 
440     return this->createPatternedIndexBuffer(kAAQuadIndexPattern, kIndicesPerAAQuad,
441                                             kMaxNumAAQuads, kVertsPerAAQuad, nullptr);
442 }
443 
MaxNumAAQuads()444 int GrResourceProvider::MaxNumAAQuads() { return kMaxNumAAQuads; }
NumVertsPerAAQuad()445 int GrResourceProvider::NumVertsPerAAQuad() { return kVertsPerAAQuad; }
NumIndicesPerAAQuad()446 int GrResourceProvider::NumIndicesPerAAQuad() { return kIndicesPerAAQuad; }
447 
448 ///////////////////////////////////////////////////////////////////////////////////////////////////
createPath(const SkPath & path,const GrStyle & style)449 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
450     if (this->isAbandoned()) {
451         return nullptr;
452     }
453 
454     SkASSERT(this->gpu()->pathRendering());
455     return this->gpu()->pathRendering()->createPath(path, style);
456 }
457 
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)458 sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
459                                                     GrAccessPattern accessPattern,
460                                                     const void* data) {
461     if (this->isAbandoned()) {
462         return nullptr;
463     }
464     if (kDynamic_GrAccessPattern != accessPattern) {
465         return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
466     }
467     // bin by pow2+midpoint with a reasonable min
468     static const size_t MIN_SIZE = 1 << 12;
469     size_t allocSize = std::max(size, MIN_SIZE);
470     size_t ceilPow2 = GrNextSizePow2(allocSize);
471     size_t floorPow2 = ceilPow2 >> 1;
472     size_t mid = floorPow2 + (floorPow2 >> 1);
473     allocSize = (allocSize <= mid) ? mid : ceilPow2;
474 
475     GrScratchKey key;
476     GrGpuBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
477     auto buffer =
478             sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
479                     key)));
480     if (!buffer) {
481         buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
482         if (!buffer) {
483             return nullptr;
484         }
485     }
486     if (data) {
487         buffer->updateData(data, size);
488     }
489     return buffer;
490 }
491 
attachStencilAttachment(GrRenderTarget * rt,int numStencilSamples)492 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, int numStencilSamples) {
493     SkASSERT(rt);
494     GrAttachment* stencil = rt->getStencilAttachment();
495     if (stencil && stencil->numSamples() == numStencilSamples) {
496         return true;
497     }
498 
499     if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
500         GrUniqueKey sbKey;
501 
502 #if 0
503         if (this->caps()->oversizedStencilSupport()) {
504             width  = SkNextPow2(width);
505             height = SkNextPow2(height);
506         }
507 #endif
508         GrBackendFormat stencilFormat =
509                 this->gpu()->getPreferredStencilFormat(rt->backendFormat());
510         if (!stencilFormat.isValid()) {
511             return false;
512         }
513         GrProtected isProtected = rt->isProtected() ? GrProtected::kYes : GrProtected::kNo;
514         GrAttachment::ComputeSharedAttachmentUniqueKey(
515                 *this->caps(), stencilFormat, rt->dimensions(),
516                 GrAttachment::UsageFlags::kStencilAttachment, numStencilSamples, isProtected,
517                 &sbKey);
518         auto stencil = this->findByUniqueKey<GrAttachment>(sbKey);
519         if (!stencil) {
520             // Need to try and create a new stencil
521             stencil = this->gpu()->makeStencilAttachmentForRenderTarget(rt, rt->dimensions(),
522                                                                         numStencilSamples);
523             if (!stencil) {
524                 return false;
525             }
526             this->assignUniqueKeyToResource(sbKey, stencil.get());
527         }
528         rt->attachStencilAttachment(std::move(stencil));
529     }
530 
531     if (GrAttachment* stencil = rt->getStencilAttachment()) {
532         return stencil->numSamples() == numStencilSamples;
533     }
534     return false;
535 }
536 
makeMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected)537 sk_sp<GrAttachment> GrResourceProvider::makeMSAAAttachment(SkISize dimensions,
538                                                            const GrBackendFormat& format,
539                                                            int sampleCnt,
540                                                            GrProtected isProtected) {
541     ASSERT_SINGLE_OWNER
542 
543     SkASSERT(sampleCnt > 1);
544 
545     if (this->isAbandoned()) {
546         return nullptr;
547     }
548 
549     if (!fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
550                                       GrMipMapped::kNo)) {
551         return nullptr;
552     }
553 
554     auto scratch = this->refScratchMSAAAttachment(dimensions, format, sampleCnt, isProtected);
555     if (scratch) {
556         return scratch;
557     }
558 
559     return fGpu->makeMSAAAttachment(dimensions, format, sampleCnt, isProtected);
560 }
561 
refScratchMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected)562 sk_sp<GrAttachment> GrResourceProvider::refScratchMSAAAttachment(SkISize dimensions,
563                                                                  const GrBackendFormat& format,
564                                                                  int sampleCnt,
565                                                                  GrProtected isProtected) {
566     ASSERT_SINGLE_OWNER
567     SkASSERT(!this->isAbandoned());
568     SkASSERT(!this->caps()->isFormatCompressed(format));
569     SkASSERT(fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
570                                           GrMipmapped::kNo));
571 
572     GrScratchKey key;
573     GrAttachment::ComputeScratchKey(*this->caps(), format, dimensions,
574                                     GrAttachment::UsageFlags::kColorAttachment, sampleCnt,
575                                     isProtected, &key);
576     GrGpuResource* resource = fCache->findAndRefScratchResource(key);
577     if (resource) {
578         fGpu->stats()->incNumScratchMSAAAttachmentsReused();
579         GrAttachment* attachment = static_cast<GrAttachment*>(resource);
580         return sk_sp<GrAttachment>(attachment);
581     }
582 
583     return nullptr;
584 }
585 
makeSemaphore(bool isOwned)586 std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(
587         bool isOwned) {
588     return this->isAbandoned() ? nullptr : fGpu->makeSemaphore(isOwned);
589 }
590 
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)591 std::unique_ptr<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(
592         const GrBackendSemaphore& semaphore,
593         SemaphoreWrapType wrapType,
594         GrWrapOwnership ownership) {
595     ASSERT_SINGLE_OWNER
596     return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
597                                                                       wrapType,
598                                                                       ownership);
599 }
600 
601 // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
602 // to make the row bytes tight if necessary. Returns false if the input row bytes are invalid.
prepare_level(const GrMipLevel & inLevel,SkISize dimensions,bool rowBytesSupport,GrColorType origColorType,GrColorType allowedColorType,GrMipLevel * outLevel,std::unique_ptr<char[]> * data)603 static bool prepare_level(const GrMipLevel& inLevel,
604                           SkISize dimensions,
605                           bool rowBytesSupport,
606                           GrColorType origColorType,
607                           GrColorType allowedColorType,
608                           GrMipLevel* outLevel,
609                           std::unique_ptr<char[]>* data) {
610     if (!inLevel.fPixels) {
611         outLevel->fPixels = nullptr;
612         outLevel->fRowBytes = 0;
613         return true;
614     }
615     size_t minRB = dimensions.fWidth * GrColorTypeBytesPerPixel(origColorType);
616     size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
617     if (actualRB < minRB) {
618         return false;
619     }
620     if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
621         outLevel->fRowBytes = actualRB;
622         outLevel->fPixels = inLevel.fPixels;
623         return true;
624     }
625     auto tempRB = dimensions.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
626     data->reset(new char[tempRB * dimensions.fHeight]);
627     outLevel->fPixels = data->get();
628     outLevel->fRowBytes = tempRB;
629     GrImageInfo srcInfo(origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
630     GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
631     return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
632 }
633 
prepareLevels(const GrBackendFormat & format,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount,TempLevels * tempLevels,TempLevelDatas * tempLevelDatas) const634 GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
635                                               GrColorType colorType,
636                                               SkISize baseSize,
637                                               const GrMipLevel texels[],
638                                               int mipLevelCount,
639                                               TempLevels* tempLevels,
640                                               TempLevelDatas* tempLevelDatas) const {
641     SkASSERT(mipLevelCount && texels && texels[0].fPixels);
642 
643     auto allowedColorType =
644             this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
645     if (allowedColorType == GrColorType::kUnknown) {
646         return GrColorType::kUnknown;
647     }
648     bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
649     tempLevels->reset(mipLevelCount);
650     tempLevelDatas->reset(mipLevelCount);
651     auto size = baseSize;
652     for (int i = 0; i < mipLevelCount; ++i) {
653         if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
654                            &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
655             return GrColorType::kUnknown;
656         }
657         size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
658     }
659     return allowedColorType;
660 }
661 
writePixels(sk_sp<GrTexture> texture,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount) const662 sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
663                                                  GrColorType colorType,
664                                                  SkISize baseSize,
665                                                  const GrMipLevel texels[],
666                                                  int mipLevelCount) const {
667     SkASSERT(!this->isAbandoned());
668     SkASSERT(texture);
669     SkASSERT(colorType != GrColorType::kUnknown);
670     SkASSERT(mipLevelCount && texels && texels[0].fPixels);
671 
672     SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
673     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
674     auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
675                                              mipLevelCount, &tmpTexels, &tmpDatas);
676     if (tempColorType == GrColorType::kUnknown) {
677         return nullptr;
678     }
679     SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
680                                      colorType, tempColorType, tmpTexels.get(), mipLevelCount));
681     return texture;
682 }
683