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