• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkSurface.h"
10 #include "include/gpu/GrContext.h"
11 #include "include/gpu/GrTexture.h"
12 #include "src/core/SkAutoPixmapStorage.h"
13 #include "src/core/SkCompressedDataUtils.h"
14 #include "src/gpu/GrBitmapTextureMaker.h"
15 #include "src/gpu/GrClip.h"
16 #include "src/gpu/GrContextPriv.h"
17 #include "src/gpu/GrGpu.h"
18 #include "src/gpu/GrImageInfo.h"
19 #include "src/gpu/GrProxyProvider.h"
20 #include "src/gpu/GrRenderTarget.h"
21 #include "src/gpu/GrResourceProvider.h"
22 #include "src/gpu/GrTexturePriv.h"
23 #include "tests/Test.h"
24 #include "tests/TestUtils.h"
25 
26 // Tests that GrSurface::asTexture(), GrSurface::asRenderTarget(), and static upcasting of texture
27 // and render targets to GrSurface all work as expected.
DEF_GPUTEST_FOR_MOCK_CONTEXT(GrSurface,reporter,ctxInfo)28 DEF_GPUTEST_FOR_MOCK_CONTEXT(GrSurface, reporter, ctxInfo) {
29     GrContext* context = ctxInfo.grContext();
30     auto resourceProvider = context->priv().resourceProvider();
31 
32     static constexpr SkISize kDesc = {256, 256};
33     auto format = context->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
34                                                                   GrRenderable::kYes);
35     sk_sp<GrSurface> texRT1 =
36             resourceProvider->createTexture(kDesc, format, GrRenderable::kYes, 1, GrMipMapped::kNo,
37                                             SkBudgeted::kNo, GrProtected::kNo);
38 
39     REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asRenderTarget());
40     REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asTexture());
41     REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
42                     texRT1->asTexture());
43     REPORTER_ASSERT(reporter, texRT1->asRenderTarget() ==
44                     static_cast<GrSurface*>(texRT1->asTexture()));
45     REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
46                     static_cast<GrSurface*>(texRT1->asTexture()));
47 
48     sk_sp<GrTexture> tex1 =
49             resourceProvider->createTexture(kDesc, format, GrRenderable::kNo, 1, GrMipMapped::kNo,
50                                             SkBudgeted::kNo, GrProtected::kNo);
51     REPORTER_ASSERT(reporter, nullptr == tex1->asRenderTarget());
52     REPORTER_ASSERT(reporter, tex1.get() == tex1->asTexture());
53     REPORTER_ASSERT(reporter, static_cast<GrSurface*>(tex1.get()) == tex1->asTexture());
54 
55     GrBackendTexture backendTex = context->createBackendTexture(
56         256, 256, kRGBA_8888_SkColorType,
57         SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
58 
59     sk_sp<GrSurface> texRT2 = resourceProvider->wrapRenderableBackendTexture(
60             backendTex, 1, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo);
61 
62     REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asRenderTarget());
63     REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asTexture());
64     REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
65                     texRT2->asTexture());
66     REPORTER_ASSERT(reporter, texRT2->asRenderTarget() ==
67                     static_cast<GrSurface*>(texRT2->asTexture()));
68     REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
69                     static_cast<GrSurface*>(texRT2->asTexture()));
70 
71     context->deleteBackendTexture(backendTex);
72 }
73 
74 // This test checks that the isFormatTexturable and isFormatRenderable are
75 // consistent with createTexture's result.
DEF_GPUTEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability,reporter,ctxInfo)76 DEF_GPUTEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability, reporter, ctxInfo) {
77     GrContext* context = ctxInfo.grContext();
78     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
79     GrResourceProvider* resourceProvider = context->priv().resourceProvider();
80     const GrCaps* caps = context->priv().caps();
81 
82     // TODO: Should only need format here but need to determine compression type from format
83     // without config.
84     auto createTexture = [](SkISize dimensions, GrColorType colorType,
85                             const GrBackendFormat& format, GrRenderable renderable,
86                             GrResourceProvider* rp) -> sk_sp<GrTexture> {
87         SkImage::CompressionType compression = rp->caps()->compressionType(format);
88         if (compression != SkImage::CompressionType::kNone) {
89             if (renderable == GrRenderable::kYes) {
90                 return nullptr;
91             }
92             auto size = SkCompressedDataSize(compression, dimensions, nullptr, false);
93             auto data = SkData::MakeUninitialized(size);
94             SkColor4f color = {0, 0, 0, 0};
95             GrFillInCompressedData(compression, dimensions, GrMipMapped::kNo,
96                                    (char*)data->writable_data(), color);
97             return rp->createCompressedTexture(dimensions, format, SkBudgeted::kNo,
98                                                GrMipMapped::kNo, GrProtected::kNo, data.get());
99         } else {
100             return rp->createTexture(dimensions, format, renderable, 1, GrMipMapped::kNo,
101                                      SkBudgeted::kNo, GrProtected::kNo);
102         }
103     };
104 
105     static constexpr SkISize kDims = {64, 64};
106 
107     const std::vector<GrCaps::TestFormatColorTypeCombination>& combos =
108                                                                     caps->getTestingCombinations();
109 
110     for (auto combo : combos) {
111 
112         SkASSERT(combo.fColorType != GrColorType::kUnknown);
113         SkASSERT(combo.fFormat.isValid());
114 
115         // Right now Vulkan has two backend formats that support ABGR_4444 (R4G4B4A4 and B4G4R4A4).
116         // Until we can create textures directly from the backend format this yields some
117         // ambiguity in what is actually supported and which textures can be created.
118         if (ctxInfo.backend() == kVulkan_GrBackend && combo.fColorType == GrColorType::kABGR_4444) {
119             continue;
120         }
121 
122         // Check if 'isFormatTexturable' agrees with 'createTexture' and that the mipmap
123         // support check is working
124         {
125             bool isCompressed = caps->isFormatCompressed(combo.fFormat);
126             bool isTexturable;
127             if (isCompressed) {
128                 isTexturable = caps->isFormatTexturable(combo.fFormat);
129             } else {
130                 isTexturable =
131                         caps->isFormatTexturableAndUploadable(combo.fColorType, combo.fFormat);
132             }
133 
134             sk_sp<GrSurface> tex = createTexture(kDims, combo.fColorType, combo.fFormat,
135                                                  GrRenderable::kNo, resourceProvider);
136             REPORTER_ASSERT(reporter, SkToBool(tex) == isTexturable,
137                             "ct:%s format:%s, tex:%d, isTexturable:%d",
138                             GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
139                             SkToBool(tex), isTexturable);
140 
141             // Check that the lack of mipmap support blocks the creation of mipmapped
142             // proxies
143             bool expectedMipMapability = isTexturable && caps->mipMapSupport() && !isCompressed;
144 
145             GrSwizzle swizzle = caps->getReadSwizzle(combo.fFormat, combo.fColorType);
146 
147             sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(
148                     combo.fFormat, kDims, swizzle, GrRenderable::kNo, 1, GrMipMapped::kYes,
149                     SkBackingFit::kExact, SkBudgeted::kNo, GrProtected::kNo);
150             REPORTER_ASSERT(reporter, SkToBool(proxy.get()) == expectedMipMapability,
151                             "ct:%s format:%s, tex:%d, expectedMipMapability:%d",
152                             GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
153                             SkToBool(proxy.get()), expectedMipMapability);
154         }
155 
156         // Check if 'isFormatAsColorTypeRenderable' agrees with 'createTexture' (w/o MSAA)
157         {
158             bool isRenderable = caps->isFormatRenderable(combo.fFormat, 1);
159 
160             sk_sp<GrSurface> tex = resourceProvider->createTexture(
161                     kDims, combo.fFormat, GrRenderable::kYes, 1, GrMipMapped::kNo, SkBudgeted::kNo,
162                     GrProtected::kNo);
163             REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
164                             "ct:%s format:%s, tex:%d, isRenderable:%d",
165                             GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
166                             SkToBool(tex), isRenderable);
167         }
168 
169         // Check if 'isFormatAsColorTypeRenderable' agrees with 'createTexture' w/ MSAA
170         {
171             bool isRenderable = caps->isFormatRenderable(combo.fFormat, 2);
172 
173             sk_sp<GrSurface> tex = resourceProvider->createTexture(
174                     kDims, combo.fFormat, GrRenderable::kYes, 2, GrMipMapped::kNo, SkBudgeted::kNo,
175                     GrProtected::kNo);
176             REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
177                             "ct:%s format:%s, tex:%d, isRenderable:%d",
178                             GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
179                             SkToBool(tex), isRenderable);
180         }
181     }
182 }
183 
184 #include "src/gpu/GrDrawingManager.h"
185 #include "src/gpu/GrSurfaceProxy.h"
186 
187 // For each context, set it to always clear the textures and then run through all the
188 // supported formats checking that the textures are actually cleared
DEF_GPUTEST(InitialTextureClear,reporter,baseOptions)189 DEF_GPUTEST(InitialTextureClear, reporter, baseOptions) {
190     GrContextOptions options = baseOptions;
191     options.fClearAllTextures = true;
192 
193     static constexpr int kSize = 100;
194     static constexpr SkColor kClearColor = 0xABABABAB;
195 
196     const SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
197                                                kPremul_SkAlphaType);
198 
199     SkAutoPixmapStorage readback;
200     readback.alloc(info);
201 
202     SkISize desc;
203     desc.fWidth = desc.fHeight = kSize;
204 
205     for (int ct = 0; ct < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++ct) {
206         sk_gpu_test::GrContextFactory factory(options);
207         auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(ct);
208         if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
209             continue;
210         }
211         auto context = factory.get(contextType);
212         if (!context) {
213             continue;
214         }
215 
216         GrProxyProvider* proxyProvider = context->priv().proxyProvider();
217         const GrCaps* caps = context->priv().caps();
218 
219         const std::vector<GrCaps::TestFormatColorTypeCombination>& combos =
220                                                                     caps->getTestingCombinations();
221 
222         for (auto combo : combos) {
223 
224             SkASSERT(combo.fColorType != GrColorType::kUnknown);
225             SkASSERT(combo.fFormat.isValid());
226 
227             if (!caps->isFormatTexturableAndUploadable(combo.fColorType, combo.fFormat)) {
228                 continue;
229             }
230 
231             auto checkColor = [reporter](const GrCaps::TestFormatColorTypeCombination& combo,
232                                          uint32_t readColor) {
233                 // We expect that if there is no alpha in the src color type and we read it to a
234                 // color type with alpha that we will get one for alpha rather than zero. We used to
235                 // require this but the Intel Iris 6100 on Win 10 test bot doesn't put one in the
236                 // alpha channel when reading back from GL_RG16 or GL_RG16F. So now we allow either.
237                 uint32_t components = GrColorTypeComponentFlags(combo.fColorType);
238                 bool allowAlphaOne = !(components & kAlpha_SkColorTypeComponentFlag);
239                 if (allowAlphaOne) {
240                     if (readColor != 0x00000000 && readColor != 0xFF000000) {
241                         ERRORF(reporter,
242                                "Failed on ct %s format %s 0x%08x is not 0x00000000 or 0xFF000000",
243                                GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
244                                readColor);
245                         return false;
246                     }
247                 } else {
248                     if (readColor) {
249                         ERRORF(reporter, "Failed on ct %s format %s 0x%08x != 0x00000000",
250                                GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
251                                readColor);
252                         return false;
253                     }
254                 }
255                 return true;
256             };
257 
258             for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
259                 if (renderable == GrRenderable::kYes &&
260                     !caps->isFormatAsColorTypeRenderable(combo.fColorType, combo.fFormat)) {
261                     continue;
262                 }
263 
264                 for (auto fit : {SkBackingFit::kApprox, SkBackingFit::kExact}) {
265 
266                     // Does directly allocating a texture clear it?
267                     {
268                         auto proxy = proxyProvider->testingOnly_createInstantiatedProxy(
269                                 {kSize, kSize}, combo.fColorType, combo.fFormat, renderable, 1, fit,
270                                 SkBudgeted::kYes, GrProtected::kNo);
271                         if (proxy) {
272                             GrSwizzle swizzle = caps->getReadSwizzle(combo.fFormat,
273                                                                      combo.fColorType);
274                             GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin,
275                                                     swizzle);
276                             auto texCtx = GrSurfaceContext::Make(context, std::move(view),
277                                                                  combo.fColorType,
278                                                                  kPremul_SkAlphaType, nullptr);
279 
280                             readback.erase(kClearColor);
281                             if (texCtx->readPixels(readback.info(), readback.writable_addr(),
282                                                    readback.rowBytes(), {0, 0})) {
283                                 for (int i = 0; i < kSize * kSize; ++i) {
284                                     if (!checkColor(combo, readback.addr32()[i])) {
285                                         break;
286                                     }
287                                 }
288                             }
289                         }
290 
291                         context->priv().testingOnly_purgeAllUnlockedResources();
292                     }
293 
294                     // Try creating the texture as a deferred proxy.
295                     {
296                         std::unique_ptr<GrSurfaceContext> surfCtx;
297                         if (renderable == GrRenderable::kYes) {
298                             surfCtx = GrRenderTargetContext::Make(
299                                     context, combo.fColorType, nullptr, fit,
300                                     {desc.fWidth, desc.fHeight}, 1, GrMipMapped::kNo,
301                                     GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
302                         } else {
303                             surfCtx = GrSurfaceContext::Make(
304                                     context, {desc.fWidth, desc.fHeight}, combo.fFormat,
305                                     GrRenderable::kNo, 1, GrMipMapped::kNo, GrProtected::kNo,
306                                     kTopLeft_GrSurfaceOrigin, combo.fColorType,
307                                     kUnknown_SkAlphaType, nullptr, fit, SkBudgeted::kYes);
308                         }
309                         if (!surfCtx) {
310                             continue;
311                         }
312 
313                         readback.erase(kClearColor);
314                         if (surfCtx->readPixels(readback.info(), readback.writable_addr(),
315                                                 readback.rowBytes(), {0, 0})) {
316                             for (int i = 0; i < kSize * kSize; ++i) {
317                                 if (!checkColor(combo, readback.addr32()[i])) {
318                                     break;
319                                 }
320                             }
321                         }
322                         context->priv().testingOnly_purgeAllUnlockedResources();
323                     }
324                 }
325             }
326         }
327     }
328 }
329 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture,reporter,context_info)330 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture, reporter, context_info) {
331     auto fillPixels = [](SkPixmap* p, const std::function<uint32_t(int x, int y)>& f) {
332         for (int y = 0; y < p->height(); ++y) {
333             for (int x = 0; x < p->width(); ++x) {
334                 *p->writable_addr32(x, y) = f(x, y);
335             }
336         }
337     };
338 
339     auto comparePixels = [](const SkPixmap& p1, const SkPixmap& p2, skiatest::Reporter* reporter) {
340         SkASSERT(p1.info() == p2.info());
341         for (int y = 0; y < p1.height(); ++y) {
342             for (int x = 0; x < p1.width(); ++x) {
343                 REPORTER_ASSERT(reporter, p1.getColor(x, y) == p2.getColor(x, y));
344                 if (p1.getColor(x, y) != p2.getColor(x, y)) {
345                     return;
346                 }
347             }
348         }
349     };
350 
351     static constexpr int kSize = 100;
352     SkImageInfo ii = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
353     SkAutoPixmapStorage srcPixmap;
354     srcPixmap.alloc(ii);
355     fillPixels(&srcPixmap,
356                [](int x, int y) {
357                     return (0xFFU << 24) | (x << 16) | (y << 8) | uint8_t((x * y) & 0xFF);
358                });
359 
360     GrContext* context = context_info.grContext();
361     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
362 
363     // We test both kRW in addition to kRead mostly to ensure that the calls are structured such
364     // that they'd succeed if the texture wasn't kRead. We want to be sure we're failing with
365     // kRead for the right reason.
366     for (auto ioType : {kRead_GrIOType, kRW_GrIOType}) {
367         auto backendTex = context->createBackendTexture(&srcPixmap, 1,
368                                                         GrRenderable::kYes, GrProtected::kNo);
369 
370         auto proxy = proxyProvider->wrapBackendTexture(backendTex, GrColorType::kRGBA_8888,
371                                                        kBorrow_GrWrapOwnership,
372                                                        GrWrapCacheable::kNo, ioType);
373         GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(proxy->backendFormat(),
374                                                                    GrColorType::kRGBA_8888);
375         GrSurfaceProxyView view(proxy, kTopLeft_GrSurfaceOrigin, swizzle);
376         auto surfContext = GrSurfaceContext::Make(context, std::move(view), GrColorType::kRGBA_8888,
377                                                   kPremul_SkAlphaType, nullptr);
378 
379         // Read pixels should work with a read-only texture.
380         {
381             SkAutoPixmapStorage read;
382             read.alloc(srcPixmap.info());
383             auto readResult = surfContext->readPixels(srcPixmap.info(), read.writable_addr(),
384                                                       0, { 0, 0 });
385             REPORTER_ASSERT(reporter, readResult);
386             if (readResult) {
387                 comparePixels(srcPixmap, read, reporter);
388             }
389         }
390 
391         // Write pixels should not work with a read-only texture.
392         SkAutoPixmapStorage write;
393         write.alloc(srcPixmap.info());
394         fillPixels(&write, [&srcPixmap](int x, int y) { return ~*srcPixmap.addr32(); });
395         auto writeResult = surfContext->writePixels(srcPixmap.info(), write.addr(), 0, {0, 0});
396         REPORTER_ASSERT(reporter, writeResult == (ioType == kRW_GrIOType));
397         // Try the low level write.
398         context->flush();
399         auto gpuWriteResult = context->priv().getGpu()->writePixels(
400                 proxy->peekTexture(), 0, 0, kSize, kSize, GrColorType::kRGBA_8888,
401                 GrColorType::kRGBA_8888, write.addr32(),
402                 kSize * GrColorTypeBytesPerPixel(GrColorType::kRGBA_8888));
403         REPORTER_ASSERT(reporter, gpuWriteResult == (ioType == kRW_GrIOType));
404 
405         SkBitmap copySrcBitmap;
406         copySrcBitmap.installPixels(write);
407         copySrcBitmap.setImmutable();
408 
409         GrBitmapTextureMaker maker(context, copySrcBitmap);
410         auto[copySrc, grCT] = maker.view(GrMipMapped::kNo);
411 
412         REPORTER_ASSERT(reporter, copySrc.proxy());
413         auto copyResult = surfContext->testCopy(copySrc.proxy(), copySrc.origin());
414         REPORTER_ASSERT(reporter, copyResult == (ioType == kRW_GrIOType));
415         // Try the low level copy.
416         context->flush();
417         auto gpuCopyResult = context->priv().getGpu()->copySurface(
418                 proxy->peekSurface(), copySrc.proxy()->peekSurface(), SkIRect::MakeWH(kSize, kSize),
419                 {0, 0});
420         REPORTER_ASSERT(reporter, gpuCopyResult == (ioType == kRW_GrIOType));
421 
422         // Mip regen should not work with a read only texture.
423         if (context->priv().caps()->mipMapSupport()) {
424             DeleteBackendTexture(context, backendTex);
425             backendTex = context->createBackendTexture(
426                     kSize, kSize, kRGBA_8888_SkColorType,
427                     SkColors::kTransparent, GrMipMapped::kYes, GrRenderable::kYes,
428                     GrProtected::kNo);
429             proxy = proxyProvider->wrapBackendTexture(backendTex, GrColorType::kRGBA_8888,
430                                                       kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
431                                                       ioType);
432             context->flush();
433             proxy->peekTexture()->texturePriv().markMipMapsDirty();  // avoids assert in GrGpu.
434             auto regenResult =
435                     context->priv().getGpu()->regenerateMipMapLevels(proxy->peekTexture());
436             REPORTER_ASSERT(reporter, regenResult == (ioType == kRW_GrIOType));
437         }
438         DeleteBackendTexture(context, backendTex);
439     }
440 }
441 
442 static const int kSurfSize = 10;
443 
make_wrapped_texture(GrContext * context,GrRenderable renderable)444 static sk_sp<GrTexture> make_wrapped_texture(GrContext* context, GrRenderable renderable) {
445     auto backendTexture = context->createBackendTexture(
446             kSurfSize, kSurfSize, kRGBA_8888_SkColorType, SkColors::kTransparent, GrMipMapped::kNo,
447             renderable, GrProtected::kNo);
448     sk_sp<GrTexture> texture;
449     if (GrRenderable::kYes == renderable) {
450         texture = context->priv().resourceProvider()->wrapRenderableBackendTexture(
451                 backendTexture, 1, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership,
452                 GrWrapCacheable::kNo);
453     } else {
454         texture = context->priv().resourceProvider()->wrapBackendTexture(
455                 backendTexture, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership,
456                 GrWrapCacheable::kNo, kRW_GrIOType);
457     }
458     // Add a release proc that deletes the GrBackendTexture.
459     struct ReleaseContext {
460         GrContext* fContext;
461         GrBackendTexture fBackendTexture;
462     };
463     auto release = [](void* rc) {
464         auto releaseContext = static_cast<ReleaseContext*>(rc);
465         auto context = releaseContext->fContext;
466         context->deleteBackendTexture(releaseContext->fBackendTexture);
467         delete releaseContext;
468     };
469     texture->setRelease(release, new ReleaseContext{context, backendTexture});
470     return texture;
471 }
472 
make_normal_texture(GrContext * context,GrRenderable renderable)473 static sk_sp<GrTexture> make_normal_texture(GrContext* context, GrRenderable renderable) {
474     SkISize desc;
475     desc.fWidth = desc.fHeight = kSurfSize;
476     auto format =
477             context->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888, renderable);
478     return context->priv().resourceProvider()->createTexture(
479             desc, format, renderable, 1, GrMipMapped::kNo, SkBudgeted::kNo, GrProtected::kNo);
480 }
481 
DEF_GPUTEST(TextureIdleProcTest,reporter,options)482 DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
483     // Various ways of making textures.
484     auto makeWrapped = [](GrContext* context) {
485         return make_wrapped_texture(context, GrRenderable::kNo);
486     };
487     auto makeWrappedRenderable = [](GrContext* context) {
488         return make_wrapped_texture(context, GrRenderable::kYes);
489     };
490     auto makeNormal = [](GrContext* context) {
491         return make_normal_texture(context, GrRenderable::kNo);
492     };
493     auto makeRenderable = [](GrContext* context) {
494         return make_normal_texture(context, GrRenderable::kYes);
495     };
496 
497     std::function<sk_sp<GrTexture>(GrContext*)> makers[] = {makeWrapped, makeWrappedRenderable,
498                                                             makeNormal, makeRenderable};
499 
500     // Add a unique key, or not.
501     auto addKey = [](GrTexture* texture) {
502         static uint32_t gN = 0;
503         static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
504         GrUniqueKey key;
505         GrUniqueKey::Builder builder(&key, kDomain, 1);
506         builder[0] = gN++;
507         builder.finish();
508         texture->resourcePriv().setUniqueKey(key);
509     };
510     auto dontAddKey = [](GrTexture* texture) {};
511     std::function<void(GrTexture*)> keyAdders[] = {addKey, dontAddKey};
512 
513     for (const auto& m : makers) {
514         for (const auto& keyAdder : keyAdders) {
515             for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
516                 sk_gpu_test::GrContextFactory factory;
517                 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
518                 GrContext* context = factory.get(contextType);
519                 if (!context) {
520                     continue;
521                 }
522 
523                 // The callback we add simply adds an integer to a set.
524                 std::set<int> idleIDs;
525                 struct Context {
526                     std::set<int>* fIdleIDs;
527                     int fNum;
528                 };
529                 auto proc = [](void* context) {
530                     static_cast<Context*>(context)->fIdleIDs->insert(
531                             static_cast<Context*>(context)->fNum);
532                     delete static_cast<Context*>(context);
533                 };
534 
535                 // Makes a texture, possibly adds a key, and sets the callback.
536                 auto make = [&m, &keyAdder, &proc, &idleIDs](GrContext* context, int num) {
537                     sk_sp<GrTexture> texture = m(context);
538                     texture->addIdleProc(proc, new Context{&idleIDs, num},
539                                          GrTexture::IdleState::kFinished);
540                     keyAdder(texture.get());
541                     return texture;
542                 };
543 
544                 auto texture = make(context, 1);
545                 REPORTER_ASSERT(reporter, idleIDs.find(1) == idleIDs.end());
546                 auto renderable = GrRenderable(SkToBool(texture->asRenderTarget()));
547                 auto backendFormat = texture->backendFormat();
548                 texture.reset();
549                 REPORTER_ASSERT(reporter, idleIDs.find(1) != idleIDs.end());
550 
551                 texture = make(context, 2);
552                 int w = texture->width();
553                 int h = texture->height();
554                 SkImageInfo info =
555                         SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
556                 auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
557                 auto rtc = rt->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
558                 auto singleUseLazyCB = [&texture](GrResourceProvider* rp) {
559                     auto mode = GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
560                     if (texture->getUniqueKey().isValid()) {
561                         mode = GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
562                     }
563                     return GrSurfaceProxy::LazyCallbackResult{std::move(texture), true, mode};
564                 };
565                 SkISize desc;
566                 desc.fWidth = w;
567                 desc.fHeight = h;
568                 SkBudgeted budgeted;
569                 if (texture->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted) {
570                     budgeted = SkBudgeted::kYes;
571                 } else {
572                     budgeted = SkBudgeted::kNo;
573                 }
574                 GrSwizzle readSwizzle = context->priv().caps()->getReadSwizzle(
575                         backendFormat, GrColorType::kRGBA_8888);
576                 auto proxy = context->priv().proxyProvider()->createLazyProxy(
577                         singleUseLazyCB, backendFormat, desc, readSwizzle, renderable, 1,
578                         GrMipMapped::kNo, GrMipMapsStatus::kNotAllocated,
579                         GrInternalSurfaceFlags ::kNone, SkBackingFit::kExact, budgeted,
580                         GrProtected::kNo, GrSurfaceProxy::UseAllocator::kYes);
581                 GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin, readSwizzle);
582                 rtc->drawTexture(GrNoClip(), view, kPremul_SkAlphaType,
583                                  GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
584                                  SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h),
585                                  GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
586                                  SkMatrix::I(), nullptr);
587                 // We still have the proxy, which should remain instantiated, thereby keeping the
588                 // texture not purgeable.
589                 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
590                 context->flush();
591                 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
592                 context->priv().getGpu()->testingOnly_flushGpuAndSync();
593                 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
594 
595                 // This time we move the proxy into the draw.
596                 rtc->drawTexture(GrNoClip(), std::move(view), kPremul_SkAlphaType,
597                                  GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
598                                  SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h),
599                                  GrAA::kNo, GrQuadAAFlags::kNone,
600                                  SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
601                 REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
602                 context->flush();
603                 context->priv().getGpu()->testingOnly_flushGpuAndSync();
604                 // Now that the draw is fully consumed by the GPU, the texture should be idle.
605                 REPORTER_ASSERT(reporter, idleIDs.find(2) != idleIDs.end());
606 
607                 // Make sure we make the call during various shutdown scenarios where the texture
608                 // might persist after context is destroyed, abandoned, etc. We test three
609                 // variations of each scenario. One where the texture is just created. Another,
610                 // where the texture has been used in a draw and then the context is flushed. And
611                 // one where the the texture was drawn but the context is not flushed.
612                 // In each scenario we test holding a ref beyond the context shutdown and not.
613 
614                 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
615                 // and http://skbug.com/8275
616                 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
617                 if (api == GrBackendApi::kVulkan) {
618                     continue;
619                 }
620                 int id = 3;
621                 enum class DrawType {
622                     kNoDraw,
623                     kDraw,
624                     kDrawAndFlush,
625                 };
626                 for (auto drawType :
627                      {DrawType::kNoDraw, DrawType::kDraw, DrawType::kDrawAndFlush}) {
628                     for (bool unrefFirst : {false, true}) {
629                         auto possiblyDrawAndFlush = [&context, &texture, drawType, unrefFirst, w,
630                                                      h] {
631                             if (drawType == DrawType::kNoDraw) {
632                                 return;
633                             }
634                             SkImageInfo info = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
635                                                                  kPremul_SkAlphaType);
636                             auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
637                                                                   nullptr);
638                             auto rtc = rt->getCanvas()
639                                             ->internal_private_accessTopLayerRenderTargetContext();
640                             auto proxy = context->priv().proxyProvider()->testingOnly_createWrapped(
641                                     texture, GrColorType::kRGBA_8888);
642                             GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(
643                                     proxy->backendFormat(), GrColorType::kRGBA_8888);
644                             GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin,
645                                                     swizzle);
646                             rtc->drawTexture(
647                                     GrNoClip(), std::move(view), kPremul_SkAlphaType,
648                                     GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
649                                     SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h),
650                                     GrAA::kNo, GrQuadAAFlags::kNone,
651                                     SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
652                             if (drawType == DrawType::kDrawAndFlush) {
653                                 context->flush();
654                             }
655                             if (unrefFirst) {
656                                 texture.reset();
657                             }
658                         };
659                         texture = make(context, id);
660                         possiblyDrawAndFlush();
661                         context->abandonContext();
662                         texture.reset();
663                         REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
664                         factory.destroyContexts();
665                         context = factory.get(contextType);
666                         ++id;
667 
668                         // Similar to previous, but reset the texture after the context was
669                         // abandoned and then destroyed.
670                         texture = make(context, id);
671                         possiblyDrawAndFlush();
672                         context->abandonContext();
673                         factory.destroyContexts();
674                         texture.reset();
675                         REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
676                         context = factory.get(contextType);
677                         id++;
678 
679                         texture = make(context, id);
680                         possiblyDrawAndFlush();
681                         factory.destroyContexts();
682                         texture.reset();
683                         REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
684                         context = factory.get(contextType);
685                         id++;
686 
687                         texture = make(context, id);
688                         possiblyDrawAndFlush();
689                         factory.releaseResourcesAndAbandonContexts();
690                         texture.reset();
691                         REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
692                         context = factory.get(contextType);
693                         id++;
694                     }
695                 }
696             }
697         }
698     }
699 }
700 
701 // Tests an idle proc that unrefs another resource down to zero.
DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcCacheManipulationTest,reporter,contextInfo)702 DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcCacheManipulationTest, reporter, contextInfo) {
703     GrContext* context = contextInfo.grContext();
704 
705     // idle proc that releases another texture.
706     auto idleProc = [](void* texture) { reinterpret_cast<GrTexture*>(texture)->unref(); };
707 
708     for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
709         for (const auto& otherMaker : {make_wrapped_texture, make_normal_texture}) {
710             for (auto idleState :
711                  {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
712                 auto idleTexture = idleMaker(context, GrRenderable::kNo);
713                 auto otherTexture = otherMaker(context, GrRenderable::kNo);
714                 otherTexture->ref();
715                 idleTexture->addIdleProc(idleProc, otherTexture.get(), idleState);
716                 otherTexture.reset();
717                 idleTexture.reset();
718             }
719         }
720     }
721 }
722 
723 // Similar to above but more complicated. This flushes the context from the idle proc.
724 // crbug.com/933526.
DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcFlushTest,reporter,contextInfo)725 DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcFlushTest, reporter, contextInfo) {
726     GrContext* context = contextInfo.grContext();
727 
728     // idle proc that flushes the context.
729     auto idleProc = [](void* context) { reinterpret_cast<GrContext*>(context)->flush(); };
730 
731     for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
732         for (auto idleState : {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
733             auto idleTexture = idleMaker(context, GrRenderable::kNo);
734             idleTexture->addIdleProc(idleProc, context, idleState);
735             auto info = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
736             auto surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 1, nullptr);
737             // We'll draw two images to the canvas. One is a normal texture-backed image. The other
738             // is a wrapped-texture backed image.
739             surf->getCanvas()->clear(SK_ColorWHITE);
740             auto img1 = surf->makeImageSnapshot();
741 
742             GrBackendTexture backendTexture;
743 
744             if (!CreateBackendTexture(context, &backendTexture, info, SkColors::kBlack,
745                                       GrMipMapped::kNo, GrRenderable::kNo)) {
746                 REPORTER_ASSERT(reporter, false);
747                 continue;
748             }
749 
750             auto img2 = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
751                                                  info.colorType(), info.alphaType(), nullptr);
752             surf->getCanvas()->drawImage(std::move(img1), 0, 0);
753             surf->getCanvas()->drawImage(std::move(img2), 1, 1);
754             idleTexture.reset();
755 
756             DeleteBackendTexture(context, backendTexture);
757         }
758     }
759 }
760 
DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcRerefTest,reporter,contextInfo)761 DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcRerefTest, reporter, contextInfo) {
762     GrContext* context = contextInfo.grContext();
763     // idle proc that refs the texture
764     auto idleProc = [](void* texture) { reinterpret_cast<GrTexture*>(texture)->ref(); };
765     // release proc to check whether the texture was released or not.
766     auto releaseProc = [](void* isReleased) { *reinterpret_cast<bool*>(isReleased) = true; };
767     for (auto idleState : {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
768         bool isReleased = false;
769         auto idleTexture = make_normal_texture(context, GrRenderable::kNo);
770         // This test assumes the texture won't be cached (or else the release proc doesn't get
771         // called).
772         idleTexture->resourcePriv().removeScratchKey();
773         context->flush();
774         idleTexture->addIdleProc(idleProc, idleTexture.get(), idleState);
775         idleTexture->setRelease(releaseProc, &isReleased);
776         auto* raw = idleTexture.get();
777         idleTexture.reset();
778         REPORTER_ASSERT(reporter, !isReleased);
779         raw->unref();
780         REPORTER_ASSERT(reporter, isReleased);
781     }
782 }
783 
DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleStateTest,reporter,contextInfo)784 DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleStateTest, reporter, contextInfo) {
785     GrContext* context = contextInfo.grContext();
786     for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
787         auto idleTexture = idleMaker(context, GrRenderable::kNo);
788 
789         uint32_t flags = 0;
790         static constexpr uint32_t kFlushFlag = 0x1;
791         static constexpr uint32_t kFinishFlag = 0x2;
792         auto flushProc = [](void* flags) { *static_cast<uint32_t*>(flags) |= kFlushFlag; };
793         auto finishProc = [](void* flags) { *static_cast<uint32_t*>(flags) |= kFinishFlag; };
794         idleTexture->addIdleProc(flushProc, &flags, GrTexture::IdleState::kFlushed);
795         idleTexture->addIdleProc(finishProc, &flags, GrTexture::IdleState::kFinished);
796 
797         // Insert a copy from idleTexture to another texture so that we have some queued IO on
798         // idleTexture.
799         SkImageInfo info = SkImageInfo::Make(kSurfSize, kSurfSize, kRGBA_8888_SkColorType,
800                                              kPremul_SkAlphaType);
801         auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
802         auto rtc = rt->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
803         auto proxy = context->priv().proxyProvider()->testingOnly_createWrapped(
804                 std::move(idleTexture), GrColorType::kRGBA_8888);
805         context->flush();
806         SkAssertResult(rtc->testCopy(proxy.get(), rtc->origin()));
807         proxy.reset();
808         REPORTER_ASSERT(reporter, flags == 0);
809 
810         // After a flush we expect idleTexture to have reached the kFlushed state on all backends.
811         // On "managed" backends we expect it to reach kFinished as well. On Vulkan, the only
812         // current "unmanaged" backend, we *may* need a sync to reach kFinished.
813         context->flush();
814         if (contextInfo.backend() == kVulkan_GrBackend) {
815             REPORTER_ASSERT(reporter, flags & kFlushFlag);
816         } else {
817             REPORTER_ASSERT(reporter, flags == (kFlushFlag | kFinishFlag));
818         }
819         context->priv().getGpu()->testingOnly_flushGpuAndSync();
820         REPORTER_ASSERT(reporter, flags == (kFlushFlag | kFinishFlag));
821     }
822 }
823