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