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