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