1 /*
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
8 #include <set>
9 #include "GrClip.h"
10 #include "GrContext.h"
11 #include "GrContextPriv.h"
12 #include "GrGpu.h"
13 #include "GrProxyProvider.h"
14 #include "GrRenderTarget.h"
15 #include "GrResourceProvider.h"
16 #include "GrTexture.h"
17 #include "GrTexturePriv.h"
18 #include "SkAutoPixmapStorage.h"
19 #include "SkMipMap.h"
20 #include "SkSurface.h"
21 #include "Test.h"
22
23 // Tests that GrSurface::asTexture(), GrSurface::asRenderTarget(), and static upcasting of texture
24 // and render targets to GrSurface all work as expected.
DEF_GPUTEST_FOR_NULLGL_CONTEXT(GrSurface,reporter,ctxInfo)25 DEF_GPUTEST_FOR_NULLGL_CONTEXT(GrSurface, reporter, ctxInfo) {
26 GrContext* context = ctxInfo.grContext();
27 auto resourceProvider = context->contextPriv().resourceProvider();
28 GrGpu* gpu = context->contextPriv().getGpu();
29
30 GrSurfaceDesc desc;
31 desc.fFlags = kRenderTarget_GrSurfaceFlag;
32 desc.fWidth = 256;
33 desc.fHeight = 256;
34 desc.fConfig = kRGBA_8888_GrPixelConfig;
35 desc.fSampleCnt = 1;
36 sk_sp<GrSurface> texRT1 = resourceProvider->createTexture(desc, SkBudgeted::kNo);
37
38 REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asRenderTarget());
39 REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asTexture());
40 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
41 texRT1->asTexture());
42 REPORTER_ASSERT(reporter, texRT1->asRenderTarget() ==
43 static_cast<GrSurface*>(texRT1->asTexture()));
44 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
45 static_cast<GrSurface*>(texRT1->asTexture()));
46
47 desc.fFlags = kNone_GrSurfaceFlags;
48 sk_sp<GrTexture> tex1 = resourceProvider->createTexture(desc, SkBudgeted::kNo);
49 REPORTER_ASSERT(reporter, nullptr == tex1->asRenderTarget());
50 REPORTER_ASSERT(reporter, tex1.get() == tex1->asTexture());
51 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(tex1.get()) == tex1->asTexture());
52
53 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
54 nullptr, 256, 256, GrColorType::kRGBA_8888, false, GrMipMapped::kNo);
55
56 sk_sp<GrSurface> texRT2 = resourceProvider->wrapRenderableBackendTexture(
57 backendTex, 1, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo);
58
59 REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asRenderTarget());
60 REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asTexture());
61 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
62 texRT2->asTexture());
63 REPORTER_ASSERT(reporter, texRT2->asRenderTarget() ==
64 static_cast<GrSurface*>(texRT2->asTexture()));
65 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
66 static_cast<GrSurface*>(texRT2->asTexture()));
67
68 gpu->deleteTestingOnlyBackendTexture(backendTex);
69 }
70
71 // This test checks that the isConfigTexturable and isConfigRenderable are
72 // consistent with createTexture's result.
DEF_GPUTEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability,reporter,ctxInfo)73 DEF_GPUTEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability, reporter, ctxInfo) {
74 GrContext* context = ctxInfo.grContext();
75 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
76 GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider();
77 const GrCaps* caps = context->contextPriv().caps();
78
79 GrPixelConfig configs[] = {
80 kUnknown_GrPixelConfig,
81 kAlpha_8_GrPixelConfig,
82 kAlpha_8_as_Alpha_GrPixelConfig,
83 kAlpha_8_as_Red_GrPixelConfig,
84 kGray_8_GrPixelConfig,
85 kGray_8_as_Lum_GrPixelConfig,
86 kGray_8_as_Red_GrPixelConfig,
87 kRGB_565_GrPixelConfig,
88 kRGBA_4444_GrPixelConfig,
89 kRGBA_8888_GrPixelConfig,
90 kRGB_888_GrPixelConfig,
91 kRG_88_GrPixelConfig,
92 kBGRA_8888_GrPixelConfig,
93 kSRGBA_8888_GrPixelConfig,
94 kSBGRA_8888_GrPixelConfig,
95 kRGBA_1010102_GrPixelConfig,
96 kRGBA_float_GrPixelConfig,
97 kRG_float_GrPixelConfig,
98 kAlpha_half_GrPixelConfig,
99 kAlpha_half_as_Red_GrPixelConfig,
100 kRGBA_half_GrPixelConfig,
101 kRGB_ETC1_GrPixelConfig,
102 };
103 GR_STATIC_ASSERT(kGrPixelConfigCnt == SK_ARRAY_COUNT(configs));
104
105 GrSurfaceDesc desc;
106 desc.fWidth = 64;
107 desc.fHeight = 64;
108
109 for (GrPixelConfig config : configs) {
110 for (GrSurfaceOrigin origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
111 desc.fFlags = kNone_GrSurfaceFlags;
112 desc.fConfig = config;
113 desc.fSampleCnt = 1;
114
115 sk_sp<GrSurface> tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
116 bool ict = caps->isConfigTexturable(desc.fConfig);
117 REPORTER_ASSERT(reporter, SkToBool(tex) == ict,
118 "config:%d, tex:%d, isConfigTexturable:%d", config, SkToBool(tex), ict);
119
120 GrSRGBEncoded srgbEncoded = GrSRGBEncoded::kNo;
121 GrColorType colorType = GrPixelConfigToColorTypeAndEncoding(config, &srgbEncoded);
122 const GrBackendFormat format =
123 caps->getBackendFormatFromGrColorType(colorType, srgbEncoded);
124
125 sk_sp<GrTextureProxy> proxy =
126 proxyProvider->createMipMapProxy(format, desc, origin, SkBudgeted::kNo);
127 REPORTER_ASSERT(reporter, SkToBool(proxy.get()) ==
128 (caps->isConfigTexturable(desc.fConfig) &&
129 caps->mipMapSupport()));
130
131 desc.fFlags = kRenderTarget_GrSurfaceFlag;
132 tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
133 bool isRenderable = caps->isConfigRenderable(config);
134 REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
135 "config:%d, tex:%d, isRenderable:%d", config, SkToBool(tex),
136 isRenderable);
137
138 desc.fSampleCnt = 2;
139 tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
140 isRenderable = SkToBool(caps->getRenderTargetSampleCount(2, config));
141 REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
142 "config:%d, tex:%d, isRenderable:%d", config, SkToBool(tex),
143 isRenderable);
144 }
145 }
146 }
147
148 #include "GrDrawingManager.h"
149 #include "GrSurfaceProxy.h"
150 #include "GrTextureContext.h"
151
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(InitialTextureClear,reporter,context_info)152 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(InitialTextureClear, reporter, context_info) {
153 static constexpr int kSize = 100;
154 GrSurfaceDesc desc;
155 desc.fWidth = desc.fHeight = kSize;
156 std::unique_ptr<uint32_t[]> data(new uint32_t[kSize * kSize]);
157
158 GrContext* context = context_info.grContext();
159 const GrCaps* caps = context->contextPriv().caps();
160 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
161
162 for (int c = 0; c <= kLast_GrPixelConfig; ++c) {
163 desc.fConfig = static_cast<GrPixelConfig>(c);
164 if (!caps->isConfigTexturable(desc.fConfig)) {
165 continue;
166 }
167 desc.fFlags = kPerformInitialClear_GrSurfaceFlag;
168 for (bool rt : {false, true}) {
169 if (rt && !caps->isConfigRenderable(desc.fConfig)) {
170 continue;
171 }
172 desc.fFlags |= rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
173 for (GrSurfaceOrigin origin :
174 {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
175 for (auto fit : { SkBackingFit::kApprox, SkBackingFit::kExact }) {
176 // Try directly creating the texture.
177 // Do this twice in an attempt to hit the cache on the second time through.
178 for (int i = 0; i < 2; ++i) {
179 auto proxy = proxyProvider->testingOnly_createInstantiatedProxy(
180 desc, origin, fit, SkBudgeted::kYes);
181 if (!proxy) {
182 continue;
183 }
184 auto texCtx = context->contextPriv().makeWrappedSurfaceContext(
185 std::move(proxy));
186 SkImageInfo info = SkImageInfo::Make(
187 kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
188 memset(data.get(), 0xAB, kSize * kSize * sizeof(uint32_t));
189 if (texCtx->readPixels(info, data.get(), 0, 0, 0)) {
190 uint32_t cmp = GrPixelConfigIsOpaque(desc.fConfig) ? 0xFF000000 : 0;
191 for (int i = 0; i < kSize * kSize; ++i) {
192 if (cmp != data.get()[i]) {
193 ERRORF(reporter, "Failed on config %d", desc.fConfig);
194 break;
195 }
196 }
197 }
198 memset(data.get(), 0xBC, kSize * kSize * sizeof(uint32_t));
199 // Here we overwrite the texture so that the second time through we
200 // test against recycling without reclearing.
201 if (0 == i) {
202 texCtx->writePixels(info, data.get(), 0, 0, 0);
203 }
204 }
205 context->contextPriv().purgeAllUnlockedResources_ForTesting();
206
207 GrSRGBEncoded srgbEncoded = GrSRGBEncoded::kNo;
208 GrColorType colorType = GrPixelConfigToColorTypeAndEncoding(desc.fConfig,
209 &srgbEncoded);
210 const GrBackendFormat format =
211 caps->getBackendFormatFromGrColorType(colorType, srgbEncoded);
212
213 // Try creating the texture as a deferred proxy.
214 for (int i = 0; i < 2; ++i) {
215 auto surfCtx = context->contextPriv().makeDeferredSurfaceContext(
216 format, desc, origin, GrMipMapped::kNo, fit, SkBudgeted::kYes);
217 if (!surfCtx) {
218 continue;
219 }
220 SkImageInfo info = SkImageInfo::Make(
221 kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
222 memset(data.get(), 0xAB, kSize * kSize * sizeof(uint32_t));
223 if (surfCtx->readPixels(info, data.get(), 0, 0, 0)) {
224 uint32_t cmp = GrPixelConfigIsOpaque(desc.fConfig) ? 0xFF000000 : 0;
225 for (int i = 0; i < kSize * kSize; ++i) {
226 if (cmp != data.get()[i]) {
227 ERRORF(reporter, "Failed on config %d", desc.fConfig);
228 break;
229 }
230 }
231 }
232 // Here we overwrite the texture so that the second time through we
233 // test against recycling without reclearing.
234 if (0 == i) {
235 surfCtx->writePixels(info, data.get(), 0, 0, 0);
236 }
237 }
238 context->contextPriv().purgeAllUnlockedResources_ForTesting();
239 }
240 }
241 }
242 }
243 }
244
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture,reporter,context_info)245 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture, reporter, context_info) {
246 auto fillPixels = [](const SkPixmap* p, const std::function<uint32_t(int x, int y)>& f) {
247 for (int y = 0; y < p->height(); ++y) {
248 for (int x = 0; x < p->width(); ++x) {
249 *p->writable_addr32(x, y) = f(x, y);
250 }
251 }
252 };
253
254 auto comparePixels = [](const SkPixmap& p1, const SkPixmap& p2, skiatest::Reporter* reporter) {
255 SkASSERT(p1.info() == p2.info());
256 for (int y = 0; y < p1.height(); ++y) {
257 for (int x = 0; x < p1.width(); ++x) {
258 REPORTER_ASSERT(reporter, p1.getColor(x, y) == p2.getColor(x, y));
259 if (p1.getColor(x, y) != p2.getColor(x, y)) {
260 return;
261 }
262 }
263 }
264 };
265
266 static constexpr int kSize = 100;
267 SkAutoPixmapStorage pixels;
268 pixels.alloc(SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
269 fillPixels(&pixels,
270 [](int x, int y) { return (0xFFU << 24) | (x << 16) | (y << 8) | uint8_t(x * y); });
271
272 GrContext* context = context_info.grContext();
273 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
274
275 // We test both kRW in addition to kRead mostly to ensure that the calls are structured such
276 // that they'd succeed if the texture wasn't kRead. We want to be sure we're failing with
277 // kRead for the right reason.
278 for (auto ioType : {kRead_GrIOType, kRW_GrIOType}) {
279 auto backendTex = context->contextPriv().getGpu()->createTestingOnlyBackendTexture(
280 pixels.addr(), kSize, kSize, kRGBA_8888_SkColorType, true, GrMipMapped::kNo);
281 auto proxy = proxyProvider->wrapBackendTexture(backendTex, kTopLeft_GrSurfaceOrigin,
282 kBorrow_GrWrapOwnership,
283 GrWrapCacheable::kNo, ioType);
284 auto surfContext = context->contextPriv().makeWrappedSurfaceContext(proxy);
285
286 // Read pixels should work with a read-only texture.
287 SkAutoPixmapStorage read;
288 read.alloc(pixels.info());
289 auto readResult = surfContext->readPixels(pixels.info(), read.writable_addr(), 0, 0, 0);
290 REPORTER_ASSERT(reporter, readResult);
291 if (readResult) {
292 comparePixels(pixels, read, reporter);
293 }
294
295 // Write pixels should not work with a read-only texture.
296 SkAutoPixmapStorage write;
297 write.alloc(pixels.info());
298 fillPixels(&write, [&pixels](int x, int y) { return ~*pixels.addr32(); });
299 auto writeResult = surfContext->writePixels(pixels.info(), pixels.addr(), 0, 0, 0);
300 REPORTER_ASSERT(reporter, writeResult == (ioType == kRW_GrIOType));
301 // Try the low level write.
302 context->flush();
303 auto gpuWriteResult = context->contextPriv().getGpu()->writePixels(
304 proxy->peekTexture(), 0, 0, kSize, kSize, GrColorType::kRGBA_8888, write.addr32(),
305 0);
306 REPORTER_ASSERT(reporter, gpuWriteResult == (ioType == kRW_GrIOType));
307
308 // Copies should not work with a read-only texture
309 auto copySrc = proxyProvider->createTextureProxy(
310 SkImage::MakeFromRaster(write, nullptr, nullptr), kNone_GrSurfaceFlags, 1,
311 SkBudgeted::kYes, SkBackingFit::kExact);
312 REPORTER_ASSERT(reporter, copySrc);
313 auto copyResult = surfContext->copy(copySrc.get());
314 REPORTER_ASSERT(reporter, copyResult == (ioType == kRW_GrIOType));
315 // Try the low level copy.
316 context->flush();
317 auto gpuCopyResult = context->contextPriv().getGpu()->copySurface(
318 proxy->peekTexture(), kTopLeft_GrSurfaceOrigin, copySrc->peekTexture(),
319 kTopLeft_GrSurfaceOrigin, SkIRect::MakeWH(kSize, kSize), {0, 0});
320 REPORTER_ASSERT(reporter, gpuCopyResult == (ioType == kRW_GrIOType));
321
322 // Mip regen should not work with a read only texture.
323 if (context->contextPriv().caps()->mipMapSupport()) {
324 backendTex = context->contextPriv().getGpu()->createTestingOnlyBackendTexture(
325 nullptr, kSize, kSize, kRGBA_8888_SkColorType, true, GrMipMapped::kYes);
326 proxy = proxyProvider->wrapBackendTexture(backendTex, kTopLeft_GrSurfaceOrigin,
327 kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
328 ioType);
329 context->flush();
330 proxy->peekTexture()->texturePriv().markMipMapsDirty(); // avoids assert in GrGpu.
331 auto regenResult =
332 context->contextPriv().getGpu()->regenerateMipMapLevels(proxy->peekTexture());
333 REPORTER_ASSERT(reporter, regenResult == (ioType == kRW_GrIOType));
334 }
335 }
336 }
337
DEF_GPUTEST(TextureIdleProcTest,reporter,options)338 DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
339 static const int kS = 10;
340
341 // Helper to delete a backend texture in a GrTexture's release proc.
342 static const auto installBackendTextureReleaseProc = [](GrTexture* texture) {
343 auto backendTexture = texture->getBackendTexture();
344 auto context = texture->getContext();
345 struct ReleaseContext {
346 GrContext* fContext;
347 GrBackendTexture fBackendTexture;
348 };
349 auto release = [](void* rc) {
350 auto releaseContext = static_cast<ReleaseContext*>(rc);
351 if (!releaseContext->fContext->abandoned()) {
352 if (auto gpu = releaseContext->fContext->contextPriv().getGpu()) {
353 gpu->deleteTestingOnlyBackendTexture(releaseContext->fBackendTexture);
354 }
355 }
356 delete releaseContext;
357 };
358 texture->setRelease(sk_make_sp<GrReleaseProcHelper>(
359 release, new ReleaseContext{context, backendTexture}));
360 };
361
362 // Various ways of making textures.
363 auto makeWrapped = [](GrContext* context) {
364 auto backendTexture = context->contextPriv().getGpu()->createTestingOnlyBackendTexture(
365 nullptr, kS, kS, GrColorType::kRGBA_8888, false, GrMipMapped::kNo);
366 auto texture = context->contextPriv().resourceProvider()->wrapBackendTexture(
367 backendTexture, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType);
368 installBackendTextureReleaseProc(texture.get());
369 return texture;
370 };
371
372 auto makeWrappedRenderable = [](GrContext* context) {
373 auto backendTexture = context->contextPriv().getGpu()->createTestingOnlyBackendTexture(
374 nullptr, kS, kS, GrColorType::kRGBA_8888, true, GrMipMapped::kNo);
375 auto texture = context->contextPriv().resourceProvider()->wrapRenderableBackendTexture(
376 backendTexture, 1, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo);
377 installBackendTextureReleaseProc(texture.get());
378 return texture;
379 };
380
381 auto makeNormal = [](GrContext* context) {
382 GrSurfaceDesc desc;
383 desc.fConfig = kRGBA_8888_GrPixelConfig;
384 desc.fWidth = desc.fHeight = kS;
385 return context->contextPriv().resourceProvider()->createTexture(desc, SkBudgeted::kNo);
386 };
387
388 auto makeRenderable = [](GrContext* context) {
389 GrSurfaceDesc desc;
390 desc.fFlags = kRenderTarget_GrSurfaceFlag;
391 desc.fConfig = kRGBA_8888_GrPixelConfig;
392 desc.fWidth = desc.fHeight = kS;
393 return context->contextPriv().resourceProvider()->createTexture(desc, SkBudgeted::kNo);
394 };
395
396 std::function<sk_sp<GrTexture>(GrContext*)> makers[] = {makeWrapped, makeWrappedRenderable,
397 makeNormal, makeRenderable};
398
399 // Add a unique key, or not.
400 auto addKey = [](GrTexture* texture) {
401 static uint32_t gN = 0;
402 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
403 GrUniqueKey key;
404 GrUniqueKey::Builder builder(&key, kDomain, 1);
405 builder[0] = gN++;
406 builder.finish();
407 texture->resourcePriv().setUniqueKey(key);
408 };
409 auto dontAddKey = [](GrTexture* texture) {};
410 std::function<void(GrTexture*)> keyAdders[] = {addKey, dontAddKey};
411
412 for (const auto& m : makers) {
413 for (const auto& keyAdder : keyAdders) {
414 for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
415 sk_gpu_test::GrContextFactory factory;
416 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
417 GrContext* context = factory.get(contextType);
418 if (!context) {
419 continue;
420 }
421
422 // The callback we add simply adds an integer to a set.
423 std::set<int> idleIDs;
424 struct Context {
425 std::set<int>* fIdleIDs;
426 int fNum;
427 };
428 auto proc = [](void* context) {
429 static_cast<Context*>(context)->fIdleIDs->insert(
430 static_cast<Context*>(context)->fNum);
431 delete static_cast<Context*>(context);
432 };
433
434 // Makes a texture, possibly adds a key, and sets the callback.
435 auto make = [&m, &keyAdder, &proc, &idleIDs](GrContext* context, int num) {
436 sk_sp<GrTexture> texture = m(context);
437 texture->setIdleProc(proc, new Context{&idleIDs, num});
438 keyAdder(texture.get());
439 return texture;
440 };
441
442 auto texture = make(context, 1);
443 REPORTER_ASSERT(reporter, idleIDs.find(1) == idleIDs.end());
444 bool isRT = SkToBool(texture->asRenderTarget());
445 auto backendFormat = texture->backendFormat();
446 texture.reset();
447 REPORTER_ASSERT(reporter, idleIDs.find(1) != idleIDs.end());
448
449 texture = make(context, 2);
450 SkImageInfo info =
451 SkImageInfo::Make(kS, kS, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
452 auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
453 auto rtc = rt->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
454 auto singleUseLazyCB = [&texture](GrResourceProvider* rp) {
455 return rp ? std::move(texture) : nullptr;
456 };
457 GrSurfaceDesc desc;
458 desc.fWidth = desc.fHeight = kS;
459 desc.fConfig = kRGBA_8888_GrPixelConfig;
460 if (isRT) {
461 desc.fFlags = kRenderTarget_GrSurfaceFlag;
462 }
463 SkBudgeted budgeted;
464 if (texture->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted) {
465 budgeted = SkBudgeted::kYes;
466 } else {
467 budgeted = SkBudgeted::kNo;
468 }
469 auto proxy = context->contextPriv().proxyProvider()->createLazyProxy(
470 singleUseLazyCB, backendFormat, desc,
471 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
472 GrInternalSurfaceFlags ::kNone, SkBackingFit::kExact, budgeted,
473 GrSurfaceProxy::LazyInstantiationType::kSingleUse);
474 rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest, SkPMColor4f(),
475 SkRect::MakeWH(kS, kS), SkRect::MakeWH(kS, kS),
476 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
477 SkMatrix::I(), nullptr);
478 // We still have the proxy, which should remain instantiated, thereby keeping the
479 // texture not purgeable.
480 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
481 context->flush();
482 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
483 context->contextPriv().getGpu()->testingOnly_flushGpuAndSync();
484 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
485
486 // This time we move the proxy into the draw.
487 rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
488 SkPMColor4f(), SkRect::MakeWH(kS, kS), SkRect::MakeWH(kS, kS),
489 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
490 SkMatrix::I(), nullptr);
491 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
492 context->flush();
493 context->contextPriv().getGpu()->testingOnly_flushGpuAndSync();
494 // Now that the draw is fully consumed by the GPU, the texture should be idle.
495 REPORTER_ASSERT(reporter, idleIDs.find(2) != idleIDs.end());
496
497 // Make a proxy that should deinstantiate even if we keep a ref on it.
498 auto deinstantiateLazyCB = [&make, &context](GrResourceProvider* rp) {
499 return rp ? make(context, 3) : nullptr;
500 };
501 proxy = context->contextPriv().proxyProvider()->createLazyProxy(
502 deinstantiateLazyCB, backendFormat, desc,
503 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
504 GrInternalSurfaceFlags ::kNone, SkBackingFit::kExact, budgeted,
505 GrSurfaceProxy::LazyInstantiationType::kDeinstantiate);
506 rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
507 SkPMColor4f(), SkRect::MakeWH(kS, kS), SkRect::MakeWH(kS, kS),
508 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
509 SkMatrix::I(), nullptr);
510 // At this point the proxy shouldn't even be instantiated, there is no texture with
511 // id 3.
512 REPORTER_ASSERT(reporter, idleIDs.find(3) == idleIDs.end());
513 context->flush();
514 context->contextPriv().getGpu()->testingOnly_flushGpuAndSync();
515 // Now that the draw is fully consumed, we should have deinstantiated the proxy and
516 // the texture it made should be idle.
517 REPORTER_ASSERT(reporter, idleIDs.find(3) != idleIDs.end());
518
519 // Make sure we make the call during various shutdown scenarios where the texture
520 // might persist after context is destroyed, abandoned, etc. We test three
521 // variations of each scenario. One where the texture is just created. Another,
522 // where the texture has been used in a draw and then the context is flushed. And
523 // one where the the texture was drawn but the context is not flushed.
524 // In each scenario we test holding a ref beyond the context shutdown and not.
525
526 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
527 // and http://skbug.com/8275
528 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
529 if (api == GrBackendApi::kVulkan) {
530 continue;
531 }
532 int id = 4;
533 enum class DrawType {
534 kNoDraw,
535 kDraw,
536 kDrawAndFlush,
537 };
538 for (auto drawType :
539 {DrawType::kNoDraw, DrawType::kDraw, DrawType::kDrawAndFlush}) {
540 for (bool unrefFirst : {false, true}) {
541 auto possiblyDrawAndFlush = [&context, &texture, drawType, unrefFirst] {
542 if (drawType == DrawType::kNoDraw) {
543 return;
544 }
545 SkImageInfo info = SkImageInfo::Make(kS, kS, kRGBA_8888_SkColorType,
546 kPremul_SkAlphaType);
547 auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
548 nullptr);
549 auto rtc =
550 rt->getCanvas()
551 ->internal_private_accessTopLayerRenderTargetContext();
552 auto proxy = context->contextPriv()
553 .proxyProvider()
554 ->testingOnly_createWrapped(
555 texture, kTopLeft_GrSurfaceOrigin);
556 rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
557 SkPMColor4f(), SkRect::MakeWH(kS, kS),
558 SkRect::MakeWH(kS, kS), GrQuadAAFlags::kNone,
559 SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
560 nullptr);
561 if (drawType == DrawType::kDrawAndFlush) {
562 context->flush();
563 }
564 if (unrefFirst) {
565 texture.reset();
566 }
567 };
568 texture = make(context, id);
569 possiblyDrawAndFlush();
570 context->abandonContext();
571 texture.reset();
572 REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
573 factory.destroyContexts();
574 context = factory.get(contextType);
575 ++id;
576
577 // Similar to previous, but reset the texture after the context was
578 // abandoned and then destroyed.
579 texture = make(context, id);
580 possiblyDrawAndFlush();
581 context->abandonContext();
582 factory.destroyContexts();
583 texture.reset();
584 REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
585 context = factory.get(contextType);
586 id++;
587
588 texture = make(context, id);
589 possiblyDrawAndFlush();
590 factory.destroyContexts();
591 texture.reset();
592 REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
593 context = factory.get(contextType);
594 id++;
595
596 texture = make(context, id);
597 possiblyDrawAndFlush();
598 factory.releaseResourcesAndAbandonContexts();
599 texture.reset();
600 REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
601 context = factory.get(contextType);
602 id++;
603 }
604 }
605 }
606 }
607 }
608 }
609