blob: 5e2798a31299147f85ea8f3cec985c7b4a930ed5 [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/private/GrResourceKey.h"
12#include "include/private/GrSingleOwner.h"
Brian Salomon1047a492019-07-02 12:25:21 -040013#include "src/core/SkConvertPixels.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/core/SkMathPriv.h"
Robert Phillips6c706612020-12-07 12:12:05 -050015#include "src/core/SkMipmap.h"
Greg Danielc0d69152020-10-08 14:59:00 -040016#include "src/gpu/GrAttachment.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrCaps.h"
Robert Phillipse19babf2020-04-06 13:57:30 -040018#include "src/gpu/GrDataUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/GrGpu.h"
20#include "src/gpu/GrGpuBuffer.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040021#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/gpu/GrPath.h"
23#include "src/gpu/GrPathRendering.h"
24#include "src/gpu/GrProxyProvider.h"
Brian Salomonf7f54332020-07-28 09:23:35 -040025#include "src/gpu/GrRenderTarget.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/GrResourceCache.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/gpu/GrSemaphore.h"
Brian Salomon4cfae3b2020-07-23 10:33:24 -040028#include "src/gpu/GrTexture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#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
Adlai Holler33dbd652020-06-01 12:35:42 -040033#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fSingleOwner)
Brian Osman32342f02017-03-04 08:12:46 -050034
Robert Phillips12c46292019-04-23 07:36:17 -040035GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner)
Brian Osman32342f02017-03-04 08:12:46 -050036 : fCache(cache)
37 , fGpu(gpu)
38#ifdef SK_DEBUG
39 , fSingleOwner(owner)
40#endif
Robert Phillips4150eea2018-02-07 17:08:21 -050041{
Robert Phillips26c90e02017-03-14 14:39:29 -040042 fCaps = sk_ref_sp(fGpu->caps());
bsalomoned0bcad2015-05-04 10:36:42 -070043}
44
Brian Salomona56a7462020-02-07 14:17:25 -050045sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
Brian Salomon4eb38b72019-08-05 12:58:39 -040046 const GrBackendFormat& format,
Brian Salomona90382f2019-09-17 09:01:56 -040047 GrColorType colorType,
Brian Salomon27b4d8d2019-07-22 14:23:45 -040048 GrRenderable renderable,
Brian Salomon2af3e702019-08-11 19:10:31 -040049 int renderTargetSampleCnt,
50 SkBudgeted budgeted,
Robert Phillips6c706612020-12-07 12:12:05 -050051 GrMipMapped mipMapped,
Brian Salomone8a766b2019-07-19 14:24:36 -040052 GrProtected isProtected,
Robert Phillips6c706612020-12-07 12:12:05 -050053 const GrMipLevel texels[]) {
Brian Osman32342f02017-03-04 08:12:46 -050054 ASSERT_SINGLE_OWNER
55
56 if (this->isAbandoned()) {
57 return nullptr;
58 }
Robert Phillips1119dc32017-04-11 12:54:57 -040059
Robert Phillips6c706612020-12-07 12:12:05 -050060 int numMipLevels = 1;
61 if (mipMapped == GrMipMapped::kYes) {
62 numMipLevels = SkMipmap::ComputeLevelCount(dimensions.fWidth, dimensions.fHeight) + 1;
63 }
64
Brian Salomona56a7462020-02-07 14:17:25 -050065 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
66 mipMapped)) {
Brian Osman32342f02017-03-04 08:12:46 -050067 return nullptr;
68 }
Brian Salomon8660eb02019-09-20 13:04:13 -040069 // Current rule is that you can provide no level data, just the base, or all the levels.
Robert Phillips6c706612020-12-07 12:12:05 -050070 bool hasPixels = texels[0].fPixels;
Brian Salomona56a7462020-02-07 14:17:25 -050071 auto scratch = this->getExactScratch(dimensions, format, renderable, renderTargetSampleCnt,
72 budgeted, mipMapped, isProtected);
Brian Salomon8660eb02019-09-20 13:04:13 -040073 if (scratch) {
74 if (!hasPixels) {
75 return scratch;
76 }
Robert Phillips6c706612020-12-07 12:12:05 -050077 return this->writePixels(std::move(scratch), colorType, dimensions, texels, numMipLevels);
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) {
Robert Phillips6c706612020-12-07 12:12:05 -050083 tempColorType = this->prepareLevels(format, colorType, dimensions, texels, numMipLevels,
Brian Salomona56a7462020-02-07 14:17:25 -050084 &tmpTexels, &tmpDatas);
Brian Salomon8660eb02019-09-20 13:04:13 -040085 if (tempColorType == GrColorType::kUnknown) {
86 return nullptr;
Brian Salomon1047a492019-07-02 12:25:21 -040087 }
88 }
Brian Salomona56a7462020-02-07 14:17:25 -050089 return fGpu->createTexture(dimensions, format, renderable, renderTargetSampleCnt, budgeted,
Brian Salomon8660eb02019-09-20 13:04:13 -040090 isProtected, colorType, tempColorType, tmpTexels.get(),
Robert Phillips6c706612020-12-07 12:12:05 -050091 numMipLevels);
Brian Osman32342f02017-03-04 08:12:46 -050092}
93
Brian Salomona56a7462020-02-07 14:17:25 -050094sk_sp<GrTexture> GrResourceProvider::getExactScratch(SkISize dimensions,
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 Salomon7e67dca2020-07-21 09:27:25 -040099 GrMipmapped mipMapped,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400100 GrProtected isProtected) {
Brian Salomona56a7462020-02-07 14:17:25 -0500101 sk_sp<GrTexture> tex(this->refScratchTexture(dimensions, format, renderable,
102 renderTargetSampleCnt, 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
Brian Salomona56a7462020-02-07 14:17:25 -0500110sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
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 }
Brian Salomona56a7462020-02-07 14:17:25 -0500129 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400130 GrMipmapped::kNo)) {
Brian Salomon8660eb02019-09-20 13:04:13 -0400131 return nullptr;
132 }
133
Brian Salomona56a7462020-02-07 14:17:25 -0500134 auto tex = this->createApproxTexture(dimensions, format, renderable, renderTargetSampleCnt,
Brian Salomon8660eb02019-09-20 13:04:13 -0400135 isProtected);
Brian Salomona90382f2019-09-17 09:01:56 -0400136 if (!tex) {
137 return nullptr;
138 }
Brian Salomona56a7462020-02-07 14:17:25 -0500139 return this->writePixels(std::move(tex), colorType, dimensions, &mipLevel, 1);
Brian Salomona90382f2019-09-17 09:01:56 -0400140 } else {
Brian Salomona56a7462020-02-07 14:17:25 -0500141 return this->createTexture(dimensions, format, colorType, renderable, renderTargetSampleCnt,
Robert Phillips6c706612020-12-07 12:12:05 -0500142 budgeted, GrMipMapped::kNo, isProtected, &mipLevel);
Brian Salomona3ffaab2019-07-09 12:26:46 -0400143 }
Robert Phillips45fdae12017-04-17 12:57:27 -0400144}
145
Robert Phillips9f744f72019-12-19 19:14:33 -0500146sk_sp<GrTexture> GrResourceProvider::createCompressedTexture(SkISize dimensions,
Greg Daniel7bfc9132019-08-14 14:23:53 -0400147 const GrBackendFormat& format,
Robert Phillipse4720c62020-01-14 14:33:24 -0500148 SkBudgeted budgeted,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400149 GrMipmapped mipMapped,
Robert Phillips3a833922020-01-21 15:25:58 -0500150 GrProtected isProtected,
Robert Phillipse4720c62020-01-14 14:33:24 -0500151 SkData* data) {
Brian Salomonbb8dde82019-06-27 10:52:13 -0400152 ASSERT_SINGLE_OWNER
153 if (this->isAbandoned()) {
154 return nullptr;
155 }
Robert Phillipse4720c62020-01-14 14:33:24 -0500156 return fGpu->createCompressedTexture(dimensions, format, budgeted, mipMapped,
Robert Phillips3a833922020-01-21 15:25:58 -0500157 isProtected, data->data(), data->size());
Brian Salomonbb8dde82019-06-27 10:52:13 -0400158}
159
Brian Salomona56a7462020-02-07 14:17:25 -0500160sk_sp<GrTexture> GrResourceProvider::createTexture(SkISize dimensions,
Brian Salomon4eb38b72019-08-05 12:58:39 -0400161 const GrBackendFormat& format,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400162 GrRenderable renderable,
163 int renderTargetSampleCnt,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400164 GrMipmapped mipMapped,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400165 SkBudgeted budgeted,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400166 GrProtected isProtected) {
Robert Phillipse78b7252017-04-06 07:59:41 -0400167 ASSERT_SINGLE_OWNER
Robert Phillipse78b7252017-04-06 07:59:41 -0400168 if (this->isAbandoned()) {
169 return nullptr;
Brian Osman32342f02017-03-04 08:12:46 -0500170 }
Robert Phillipse78b7252017-04-06 07:59:41 -0400171
Brian Salomona56a7462020-02-07 14:17:25 -0500172 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
173 mipMapped)) {
Robert Phillipse78b7252017-04-06 07:59:41 -0400174 return nullptr;
175 }
176
Greg Danielc3a927f2019-10-16 12:03:50 -0400177 // Currently we don't recycle compressed textures as scratch. Additionally all compressed
178 // textures should be created through the createCompressedTexture function.
179 SkASSERT(!this->caps()->isFormatCompressed(format));
180
Brian Salomon7e67dca2020-07-21 09:27:25 -0400181 // TODO: Support GrMipmapped::kYes in scratch texture lookup here.
Brian Salomona56a7462020-02-07 14:17:25 -0500182 sk_sp<GrTexture> tex =
183 this->getExactScratch(dimensions, format, renderable, renderTargetSampleCnt, budgeted,
184 mipMapped, isProtected);
Greg Danielc3a927f2019-10-16 12:03:50 -0400185 if (tex) {
186 return tex;
Robert Phillipse78b7252017-04-06 07:59:41 -0400187 }
188
Brian Salomona56a7462020-02-07 14:17:25 -0500189 return fGpu->createTexture(dimensions, format, renderable, renderTargetSampleCnt, mipMapped,
190 budgeted, isProtected);
Brian Osman32342f02017-03-04 08:12:46 -0500191}
192
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400193// Map 'value' to a larger multiple of 2. Values <= 'kMagicTol' will pop up to
194// 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 -0400195SkISize GrResourceProvider::MakeApprox(SkISize dimensions) {
196 auto adjust = [](int value) {
197 static const int kMagicTol = 1024;
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400198
Brian Osman788b9162020-02-07 10:36:46 -0500199 value = std::max(kMinScratchTextureSize, value);
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400200
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400201 if (SkIsPow2(value)) {
202 return value;
203 }
204
205 int ceilPow2 = SkNextPow2(value);
206 if (value <= kMagicTol) {
207 return ceilPow2;
208 }
209
210 int floorPow2 = ceilPow2 >> 1;
211 int mid = floorPow2 + (floorPow2 >> 1);
212
213 if (value <= mid) {
214 return mid;
215 }
Brian Salomon322301a2019-10-24 12:50:50 -0400216 return ceilPow2;
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400217 };
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400218
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400219 return {adjust(dimensions.width()), adjust(dimensions.height())};
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400220}
221
Brian Salomona56a7462020-02-07 14:17:25 -0500222sk_sp<GrTexture> GrResourceProvider::createApproxTexture(SkISize dimensions,
Brian Salomon4eb38b72019-08-05 12:58:39 -0400223 const GrBackendFormat& format,
Brian Salomone8a766b2019-07-19 14:24:36 -0400224 GrRenderable renderable,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400225 int renderTargetSampleCnt,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400226 GrProtected isProtected) {
Brian Osman32342f02017-03-04 08:12:46 -0500227 ASSERT_SINGLE_OWNER
Brian Osman32342f02017-03-04 08:12:46 -0500228
Brian Osman32342f02017-03-04 08:12:46 -0500229 if (this->isAbandoned()) {
230 return nullptr;
231 }
Robert Phillips1119dc32017-04-11 12:54:57 -0400232
Greg Danielc3a927f2019-10-16 12:03:50 -0400233 // Currently we don't recycle compressed textures as scratch. Additionally all compressed
234 // textures should be created through the createCompressedTexture function.
235 SkASSERT(!this->caps()->isFormatCompressed(format));
Jim Van Verth1676cb92019-01-15 13:24:45 -0500236
Brian Salomona56a7462020-02-07 14:17:25 -0500237 if (!fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400238 GrMipmapped::kNo)) {
Brian Salomond34edf32017-05-19 15:45:48 -0400239 return nullptr;
240 }
241
Brian Salomona56a7462020-02-07 14:17:25 -0500242 auto copyDimensions = MakeApprox(dimensions);
Greg Daniel29bf84f2017-09-25 12:25:12 -0400243
Brian Salomona56a7462020-02-07 14:17:25 -0500244 if (auto tex = this->refScratchTexture(copyDimensions, format, renderable,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400245 renderTargetSampleCnt, GrMipmapped::kNo, isProtected)) {
Greg Daniel29bf84f2017-09-25 12:25:12 -0400246 return tex;
247 }
248
Brian Salomona56a7462020-02-07 14:17:25 -0500249 return fGpu->createTexture(copyDimensions, format, renderable, renderTargetSampleCnt,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400250 GrMipmapped::kNo, SkBudgeted::kYes, isProtected);
Brian Osman32342f02017-03-04 08:12:46 -0500251}
252
Brian Salomona56a7462020-02-07 14:17:25 -0500253sk_sp<GrTexture> GrResourceProvider::refScratchTexture(SkISize dimensions,
Brian Salomon4eb38b72019-08-05 12:58:39 -0400254 const GrBackendFormat& format,
Brian Salomone8a766b2019-07-19 14:24:36 -0400255 GrRenderable renderable,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400256 int renderTargetSampleCnt,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400257 GrMipmapped mipMapped,
Robert Phillipsaee18c92019-09-06 11:48:27 -0400258 GrProtected isProtected) {
Brian Osman32342f02017-03-04 08:12:46 -0500259 ASSERT_SINGLE_OWNER
260 SkASSERT(!this->isAbandoned());
Greg Danielc3a927f2019-10-16 12:03:50 -0400261 SkASSERT(!this->caps()->isFormatCompressed(format));
Brian Salomona56a7462020-02-07 14:17:25 -0500262 SkASSERT(fCaps->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400263 GrMipmapped::kNo));
Brian Osman32342f02017-03-04 08:12:46 -0500264
Brian Salomond17b4a62017-05-23 16:53:47 -0400265 // We could make initial clears work with scratch textures but it is a rare case so we just opt
266 // to fall back to making a new texture.
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400267 if (fGpu->caps()->reuseScratchTextures() || renderable == GrRenderable::kYes) {
Brian Osman32342f02017-03-04 08:12:46 -0500268 GrScratchKey key;
Brian Salomon4cfae3b2020-07-23 10:33:24 -0400269 GrTexture::ComputeScratchKey(*this->caps(), format, dimensions, renderable,
270 renderTargetSampleCnt, mipMapped, isProtected, &key);
Robert Phillipsaee18c92019-09-06 11:48:27 -0400271 GrGpuResource* resource = fCache->findAndRefScratchResource(key);
Brian Osman32342f02017-03-04 08:12:46 -0500272 if (resource) {
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400273 fGpu->stats()->incNumScratchTexturesReused();
Brian Osman32342f02017-03-04 08:12:46 -0500274 GrSurface* surface = static_cast<GrSurface*>(resource);
Robert Phillips67d52cf2017-06-05 13:38:13 -0400275 return sk_sp<GrTexture>(surface->asTexture());
Brian Osman32342f02017-03-04 08:12:46 -0500276 }
277 }
278
Brian Osman32342f02017-03-04 08:12:46 -0500279 return nullptr;
280}
281
Greg Daniel7ef28f32017-04-20 16:41:55 +0000282sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
Greg Daniel2268ad22018-11-15 09:27:38 -0500283 GrWrapOwnership ownership,
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500284 GrWrapCacheable cacheable,
285 GrIOType ioType) {
Brian Osman32342f02017-03-04 08:12:46 -0500286 ASSERT_SINGLE_OWNER
287 if (this->isAbandoned()) {
288 return nullptr;
289 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400290 return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType);
Brian Salomond17f6582017-07-19 18:28:58 -0400291}
292
Robert Phillipsead321b2019-12-19 10:16:32 -0500293sk_sp<GrTexture> GrResourceProvider::wrapCompressedBackendTexture(const GrBackendTexture& tex,
294 GrWrapOwnership ownership,
295 GrWrapCacheable cacheable) {
296 ASSERT_SINGLE_OWNER
297 if (this->isAbandoned()) {
298 return nullptr;
299 }
300
301 return fGpu->wrapCompressedBackendTexture(tex, ownership, cacheable);
302}
303
304
Brian Salomond17f6582017-07-19 18:28:58 -0400305sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
Brian Salomond17f6582017-07-19 18:28:58 -0400306 int sampleCnt,
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500307 GrWrapOwnership ownership,
308 GrWrapCacheable cacheable) {
Brian Salomond17f6582017-07-19 18:28:58 -0400309 ASSERT_SINGLE_OWNER
310 if (this->isAbandoned()) {
311 return nullptr;
312 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400313 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable);
Brian Osman32342f02017-03-04 08:12:46 -0500314}
315
316sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400317 const GrBackendRenderTarget& backendRT) {
Brian Osman32342f02017-03-04 08:12:46 -0500318 ASSERT_SINGLE_OWNER
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400319 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
Brian Osman32342f02017-03-04 08:12:46 -0500320}
321
Greg Danielb46add82019-01-02 14:51:29 -0500322sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
323 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
324 ASSERT_SINGLE_OWNER
325 return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
326 vkInfo);
327
328}
329
Brian Osman32342f02017-03-04 08:12:46 -0500330void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
331 GrGpuResource* resource) {
332 ASSERT_SINGLE_OWNER
333 if (this->isAbandoned() || !resource) {
334 return;
335 }
336 resource->resourcePriv().setUniqueKey(key);
337}
338
Brian Salomond28a79d2017-10-16 13:01:07 -0400339sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
Brian Osman32342f02017-03-04 08:12:46 -0500340 ASSERT_SINGLE_OWNER
Brian Salomond28a79d2017-10-16 13:01:07 -0400341 return this->isAbandoned() ? nullptr
342 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
Brian Osman32342f02017-03-04 08:12:46 -0500343}
344
Brian Salomondbf70722019-02-07 11:31:24 -0500345sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
346 size_t size,
347 const void* data,
348 const GrUniqueKey& key) {
349 if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
Mike Kleina9609ea2020-02-18 13:33:23 -0600350 return std::move(buffer);
Chris Dalton5d2de082017-12-19 10:40:23 -0700351 }
Brian Salomondbf70722019-02-07 11:31:24 -0500352 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
Chris Dalton133944a2018-11-16 23:30:29 -0500353 // We shouldn't bin and/or cache static buffers.
Brian Salomondbf70722019-02-07 11:31:24 -0500354 SkASSERT(buffer->size() == size);
Chris Dalton5d2de082017-12-19 10:40:23 -0700355 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
Chris Dalton5d2de082017-12-19 10:40:23 -0700356 buffer->resourcePriv().setUniqueKey(key);
Brian Salomondbf70722019-02-07 11:31:24 -0500357 return sk_sp<const GrGpuBuffer>(buffer);
Chris Dalton5d2de082017-12-19 10:40:23 -0700358 }
359 return nullptr;
360}
361
Brian Salomondbf70722019-02-07 11:31:24 -0500362sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
363 int patternSize,
364 int reps,
365 int vertCount,
Brian Salomona29dd9d2019-02-07 13:27:18 -0500366 const GrUniqueKey* key) {
bsalomoned0bcad2015-05-04 10:36:42 -0700367 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
368
Brian Salomondbf70722019-02-07 11:31:24 -0500369 sk_sp<GrGpuBuffer> buffer(
370 this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
bsalomoned0bcad2015-05-04 10:36:42 -0700371 if (!buffer) {
halcanary96fcdcc2015-08-27 07:41:13 -0700372 return nullptr;
bsalomoned0bcad2015-05-04 10:36:42 -0700373 }
Brian Salomon7f56d3d2017-10-09 13:02:49 -0400374 uint16_t* data = (uint16_t*) buffer->map();
375 SkAutoTArray<uint16_t> temp;
376 if (!data) {
377 temp.reset(reps * patternSize);
378 data = temp.get();
379 }
bsalomoned0bcad2015-05-04 10:36:42 -0700380 for (int i = 0; i < reps; ++i) {
381 int baseIdx = i * patternSize;
382 uint16_t baseVert = (uint16_t)(i * vertCount);
383 for (int j = 0; j < patternSize; ++j) {
384 data[baseIdx+j] = baseVert + pattern[j];
385 }
386 }
Brian Salomon7f56d3d2017-10-09 13:02:49 -0400387 if (temp.get()) {
388 if (!buffer->updateData(data, bufferSize)) {
389 return nullptr;
390 }
391 } else {
392 buffer->unmap();
bsalomoned0bcad2015-05-04 10:36:42 -0700393 }
Brian Salomona29dd9d2019-02-07 13:27:18 -0500394 if (key) {
395 SkASSERT(key->isValid());
396 this->assignUniqueKeyToResource(*key, buffer.get());
397 }
Mike Kleina9609ea2020-02-18 13:33:23 -0600398 return std::move(buffer);
bsalomoned0bcad2015-05-04 10:36:42 -0700399}
400
Robert Phillipsee08d522019-10-28 16:34:44 -0400401///////////////////////////////////////////////////////////////////////////////////////////////////
402static constexpr int kMaxNumNonAAQuads = 1 << 12; // max possible: (1 << 14) - 1;
403static const int kVertsPerNonAAQuad = 4;
404static const int kIndicesPerNonAAQuad = 6;
Brian Salomon34169692017-08-28 15:32:01 -0400405
Robert Phillipsee08d522019-10-28 16:34:44 -0400406sk_sp<const GrGpuBuffer> GrResourceProvider::createNonAAQuadIndexBuffer() {
Brian Salomon4dea72a2019-12-18 10:43:10 -0500407 static_assert(kVertsPerNonAAQuad * kMaxNumNonAAQuads <= 65535); // indices fit in a uint16_t
Robert Phillipsee08d522019-10-28 16:34:44 -0400408
409 static const uint16_t kNonAAQuadIndexPattern[] = {
410 0, 1, 2, 2, 1, 3
411 };
412
Brian Salomon4dea72a2019-12-18 10:43:10 -0500413 static_assert(SK_ARRAY_COUNT(kNonAAQuadIndexPattern) == kIndicesPerNonAAQuad);
Robert Phillipsee08d522019-10-28 16:34:44 -0400414
415 return this->createPatternedIndexBuffer(kNonAAQuadIndexPattern, kIndicesPerNonAAQuad,
416 kMaxNumNonAAQuads, kVertsPerNonAAQuad, nullptr);
bsalomoned0bcad2015-05-04 10:36:42 -0700417}
418
Robert Phillipsee08d522019-10-28 16:34:44 -0400419int GrResourceProvider::MaxNumNonAAQuads() { return kMaxNumNonAAQuads; }
420int GrResourceProvider::NumVertsPerNonAAQuad() { return kVertsPerNonAAQuad; }
421int GrResourceProvider::NumIndicesPerNonAAQuad() { return kIndicesPerNonAAQuad; }
Brian Salomon34169692017-08-28 15:32:01 -0400422
Robert Phillipsee08d522019-10-28 16:34:44 -0400423///////////////////////////////////////////////////////////////////////////////////////////////////
Robert Phillips8bc157e2019-11-15 12:04:48 -0500424static constexpr int kMaxNumAAQuads = 1 << 9; // max possible: (1 << 13) - 1;
Robert Phillipsee08d522019-10-28 16:34:44 -0400425static const int kVertsPerAAQuad = 8;
426static const int kIndicesPerAAQuad = 30;
427
428sk_sp<const GrGpuBuffer> GrResourceProvider::createAAQuadIndexBuffer() {
Brian Salomon4dea72a2019-12-18 10:43:10 -0500429 static_assert(kVertsPerAAQuad * kMaxNumAAQuads <= 65535); // indices fit in a uint16_t
Robert Phillipsee08d522019-10-28 16:34:44 -0400430
431 // clang-format off
432 static const uint16_t kAAQuadIndexPattern[] = {
433 0, 1, 2, 1, 3, 2,
434 0, 4, 1, 4, 5, 1,
435 0, 6, 4, 0, 2, 6,
436 2, 3, 6, 3, 7, 6,
437 1, 5, 3, 3, 5, 7,
438 };
439 // clang-format on
440
Brian Salomon4dea72a2019-12-18 10:43:10 -0500441 static_assert(SK_ARRAY_COUNT(kAAQuadIndexPattern) == kIndicesPerAAQuad);
Robert Phillipsee08d522019-10-28 16:34:44 -0400442
443 return this->createPatternedIndexBuffer(kAAQuadIndexPattern, kIndicesPerAAQuad,
444 kMaxNumAAQuads, kVertsPerAAQuad, nullptr);
445}
446
447int GrResourceProvider::MaxNumAAQuads() { return kMaxNumAAQuads; }
448int GrResourceProvider::NumVertsPerAAQuad() { return kVertsPerAAQuad; }
449int GrResourceProvider::NumIndicesPerAAQuad() { return kIndicesPerAAQuad; }
450
451///////////////////////////////////////////////////////////////////////////////////////////////////
Robert Phillips67d52cf2017-06-05 13:38:13 -0400452sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
Robert Phillips0f171812017-09-21 14:25:31 -0400453 if (this->isAbandoned()) {
454 return nullptr;
455 }
456
bsalomon706f08f2015-05-22 07:35:58 -0700457 SkASSERT(this->gpu()->pathRendering());
bsalomon6663acf2016-05-10 09:14:17 -0700458 return this->gpu()->pathRendering()->createPath(path, style);
bsalomon706f08f2015-05-22 07:35:58 -0700459}
460
Brian Salomondbf70722019-02-07 11:31:24 -0500461sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
462 GrAccessPattern accessPattern,
463 const void* data) {
robertphillips1b8e1b52015-06-24 06:54:10 -0700464 if (this->isAbandoned()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700465 return nullptr;
robertphillips1b8e1b52015-06-24 06:54:10 -0700466 }
cdaltond37fe762016-04-21 07:41:50 -0700467 if (kDynamic_GrAccessPattern != accessPattern) {
468 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
469 }
Jim Van Verth939cc7a2020-08-14 18:00:36 -0400470 // bin by pow2+midpoint with a reasonable min
Robert Phillips9e380472016-10-28 12:15:03 -0400471 static const size_t MIN_SIZE = 1 << 12;
Greg Daniel8eb119a2021-02-04 09:41:19 -0500472 static const size_t MIN_UNIFORM_SIZE = 1 << 7;
473 size_t allocSize = intendedType == GrGpuBufferType::kUniform ? std::max(size, MIN_UNIFORM_SIZE)
474 : std::max(size, MIN_SIZE);
Jim Van Verth939cc7a2020-08-14 18:00:36 -0400475 size_t ceilPow2 = GrNextSizePow2(allocSize);
476 size_t floorPow2 = ceilPow2 >> 1;
477 size_t mid = floorPow2 + (floorPow2 >> 1);
478 allocSize = (allocSize <= mid) ? mid : ceilPow2;
robertphillips1b8e1b52015-06-24 06:54:10 -0700479
cdaltond37fe762016-04-21 07:41:50 -0700480 GrScratchKey key;
Greg Daniel8eb119a2021-02-04 09:41:19 -0500481 GrGpuBuffer::ComputeScratchKeyForDynamicBuffer(allocSize, intendedType, &key);
Brian Salomondbf70722019-02-07 11:31:24 -0500482 auto buffer =
483 sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
Robert Phillipsaee18c92019-09-06 11:48:27 -0400484 key)));
cdaltond37fe762016-04-21 07:41:50 -0700485 if (!buffer) {
486 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
487 if (!buffer) {
488 return nullptr;
robertphillips1b8e1b52015-06-24 06:54:10 -0700489 }
490 }
cdaltond37fe762016-04-21 07:41:50 -0700491 if (data) {
492 buffer->updateData(data, size);
493 }
494 return buffer;
jvanverth17aa0472016-01-05 10:41:27 -0800495}
496
Chris Daltonf00b95b2019-11-07 21:14:41 -0700497bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt, int numStencilSamples) {
egdanielec00d942015-09-14 12:56:10 -0700498 SkASSERT(rt);
Greg Danielc0d69152020-10-08 14:59:00 -0400499 GrAttachment* stencil = rt->getStencilAttachment();
Chris Daltonf00b95b2019-11-07 21:14:41 -0700500 if (stencil && stencil->numSamples() == numStencilSamples) {
Robert Phillipsc0192e32017-09-21 12:00:26 -0400501 return true;
egdanielec00d942015-09-14 12:56:10 -0700502 }
503
504 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
505 GrUniqueKey sbKey;
506
egdanielec00d942015-09-14 12:56:10 -0700507#if 0
508 if (this->caps()->oversizedStencilSupport()) {
509 width = SkNextPow2(width);
510 height = SkNextPow2(height);
511 }
512#endif
Greg Danielb8949bd2020-10-12 15:21:02 -0400513 GrBackendFormat stencilFormat =
514 this->gpu()->getPreferredStencilFormat(rt->backendFormat());
515 if (!stencilFormat.isValid()) {
516 return false;
517 }
518 GrProtected isProtected = rt->isProtected() ? GrProtected::kYes : GrProtected::kNo;
Greg Danielc0d69152020-10-08 14:59:00 -0400519 GrAttachment::ComputeSharedAttachmentUniqueKey(
Greg Daniel25ebd952020-11-03 11:17:05 -0500520 *this->caps(), stencilFormat, rt->dimensions(),
521 GrAttachment::UsageFlags::kStencilAttachment, numStencilSamples, isProtected,
522 &sbKey);
Greg Danielc0d69152020-10-08 14:59:00 -0400523 auto stencil = this->findByUniqueKey<GrAttachment>(sbKey);
egdanielec00d942015-09-14 12:56:10 -0700524 if (!stencil) {
525 // Need to try and create a new stencil
Greg Danielc0d69152020-10-08 14:59:00 -0400526 stencil = this->gpu()->makeStencilAttachmentForRenderTarget(rt, rt->dimensions(),
527 numStencilSamples);
Robert Phillips01a91282018-07-26 08:03:04 -0400528 if (!stencil) {
529 return false;
egdanielec00d942015-09-14 12:56:10 -0700530 }
Robert Phillips01a91282018-07-26 08:03:04 -0400531 this->assignUniqueKeyToResource(sbKey, stencil.get());
egdanielec00d942015-09-14 12:56:10 -0700532 }
Brian Salomonf7f54332020-07-28 09:23:35 -0400533 rt->attachStencilAttachment(std::move(stencil));
egdanielec00d942015-09-14 12:56:10 -0700534 }
Chris Dalton215ff332019-07-02 09:38:22 -0600535
Greg Danielc0d69152020-10-08 14:59:00 -0400536 if (GrAttachment* stencil = rt->getStencilAttachment()) {
Chris Daltonf00b95b2019-11-07 21:14:41 -0700537 return stencil->numSamples() == numStencilSamples;
Chris Dalton215ff332019-07-02 09:38:22 -0600538 }
539 return false;
egdanielec00d942015-09-14 12:56:10 -0700540}
541
Greg Daniel5d0330e2020-10-12 16:05:21 -0400542sk_sp<GrAttachment> GrResourceProvider::makeMSAAAttachment(SkISize dimensions,
543 const GrBackendFormat& format,
544 int sampleCnt,
545 GrProtected isProtected) {
546 ASSERT_SINGLE_OWNER
547
548 SkASSERT(sampleCnt > 1);
549
550 if (this->isAbandoned()) {
551 return nullptr;
552 }
553
554 if (!fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
555 GrMipMapped::kNo)) {
556 return nullptr;
557 }
558
559 auto scratch = this->refScratchMSAAAttachment(dimensions, format, sampleCnt, isProtected);
560 if (scratch) {
561 return scratch;
562 }
563
564 return fGpu->makeMSAAAttachment(dimensions, format, sampleCnt, isProtected);
565}
566
567sk_sp<GrAttachment> GrResourceProvider::refScratchMSAAAttachment(SkISize dimensions,
568 const GrBackendFormat& format,
569 int sampleCnt,
570 GrProtected isProtected) {
571 ASSERT_SINGLE_OWNER
572 SkASSERT(!this->isAbandoned());
573 SkASSERT(!this->caps()->isFormatCompressed(format));
574 SkASSERT(fCaps->validateSurfaceParams(dimensions, format, GrRenderable::kYes, sampleCnt,
575 GrMipmapped::kNo));
576
577 GrScratchKey key;
578 GrAttachment::ComputeScratchKey(*this->caps(), format, dimensions,
Greg Daniel25ebd952020-11-03 11:17:05 -0500579 GrAttachment::UsageFlags::kColorAttachment, sampleCnt,
580 isProtected, &key);
Greg Daniel5d0330e2020-10-12 16:05:21 -0400581 GrGpuResource* resource = fCache->findAndRefScratchResource(key);
582 if (resource) {
583 fGpu->stats()->incNumScratchMSAAAttachmentsReused();
584 GrAttachment* attachment = static_cast<GrAttachment*>(resource);
585 return sk_sp<GrAttachment>(attachment);
586 }
587
588 return nullptr;
589}
590
Greg Daniel301015c2019-11-18 14:06:46 -0500591std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(
592 bool isOwned) {
593 return this->isAbandoned() ? nullptr : fGpu->makeSemaphore(isOwned);
Greg Daniela5cb7812017-06-16 09:45:32 -0400594}
595
Greg Daniel301015c2019-11-18 14:06:46 -0500596std::unique_ptr<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(
597 const GrBackendSemaphore& semaphore,
598 SemaphoreWrapType wrapType,
599 GrWrapOwnership ownership) {
Greg Daniela5cb7812017-06-16 09:45:32 -0400600 ASSERT_SINGLE_OWNER
Greg Daniel17b7c052018-01-09 13:55:33 -0500601 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
602 wrapType,
603 ownership);
Greg Danield85f97d2017-03-07 13:37:21 -0500604}
Brian Salomon8660eb02019-09-20 13:04:13 -0400605
606// Ensures the row bytes are populated (not 0) and makes a copy to a temporary
607// to make the row bytes tight if necessary. Returns false if the input row bytes are invalid.
608static bool prepare_level(const GrMipLevel& inLevel,
Brian Salomona56a7462020-02-07 14:17:25 -0500609 SkISize dimensions,
Brian Salomon8660eb02019-09-20 13:04:13 -0400610 bool rowBytesSupport,
611 GrColorType origColorType,
612 GrColorType allowedColorType,
613 GrMipLevel* outLevel,
614 std::unique_ptr<char[]>* data) {
615 if (!inLevel.fPixels) {
616 outLevel->fPixels = nullptr;
617 outLevel->fRowBytes = 0;
618 return true;
619 }
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400620 size_t minRB = dimensions.fWidth * GrColorTypeBytesPerPixel(origColorType);
Brian Salomon8660eb02019-09-20 13:04:13 -0400621 size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
622 if (actualRB < minRB) {
623 return false;
624 }
625 if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
626 outLevel->fRowBytes = actualRB;
627 outLevel->fPixels = inLevel.fPixels;
628 return true;
629 }
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400630 auto tempRB = dimensions.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
631 data->reset(new char[tempRB * dimensions.fHeight]);
Brian Salomon8660eb02019-09-20 13:04:13 -0400632 outLevel->fPixels = data->get();
633 outLevel->fRowBytes = tempRB;
Brian Salomon9f2b86c2019-10-22 10:37:46 -0400634 GrImageInfo srcInfo(origColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
635 GrImageInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, dimensions);
Brian Salomon8660eb02019-09-20 13:04:13 -0400636 return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
637}
638
639GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
640 GrColorType colorType,
Brian Salomona56a7462020-02-07 14:17:25 -0500641 SkISize baseSize,
Brian Salomon8660eb02019-09-20 13:04:13 -0400642 const GrMipLevel texels[],
643 int mipLevelCount,
644 TempLevels* tempLevels,
645 TempLevelDatas* tempLevelDatas) const {
646 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
647
648 auto allowedColorType =
649 this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
650 if (allowedColorType == GrColorType::kUnknown) {
651 return GrColorType::kUnknown;
652 }
653 bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
654 tempLevels->reset(mipLevelCount);
655 tempLevelDatas->reset(mipLevelCount);
656 auto size = baseSize;
657 for (int i = 0; i < mipLevelCount; ++i) {
658 if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
659 &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
660 return GrColorType::kUnknown;
661 }
662 size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
663 }
664 return allowedColorType;
665}
666
667sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
668 GrColorType colorType,
Brian Salomona56a7462020-02-07 14:17:25 -0500669 SkISize baseSize,
Brian Salomon8660eb02019-09-20 13:04:13 -0400670 const GrMipLevel texels[],
671 int mipLevelCount) const {
672 SkASSERT(!this->isAbandoned());
673 SkASSERT(texture);
674 SkASSERT(colorType != GrColorType::kUnknown);
675 SkASSERT(mipLevelCount && texels && texels[0].fPixels);
676
677 SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
678 SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
679 auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
680 mipLevelCount, &tmpTexels, &tmpDatas);
681 if (tempColorType == GrColorType::kUnknown) {
682 return nullptr;
683 }
684 SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
685 colorType, tempColorType, tmpTexels.get(), mipLevelCount));
686 return texture;
687}