• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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