• 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/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