• 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/private/GrResourceKey.h"
12 #include "include/private/GrSingleOwner.h"
13 #include "src/core/SkConvertPixels.h"
14 #include "src/core/SkMathPriv.h"
15 #include "src/core/SkMipmap.h"
16 #include "src/gpu/GrAttachment.h"
17 #include "src/gpu/GrCaps.h"
18 #include "src/gpu/GrDataUtils.h"
19 #include "src/gpu/GrGpu.h"
20 #include "src/gpu/GrGpuBuffer.h"
21 #include "src/gpu/GrImageInfo.h"
22 #include "src/gpu/GrProxyProvider.h"
23 #include "src/gpu/GrRenderTarget.h"
24 #include "src/gpu/GrResourceCache.h"
25 #include "src/gpu/GrSemaphore.h"
26 #include "src/gpu/GrTexture.h"
27 #include "src/gpu/SkGr.h"
28 
29 const int GrResourceProvider::kMinScratchTextureSize = 16;
30 
31 #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(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 
createTexture(SkISize dimensions,const GrBackendFormat & format,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipmapped mipmapped,GrProtected isProtected,const GrMipLevel texels[])43 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
44                                                    const GrBackendFormat& format,
45                                                    GrColorType colorType,
46                                                    GrRenderable renderable,
47                                                    int renderTargetSampleCnt,
48                                                    SkBudgeted budgeted,
49                                                    GrMipmapped mipmapped,
50                                                    GrProtected isProtected,
51                                                    const GrMipLevel texels[]) {
52     ASSERT_SINGLE_OWNER
53 
54     if (this->isAbandoned()) {
55         return nullptr;
56     }
57 
58     int numMipLevels = 1;
59     if (mipmapped == GrMipmapped::kYes) {
60         numMipLevels = SkMipmap::ComputeLevelCount(dimensions.fWidth, dimensions.fHeight) + 1;
61     }
62 
63     if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
64                                       mipmapped)) {
65         return nullptr;
66     }
67     // Current rule is that you can provide no level data, just the base, or all the levels.
68     bool hasPixels = texels[0].fPixels;
69     auto scratch = this->getExactScratch(dimensions, format, renderable, renderTargetSampleCnt,
70                                          budgeted, mipmapped, isProtected);
71     if (scratch) {
72         if (!hasPixels) {
73             return scratch;
74         }
75         return this->writePixels(std::move(scratch), colorType, dimensions, texels, numMipLevels);
76     }
77     SkAutoSTArray<14, GrMipLevel> tmpTexels;
78     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
79     GrColorType tempColorType = GrColorType::kUnknown;
80     if (hasPixels) {
81         tempColorType = this->prepareLevels(format, colorType, dimensions, texels, numMipLevels,
82                                             &tmpTexels, &tmpDatas);
83         if (tempColorType == GrColorType::kUnknown) {
84             return nullptr;
85         }
86     }
87     return fGpu->createTexture(dimensions, format, renderable, renderTargetSampleCnt, budgeted,
88                                isProtected, colorType, tempColorType, tmpTexels.get(),
89                                numMipLevels);
90 }
91 
getExactScratch(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipmapped mipmapped,GrProtected isProtected)92 sk_sp<GrTexture> GrResourceProvider::getExactScratch(SkISize dimensions,
93                                                      const GrBackendFormat& format,
94                                                      GrRenderable renderable,
95                                                      int renderTargetSampleCnt,
96                                                      SkBudgeted budgeted,
97                                                      GrMipmapped mipmapped,
98                                                      GrProtected isProtected) {
99     sk_sp<GrTexture> tex(this->findAndRefScratchTexture(dimensions, format, renderable,
100                                                         renderTargetSampleCnt, mipmapped,
101                                                         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, GrMipmapped::kNo, isProtected, &mipLevel);
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->findAndRefScratchTexture(copyDimensions, format, renderable,
244                                                   renderTargetSampleCnt, GrMipmapped::kNo,
245                                                   isProtected)) {
246         return tex;
247     }
248 
249     return fGpu->createTexture(copyDimensions, format, renderable, renderTargetSampleCnt,
250                                GrMipmapped::kNo, SkBudgeted::kYes, isProtected);
251 }
252 
findAndRefScratchTexture(const GrScratchKey & key)253 sk_sp<GrTexture> GrResourceProvider::findAndRefScratchTexture(const GrScratchKey& key) {
254     ASSERT_SINGLE_OWNER
255     SkASSERT(!this->isAbandoned());
256     SkASSERT(key.isValid());
257 
258     if (GrGpuResource* resource = fCache->findAndRefScratchResource(key)) {
259         fGpu->stats()->incNumScratchTexturesReused();
260         GrSurface* surface = static_cast<GrSurface*>(resource);
261         return sk_sp<GrTexture>(surface->asTexture());
262     }
263     return nullptr;
264 }
265 
findAndRefScratchTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipmapped,GrProtected isProtected)266 sk_sp<GrTexture> GrResourceProvider::findAndRefScratchTexture(SkISize dimensions,
267                                                               const GrBackendFormat& format,
268                                                               GrRenderable renderable,
269                                                               int renderTargetSampleCnt,
270                                                               GrMipmapped mipmapped,
271                                                               GrProtected isProtected) {
272     ASSERT_SINGLE_OWNER
273     SkASSERT(!this->isAbandoned());
274     SkASSERT(!this->caps()->isFormatCompressed(format));
275     SkASSERT(fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
276                                           GrMipmapped::kNo));
277 
278     // We could make initial clears work with scratch textures but it is a rare case so we just opt
279     // to fall back to making a new texture.
280     if (fGpu->caps()->reuseScratchTextures() || renderable == GrRenderable::kYes) {
281         GrScratchKey key;
282         GrTexture::ComputeScratchKey(*this->caps(), format, dimensions, renderable,
283                                      renderTargetSampleCnt, mipmapped, isProtected, &key);
284         return this->findAndRefScratchTexture(key);
285     }
286 
287     return nullptr;
288 }
289 
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)290 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
291                                                         GrWrapOwnership ownership,
292                                                         GrWrapCacheable cacheable,
293                                                         GrIOType ioType) {
294     ASSERT_SINGLE_OWNER
295     if (this->isAbandoned()) {
296         return nullptr;
297     }
298     return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType);
299 }
300 
wrapCompressedBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable)301 sk_sp<GrTexture> GrResourceProvider::wrapCompressedBackendTexture(const GrBackendTexture& tex,
302                                                                   GrWrapOwnership ownership,
303                                                                   GrWrapCacheable cacheable) {
304     ASSERT_SINGLE_OWNER
305     if (this->isAbandoned()) {
306         return nullptr;
307     }
308 
309     return fGpu->wrapCompressedBackendTexture(tex, ownership, cacheable);
310 }
311 
312 
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)313 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
314                                                                   int sampleCnt,
315                                                                   GrWrapOwnership ownership,
316                                                                   GrWrapCacheable cacheable) {
317     ASSERT_SINGLE_OWNER
318     if (this->isAbandoned()) {
319         return nullptr;
320     }
321     return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable);
322 }
323 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)324 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
325         const GrBackendRenderTarget& backendRT) {
326     ASSERT_SINGLE_OWNER
327     return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
328 }
329 
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)330 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
331         const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
332     ASSERT_SINGLE_OWNER
333     return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
334                                                                                      vkInfo);
335 
336 }
337 
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)338 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
339                                                    GrGpuResource* resource) {
340     ASSERT_SINGLE_OWNER
341     if (this->isAbandoned() || !resource) {
342         return;
343     }
344     resource->resourcePriv().setUniqueKey(key);
345 }
346 
findResourceByUniqueKey(const GrUniqueKey & key)347 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
348     ASSERT_SINGLE_OWNER
349     return this->isAbandoned() ? nullptr
350                                : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
351 }
352 
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)353 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
354                                                                     size_t size,
355                                                                     const void* data,
356                                                                     const GrUniqueKey& key) {
357     if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
358         return std::move(buffer);
359     }
360     if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
361         // We shouldn't bin and/or cache static buffers.
362         SkASSERT(buffer->size() == size);
363         SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
364         buffer->resourcePriv().setUniqueKey(key);
365         return sk_sp<const GrGpuBuffer>(buffer);
366     }
367     return nullptr;
368 }
369 
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey * key)370 sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
371                                                                         int patternSize,
372                                                                         int reps,
373                                                                         int vertCount,
374                                                                         const GrUniqueKey* key) {
375     size_t bufferSize = patternSize * reps * sizeof(uint16_t);
376 
377     sk_sp<GrGpuBuffer> buffer(
378             this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
379     if (!buffer) {
380         return nullptr;
381     }
382     uint16_t* data = (uint16_t*) buffer->map();
383     SkAutoTArray<uint16_t> temp;
384     if (!data) {
385         temp.reset(reps * patternSize);
386         data = temp.get();
387     }
388     for (int i = 0; i < reps; ++i) {
389         int baseIdx = i * patternSize;
390         uint16_t baseVert = (uint16_t)(i * vertCount);
391         for (int j = 0; j < patternSize; ++j) {
392             data[baseIdx+j] = baseVert + pattern[j];
393         }
394     }
395     if (temp.get()) {
396         if (!buffer->updateData(data, bufferSize)) {
397             return nullptr;
398         }
399     } else {
400         buffer->unmap();
401     }
402     if (key) {
403         SkASSERT(key->isValid());
404         this->assignUniqueKeyToResource(*key, buffer.get());
405     }
406     return std::move(buffer);
407 }
408 
409 ///////////////////////////////////////////////////////////////////////////////////////////////////
410 static constexpr int kMaxNumNonAAQuads = 1 << 12;  // max possible: (1 << 14) - 1;
411 static const int kVertsPerNonAAQuad = 4;
412 static const int kIndicesPerNonAAQuad = 6;
413 
createNonAAQuadIndexBuffer()414 sk_sp<const GrGpuBuffer> GrResourceProvider::createNonAAQuadIndexBuffer() {
415     static_assert(kVertsPerNonAAQuad * kMaxNumNonAAQuads <= 65535);  // indices fit in a uint16_t
416 
417     static const uint16_t kNonAAQuadIndexPattern[] = {
418         0, 1, 2, 2, 1, 3
419     };
420 
421     static_assert(SK_ARRAY_COUNT(kNonAAQuadIndexPattern) == kIndicesPerNonAAQuad);
422 
423     return this->createPatternedIndexBuffer(kNonAAQuadIndexPattern, kIndicesPerNonAAQuad,
424                                             kMaxNumNonAAQuads, kVertsPerNonAAQuad, nullptr);
425 }
426 
MaxNumNonAAQuads()427 int GrResourceProvider::MaxNumNonAAQuads() { return kMaxNumNonAAQuads; }
NumVertsPerNonAAQuad()428 int GrResourceProvider::NumVertsPerNonAAQuad() { return kVertsPerNonAAQuad; }
NumIndicesPerNonAAQuad()429 int GrResourceProvider::NumIndicesPerNonAAQuad() { return kIndicesPerNonAAQuad; }
430 
431 ///////////////////////////////////////////////////////////////////////////////////////////////////
432 static constexpr int kMaxNumAAQuads = 1 << 9;  // max possible: (1 << 13) - 1;
433 static const int kVertsPerAAQuad = 8;
434 static const int kIndicesPerAAQuad = 30;
435 
createAAQuadIndexBuffer()436 sk_sp<const GrGpuBuffer> GrResourceProvider::createAAQuadIndexBuffer() {
437     static_assert(kVertsPerAAQuad * kMaxNumAAQuads <= 65535);  // indices fit in a uint16_t
438 
439     // clang-format off
440     static const uint16_t kAAQuadIndexPattern[] = {
441         0, 1, 2, 1, 3, 2,
442         0, 4, 1, 4, 5, 1,
443         0, 6, 4, 0, 2, 6,
444         2, 3, 6, 3, 7, 6,
445         1, 5, 3, 3, 5, 7,
446     };
447     // clang-format on
448 
449     static_assert(SK_ARRAY_COUNT(kAAQuadIndexPattern) == kIndicesPerAAQuad);
450 
451     return this->createPatternedIndexBuffer(kAAQuadIndexPattern, kIndicesPerAAQuad,
452                                             kMaxNumAAQuads, kVertsPerAAQuad, nullptr);
453 }
454 
MaxNumAAQuads()455 int GrResourceProvider::MaxNumAAQuads() { return kMaxNumAAQuads; }
NumVertsPerAAQuad()456 int GrResourceProvider::NumVertsPerAAQuad() { return kVertsPerAAQuad; }
NumIndicesPerAAQuad()457 int GrResourceProvider::NumIndicesPerAAQuad() { return kIndicesPerAAQuad; }
458 
459 ///////////////////////////////////////////////////////////////////////////////////////////////////
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)460 sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
461                                                     GrAccessPattern accessPattern,
462                                                     const void* data) {
463     if (this->isAbandoned()) {
464         return nullptr;
465     }
466     if (kDynamic_GrAccessPattern != accessPattern) {
467         return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
468     }
469     // bin by pow2+midpoint with a reasonable min
470     static const size_t MIN_SIZE = 1 << 12;
471     static const size_t MIN_UNIFORM_SIZE = 1 << 7;
472     size_t allocSize = intendedType == GrGpuBufferType::kUniform ? std::max(size, MIN_UNIFORM_SIZE)
473                                                                  : std::max(size, MIN_SIZE);
474     size_t ceilPow2 = GrNextSizePow2(allocSize);
475     size_t floorPow2 = ceilPow2 >> 1;
476     size_t mid = floorPow2 + (floorPow2 >> 1);
477     allocSize = (allocSize <= mid) ? mid : ceilPow2;
478 
479     GrScratchKey key;
480     GrGpuBuffer::ComputeScratchKeyForDynamicBuffer(allocSize, intendedType, &key);
481     auto buffer =
482             sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
483                     key)));
484     if (!buffer) {
485         buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
486         if (!buffer) {
487             return nullptr;
488         }
489     }
490     if (data) {
491         buffer->updateData(data, size);
492     }
493     return buffer;
494 }
495 
num_stencil_samples(const GrRenderTarget * rt,bool useMSAASurface,const GrCaps & caps)496 static int num_stencil_samples(const GrRenderTarget* rt, bool useMSAASurface, const GrCaps& caps) {
497     int numSamples = rt->numSamples();
498     if (numSamples == 1 && useMSAASurface) {  // Are we using dynamic msaa?
499         numSamples = caps.internalMultisampleCount(rt->backendFormat());
500         SkASSERT(numSamples > 1);  // Caller must ensure dmsaa is supported before trying to use it.
501     }
502     return numSamples;
503 }
504 
attachStencilAttachment(GrRenderTarget * rt,bool useMSAASurface)505 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, bool useMSAASurface) {
506     SkASSERT(rt);
507     SkASSERT(!this->caps()->avoidStencilBuffers());
508 
509     GrAttachment* stencil = rt->getStencilAttachment(useMSAASurface);
510     if (stencil) {
511         SkASSERT(stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
512         return true;
513     }
514 
515     if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment(useMSAASurface)) {
516         GrUniqueKey sbKey;
517 
518 #if 0
519         if (this->caps()->oversizedStencilSupport()) {
520             width  = SkNextPow2(width);
521             height = SkNextPow2(height);
522         }
523 #endif
524         GrBackendFormat stencilFormat = this->gpu()->getPreferredStencilFormat(rt->backendFormat());
525         if (!stencilFormat.isValid()) {
526             return false;
527         }
528         GrProtected isProtected = rt->isProtected() ? GrProtected::kYes : GrProtected::kNo;
529         int numStencilSamples = num_stencil_samples(rt, useMSAASurface, *this->caps());
530         GrAttachment::ComputeSharedAttachmentUniqueKey(
531                 *this->caps(), stencilFormat, rt->dimensions(),
532                 GrAttachment::UsageFlags::kStencilAttachment, numStencilSamples, GrMipmapped::kNo,
533                 isProtected, &sbKey);
534         auto stencil = this->findByUniqueKey<GrAttachment>(sbKey);
535         if (!stencil) {
536             // Need to try and create a new stencil
537             stencil = this->gpu()->makeStencilAttachment(rt->backendFormat(), rt->dimensions(),
538                                                          numStencilSamples);
539             if (!stencil) {
540                 return false;
541             }
542             this->assignUniqueKeyToResource(sbKey, stencil.get());
543         }
544         rt->attachStencilAttachment(std::move(stencil), useMSAASurface);
545     }
546     stencil = rt->getStencilAttachment(useMSAASurface);
547     SkASSERT(!stencil ||
548              stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
549     return stencil != nullptr;
550 }
551 
makeMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected)552 sk_sp<GrAttachment> GrResourceProvider::makeMSAAAttachment(SkISize dimensions,
553                                                            const GrBackendFormat& format,
554                                                            int sampleCnt,
555                                                            GrProtected isProtected) {
556     ASSERT_SINGLE_OWNER
557 
558     SkASSERT(sampleCnt > 1);
559 
560     if (this->isAbandoned()) {
561         return nullptr;
562     }
563 
564     if (!fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
565                                       GrMipmapped::kNo)) {
566         return nullptr;
567     }
568 
569     auto scratch = this->refScratchMSAAAttachment(dimensions, format, sampleCnt, isProtected);
570     if (scratch) {
571         return scratch;
572     }
573 
574     return fGpu->makeMSAAAttachment(dimensions, format, sampleCnt, isProtected);
575 }
576 
refScratchMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected)577 sk_sp<GrAttachment> GrResourceProvider::refScratchMSAAAttachment(SkISize dimensions,
578                                                                  const GrBackendFormat& format,
579                                                                  int sampleCnt,
580                                                                  GrProtected isProtected) {
581     ASSERT_SINGLE_OWNER
582     SkASSERT(!this->isAbandoned());
583     SkASSERT(!this->caps()->isFormatCompressed(format));
584     SkASSERT(fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
585                                           GrMipmapped::kNo));
586 
587     GrScratchKey key;
588     GrAttachment::ComputeScratchKey(*this->caps(), format, dimensions,
589                                     GrAttachment::UsageFlags::kColorAttachment, sampleCnt,
590                                     GrMipmapped::kNo, isProtected, &key);
591     GrGpuResource* resource = fCache->findAndRefScratchResource(key);
592     if (resource) {
593         fGpu->stats()->incNumScratchMSAAAttachmentsReused();
594         GrAttachment* attachment = static_cast<GrAttachment*>(resource);
595         return sk_sp<GrAttachment>(attachment);
596     }
597 
598     return nullptr;
599 }
600 
makeSemaphore(bool isOwned)601 std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(
602         bool isOwned) {
603     return this->isAbandoned() ? nullptr : fGpu->makeSemaphore(isOwned);
604 }
605 
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)606 std::unique_ptr<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(
607         const GrBackendSemaphore& semaphore,
608         SemaphoreWrapType wrapType,
609         GrWrapOwnership ownership) {
610     ASSERT_SINGLE_OWNER
611     return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
612                                                                       wrapType,
613                                                                       ownership);
614 }
615 
616 // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
617 // 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)618 static bool prepare_level(const GrMipLevel& inLevel,
619                           SkISize dimensions,
620                           bool rowBytesSupport,
621                           GrColorType origColorType,
622                           GrColorType allowedColorType,
623                           GrMipLevel* outLevel,
624                           std::unique_ptr<char[]>* data) {
625     if (!inLevel.fPixels) {
626         outLevel->fPixels = nullptr;
627         outLevel->fRowBytes = 0;
628         return true;
629     }
630     size_t minRB = dimensions.fWidth * GrColorTypeBytesPerPixel(origColorType);
631     size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
632     if (actualRB < minRB) {
633         return false;
634     }
635     if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
636         outLevel->fRowBytes = actualRB;
637         outLevel->fPixels = inLevel.fPixels;
638         return true;
639     }
640     auto tempRB = dimensions.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
641     data->reset(new char[tempRB * dimensions.fHeight]);
642     outLevel->fPixels = data->get();
643     outLevel->fRowBytes = tempRB;
644     GrImageInfo srcInfo(   origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
645     GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
646     return GrConvertPixels( GrPixmap(dstInfo,     data->get(),   tempRB),
647                            GrCPixmap(srcInfo, inLevel.fPixels, actualRB));
648 }
649 
prepareLevels(const GrBackendFormat & format,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount,TempLevels * tempLevels,TempLevelDatas * tempLevelDatas) const650 GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
651                                               GrColorType colorType,
652                                               SkISize baseSize,
653                                               const GrMipLevel texels[],
654                                               int mipLevelCount,
655                                               TempLevels* tempLevels,
656                                               TempLevelDatas* tempLevelDatas) const {
657     SkASSERT(mipLevelCount && texels && texels[0].fPixels);
658 
659     auto allowedColorType =
660             this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
661     if (allowedColorType == GrColorType::kUnknown) {
662         return GrColorType::kUnknown;
663     }
664     bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
665     tempLevels->reset(mipLevelCount);
666     tempLevelDatas->reset(mipLevelCount);
667     auto size = baseSize;
668     for (int i = 0; i < mipLevelCount; ++i) {
669         if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
670                            &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
671             return GrColorType::kUnknown;
672         }
673         size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
674     }
675     return allowedColorType;
676 }
677 
writePixels(sk_sp<GrTexture> texture,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount) const678 sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
679                                                  GrColorType colorType,
680                                                  SkISize baseSize,
681                                                  const GrMipLevel texels[],
682                                                  int mipLevelCount) const {
683     SkASSERT(!this->isAbandoned());
684     SkASSERT(texture);
685     SkASSERT(colorType != GrColorType::kUnknown);
686     SkASSERT(mipLevelCount && texels && texels[0].fPixels);
687 
688     SkAutoSTArray<14, GrMipLevel> tmpTexels;
689     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
690     auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
691                                              mipLevelCount, &tmpTexels, &tmpDatas);
692     if (tempColorType == GrColorType::kUnknown) {
693         return nullptr;
694     }
695     SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
696                                      colorType, tempColorType, tmpTexels.get(), mipLevelCount));
697     return texture;
698 }
699