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/SkAlphaType.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkColorType.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/core/SkSamplingOptions.h"
19 #include "include/core/SkSurface.h"
20 #include "include/core/SkTypes.h"
21 #include "include/gpu/GpuTypes.h"
22 #include "include/gpu/ganesh/GrBackendSurface.h"
23 #include "include/gpu/ganesh/GrDirectContext.h"
24 #include "include/gpu/ganesh/GrTypes.h"
25 #include "include/gpu/ganesh/SkImageGanesh.h"
26 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
27 #include "src/gpu/ganesh/GrCaps.h"
28 #include "src/gpu/ganesh/GrDirectContextPriv.h"
29 #include "src/gpu/ganesh/GrTexture.h"
30 #include "src/gpu/ganesh/GrTextureProxy.h"
31 #include "tests/CtsEnforcement.h"
32 #include "tests/Test.h"
33 #include "tools/gpu/ProxyUtils.h"
34
35 #include <cstdint>
36 #include <functional>
37 #include <initializer_list>
38 #include <utility>
39
40 struct GrContextOptions;
41
42 // Tests that MIP maps are created and invalidated as expected when drawing to and from GrTextures.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrTextureMipMapInvalidationTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)43 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrTextureMipMapInvalidationTest,
44 reporter,
45 ctxInfo,
46 CtsEnforcement::kApiLevel_T) {
47 auto context = ctxInfo.directContext();
48 if (!context->priv().caps()->mipmapSupport()) {
49 return;
50 }
51
52 auto isMipped = [reporter](SkSurface* surf) {
53 sk_sp<SkImage> image = surf->makeImageSnapshot();
54 GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(),
55 surf->recordingContext());
56 bool proxyIsMipmapped = proxy->mipmapped() == skgpu::Mipmapped::kYes;
57 REPORTER_ASSERT(reporter, proxyIsMipmapped == image->hasMipmaps());
58 return image->hasMipmaps();
59 };
60
61 auto mipsAreDirty = [](SkSurface* surf) {
62 sk_sp<SkImage> image = surf->makeImageSnapshot();
63 GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(),
64 surf->recordingContext());
65 return proxy->peekTexture()->mipmapsAreDirty();
66 };
67
68 auto info = SkImageInfo::MakeN32Premul(256, 256);
69 for (auto allocateMips : {false, true}) {
70 auto surf1 = SkSurfaces::RenderTarget(context,
71 skgpu::Budgeted::kYes,
72 info,
73 0,
74 kBottomLeft_GrSurfaceOrigin,
75 nullptr,
76 allocateMips);
77 auto surf2 = SkSurfaces::RenderTarget(context, skgpu::Budgeted::kYes, info);
78 // Draw something just in case we ever had a solid color optimization
79 surf1->getCanvas()->drawCircle(128, 128, 50, SkPaint());
80 context->flushAndSubmit(surf1.get(), GrSyncCpu::kNo);
81
82 // No mipmaps initially
83 REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
84
85 // Painting with downscale and medium filter quality should result in mipmap creation
86 // Flush the context rather than the canvas as flushing the canvas triggers MIP level
87 // generation.
88 SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kLinear);
89
90 surf2->getCanvas()->scale(0.2f, 0.2f);
91 surf2->getCanvas()->drawImage(surf1->makeImageSnapshot(), 0, 0, sampling);
92 context->flushAndSubmit();
93 REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
94 REPORTER_ASSERT(reporter, !allocateMips || !mipsAreDirty(surf1.get()));
95
96 // Changing the contents of the surface should invalidate the mipmap, but not de-allocate
97 surf1->getCanvas()->drawCircle(128, 128, 100, SkPaint());
98 context->flushAndSubmit();
99 REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips);
100 REPORTER_ASSERT(reporter, mipsAreDirty(surf1.get()));
101 }
102 }
103
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ReimportImageTextureWithMipLevels,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)104 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ReimportImageTextureWithMipLevels,
105 reporter,
106 ctxInfo,
107 CtsEnforcement::kApiLevel_T) {
108 auto dContext = ctxInfo.directContext();
109 if (!dContext->priv().caps()->mipmapSupport()) {
110 return;
111 }
112 static constexpr auto kCreateWithMipMaps = true;
113 auto surf = SkSurfaces::RenderTarget(
114 dContext,
115 skgpu::Budgeted::kYes,
116 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
117 1,
118 kTopLeft_GrSurfaceOrigin,
119 nullptr,
120 kCreateWithMipMaps);
121 if (!surf) {
122 return;
123 }
124 surf->getCanvas()->drawColor(SK_ColorDKGRAY);
125 auto img = surf->makeImageSnapshot();
126 if (!img) {
127 return;
128 }
129 surf.reset();
130 GrBackendTexture btex;
131 SkImages::BackendTextureReleaseProc texRelease;
132 if (!SkImages::MakeBackendTextureFromImage(dContext, std::move(img), &btex, &texRelease)) {
133 // Not all backends support stealing textures yet.
134 // ERRORF(reporter, "Could not turn image into texture");
135 return;
136 }
137 REPORTER_ASSERT(reporter, btex.hasMipmaps());
138 // Reimport the texture as an image and perform a downsampling draw with medium quality which
139 // should use the upper MIP levels.
140 img = SkImages::BorrowTextureFrom(dContext,
141 btex,
142 kTopLeft_GrSurfaceOrigin,
143 kRGBA_8888_SkColorType,
144 kPremul_SkAlphaType,
145 nullptr);
146 const auto singlePixelInfo =
147 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
148 surf = SkSurfaces::RenderTarget(
149 dContext, skgpu::Budgeted::kYes, singlePixelInfo, 1, kTopLeft_GrSurfaceOrigin, nullptr);
150
151 surf->getCanvas()->drawImageRect(img, SkRect::MakeWH(1, 1),
152 SkSamplingOptions(SkFilterMode::kLinear,
153 SkMipmapMode::kLinear));
154 uint32_t pixel;
155 surf->readPixels(singlePixelInfo, &pixel, sizeof(uint32_t), 0, 0);
156 REPORTER_ASSERT(reporter, pixel == SkPreMultiplyColor(SK_ColorDKGRAY));
157 img.reset();
158 texRelease(btex);
159 }
160