blob: 363d2f6318692d92f1536c842de910b39762343f [file] [log] [blame]
bsalomon@google.com686bcb82013-04-09 15:04:12 +00001/*
2 * Copyright 2013 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 Salomon614c1a82018-12-19 15:42:06 -05008#include <set>
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/core/SkSurface.h"
10#include "include/gpu/GrContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/gpu/GrTexture.h"
12#include "src/core/SkAutoPixmapStorage.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrClip.h"
14#include "src/gpu/GrContextPriv.h"
15#include "src/gpu/GrGpu.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040016#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrProxyProvider.h"
Brian Salomon201cdbb2019-08-14 17:00:30 -040018#include "src/gpu/GrRenderTarget.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/GrResourceProvider.h"
20#include "src/gpu/GrTexturePriv.h"
21#include "tests/Test.h"
Robert Phillipsee5fd132019-05-07 13:29:22 -040022#include "tests/TestUtils.h"
bsalomon@google.com686bcb82013-04-09 15:04:12 +000023
bsalomona2c23232014-11-25 07:41:12 -080024// Tests that GrSurface::asTexture(), GrSurface::asRenderTarget(), and static upcasting of texture
25// and render targets to GrSurface all work as expected.
Brian Osmanfbe24062019-04-03 16:04:45 +000026DEF_GPUTEST_FOR_MOCK_CONTEXT(GrSurface, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -070027 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -050028 auto resourceProvider = context->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -050029
kkinnunen15302832015-12-01 04:35:26 -080030 GrSurfaceDesc desc;
kkinnunen15302832015-12-01 04:35:26 -080031 desc.fWidth = 256;
32 desc.fHeight = 256;
Robert Phillips16d8ec62017-07-27 16:16:25 -040033 desc.fConfig = kRGBA_8888_GrPixelConfig;
Brian Salomon4eb38b72019-08-05 12:58:39 -040034 auto format = context->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
35 GrRenderable::kYes);
Brian Salomona90382f2019-09-17 09:01:56 -040036 sk_sp<GrSurface> texRT1 =
37 resourceProvider->createTexture(desc, format, GrRenderable::kYes, 1, GrMipMapped::kNo,
38 SkBudgeted::kNo, GrProtected::kNo);
bsalomona2c23232014-11-25 07:41:12 -080039
Robert Phillipse78b7252017-04-06 07:59:41 -040040 REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asRenderTarget());
41 REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asTexture());
kkinnunen15302832015-12-01 04:35:26 -080042 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
43 texRT1->asTexture());
44 REPORTER_ASSERT(reporter, texRT1->asRenderTarget() ==
45 static_cast<GrSurface*>(texRT1->asTexture()));
46 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
47 static_cast<GrSurface*>(texRT1->asTexture()));
bsalomona2c23232014-11-25 07:41:12 -080048
Brian Salomona90382f2019-09-17 09:01:56 -040049 sk_sp<GrTexture> tex1 =
50 resourceProvider->createTexture(desc, format, GrRenderable::kNo, 1, GrMipMapped::kNo,
51 SkBudgeted::kNo, GrProtected::kNo);
kkinnunen15302832015-12-01 04:35:26 -080052 REPORTER_ASSERT(reporter, nullptr == tex1->asRenderTarget());
Robert Phillipse78b7252017-04-06 07:59:41 -040053 REPORTER_ASSERT(reporter, tex1.get() == tex1->asTexture());
54 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(tex1.get()) == tex1->asTexture());
bsalomon@google.com686bcb82013-04-09 15:04:12 +000055
Robert Phillips4bdd36f2019-06-04 11:03:06 -040056 GrBackendTexture backendTex = context->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -040057 256, 256, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -040058 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
bsalomon091f60c2015-11-10 11:54:56 -080059
Brian Salomonaa6ca0a2019-01-24 16:03:07 -050060 sk_sp<GrSurface> texRT2 = resourceProvider->wrapRenderableBackendTexture(
Robert Phillips0902c982019-07-16 07:47:56 -040061 backendTex, 1, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo);
Greg Daniel7ef28f32017-04-20 16:41:55 +000062
bungeman6bd52842016-10-27 09:30:08 -070063 REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asRenderTarget());
64 REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asTexture());
kkinnunen15302832015-12-01 04:35:26 -080065 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
66 texRT2->asTexture());
67 REPORTER_ASSERT(reporter, texRT2->asRenderTarget() ==
68 static_cast<GrSurface*>(texRT2->asTexture()));
69 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
70 static_cast<GrSurface*>(texRT2->asTexture()));
bsalomon@google.com686bcb82013-04-09 15:04:12 +000071
Robert Phillips5c7a25b2019-05-20 08:38:07 -040072 context->deleteBackendTexture(backendTex);
bsalomon@google.com686bcb82013-04-09 15:04:12 +000073}
74
Greg Daniel7bfc9132019-08-14 14:23:53 -040075// This test checks that the isFormatTexturable and isFormatRenderable are
Robert Phillipsb7b7e5f2017-05-22 13:23:19 -040076// consistent with createTexture's result.
77DEF_GPUTEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability, reporter, ctxInfo) {
78 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -050079 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
80 GrResourceProvider* resourceProvider = context->priv().resourceProvider();
81 const GrCaps* caps = context->priv().caps();
Robert Phillipsb7b7e5f2017-05-22 13:23:19 -040082
Brian Salomon4eb38b72019-08-05 12:58:39 -040083 // TODO: Should only need format here but need to determine compression type from format
84 // without config.
85 auto createTexture = [](int width, int height, GrColorType colorType,
86 const GrBackendFormat& format, GrRenderable renderable,
Brian Salomonbb8dde82019-06-27 10:52:13 -040087 GrResourceProvider* rp) -> sk_sp<GrTexture> {
Brian Salomon4eb38b72019-08-05 12:58:39 -040088 GrPixelConfig config = rp->caps()->getConfigFromBackendFormat(format, colorType);
89 bool compressed = rp->caps()->isFormatCompressed(format);
90 if (compressed) {
Brian Salomonbb8dde82019-06-27 10:52:13 -040091 if (renderable == GrRenderable::kYes) {
92 return nullptr;
93 }
94 SkImage::CompressionType type;
95 switch (config) {
96 case kRGB_ETC1_GrPixelConfig:
97 type = SkImage::kETC1_CompressionType;
98 break;
99 default:
100 SK_ABORT("Unexpected config");
Brian Salomonbb8dde82019-06-27 10:52:13 -0400101 }
102 // Only supported compression type right now.
103 SkASSERT(config == kRGB_ETC1_GrPixelConfig);
104 auto size = GrCompressedDataSize(type, width, height);
105 auto data = SkData::MakeUninitialized(size);
106 SkColor4f color = {0, 0, 0, 0};
107 GrFillInCompressedData(type, width, height, (char*)data->writable_data(), color);
Greg Daniel7bfc9132019-08-14 14:23:53 -0400108 return rp->createCompressedTexture(width, height, format,
109 SkImage::kETC1_CompressionType,
Brian Salomonbb8dde82019-06-27 10:52:13 -0400110 SkBudgeted::kNo, data.get());
111 } else {
112 GrSurfaceDesc desc;
113 desc.fWidth = width;
114 desc.fHeight = height;
Brian Salomonbb8dde82019-06-27 10:52:13 -0400115 desc.fConfig = config;
Brian Salomona90382f2019-09-17 09:01:56 -0400116 return rp->createTexture(desc, format, renderable, 1, GrMipMapped::kNo, SkBudgeted::kNo,
117 GrProtected::kNo);
Brian Salomonbb8dde82019-06-27 10:52:13 -0400118 }
119 };
Robert Phillipsb7b7e5f2017-05-22 13:23:19 -0400120
Robert Phillipsffe27292019-08-01 10:08:07 -0400121 static constexpr int kW = 64;
122 static constexpr int kH = 64;
Robert Phillipsa5e78be2019-07-09 12:34:38 -0400123
Robert Phillipsffe27292019-08-01 10:08:07 -0400124 const std::vector<GrCaps::TestFormatColorTypeCombination>& combos =
125 caps->getTestingCombinations();
Robert Phillips0902c982019-07-16 07:47:56 -0400126
Robert Phillipsffe27292019-08-01 10:08:07 -0400127 for (auto combo : combos) {
128
129 SkASSERT(combo.fColorType != GrColorType::kUnknown);
130 SkASSERT(combo.fFormat.isValid());
131
132 // Right now Vulkan has two backend formats that support ABGR_4444 (R4G4B4A4 and B4G4R4A4).
133 // Until we can create textures directly from the backend format this yields some
134 // ambiguity in what is actually supported and which textures can be created.
135 if (ctxInfo.backend() == kVulkan_GrBackend && combo.fColorType == GrColorType::kABGR_4444) {
Robert Phillips0902c982019-07-16 07:47:56 -0400136 continue;
137 }
138
Robert Phillipsb7b7e5f2017-05-22 13:23:19 -0400139 for (GrSurfaceOrigin origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
Brian Salomonbb8dde82019-06-27 10:52:13 -0400140 GrSurfaceDesc desc;
141 desc.fWidth = kW;
142 desc.fHeight = kH;
Brian Salomon4eb38b72019-08-05 12:58:39 -0400143 desc.fConfig = caps->getConfigFromBackendFormat(combo.fFormat, combo.fColorType);
144 SkASSERT(desc.fConfig != kUnknown_GrPixelConfig);
Brian Salomonbb8dde82019-06-27 10:52:13 -0400145
Robert Phillipsffe27292019-08-01 10:08:07 -0400146 // Check if 'isFormatTexturable' agrees with 'createTexture' and that the mipmap
147 // support check is working
148 {
Greg Daniel7bfc9132019-08-14 14:23:53 -0400149
150 bool compressed = caps->isFormatCompressed(combo.fFormat);
151 bool isTexturable;
152 if (compressed) {
153 isTexturable = caps->isFormatTexturable(combo.fFormat);
154 } else {
155 isTexturable = caps->isFormatTexturableAndUploadable(combo.fColorType,
156 combo.fFormat);
157 }
Brian Osman48c99192017-06-02 08:45:06 -0400158
Brian Salomon4eb38b72019-08-05 12:58:39 -0400159 sk_sp<GrSurface> tex = createTexture(kW, kH, combo.fColorType, combo.fFormat,
Robert Phillipsffe27292019-08-01 10:08:07 -0400160 GrRenderable::kNo, resourceProvider);
161 REPORTER_ASSERT(reporter, SkToBool(tex) == isTexturable,
Robert Phillipsbac46722019-08-01 15:09:17 -0400162 "ct:%s format:%s, tex:%d, isTexturable:%d",
Robert Phillipsffe27292019-08-01 10:08:07 -0400163 GrColorTypeToStr(combo.fColorType),
Robert Phillipsbac46722019-08-01 15:09:17 -0400164 combo.fFormat.toStr().c_str(),
165 SkToBool(tex), isTexturable);
Robert Phillipsb7b7e5f2017-05-22 13:23:19 -0400166
Robert Phillipsffe27292019-08-01 10:08:07 -0400167 // Check that the lack of mipmap support blocks the creation of mipmapped
168 // proxies
Robert Phillipsbac46722019-08-01 15:09:17 -0400169 bool expectedMipMapability = isTexturable && caps->mipMapSupport() &&
170 !caps->isFormatCompressed(combo.fFormat);
171
Brian Salomonbeb7f522019-08-30 16:19:42 -0400172 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(
173 combo.fFormat, desc, GrRenderable::kNo, 1, origin, GrMipMapped::kYes,
174 SkBackingFit::kExact, SkBudgeted::kNo, GrProtected::kNo);
Robert Phillipsbac46722019-08-01 15:09:17 -0400175 REPORTER_ASSERT(reporter, SkToBool(proxy.get()) == expectedMipMapability,
176 "ct:%s format:%s, tex:%d, expectedMipMapability:%d",
177 GrColorTypeToStr(combo.fColorType),
178 combo.fFormat.toStr().c_str(),
179 SkToBool(proxy.get()), expectedMipMapability);
Robert Phillipsffe27292019-08-01 10:08:07 -0400180 }
181
Greg Daniel900583a2019-08-06 12:05:31 -0400182 // Check if 'isFormatAsColorTypeRenderable' agrees with 'createTexture' (w/o MSAA)
Robert Phillipsffe27292019-08-01 10:08:07 -0400183 {
Greg Daniel6fa62e22019-08-07 15:52:37 -0400184 bool isRenderable = caps->isFormatRenderable(combo.fFormat, 1);
Robert Phillipsffe27292019-08-01 10:08:07 -0400185
Brian Salomon4eb38b72019-08-05 12:58:39 -0400186 sk_sp<GrSurface> tex = resourceProvider->createTexture(
Brian Salomona90382f2019-09-17 09:01:56 -0400187 desc, combo.fFormat, GrRenderable::kYes, 1, GrMipMapped::kNo,
188 SkBudgeted::kNo, GrProtected::kNo);
Robert Phillipsffe27292019-08-01 10:08:07 -0400189 REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
Robert Phillipsbac46722019-08-01 15:09:17 -0400190 "ct:%s format:%s, tex:%d, isRenderable:%d",
Robert Phillipsffe27292019-08-01 10:08:07 -0400191 GrColorTypeToStr(combo.fColorType),
Robert Phillipsbac46722019-08-01 15:09:17 -0400192 combo.fFormat.toStr().c_str(),
193 SkToBool(tex), isRenderable);
Robert Phillipsffe27292019-08-01 10:08:07 -0400194 }
195
Greg Daniel900583a2019-08-06 12:05:31 -0400196 // Check if 'isFormatAsColorTypeRenderable' agrees with 'createTexture' w/ MSAA
Robert Phillipsffe27292019-08-01 10:08:07 -0400197 {
Greg Daniel6fa62e22019-08-07 15:52:37 -0400198 bool isRenderable = caps->isFormatRenderable(combo.fFormat, 2);
Robert Phillipsffe27292019-08-01 10:08:07 -0400199
Brian Salomon4eb38b72019-08-05 12:58:39 -0400200 sk_sp<GrSurface> tex = resourceProvider->createTexture(
Brian Salomona90382f2019-09-17 09:01:56 -0400201 desc, combo.fFormat, GrRenderable::kYes, 2, GrMipMapped::kNo,
202 SkBudgeted::kNo, GrProtected::kNo);
Robert Phillipsffe27292019-08-01 10:08:07 -0400203 REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
Robert Phillipsbac46722019-08-01 15:09:17 -0400204 "ct:%s format:%s, tex:%d, isRenderable:%d",
Robert Phillipsffe27292019-08-01 10:08:07 -0400205 GrColorTypeToStr(combo.fColorType),
Robert Phillipsbac46722019-08-01 15:09:17 -0400206 combo.fFormat.toStr().c_str(),
207 SkToBool(tex), isRenderable);
Robert Phillipsffe27292019-08-01 10:08:07 -0400208 }
Robert Phillipsb7b7e5f2017-05-22 13:23:19 -0400209 }
210 }
211}
Robert Phillipsb7b7e5f2017-05-22 13:23:19 -0400212
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500213#include "src/gpu/GrDrawingManager.h"
Greg Danielf91aeb22019-06-18 09:58:02 -0400214#include "src/gpu/GrSurfaceProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500215#include "src/gpu/GrTextureContext.h"
Brian Salomond17b4a62017-05-23 16:53:47 -0400216
Robert Phillipsffe27292019-08-01 10:08:07 -0400217// For each context, set it to always clear the textures and then run through all the
218// supported formats checking that the textures are actually cleared
Brian Salomona3e29962019-07-16 11:52:08 -0400219DEF_GPUTEST(InitialTextureClear, reporter, baseOptions) {
220 GrContextOptions options = baseOptions;
221 options.fClearAllTextures = true;
Robert Phillipsd3442842019-08-02 12:26:22 -0400222
Brian Salomond17b4a62017-05-23 16:53:47 -0400223 static constexpr int kSize = 100;
Robert Phillipsd3442842019-08-02 12:26:22 -0400224 static constexpr SkColor kClearColor = 0xABABABAB;
Robert Phillipsffe27292019-08-01 10:08:07 -0400225
226 const SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
227 kPremul_SkAlphaType);
228
Robert Phillipsd3442842019-08-02 12:26:22 -0400229 SkAutoPixmapStorage readback;
230 readback.alloc(info);
231
Robert Phillipsffe27292019-08-01 10:08:07 -0400232 GrSurfaceDesc desc;
233 desc.fWidth = desc.fHeight = kSize;
234
Brian Salomona3e29962019-07-16 11:52:08 -0400235 for (int ct = 0; ct < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++ct) {
236 sk_gpu_test::GrContextFactory factory(options);
237 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(ct);
238 if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
Brian Salomond17b4a62017-05-23 16:53:47 -0400239 continue;
240 }
Brian Salomona3e29962019-07-16 11:52:08 -0400241 auto context = factory.get(contextType);
242 if (!context) {
243 continue;
244 }
Brian Salomona3e29962019-07-16 11:52:08 -0400245
Brian Salomona3e29962019-07-16 11:52:08 -0400246 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
Robert Phillipsffe27292019-08-01 10:08:07 -0400247 const GrCaps* caps = context->priv().caps();
Brian Salomona3e29962019-07-16 11:52:08 -0400248
Robert Phillipsffe27292019-08-01 10:08:07 -0400249 const std::vector<GrCaps::TestFormatColorTypeCombination>& combos =
250 caps->getTestingCombinations();
251
252 for (auto combo : combos) {
253
254 SkASSERT(combo.fColorType != GrColorType::kUnknown);
255 SkASSERT(combo.fFormat.isValid());
256
Greg Daniel7bfc9132019-08-14 14:23:53 -0400257 if (!caps->isFormatTexturableAndUploadable(combo.fColorType, combo.fFormat)) {
Brian Salomond17b4a62017-05-23 16:53:47 -0400258 continue;
259 }
Robert Phillipsffe27292019-08-01 10:08:07 -0400260
261 {
262 GrPixelConfig config = caps->getConfigFromBackendFormat(combo.fFormat,
263 combo.fColorType);
264 SkASSERT(config != kUnknown_GrPixelConfig);
265
266 desc.fConfig = config;
267 }
268
Brian Salomon614cdab2019-09-26 11:04:28 -0400269 auto checkColor = [reporter](const GrCaps::TestFormatColorTypeCombination& combo,
270 uint32_t readColor) {
271 // We expect that if there is no alpha in the src color type and we read it to a
272 // color type with alpha that we will get one for alpha rather than zero. We used to
273 // require this but the Intel Iris 6100 on Win 10 test bot doesn't put one in the
274 // alpha channel when reading back from GL_RG16 or GL_RG16F. So now we allow either.
275 uint32_t components = GrColorTypeComponentFlags(combo.fColorType);
276 bool allowAlphaOne = !(components & kAlpha_SkColorTypeComponentFlag);
277 if (allowAlphaOne) {
278 if (readColor != 0x00000000 && readColor != 0xFF000000) {
279 ERRORF(reporter,
280 "Failed on ct %s format %s 0x%08x is not 0x00000000 or 0xFF000000",
281 GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
282 readColor);
283 return false;
284 }
285 } else {
286 if (readColor) {
287 ERRORF(reporter, "Failed on ct %s format %s 0x%08x != 0x00000000",
288 GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
289 readColor);
290 return false;
291 }
292 }
293 return true;
294 };
Robert Phillipsffe27292019-08-01 10:08:07 -0400295
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400296 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Robert Phillipsffe27292019-08-01 10:08:07 -0400297 if (renderable == GrRenderable::kYes &&
Greg Daniel900583a2019-08-06 12:05:31 -0400298 !caps->isFormatAsColorTypeRenderable(combo.fColorType, combo.fFormat)) {
Brian Salomona3e29962019-07-16 11:52:08 -0400299 continue;
300 }
Robert Phillipsffe27292019-08-01 10:08:07 -0400301
302 for (auto fit : {SkBackingFit::kApprox, SkBackingFit::kExact}) {
303
304 // Does directly allocating a texture clear it?
305 {
Chris Daltond004e0b2018-09-27 09:28:03 -0600306 auto proxy = proxyProvider->testingOnly_createInstantiatedProxy(
Brian Salomon4eb38b72019-08-05 12:58:39 -0400307 {kSize, kSize}, combo.fColorType, combo.fFormat, renderable, 1,
308 kTopLeft_GrSurfaceOrigin, fit, SkBudgeted::kYes, GrProtected::kNo);
Robert Phillipsffe27292019-08-01 10:08:07 -0400309 if (proxy) {
310 auto texCtx = context->priv().makeWrappedSurfaceContext(
311 std::move(proxy), combo.fColorType, kPremul_SkAlphaType);
312
Robert Phillipsd3442842019-08-02 12:26:22 -0400313 readback.erase(kClearColor);
314 if (texCtx->readPixels(readback.info(), readback.writable_addr(),
315 readback.rowBytes(), {0, 0})) {
Robert Phillipsffe27292019-08-01 10:08:07 -0400316 for (int i = 0; i < kSize * kSize; ++i) {
Brian Salomon614cdab2019-09-26 11:04:28 -0400317 if (!checkColor(combo, readback.addr32()[i])) {
Robert Phillipsffe27292019-08-01 10:08:07 -0400318 break;
319 }
320 }
321 }
322 }
323
324 context->priv().testingOnly_purgeAllUnlockedResources();
325 }
326
327 // Try creating the texture as a deferred proxy.
328 {
Brian Salomonbf6b9792019-08-21 09:38:10 -0400329 std::unique_ptr<GrSurfaceContext> surfCtx;
Robert Phillipsffe27292019-08-01 10:08:07 -0400330 if (renderable == GrRenderable::kYes) {
331 surfCtx = context->priv().makeDeferredRenderTargetContext(
332 fit, desc.fWidth, desc.fHeight, combo.fColorType, nullptr,
333 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin, nullptr);
334 } else {
335 surfCtx = context->priv().makeDeferredTextureContext(
336 fit, desc.fWidth, desc.fHeight, combo.fColorType,
337 kUnknown_SkAlphaType, nullptr, GrMipMapped::kNo,
338 kTopLeft_GrSurfaceOrigin);
339 }
340 if (!surfCtx) {
Greg Daniel90f28ec2017-09-25 12:26:58 -0400341 continue;
342 }
Robert Phillipsffe27292019-08-01 10:08:07 -0400343
Robert Phillipsd3442842019-08-02 12:26:22 -0400344 readback.erase(kClearColor);
345 if (surfCtx->readPixels(readback.info(), readback.writable_addr(),
346 readback.rowBytes(), {0, 0})) {
Greg Daniel90f28ec2017-09-25 12:26:58 -0400347 for (int i = 0; i < kSize * kSize; ++i) {
Brian Salomon614cdab2019-09-26 11:04:28 -0400348 if (!checkColor(combo, readback.addr32()[i])) {
Greg Daniel90f28ec2017-09-25 12:26:58 -0400349 break;
Brian Salomond17b4a62017-05-23 16:53:47 -0400350 }
351 }
Brian Salomond17b4a62017-05-23 16:53:47 -0400352 }
Brian Salomona3e29962019-07-16 11:52:08 -0400353 context->priv().testingOnly_purgeAllUnlockedResources();
Greg Daniel90f28ec2017-09-25 12:26:58 -0400354 }
Brian Salomond17b4a62017-05-23 16:53:47 -0400355 }
356 }
357 }
358 }
359}
Brian Salomonc67c31c2018-12-06 10:00:03 -0500360
361DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture, reporter, context_info) {
Robert Phillipscb1adb42019-06-10 15:09:34 -0400362 auto fillPixels = [](SkPixmap* p, const std::function<uint32_t(int x, int y)>& f) {
Brian Salomonc67c31c2018-12-06 10:00:03 -0500363 for (int y = 0; y < p->height(); ++y) {
364 for (int x = 0; x < p->width(); ++x) {
365 *p->writable_addr32(x, y) = f(x, y);
366 }
367 }
368 };
369
370 auto comparePixels = [](const SkPixmap& p1, const SkPixmap& p2, skiatest::Reporter* reporter) {
371 SkASSERT(p1.info() == p2.info());
372 for (int y = 0; y < p1.height(); ++y) {
373 for (int x = 0; x < p1.width(); ++x) {
374 REPORTER_ASSERT(reporter, p1.getColor(x, y) == p2.getColor(x, y));
375 if (p1.getColor(x, y) != p2.getColor(x, y)) {
376 return;
377 }
378 }
379 }
380 };
381
382 static constexpr int kSize = 100;
Robert Phillips4d87b2b2019-07-23 13:44:16 -0400383 SkImageInfo ii = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
384 SkAutoPixmapStorage srcPixmap;
385 srcPixmap.alloc(ii);
386 fillPixels(&srcPixmap,
Robert Phillipscb1adb42019-06-10 15:09:34 -0400387 [](int x, int y) {
388 return (0xFFU << 24) | (x << 16) | (y << 8) | uint8_t((x * y) & 0xFF);
389 });
Brian Salomonc67c31c2018-12-06 10:00:03 -0500390
391 GrContext* context = context_info.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500392 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
Brian Salomonc67c31c2018-12-06 10:00:03 -0500393
394 // We test both kRW in addition to kRead mostly to ensure that the calls are structured such
395 // that they'd succeed if the texture wasn't kRead. We want to be sure we're failing with
396 // kRead for the right reason.
397 for (auto ioType : {kRead_GrIOType, kRW_GrIOType}) {
Robert Phillips66944402019-09-30 13:21:25 -0400398 auto backendTex = context->createBackendTexture(&srcPixmap, 1,
399 GrRenderable::kYes, GrProtected::kNo);
Robert Phillipscb1adb42019-06-10 15:09:34 -0400400
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400401 auto proxy = proxyProvider->wrapBackendTexture(backendTex, GrColorType::kRGBA_8888,
402 kTopLeft_GrSurfaceOrigin,
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500403 kBorrow_GrWrapOwnership,
404 GrWrapCacheable::kNo, ioType);
Brian Salomond6287472019-06-24 15:50:07 -0400405 auto surfContext = context->priv().makeWrappedSurfaceContext(proxy, GrColorType::kRGBA_8888,
406 kPremul_SkAlphaType);
Brian Salomonc67c31c2018-12-06 10:00:03 -0500407
408 // Read pixels should work with a read-only texture.
Robert Phillips4d87b2b2019-07-23 13:44:16 -0400409 {
410 SkAutoPixmapStorage read;
411 read.alloc(srcPixmap.info());
412 auto readResult = surfContext->readPixels(srcPixmap.info(), read.writable_addr(),
413 0, { 0, 0 });
414 REPORTER_ASSERT(reporter, readResult);
415 if (readResult) {
416 comparePixels(srcPixmap, read, reporter);
417 }
Brian Salomonc67c31c2018-12-06 10:00:03 -0500418 }
419
420 // Write pixels should not work with a read-only texture.
421 SkAutoPixmapStorage write;
Robert Phillips4d87b2b2019-07-23 13:44:16 -0400422 write.alloc(srcPixmap.info());
423 fillPixels(&write, [&srcPixmap](int x, int y) { return ~*srcPixmap.addr32(); });
424 auto writeResult = surfContext->writePixels(srcPixmap.info(), write.addr(), 0, {0, 0});
Brian Salomonc67c31c2018-12-06 10:00:03 -0500425 REPORTER_ASSERT(reporter, writeResult == (ioType == kRW_GrIOType));
426 // Try the low level write.
427 context->flush();
Robert Phillips9da87e02019-02-04 13:26:26 -0500428 auto gpuWriteResult = context->priv().getGpu()->writePixels(
Brian Salomonf77c1462019-08-01 15:19:29 -0400429 proxy->peekTexture(), 0, 0, kSize, kSize, GrColorType::kRGBA_8888,
430 GrColorType::kRGBA_8888, write.addr32(),
Brian Salomon1047a492019-07-02 12:25:21 -0400431 kSize * GrColorTypeBytesPerPixel(GrColorType::kRGBA_8888));
Brian Salomonc67c31c2018-12-06 10:00:03 -0500432 REPORTER_ASSERT(reporter, gpuWriteResult == (ioType == kRW_GrIOType));
433
434 // Copies should not work with a read-only texture
Brian Salomon96b383a2019-08-13 16:55:41 -0400435 auto copySrc =
436 proxyProvider->createTextureProxy(SkImage::MakeFromRaster(write, nullptr, nullptr),
437 1, SkBudgeted::kYes, SkBackingFit::kExact);
Brian Salomonc67c31c2018-12-06 10:00:03 -0500438 REPORTER_ASSERT(reporter, copySrc);
Greg Daniel46cfbc62019-06-07 11:43:30 -0400439 auto copyResult = surfContext->testCopy(copySrc.get());
Brian Salomonc67c31c2018-12-06 10:00:03 -0500440 REPORTER_ASSERT(reporter, copyResult == (ioType == kRW_GrIOType));
441 // Try the low level copy.
442 context->flush();
Robert Phillips9da87e02019-02-04 13:26:26 -0500443 auto gpuCopyResult = context->priv().getGpu()->copySurface(
Greg Daniel46cfbc62019-06-07 11:43:30 -0400444 proxy->peekTexture(), copySrc->peekTexture(), SkIRect::MakeWH(kSize, kSize),
445 {0, 0});
Brian Salomonc67c31c2018-12-06 10:00:03 -0500446 REPORTER_ASSERT(reporter, gpuCopyResult == (ioType == kRW_GrIOType));
447
448 // Mip regen should not work with a read only texture.
Robert Phillips9da87e02019-02-04 13:26:26 -0500449 if (context->priv().caps()->mipMapSupport()) {
Greg Danielb3f82dd2019-05-29 14:24:32 -0400450 delete_backend_texture(context, backendTex);
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400451 backendTex = context->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400452 kSize, kSize, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400453 SkColors::kTransparent, GrMipMapped::kYes, GrRenderable::kYes,
454 GrProtected::kNo);
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400455 proxy = proxyProvider->wrapBackendTexture(backendTex, GrColorType::kRGBA_8888,
456 kTopLeft_GrSurfaceOrigin,
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500457 kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
458 ioType);
Brian Salomonc67c31c2018-12-06 10:00:03 -0500459 context->flush();
460 proxy->peekTexture()->texturePriv().markMipMapsDirty(); // avoids assert in GrGpu.
461 auto regenResult =
Robert Phillips9da87e02019-02-04 13:26:26 -0500462 context->priv().getGpu()->regenerateMipMapLevels(proxy->peekTexture());
Brian Salomonc67c31c2018-12-06 10:00:03 -0500463 REPORTER_ASSERT(reporter, regenResult == (ioType == kRW_GrIOType));
464 }
Greg Danielb3f82dd2019-05-29 14:24:32 -0400465 delete_backend_texture(context, backendTex);
Brian Salomonc67c31c2018-12-06 10:00:03 -0500466 }
467}
Brian Salomon614c1a82018-12-19 15:42:06 -0500468
Greg Daniel46cfbc62019-06-07 11:43:30 -0400469static const int kSurfSize = 10;
470
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400471static sk_sp<GrTexture> make_wrapped_texture(GrContext* context, GrRenderable renderable) {
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400472 auto backendTexture = context->createBackendTexture(
Greg Daniel46cfbc62019-06-07 11:43:30 -0400473 kSurfSize, kSurfSize, kRGBA_8888_SkColorType, SkColors::kTransparent, GrMipMapped::kNo,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400474 renderable, GrProtected::kNo);
Brian Salomon8cabb322019-02-22 10:44:19 -0500475 sk_sp<GrTexture> texture;
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400476 if (GrRenderable::kYes == renderable) {
Brian Salomon8cabb322019-02-22 10:44:19 -0500477 texture = context->priv().resourceProvider()->wrapRenderableBackendTexture(
Robert Phillips0902c982019-07-16 07:47:56 -0400478 backendTexture, 1, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership,
479 GrWrapCacheable::kNo);
Brian Salomon8cabb322019-02-22 10:44:19 -0500480 } else {
481 texture = context->priv().resourceProvider()->wrapBackendTexture(
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400482 backendTexture, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership,
483 GrWrapCacheable::kNo, kRW_GrIOType);
Brian Salomon8cabb322019-02-22 10:44:19 -0500484 }
485 // Add a release proc that deletes the GrBackendTexture.
486 struct ReleaseContext {
487 GrContext* fContext;
488 GrBackendTexture fBackendTexture;
Brian Salomon614c1a82018-12-19 15:42:06 -0500489 };
Brian Salomon8cabb322019-02-22 10:44:19 -0500490 auto release = [](void* rc) {
491 auto releaseContext = static_cast<ReleaseContext*>(rc);
Robert Phillips9b16f812019-05-17 10:01:21 -0400492 auto context = releaseContext->fContext;
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400493 context->deleteBackendTexture(releaseContext->fBackendTexture);
Brian Salomon8cabb322019-02-22 10:44:19 -0500494 delete releaseContext;
495 };
Brian Salomon2ca31f82019-03-05 13:28:58 -0500496 texture->setRelease(release, new ReleaseContext{context, backendTexture});
Brian Salomon8cabb322019-02-22 10:44:19 -0500497 return texture;
498}
Brian Salomon614c1a82018-12-19 15:42:06 -0500499
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400500static sk_sp<GrTexture> make_normal_texture(GrContext* context, GrRenderable renderable) {
Brian Salomon8cabb322019-02-22 10:44:19 -0500501 GrSurfaceDesc desc;
502 desc.fConfig = kRGBA_8888_GrPixelConfig;
Greg Daniel46cfbc62019-06-07 11:43:30 -0400503 desc.fWidth = desc.fHeight = kSurfSize;
Brian Salomon4eb38b72019-08-05 12:58:39 -0400504 auto format =
505 context->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888, renderable);
Robert Phillips9313aa72019-04-09 18:41:27 -0400506 return context->priv().resourceProvider()->createTexture(
Brian Salomona90382f2019-09-17 09:01:56 -0400507 desc, format, renderable, 1, GrMipMapped::kNo, SkBudgeted::kNo, GrProtected::kNo);
Brian Salomon8cabb322019-02-22 10:44:19 -0500508}
Brian Salomon614c1a82018-12-19 15:42:06 -0500509
Brian Salomon8cabb322019-02-22 10:44:19 -0500510DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
511 // Various ways of making textures.
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400512 auto makeWrapped = [](GrContext* context) {
513 return make_wrapped_texture(context, GrRenderable::kNo);
Brian Salomon614c1a82018-12-19 15:42:06 -0500514 };
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400515 auto makeWrappedRenderable = [](GrContext* context) {
516 return make_wrapped_texture(context, GrRenderable::kYes);
517 };
518 auto makeNormal = [](GrContext* context) {
519 return make_normal_texture(context, GrRenderable::kNo);
520 };
521 auto makeRenderable = [](GrContext* context) {
522 return make_normal_texture(context, GrRenderable::kYes);
523 };
Brian Salomon614c1a82018-12-19 15:42:06 -0500524
525 std::function<sk_sp<GrTexture>(GrContext*)> makers[] = {makeWrapped, makeWrappedRenderable,
526 makeNormal, makeRenderable};
527
528 // Add a unique key, or not.
529 auto addKey = [](GrTexture* texture) {
530 static uint32_t gN = 0;
531 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
532 GrUniqueKey key;
533 GrUniqueKey::Builder builder(&key, kDomain, 1);
534 builder[0] = gN++;
535 builder.finish();
536 texture->resourcePriv().setUniqueKey(key);
537 };
538 auto dontAddKey = [](GrTexture* texture) {};
539 std::function<void(GrTexture*)> keyAdders[] = {addKey, dontAddKey};
540
541 for (const auto& m : makers) {
542 for (const auto& keyAdder : keyAdders) {
543 for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
544 sk_gpu_test::GrContextFactory factory;
545 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500546 GrContext* context = factory.get(contextType);
Brian Salomon614c1a82018-12-19 15:42:06 -0500547 if (!context) {
548 continue;
549 }
550
551 // The callback we add simply adds an integer to a set.
552 std::set<int> idleIDs;
553 struct Context {
554 std::set<int>* fIdleIDs;
555 int fNum;
556 };
557 auto proc = [](void* context) {
558 static_cast<Context*>(context)->fIdleIDs->insert(
559 static_cast<Context*>(context)->fNum);
560 delete static_cast<Context*>(context);
561 };
562
563 // Makes a texture, possibly adds a key, and sets the callback.
564 auto make = [&m, &keyAdder, &proc, &idleIDs](GrContext* context, int num) {
565 sk_sp<GrTexture> texture = m(context);
Brian Salomone80b8092019-03-08 13:25:19 -0500566 texture->addIdleProc(proc, new Context{&idleIDs, num},
567 GrTexture::IdleState::kFinished);
Brian Salomon614c1a82018-12-19 15:42:06 -0500568 keyAdder(texture.get());
569 return texture;
570 };
571
572 auto texture = make(context, 1);
573 REPORTER_ASSERT(reporter, idleIDs.find(1) == idleIDs.end());
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400574 auto renderable = GrRenderable(SkToBool(texture->asRenderTarget()));
Brian Salomon614c1a82018-12-19 15:42:06 -0500575 auto backendFormat = texture->backendFormat();
576 texture.reset();
577 REPORTER_ASSERT(reporter, idleIDs.find(1) != idleIDs.end());
578
579 texture = make(context, 2);
Brian Salomon8cabb322019-02-22 10:44:19 -0500580 int w = texture->width();
581 int h = texture->height();
Brian Salomon614c1a82018-12-19 15:42:06 -0500582 SkImageInfo info =
Brian Salomon8cabb322019-02-22 10:44:19 -0500583 SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Brian Salomon614c1a82018-12-19 15:42:06 -0500584 auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
585 auto rtc = rt->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
586 auto singleUseLazyCB = [&texture](GrResourceProvider* rp) {
Brian Salomonb6a3a3b2019-04-01 12:29:34 -0400587 auto mode = GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
588 if (texture->getUniqueKey().isValid()) {
589 mode = GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
590 }
Brian Salomonbeb7f522019-08-30 16:19:42 -0400591 return GrSurfaceProxy::LazyCallbackResult{std::move(texture), true, mode};
Brian Salomon614c1a82018-12-19 15:42:06 -0500592 };
593 GrSurfaceDesc desc;
Brian Salomon8cabb322019-02-22 10:44:19 -0500594 desc.fWidth = w;
595 desc.fHeight = h;
Brian Salomon614c1a82018-12-19 15:42:06 -0500596 desc.fConfig = kRGBA_8888_GrPixelConfig;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500597 SkBudgeted budgeted;
598 if (texture->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted) {
599 budgeted = SkBudgeted::kYes;
600 } else {
601 budgeted = SkBudgeted::kNo;
602 }
Robert Phillips9da87e02019-02-04 13:26:26 -0500603 auto proxy = context->priv().proxyProvider()->createLazyProxy(
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400604 singleUseLazyCB, backendFormat, desc, renderable, 1,
Brian Salomon614c1a82018-12-19 15:42:06 -0500605 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
Chris Dalton95d8ceb2019-07-30 11:17:59 -0600606 GrMipMapsStatus::kNotAllocated, GrInternalSurfaceFlags ::kNone,
607 SkBackingFit::kExact, budgeted, GrProtected::kNo,
Brian Salomonbeb7f522019-08-30 16:19:42 -0400608 GrSurfaceProxy::UseAllocator::kYes);
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500609 rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
Brian Salomon8cabb322019-02-22 10:44:19 -0500610 SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(w, h),
611 SkRect::MakeWH(w, h), GrAA::kNo, GrQuadAAFlags::kNone,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500612 SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
Brian Salomon614c1a82018-12-19 15:42:06 -0500613 // We still have the proxy, which should remain instantiated, thereby keeping the
614 // texture not purgeable.
615 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
616 context->flush();
617 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
Robert Phillips9da87e02019-02-04 13:26:26 -0500618 context->priv().getGpu()->testingOnly_flushGpuAndSync();
Brian Salomon614c1a82018-12-19 15:42:06 -0500619 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
620
621 // This time we move the proxy into the draw.
622 rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
Brian Salomon8cabb322019-02-22 10:44:19 -0500623 SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(w, h),
624 SkRect::MakeWH(w, h), GrAA::kNo, GrQuadAAFlags::kNone,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500625 SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
Brian Salomon614c1a82018-12-19 15:42:06 -0500626 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
627 context->flush();
Robert Phillips9da87e02019-02-04 13:26:26 -0500628 context->priv().getGpu()->testingOnly_flushGpuAndSync();
Brian Salomon614c1a82018-12-19 15:42:06 -0500629 // Now that the draw is fully consumed by the GPU, the texture should be idle.
630 REPORTER_ASSERT(reporter, idleIDs.find(2) != idleIDs.end());
631
Brian Salomon9bc76d92019-01-24 12:18:33 -0500632 // Make sure we make the call during various shutdown scenarios where the texture
633 // might persist after context is destroyed, abandoned, etc. We test three
634 // variations of each scenario. One where the texture is just created. Another,
635 // where the texture has been used in a draw and then the context is flushed. And
636 // one where the the texture was drawn but the context is not flushed.
637 // In each scenario we test holding a ref beyond the context shutdown and not.
Brian Salomon614c1a82018-12-19 15:42:06 -0500638
Brian Salomon9bc76d92019-01-24 12:18:33 -0500639 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
640 // and http://skbug.com/8275
641 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
642 if (api == GrBackendApi::kVulkan) {
643 continue;
644 }
Brian Salomonbeb7f522019-08-30 16:19:42 -0400645 int id = 3;
Brian Salomon9bc76d92019-01-24 12:18:33 -0500646 enum class DrawType {
647 kNoDraw,
648 kDraw,
649 kDrawAndFlush,
650 };
651 for (auto drawType :
652 {DrawType::kNoDraw, DrawType::kDraw, DrawType::kDrawAndFlush}) {
653 for (bool unrefFirst : {false, true}) {
Brian Salomon8cabb322019-02-22 10:44:19 -0500654 auto possiblyDrawAndFlush = [&context, &texture, drawType, unrefFirst, w,
655 h] {
Brian Salomon9bc76d92019-01-24 12:18:33 -0500656 if (drawType == DrawType::kNoDraw) {
657 return;
658 }
Brian Salomon8cabb322019-02-22 10:44:19 -0500659 SkImageInfo info = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
Brian Salomon9bc76d92019-01-24 12:18:33 -0500660 kPremul_SkAlphaType);
661 auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
662 nullptr);
Robert Phillips9da87e02019-02-04 13:26:26 -0500663 auto rtc = rt->getCanvas()
Brian Salomon9bc76d92019-01-24 12:18:33 -0500664 ->internal_private_accessTopLayerRenderTargetContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500665 auto proxy = context->priv().proxyProvider()->testingOnly_createWrapped(
Brian Salomon2af3e702019-08-11 19:10:31 -0400666 texture, GrColorType::kRGBA_8888, kTopLeft_GrSurfaceOrigin);
Brian Salomon8cabb322019-02-22 10:44:19 -0500667 rtc->drawTexture(
668 GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
669 SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(w, h),
670 SkRect::MakeWH(w, h), GrAA::kNo, GrQuadAAFlags::kNone,
671 SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500672 if (drawType == DrawType::kDrawAndFlush) {
673 context->flush();
674 }
675 if (unrefFirst) {
676 texture.reset();
677 }
678 };
679 texture = make(context, id);
680 possiblyDrawAndFlush();
681 context->abandonContext();
682 texture.reset();
683 REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
684 factory.destroyContexts();
685 context = factory.get(contextType);
686 ++id;
Brian Salomon614c1a82018-12-19 15:42:06 -0500687
Brian Salomon9bc76d92019-01-24 12:18:33 -0500688 // Similar to previous, but reset the texture after the context was
689 // abandoned and then destroyed.
690 texture = make(context, id);
691 possiblyDrawAndFlush();
692 context->abandonContext();
693 factory.destroyContexts();
694 texture.reset();
695 REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
696 context = factory.get(contextType);
697 id++;
698
699 texture = make(context, id);
700 possiblyDrawAndFlush();
701 factory.destroyContexts();
702 texture.reset();
703 REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
704 context = factory.get(contextType);
705 id++;
706
707 texture = make(context, id);
708 possiblyDrawAndFlush();
709 factory.releaseResourcesAndAbandonContexts();
710 texture.reset();
711 REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
712 context = factory.get(contextType);
713 id++;
714 }
715 }
Brian Salomon614c1a82018-12-19 15:42:06 -0500716 }
717 }
718 }
719}
Brian Salomon8cabb322019-02-22 10:44:19 -0500720
721// Tests an idle proc that unrefs another resource down to zero.
722DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcCacheManipulationTest, reporter, contextInfo) {
723 GrContext* context = contextInfo.grContext();
724
725 // idle proc that releases another texture.
726 auto idleProc = [](void* texture) { reinterpret_cast<GrTexture*>(texture)->unref(); };
727
728 for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
729 for (const auto& otherMaker : {make_wrapped_texture, make_normal_texture}) {
Brian Salomone80b8092019-03-08 13:25:19 -0500730 for (auto idleState :
731 {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400732 auto idleTexture = idleMaker(context, GrRenderable::kNo);
733 auto otherTexture = otherMaker(context, GrRenderable::kNo);
Brian Salomone80b8092019-03-08 13:25:19 -0500734 otherTexture->ref();
735 idleTexture->addIdleProc(idleProc, otherTexture.get(), idleState);
736 otherTexture.reset();
737 idleTexture.reset();
738 }
Brian Salomon8cabb322019-02-22 10:44:19 -0500739 }
740 }
741}
742
743// Similar to above but more complicated. This flushes the context from the idle proc.
744// crbug.com/933526.
745DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcFlushTest, reporter, contextInfo) {
746 GrContext* context = contextInfo.grContext();
747
748 // idle proc that flushes the context.
749 auto idleProc = [](void* context) { reinterpret_cast<GrContext*>(context)->flush(); };
750
751 for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
Brian Salomone80b8092019-03-08 13:25:19 -0500752 for (auto idleState : {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400753 auto idleTexture = idleMaker(context, GrRenderable::kNo);
Brian Salomone80b8092019-03-08 13:25:19 -0500754 idleTexture->addIdleProc(idleProc, context, idleState);
755 auto info = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
756 auto surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 1, nullptr);
757 // We'll draw two images to the canvas. One is a normal texture-backed image. The other
758 // is a wrapped-texture backed image.
759 surf->getCanvas()->clear(SK_ColorWHITE);
760 auto img1 = surf->makeImageSnapshot();
Robert Phillipsee5fd132019-05-07 13:29:22 -0400761
762 GrBackendTexture backendTexture;
763
Robert Phillips4d87b2b2019-07-23 13:44:16 -0400764 if (!create_backend_texture(context, &backendTexture, info, SkColors::kBlack,
765 GrMipMapped::kNo, GrRenderable::kNo)) {
Robert Phillipsee5fd132019-05-07 13:29:22 -0400766 REPORTER_ASSERT(reporter, false);
767 continue;
768 }
769
Brian Salomone80b8092019-03-08 13:25:19 -0500770 auto img2 = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
771 info.colorType(), info.alphaType(), nullptr);
772 surf->getCanvas()->drawImage(std::move(img1), 0, 0);
773 surf->getCanvas()->drawImage(std::move(img2), 1, 1);
774 idleTexture.reset();
Robert Phillipsee5fd132019-05-07 13:29:22 -0400775
776 delete_backend_texture(context, backendTexture);
Brian Salomone80b8092019-03-08 13:25:19 -0500777 }
Brian Salomon8cabb322019-02-22 10:44:19 -0500778 }
779}
780
781DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcRerefTest, reporter, contextInfo) {
782 GrContext* context = contextInfo.grContext();
783 // idle proc that refs the texture
784 auto idleProc = [](void* texture) { reinterpret_cast<GrTexture*>(texture)->ref(); };
785 // release proc to check whether the texture was released or not.
786 auto releaseProc = [](void* isReleased) { *reinterpret_cast<bool*>(isReleased) = true; };
Brian Salomone80b8092019-03-08 13:25:19 -0500787 for (auto idleState : {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
788 bool isReleased = false;
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400789 auto idleTexture = make_normal_texture(context, GrRenderable::kNo);
Brian Salomone80b8092019-03-08 13:25:19 -0500790 // This test assumes the texture won't be cached (or else the release proc doesn't get
791 // called).
792 idleTexture->resourcePriv().removeScratchKey();
793 context->flush();
794 idleTexture->addIdleProc(idleProc, idleTexture.get(), idleState);
795 idleTexture->setRelease(releaseProc, &isReleased);
796 auto* raw = idleTexture.get();
797 idleTexture.reset();
798 REPORTER_ASSERT(reporter, !isReleased);
799 raw->unref();
800 REPORTER_ASSERT(reporter, isReleased);
801 }
802}
803
804DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleStateTest, reporter, contextInfo) {
805 GrContext* context = contextInfo.grContext();
806 for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400807 auto idleTexture = idleMaker(context, GrRenderable::kNo);
Brian Salomone80b8092019-03-08 13:25:19 -0500808
809 uint32_t flags = 0;
810 static constexpr uint32_t kFlushFlag = 0x1;
811 static constexpr uint32_t kFinishFlag = 0x2;
812 auto flushProc = [](void* flags) { *static_cast<uint32_t*>(flags) |= kFlushFlag; };
813 auto finishProc = [](void* flags) { *static_cast<uint32_t*>(flags) |= kFinishFlag; };
814 idleTexture->addIdleProc(flushProc, &flags, GrTexture::IdleState::kFlushed);
815 idleTexture->addIdleProc(finishProc, &flags, GrTexture::IdleState::kFinished);
816
817 // Insert a copy from idleTexture to another texture so that we have some queued IO on
818 // idleTexture.
Greg Daniel46cfbc62019-06-07 11:43:30 -0400819 SkImageInfo info = SkImageInfo::Make(kSurfSize, kSurfSize, kRGBA_8888_SkColorType,
820 kPremul_SkAlphaType);
Brian Salomone80b8092019-03-08 13:25:19 -0500821 auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
822 auto rtc = rt->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
Greg Daniel46cfbc62019-06-07 11:43:30 -0400823 auto proxy = context->priv().proxyProvider()->testingOnly_createWrapped(
Brian Salomon2af3e702019-08-11 19:10:31 -0400824 std::move(idleTexture), GrColorType::kRGBA_8888, rtc->asSurfaceProxy()->origin());
Brian Salomone80b8092019-03-08 13:25:19 -0500825 context->flush();
Greg Daniel46cfbc62019-06-07 11:43:30 -0400826 SkAssertResult(rtc->testCopy(proxy.get()));
Brian Salomone80b8092019-03-08 13:25:19 -0500827 proxy.reset();
828 REPORTER_ASSERT(reporter, flags == 0);
829
830 // After a flush we expect idleTexture to have reached the kFlushed state on all backends.
831 // On "managed" backends we expect it to reach kFinished as well. On Vulkan, the only
832 // current "unmanaged" backend, we *may* need a sync to reach kFinished.
833 context->flush();
834 if (contextInfo.backend() == kVulkan_GrBackend) {
835 REPORTER_ASSERT(reporter, flags & kFlushFlag);
836 } else {
837 REPORTER_ASSERT(reporter, flags == (kFlushFlag | kFinishFlag));
838 }
839 context->priv().getGpu()->testingOnly_flushGpuAndSync();
840 REPORTER_ASSERT(reporter, flags == (kFlushFlag | kFinishFlag));
841 }
Brian Salomon8cabb322019-02-22 10:44:19 -0500842}