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 "include/core/SkTypes.h"
9
10 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
11
12 #include "include/core/SkBitmap.h"
13 #include "include/core/SkCanvas.h"
14 #include "include/core/SkColorSpace.h"
15 #include "tools/ToolUtils.h"
16 #include "tools/viewer/Slide.h"
17
18 #if defined(SK_GANESH)
19 #include "include/android/SkImageAndroid.h"
20 #include "include/android/SkSurfaceAndroid.h"
21 #include "include/gpu/ganesh/GrDirectContext.h"
22 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
23 #endif
24
25 #if defined(SK_GRAPHITE)
26 #include "include/android/graphite/SurfaceAndroid.h"
27 #include "include/gpu/graphite/Context.h"
28 #include "include/gpu/graphite/Surface.h"
29 #include "src/gpu/graphite/RecorderPriv.h"
30
31 #else
32 namespace skgpu::graphite {
33 class Recorder;
34 }
35 #endif
36
37 #include <android/hardware_buffer.h>
38
39 using namespace skgpu::graphite;
40
41 namespace {
42
release_buffer(AHardwareBuffer * buffer)43 static void release_buffer(AHardwareBuffer* buffer) {
44 if (buffer) {
45 AHardwareBuffer_release(buffer);
46 }
47 }
48
wrap_buffer(GrDirectContext * dContext,Recorder * recorder,AHardwareBuffer * buffer)49 sk_sp<SkSurface> wrap_buffer(GrDirectContext* dContext,
50 Recorder* recorder,
51 AHardwareBuffer* buffer) {
52 #if defined(SK_GANESH)
53 if (dContext) {
54 return SkSurfaces::WrapAndroidHardwareBuffer(dContext,
55 buffer,
56 kTopLeft_GrSurfaceOrigin,
57 /* colorSpace= */ nullptr,
58 /* surfaceProps= */ nullptr);
59 }
60 #endif
61
62 #if defined(SK_GRAPHITE)
63 if (recorder) {
64 return SkSurfaces::WrapAndroidHardwareBuffer(recorder,
65 buffer,
66 /* colorSpace= */ nullptr,
67 /* surfaceProps= */ nullptr);
68 }
69 #endif
70
71 return nullptr;
72 }
73
create_protected_render_target(GrDirectContext * dContext,Recorder * recorder,const SkImageInfo & ii)74 sk_sp<SkSurface> create_protected_render_target(GrDirectContext* dContext,
75 Recorder* recorder,
76 const SkImageInfo& ii) {
77 #if defined(SK_GANESH)
78 if (dContext) {
79 return SkSurfaces::RenderTarget(dContext,
80 skgpu::Budgeted::kYes,
81 ii,
82 /* sampleCount= */ 1,
83 kTopLeft_GrSurfaceOrigin,
84 /* surfaceProps= */ nullptr,
85 /* shouldCreateWithMips= */ false,
86 /* isProtected= */ true);
87 }
88 #endif
89
90 #if defined(SK_GRAPHITE)
91 if (recorder) {
92 // Protected-ness is pulled off of the recorder
93 return SkSurfaces::RenderTarget(recorder,
94 ii,
95 skgpu::Mipmapped::kNo,
96 /* props= */ nullptr);
97 }
98 #endif
99
100 return nullptr;
101 }
102
create_protected_buffer(int width,int height)103 AHardwareBuffer* create_protected_buffer(int width, int height) {
104
105 AHardwareBuffer* buffer = nullptr;
106
107 AHardwareBuffer_Desc hwbDesc;
108 hwbDesc.width = width;
109 hwbDesc.height = height;
110 hwbDesc.layers = 1;
111 hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
112 AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
113 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
114 AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
115
116 hwbDesc.usage |= AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
117
118 hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
119 // The following three are not used in the allocate
120 hwbDesc.stride = 0;
121 hwbDesc.rfu0= 0;
122 hwbDesc.rfu1= 0;
123
124 if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) {
125 SkDebugf("Failed to allocated hardware buffer, error: %d\n", error);
126 release_buffer(buffer);
127 return nullptr;
128 }
129
130 return buffer;
131 }
132
create_protected_AHB_image(GrDirectContext * dContext,Recorder * recorder,AHardwareBuffer * buffer,SkColor color)133 sk_sp<SkImage> create_protected_AHB_image(GrDirectContext* dContext,
134 Recorder* recorder,
135 AHardwareBuffer* buffer,
136 SkColor color) {
137
138 sk_sp<SkSurface> surf = wrap_buffer(dContext, recorder, buffer);
139 if (!surf) {
140 SkDebugf("Failed to make SkSurface.\n");
141 return nullptr;
142 }
143
144 ToolUtils::draw_checkerboard(surf->getCanvas(), color, SK_ColorTRANSPARENT, 32);
145
146 return surf->makeImageSnapshot();
147 }
148
create_protected_skia_image(GrDirectContext * dContext,Recorder * recorder,int width,int height,SkColor color)149 sk_sp<SkImage> create_protected_skia_image(GrDirectContext* dContext,
150 Recorder* recorder,
151 int width, int height,
152 SkColor color) {
153 SkImageInfo ii = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
154 kPremul_SkAlphaType);
155
156 sk_sp<SkSurface> tmpSurface = create_protected_render_target(dContext, recorder, ii);
157 if (!tmpSurface) {
158 return nullptr;
159 }
160
161 ToolUtils::draw_checkerboard(tmpSurface->getCanvas(), color, SK_ColorTRANSPARENT, 32);
162
163 return tmpSurface->makeImageSnapshot();
164 }
165
166 } // anonymous namespace
167
168 class ProtectedSlide : public Slide {
169 public:
ProtectedSlide()170 ProtectedSlide() { fName = "Protected"; }
171
getDimensions() const172 SkISize getDimensions() const override { return {kSize, 2*kSize}; }
173
draw(SkCanvas * origCanvas)174 void draw(SkCanvas* origCanvas) override {
175 origCanvas->clear(SK_ColorDKGRAY);
176
177 skgpu::graphite::Recorder* recorder = origCanvas->recorder();
178 GrDirectContext* dContext = GrAsDirectContext(origCanvas->recordingContext());
179
180 #if defined(SK_GANESH)
181 if (dContext && !dContext->supportsProtectedContent()) {
182 origCanvas->clear(SK_ColorGREEN);
183 return;
184 }
185 #endif
186
187 #if defined(SK_GRAPHITE)
188 if (recorder && recorder->priv().isProtected() == skgpu::Protected::kNo) {
189 origCanvas->clear(SK_ColorBLUE);
190 return;
191 }
192 #endif
193
194 if (!dContext && !recorder) {
195 origCanvas->clear(SK_ColorRED);
196 return;
197 }
198
199 AHardwareBuffer* buffer = create_protected_buffer(kSize, kSize);
200
201 sk_sp<SkImage> protectedAHBImage = create_protected_AHB_image(dContext, recorder, buffer,
202 SK_ColorRED);
203 sk_sp<SkImage> protectedSkImage = create_protected_skia_image(dContext, recorder,
204 kSize, kSize, SK_ColorBLUE);
205
206 // Pick one of the two protected images to draw. Only the protected AHB-backed image will
207 // reproduce the bug (b/242266174).
208 SkImage* imgToUse = protectedAHBImage.get();
209 // SkImage* imgToUse = protectedSkImage.get();
210
211 sk_sp<SkImage> indirectImg;
212
213 {
214 SkImageInfo ii = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
215 kPremul_SkAlphaType);
216 sk_sp<SkSurface> tmpS = create_protected_render_target(dContext, recorder, ii);
217
218 tmpS->getCanvas()->clear(SK_ColorMAGENTA);
219 tmpS->getCanvas()->drawCircle(64, 64, 32, SkPaint());
220
221 // For protected AHB-backed images this draw seems to poison all above the draws too
222 tmpS->getCanvas()->drawImage(imgToUse, 0, 0);
223 indirectImg = tmpS->makeImageSnapshot();
224 }
225
226 origCanvas->drawImage(imgToUse, 0, 0);
227 origCanvas->drawImage(indirectImg, 0, kSize);
228
229 protectedAHBImage.reset();
230 protectedSkImage.reset();
231 release_buffer(buffer);
232 }
233
234 private:
235 static const int kSize = 128;
236 };
237
238 DEF_SLIDE( return new ProtectedSlide(); )
239
240 #endif
241