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