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 uint32_t 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(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,const GrMipLevel texels[],int mipLevelCount)46 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
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({desc.fWidth, desc.fHeight}, format, desc.fConfig, renderable,
65 renderTargetSampleCnt, 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(desc, format, renderable, renderTargetSampleCnt, budgeted,
71 mipMapped, isProtected);
72 if (scratch) {
73 if (!hasPixels) {
74 return scratch;
75 }
76 return this->writePixels(std::move(scratch), colorType, {desc.fWidth, desc.fHeight}, texels,
77 mipLevelCount);
78 }
79 SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
80 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
81 GrColorType tempColorType = GrColorType::kUnknown;
82 if (hasPixels) {
83 tempColorType = this->prepareLevels(format, colorType, {desc.fWidth, desc.fHeight}, texels,
84 mipLevelCount, &tmpTexels, &tmpDatas);
85 if (tempColorType == GrColorType::kUnknown) {
86 return nullptr;
87 }
88 }
89 return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
90 isProtected, colorType, tempColorType, tmpTexels.get(),
91 mipLevelCount);
92 }
93
getExactScratch(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrMipMapped mipMapped,GrProtected isProtected)94 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc,
95 const GrBackendFormat& format,
96 GrRenderable renderable,
97 int renderTargetSampleCnt,
98 SkBudgeted budgeted,
99 GrMipMapped mipMapped,
100 GrProtected isProtected) {
101 sk_sp<GrTexture> tex(this->refScratchTexture(desc, format, renderable, renderTargetSampleCnt,
102 mipMapped, isProtected));
103 if (tex && SkBudgeted::kNo == budgeted) {
104 tex->resourcePriv().makeUnbudgeted();
105 }
106
107 return tex;
108 }
109
createTexture(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrColorType colorType,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,SkBackingFit fit,GrProtected isProtected,const GrMipLevel & mipLevel)110 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
111 const GrBackendFormat& format,
112 GrColorType colorType,
113 GrRenderable renderable,
114 int renderTargetSampleCnt,
115 SkBudgeted budgeted,
116 SkBackingFit fit,
117 GrProtected isProtected,
118 const GrMipLevel& mipLevel) {
119 ASSERT_SINGLE_OWNER
120
121 if (!mipLevel.fPixels) {
122 return nullptr;
123 }
124
125 if (SkBackingFit::kApprox == fit) {
126 if (this->isAbandoned()) {
127 return nullptr;
128 }
129 if (!fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
130 renderable, renderTargetSampleCnt, GrMipMapped::kNo)) {
131 return nullptr;
132 }
133
134 auto tex = this->createApproxTexture(desc, format, renderable, renderTargetSampleCnt,
135 isProtected);
136 if (!tex) {
137 return nullptr;
138 }
139 return this->writePixels(std::move(tex), colorType, {desc.fWidth, desc.fHeight}, &mipLevel,
140 1);
141 } else {
142 return this->createTexture(desc, format, colorType, renderable, renderTargetSampleCnt,
143 budgeted, isProtected, &mipLevel, 1);
144 }
145 }
146
createCompressedTexture(int width,int height,const GrBackendFormat & format,SkImage::CompressionType compression,SkBudgeted budgeted,SkData * data)147 sk_sp<GrTexture> GrResourceProvider::createCompressedTexture(int width, int height,
148 const GrBackendFormat& format,
149 SkImage::CompressionType compression,
150 SkBudgeted budgeted, SkData* data) {
151 ASSERT_SINGLE_OWNER
152 if (this->isAbandoned()) {
153 return nullptr;
154 }
155 return fGpu->createCompressedTexture(width, height, format, compression, budgeted, data->data(),
156 data->size());
157 }
158
createTexture(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipMapped mipMapped,SkBudgeted budgeted,GrProtected isProtected)159 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
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({desc.fWidth, desc.fHeight}, format, desc.fConfig, renderable,
172 renderTargetSampleCnt, mipMapped)) {
173 return nullptr;
174 }
175
176 // Compressed textures are read-only so they don't support re-use for scratch.
177 // TODO: Support GrMipMapped::kYes in scratch texture lookup here.
178 if (!GrPixelConfigIsCompressed(desc.fConfig)) {
179 sk_sp<GrTexture> tex = this->getExactScratch(
180 desc, format, renderable, renderTargetSampleCnt, budgeted, mipMapped, isProtected);
181 if (tex) {
182 return tex;
183 }
184 }
185
186 return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, mipMapped, budgeted,
187 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(uint32_t value)192 uint32_t GrResourceProvider::MakeApprox(uint32_t value) {
193 static const int kMagicTol = 1024;
194
195 value = SkTMax(kMinScratchTextureSize, value);
196
197 if (SkIsPow2(value)) {
198 return value;
199 }
200
201 uint32_t ceilPow2 = GrNextPow2(value);
202 if (value <= kMagicTol) {
203 return ceilPow2;
204 }
205
206 uint32_t floorPow2 = ceilPow2 >> 1;
207 uint32_t mid = floorPow2 + (floorPow2 >> 1);
208
209 if (value <= mid) {
210 return mid;
211 }
212
213 return ceilPow2;
214 }
215
createApproxTexture(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrProtected isProtected)216 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc,
217 const GrBackendFormat& format,
218 GrRenderable renderable,
219 int renderTargetSampleCnt,
220 GrProtected isProtected) {
221 ASSERT_SINGLE_OWNER
222
223 if (this->isAbandoned()) {
224 return nullptr;
225 }
226
227 // Currently we don't recycle compressed textures as scratch.
228 if (GrPixelConfigIsCompressed(desc.fConfig)) {
229 return nullptr;
230 }
231
232 if (!fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig, renderable,
233 renderTargetSampleCnt, GrMipMapped::kNo)) {
234 return nullptr;
235 }
236
237 // bin by some multiple or power of 2 with a reasonable min
238 GrSurfaceDesc copyDesc(desc);
239 copyDesc.fWidth = MakeApprox(desc.fWidth);
240 copyDesc.fHeight = MakeApprox(desc.fHeight);
241
242 if (auto tex = this->refScratchTexture(copyDesc, format, renderable, renderTargetSampleCnt,
243 GrMipMapped::kNo, isProtected)) {
244 return tex;
245 }
246
247 return fGpu->createTexture(copyDesc, format, renderable, renderTargetSampleCnt,
248 GrMipMapped::kNo, SkBudgeted::kYes, isProtected);
249 }
250
refScratchTexture(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipMapped mipMapped,GrProtected isProtected)251 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc,
252 const GrBackendFormat& format,
253 GrRenderable renderable,
254 int renderTargetSampleCnt,
255 GrMipMapped mipMapped,
256 GrProtected isProtected) {
257 ASSERT_SINGLE_OWNER
258 SkASSERT(!this->isAbandoned());
259 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
260 SkASSERT(fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
261 renderable, renderTargetSampleCnt, GrMipMapped::kNo));
262
263 // We could make initial clears work with scratch textures but it is a rare case so we just opt
264 // to fall back to making a new texture.
265 if (fGpu->caps()->reuseScratchTextures() || renderable == GrRenderable::kYes) {
266 GrScratchKey key;
267 GrTexturePriv::ComputeScratchKey(desc.fConfig, desc.fWidth, desc.fHeight, renderable,
268 renderTargetSampleCnt, mipMapped, isProtected, &key);
269 GrGpuResource* resource = fCache->findAndRefScratchResource(key);
270 if (resource) {
271 fGpu->stats()->incNumScratchTexturesReused();
272 GrSurface* surface = static_cast<GrSurface*>(resource);
273 return sk_sp<GrTexture>(surface->asTexture());
274 }
275 }
276
277 return nullptr;
278 }
279
wrapBackendTexture(const GrBackendTexture & tex,GrColorType colorType,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)280 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
281 GrColorType colorType,
282 GrWrapOwnership ownership,
283 GrWrapCacheable cacheable,
284 GrIOType ioType) {
285 ASSERT_SINGLE_OWNER
286 if (this->isAbandoned()) {
287 return nullptr;
288 }
289 return fGpu->wrapBackendTexture(tex, colorType, ownership, cacheable, ioType);
290 }
291
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrColorType colorType,GrWrapOwnership ownership,GrWrapCacheable cacheable)292 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
293 int sampleCnt,
294 GrColorType colorType,
295 GrWrapOwnership ownership,
296 GrWrapCacheable cacheable) {
297 ASSERT_SINGLE_OWNER
298 if (this->isAbandoned()) {
299 return nullptr;
300 }
301 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, colorType, ownership, cacheable);
302 }
303
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT,GrColorType colorType)304 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
305 const GrBackendRenderTarget& backendRT, GrColorType colorType)
306 {
307 ASSERT_SINGLE_OWNER
308 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT, colorType);
309 }
310
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)311 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
312 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
313 ASSERT_SINGLE_OWNER
314 return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
315 vkInfo);
316
317 }
318
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)319 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
320 GrGpuResource* resource) {
321 ASSERT_SINGLE_OWNER
322 if (this->isAbandoned() || !resource) {
323 return;
324 }
325 resource->resourcePriv().setUniqueKey(key);
326 }
327
findResourceByUniqueKey(const GrUniqueKey & key)328 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
329 ASSERT_SINGLE_OWNER
330 return this->isAbandoned() ? nullptr
331 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
332 }
333
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)334 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
335 size_t size,
336 const void* data,
337 const GrUniqueKey& key) {
338 if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
339 return buffer;
340 }
341 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
342 // We shouldn't bin and/or cache static buffers.
343 SkASSERT(buffer->size() == size);
344 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
345 buffer->resourcePriv().setUniqueKey(key);
346 return sk_sp<const GrGpuBuffer>(buffer);
347 }
348 return nullptr;
349 }
350
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey * key)351 sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
352 int patternSize,
353 int reps,
354 int vertCount,
355 const GrUniqueKey* key) {
356 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
357
358 sk_sp<GrGpuBuffer> buffer(
359 this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
360 if (!buffer) {
361 return nullptr;
362 }
363 uint16_t* data = (uint16_t*) buffer->map();
364 SkAutoTArray<uint16_t> temp;
365 if (!data) {
366 temp.reset(reps * patternSize);
367 data = temp.get();
368 }
369 for (int i = 0; i < reps; ++i) {
370 int baseIdx = i * patternSize;
371 uint16_t baseVert = (uint16_t)(i * vertCount);
372 for (int j = 0; j < patternSize; ++j) {
373 data[baseIdx+j] = baseVert + pattern[j];
374 }
375 }
376 if (temp.get()) {
377 if (!buffer->updateData(data, bufferSize)) {
378 return nullptr;
379 }
380 } else {
381 buffer->unmap();
382 }
383 if (key) {
384 SkASSERT(key->isValid());
385 this->assignUniqueKeyToResource(*key, buffer.get());
386 }
387 return buffer;
388 }
389
390 static constexpr int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1;
391
createQuadIndexBuffer()392 sk_sp<const GrGpuBuffer> GrResourceProvider::createQuadIndexBuffer() {
393 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
394 static const uint16_t kPattern[] = { 0, 1, 2, 2, 1, 3 };
395 return this->createPatternedIndexBuffer(kPattern, 6, kMaxQuads, 4, nullptr);
396 }
397
QuadCountOfQuadBuffer()398 int GrResourceProvider::QuadCountOfQuadBuffer() { return kMaxQuads; }
399
createPath(const SkPath & path,const GrStyle & style)400 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
401 if (this->isAbandoned()) {
402 return nullptr;
403 }
404
405 SkASSERT(this->gpu()->pathRendering());
406 return this->gpu()->pathRendering()->createPath(path, style);
407 }
408
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)409 sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
410 GrAccessPattern accessPattern,
411 const void* data) {
412 if (this->isAbandoned()) {
413 return nullptr;
414 }
415 if (kDynamic_GrAccessPattern != accessPattern) {
416 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
417 }
418 // bin by pow2 with a reasonable min
419 static const size_t MIN_SIZE = 1 << 12;
420 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
421
422 GrScratchKey key;
423 GrGpuBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
424 auto buffer =
425 sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
426 key)));
427 if (!buffer) {
428 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
429 if (!buffer) {
430 return nullptr;
431 }
432 }
433 if (data) {
434 buffer->updateData(data, size);
435 }
436 return buffer;
437 }
438
attachStencilAttachment(GrRenderTarget * rt,int minStencilSampleCount)439 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, int minStencilSampleCount) {
440 SkASSERT(rt);
441 GrStencilAttachment* stencil = rt->renderTargetPriv().getStencilAttachment();
442 if (stencil && stencil->numSamples() >= minStencilSampleCount) {
443 return true;
444 }
445
446 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
447 GrUniqueKey sbKey;
448
449 int width = rt->width();
450 int height = rt->height();
451 #if 0
452 if (this->caps()->oversizedStencilSupport()) {
453 width = SkNextPow2(width);
454 height = SkNextPow2(height);
455 }
456 #endif
457 GrStencilAttachment::ComputeSharedStencilAttachmentKey(
458 width, height, minStencilSampleCount, &sbKey);
459 auto stencil = this->findByUniqueKey<GrStencilAttachment>(sbKey);
460 if (!stencil) {
461 // Need to try and create a new stencil
462 stencil.reset(this->gpu()->createStencilAttachmentForRenderTarget(
463 rt, width, height, minStencilSampleCount));
464 if (!stencil) {
465 return false;
466 }
467 this->assignUniqueKeyToResource(sbKey, stencil.get());
468 }
469 rt->renderTargetPriv().attachStencilAttachment(std::move(stencil));
470 }
471
472 if (GrStencilAttachment* stencil = rt->renderTargetPriv().getStencilAttachment()) {
473 return stencil->numSamples() >= minStencilSampleCount;
474 }
475 return false;
476 }
477
wrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,int sampleCnt,GrColorType colorType)478 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
479 const GrBackendTexture& tex, int sampleCnt, GrColorType colorType)
480 {
481 if (this->isAbandoned()) {
482 return nullptr;
483 }
484 return fGpu->wrapBackendTextureAsRenderTarget(tex, sampleCnt, colorType);
485 }
486
makeSemaphore(bool isOwned)487 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) {
488 return fGpu->makeSemaphore(isOwned);
489 }
490
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)491 sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
492 SemaphoreWrapType wrapType,
493 GrWrapOwnership ownership) {
494 ASSERT_SINGLE_OWNER
495 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
496 wrapType,
497 ownership);
498 }
499
500 // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
501 // to make the row bytes tight if necessary. Returns false if the input row bytes are invalid.
prepare_level(const GrMipLevel & inLevel,const SkISize & size,bool rowBytesSupport,GrColorType origColorType,GrColorType allowedColorType,GrMipLevel * outLevel,std::unique_ptr<char[]> * data)502 static bool prepare_level(const GrMipLevel& inLevel,
503 const SkISize& size,
504 bool rowBytesSupport,
505 GrColorType origColorType,
506 GrColorType allowedColorType,
507 GrMipLevel* outLevel,
508 std::unique_ptr<char[]>* data) {
509 if (!inLevel.fPixels) {
510 outLevel->fPixels = nullptr;
511 outLevel->fRowBytes = 0;
512 return true;
513 }
514 size_t minRB = size.fWidth * GrColorTypeBytesPerPixel(origColorType);
515 size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
516 if (actualRB < minRB) {
517 return false;
518 }
519 if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
520 outLevel->fRowBytes = actualRB;
521 outLevel->fPixels = inLevel.fPixels;
522 return true;
523 }
524 auto tempRB = size.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
525 data->reset(new char[tempRB * size.fHeight]);
526 outLevel->fPixels = data->get();
527 outLevel->fRowBytes = tempRB;
528 GrImageInfo srcInfo(origColorType, kUnpremul_SkAlphaType, nullptr, size);
529 GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, size);
530 return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
531 }
532
prepareLevels(const GrBackendFormat & format,GrColorType colorType,const SkISize & baseSize,const GrMipLevel texels[],int mipLevelCount,TempLevels * tempLevels,TempLevelDatas * tempLevelDatas) const533 GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
534 GrColorType colorType,
535 const SkISize& baseSize,
536 const GrMipLevel texels[],
537 int mipLevelCount,
538 TempLevels* tempLevels,
539 TempLevelDatas* tempLevelDatas) const {
540 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
541
542 auto allowedColorType =
543 this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
544 if (allowedColorType == GrColorType::kUnknown) {
545 return GrColorType::kUnknown;
546 }
547 bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
548 tempLevels->reset(mipLevelCount);
549 tempLevelDatas->reset(mipLevelCount);
550 auto size = baseSize;
551 for (int i = 0; i < mipLevelCount; ++i) {
552 if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
553 &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
554 return GrColorType::kUnknown;
555 }
556 size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
557 }
558 return allowedColorType;
559 }
560
writePixels(sk_sp<GrTexture> texture,GrColorType colorType,const SkISize & baseSize,const GrMipLevel texels[],int mipLevelCount) const561 sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
562 GrColorType colorType,
563 const SkISize& baseSize,
564 const GrMipLevel texels[],
565 int mipLevelCount) const {
566 SkASSERT(!this->isAbandoned());
567 SkASSERT(texture);
568 SkASSERT(colorType != GrColorType::kUnknown);
569 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
570
571 SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
572 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
573 auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
574 mipLevelCount, &tmpTexels, &tmpDatas);
575 if (tempColorType == GrColorType::kUnknown) {
576 return nullptr;
577 }
578 SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
579 colorType, tempColorType, tmpTexels.get(), mipLevelCount));
580 return texture;
581 }
582