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