blob: 2c698cb0b2993e939dd0e5fc2017d70b1da36c32 [file] [log] [blame]
Greg Danielb2acf0a2018-09-12 09:17:11 -04001/*
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
26static const int DEV_W = 16, DEV_H = 16;
27
28static 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
58static 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
74static 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 }
86 }
87 }
88 return result;
89}
90
91static void cleanup_resources(AHardwareBuffer* buffer) {
92 if (buffer) {
93 AHardwareBuffer_release(buffer);
94 }
95}
96
97// Basic test to make sure we can import an AHardwareBuffer into an SkImage and draw it into a
98// surface.
99DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrAHardwareBuffer_BasicDrawTest,
100 reporter, context_info) {
101 GrContext* context = context_info.grContext();
102 if (!context->contextPriv().caps()->supportsAHardwareBufferImages()) {
103 return;
104 }
105
106 ///////////////////////////////////////////////////////////////////////////
107 // Setup SkBitmaps
108 ///////////////////////////////////////////////////////////////////////////
109
110 const SkBitmap srcBitmap = make_src_bitmap();
111
112 ///////////////////////////////////////////////////////////////////////////
113 // Setup AHardwareBuffer
114 ///////////////////////////////////////////////////////////////////////////
115
116 AHardwareBuffer* buffer = nullptr;
117
118 AHardwareBuffer_Desc hwbDesc;
119 hwbDesc.width = DEV_W;
120 hwbDesc.height = DEV_H;
121 hwbDesc.layers = 1;
122 hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
123 AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
124 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
125 hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
126 // The following three are not used in the allocate
127 hwbDesc.stride = 0;
128 hwbDesc.rfu0= 0;
129 hwbDesc.rfu1= 0;
130
131 if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) {
132 ERRORF(reporter, "Failed to allocated hardware buffer, error: %d", error);
133 cleanup_resources(buffer);
134 return;
135 }
136
137 // Get actual desc for allocated buffer so we know the stride for uploading cpu data.
138 AHardwareBuffer_describe(buffer, &hwbDesc);
139
140 uint32_t* bufferAddr;
141 if (AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr,
142 reinterpret_cast<void**>(&bufferAddr))) {
143 ERRORF(reporter, "Failed to lock hardware buffer");
144 cleanup_resources(buffer);
145 return;
146 }
147
148 int bbp = srcBitmap.bytesPerPixel();
149 uint32_t* src = (uint32_t*)srcBitmap.getPixels();
150 uint32_t* dst = bufferAddr;
151 for (int y = 0; y < DEV_H; ++y) {
152 memcpy(dst, src, DEV_W * bbp);
153 src += DEV_W;
154 dst += hwbDesc.stride;
155 }
156 AHardwareBuffer_unlock(buffer, nullptr);
157
158 ///////////////////////////////////////////////////////////////////////////
159 // Wrap AHardwareBuffer in SkImage
160 ///////////////////////////////////////////////////////////////////////////
161
162 sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer(buffer);
163 REPORTER_ASSERT(reporter, image);
164
165 ///////////////////////////////////////////////////////////////////////////
166 // Make a surface to draw into
167 ///////////////////////////////////////////////////////////////////////////
168
169 SkImageInfo imageInfo = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType,
170 kPremul_SkAlphaType);
171 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo,
172 imageInfo);
173 REPORTER_ASSERT(reporter, surface);
174
175 ///////////////////////////////////////////////////////////////////////////
176 // Draw the AHardwareBuffer SkImage into surface
177 ///////////////////////////////////////////////////////////////////////////
178
179 surface->getCanvas()->drawImage(image, 0, 0);
180
181 SkBitmap readbackBitmap;
182 readbackBitmap.allocN32Pixels(DEV_W, DEV_H);
183
184 REPORTER_ASSERT(reporter, surface->readPixels(readbackBitmap, 0, 0));
185 REPORTER_ASSERT(reporter, check_read(reporter, srcBitmap, readbackBitmap));
186
187 image.reset();
188
189 cleanup_resources(buffer);
190}
191
192#endif