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/GrAttachment.h"
17 #include "src/gpu/GrCaps.h"
18 #include "src/gpu/GrDataUtils.h"
19 #include "src/gpu/GrGpu.h"
20 #include "src/gpu/GrGpuBuffer.h"
21 #include "src/gpu/GrImageInfo.h"
22 #include "src/gpu/GrProxyProvider.h"
23 #include "src/gpu/GrRenderTarget.h"
24 #include "src/gpu/GrResourceCache.h"
25 #include "src/gpu/GrSemaphore.h"
26 #include "src/gpu/GrTexture.h"
27 #include "src/gpu/SkGr.h"
28
29 const int GrResourceProvider::kMinScratchTextureSize = 16;
30
31 #define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fSingleOwner)
32
GrResourceProvider(GrGpu * gpu,GrResourceCache * cache,GrSingleOwner * owner)33 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner)
34 : fCache(cache)
35 , fGpu(gpu)
36 #ifdef SK_DEBUG
37 , fSingleOwner(owner)
38 #endif
39 {
40 fCaps = sk_ref_sp(fGpu->caps());
41 }
42
createTexture(SkISize dimensions,const GrBackendFormat & format,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipmapped mipmapped,GrProtected isProtected,const GrMipLevel texels[])43 sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
44 const GrBackendFormat& format,
45 GrColorType colorType,
46 GrRenderable renderable,
47 int renderTargetSampleCnt,
48 SkBudgeted budgeted,
49 GrMipmapped mipmapped,
50 GrProtected isProtected,
51 const GrMipLevel texels[]) {
52 ASSERT_SINGLE_OWNER
53
54 if (this->isAbandoned()) {
55 return nullptr;
56 }
57
58 int numMipLevels = 1;
59 if (mipmapped == GrMipmapped::kYes) {
60 numMipLevels = SkMipmap::ComputeLevelCount(dimensions.fWidth, dimensions.fHeight) + 1;
61 }
62
63 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
64 mipmapped)) {
65 return nullptr;
66 }
67 // Current rule is that you can provide no level data, just the base, or all the levels.
68 bool hasPixels = texels[0].fPixels;
69 auto scratch = this->getExactScratch(dimensions, format, renderable, renderTargetSampleCnt,
70 budgeted, mipmapped, isProtected);
71 if (scratch) {
72 if (!hasPixels) {
73 return scratch;
74 }
75 return this->writePixels(std::move(scratch), colorType, dimensions, texels, numMipLevels);
76 }
77 SkAutoSTArray<14, GrMipLevel> tmpTexels;
78 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
79 GrColorType tempColorType = GrColorType::kUnknown;
80 if (hasPixels) {
81 tempColorType = this->prepareLevels(format, colorType, dimensions, texels, numMipLevels,
82 &tmpTexels, &tmpDatas);
83 if (tempColorType == GrColorType::kUnknown) {
84 return nullptr;
85 }
86 }
87 return fGpu->createTexture(dimensions, format, renderable, renderTargetSampleCnt, budgeted,
88 isProtected, colorType, tempColorType, tmpTexels.get(),
89 numMipLevels);
90 }
91
getExactScratch(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipmapped mipmapped,GrProtected isProtected)92 sk_sp<GrTexture> GrResourceProvider::getExactScratch(SkISize dimensions,
93 const GrBackendFormat& format,
94 GrRenderable renderable,
95 int renderTargetSampleCnt,
96 SkBudgeted budgeted,
97 GrMipmapped mipmapped,
98 GrProtected isProtected) {
99 sk_sp<GrTexture> tex(this->findAndRefScratchTexture(dimensions, format, renderable,
100 renderTargetSampleCnt, mipmapped,
101 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, GrMipmapped::kNo, isProtected, &mipLevel);
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->findAndRefScratchTexture(copyDimensions, format, renderable,
244 renderTargetSampleCnt, GrMipmapped::kNo,
245 isProtected)) {
246 return tex;
247 }
248
249 return fGpu->createTexture(copyDimensions, format, renderable, renderTargetSampleCnt,
250 GrMipmapped::kNo, SkBudgeted::kYes, isProtected);
251 }
252
findAndRefScratchTexture(const GrScratchKey & key)253 sk_sp<GrTexture> GrResourceProvider::findAndRefScratchTexture(const GrScratchKey& key) {
254 ASSERT_SINGLE_OWNER
255 SkASSERT(!this->isAbandoned());
256 SkASSERT(key.isValid());
257
258 if (GrGpuResource* resource = fCache->findAndRefScratchResource(key)) {
259 fGpu->stats()->incNumScratchTexturesReused();
260 GrSurface* surface = static_cast<GrSurface*>(resource);
261 return sk_sp<GrTexture>(surface->asTexture());
262 }
263 return nullptr;
264 }
265
findAndRefScratchTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipmapped mipmapped,GrProtected isProtected)266 sk_sp<GrTexture> GrResourceProvider::findAndRefScratchTexture(SkISize dimensions,
267 const GrBackendFormat& format,
268 GrRenderable renderable,
269 int renderTargetSampleCnt,
270 GrMipmapped mipmapped,
271 GrProtected isProtected) {
272 ASSERT_SINGLE_OWNER
273 SkASSERT(!this->isAbandoned());
274 SkASSERT(!this->caps()->isFormatCompressed(format));
275 SkASSERT(fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
276 GrMipmapped::kNo));
277
278 // We could make initial clears work with scratch textures but it is a rare case so we just opt
279 // to fall back to making a new texture.
280 if (fGpu->caps()->reuseScratchTextures() || renderable == GrRenderable::kYes) {
281 GrScratchKey key;
282 GrTexture::ComputeScratchKey(*this->caps(), format, dimensions, renderable,
283 renderTargetSampleCnt, mipmapped, isProtected, &key);
284 return this->findAndRefScratchTexture(key);
285 }
286
287 return nullptr;
288 }
289
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)290 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
291 GrWrapOwnership ownership,
292 GrWrapCacheable cacheable,
293 GrIOType ioType) {
294 ASSERT_SINGLE_OWNER
295 if (this->isAbandoned()) {
296 return nullptr;
297 }
298 return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType);
299 }
300
wrapCompressedBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable)301 sk_sp<GrTexture> GrResourceProvider::wrapCompressedBackendTexture(const GrBackendTexture& tex,
302 GrWrapOwnership ownership,
303 GrWrapCacheable cacheable) {
304 ASSERT_SINGLE_OWNER
305 if (this->isAbandoned()) {
306 return nullptr;
307 }
308
309 return fGpu->wrapCompressedBackendTexture(tex, ownership, cacheable);
310 }
311
312
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)313 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
314 int sampleCnt,
315 GrWrapOwnership ownership,
316 GrWrapCacheable cacheable) {
317 ASSERT_SINGLE_OWNER
318 if (this->isAbandoned()) {
319 return nullptr;
320 }
321 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable);
322 }
323
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)324 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
325 const GrBackendRenderTarget& backendRT) {
326 ASSERT_SINGLE_OWNER
327 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
328 }
329
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)330 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
331 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
332 ASSERT_SINGLE_OWNER
333 return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
334 vkInfo);
335
336 }
337
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)338 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
339 GrGpuResource* resource) {
340 ASSERT_SINGLE_OWNER
341 if (this->isAbandoned() || !resource) {
342 return;
343 }
344 resource->resourcePriv().setUniqueKey(key);
345 }
346
findResourceByUniqueKey(const GrUniqueKey & key)347 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
348 ASSERT_SINGLE_OWNER
349 return this->isAbandoned() ? nullptr
350 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
351 }
352
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)353 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
354 size_t size,
355 const void* data,
356 const GrUniqueKey& key) {
357 if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
358 return std::move(buffer);
359 }
360 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
361 // We shouldn't bin and/or cache static buffers.
362 SkASSERT(buffer->size() == size);
363 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
364 buffer->resourcePriv().setUniqueKey(key);
365 return sk_sp<const GrGpuBuffer>(buffer);
366 }
367 return nullptr;
368 }
369
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey * key)370 sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
371 int patternSize,
372 int reps,
373 int vertCount,
374 const GrUniqueKey* key) {
375 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
376
377 sk_sp<GrGpuBuffer> buffer(
378 this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
379 if (!buffer) {
380 return nullptr;
381 }
382 uint16_t* data = (uint16_t*) buffer->map();
383 SkAutoTArray<uint16_t> temp;
384 if (!data) {
385 temp.reset(reps * patternSize);
386 data = temp.get();
387 }
388 for (int i = 0; i < reps; ++i) {
389 int baseIdx = i * patternSize;
390 uint16_t baseVert = (uint16_t)(i * vertCount);
391 for (int j = 0; j < patternSize; ++j) {
392 data[baseIdx+j] = baseVert + pattern[j];
393 }
394 }
395 if (temp.get()) {
396 if (!buffer->updateData(data, bufferSize)) {
397 return nullptr;
398 }
399 } else {
400 buffer->unmap();
401 }
402 if (key) {
403 SkASSERT(key->isValid());
404 this->assignUniqueKeyToResource(*key, buffer.get());
405 }
406 return std::move(buffer);
407 }
408
409 ///////////////////////////////////////////////////////////////////////////////////////////////////
410 static constexpr int kMaxNumNonAAQuads = 1 << 12; // max possible: (1 << 14) - 1;
411 static const int kVertsPerNonAAQuad = 4;
412 static const int kIndicesPerNonAAQuad = 6;
413
createNonAAQuadIndexBuffer()414 sk_sp<const GrGpuBuffer> GrResourceProvider::createNonAAQuadIndexBuffer() {
415 static_assert(kVertsPerNonAAQuad * kMaxNumNonAAQuads <= 65535); // indices fit in a uint16_t
416
417 static const uint16_t kNonAAQuadIndexPattern[] = {
418 0, 1, 2, 2, 1, 3
419 };
420
421 static_assert(SK_ARRAY_COUNT(kNonAAQuadIndexPattern) == kIndicesPerNonAAQuad);
422
423 return this->createPatternedIndexBuffer(kNonAAQuadIndexPattern, kIndicesPerNonAAQuad,
424 kMaxNumNonAAQuads, kVertsPerNonAAQuad, nullptr);
425 }
426
MaxNumNonAAQuads()427 int GrResourceProvider::MaxNumNonAAQuads() { return kMaxNumNonAAQuads; }
NumVertsPerNonAAQuad()428 int GrResourceProvider::NumVertsPerNonAAQuad() { return kVertsPerNonAAQuad; }
NumIndicesPerNonAAQuad()429 int GrResourceProvider::NumIndicesPerNonAAQuad() { return kIndicesPerNonAAQuad; }
430
431 ///////////////////////////////////////////////////////////////////////////////////////////////////
432 static constexpr int kMaxNumAAQuads = 1 << 9; // max possible: (1 << 13) - 1;
433 static const int kVertsPerAAQuad = 8;
434 static const int kIndicesPerAAQuad = 30;
435
createAAQuadIndexBuffer()436 sk_sp<const GrGpuBuffer> GrResourceProvider::createAAQuadIndexBuffer() {
437 static_assert(kVertsPerAAQuad * kMaxNumAAQuads <= 65535); // indices fit in a uint16_t
438
439 // clang-format off
440 static const uint16_t kAAQuadIndexPattern[] = {
441 0, 1, 2, 1, 3, 2,
442 0, 4, 1, 4, 5, 1,
443 0, 6, 4, 0, 2, 6,
444 2, 3, 6, 3, 7, 6,
445 1, 5, 3, 3, 5, 7,
446 };
447 // clang-format on
448
449 static_assert(SK_ARRAY_COUNT(kAAQuadIndexPattern) == kIndicesPerAAQuad);
450
451 return this->createPatternedIndexBuffer(kAAQuadIndexPattern, kIndicesPerAAQuad,
452 kMaxNumAAQuads, kVertsPerAAQuad, nullptr);
453 }
454
MaxNumAAQuads()455 int GrResourceProvider::MaxNumAAQuads() { return kMaxNumAAQuads; }
NumVertsPerAAQuad()456 int GrResourceProvider::NumVertsPerAAQuad() { return kVertsPerAAQuad; }
NumIndicesPerAAQuad()457 int GrResourceProvider::NumIndicesPerAAQuad() { return kIndicesPerAAQuad; }
458
459 ///////////////////////////////////////////////////////////////////////////////////////////////////
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)460 sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
461 GrAccessPattern accessPattern,
462 const void* data) {
463 if (this->isAbandoned()) {
464 return nullptr;
465 }
466 if (kDynamic_GrAccessPattern != accessPattern) {
467 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
468 }
469 // bin by pow2+midpoint with a reasonable min
470 static const size_t MIN_SIZE = 1 << 12;
471 static const size_t MIN_UNIFORM_SIZE = 1 << 7;
472 size_t allocSize = intendedType == GrGpuBufferType::kUniform ? std::max(size, MIN_UNIFORM_SIZE)
473 : std::max(size, MIN_SIZE);
474 size_t ceilPow2 = GrNextSizePow2(allocSize);
475 size_t floorPow2 = ceilPow2 >> 1;
476 size_t mid = floorPow2 + (floorPow2 >> 1);
477 allocSize = (allocSize <= mid) ? mid : ceilPow2;
478
479 GrScratchKey key;
480 GrGpuBuffer::ComputeScratchKeyForDynamicBuffer(allocSize, intendedType, &key);
481 auto buffer =
482 sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
483 key)));
484 if (!buffer) {
485 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
486 if (!buffer) {
487 return nullptr;
488 }
489 }
490 if (data) {
491 buffer->updateData(data, size);
492 }
493 return buffer;
494 }
495
num_stencil_samples(const GrRenderTarget * rt,bool useMSAASurface,const GrCaps & caps)496 static int num_stencil_samples(const GrRenderTarget* rt, bool useMSAASurface, const GrCaps& caps) {
497 int numSamples = rt->numSamples();
498 if (numSamples == 1 && useMSAASurface) { // Are we using dynamic msaa?
499 numSamples = caps.internalMultisampleCount(rt->backendFormat());
500 SkASSERT(numSamples > 1); // Caller must ensure dmsaa is supported before trying to use it.
501 }
502 return numSamples;
503 }
504
attachStencilAttachment(GrRenderTarget * rt,bool useMSAASurface)505 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, bool useMSAASurface) {
506 SkASSERT(rt);
507 SkASSERT(!this->caps()->avoidStencilBuffers());
508
509 GrAttachment* stencil = rt->getStencilAttachment(useMSAASurface);
510 if (stencil) {
511 SkASSERT(stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
512 return true;
513 }
514
515 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment(useMSAASurface)) {
516 GrUniqueKey sbKey;
517
518 #if 0
519 if (this->caps()->oversizedStencilSupport()) {
520 width = SkNextPow2(width);
521 height = SkNextPow2(height);
522 }
523 #endif
524 GrBackendFormat stencilFormat = this->gpu()->getPreferredStencilFormat(rt->backendFormat());
525 if (!stencilFormat.isValid()) {
526 return false;
527 }
528 GrProtected isProtected = rt->isProtected() ? GrProtected::kYes : GrProtected::kNo;
529 int numStencilSamples = num_stencil_samples(rt, useMSAASurface, *this->caps());
530 GrAttachment::ComputeSharedAttachmentUniqueKey(
531 *this->caps(), stencilFormat, rt->dimensions(),
532 GrAttachment::UsageFlags::kStencilAttachment, numStencilSamples, GrMipmapped::kNo,
533 isProtected, &sbKey);
534 auto stencil = this->findByUniqueKey<GrAttachment>(sbKey);
535 if (!stencil) {
536 // Need to try and create a new stencil
537 stencil = this->gpu()->makeStencilAttachment(rt->backendFormat(), rt->dimensions(),
538 numStencilSamples);
539 if (!stencil) {
540 return false;
541 }
542 this->assignUniqueKeyToResource(sbKey, stencil.get());
543 }
544 rt->attachStencilAttachment(std::move(stencil), useMSAASurface);
545 }
546 stencil = rt->getStencilAttachment(useMSAASurface);
547 SkASSERT(!stencil ||
548 stencil->numSamples() == num_stencil_samples(rt, useMSAASurface, *this->caps()));
549 return stencil != nullptr;
550 }
551
makeMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected)552 sk_sp<GrAttachment> GrResourceProvider::makeMSAAAttachment(SkISize dimensions,
553 const GrBackendFormat& format,
554 int sampleCnt,
555 GrProtected isProtected) {
556 ASSERT_SINGLE_OWNER
557
558 SkASSERT(sampleCnt > 1);
559
560 if (this->isAbandoned()) {
561 return nullptr;
562 }
563
564 if (!fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
565 GrMipmapped::kNo)) {
566 return nullptr;
567 }
568
569 auto scratch = this->refScratchMSAAAttachment(dimensions, format, sampleCnt, isProtected);
570 if (scratch) {
571 return scratch;
572 }
573
574 return fGpu->makeMSAAAttachment(dimensions, format, sampleCnt, isProtected);
575 }
576
refScratchMSAAAttachment(SkISize dimensions,const GrBackendFormat & format,int sampleCnt,GrProtected isProtected)577 sk_sp<GrAttachment> GrResourceProvider::refScratchMSAAAttachment(SkISize dimensions,
578 const GrBackendFormat& format,
579 int sampleCnt,
580 GrProtected isProtected) {
581 ASSERT_SINGLE_OWNER
582 SkASSERT(!this->isAbandoned());
583 SkASSERT(!this->caps()->isFormatCompressed(format));
584 SkASSERT(fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
585 GrMipmapped::kNo));
586
587 GrScratchKey key;
588 GrAttachment::ComputeScratchKey(*this->caps(), format, dimensions,
589 GrAttachment::UsageFlags::kColorAttachment, sampleCnt,
590 GrMipmapped::kNo, isProtected, &key);
591 GrGpuResource* resource = fCache->findAndRefScratchResource(key);
592 if (resource) {
593 fGpu->stats()->incNumScratchMSAAAttachmentsReused();
594 GrAttachment* attachment = static_cast<GrAttachment*>(resource);
595 return sk_sp<GrAttachment>(attachment);
596 }
597
598 return nullptr;
599 }
600
makeSemaphore(bool isOwned)601 std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(
602 bool isOwned) {
603 return this->isAbandoned() ? nullptr : fGpu->makeSemaphore(isOwned);
604 }
605
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)606 std::unique_ptr<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(
607 const GrBackendSemaphore& semaphore,
608 SemaphoreWrapType wrapType,
609 GrWrapOwnership ownership) {
610 ASSERT_SINGLE_OWNER
611 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
612 wrapType,
613 ownership);
614 }
615
616 // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
617 // 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)618 static bool prepare_level(const GrMipLevel& inLevel,
619 SkISize dimensions,
620 bool rowBytesSupport,
621 GrColorType origColorType,
622 GrColorType allowedColorType,
623 GrMipLevel* outLevel,
624 std::unique_ptr<char[]>* data) {
625 if (!inLevel.fPixels) {
626 outLevel->fPixels = nullptr;
627 outLevel->fRowBytes = 0;
628 return true;
629 }
630 size_t minRB = dimensions.fWidth * GrColorTypeBytesPerPixel(origColorType);
631 size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
632 if (actualRB < minRB) {
633 return false;
634 }
635 if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
636 outLevel->fRowBytes = actualRB;
637 outLevel->fPixels = inLevel.fPixels;
638 return true;
639 }
640 auto tempRB = dimensions.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
641 data->reset(new char[tempRB * dimensions.fHeight]);
642 outLevel->fPixels = data->get();
643 outLevel->fRowBytes = tempRB;
644 GrImageInfo srcInfo( origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
645 GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
646 return GrConvertPixels( GrPixmap(dstInfo, data->get(), tempRB),
647 GrCPixmap(srcInfo, inLevel.fPixels, actualRB));
648 }
649
prepareLevels(const GrBackendFormat & format,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount,TempLevels * tempLevels,TempLevelDatas * tempLevelDatas) const650 GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
651 GrColorType colorType,
652 SkISize baseSize,
653 const GrMipLevel texels[],
654 int mipLevelCount,
655 TempLevels* tempLevels,
656 TempLevelDatas* tempLevelDatas) const {
657 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
658
659 auto allowedColorType =
660 this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
661 if (allowedColorType == GrColorType::kUnknown) {
662 return GrColorType::kUnknown;
663 }
664 bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
665 tempLevels->reset(mipLevelCount);
666 tempLevelDatas->reset(mipLevelCount);
667 auto size = baseSize;
668 for (int i = 0; i < mipLevelCount; ++i) {
669 if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
670 &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
671 return GrColorType::kUnknown;
672 }
673 size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
674 }
675 return allowedColorType;
676 }
677
writePixels(sk_sp<GrTexture> texture,GrColorType colorType,SkISize baseSize,const GrMipLevel texels[],int mipLevelCount) const678 sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
679 GrColorType colorType,
680 SkISize baseSize,
681 const GrMipLevel texels[],
682 int mipLevelCount) const {
683 SkASSERT(!this->isAbandoned());
684 SkASSERT(texture);
685 SkASSERT(colorType != GrColorType::kUnknown);
686 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
687
688 SkAutoSTArray<14, GrMipLevel> tmpTexels;
689 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
690 auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
691 mipLevelCount, &tmpTexels, &tmpDatas);
692 if (tempColorType == GrColorType::kUnknown) {
693 return nullptr;
694 }
695 SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
696 colorType, tempColorType, tmpTexels.get(), mipLevelCount));
697 return texture;
698 }
699