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
27static const int DEV_W = 16, DEV_H = 16;
28
29static 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
59static 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
75static 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
95static void cleanup_resources(AHardwareBuffer* buffer) {
96    if (buffer) {
97        AHardwareBuffer_release(buffer);
98    }
99}
100
101static 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.
205DEF_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
211static 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.
273DEF_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