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