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