xref: /aosp_15_r20/external/skia/tests/WrappedSurfaceCopyOnWriteTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2021 Google LLC
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/SkRect.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkSamplingOptions.h"
18 #include "include/core/SkSurface.h"
19 #include "include/core/SkTypes.h"
20 #include "include/gpu/GpuTypes.h"
21 #include "include/gpu/ganesh/GrDirectContext.h"
22 #include "include/gpu/ganesh/GrTypes.h"
23 #include "include/private/SkColorData.h"
24 #include "include/private/chromium/GrDeferredDisplayListRecorder.h"
25 #include "include/private/chromium/GrSurfaceCharacterization.h"
26 #include "include/private/gpu/ganesh/GrTypesPriv.h"
27 #include "src/core/SkAutoPixmapStorage.h"
28 #include "src/gpu/SkBackingFit.h"
29 #include "src/gpu/ganesh/GrCanvas.h"
30 #include "src/gpu/ganesh/GrDirectContextPriv.h"
31 #include "src/gpu/ganesh/GrDrawingManager.h"
32 #include "src/gpu/ganesh/GrImageInfo.h"
33 #include "src/gpu/ganesh/GrRenderTargetProxy.h"
34 #include "src/gpu/ganesh/GrRenderTask.h"
35 #include "src/gpu/ganesh/GrSamplerState.h"
36 #include "src/gpu/ganesh/GrSurfaceProxy.h"
37 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
38 #include "src/gpu/ganesh/GrTextureProxy.h"
39 #include "src/gpu/ganesh/SurfaceContext.h"
40 #include "src/gpu/ganesh/SurfaceFillContext.h"
41 #include "tests/CtsEnforcement.h"
42 #include "tests/Test.h"
43 #include "tests/TestUtils.h"
44 #include "tools/gpu/BackendSurfaceFactory.h"
45 #include "tools/gpu/ProxyUtils.h"
46 
47 #include <functional>
48 #include <memory>
49 
50 struct GrContextOptions;
51 
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(WrappedSurfaceCopyOnWrite,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)52 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(WrappedSurfaceCopyOnWrite,
53                                  reporter,
54                                  ctxInfo,
55                                  CtsEnforcement::kApiLevel_T) {
56     using namespace skgpu;
57 
58     GrDirectContext* dContext = ctxInfo.directContext();
59 
60     Protected isProtected = Protected(dContext->priv().caps()->supportsProtectedContent());
61 
62     auto makeDirectBackendSurface = [&]() {
63         auto info = SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
64         return sk_gpu_test::MakeBackendTextureSurface(dContext,
65                                                       info,
66                                                       kTopLeft_GrSurfaceOrigin,
67                                                       /* sampleCnt= */ 1,
68                                                       Mipmapped::kNo,
69                                                       isProtected);
70     };
71 
72     auto imageProxyID = [&](const sk_sp<SkImage>& img) {
73         return sk_gpu_test::GetTextureImageProxy(img.get(), dContext)->uniqueID();
74     };
75 
76     auto surfaceProxyID = [&](const sk_sp<SkSurface>& surf) {
77         GrRenderTargetProxy* rtp = skgpu::ganesh::TopDeviceTargetProxy(surf->getCanvas());
78         return rtp->uniqueID();
79     };
80 
81     sk_sp<SkSurface> surf = makeDirectBackendSurface();
82     surf->getCanvas()->clear(SkColor4f{1, 0, 0, 1});
83     sk_sp<SkImage> img = surf->makeImageSnapshot();
84     // Initially they share
85     REPORTER_ASSERT(reporter, surfaceProxyID(surf) == imageProxyID(img));
86     // Using the image on the direct context shouldn't affect sharing.
87     sk_sp<SkSurface> surf2 = makeDirectBackendSurface();
88     surf2->getCanvas()->drawImage(img, 0, 0);
89     REPORTER_ASSERT(reporter, surfaceProxyID(surf) == imageProxyID(img));
90     // Modifying the original surface should trigger using the copy proxy.
91     surf->getCanvas()->clear({0, 0, 1, 1});
92     REPORTER_ASSERT(reporter, surfaceProxyID(surf) != imageProxyID(img));
93     // Image caching on surface should mean another snapshot gives us the same image.
94     GrSurfaceProxy::UniqueID imageID = imageProxyID(img);
95     img = surf->makeImageSnapshot();
96     REPORTER_ASSERT(reporter, imageProxyID(img) != imageID);
97 
98     GrSurfaceCharacterization characterization;
99     REPORTER_ASSERT(reporter, surf->characterize(&characterization));
100     GrDeferredDisplayListRecorder recorder(characterization);
101 
102     // Using an image from a direct context on a recording context should trigger using the copy.
103     surf = makeDirectBackendSurface();
104     img = surf->makeImageSnapshot();
105     REPORTER_ASSERT(reporter, surfaceProxyID(surf) == imageProxyID(img));
106     recorder.getCanvas()->drawImage(img, 0, 0);
107     REPORTER_ASSERT(reporter, surfaceProxyID(surf) != imageProxyID(img));
108 
109     // Same as above but if the surface goes out of scope first we keep using the original
110     surf = makeDirectBackendSurface();
111     img = surf->makeImageSnapshot();
112     GrSurfaceProxy::UniqueID surfID = surfaceProxyID(surf);
113     REPORTER_ASSERT(reporter, surfaceProxyID(surf) == imageProxyID(img));
114     surf.reset();
115     recorder.getCanvas()->drawImage(img, 0, 0);
116     REPORTER_ASSERT(reporter, surfID == imageProxyID(img));
117 }
118 
119 // Make sure GrCopyRenderTasks's skip actually skips the copy.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkipCopyTaskTest,reporter,ctxInfo,CtsEnforcement::kNever)120 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkipCopyTaskTest,
121                                        reporter,
122                                        ctxInfo,
123                                        CtsEnforcement::kNever) {
124     GrDirectContext* dContext = ctxInfo.directContext();
125 
126     GrImageInfo info(GrColorType::kRGBA_8888,
127                      kPremul_SkAlphaType,
128                      /*color space*/ nullptr,
129                      10, 10);
130 
131     auto dstSC = CreateSurfaceContext(dContext,
132                                       info,
133                                       SkBackingFit::kExact,
134                                       kBottomLeft_GrSurfaceOrigin,
135                                       GrRenderable::kYes);
136     dstSC->asFillContext()->clear(SkPMColor4f{1, 0, 0, 1});
137 
138     auto srcSC = CreateSurfaceContext(dContext,
139                                       info,
140                                       SkBackingFit::kExact,
141                                       kBottomLeft_GrSurfaceOrigin,
142                                       GrRenderable::kYes);
143     srcSC->asFillContext()->clear(SkPMColor4f{0, 0, 1, 1});
144 
145     sk_sp<GrRenderTask> task =
146             dContext->priv().drawingManager()->newCopyRenderTask(dstSC->asSurfaceProxyRef(),
147                                                                  SkIRect::MakeWH(10, 10),
148                                                                  srcSC->asSurfaceProxyRef(),
149                                                                  SkIRect::MakeWH(10, 10),
150                                                                  GrSamplerState::Filter::kNearest,
151                                                                  kTopLeft_GrSurfaceOrigin);
152 
153     if (!task) {
154         ERRORF(reporter, "Couldn't make a copy task.");
155         return;
156     }
157 
158     task->makeSkippable();
159 
160     SkAutoPixmapStorage pixels;
161     pixels.alloc(SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
162     dstSC->readPixels(dContext, pixels, {0, 0});
163     float kTol[4] = {};
164     std::function<ComparePixmapsErrorReporter> errorReporter(
165             [&](int x, int y, const float diffs[4]) {
166                 ERRORF(reporter, "Expected {1, 0, 0, 1}. diff {%f, %f, %f, %f}",
167                        diffs[0], diffs[1], diffs[2], diffs[3]);
168             });
169     CheckSolidPixels(SkColor4f{1, 0, 0, 1}, pixels, kTol, errorReporter);
170 }
171 
172 #if defined(SK_GANESH)
173 
174 // Make sure OpsTask are skippable
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkipOpsTaskTest,reporter,ctxInfo,CtsEnforcement::kNever)175 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkipOpsTaskTest, reporter, ctxInfo, CtsEnforcement::kNever) {
176     GrDirectContext* dContext = ctxInfo.directContext();
177 
178     GrImageInfo ii(GrColorType::kRGBA_8888, kPremul_SkAlphaType, /*color space*/ nullptr, 10, 10);
179 
180     auto dst = dContext->priv().makeSFC(ii, /*label=*/{}, SkBackingFit::kExact);
181     dst->clear(SkPMColor4f{1, 0, 0, 1});
182     dContext->flush();
183 
184     dst->clear(SkPMColor4f{0, 0, 1, 1});
185     sk_sp<GrRenderTask> task = dst->refRenderTask();
186 
187     // GrDrawingManager maintains an "active ops task" and doesn't like having it closed behind
188     // its back. temp exists just to replace dst's ops task as the active one.
189     auto temp = dContext->priv().makeSFC(ii, /*label=*/{}, SkBackingFit::kExact);
190     temp->clear(SkPMColor4f{0, 0, 0, 0});
191 
192     GrSurfaceProxyView readView = dst->readSurfaceView();
193     task->makeSkippable();
194 
195     SkAutoPixmapStorage pixels;
196     pixels.alloc(SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
197     dst->readPixels(dContext, pixels, {0, 0});
198     float kTol[4] = {};
199     std::function<ComparePixmapsErrorReporter> errorReporter(
200             [&](int x, int y, const float diffs[4]) {
201                 ERRORF(reporter, "Expected {1, 0, 0, 1}. diff {%f, %f, %f, %f}",
202                        diffs[0], diffs[1], diffs[2], diffs[3]);
203             });
204     CheckSolidPixels(SkColor4f{1, 0, 0, 1}, pixels, kTol, errorReporter);
205 }
206 #endif // defined(SK_GANESH)
207