Home | History | Annotate | Download | only in jni
      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