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