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