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