1 /*
2 * Copyright 2018 Google Inc.
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 // This is a GPU-backend specific test. It relies on static initializers to work
9
10 #include "include/core/SkTypes.h"
11
12 #if defined(SK_GANESH) && defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
13
14 #include "include/core/SkCanvas.h"
15 #include "include/core/SkColorSpace.h"
16 #include "include/core/SkImage.h"
17 #include "include/core/SkSurface.h"
18 #include "include/gpu/GrDirectContext.h"
19 #include "src/gpu/ganesh/GrAHardwareBufferImageGenerator.h"
20 #include "src/gpu/ganesh/GrDirectContextPriv.h"
21 #include "src/gpu/ganesh/GrGpu.h"
22 #include "tests/Test.h"
23 #include "tools/gpu/GrContextFactory.h"
24
25 #include <android/hardware_buffer.h>
26 #include <cinttypes>
27
28 static const int DEV_W = 16, DEV_H = 16;
29
get_src_color(int x,int y)30 static SkPMColor get_src_color(int x, int y) {
31 SkASSERT(x >= 0 && x < DEV_W);
32 SkASSERT(y >= 0 && y < DEV_H);
33
34 U8CPU r = x;
35 U8CPU g = y;
36 U8CPU b = 0xc;
37
38 U8CPU a = 0xff;
39 switch ((x+y) % 5) {
40 case 0:
41 a = 0xff;
42 break;
43 case 1:
44 a = 0x80;
45 break;
46 case 2:
47 a = 0xCC;
48 break;
49 case 4:
50 a = 0x01;
51 break;
52 case 3:
53 a = 0x00;
54 break;
55 }
56 a = 0xff;
57 return SkPremultiplyARGBInline(a, r, g, b);
58 }
59
make_src_bitmap()60 static SkBitmap make_src_bitmap() {
61 static SkBitmap bmp;
62 if (bmp.isNull()) {
63 bmp.allocN32Pixels(DEV_W, DEV_H);
64 intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
65 for (int y = 0; y < DEV_H; ++y) {
66 for (int x = 0; x < DEV_W; ++x) {
67 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(
68 pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
69 *pixel = get_src_color(x, y);
70 }
71 }
72 }
73 return bmp;
74 }
75
check_read(skiatest::Reporter * reporter,const SkBitmap & expectedBitmap,const SkBitmap & actualBitmap)76 static bool check_read(skiatest::Reporter* reporter, const SkBitmap& expectedBitmap,
77 const SkBitmap& actualBitmap) {
78 bool result = true;
79 for (int y = 0; y < DEV_H && result; ++y) {
80 for (int x = 0; x < DEV_W && result; ++x) {
81 const uint32_t srcPixel = *expectedBitmap.getAddr32(x, y);
82 const uint32_t dstPixel = *actualBitmap.getAddr32(x, y);
83 if (srcPixel != dstPixel) {
84 ERRORF(reporter, "Expected readback pixel (%d, %d) value 0x%08x, got 0x%08x.",
85 x, y, srcPixel, dstPixel);
86 result = false;
87 }/* else {
88 SkDebugf("Got good pixel (%d, %d) value 0x%08x, got 0x%08x.\n",
89 x, y, srcPixel, dstPixel);
90 }*/
91 }
92 }
93 return result;
94 }
95
cleanup_resources(AHardwareBuffer * buffer)96 static void cleanup_resources(AHardwareBuffer* buffer) {
97 if (buffer) {
98 AHardwareBuffer_release(buffer);
99 }
100 }
101
basic_draw_test_helper(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & info,GrSurfaceOrigin surfaceOrigin)102 static void basic_draw_test_helper(skiatest::Reporter* reporter,
103 const sk_gpu_test::ContextInfo& info,
104 GrSurfaceOrigin surfaceOrigin) {
105
106 auto context = info.directContext();
107 if (!context->priv().caps()->supportsAHardwareBufferImages()) {
108 return;
109 }
110
111 ///////////////////////////////////////////////////////////////////////////
112 // Setup SkBitmaps
113 ///////////////////////////////////////////////////////////////////////////
114
115 const SkBitmap srcBitmap = make_src_bitmap();
116
117 ///////////////////////////////////////////////////////////////////////////
118 // Setup AHardwareBuffer
119 ///////////////////////////////////////////////////////////////////////////
120
121 AHardwareBuffer* buffer = nullptr;
122
123 AHardwareBuffer_Desc hwbDesc;
124 hwbDesc.width = DEV_W;
125 hwbDesc.height = DEV_H;
126 hwbDesc.layers = 1;
127 hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
128 AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
129 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
130 hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
131 // The following three are not used in the allocate
132 hwbDesc.stride = 0;
133 hwbDesc.rfu0= 0;
134 hwbDesc.rfu1= 0;
135
136 if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) {
137 ERRORF(reporter, "Failed to allocated hardware buffer, error: %d", error);
138 cleanup_resources(buffer);
139 return;
140 }
141
142 // Get actual desc for allocated buffer so we know the stride for uploading cpu data.
143 AHardwareBuffer_describe(buffer, &hwbDesc);
144
145 uint32_t* bufferAddr;
146 if (AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr,
147 reinterpret_cast<void**>(&bufferAddr))) {
148 ERRORF(reporter, "Failed to lock hardware buffer");
149 cleanup_resources(buffer);
150 return;
151 }
152
153 int bbp = srcBitmap.bytesPerPixel();
154 uint32_t* src = (uint32_t*)srcBitmap.getPixels();
155 int nextLineStep = DEV_W;
156 if (surfaceOrigin == kBottomLeft_GrSurfaceOrigin) {
157 nextLineStep = -nextLineStep;
158 src += (DEV_H-1)*DEV_W;
159 }
160 uint32_t* dst = bufferAddr;
161 for (int y = 0; y < DEV_H; ++y) {
162 memcpy(dst, src, DEV_W * bbp);
163 src += nextLineStep;
164 dst += hwbDesc.stride;
165 }
166 AHardwareBuffer_unlock(buffer, nullptr);
167
168 ///////////////////////////////////////////////////////////////////////////
169 // Wrap AHardwareBuffer in SkImage
170 ///////////////////////////////////////////////////////////////////////////
171
172 sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer(buffer, kPremul_SkAlphaType,
173 nullptr, surfaceOrigin);
174 REPORTER_ASSERT(reporter, image);
175
176 ///////////////////////////////////////////////////////////////////////////
177 // Make a surface to draw into
178 ///////////////////////////////////////////////////////////////////////////
179
180 SkImageInfo imageInfo = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType,
181 kPremul_SkAlphaType);
182 sk_sp<SkSurface> surface =
183 SkSurface::MakeRenderTarget(context, skgpu::Budgeted::kNo, imageInfo);
184 REPORTER_ASSERT(reporter, surface);
185
186 ///////////////////////////////////////////////////////////////////////////
187 // Draw the AHardwareBuffer SkImage into surface
188 ///////////////////////////////////////////////////////////////////////////
189
190 surface->getCanvas()->drawImage(image, 0, 0);
191
192 SkBitmap readbackBitmap;
193 readbackBitmap.allocN32Pixels(DEV_W, DEV_H);
194
195 REPORTER_ASSERT(reporter, surface->readPixels(readbackBitmap, 0, 0));
196 REPORTER_ASSERT(reporter, check_read(reporter, srcBitmap, readbackBitmap));
197
198 // Draw the image a second time to make sure we get the correct origin when we get the cached
199 // proxy from the generator.
200 surface->getCanvas()->drawImage(image, 0, 0);
201 REPORTER_ASSERT(reporter, surface->readPixels(readbackBitmap, 0, 0));
202 REPORTER_ASSERT(reporter, check_read(reporter, srcBitmap, readbackBitmap));
203
204 image.reset();
205
206 cleanup_resources(buffer);
207 }
208
209 // Basic test to make sure we can import an AHardwareBuffer into an SkImage and draw it into a
210 // surface.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrAHardwareBuffer_BasicDrawTest,reporter,context_info,CtsEnforcement::kApiLevel_T)211 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrAHardwareBuffer_BasicDrawTest,
212 reporter,
213 context_info,
214 CtsEnforcement::kApiLevel_T) {
215 basic_draw_test_helper(reporter, context_info, kTopLeft_GrSurfaceOrigin);
216 basic_draw_test_helper(reporter, context_info, kBottomLeft_GrSurfaceOrigin);
217 }
218
surface_draw_test_helper(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & info,GrSurfaceOrigin surfaceOrigin)219 static void surface_draw_test_helper(skiatest::Reporter* reporter,
220 const sk_gpu_test::ContextInfo& info,
221 GrSurfaceOrigin surfaceOrigin) {
222
223 auto context = info.directContext();
224 if (!context->priv().caps()->supportsAHardwareBufferImages()) {
225 return;
226 }
227
228 ///////////////////////////////////////////////////////////////////////////
229 // Setup SkBitmaps
230 ///////////////////////////////////////////////////////////////////////////
231
232 const SkBitmap srcBitmap = make_src_bitmap();
233
234 ///////////////////////////////////////////////////////////////////////////
235 // Setup AHardwareBuffer
236 ///////////////////////////////////////////////////////////////////////////
237
238 AHardwareBuffer* buffer = nullptr;
239
240 AHardwareBuffer_Desc hwbDesc;
241 hwbDesc.width = DEV_W;
242 hwbDesc.height = DEV_H;
243 hwbDesc.layers = 1;
244 hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
245 AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
246 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
247 AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
248
249 hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
250 // The following three are not used in the allocate
251 hwbDesc.stride = 0;
252 hwbDesc.rfu0= 0;
253 hwbDesc.rfu1= 0;
254
255 if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) {
256 ERRORF(reporter, "Failed to allocated hardware buffer, error: %d", error);
257 cleanup_resources(buffer);
258 return;
259 }
260
261 sk_sp<SkSurface> surface = SkSurface::MakeFromAHardwareBuffer(context, buffer, surfaceOrigin,
262 nullptr, nullptr);
263 if (!surface) {
264 ERRORF(reporter, "Failed to make SkSurface.");
265 cleanup_resources(buffer);
266 return;
267 }
268
269 surface->getCanvas()->drawImage(srcBitmap.asImage(), 0, 0);
270
271 SkBitmap readbackBitmap;
272 readbackBitmap.allocN32Pixels(DEV_W, DEV_H);
273
274 REPORTER_ASSERT(reporter, surface->readPixels(readbackBitmap, 0, 0));
275 REPORTER_ASSERT(reporter, check_read(reporter, srcBitmap, readbackBitmap));
276
277 cleanup_resources(buffer);
278 }
279
280 // Test to make sure we can import an AHardwareBuffer into an SkSurface and draw into it.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrAHardwareBuffer_ImportAsSurface,reporter,context_info,CtsEnforcement::kApiLevel_T)281 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrAHardwareBuffer_ImportAsSurface,
282 reporter,
283 context_info,
284 CtsEnforcement::kApiLevel_T) {
285 surface_draw_test_helper(reporter, context_info, kTopLeft_GrSurfaceOrigin);
286 surface_draw_test_helper(reporter, context_info, kBottomLeft_GrSurfaceOrigin);
287 }
288
289 #endif
290