• 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/SingleOwner.h"
12 #include "src/core/SkConvertPixels.h"
13 #include "src/core/SkMathPriv.h"
14 #include "src/core/SkMipmap.h"
15 #include "src/gpu/BufferWriter.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/ResourceKey.h"
28 #include "src/gpu/SkGr.h"
29 
30 const int GrResourceProvider::kMinScratchTextureSize = 16;
31 
32 #define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(fSingleOwner)
33 
GrResourceProvider(GrGpu * gpu,GrResourceCache * cache,skgpu::SingleOwner * owner)34 GrResourceProvider::GrResourceProvider(GrGpu* gpu,
35                                        GrResourceCache* cache,
36                                        skgpu::SingleOwner* 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,GrTextureType textureType,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipmapped mipmapped,GrProtected isProtected,const GrMipLevel texels[])46 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
47                                                    const GrBackendFormat& format,
48                                                    GrTextureType textureType,
49                                                    GrColorType colorType,
50                                                    GrRenderable renderable,
51                                                    int renderTargetSampleCnt,
52                                                    SkBudgeted budgeted,
53                                                    GrMipmapped mipmapped,
54                                                    GrProtected isProtected,
55                                                    const GrMipLevel texels[]) {
56     ASSERT_SINGLE_OWNER
57 
58     if (this->isAbandoned()) {
59         return nullptr;
60     }
61 
62     int numMipLevels = 1;
63     if (mipmapped == GrMipmapped::kYes) {
64         numMipLevels = SkMipmap::ComputeLevelCount(dimensions.fWidth, dimensions.fHeight) + 1;
65     }
66 
67     if (!fCaps->validateSurfaceParams(dimensions,
68                                       format,
69                                       renderable,
70                                       renderTargetSampleCnt,
71                                       mipmapped,
72                                       textureType)) {
73         return nullptr;
74     }
75     // Current rule is that you can provide no level data, just the base, or all the levels.
76     bool hasPixels = texels[0].fPixels;
77     auto scratch = this->getExactScratch(dimensions,
78                                          format,
79                                          textureType,
80                                          renderable,
81                                          renderTargetSampleCnt,
82                                          budgeted,
83                                          mipmapped,
84                                          isProtected);
85     if (scratch) {
86         if (!hasPixels) {
87             return scratch;
88         }
89         return this->writePixels(std::move(scratch), colorType, dimensions, texels, numMipLevels);
90     }
91     SkAutoSTArray<14, GrMipLevel> tmpTexels;
92     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
93     GrColorType tempColorType = GrColorType::kUnknown;
94     if (hasPixels) {
95         tempColorType = this->prepareLevels(format, colorType, dimensions, texels, numMipLevels,
96                                             &tmpTexels, &tmpDatas);
97         if (tempColorType == GrColorType::kUnknown) {
98             return nullptr;
99         }
100     }
101     return fGpu->createTexture(dimensions,
102                                format,
103                                textureType,
104                                renderable,
105                                renderTargetSampleCnt,
106                                budgeted,
107                                isProtected,
108                                colorType,
109                                tempColorType,
110                                tmpTexels.get(),
111                                numMipLevels);
112 }
113 
getExactScratch(SkISize dimensions,const GrBackendFormat & format,GrTextureType textureType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipmapped mipmapped,GrProtected isProtected)114 sk_sp<GrTexture> GrResourceProvider::getExactScratch(SkISize dimensions,
115                                                      const GrBackendFormat& format,
116                                                      GrTextureType textureType,
117                                                      GrRenderable renderable,
118                                                      int renderTargetSampleCnt,
119                                                      SkBudgeted budgeted,
120                                                      GrMipmapped mipmapped,
121                                                      GrProtected isProtected) {
122     sk_sp<GrTexture> tex(this->findAndRefScratchTexture(dimensions,
123                                                         format,
124                                                         textureType,
125                                                         renderable,
126                                                         renderTargetSampleCnt,
127                                                         mipmapped,
128                                                         isProtected));
129     if (tex && SkBudgeted::kNo == budgeted) {
130         tex->resourcePriv().makeUnbudgeted();
131     }
132 
133     return tex;
134 }
135 
createTexture(SkISize dimensions,const GrBackendFormat & format,GrTextureType textureType,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,SkBackingFit fit,GrProtected isProtected,const GrMipLevel & mipLevel)136 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
137                                                    const GrBackendFormat& format,
138                                                    GrTextureType textureType,
139                                                    GrColorType colorType,
140                                                    GrRenderable renderable,
141                                                    int renderTargetSampleCnt,
142                                                    SkBudgeted budgeted,
143                                                    SkBackingFit fit,
144                                                    GrProtected isProtected,
145                                                    const GrMipLevel& mipLevel) {
146     ASSERT_SINGLE_OWNER
147 
148     if (!mipLevel.fPixels) {
149         return nullptr;
150     }
151 
152     if (SkBackingFit::kApprox == fit) {
153         if (this->isAbandoned()) {
154             return nullptr;
155         }
156         if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
157                                           GrMipmapped::kNo, textureType)) {
158             return nullptr;
159         }
160 
161         auto tex = this->createApproxTexture(dimensions, format, textureType, renderable,
162                                              renderTargetSampleCnt, isProtected);
163         if (!tex) {
164             return nullptr;
165         }
166         return this->writePixels(std::move(tex), colorType, dimensions, &mipLevel, 1);
167     } else {
168         return this->createTexture(dimensions,
169                                    format,
170                                    textureType,
171                                    colorType,
172                                    renderable,
173                                    renderTargetSampleCnt,
174                                    budgeted,
175                                    GrMipmapped::kNo,
176                                    isProtected,
177                                    &mipLevel);
178     }
179 }
180 
createCompressedTexture(SkISize dimensions,const GrBackendFormat & format,SkBudgeted budgeted,GrMipmapped mipmapped,GrProtected isProtected,SkData * data)181 sk_sp<GrTexture> GrResourceProvider::createCompressedTexture(SkISize dimensions,
182                                                              const GrBackendFormat& format,
183                                                              SkBudgeted budgeted,
184                                                              GrMipmapped mipmapped,
185                                                              GrProtected isProtected,
186                                                              SkData* data) {
187     ASSERT_SINGLE_OWNER
188     if (this->isAbandoned()) {
189         return nullptr;
190     }
191     return fGpu->createCompressedTexture(dimensions, format, budgeted, mipmapped,
192                                          isProtected, data->data(), data->size());
193 }
194 
createTexture(SkISize dimensions,const GrBackendFormat & format,GrTextureType textureType,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipmapped,SkBudgeted budgeted,GrProtected isProtected)195 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
196                                                    const GrBackendFormat& format,
197                                                    GrTextureType textureType,
198                                                    GrRenderable renderable,
199                                                    int renderTargetSampleCnt,
200                                                    GrMipmapped mipmapped,
201                                                    SkBudgeted budgeted,
202                                                    GrProtected isProtected) {
203     ASSERT_SINGLE_OWNER
204     if (this->isAbandoned()) {
205         return nullptr;
206     }
207 
208     if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
209                                       mipmapped, textureType)) {
210         return nullptr;
211     }
212 
213     // Currently we don't recycle compressed textures as scratch. Additionally all compressed
214     // textures should be created through the createCompressedTexture function.
215     SkASSERT(!this->caps()->isFormatCompressed(format));
216 
217     // TODO: Support GrMipmapped::kYes in scratch texture lookup here.
218     sk_sp<GrTexture> tex =
219             this->getExactScratch(dimensions,
220                                   format,
221                                   textureType,
222                                   renderable,
223                                   renderTargetSampleCnt,
224                                   budgeted,
225                                   mipmapped,
226                                   isProtected);
227     if (tex) {
228         return tex;
229     }
230 
231     return fGpu->createTexture(dimensions,
232                                format,
233                                textureType,
234                                renderable,
235                                renderTargetSampleCnt,
236                                mipmapped,
237                                budgeted,
238                                isProtected);
239 }
240 
241 // Map 'value' to a larger multiple of 2. Values <= 'kMagicTol' will pop up to
242 // the next power of 2. Those above 'kMagicTol' will only go up half the floor power of 2.
MakeApprox(SkISize dimensions)243 SkISize GrResourceProvider::MakeApprox(SkISize dimensions) {
244     auto adjust = [](int value) {
245         static const int kMagicTol = 1024;
246 
247         value = std::max(kMinScratchTextureSize, value);
248 
249         if (SkIsPow2(value)) {
250             return value;
251         }
252 
253         int ceilPow2 = SkNextPow2(value);
254         if (value <= kMagicTol) {
255             return ceilPow2;
256         }
257 
258         int floorPow2 = ceilPow2 >> 1;
259         int mid = floorPow2 + (floorPow2 >> 1);
260 
261         if (value <= mid) {
262             return mid;
263         }
264         return ceilPow2;
265     };
266 
267     return {adjust(dimensions.width()), adjust(dimensions.height())};
268 }
269 
createApproxTexture(SkISize dimensions,const GrBackendFormat & format,GrTextureType textureType,GrRenderable renderable,int renderTargetSampleCnt,GrProtected isProtected)270 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(SkISize dimensions,
271                                                          const GrBackendFormat& format,
272                                                          GrTextureType textureType,
273                                                          GrRenderable renderable,
274                                                          int renderTargetSampleCnt,
275                                                          GrProtected isProtected) {
276     ASSERT_SINGLE_OWNER
277 
278     if (this->isAbandoned()) {
279         return nullptr;
280     }
281 
282     // Currently we don't recycle compressed textures as scratch. Additionally all compressed
283     // textures should be created through the createCompressedTexture function.
284     SkASSERT(!this->caps()->isFormatCompressed(format));
285 
286     if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
287                                       GrMipmapped::kNo, textureType)) {
288         return nullptr;
289     }
290 
291     auto copyDimensions = MakeApprox(dimensions);
292 
293     if (auto tex = this->findAndRefScratchTexture(copyDimensions, format, textureType, renderable,
294                                                   renderTargetSampleCnt, GrMipmapped::kNo,
295                                                   isProtected)) {
296         return tex;
297     }
298 
299     return fGpu->createTexture(copyDimensions,
300                                format,
301                                textureType,
302                                renderable,
303                                renderTargetSampleCnt,
304                                GrMipmapped::kNo,
305                                SkBudgeted::kYes,
306                                isProtected);
307 }
308 
findAndRefScratchTexture(const skgpu::ScratchKey & key)309 sk_sp<GrTexture> GrResourceProvider::findAndRefScratchTexture(const skgpu::ScratchKey& key) {
310     ASSERT_SINGLE_OWNER
311     SkASSERT(!this->isAbandoned());
312     SkASSERT(key.isValid());
313 
314     if (GrGpuResource* resource = fCache->findAndRefScratchResource(key)) {
315         fGpu->stats()->incNumScratchTexturesReused();
316         GrSurface* surface = static_cast<GrSurface*>(resource);
317         return sk_sp<GrTexture>(surface->asTexture());
318     }
319     return nullptr;
320 }
321 
findAndRefScratchTexture(SkISize dimensions,const GrBackendFormat & format,GrTextureType textureType,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipmapped,GrProtected isProtected)322 sk_sp<GrTexture> GrResourceProvider::findAndRefScratchTexture(SkISize dimensions,
323                                                               const GrBackendFormat& format,
324                                                               GrTextureType textureType,
325                                                               GrRenderable renderable,
326                                                               int renderTargetSampleCnt,
327                                                               GrMipmapped mipmapped,
328                                                               GrProtected isProtected) {
329     ASSERT_SINGLE_OWNER
330     SkASSERT(!this->isAbandoned());
331     SkASSERT(!this->caps()->isFormatCompressed(format));
332     SkASSERT(fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
333                                           GrMipmapped::kNo, textureType));
334 
335     // We could make initial clears work with scratch textures but it is a rare case so we just opt
336     // to fall back to making a new texture.
337     if (fGpu->caps()->reuseScratchTextures() || renderable == GrRenderable::kYes) {
338         skgpu::ScratchKey key;
339         GrTexture::ComputeScratchKey(*this->caps(), format, dimensions, renderable,
340                                      renderTargetSampleCnt, mipmapped, isProtected, &key);
341         return this->findAndRefScratchTexture(key);
342     }
343 
344     return nullptr;
345 }
346 
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)347 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
348                                                         GrWrapOwnership ownership,
349                                                         GrWrapCacheable cacheable,
350                                                         GrIOType ioType) {
351     ASSERT_SINGLE_OWNER
352     if (this->isAbandoned()) {
353         return nullptr;
354     }
355     return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType);
356 }
357 
wrapCompressedBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable)358 sk_sp<GrTexture> GrResourceProvider::wrapCompressedBackendTexture(const GrBackendTexture& tex,
359                                                                   GrWrapOwnership ownership,
360                                                                   GrWrapCacheable cacheable) {
361     ASSERT_SINGLE_OWNER
362     if (this->isAbandoned()) {
363         return nullptr;
364     }
365 
366     return fGpu->wrapCompressedBackendTexture(tex, ownership, cacheable);
367 }
368 
369 
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)370 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
371                                                                   int sampleCnt,
372                                                                   GrWrapOwnership ownership,
373                                                                   GrWrapCacheable cacheable) {
374     ASSERT_SINGLE_OWNER
375     if (this->isAbandoned()) {
376         return nullptr;
377     }
378     return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable);
379 }
380 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)381 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
382         const GrBackendRenderTarget& backendRT) {
383     ASSERT_SINGLE_OWNER
384     return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
385 }
386 
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)387 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
388         const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
389     ASSERT_SINGLE_OWNER
390     return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
391                                                                                      vkInfo);
392 
393 }
394 
assignUniqueKeyToResource(const skgpu::UniqueKey & key,GrGpuResource * resource)395 void GrResourceProvider::assignUniqueKeyToResource(const skgpu::UniqueKey& key,
396                                                    GrGpuResource* resource) {
397     ASSERT_SINGLE_OWNER
398     if (this->isAbandoned() || !resource) {
399         return;
400     }
401     resource->resourcePriv().setUniqueKey(key);
402 }
403 
findResourceByUniqueKey(const skgpu::UniqueKey & key)404 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const skgpu::UniqueKey& key) {
405     ASSERT_SINGLE_OWNER
406     return this->isAbandoned() ? nullptr
407                                : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
408 }
409 
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const void * staticData,const skgpu::UniqueKey & key)410 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
411                                                                     size_t size,
412                                                                     const void* staticData,
413                                                                     const skgpu::UniqueKey& key) {
414     if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
415         return std::move(buffer);
416     }
417     if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, staticData)) {
418         // We shouldn't bin and/or cache static buffers.
419         SkASSERT(buffer->size() == size);
420         SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
421         buffer->resourcePriv().setUniqueKey(key);
422         return sk_sp<const GrGpuBuffer>(buffer);
423     }
424     return nullptr;
425 }
426 
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const skgpu::UniqueKey & uniqueKey,InitializeBufferFn initializeBufferFn)427 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(
428         GrGpuBufferType intendedType,
429         size_t size,
430         const skgpu::UniqueKey& uniqueKey,
431         InitializeBufferFn initializeBufferFn) {
432     if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(uniqueKey)) {
433         return std::move(buffer);
434     }
435     if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern)) {
436         // We shouldn't bin and/or cache static buffers.
437         SkASSERT(buffer->size() == size);
438         SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
439         buffer->resourcePriv().setUniqueKey(uniqueKey);
440 
441         // Map the buffer. Use a staging buffer on the heap if mapping isn't supported.
442         skgpu::VertexWriter vertexWriter = {buffer->map(), size};
443         SkAutoTMalloc<char> stagingBuffer;
444         if (!vertexWriter) {
445             SkASSERT(!buffer->isMapped());
446             vertexWriter = {stagingBuffer.reset(size), size};
447         }
448 
449         initializeBufferFn(std::move(vertexWriter), size);
450 
451         if (buffer->isMapped()) {
452             buffer->unmap();
453         } else {
454             buffer->updateData(stagingBuffer, size);
455         }
456         return std::move(buffer);
457     }
458     return nullptr;
459 }
460 
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const skgpu::UniqueKey * key)461 sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(
462         const uint16_t* pattern,
463         int patternSize,
464         int reps,
465         int vertCount,
466         const skgpu::UniqueKey* key) {
467     size_t bufferSize = patternSize * reps * sizeof(uint16_t);
468 
469     sk_sp<GrGpuBuffer> buffer(
470             this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
471     if (!buffer) {
472         return nullptr;
473     }
474     uint16_t* data = (uint16_t*) buffer->map();
475     SkAutoTArray<uint16_t> temp;
476     if (!data) {
477         temp.reset(reps * patternSize);
478         data = temp.get();
479     }
480     for (int i = 0; i < reps; ++i) {
481         int baseIdx = i * patternSize;
482         uint16_t baseVert = (uint16_t)(i * vertCount);
483         for (int j = 0; j < patternSize; ++j) {
484             data[baseIdx+j] = baseVert + pattern[j];
485         }
486     }
487     if (temp.get()) {
488         if (!buffer->updateData(data, bufferSize)) {
489             return nullptr;
490         }
491     } else {
492         buffer->unmap();
493     }
494     if (key) {
495         SkASSERT(key->isValid());
496         this->assignUniqueKeyToResource(*key, buffer.get());
497     }
498     return std::move(buffer);
499 }
500 
501 ///////////////////////////////////////////////////////////////////////////////////////////////////
502 static constexpr int kMaxNumNonAAQuads = 1 << 12;  // max possible: (1 << 14) - 1;
503 static const int kVertsPerNonAAQuad = 4;
504 static const int kIndicesPerNonAAQuad = 6;
505 
createNonAAQuadIndexBuffer()506 sk_sp<const GrGpuBuffer> GrResourceProvider::createNonAAQuadIndexBuffer() {
507     static_assert(kVertsPerNonAAQuad * kMaxNumNonAAQuads <= 65535);  // indices fit in a uint16_t
508 
509     static const uint16_t kNonAAQuadIndexPattern[] = {
510         0, 1, 2, 2, 1, 3
511     };
512 
513     static_assert(SK_ARRAY_COUNT(kNonAAQuadIndexPattern) == kIndicesPerNonAAQuad);
514 
515     return this->createPatternedIndexBuffer(kNonAAQuadIndexPattern, kIndicesPerNonAAQuad,
516                                             kMaxNumNonAAQuads, kVertsPerNonAAQuad, nullptr);
517 }
518 
MaxNumNonAAQuads()519 int GrResourceProvider::MaxNumNonAAQuads() { return kMaxNumNonAAQuads; }
NumVertsPerNonAAQuad()520 int GrResourceProvider::NumVertsPerNonAAQuad() { return kVertsPerNonAAQuad; }
NumIndicesPerNonAAQuad()521 int GrResourceProvider::NumIndicesPerNonAAQuad() { return kIndicesPerNonAAQuad; }
522 
523 ///////////////////////////////////////////////////////////////////////////////////////////////////
524 static constexpr int kMaxNumAAQuads = 1 << 9;  // max possible: (1 << 13) - 1;
525 static const int kVertsPerAAQuad = 8;
526 static const int kIndicesPerAAQuad = 30;
527 
createAAQuadIndexBuffer()528 sk_sp<const GrGpuBuffer> GrResourceProvider::createAAQuadIndexBuffer() {
529     static_assert(kVertsPerAAQuad * kMaxNumAAQuads <= 65535);  // indices fit in a uint16_t
530 
531     // clang-format off
532     static const uint16_t kAAQuadIndexPattern[] = {
533         0, 1, 2, 1, 3, 2,
534         0, 4, 1, 4, 5, 1,
535         0, 6, 4, 0, 2, 6,
536         2, 3, 6, 3, 7, 6,
537         1, 5, 3, 3, 5, 7,
538     };
539     // clang-format on
540 
541     static_assert(SK_ARRAY_COUNT(kAAQuadIndexPattern) == kIndicesPerAAQuad);
542 
543     return this->createPatternedIndexBuffer(kAAQuadIndexPattern, kIndicesPerAAQuad,
544                                             kMaxNumAAQuads, kVertsPerAAQuad, nullptr);
545 }
546 
MaxNumAAQuads()547 int GrResourceProvider::MaxNumAAQuads() { return kMaxNumAAQuads; }
NumVertsPerAAQuad()548 int GrResourceProvider::NumVertsPerAAQuad() { return kVertsPerAAQuad; }
NumIndicesPerAAQuad()549 int GrResourceProvider::NumIndicesPerAAQuad() { return kIndicesPerAAQuad; }
550 
551 ///////////////////////////////////////////////////////////////////////////////////////////////////
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)552 sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
553                                                     GrAccessPattern accessPattern,
554                                                     const void* data) {
555     if (this->isAbandoned()) {
556         return nullptr;
557     }
558     if (kDynamic_GrAccessPattern != accessPattern) {
559         return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
560     }
561     // bin by pow2+midpoint with a reasonable min
562     static const size_t MIN_SIZE = 1 << 12;
563     static const size_t MIN_UNIFORM_SIZE = 1 << 7;
564     size_t allocSize = intendedType == GrGpuBufferType::kUniform ? std::max(size, MIN_UNIFORM_SIZE)
565                                                                  : std::max(size, MIN_SIZE);
566     size_t ceilPow2 = GrNextSizePow2(allocSize);
567     size_t floorPow2 = ceilPow2 >> 1;
568     size_t mid = floorPow2 + (floorPow2 >> 1);
569     allocSize = (allocSize <= mid) ? mid : ceilPow2;
570 
571     skgpu::ScratchKey key;
572     GrGpuBuffer::ComputeScratchKeyForDynamicBuffer(allocSize, intendedType, &key);
573     auto buffer =
574             sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
575                     key)));
576     if (!buffer) {
577         buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
578         if (!buffer) {
579             return nullptr;
580         }
581     }
582     if (data) {
583         buffer->updateData(data, size);
584     }
585     return buffer;
586 }
587 
num_stencil_samples(const GrRenderTarget * rt,bool useMSAASurface,const GrCaps & caps)588 static int num_stencil_samples(const GrRenderTarget* rt, bool useMSAASurface, const GrCaps& caps) {
589     int numSamples = rt->numSamples();
590     if (numSamples == 1 && useMSAASurface) {  // Are we using dynamic msaa?
591         numSamples = caps.internalMultisampleCount(rt->backendFormat());
592         SkASSERT(numSamples > 1);  // Caller must ensure dmsaa is supported before trying to use it.
593     }
594     return numSamples;
595 }
596 
attachStencilAttachment(GrRenderTarget * rt,bool useMSAASurface)597 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, bool useMSAASurface) {
598     SkASSERT(rt);
599     SkASSERT(!this->caps()->avoidStencilBuffers());
600 
601     GrAttachment* stencil = rt->getStencilAttachment(useMSAASurface);
602     if (stencil) {
603         SkASSERT(stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
604         return true;
605     }
606 
607     if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment(useMSAASurface)) {
608         skgpu::UniqueKey sbKey;
609 
610 #if 0
611         if (this->caps()->oversizedStencilSupport()) {
612             width  = SkNextPow2(width);
613             height = SkNextPow2(height);
614         }
615 #endif
616         GrBackendFormat stencilFormat = this->gpu()->getPreferredStencilFormat(rt->backendFormat());
617         if (!stencilFormat.isValid()) {
618             return false;
619         }
620         GrProtected isProtected = rt->isProtected() ? GrProtected::kYes : GrProtected::kNo;
621         int numStencilSamples = num_stencil_samples(rt, useMSAASurface, *this->caps());
622         GrAttachment::ComputeSharedAttachmentUniqueKey(
623                 *this->caps(), stencilFormat, rt->dimensions(),
624                 GrAttachment::UsageFlags::kStencilAttachment, numStencilSamples, GrMipmapped::kNo,
625                 isProtected, GrMemoryless::kNo, &sbKey);
626         auto keyedStencil = this->findByUniqueKey<GrAttachment>(sbKey);
627         if (!keyedStencil) {
628             // Need to try and create a new stencil
629             keyedStencil = this->gpu()->makeStencilAttachment(rt->backendFormat(), rt->dimensions(),
630                                                               numStencilSamples);
631             if (!keyedStencil) {
632                 return false;
633             }
634             this->assignUniqueKeyToResource(sbKey, keyedStencil.get());
635         }
636         rt->attachStencilAttachment(std::move(keyedStencil), useMSAASurface);
637     }
638     stencil = rt->getStencilAttachment(useMSAASurface);
639     SkASSERT(!stencil ||
640              stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
641     return stencil != nullptr;
642 }
643 
getDiscardableMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected,GrMemoryless memoryless)644 sk_sp<GrAttachment> GrResourceProvider::getDiscardableMSAAAttachment(SkISize dimensions,
645                                                                      const GrBackendFormat& format,
646                                                                      int sampleCnt,
647                                                                      GrProtected isProtected,
648                                                                      GrMemoryless memoryless) {
649     ASSERT_SINGLE_OWNER
650 
651     SkASSERT(sampleCnt > 1);
652 
653     if (this->isAbandoned()) {
654         return nullptr;
655     }
656 
657     if (!fCaps->validateSurfaceParams(dimensions,
658                                       format,
659                                       GrRenderable::kYes,
660                                       sampleCnt,
661                                       GrMipmapped::kNo,
662                                       GrTextureType::kNone)) {
663         return nullptr;
664     }
665 
666     skgpu::UniqueKey key;
667     GrAttachment::ComputeSharedAttachmentUniqueKey(*this->caps(),
668                                                    format,
669                                                    dimensions,
670                                                    GrAttachment::UsageFlags::kColorAttachment,
671                                                    sampleCnt,
672                                                    GrMipmapped::kNo,
673                                                    isProtected,
674                                                    memoryless,
675                                                    &key);
676     auto msaaAttachment = this->findByUniqueKey<GrAttachment>(key);
677     if (msaaAttachment) {
678         return msaaAttachment;
679     }
680     msaaAttachment = this->makeMSAAAttachment(dimensions, format, sampleCnt, isProtected,
681                                               memoryless);
682     if (msaaAttachment) {
683         this->assignUniqueKeyToResource(key, msaaAttachment.get());
684     }
685     return msaaAttachment;
686 }
687 
makeMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected,GrMemoryless memoryless)688 sk_sp<GrAttachment> GrResourceProvider::makeMSAAAttachment(SkISize dimensions,
689                                                            const GrBackendFormat& format,
690                                                            int sampleCnt,
691                                                            GrProtected isProtected,
692                                                            GrMemoryless memoryless) {
693     ASSERT_SINGLE_OWNER
694 
695     SkASSERT(sampleCnt > 1);
696 
697     if (this->isAbandoned()) {
698         return nullptr;
699     }
700 
701     if (!fCaps->validateSurfaceParams(dimensions,
702                                       format,
703                                       GrRenderable::kYes,
704                                       sampleCnt,
705                                       GrMipmapped::kNo,
706                                       GrTextureType::kNone)) {
707         return nullptr;
708     }
709 
710     auto scratch = this->refScratchMSAAAttachment(dimensions,
711                                                   format,
712                                                   sampleCnt,
713                                                   isProtected,
714                                                   memoryless);
715     if (scratch) {
716         return scratch;
717     }
718 
719     return fGpu->makeMSAAAttachment(dimensions, format, sampleCnt, isProtected, memoryless);
720 }
721 
refScratchMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected,GrMemoryless memoryless)722 sk_sp<GrAttachment> GrResourceProvider::refScratchMSAAAttachment(SkISize dimensions,
723                                                                  const GrBackendFormat& format,
724                                                                  int sampleCnt,
725                                                                  GrProtected isProtected,
726                                                                  GrMemoryless memoryless) {
727     ASSERT_SINGLE_OWNER
728     SkASSERT(!this->isAbandoned());
729     SkASSERT(!this->caps()->isFormatCompressed(format));
730     SkASSERT(fCaps->validateSurfaceParams(dimensions,
731                                           format,
732                                           GrRenderable::kYes,
733                                           sampleCnt,
734                                           GrMipmapped::kNo,
735                                           GrTextureType::kNone));
736 
737     skgpu::ScratchKey key;
738     GrAttachment::ComputeScratchKey(*this->caps(), format, dimensions,
739                                     GrAttachment::UsageFlags::kColorAttachment, sampleCnt,
740                                     GrMipmapped::kNo, isProtected, memoryless, &key);
741     GrGpuResource* resource = fCache->findAndRefScratchResource(key);
742     if (resource) {
743         fGpu->stats()->incNumScratchMSAAAttachmentsReused();
744         GrAttachment* attachment = static_cast<GrAttachment*>(resource);
745         return sk_sp<GrAttachment>(attachment);
746     }
747 
748     return nullptr;
749 }
750 
makeSemaphore(bool isOwned)751 std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(
752         bool isOwned) {
753     return this->isAbandoned() ? nullptr : fGpu->makeSemaphore(isOwned);
754 }
755 
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,GrSemaphoreWrapType wrapType,GrWrapOwnership ownership)756 std::unique_ptr<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(
757         const GrBackendSemaphore& semaphore,
758         GrSemaphoreWrapType wrapType,
759         GrWrapOwnership ownership) {
760     ASSERT_SINGLE_OWNER
761     return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
762                                                                       wrapType,
763                                                                       ownership);
764 }
765 
766 // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
767 // 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)768 static bool prepare_level(const GrMipLevel& inLevel,
769                           SkISize dimensions,
770                           bool rowBytesSupport,
771                           GrColorType origColorType,
772                           GrColorType allowedColorType,
773                           GrMipLevel* outLevel,
774                           std::unique_ptr<char[]>* data) {
775     if (!inLevel.fPixels) {
776         outLevel->fPixels = nullptr;
777         outLevel->fRowBytes = 0;
778         return true;
779     }
780     size_t minRB = dimensions.fWidth * GrColorTypeBytesPerPixel(origColorType);
781     size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
782     if (actualRB < minRB) {
783         return false;
784     }
785     if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
786         outLevel->fRowBytes = actualRB;
787         outLevel->fPixels = inLevel.fPixels;
788         return true;
789     }
790     auto tempRB = dimensions.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
791     data->reset(new char[tempRB * dimensions.fHeight]);
792     outLevel->fPixels = data->get();
793     outLevel->fRowBytes = tempRB;
794     GrImageInfo srcInfo(   origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
795     GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
796     return GrConvertPixels( GrPixmap(dstInfo,     data->get(),   tempRB),
797                            GrCPixmap(srcInfo, inLevel.fPixels, actualRB));
798 }
799 
prepareLevels(const GrBackendFormat & format,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount,TempLevels * tempLevels,TempLevelDatas * tempLevelDatas) const800 GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
801                                               GrColorType colorType,
802                                               SkISize baseSize,
803                                               const GrMipLevel texels[],
804                                               int mipLevelCount,
805                                               TempLevels* tempLevels,
806                                               TempLevelDatas* tempLevelDatas) const {
807     SkASSERT(mipLevelCount && texels && texels[0].fPixels);
808 
809     auto allowedColorType =
810             this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
811     if (allowedColorType == GrColorType::kUnknown) {
812         return GrColorType::kUnknown;
813     }
814     bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
815     tempLevels->reset(mipLevelCount);
816     tempLevelDatas->reset(mipLevelCount);
817     auto size = baseSize;
818     for (int i = 0; i < mipLevelCount; ++i) {
819         if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
820                            &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
821             return GrColorType::kUnknown;
822         }
823         size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
824     }
825     return allowedColorType;
826 }
827 
writePixels(sk_sp<GrTexture> texture,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount) const828 sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
829                                                  GrColorType colorType,
830                                                  SkISize baseSize,
831                                                  const GrMipLevel texels[],
832                                                  int mipLevelCount) const {
833     SkASSERT(!this->isAbandoned());
834     SkASSERT(texture);
835     SkASSERT(colorType != GrColorType::kUnknown);
836     SkASSERT(mipLevelCount && texels && texels[0].fPixels);
837 
838     SkAutoSTArray<14, GrMipLevel> tmpTexels;
839     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
840     auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
841                                              mipLevelCount, &tmpTexels, &tmpDatas);
842     if (tempColorType == GrColorType::kUnknown) {
843         return nullptr;
844     }
845     SkAssertResult(fGpu->writePixels(texture.get(),
846                                      SkIRect::MakeSize(baseSize),
847                                      colorType,
848                                      tempColorType,
849                                      tmpTexels.get(),
850                                      mipLevelCount));
851     return texture;
852 }
853