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