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/gpu/GrAttachment.h"
16 #include "src/gpu/GrCaps.h"
17 #include "src/gpu/GrDataUtils.h"
18 #include "src/gpu/GrGpu.h"
19 #include "src/gpu/GrGpuBuffer.h"
20 #include "src/gpu/GrImageInfo.h"
21 #include "src/gpu/GrPath.h"
22 #include "src/gpu/GrPathRendering.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,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,const GrMipLevel texels[],int mipLevelCount)44 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
45 const GrBackendFormat& format,
46 GrColorType colorType,
47 GrRenderable renderable,
48 int renderTargetSampleCnt,
49 SkBudgeted budgeted,
50 GrProtected isProtected,
51 const GrMipLevel texels[],
52 int mipLevelCount) {
53 ASSERT_SINGLE_OWNER
54
55 SkASSERT(mipLevelCount > 0);
56
57 if (this->isAbandoned()) {
58 return nullptr;
59 }
60
61 GrMipmapped mipMapped = mipLevelCount > 1 ? GrMipmapped::kYes : GrMipmapped::kNo;
62 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
63 mipMapped)) {
64 return nullptr;
65 }
66 // Current rule is that you can provide no level data, just the base, or all the levels.
67 bool hasPixels = mipLevelCount && texels[0].fPixels;
68 auto scratch = this->getExactScratch(dimensions, format, renderable, renderTargetSampleCnt,
69 budgeted, mipMapped, isProtected);
70 if (scratch) {
71 if (!hasPixels) {
72 return scratch;
73 }
74 return this->writePixels(std::move(scratch), colorType, dimensions, texels, mipLevelCount);
75 }
76 SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
77 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
78 GrColorType tempColorType = GrColorType::kUnknown;
79 if (hasPixels) {
80 tempColorType = this->prepareLevels(format, colorType, dimensions, texels, mipLevelCount,
81 &tmpTexels, &tmpDatas);
82 if (tempColorType == GrColorType::kUnknown) {
83 return nullptr;
84 }
85 }
86 return fGpu->createTexture(dimensions, format, renderable, renderTargetSampleCnt, budgeted,
87 isProtected, colorType, tempColorType, tmpTexels.get(),
88 mipLevelCount);
89 }
90
getExactScratch(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipmapped mipMapped,GrProtected isProtected)91 sk_sp<GrTexture> GrResourceProvider::getExactScratch(SkISize dimensions,
92 const GrBackendFormat& format,
93 GrRenderable renderable,
94 int renderTargetSampleCnt,
95 SkBudgeted budgeted,
96 GrMipmapped mipMapped,
97 GrProtected isProtected) {
98 sk_sp<GrTexture> tex(this->refScratchTexture(dimensions, format, renderable,
99 renderTargetSampleCnt, mipMapped, isProtected));
100 if (tex && SkBudgeted::kNo == budgeted) {
101 tex->resourcePriv().makeUnbudgeted();
102 }
103
104 return tex;
105 }
106
createTexture(SkISize dimensions,const GrBackendFormat & format,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,SkBackingFit fit,GrProtected isProtected,const GrMipLevel & mipLevel)107 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
108 const GrBackendFormat& format,
109 GrColorType colorType,
110 GrRenderable renderable,
111 int renderTargetSampleCnt,
112 SkBudgeted budgeted,
113 SkBackingFit fit,
114 GrProtected isProtected,
115 const GrMipLevel& mipLevel) {
116 ASSERT_SINGLE_OWNER
117
118 if (!mipLevel.fPixels) {
119 return nullptr;
120 }
121
122 if (SkBackingFit::kApprox == fit) {
123 if (this->isAbandoned()) {
124 return nullptr;
125 }
126 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
127 GrMipmapped::kNo)) {
128 return nullptr;
129 }
130
131 auto tex = this->createApproxTexture(dimensions, format, renderable, renderTargetSampleCnt,
132 isProtected);
133 if (!tex) {
134 return nullptr;
135 }
136 return this->writePixels(std::move(tex), colorType, dimensions, &mipLevel, 1);
137 } else {
138 return this->createTexture(dimensions, format, colorType, renderable, renderTargetSampleCnt,
139 budgeted, isProtected, &mipLevel, 1);
140 }
141 }
142
createCompressedTexture(SkISize dimensions,const GrBackendFormat & format,SkBudgeted budgeted,GrMipmapped mipMapped,GrProtected isProtected,SkData * data)143 sk_sp<GrTexture> GrResourceProvider::createCompressedTexture(SkISize dimensions,
144 const GrBackendFormat& format,
145 SkBudgeted budgeted,
146 GrMipmapped mipMapped,
147 GrProtected isProtected,
148 SkData* data) {
149 ASSERT_SINGLE_OWNER
150 if (this->isAbandoned()) {
151 return nullptr;
152 }
153 return fGpu->createCompressedTexture(dimensions, format, budgeted, mipMapped,
154 isProtected, data->data(), data->size());
155 }
156
createTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipMapped,SkBudgeted budgeted,GrProtected isProtected)157 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
158 const GrBackendFormat& format,
159 GrRenderable renderable,
160 int renderTargetSampleCnt,
161 GrMipmapped mipMapped,
162 SkBudgeted budgeted,
163 GrProtected isProtected) {
164 ASSERT_SINGLE_OWNER
165 if (this->isAbandoned()) {
166 return nullptr;
167 }
168
169 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
170 mipMapped)) {
171 return nullptr;
172 }
173
174 // Currently we don't recycle compressed textures as scratch. Additionally all compressed
175 // textures should be created through the createCompressedTexture function.
176 SkASSERT(!this->caps()->isFormatCompressed(format));
177
178 // TODO: Support GrMipmapped::kYes in scratch texture lookup here.
179 sk_sp<GrTexture> tex =
180 this->getExactScratch(dimensions, format, renderable, renderTargetSampleCnt, budgeted,
181 mipMapped, isProtected);
182 if (tex) {
183 return tex;
184 }
185
186 return fGpu->createTexture(dimensions, format, renderable, renderTargetSampleCnt, mipMapped,
187 budgeted, isProtected);
188 }
189
190 // Map 'value' to a larger multiple of 2. Values <= 'kMagicTol' will pop up to
191 // the next power of 2. Those above 'kMagicTol' will only go up half the floor power of 2.
MakeApprox(SkISize dimensions)192 SkISize GrResourceProvider::MakeApprox(SkISize dimensions) {
193 auto adjust = [](int value) {
194 static const int kMagicTol = 1024;
195
196 value = std::max(kMinScratchTextureSize, value);
197
198 if (SkIsPow2(value)) {
199 return value;
200 }
201
202 int ceilPow2 = SkNextPow2(value);
203 if (value <= kMagicTol) {
204 return ceilPow2;
205 }
206
207 int floorPow2 = ceilPow2 >> 1;
208 int mid = floorPow2 + (floorPow2 >> 1);
209
210 if (value <= mid) {
211 return mid;
212 }
213 return ceilPow2;
214 };
215
216 return {adjust(dimensions.width()), adjust(dimensions.height())};
217 }
218
createApproxTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrProtected isProtected)219 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(SkISize dimensions,
220 const GrBackendFormat& format,
221 GrRenderable renderable,
222 int renderTargetSampleCnt,
223 GrProtected isProtected) {
224 ASSERT_SINGLE_OWNER
225
226 if (this->isAbandoned()) {
227 return nullptr;
228 }
229
230 // Currently we don't recycle compressed textures as scratch. Additionally all compressed
231 // textures should be created through the createCompressedTexture function.
232 SkASSERT(!this->caps()->isFormatCompressed(format));
233
234 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
235 GrMipmapped::kNo)) {
236 return nullptr;
237 }
238
239 auto copyDimensions = MakeApprox(dimensions);
240
241 if (auto tex = this->refScratchTexture(copyDimensions, format, renderable,
242 renderTargetSampleCnt, GrMipmapped::kNo, isProtected)) {
243 return tex;
244 }
245
246 return fGpu->createTexture(copyDimensions, format, renderable, renderTargetSampleCnt,
247 GrMipmapped::kNo, SkBudgeted::kYes, isProtected);
248 }
249
refScratchTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipMapped,GrProtected isProtected)250 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(SkISize dimensions,
251 const GrBackendFormat& format,
252 GrRenderable renderable,
253 int renderTargetSampleCnt,
254 GrMipmapped mipMapped,
255 GrProtected isProtected) {
256 ASSERT_SINGLE_OWNER
257 SkASSERT(!this->isAbandoned());
258 SkASSERT(!this->caps()->isFormatCompressed(format));
259 SkASSERT(fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
260 GrMipmapped::kNo));
261
262 // We could make initial clears work with scratch textures but it is a rare case so we just opt
263 // to fall back to making a new texture.
264 if (fGpu->caps()->reuseScratchTextures() || renderable == GrRenderable::kYes) {
265 GrScratchKey key;
266 GrTexture::ComputeScratchKey(*this->caps(), format, dimensions, renderable,
267 renderTargetSampleCnt, mipMapped, isProtected, &key);
268 GrGpuResource* resource = fCache->findAndRefScratchResource(key);
269 if (resource) {
270 fGpu->stats()->incNumScratchTexturesReused();
271 GrSurface* surface = static_cast<GrSurface*>(resource);
272 return sk_sp<GrTexture>(surface->asTexture());
273 }
274 }
275
276 return nullptr;
277 }
278
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)279 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
280 GrWrapOwnership ownership,
281 GrWrapCacheable cacheable,
282 GrIOType ioType) {
283 ASSERT_SINGLE_OWNER
284 if (this->isAbandoned()) {
285 return nullptr;
286 }
287 return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType);
288 }
289
wrapCompressedBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable)290 sk_sp<GrTexture> GrResourceProvider::wrapCompressedBackendTexture(const GrBackendTexture& tex,
291 GrWrapOwnership ownership,
292 GrWrapCacheable cacheable) {
293 ASSERT_SINGLE_OWNER
294 if (this->isAbandoned()) {
295 return nullptr;
296 }
297
298 return fGpu->wrapCompressedBackendTexture(tex, ownership, cacheable);
299 }
300
301
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)302 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
303 int sampleCnt,
304 GrWrapOwnership ownership,
305 GrWrapCacheable cacheable) {
306 ASSERT_SINGLE_OWNER
307 if (this->isAbandoned()) {
308 return nullptr;
309 }
310 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable);
311 }
312
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)313 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
314 const GrBackendRenderTarget& backendRT) {
315 ASSERT_SINGLE_OWNER
316 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
317 }
318
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)319 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
320 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
321 ASSERT_SINGLE_OWNER
322 return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
323 vkInfo);
324
325 }
326
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)327 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
328 GrGpuResource* resource) {
329 ASSERT_SINGLE_OWNER
330 if (this->isAbandoned() || !resource) {
331 return;
332 }
333 resource->resourcePriv().setUniqueKey(key);
334 }
335
findResourceByUniqueKey(const GrUniqueKey & key)336 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
337 ASSERT_SINGLE_OWNER
338 return this->isAbandoned() ? nullptr
339 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
340 }
341
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)342 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
343 size_t size,
344 const void* data,
345 const GrUniqueKey& key) {
346 if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
347 return std::move(buffer);
348 }
349 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
350 // We shouldn't bin and/or cache static buffers.
351 SkASSERT(buffer->size() == size);
352 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
353 buffer->resourcePriv().setUniqueKey(key);
354 return sk_sp<const GrGpuBuffer>(buffer);
355 }
356 return nullptr;
357 }
358
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey * key)359 sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
360 int patternSize,
361 int reps,
362 int vertCount,
363 const GrUniqueKey* key) {
364 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
365
366 sk_sp<GrGpuBuffer> buffer(
367 this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
368 if (!buffer) {
369 return nullptr;
370 }
371 uint16_t* data = (uint16_t*) buffer->map();
372 SkAutoTArray<uint16_t> temp;
373 if (!data) {
374 temp.reset(reps * patternSize);
375 data = temp.get();
376 }
377 for (int i = 0; i < reps; ++i) {
378 int baseIdx = i * patternSize;
379 uint16_t baseVert = (uint16_t)(i * vertCount);
380 for (int j = 0; j < patternSize; ++j) {
381 data[baseIdx+j] = baseVert + pattern[j];
382 }
383 }
384 if (temp.get()) {
385 if (!buffer->updateData(data, bufferSize)) {
386 return nullptr;
387 }
388 } else {
389 buffer->unmap();
390 }
391 if (key) {
392 SkASSERT(key->isValid());
393 this->assignUniqueKeyToResource(*key, buffer.get());
394 }
395 return std::move(buffer);
396 }
397
398 ///////////////////////////////////////////////////////////////////////////////////////////////////
399 static constexpr int kMaxNumNonAAQuads = 1 << 12; // max possible: (1 << 14) - 1;
400 static const int kVertsPerNonAAQuad = 4;
401 static const int kIndicesPerNonAAQuad = 6;
402
createNonAAQuadIndexBuffer()403 sk_sp<const GrGpuBuffer> GrResourceProvider::createNonAAQuadIndexBuffer() {
404 static_assert(kVertsPerNonAAQuad * kMaxNumNonAAQuads <= 65535); // indices fit in a uint16_t
405
406 static const uint16_t kNonAAQuadIndexPattern[] = {
407 0, 1, 2, 2, 1, 3
408 };
409
410 static_assert(SK_ARRAY_COUNT(kNonAAQuadIndexPattern) == kIndicesPerNonAAQuad);
411
412 return this->createPatternedIndexBuffer(kNonAAQuadIndexPattern, kIndicesPerNonAAQuad,
413 kMaxNumNonAAQuads, kVertsPerNonAAQuad, nullptr);
414 }
415
MaxNumNonAAQuads()416 int GrResourceProvider::MaxNumNonAAQuads() { return kMaxNumNonAAQuads; }
NumVertsPerNonAAQuad()417 int GrResourceProvider::NumVertsPerNonAAQuad() { return kVertsPerNonAAQuad; }
NumIndicesPerNonAAQuad()418 int GrResourceProvider::NumIndicesPerNonAAQuad() { return kIndicesPerNonAAQuad; }
419
420 ///////////////////////////////////////////////////////////////////////////////////////////////////
421 static constexpr int kMaxNumAAQuads = 1 << 9; // max possible: (1 << 13) - 1;
422 static const int kVertsPerAAQuad = 8;
423 static const int kIndicesPerAAQuad = 30;
424
createAAQuadIndexBuffer()425 sk_sp<const GrGpuBuffer> GrResourceProvider::createAAQuadIndexBuffer() {
426 static_assert(kVertsPerAAQuad * kMaxNumAAQuads <= 65535); // indices fit in a uint16_t
427
428 // clang-format off
429 static const uint16_t kAAQuadIndexPattern[] = {
430 0, 1, 2, 1, 3, 2,
431 0, 4, 1, 4, 5, 1,
432 0, 6, 4, 0, 2, 6,
433 2, 3, 6, 3, 7, 6,
434 1, 5, 3, 3, 5, 7,
435 };
436 // clang-format on
437
438 static_assert(SK_ARRAY_COUNT(kAAQuadIndexPattern) == kIndicesPerAAQuad);
439
440 return this->createPatternedIndexBuffer(kAAQuadIndexPattern, kIndicesPerAAQuad,
441 kMaxNumAAQuads, kVertsPerAAQuad, nullptr);
442 }
443
MaxNumAAQuads()444 int GrResourceProvider::MaxNumAAQuads() { return kMaxNumAAQuads; }
NumVertsPerAAQuad()445 int GrResourceProvider::NumVertsPerAAQuad() { return kVertsPerAAQuad; }
NumIndicesPerAAQuad()446 int GrResourceProvider::NumIndicesPerAAQuad() { return kIndicesPerAAQuad; }
447
448 ///////////////////////////////////////////////////////////////////////////////////////////////////
createPath(const SkPath & path,const GrStyle & style)449 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
450 if (this->isAbandoned()) {
451 return nullptr;
452 }
453
454 SkASSERT(this->gpu()->pathRendering());
455 return this->gpu()->pathRendering()->createPath(path, style);
456 }
457
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)458 sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
459 GrAccessPattern accessPattern,
460 const void* data) {
461 if (this->isAbandoned()) {
462 return nullptr;
463 }
464 if (kDynamic_GrAccessPattern != accessPattern) {
465 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
466 }
467 // bin by pow2+midpoint with a reasonable min
468 static const size_t MIN_SIZE = 1 << 12;
469 size_t allocSize = std::max(size, MIN_SIZE);
470 size_t ceilPow2 = GrNextSizePow2(allocSize);
471 size_t floorPow2 = ceilPow2 >> 1;
472 size_t mid = floorPow2 + (floorPow2 >> 1);
473 allocSize = (allocSize <= mid) ? mid : ceilPow2;
474
475 GrScratchKey key;
476 GrGpuBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
477 auto buffer =
478 sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
479 key)));
480 if (!buffer) {
481 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
482 if (!buffer) {
483 return nullptr;
484 }
485 }
486 if (data) {
487 buffer->updateData(data, size);
488 }
489 return buffer;
490 }
491
attachStencilAttachment(GrRenderTarget * rt,int numStencilSamples)492 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, int numStencilSamples) {
493 SkASSERT(rt);
494 GrAttachment* stencil = rt->getStencilAttachment();
495 if (stencil && stencil->numSamples() == numStencilSamples) {
496 return true;
497 }
498
499 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
500 GrUniqueKey sbKey;
501
502 #if 0
503 if (this->caps()->oversizedStencilSupport()) {
504 width = SkNextPow2(width);
505 height = SkNextPow2(height);
506 }
507 #endif
508 GrBackendFormat stencilFormat =
509 this->gpu()->getPreferredStencilFormat(rt->backendFormat());
510 if (!stencilFormat.isValid()) {
511 return false;
512 }
513 GrProtected isProtected = rt->isProtected() ? GrProtected::kYes : GrProtected::kNo;
514 GrAttachment::ComputeSharedAttachmentUniqueKey(
515 *this->caps(), stencilFormat, rt->dimensions(),
516 GrAttachment::UsageFlags::kStencilAttachment, numStencilSamples, isProtected,
517 &sbKey);
518 auto stencil = this->findByUniqueKey<GrAttachment>(sbKey);
519 if (!stencil) {
520 // Need to try and create a new stencil
521 stencil = this->gpu()->makeStencilAttachmentForRenderTarget(rt, rt->dimensions(),
522 numStencilSamples);
523 if (!stencil) {
524 return false;
525 }
526 this->assignUniqueKeyToResource(sbKey, stencil.get());
527 }
528 rt->attachStencilAttachment(std::move(stencil));
529 }
530
531 if (GrAttachment* stencil = rt->getStencilAttachment()) {
532 return stencil->numSamples() == numStencilSamples;
533 }
534 return false;
535 }
536
makeMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected)537 sk_sp<GrAttachment> GrResourceProvider::makeMSAAAttachment(SkISize dimensions,
538 const GrBackendFormat& format,
539 int sampleCnt,
540 GrProtected isProtected) {
541 ASSERT_SINGLE_OWNER
542
543 SkASSERT(sampleCnt > 1);
544
545 if (this->isAbandoned()) {
546 return nullptr;
547 }
548
549 if (!fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
550 GrMipMapped::kNo)) {
551 return nullptr;
552 }
553
554 auto scratch = this->refScratchMSAAAttachment(dimensions, format, sampleCnt, isProtected);
555 if (scratch) {
556 return scratch;
557 }
558
559 return fGpu->makeMSAAAttachment(dimensions, format, sampleCnt, isProtected);
560 }
561
refScratchMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected)562 sk_sp<GrAttachment> GrResourceProvider::refScratchMSAAAttachment(SkISize dimensions,
563 const GrBackendFormat& format,
564 int sampleCnt,
565 GrProtected isProtected) {
566 ASSERT_SINGLE_OWNER
567 SkASSERT(!this->isAbandoned());
568 SkASSERT(!this->caps()->isFormatCompressed(format));
569 SkASSERT(fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
570 GrMipmapped::kNo));
571
572 GrScratchKey key;
573 GrAttachment::ComputeScratchKey(*this->caps(), format, dimensions,
574 GrAttachment::UsageFlags::kColorAttachment, sampleCnt,
575 isProtected, &key);
576 GrGpuResource* resource = fCache->findAndRefScratchResource(key);
577 if (resource) {
578 fGpu->stats()->incNumScratchMSAAAttachmentsReused();
579 GrAttachment* attachment = static_cast<GrAttachment*>(resource);
580 return sk_sp<GrAttachment>(attachment);
581 }
582
583 return nullptr;
584 }
585
makeSemaphore(bool isOwned)586 std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(
587 bool isOwned) {
588 return this->isAbandoned() ? nullptr : fGpu->makeSemaphore(isOwned);
589 }
590
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)591 std::unique_ptr<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(
592 const GrBackendSemaphore& semaphore,
593 SemaphoreWrapType wrapType,
594 GrWrapOwnership ownership) {
595 ASSERT_SINGLE_OWNER
596 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
597 wrapType,
598 ownership);
599 }
600
601 // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
602 // 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)603 static bool prepare_level(const GrMipLevel& inLevel,
604 SkISize dimensions,
605 bool rowBytesSupport,
606 GrColorType origColorType,
607 GrColorType allowedColorType,
608 GrMipLevel* outLevel,
609 std::unique_ptr<char[]>* data) {
610 if (!inLevel.fPixels) {
611 outLevel->fPixels = nullptr;
612 outLevel->fRowBytes = 0;
613 return true;
614 }
615 size_t minRB = dimensions.fWidth * GrColorTypeBytesPerPixel(origColorType);
616 size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
617 if (actualRB < minRB) {
618 return false;
619 }
620 if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
621 outLevel->fRowBytes = actualRB;
622 outLevel->fPixels = inLevel.fPixels;
623 return true;
624 }
625 auto tempRB = dimensions.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
626 data->reset(new char[tempRB * dimensions.fHeight]);
627 outLevel->fPixels = data->get();
628 outLevel->fRowBytes = tempRB;
629 GrImageInfo srcInfo(origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
630 GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
631 return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
632 }
633
prepareLevels(const GrBackendFormat & format,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount,TempLevels * tempLevels,TempLevelDatas * tempLevelDatas) const634 GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
635 GrColorType colorType,
636 SkISize baseSize,
637 const GrMipLevel texels[],
638 int mipLevelCount,
639 TempLevels* tempLevels,
640 TempLevelDatas* tempLevelDatas) const {
641 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
642
643 auto allowedColorType =
644 this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
645 if (allowedColorType == GrColorType::kUnknown) {
646 return GrColorType::kUnknown;
647 }
648 bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
649 tempLevels->reset(mipLevelCount);
650 tempLevelDatas->reset(mipLevelCount);
651 auto size = baseSize;
652 for (int i = 0; i < mipLevelCount; ++i) {
653 if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
654 &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
655 return GrColorType::kUnknown;
656 }
657 size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
658 }
659 return allowedColorType;
660 }
661
writePixels(sk_sp<GrTexture> texture,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount) const662 sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
663 GrColorType colorType,
664 SkISize baseSize,
665 const GrMipLevel texels[],
666 int mipLevelCount) const {
667 SkASSERT(!this->isAbandoned());
668 SkASSERT(texture);
669 SkASSERT(colorType != GrColorType::kUnknown);
670 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
671
672 SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
673 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
674 auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
675 mipLevelCount, &tmpTexels, &tmpDatas);
676 if (tempColorType == GrColorType::kUnknown) {
677 return nullptr;
678 }
679 SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
680 colorType, tempColorType, tmpTexels.get(), mipLevelCount));
681 return texture;
682 }
683