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