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