• 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 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