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