xref: /aosp_15_r20/external/skia/tests/GrTextureMipMapInvalidationTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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