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