1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 #define LOG_TAG "BasicVulkanGpuTest" 19 20 #include <map> 21 #include <string> 22 23 #include <android/hardware_buffer.h> 24 #include <android/log.h> 25 #include <jni.h> 26 #include <unistd.h> 27 28 #include "NativeTestHelpers.h" 29 #include "VulkanTestHelpers.h" 30 31 namespace { 32 33 static constexpr uint32_t kTestImageWidth = 64; 34 static constexpr uint32_t kTestImageHeight = 64; 35 36 } // namespace 37 38 // A Vulkan AHardwareBuffer import test which does the following: 39 // 1) Allocates an AHardwareBuffer in one of 5 formats. 40 // 2) Populates the buffer with well-defined data. 41 // 3) Creates a VkImage from this AHardwareBuffer. 42 // 4) Renders the AHardwareBuffer to a Vulkan RGBA intermediate. 43 // 5) Reads back the intermediate into a CPU accessible VkBuffer. 44 // 6) Validates that the values are as expected. 45 static void verifyBasicBufferImport(JNIEnv *env, jclass, jobject assetMgr, 46 jint format, jboolean useExternalFormat) { 47 // Define and chose parameters. 48 struct FormatDescription { 49 std::string name; 50 size_t pixelWidth; 51 VkFormat vkFormat; 52 }; 53 std::map<uint32_t, FormatDescription> bufferFormats{ 54 {AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 55 {"AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM", 4, VK_FORMAT_R8G8B8A8_UNORM}}, 56 {AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM, 57 {"AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM", 2, 58 VK_FORMAT_R5G6B5_UNORM_PACK16}}, 59 {AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, 60 {"AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM", 4, VK_FORMAT_R8G8B8A8_UNORM}}, 61 {AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM, 62 {"AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM", 3, VK_FORMAT_R8G8B8_UNORM}}, 63 {AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, 64 {"AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM", 4, 65 VK_FORMAT_A2B10G10R10_UNORM_PACK32}}, 66 // TODO(ericrk): Test float and non-renderable formats. 67 }; 68 ASSERT(bufferFormats.find(format) != bufferFormats.end(), 69 "Called verifyBasicBufferImport with unexpected format %d.", format); 70 const FormatDescription &formatDesc = bufferFormats[format]; 71 72 // Set up Vulkan. 73 VkInit init; 74 if (!init.init()) { 75 // Could not initialize Vulkan due to lack of device support, skip test. 76 return; 77 } 78 VkImageRenderer renderer(&init, kTestImageWidth, kTestImageHeight, 79 formatDesc.vkFormat, formatDesc.pixelWidth); 80 ASSERT(renderer.init(env, assetMgr), "Unable to initialize VkRenderer."); 81 82 // Create and initialize buffer based on parameters. 83 AHardwareBuffer_Desc hwbDesc{ 84 .width = kTestImageWidth, 85 .height = kTestImageHeight, 86 .layers = 1, 87 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | 88 AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | 89 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, 90 .format = static_cast<uint32_t>(format), 91 }; 92 AHardwareBuffer *buffer; 93 if (0 != AHardwareBuffer_allocate(&hwbDesc, &buffer)) { 94 // We don't require support for all formats, we only require that if a 95 // format is supported it must be importable into Vulkan. 96 return; 97 } 98 99 // Populate the buffer with well-defined data. 100 AHardwareBuffer_describe(buffer, &hwbDesc); 101 uint8_t *bufferAddr; 102 ASSERT(0 == AHardwareBuffer_lock( 103 buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr, 104 reinterpret_cast<void **>(&bufferAddr)), 105 "Unable to lock hardware buffer."); 106 107 uint8_t *dst = bufferAddr; 108 for (size_t y = 0; y < kTestImageHeight; ++y) { 109 for (size_t x = 0; x < kTestImageWidth; ++x) { 110 uint8_t *target = dst + ((y * hwbDesc.stride * formatDesc.pixelWidth) + 111 x * formatDesc.pixelWidth); 112 *target = x + y; 113 } 114 } 115 116 int syncFd = -1; 117 AHardwareBuffer_unlock(buffer, &syncFd); 118 119 // Import the AHardwareBuffer into Vulkan. 120 VkAHardwareBufferImage vkImage(&init); 121 ASSERT(vkImage.init(buffer, useExternalFormat, syncFd), 122 "Could not initialize VkAHardwareBufferImage."); 123 124 // Render the AHardwareBuffer and read back the result. 125 std::vector<uint8_t> framePixels; 126 ASSERT(renderer.renderImageAndReadback(vkImage.image(), vkImage.sampler(), 127 vkImage.view(), vkImage.semaphore(), 128 vkImage.isSamplerImmutable(), &framePixels), 129 "Could not render/read-back image bits."); 130 ASSERT(framePixels.size() == 131 kTestImageWidth * kTestImageHeight * formatDesc.pixelWidth, 132 "Got unexpected pixel size."); 133 134 // Check that the result is as expected. 135 for (uint32_t y = 0; y < kTestImageHeight; ++y) { 136 for (uint32_t x = 0; x < kTestImageWidth; ++x) { 137 size_t offset = y * kTestImageWidth * formatDesc.pixelWidth + 138 x * formatDesc.pixelWidth; 139 ASSERT(framePixels[offset] == x + y, 140 "Format %s Expected %d at (%d,%d), got %d", 141 formatDesc.name.c_str(), x + y, x, y, framePixels[offset]); 142 } 143 } 144 } 145 146 static JNINativeMethod gMethods[] = { 147 {"verifyBasicBufferImport", "(Landroid/content/res/AssetManager;IZ)V", 148 (void *)verifyBasicBufferImport}, 149 }; 150 151 int register_android_graphics_cts_BasicVulkanGpuTest(JNIEnv *env) { 152 jclass clazz = env->FindClass("android/graphics/cts/BasicVulkanGpuTest"); 153 return env->RegisterNatives(clazz, gMethods, 154 sizeof(gMethods) / sizeof(JNINativeMethod)); 155 } 156