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