1 /*
2 * Copyright 2016 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 "include/core/SkCanvas.h"
9 #include "include/core/SkSurface.h"
10 #include "include/gpu/GrDirectContext.h"
11 #include "src/gpu/GrDirectContextPriv.h"
12 #include "src/gpu/GrTexture.h"
13 #include "src/image/SkImage_Base.h"
14 #include "src/image/SkImage_GpuBase.h"
15 #include "tests/Test.h"
16 #include "tools/gpu/ProxyUtils.h"
17
18 // Tests that MIP maps are created and invalidated as expected when drawing to and from GrTextures.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrTextureMipMapInvalidationTest,reporter,ctxInfo)19 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrTextureMipMapInvalidationTest, reporter, ctxInfo) {
20 auto context = ctxInfo.directContext();
21 if (!context->priv().caps()->mipmapSupport()) {
22 return;
23 }
24
25 auto isMipped = [reporter](SkSurface* surf) {
26 sk_sp<SkImage> image = surf->makeImageSnapshot();
27 GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(),
28 surf->recordingContext());
29 bool proxyIsMipmapped = proxy->mipmapped() == GrMipmapped::kYes;
30 REPORTER_ASSERT(reporter, proxyIsMipmapped == image->hasMipmaps());
31 return image->hasMipmaps();
32 };
33
34 auto mipsAreDirty = [](SkSurface* surf) {
35 sk_sp<SkImage> image = surf->makeImageSnapshot();
36 GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(),
37 surf->recordingContext());
38 return proxy->peekTexture()->mipmapsAreDirty();
39 };
40
41 auto info = SkImageInfo::MakeN32Premul(256, 256);
42 for (auto allocateMips : {false, true}) {
43 auto surf1 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
44 kBottomLeft_GrSurfaceOrigin, nullptr,
45 allocateMips);
46 auto surf2 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info);
47 // Draw something just in case we ever had a solid color optimization
48 surf1->getCanvas()->drawCircle(128, 128, 50, SkPaint());
49 surf1->flushAndSubmit();
50
51 // No mipmaps initially
52 REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
53
54 // Painting with downscale and medium filter quality should result in mipmap creation
55 // Flush the context rather than the canvas as flushing the canvas triggers MIP level
56 // generation.
57 SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kLinear);
58
59 surf2->getCanvas()->scale(0.2f, 0.2f);
60 surf2->getCanvas()->drawImage(surf1->makeImageSnapshot(), 0, 0, sampling);
61 context->flushAndSubmit();
62 REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
63 REPORTER_ASSERT(reporter, !allocateMips || !mipsAreDirty(surf1.get()));
64
65 // Changing the contents of the surface should invalidate the mipmap, but not de-allocate
66 surf1->getCanvas()->drawCircle(128, 128, 100, SkPaint());
67 context->flushAndSubmit();
68 REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
69 REPORTER_ASSERT(reporter, mipsAreDirty(surf1.get()));
70 }
71 }
72
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReimportImageTextureWithMipLevels,reporter,ctxInfo)73 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReimportImageTextureWithMipLevels, reporter, ctxInfo) {
74 auto dContext = ctxInfo.directContext();
75 if (!dContext->priv().caps()->mipmapSupport()) {
76 return;
77 }
78 static constexpr auto kCreateWithMipMaps = true;
79 auto surf = SkSurface::MakeRenderTarget(
80 dContext, SkBudgeted::kYes,
81 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType), 1,
82 kTopLeft_GrSurfaceOrigin, nullptr, kCreateWithMipMaps);
83 if (!surf) {
84 return;
85 }
86 surf->getCanvas()->drawColor(SK_ColorDKGRAY);
87 auto img = surf->makeImageSnapshot();
88 if (!img) {
89 return;
90 }
91 surf.reset();
92 GrBackendTexture btex;
93 SkImage::BackendTextureReleaseProc texRelease;
94 if (!SkImage::MakeBackendTextureFromSkImage(dContext, std::move(img), &btex, &texRelease)) {
95 // Not all backends support stealing textures yet.
96 // ERRORF(reporter, "Could not turn image into texture");
97 return;
98 }
99 REPORTER_ASSERT(reporter, btex.hasMipmaps());
100 // Reimport the texture as an image and perform a downsampling draw with medium quality which
101 // should use the upper MIP levels.
102 img = SkImage::MakeFromTexture(dContext, btex, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
103 kPremul_SkAlphaType, nullptr);
104 const auto singlePixelInfo =
105 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
106 surf = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kYes, singlePixelInfo, 1,
107 kTopLeft_GrSurfaceOrigin, nullptr);
108
109 surf->getCanvas()->drawImageRect(img, SkRect::MakeWH(1, 1),
110 SkSamplingOptions(SkFilterMode::kLinear,
111 SkMipmapMode::kLinear));
112 uint32_t pixel;
113 surf->readPixels(singlePixelInfo, &pixel, sizeof(uint32_t), 0, 0);
114 REPORTER_ASSERT(reporter, pixel == SkPreMultiplyColor(SK_ColorDKGRAY));
115 img.reset();
116 texRelease(btex);
117 }
118