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