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