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 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 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 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 94 static void cleanup_resources(AHardwareBuffer* buffer) { 95 if (buffer) { 96 AHardwareBuffer_release(buffer); 97 } 98 } 99 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->contextPriv().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. 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 210 #endif 211