• 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 "SkTypes.h"
11 
12 #if SK_SUPPORT_GPU && defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
13 
14 #include "GrAHardwareBufferImageGenerator.h"
15 #include "GrContext.h"
16 #include "GrContextFactory.h"
17 #include "GrContextPriv.h"
18 #include "GrGpu.h"
19 #include "SkImage.h"
20 #include "SkSurface.h"
21 #include "Test.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