blob: bd6b34d37a85ded9f5fca7d2271062019dc85385 [file] [log] [blame]
bsalomoned0bcad2015-05-04 10:36:42 -07001/*
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
Brian Salomon1047a492019-07-02 12:25:21 -04008#include "src/gpu/GrResourceProvider.h"
9
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/gpu/GrBackendSemaphore.h"
11#include "include/gpu/GrContext.h"
12#include "include/private/GrResourceKey.h"
13#include "include/private/GrSingleOwner.h"
Brian Salomon1047a492019-07-02 12:25:21 -040014#include "src/core/SkConvertPixels.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#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"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040020#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/GrSemaphore.h"
27#include "src/gpu/GrStencilAttachment.h"
28#include "src/gpu/GrTexturePriv.h"
29#include "src/gpu/SkGr.h"
bsalomoned0bcad2015-05-04 10:36:42 -070030
Brian Salomon9f2b86c2019-10-22 10:37:46 -040031const int GrResourceProvider::kMinScratchTextureSize = 16;
Brian Osman32342f02017-03-04 08:12:46 -050032
33#define ASSERT_SINGLE_OWNER \
34 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
35
Robert Phillips12c46292019-04-23 07:36:17 -040036GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner)
Brian Osman32342f02017-03-04 08:12:46 -050037 : fCache(cache)
38 , fGpu(gpu)
39#ifdef SK_DEBUG
40 , fSingleOwner(owner)
41#endif
Robert Phillips4150eea2018-02-07 17:08:21 -050042{
Robert Phillips26c90e02017-03-14 14:39:29 -040043 fCaps = sk_ref_sp(fGpu->caps());
bsalomoned0bcad2015-05-04 10:36:42 -070044}
45
Brian Salomonf2c2ba92019-07-17 09:59:59 -040046sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
Brian Salomon4eb38b72019-08-05 12:58:39 -040047 const GrBackendFormat& format,
Brian Salomona90382f2019-09-17 09:01:56 -040048 GrColorType colorType,
Brian Salomon27b4d8d2019-07-22 14:23:45 -040049 GrRenderable renderable,
Brian Salomon2af3e702019-08-11 19:10:31 -040050 int renderTargetSampleCnt,
51 SkBudgeted budgeted,
Brian Salomone8a766b2019-07-19 14:24:36 -040052 GrProtected isProtected,
Brian Salomon2af3e702019-08-11 19:10:31 -040053 const GrMipLevel texels[],
54 int mipLevelCount) {
Brian Osman32342f02017-03-04 08:12:46 -050055 ASSERT_SINGLE_OWNER
56
Robert Phillips7f1b4f82017-11-28 07:38:39 -050057 SkASSERT(mipLevelCount > 0);
Robert Phillips1119dc32017-04-11 12:54:57 -040058
Brian Osman32342f02017-03-04 08:12:46 -050059 if (this->isAbandoned()) {
60 return nullptr;
61 }
Robert Phillips1119dc32017-04-11 12:54:57 -040062
Brian Salomonbdecacf2018-02-02 20:32:49 -050063 GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
Greg Daniel6fa62e22019-08-07 15:52:37 -040064 if (!fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig, renderable,
65 renderTargetSampleCnt, mipMapped)) {
Brian Osman32342f02017-03-04 08:12:46 -050066 return nullptr;
67 }
Brian Salomon8660eb02019-09-20 13:04:13 -040068 // 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);
Brian Salomona90382f2019-09-17 09:01:56 -040078 }
Brian Salomon1047a492019-07-02 12:25:21 -040079 SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
Brian Salomonc9d81f72019-07-03 07:52:41 -040080 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
Brian Salomon8660eb02019-09-20 13:04:13 -040081 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;
Brian Salomon1047a492019-07-02 12:25:21 -040087 }
88 }
Brian Salomon4eb38b72019-08-05 12:58:39 -040089 return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
Brian Salomon8660eb02019-09-20 13:04:13 -040090 isProtected, colorType, tempColorType, tmpTexels.get(),
91 mipLevelCount);
Brian Osman32342f02017-03-04 08:12:46 -050092}
93
Robert Phillips45fdae12017-04-17 12:57:27 -040094sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc,
Brian Salomon4eb38b72019-08-05 12:58:39 -040095 const GrBackendFormat& format,
Brian Salomon27b4d8d2019-07-22 14:23:45 -040096 GrRenderable renderable,
97 int renderTargetSampleCnt,
98 SkBudgeted budgeted,
Brian Salomon14cb4132019-09-16 13:14:47 -040099 GrMipMapped mipMapped,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400100 GrProtected isProtected) {
Brian Salomon4eb38b72019-08-05 12:58:39 -0400101 sk_sp<GrTexture> tex(this->refScratchTexture(desc, format, renderable, renderTargetSampleCnt,
Brian Salomon14cb4132019-09-16 13:14:47 -0400102 mipMapped, isProtected));
Robert Phillips45fdae12017-04-17 12:57:27 -0400103 if (tex && SkBudgeted::kNo == budgeted) {
104 tex->resourcePriv().makeUnbudgeted();
105 }
106
107 return tex;
108}
109
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500110sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
Brian Salomon4eb38b72019-08-05 12:58:39 -0400111 const GrBackendFormat& format,
Brian Salomona90382f2019-09-17 09:01:56 -0400112 GrColorType colorType,
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400113 GrRenderable renderable,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400114 int renderTargetSampleCnt,
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500115 SkBudgeted budgeted,
Greg Danielfb3abcd2018-02-02 15:48:33 -0500116 SkBackingFit fit,
Brian Salomone8a766b2019-07-19 14:24:36 -0400117 GrProtected isProtected,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400118 const GrMipLevel& mipLevel) {
Robert Phillips774831a2017-04-20 10:19:33 -0400119 ASSERT_SINGLE_OWNER
120
Robert Phillips45fdae12017-04-17 12:57:27 -0400121 if (!mipLevel.fPixels) {
122 return nullptr;
123 }
124
Brian Salomona90382f2019-09-17 09:01:56 -0400125 if (SkBackingFit::kApprox == fit) {
Brian Salomon8660eb02019-09-20 13:04:13 -0400126 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);
Brian Salomona90382f2019-09-17 09:01:56 -0400136 if (!tex) {
137 return nullptr;
138 }
Brian Salomon8660eb02019-09-20 13:04:13 -0400139 return this->writePixels(std::move(tex), colorType, {desc.fWidth, desc.fHeight}, &mipLevel,
140 1);
Brian Salomona90382f2019-09-17 09:01:56 -0400141 } else {
142 return this->createTexture(desc, format, colorType, renderable, renderTargetSampleCnt,
143 budgeted, isProtected, &mipLevel, 1);
Brian Salomona3ffaab2019-07-09 12:26:46 -0400144 }
Robert Phillips45fdae12017-04-17 12:57:27 -0400145}
146
Robert Phillips9f744f72019-12-19 19:14:33 -0500147sk_sp<GrTexture> GrResourceProvider::createCompressedTexture(SkISize dimensions,
Greg Daniel7bfc9132019-08-14 14:23:53 -0400148 const GrBackendFormat& format,
Brian Salomonbb8dde82019-06-27 10:52:13 -0400149 SkBudgeted budgeted, SkData* data) {
150 ASSERT_SINGLE_OWNER
151 if (this->isAbandoned()) {
152 return nullptr;
153 }
Robert Phillips9f744f72019-12-19 19:14:33 -0500154 return fGpu->createCompressedTexture(dimensions, format, budgeted,
155 data->data(), data->size());
Brian Salomonbb8dde82019-06-27 10:52:13 -0400156}
157
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400158sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
Brian Salomon4eb38b72019-08-05 12:58:39 -0400159 const GrBackendFormat& format,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400160 GrRenderable renderable,
161 int renderTargetSampleCnt,
Brian Salomona90382f2019-09-17 09:01:56 -0400162 GrMipMapped mipMapped,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400163 SkBudgeted budgeted,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400164 GrProtected isProtected) {
Robert Phillipse78b7252017-04-06 07:59:41 -0400165 ASSERT_SINGLE_OWNER
Robert Phillipse78b7252017-04-06 07:59:41 -0400166 if (this->isAbandoned()) {
167 return nullptr;
Brian Osman32342f02017-03-04 08:12:46 -0500168 }
Robert Phillipse78b7252017-04-06 07:59:41 -0400169
Greg Daniel6fa62e22019-08-07 15:52:37 -0400170 if (!fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig, renderable,
Brian Salomona90382f2019-09-17 09:01:56 -0400171 renderTargetSampleCnt, mipMapped)) {
Robert Phillipse78b7252017-04-06 07:59:41 -0400172 return nullptr;
173 }
174
Greg Danielc3a927f2019-10-16 12:03:50 -0400175 // Currently we don't recycle compressed textures as scratch. Additionally all compressed
176 // textures should be created through the createCompressedTexture function.
177 SkASSERT(!this->caps()->isFormatCompressed(format));
178
Brian Salomona90382f2019-09-17 09:01:56 -0400179 // TODO: Support GrMipMapped::kYes in scratch texture lookup here.
Greg Danielc3a927f2019-10-16 12:03:50 -0400180 sk_sp<GrTexture> tex = this->getExactScratch(
181 desc, format, renderable, renderTargetSampleCnt, budgeted, mipMapped, isProtected);
182 if (tex) {
183 return tex;
Robert Phillipse78b7252017-04-06 07:59:41 -0400184 }
185
Brian Salomona90382f2019-09-17 09:01:56 -0400186 return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, mipMapped, budgeted,
Brian Salomon4eb38b72019-08-05 12:58:39 -0400187 isProtected);
Brian Osman32342f02017-03-04 08:12:46 -0500188}
189
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400190// 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.
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400192SkISize GrResourceProvider::MakeApprox(SkISize dimensions) {
193 auto adjust = [](int value) {
194 static const int kMagicTol = 1024;
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400195
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400196 value = SkTMax(kMinScratchTextureSize, value);
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400197
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400198 if (SkIsPow2(value)) {
199 return value;
200 }
201
202 int ceilPow2 = SkNextPow2(value);
203 if (value <= kMagicTol) {
204 return ceilPow2;
205 }
206
207 int floorPow2 = ceilPow2 >> 1;
208 int mid = floorPow2 + (floorPow2 >> 1);
209
210 if (value <= mid) {
211 return mid;
212 }
Brian Salomon322301a2019-10-24 12:50:50 -0400213 return ceilPow2;
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400214 };
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400215
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400216 return {adjust(dimensions.width()), adjust(dimensions.height())};
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400217}
218
Robert Phillips67d52cf2017-06-05 13:38:13 -0400219sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc,
Brian Salomon4eb38b72019-08-05 12:58:39 -0400220 const GrBackendFormat& format,
Brian Salomone8a766b2019-07-19 14:24:36 -0400221 GrRenderable renderable,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400222 int renderTargetSampleCnt,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400223 GrProtected isProtected) {
Brian Osman32342f02017-03-04 08:12:46 -0500224 ASSERT_SINGLE_OWNER
Brian Osman32342f02017-03-04 08:12:46 -0500225
Brian Osman32342f02017-03-04 08:12:46 -0500226 if (this->isAbandoned()) {
227 return nullptr;
228 }
Robert Phillips1119dc32017-04-11 12:54:57 -0400229
Greg Danielc3a927f2019-10-16 12:03:50 -0400230 // Currently we don't recycle compressed textures as scratch. Additionally all compressed
231 // textures should be created through the createCompressedTexture function.
232 SkASSERT(!this->caps()->isFormatCompressed(format));
Jim Van Verth1676cb92019-01-15 13:24:45 -0500233
Greg Daniel6fa62e22019-08-07 15:52:37 -0400234 if (!fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig, renderable,
235 renderTargetSampleCnt, GrMipMapped::kNo)) {
Brian Salomond34edf32017-05-19 15:45:48 -0400236 return nullptr;
237 }
238
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400239 // bin by some multiple or power of 2 with a reasonable min
Michael Ludwigbd2f0702019-09-13 15:29:41 -0400240 GrSurfaceDesc copyDesc(desc);
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400241 auto size = MakeApprox({desc.fWidth, desc.fHeight});
242 copyDesc.fWidth = size.width();
243 copyDesc.fHeight = size.height();
Greg Daniel29bf84f2017-09-25 12:25:12 -0400244
Michael Ludwigbd2f0702019-09-13 15:29:41 -0400245 if (auto tex = this->refScratchTexture(copyDesc, format, renderable, renderTargetSampleCnt,
Brian Salomon14cb4132019-09-16 13:14:47 -0400246 GrMipMapped::kNo, isProtected)) {
Greg Daniel29bf84f2017-09-25 12:25:12 -0400247 return tex;
248 }
249
Michael Ludwigbd2f0702019-09-13 15:29:41 -0400250 return fGpu->createTexture(copyDesc, format, renderable, renderTargetSampleCnt,
Brian Salomona90382f2019-09-17 09:01:56 -0400251 GrMipMapped::kNo, SkBudgeted::kYes, isProtected);
Brian Osman32342f02017-03-04 08:12:46 -0500252}
253
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400254sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc,
Brian Salomon4eb38b72019-08-05 12:58:39 -0400255 const GrBackendFormat& format,
Brian Salomone8a766b2019-07-19 14:24:36 -0400256 GrRenderable renderable,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400257 int renderTargetSampleCnt,
Brian Salomon14cb4132019-09-16 13:14:47 -0400258 GrMipMapped mipMapped,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400259 GrProtected isProtected) {
Brian Osman32342f02017-03-04 08:12:46 -0500260 ASSERT_SINGLE_OWNER
261 SkASSERT(!this->isAbandoned());
Greg Danielc3a927f2019-10-16 12:03:50 -0400262 SkASSERT(!this->caps()->isFormatCompressed(format));
Greg Daniel6fa62e22019-08-07 15:52:37 -0400263 SkASSERT(fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
264 renderable, renderTargetSampleCnt, GrMipMapped::kNo));
Brian Osman32342f02017-03-04 08:12:46 -0500265
Brian Salomond17b4a62017-05-23 16:53:47 -0400266 // We could make initial clears work with scratch textures but it is a rare case so we just opt
267 // to fall back to making a new texture.
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400268 if (fGpu->caps()->reuseScratchTextures() || renderable == GrRenderable::kYes) {
Brian Osman32342f02017-03-04 08:12:46 -0500269 GrScratchKey key;
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400270 GrTexturePriv::ComputeScratchKey(desc.fConfig, {desc.fWidth, desc.fHeight}, renderable,
Brian Salomon14cb4132019-09-16 13:14:47 -0400271 renderTargetSampleCnt, mipMapped, isProtected, &key);
Robert Phillipsaee18c92019-09-06 11:48:27 -0400272 GrGpuResource* resource = fCache->findAndRefScratchResource(key);
Brian Osman32342f02017-03-04 08:12:46 -0500273 if (resource) {
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400274 fGpu->stats()->incNumScratchTexturesReused();
Brian Osman32342f02017-03-04 08:12:46 -0500275 GrSurface* surface = static_cast<GrSurface*>(resource);
Robert Phillips67d52cf2017-06-05 13:38:13 -0400276 return sk_sp<GrTexture>(surface->asTexture());
Brian Osman32342f02017-03-04 08:12:46 -0500277 }
278 }
279
Brian Osman32342f02017-03-04 08:12:46 -0500280 return nullptr;
281}
282
Greg Daniel7ef28f32017-04-20 16:41:55 +0000283sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400284 GrColorType colorType,
Greg Daniel2268ad22018-11-15 09:27:38 -0500285 GrWrapOwnership ownership,
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500286 GrWrapCacheable cacheable,
287 GrIOType ioType) {
Brian Osman32342f02017-03-04 08:12:46 -0500288 ASSERT_SINGLE_OWNER
289 if (this->isAbandoned()) {
290 return nullptr;
291 }
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400292 return fGpu->wrapBackendTexture(tex, colorType, ownership, cacheable, ioType);
Brian Salomond17f6582017-07-19 18:28:58 -0400293}
294
Robert Phillipsead321b2019-12-19 10:16:32 -0500295sk_sp<GrTexture> GrResourceProvider::wrapCompressedBackendTexture(const GrBackendTexture& tex,
296 GrWrapOwnership ownership,
297 GrWrapCacheable cacheable) {
298 ASSERT_SINGLE_OWNER
299 if (this->isAbandoned()) {
300 return nullptr;
301 }
302
303 return fGpu->wrapCompressedBackendTexture(tex, ownership, cacheable);
304}
305
306
Brian Salomond17f6582017-07-19 18:28:58 -0400307sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
Brian Salomond17f6582017-07-19 18:28:58 -0400308 int sampleCnt,
Robert Phillips0902c982019-07-16 07:47:56 -0400309 GrColorType colorType,
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500310 GrWrapOwnership ownership,
311 GrWrapCacheable cacheable) {
Brian Salomond17f6582017-07-19 18:28:58 -0400312 ASSERT_SINGLE_OWNER
313 if (this->isAbandoned()) {
314 return nullptr;
315 }
Robert Phillips0902c982019-07-16 07:47:56 -0400316 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, colorType, ownership, cacheable);
Brian Osman32342f02017-03-04 08:12:46 -0500317}
318
319sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400320 const GrBackendRenderTarget& backendRT, GrColorType colorType)
Brian Osman32342f02017-03-04 08:12:46 -0500321{
322 ASSERT_SINGLE_OWNER
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400323 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT, colorType);
Brian Osman32342f02017-03-04 08:12:46 -0500324}
325
Greg Danielb46add82019-01-02 14:51:29 -0500326sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
327 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
328 ASSERT_SINGLE_OWNER
329 return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
330 vkInfo);
331
332}
333
Brian Osman32342f02017-03-04 08:12:46 -0500334void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
335 GrGpuResource* resource) {
336 ASSERT_SINGLE_OWNER
337 if (this->isAbandoned() || !resource) {
338 return;
339 }
340 resource->resourcePriv().setUniqueKey(key);
341}
342
Brian Salomond28a79d2017-10-16 13:01:07 -0400343sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
Brian Osman32342f02017-03-04 08:12:46 -0500344 ASSERT_SINGLE_OWNER
Brian Salomond28a79d2017-10-16 13:01:07 -0400345 return this->isAbandoned() ? nullptr
346 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
Brian Osman32342f02017-03-04 08:12:46 -0500347}
348
Brian Salomondbf70722019-02-07 11:31:24 -0500349sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
350 size_t size,
351 const void* data,
352 const GrUniqueKey& key) {
353 if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
Brian Salomon9c73e3d2019-08-15 10:55:49 -0400354 return buffer;
Chris Dalton5d2de082017-12-19 10:40:23 -0700355 }
Brian Salomondbf70722019-02-07 11:31:24 -0500356 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
Chris Dalton133944a2018-11-16 23:30:29 -0500357 // We shouldn't bin and/or cache static buffers.
Brian Salomondbf70722019-02-07 11:31:24 -0500358 SkASSERT(buffer->size() == size);
Chris Dalton5d2de082017-12-19 10:40:23 -0700359 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
Chris Dalton5d2de082017-12-19 10:40:23 -0700360 buffer->resourcePriv().setUniqueKey(key);
Brian Salomondbf70722019-02-07 11:31:24 -0500361 return sk_sp<const GrGpuBuffer>(buffer);
Chris Dalton5d2de082017-12-19 10:40:23 -0700362 }
363 return nullptr;
364}
365
Brian Salomondbf70722019-02-07 11:31:24 -0500366sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
367 int patternSize,
368 int reps,
369 int vertCount,
Brian Salomona29dd9d2019-02-07 13:27:18 -0500370 const GrUniqueKey* key) {
bsalomoned0bcad2015-05-04 10:36:42 -0700371 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
372
Brian Salomondbf70722019-02-07 11:31:24 -0500373 sk_sp<GrGpuBuffer> buffer(
374 this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
bsalomoned0bcad2015-05-04 10:36:42 -0700375 if (!buffer) {
halcanary96fcdcc2015-08-27 07:41:13 -0700376 return nullptr;
bsalomoned0bcad2015-05-04 10:36:42 -0700377 }
Brian Salomon7f56d3d2017-10-09 13:02:49 -0400378 uint16_t* data = (uint16_t*) buffer->map();
379 SkAutoTArray<uint16_t> temp;
380 if (!data) {
381 temp.reset(reps * patternSize);
382 data = temp.get();
383 }
bsalomoned0bcad2015-05-04 10:36:42 -0700384 for (int i = 0; i < reps; ++i) {
385 int baseIdx = i * patternSize;
386 uint16_t baseVert = (uint16_t)(i * vertCount);
387 for (int j = 0; j < patternSize; ++j) {
388 data[baseIdx+j] = baseVert + pattern[j];
389 }
390 }
Brian Salomon7f56d3d2017-10-09 13:02:49 -0400391 if (temp.get()) {
392 if (!buffer->updateData(data, bufferSize)) {
393 return nullptr;
394 }
395 } else {
396 buffer->unmap();
bsalomoned0bcad2015-05-04 10:36:42 -0700397 }
Brian Salomona29dd9d2019-02-07 13:27:18 -0500398 if (key) {
399 SkASSERT(key->isValid());
400 this->assignUniqueKeyToResource(*key, buffer.get());
401 }
Brian Salomon9c73e3d2019-08-15 10:55:49 -0400402 return buffer;
bsalomoned0bcad2015-05-04 10:36:42 -0700403}
404
Robert Phillipsee08d522019-10-28 16:34:44 -0400405///////////////////////////////////////////////////////////////////////////////////////////////////
406static constexpr int kMaxNumNonAAQuads = 1 << 12; // max possible: (1 << 14) - 1;
407static const int kVertsPerNonAAQuad = 4;
408static const int kIndicesPerNonAAQuad = 6;
Brian Salomon34169692017-08-28 15:32:01 -0400409
Robert Phillipsee08d522019-10-28 16:34:44 -0400410sk_sp<const GrGpuBuffer> GrResourceProvider::createNonAAQuadIndexBuffer() {
Brian Salomon4dea72a2019-12-18 10:43:10 -0500411 static_assert(kVertsPerNonAAQuad * kMaxNumNonAAQuads <= 65535); // indices fit in a uint16_t
Robert Phillipsee08d522019-10-28 16:34:44 -0400412
413 static const uint16_t kNonAAQuadIndexPattern[] = {
414 0, 1, 2, 2, 1, 3
415 };
416
Brian Salomon4dea72a2019-12-18 10:43:10 -0500417 static_assert(SK_ARRAY_COUNT(kNonAAQuadIndexPattern) == kIndicesPerNonAAQuad);
Robert Phillipsee08d522019-10-28 16:34:44 -0400418
419 return this->createPatternedIndexBuffer(kNonAAQuadIndexPattern, kIndicesPerNonAAQuad,
420 kMaxNumNonAAQuads, kVertsPerNonAAQuad, nullptr);
bsalomoned0bcad2015-05-04 10:36:42 -0700421}
422
Robert Phillipsee08d522019-10-28 16:34:44 -0400423int GrResourceProvider::MaxNumNonAAQuads() { return kMaxNumNonAAQuads; }
424int GrResourceProvider::NumVertsPerNonAAQuad() { return kVertsPerNonAAQuad; }
425int GrResourceProvider::NumIndicesPerNonAAQuad() { return kIndicesPerNonAAQuad; }
Brian Salomon34169692017-08-28 15:32:01 -0400426
Robert Phillipsee08d522019-10-28 16:34:44 -0400427///////////////////////////////////////////////////////////////////////////////////////////////////
Robert Phillips8bc157e2019-11-15 12:04:48 -0500428static constexpr int kMaxNumAAQuads = 1 << 9; // max possible: (1 << 13) - 1;
Robert Phillipsee08d522019-10-28 16:34:44 -0400429static const int kVertsPerAAQuad = 8;
430static const int kIndicesPerAAQuad = 30;
431
432sk_sp<const GrGpuBuffer> GrResourceProvider::createAAQuadIndexBuffer() {
Brian Salomon4dea72a2019-12-18 10:43:10 -0500433 static_assert(kVertsPerAAQuad * kMaxNumAAQuads <= 65535); // indices fit in a uint16_t
Robert Phillipsee08d522019-10-28 16:34:44 -0400434
435 // clang-format off
436 static const uint16_t kAAQuadIndexPattern[] = {
437 0, 1, 2, 1, 3, 2,
438 0, 4, 1, 4, 5, 1,
439 0, 6, 4, 0, 2, 6,
440 2, 3, 6, 3, 7, 6,
441 1, 5, 3, 3, 5, 7,
442 };
443 // clang-format on
444
Brian Salomon4dea72a2019-12-18 10:43:10 -0500445 static_assert(SK_ARRAY_COUNT(kAAQuadIndexPattern) == kIndicesPerAAQuad);
Robert Phillipsee08d522019-10-28 16:34:44 -0400446
447 return this->createPatternedIndexBuffer(kAAQuadIndexPattern, kIndicesPerAAQuad,
448 kMaxNumAAQuads, kVertsPerAAQuad, nullptr);
449}
450
451int GrResourceProvider::MaxNumAAQuads() { return kMaxNumAAQuads; }
452int GrResourceProvider::NumVertsPerAAQuad() { return kVertsPerAAQuad; }
453int GrResourceProvider::NumIndicesPerAAQuad() { return kIndicesPerAAQuad; }
454
455///////////////////////////////////////////////////////////////////////////////////////////////////
Robert Phillips67d52cf2017-06-05 13:38:13 -0400456sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
Robert Phillips0f171812017-09-21 14:25:31 -0400457 if (this->isAbandoned()) {
458 return nullptr;
459 }
460
bsalomon706f08f2015-05-22 07:35:58 -0700461 SkASSERT(this->gpu()->pathRendering());
bsalomon6663acf2016-05-10 09:14:17 -0700462 return this->gpu()->pathRendering()->createPath(path, style);
bsalomon706f08f2015-05-22 07:35:58 -0700463}
464
Brian Salomondbf70722019-02-07 11:31:24 -0500465sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
466 GrAccessPattern accessPattern,
467 const void* data) {
robertphillips1b8e1b52015-06-24 06:54:10 -0700468 if (this->isAbandoned()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700469 return nullptr;
robertphillips1b8e1b52015-06-24 06:54:10 -0700470 }
cdaltond37fe762016-04-21 07:41:50 -0700471 if (kDynamic_GrAccessPattern != accessPattern) {
472 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
473 }
cdaltond37fe762016-04-21 07:41:50 -0700474 // bin by pow2 with a reasonable min
Robert Phillips9e380472016-10-28 12:15:03 -0400475 static const size_t MIN_SIZE = 1 << 12;
476 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
robertphillips1b8e1b52015-06-24 06:54:10 -0700477
cdaltond37fe762016-04-21 07:41:50 -0700478 GrScratchKey key;
Brian Salomondbf70722019-02-07 11:31:24 -0500479 GrGpuBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
480 auto buffer =
481 sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
Robert Phillipsaee18c92019-09-06 11:48:27 -0400482 key)));
cdaltond37fe762016-04-21 07:41:50 -0700483 if (!buffer) {
484 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
485 if (!buffer) {
486 return nullptr;
robertphillips1b8e1b52015-06-24 06:54:10 -0700487 }
488 }
cdaltond37fe762016-04-21 07:41:50 -0700489 if (data) {
490 buffer->updateData(data, size);
491 }
492 return buffer;
jvanverth17aa0472016-01-05 10:41:27 -0800493}
494
Chris Daltonf00b95b2019-11-07 21:14:41 -0700495bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, int numStencilSamples) {
egdanielec00d942015-09-14 12:56:10 -0700496 SkASSERT(rt);
Chris Daltoneffee202019-07-01 22:28:03 -0600497 GrStencilAttachment* stencil = rt->renderTargetPriv().getStencilAttachment();
Chris Daltonf00b95b2019-11-07 21:14:41 -0700498 if (stencil && stencil->numSamples() == numStencilSamples) {
Robert Phillipsc0192e32017-09-21 12:00:26 -0400499 return true;
egdanielec00d942015-09-14 12:56:10 -0700500 }
501
502 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
503 GrUniqueKey sbKey;
504
505 int width = rt->width();
506 int height = rt->height();
507#if 0
508 if (this->caps()->oversizedStencilSupport()) {
509 width = SkNextPow2(width);
510 height = SkNextPow2(height);
511 }
512#endif
Chris Daltoneffee202019-07-01 22:28:03 -0600513 GrStencilAttachment::ComputeSharedStencilAttachmentKey(
Chris Daltonf00b95b2019-11-07 21:14:41 -0700514 width, height, numStencilSamples, &sbKey);
Brian Salomond28a79d2017-10-16 13:01:07 -0400515 auto stencil = this->findByUniqueKey<GrStencilAttachment>(sbKey);
egdanielec00d942015-09-14 12:56:10 -0700516 if (!stencil) {
517 // Need to try and create a new stencil
Chris Daltoneffee202019-07-01 22:28:03 -0600518 stencil.reset(this->gpu()->createStencilAttachmentForRenderTarget(
Chris Daltonf00b95b2019-11-07 21:14:41 -0700519 rt, width, height, numStencilSamples));
Robert Phillips01a91282018-07-26 08:03:04 -0400520 if (!stencil) {
521 return false;
egdanielec00d942015-09-14 12:56:10 -0700522 }
Robert Phillips01a91282018-07-26 08:03:04 -0400523 this->assignUniqueKeyToResource(sbKey, stencil.get());
egdanielec00d942015-09-14 12:56:10 -0700524 }
Greg Danielcfa39352018-10-05 12:01:59 -0400525 rt->renderTargetPriv().attachStencilAttachment(std::move(stencil));
egdanielec00d942015-09-14 12:56:10 -0700526 }
Chris Dalton215ff332019-07-02 09:38:22 -0600527
528 if (GrStencilAttachment* stencil = rt->renderTargetPriv().getStencilAttachment()) {
Chris Daltonf00b95b2019-11-07 21:14:41 -0700529 return stencil->numSamples() == numStencilSamples;
Chris Dalton215ff332019-07-02 09:38:22 -0600530 }
531 return false;
egdanielec00d942015-09-14 12:56:10 -0700532}
533
bungeman6bd52842016-10-27 09:30:08 -0700534sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400535 const GrBackendTexture& tex, int sampleCnt, GrColorType colorType)
bungeman6bd52842016-10-27 09:30:08 -0700536{
ericrkf7b8b8a2016-02-24 14:49:51 -0800537 if (this->isAbandoned()) {
538 return nullptr;
539 }
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400540 return fGpu->wrapBackendTextureAsRenderTarget(tex, sampleCnt, colorType);
ericrkf7b8b8a2016-02-24 14:49:51 -0800541}
Greg Danield85f97d2017-03-07 13:37:21 -0500542
Greg Daniel301015c2019-11-18 14:06:46 -0500543std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(
544 bool isOwned) {
545 return this->isAbandoned() ? nullptr : fGpu->makeSemaphore(isOwned);
Greg Daniela5cb7812017-06-16 09:45:32 -0400546}
547
Greg Daniel301015c2019-11-18 14:06:46 -0500548std::unique_ptr<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(
549 const GrBackendSemaphore& semaphore,
550 SemaphoreWrapType wrapType,
551 GrWrapOwnership ownership) {
Greg Daniela5cb7812017-06-16 09:45:32 -0400552 ASSERT_SINGLE_OWNER
Greg Daniel17b7c052018-01-09 13:55:33 -0500553 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
554 wrapType,
555 ownership);
Greg Danield85f97d2017-03-07 13:37:21 -0500556}
Brian Salomon8660eb02019-09-20 13:04:13 -0400557
558// Ensures the row bytes are populated (not 0) and makes a copy to a temporary
559// to make the row bytes tight if necessary. Returns false if the input row bytes are invalid.
560static bool prepare_level(const GrMipLevel& inLevel,
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400561 const SkISize& dimensions,
Brian Salomon8660eb02019-09-20 13:04:13 -0400562 bool rowBytesSupport,
563 GrColorType origColorType,
564 GrColorType allowedColorType,
565 GrMipLevel* outLevel,
566 std::unique_ptr<char[]>* data) {
567 if (!inLevel.fPixels) {
568 outLevel->fPixels = nullptr;
569 outLevel->fRowBytes = 0;
570 return true;
571 }
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400572 size_t minRB = dimensions.fWidth * GrColorTypeBytesPerPixel(origColorType);
Brian Salomon8660eb02019-09-20 13:04:13 -0400573 size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
574 if (actualRB < minRB) {
575 return false;
576 }
577 if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
578 outLevel->fRowBytes = actualRB;
579 outLevel->fPixels = inLevel.fPixels;
580 return true;
581 }
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400582 auto tempRB = dimensions.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
583 data->reset(new char[tempRB * dimensions.fHeight]);
Brian Salomon8660eb02019-09-20 13:04:13 -0400584 outLevel->fPixels = data->get();
585 outLevel->fRowBytes = tempRB;
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400586 GrImageInfo srcInfo(origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
587 GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
Brian Salomon8660eb02019-09-20 13:04:13 -0400588 return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
589}
590
591GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
592 GrColorType colorType,
593 const SkISize& baseSize,
594 const GrMipLevel texels[],
595 int mipLevelCount,
596 TempLevels* tempLevels,
597 TempLevelDatas* tempLevelDatas) const {
598 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
599
600 auto allowedColorType =
601 this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
602 if (allowedColorType == GrColorType::kUnknown) {
603 return GrColorType::kUnknown;
604 }
605 bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
606 tempLevels->reset(mipLevelCount);
607 tempLevelDatas->reset(mipLevelCount);
608 auto size = baseSize;
609 for (int i = 0; i < mipLevelCount; ++i) {
610 if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
611 &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
612 return GrColorType::kUnknown;
613 }
614 size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
615 }
616 return allowedColorType;
617}
618
619sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
620 GrColorType colorType,
621 const SkISize& baseSize,
622 const GrMipLevel texels[],
623 int mipLevelCount) const {
624 SkASSERT(!this->isAbandoned());
625 SkASSERT(texture);
626 SkASSERT(colorType != GrColorType::kUnknown);
627 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
628
629 SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
630 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
631 auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
632 mipLevelCount, &tmpTexels, &tmpDatas);
633 if (tempColorType == GrColorType::kUnknown) {
634 return nullptr;
635 }
636 SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
637 colorType, tempColorType, tmpTexels.get(), mipLevelCount));
638 return texture;
639}