1 /*
2 * Copyright 2023 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 "tests/Test.h"
9
10 #if defined(SK_GANESH)
11
12 #include "include/core/SkBitmap.h"
13 #include "include/core/SkCanvas.h"
14 #include "include/core/SkColorSpace.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkSurface.h"
17 #include "include/gpu/ganesh/GrBackendSurface.h"
18 #include "include/gpu/ganesh/GrDirectContext.h"
19 #include "include/gpu/ganesh/SkImageGanesh.h"
20 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
21 #include "tests/CtsEnforcement.h"
22 #include "tools/gpu/ProtectedUtils.h"
23
24 static const int kSize = 8;
25
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_SmokeTest,reporter,ctxInfo,CtsEnforcement::kNever)26 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_SmokeTest, reporter, ctxInfo, CtsEnforcement::kNever) {
27 auto dContext = ctxInfo.directContext();
28
29 if (!dContext->supportsProtectedContent()) {
30 // Protected content not supported
31 return;
32 }
33
34 for (bool textureable : { true, false }) {
35 for (bool isProtected : { true, false }) {
36 if (!isProtected && GrBackendApi::kVulkan == dContext->backend()) {
37 continue;
38 }
39
40 sk_sp<SkSurface> surface = ProtectedUtils::CreateProtectedSkSurface(dContext,
41 { kSize, kSize },
42 textureable,
43 isProtected);
44 if (!surface) {
45 continue;
46 }
47
48 sk_sp<SkImage> image = surface->makeImageSnapshot();
49 if (!image) {
50 ERRORF(reporter, "Could not makeImageSnapshot from a %s surface.",
51 isProtected ? "protected" : "unprotected");
52 continue;
53 }
54
55 dContext->submit(GrSyncCpu::kYes);
56
57 REPORTER_ASSERT(reporter, image->isProtected() == isProtected);
58 ProtectedUtils::CheckImageBEProtection(image.get(), isProtected);
59 }
60 }
61
62 for (bool isProtected : { true, false }) {
63 if (!isProtected && GrBackendApi::kVulkan == dContext->backend()) {
64 continue;
65 }
66
67 sk_sp<SkImage> image = ProtectedUtils::CreateProtectedSkImage(dContext,
68 { kSize, kSize },
69 SkColors::kBlue,
70 isProtected);
71 if (!image) {
72 continue;
73 }
74
75 dContext->submit(GrSyncCpu::kYes);
76
77 REPORTER_ASSERT(reporter, image->isProtected() == isProtected);
78 ProtectedUtils::CheckImageBEProtection(image.get(), isProtected);
79 }
80
81 for (bool renderable : { true, false }) {
82 for (bool isProtected : { true, false }) {
83 GrBackendTexture beTex = dContext->createBackendTexture(16,
84 16,
85 kRGBA_8888_SkColorType,
86 SkColors::kTransparent,
87 skgpu::Mipmapped::kNo,
88 GrRenderable(renderable),
89 GrProtected(isProtected));
90
91 REPORTER_ASSERT(reporter, beTex.isValid());
92 REPORTER_ASSERT(reporter, beTex.isProtected() == isProtected);
93
94 dContext->flushAndSubmit(GrSyncCpu::kYes);
95
96 {
97 sk_sp<SkImage> img = SkImages::BorrowTextureFrom(dContext, beTex,
98 kTopLeft_GrSurfaceOrigin,
99 kRGBA_8888_SkColorType,
100 kPremul_SkAlphaType,
101 /* colorSpace= */ nullptr);
102
103 REPORTER_ASSERT(reporter, img->isProtected() == isProtected);
104 }
105
106 if (beTex.isValid()) {
107 dContext->deleteBackendTexture(beTex);
108 }
109 }
110 }
111 }
112
113 // Verify that readPixels fails on protected surfaces
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_readPixelsFromSurfaces,reporter,ctxInfo,CtsEnforcement::kNever)114 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_readPixelsFromSurfaces, reporter, ctxInfo,
115 CtsEnforcement::kNever) {
116 auto dContext = ctxInfo.directContext();
117
118 if (!dContext->supportsProtectedContent()) {
119 // Protected content not supported
120 return;
121 }
122
123 sk_sp<SkSurface> surface = ProtectedUtils::CreateProtectedSkSurface(dContext,
124 { kSize, kSize },
125 /* textureable= */ true,
126 /* isProtected= */ true);
127 if (!surface) {
128 return;
129 }
130
131 SkBitmap readback;
132 readback.allocPixels(surface->imageInfo());
133 REPORTER_ASSERT(reporter, !surface->readPixels(readback, 0, 0));
134 }
135
136 // Graphite does not perform Copy-on-Write which is why there is no DEF_GRAPHITE_TEST correlate
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_CopyOnWrite,reporter,ctxInfo,CtsEnforcement::kNever)137 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_CopyOnWrite, reporter, ctxInfo, CtsEnforcement::kNever) {
138 auto dContext = ctxInfo.directContext();
139
140 if (!dContext->supportsProtectedContent()) {
141 // Protected content not supported
142 return;
143 }
144
145 SkImageInfo ii = SkImageInfo::Make({ kSize, kSize },
146 kRGBA_8888_SkColorType,
147 kPremul_SkAlphaType);
148
149 // We can't use ProtectedUtils::CreateProtectedSkSurface here bc that will wrap a backend
150 // texture which blocks the copy-on-write-behavior
151 sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(dContext,
152 skgpu::Budgeted::kNo,
153 ii,
154 /* sampleCount= */ 1,
155 kBottomLeft_GrSurfaceOrigin,
156 /* surfaceProps= */ nullptr,
157 /* shouldCreateWithMips= */ false,
158 /* isProtected= */ true);
159 if (!surface) {
160 return;
161 }
162
163 SkCanvas* canvas = surface->getCanvas();
164 REPORTER_ASSERT(reporter, canvas);
165
166 sk_sp<SkImage> imageBefore = surface->makeImageSnapshot();
167 REPORTER_ASSERT(reporter, imageBefore);
168 REPORTER_ASSERT(reporter, imageBefore->isProtected());
169
170 SkPaint paint;
171 paint.setColor(SK_ColorBLACK);
172 canvas->drawRect(SkRect::MakeWH(4, 4), paint);
173
174 sk_sp<SkImage> imageAfter = surface->makeImageSnapshot();
175 REPORTER_ASSERT(reporter, imageAfter);
176 REPORTER_ASSERT(reporter, imageAfter->isProtected());
177
178 REPORTER_ASSERT(reporter, imageBefore != imageAfter);
179
180 SkBitmap readback;
181 readback.allocPixels(imageAfter->imageInfo());
182 REPORTER_ASSERT(reporter, !imageAfter->readPixels(dContext, readback.pixmap(), 0, 0));
183 }
184
185
186 namespace {
187
188 struct AsyncContext {
189 bool fCalled = false;
190 std::unique_ptr<const SkSurface::AsyncReadResult> fResult;
191 };
192
async_callback(void * c,std::unique_ptr<const SkSurface::AsyncReadResult> result)193 static void async_callback(void* c, std::unique_ptr<const SkSurface::AsyncReadResult> result) {
194 auto context = static_cast<AsyncContext*>(c);
195 context->fResult = std::move(result);
196 context->fCalled = true;
197 }
198
199 } // anonymous namespace
200
201 // Verify that asyncRescaleAndReadPixels fails on protected surfaces
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_asyncRescaleAndReadPixelsFromSurfaces,reporter,ctxInfo,CtsEnforcement::kNever)202 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_asyncRescaleAndReadPixelsFromSurfaces, reporter, ctxInfo,
203 CtsEnforcement::kNever) {
204 auto dContext = ctxInfo.directContext();
205
206 if (!dContext->supportsProtectedContent()) {
207 // Protected content not supported
208 return;
209 }
210
211 sk_sp<SkSurface> surface = ProtectedUtils::CreateProtectedSkSurface(dContext,
212 { kSize, kSize },
213 /* textureable= */ true,
214 /* isProtected= */ true);
215 if (!surface) {
216 return;
217 }
218
219 AsyncContext cbContext;
220
221 surface->asyncRescaleAndReadPixels(surface->imageInfo(),
222 SkIRect::MakeWH(surface->width(), surface->height()),
223 SkSurface::RescaleGamma::kSrc,
224 SkSurface::RescaleMode::kNearest,
225 async_callback, &cbContext);
226 dContext->submit();
227 while (!cbContext.fCalled) {
228 dContext->checkAsyncWorkCompletion();
229 }
230 REPORTER_ASSERT(reporter, !cbContext.fResult);
231 }
232
233 #endif // defined(SK_GANESH)
234