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 "VulkanPreTransformTestHelpers"
     19 
     20 #ifndef VK_USE_PLATFORM_ANDROID_KHR
     21 #define VK_USE_PLATFORM_ANDROID_KHR
     22 #endif
     23 
     24 #include <android/log.h>
     25 #include <cstring>
     26 
     27 #include "VulkanPreTransformTestHelpers.h"
     28 
     29 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
     30 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
     31 #define ASSERT(a)                                              \
     32     if (!(a)) {                                                \
     33         ALOGE("Failure: " #a " at " __FILE__ ":%d", __LINE__); \
     34         return VK_TEST_ERROR;                                  \
     35     }
     36 #define VK_CALL(a) ASSERT(VK_SUCCESS == (a))
     37 
     38 static const float vertexData[] = {
     39         // L:left, T:top, R:right, B:bottom, C:center
     40         -1.0f, -1.0f, 0.0f, // LT
     41         -1.0f,  0.0f, 0.0f, // LC
     42          0.0f, -1.0f, 0.0f, // CT
     43          0.0f,  0.0f, 0.0f, // CC
     44          1.0f, -1.0f, 0.0f, // RT
     45          1.0f,  0.0f, 0.0f, // RC
     46         -1.0f,  0.0f, 0.0f, // LC
     47         -1.0f,  1.0f, 0.0f, // LB
     48          0.0f,  0.0f, 0.0f, // CC
     49          0.0f,  1.0f, 0.0f, // CB
     50          1.0f,  0.0f, 0.0f, // RC
     51          1.0f,  1.0f, 0.0f, // RB
     52 };
     53 
     54 static const float fragData[] = {
     55         1.0f, 0.0f, 0.0f, // Red
     56         0.0f, 1.0f, 0.0f, // Green
     57         0.0f, 0.0f, 1.0f, // Blue
     58         1.0f, 1.0f, 0.0f, // Yellow
     59 };
     60 
     61 static const char* requiredInstanceExtensions[] = {
     62         "VK_KHR_surface",
     63         "VK_KHR_android_surface",
     64 };
     65 
     66 static const char* requiredDeviceExtensions[] = {
     67         "VK_KHR_swapchain",
     68 };
     69 
     70 static bool enumerateInstanceExtensions(std::vector<VkExtensionProperties>* extensions) {
     71     VkResult result;
     72 
     73     uint32_t count = 0;
     74     result = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
     75     if (result != VK_SUCCESS) return false;
     76 
     77     extensions->resize(count);
     78     result = vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions->data());
     79     if (result != VK_SUCCESS) return false;
     80 
     81     return true;
     82 }
     83 
     84 static bool enumerateDeviceExtensions(VkPhysicalDevice device,
     85                                       std::vector<VkExtensionProperties>* extensions) {
     86     VkResult result;
     87 
     88     uint32_t count = 0;
     89     result = vkEnumerateDeviceExtensionProperties(device, nullptr, &count, nullptr);
     90     if (result != VK_SUCCESS) return false;
     91 
     92     extensions->resize(count);
     93     result = vkEnumerateDeviceExtensionProperties(device, nullptr, &count, extensions->data());
     94     if (result != VK_SUCCESS) return false;
     95 
     96     return true;
     97 }
     98 
     99 static bool hasExtension(const char* extension_name,
    100                          const std::vector<VkExtensionProperties>& extensions) {
    101     return std::find_if(extensions.cbegin(), extensions.cend(),
    102                         [extension_name](const VkExtensionProperties& extension) {
    103                             return strcmp(extension.extensionName, extension_name) == 0;
    104                         }) != extensions.cend();
    105 }
    106 
    107 DeviceInfo::DeviceInfo()
    108       : mInstance(VK_NULL_HANDLE),
    109         mGpu(VK_NULL_HANDLE),
    110         mWindow(nullptr),
    111         mSurface(VK_NULL_HANDLE),
    112         mQueueFamilyIndex(0),
    113         mDevice(VK_NULL_HANDLE),
    114         mQueue(VK_NULL_HANDLE) {}
    115 
    116 DeviceInfo::~DeviceInfo() {
    117     if (mDevice) {
    118         vkDeviceWaitIdle(mDevice);
    119         vkDestroyDevice(mDevice, nullptr);
    120         mDevice = VK_NULL_HANDLE;
    121     }
    122     if (mInstance) {
    123         vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
    124         vkDestroyInstance(mInstance, nullptr);
    125         mInstance = VK_NULL_HANDLE;
    126     }
    127     if (mWindow) {
    128         ANativeWindow_release(mWindow);
    129         mWindow = nullptr;
    130     }
    131 }
    132 
    133 VkTestResult DeviceInfo::init(JNIEnv* env, jobject jSurface) {
    134     ASSERT(jSurface);
    135 
    136     mWindow = ANativeWindow_fromSurface(env, jSurface);
    137     ASSERT(mWindow);
    138 
    139     std::vector<VkExtensionProperties> supportedInstanceExtensions;
    140     ASSERT(enumerateInstanceExtensions(&supportedInstanceExtensions));
    141 
    142     std::vector<const char*> enabledInstanceExtensions;
    143     for (const auto extension : requiredInstanceExtensions) {
    144         ASSERT(hasExtension(extension, supportedInstanceExtensions));
    145         enabledInstanceExtensions.push_back(extension);
    146     }
    147 
    148     const VkApplicationInfo appInfo = {
    149             .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
    150             .pNext = nullptr,
    151             .pApplicationName = "VulkanPreTransformTest",
    152             .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
    153             .pEngineName = "",
    154             .engineVersion = VK_MAKE_VERSION(1, 0, 0),
    155             .apiVersion = VK_MAKE_VERSION(1, 0, 0),
    156     };
    157     const VkInstanceCreateInfo instanceInfo = {
    158             .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
    159             .pNext = nullptr,
    160             .flags = 0,
    161             .pApplicationInfo = &appInfo,
    162             .enabledLayerCount = 0,
    163             .ppEnabledLayerNames = nullptr,
    164             .enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size()),
    165             .ppEnabledExtensionNames = enabledInstanceExtensions.data(),
    166     };
    167     VK_CALL(vkCreateInstance(&instanceInfo, nullptr, &mInstance));
    168 
    169     uint32_t gpuCount = 0;
    170     VK_CALL(vkEnumeratePhysicalDevices(mInstance, &gpuCount, nullptr));
    171     if (gpuCount == 0) {
    172         ALOGD("No physical device available");
    173         return VK_TEST_PHYSICAL_DEVICE_NOT_EXISTED;
    174     }
    175 
    176     std::vector<VkPhysicalDevice> gpus(gpuCount, VK_NULL_HANDLE);
    177     VK_CALL(vkEnumeratePhysicalDevices(mInstance, &gpuCount, gpus.data()));
    178 
    179     mGpu = gpus[0];
    180 
    181     const VkAndroidSurfaceCreateInfoKHR surfaceInfo = {
    182             .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
    183             .pNext = nullptr,
    184             .flags = 0,
    185             .window = mWindow,
    186     };
    187     VK_CALL(vkCreateAndroidSurfaceKHR(mInstance, &surfaceInfo, nullptr, &mSurface));
    188 
    189     std::vector<VkExtensionProperties> supportedDeviceExtensions;
    190     ASSERT(enumerateDeviceExtensions(mGpu, &supportedDeviceExtensions));
    191 
    192     std::vector<const char*> enabledDeviceExtensions;
    193     for (const auto extension : requiredDeviceExtensions) {
    194         ASSERT(hasExtension(extension, supportedDeviceExtensions));
    195         enabledDeviceExtensions.push_back(extension);
    196     }
    197 
    198     uint32_t queueFamilyCount = 0;
    199     vkGetPhysicalDeviceQueueFamilyProperties(mGpu, &queueFamilyCount, nullptr);
    200     ASSERT(queueFamilyCount);
    201 
    202     std::vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyCount);
    203     vkGetPhysicalDeviceQueueFamilyProperties(mGpu, &queueFamilyCount, queueFamilyProperties.data());
    204 
    205     uint32_t queueFamilyIndex;
    206     for (queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; ++queueFamilyIndex) {
    207         if (queueFamilyProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
    208             break;
    209         }
    210     }
    211     ASSERT(queueFamilyIndex < queueFamilyCount);
    212     mQueueFamilyIndex = queueFamilyIndex;
    213 
    214     VkBool32 supported = VK_FALSE;
    215     VK_CALL(vkGetPhysicalDeviceSurfaceSupportKHR(mGpu, mQueueFamilyIndex, mSurface, &supported));
    216     if (supported == VK_FALSE) {
    217         ALOGD("Surface format not supported");
    218         return VK_TEST_SURFACE_FORMAT_NOT_SUPPORTED;
    219     }
    220 
    221     const float priority = 1.0f;
    222     const VkDeviceQueueCreateInfo queueCreateInfo = {
    223             .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
    224             .pNext = nullptr,
    225             .flags = 0,
    226             .queueFamilyIndex = mQueueFamilyIndex,
    227             .queueCount = 1,
    228             .pQueuePriorities = &priority,
    229     };
    230     const VkDeviceCreateInfo deviceCreateInfo = {
    231             .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
    232             .pNext = nullptr,
    233             .queueCreateInfoCount = 1,
    234             .pQueueCreateInfos = &queueCreateInfo,
    235             .enabledLayerCount = 0,
    236             .ppEnabledLayerNames = nullptr,
    237             .enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size()),
    238             .ppEnabledExtensionNames = enabledDeviceExtensions.data(),
    239             .pEnabledFeatures = nullptr,
    240     };
    241     VK_CALL(vkCreateDevice(mGpu, &deviceCreateInfo, nullptr, &mDevice));
    242 
    243     vkGetDeviceQueue(mDevice, mQueueFamilyIndex, 0, &mQueue);
    244 
    245     return VK_TEST_SUCCESS;
    246 }
    247 
    248 SwapchainInfo::SwapchainInfo(const DeviceInfo* const deviceInfo)
    249       : mDeviceInfo(deviceInfo),
    250         mFormat(VK_FORMAT_UNDEFINED),
    251         mDisplaySize({0, 0}),
    252         mSwapchain(VK_NULL_HANDLE),
    253         mSwapchainLength(0) {}
    254 
    255 SwapchainInfo::~SwapchainInfo() {
    256     if (mDeviceInfo->device()) {
    257         vkDeviceWaitIdle(mDeviceInfo->device());
    258         vkDestroySwapchainKHR(mDeviceInfo->device(), mSwapchain, nullptr);
    259     }
    260 }
    261 
    262 VkTestResult SwapchainInfo::init(bool setPreTransform, int* outPreTransformHint) {
    263     VkSurfaceCapabilitiesKHR surfaceCapabilities;
    264     VK_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(mDeviceInfo->gpu(), mDeviceInfo->surface(),
    265                                                       &surfaceCapabilities));
    266     ALOGD("Vulkan Surface Capabilities:\n");
    267     ALOGD("\timage count: %u - %u\n", surfaceCapabilities.minImageCount,
    268           surfaceCapabilities.maxImageCount);
    269     ALOGD("\tarray layers: %u\n", surfaceCapabilities.maxImageArrayLayers);
    270     ALOGD("\timage size (now): %dx%d\n", surfaceCapabilities.currentExtent.width,
    271           surfaceCapabilities.currentExtent.height);
    272     ALOGD("\timage size (extent): %dx%d - %dx%d\n", surfaceCapabilities.minImageExtent.width,
    273           surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.width,
    274           surfaceCapabilities.maxImageExtent.height);
    275     ALOGD("\tusage: %x\n", surfaceCapabilities.supportedUsageFlags);
    276     ALOGD("\tcurrent transform: %u\n", surfaceCapabilities.currentTransform);
    277     ALOGD("\tallowed transforms: %x\n", surfaceCapabilities.supportedTransforms);
    278     ALOGD("\tcomposite alpha flags: %u\n", surfaceCapabilities.supportedCompositeAlpha);
    279 
    280     uint32_t formatCount = 0;
    281     VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(mDeviceInfo->gpu(), mDeviceInfo->surface(),
    282                                                  &formatCount, nullptr));
    283 
    284     std::vector<VkSurfaceFormatKHR> formats(formatCount);
    285     VK_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(mDeviceInfo->gpu(), mDeviceInfo->surface(),
    286                                                  &formatCount, formats.data()));
    287 
    288     uint32_t formatIndex;
    289     for (formatIndex = 0; formatIndex < formatCount; ++formatIndex) {
    290         if (formats[formatIndex].format == VK_FORMAT_R8G8B8A8_UNORM) {
    291             break;
    292         }
    293     }
    294     ASSERT(formatIndex < formatCount);
    295 
    296     mFormat = formats[formatIndex].format;
    297     mDisplaySize = surfaceCapabilities.currentExtent;
    298 
    299     VkSurfaceTransformFlagBitsKHR preTransform =
    300             (setPreTransform ? surfaceCapabilities.currentTransform
    301                              : VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR);
    302     ALOGD("currentTransform = %u, preTransform = %u",
    303           static_cast<uint32_t>(surfaceCapabilities.currentTransform),
    304           static_cast<uint32_t>(preTransform));
    305 
    306     if ((preTransform &
    307          (VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
    308           VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
    309           VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR)) != 0) {
    310         std::swap(mDisplaySize.width, mDisplaySize.height);
    311     }
    312 
    313     if (outPreTransformHint) {
    314         *outPreTransformHint = surfaceCapabilities.currentTransform;
    315     }
    316 
    317     const uint32_t queueFamilyIndex = mDeviceInfo->queueFamilyIndex();
    318     const VkSwapchainCreateInfoKHR swapchainCreateInfo = {
    319             .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
    320             .pNext = nullptr,
    321             .flags = 0,
    322             .surface = mDeviceInfo->surface(),
    323             .minImageCount = surfaceCapabilities.minImageCount,
    324             .imageFormat = mFormat,
    325             .imageColorSpace = formats[formatIndex].colorSpace,
    326             .imageExtent = mDisplaySize,
    327             .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
    328             .preTransform = preTransform,
    329             .imageArrayLayers = 1,
    330             .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
    331             .queueFamilyIndexCount = 1,
    332             .pQueueFamilyIndices = &queueFamilyIndex,
    333             .compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
    334             .presentMode = VK_PRESENT_MODE_FIFO_KHR,
    335             .clipped = VK_FALSE,
    336     };
    337     VK_CALL(vkCreateSwapchainKHR(mDeviceInfo->device(), &swapchainCreateInfo, nullptr,
    338                                  &mSwapchain));
    339 
    340     VK_CALL(vkGetSwapchainImagesKHR(mDeviceInfo->device(), mSwapchain, &mSwapchainLength, nullptr));
    341     ALOGD("Swapchain length = %u", mSwapchainLength);
    342 
    343     return VK_TEST_SUCCESS;
    344 }
    345 
    346 Renderer::Renderer(const DeviceInfo* const deviceInfo, const SwapchainInfo* const swapchainInfo)
    347       : mDeviceInfo(deviceInfo),
    348         mSwapchainInfo(swapchainInfo),
    349         mDeviceMemory(VK_NULL_HANDLE),
    350         mVertexBuffer(VK_NULL_HANDLE),
    351         mRenderPass(VK_NULL_HANDLE),
    352         mVertexShader(VK_NULL_HANDLE),
    353         mFragmentShader(VK_NULL_HANDLE),
    354         mPipelineLayout(VK_NULL_HANDLE),
    355         mPipeline(VK_NULL_HANDLE),
    356         mCommandPool(VK_NULL_HANDLE),
    357         mSemaphore(VK_NULL_HANDLE),
    358         mFence(VK_NULL_HANDLE) {}
    359 
    360 Renderer::~Renderer() {
    361     if (mDeviceInfo->device()) {
    362         vkDeviceWaitIdle(mDeviceInfo->device());
    363         vkDestroyShaderModule(mDeviceInfo->device(), mVertexShader, nullptr);
    364         vkDestroyShaderModule(mDeviceInfo->device(), mFragmentShader, nullptr);
    365         vkDestroyFence(mDeviceInfo->device(), mFence, nullptr);
    366         vkDestroySemaphore(mDeviceInfo->device(), mSemaphore, nullptr);
    367         if (!mCommandBuffers.empty()) {
    368             vkFreeCommandBuffers(mDeviceInfo->device(), mCommandPool, mCommandBuffers.size(),
    369                                  mCommandBuffers.data());
    370         }
    371         vkDestroyCommandPool(mDeviceInfo->device(), mCommandPool, nullptr);
    372         vkDestroyPipeline(mDeviceInfo->device(), mPipeline, nullptr);
    373         vkDestroyPipelineLayout(mDeviceInfo->device(), mPipelineLayout, nullptr);
    374         vkDestroyBuffer(mDeviceInfo->device(), mVertexBuffer, nullptr);
    375         vkFreeMemory(mDeviceInfo->device(), mDeviceMemory, nullptr);
    376         vkDestroyRenderPass(mDeviceInfo->device(), mRenderPass, nullptr);
    377         for (auto& framebuffer : mFramebuffers) {
    378             vkDestroyFramebuffer(mDeviceInfo->device(), framebuffer, nullptr);
    379         }
    380         for (auto& imageView : mImageViews) {
    381             vkDestroyImageView(mDeviceInfo->device(), imageView, nullptr);
    382         }
    383     }
    384 }
    385 
    386 VkTestResult Renderer::createRenderPass() {
    387     const VkAttachmentDescription attachmentDescription = {
    388             .flags = 0,
    389             .format = mSwapchainInfo->format(),
    390             .samples = VK_SAMPLE_COUNT_1_BIT,
    391             .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
    392             .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
    393             .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
    394             .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
    395             .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
    396             .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    397     };
    398     const VkAttachmentReference attachmentReference = {
    399             .attachment = 0,
    400             .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    401     };
    402     const VkSubpassDescription subpassDescription = {
    403             .flags = 0,
    404             .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
    405             .inputAttachmentCount = 0,
    406             .pInputAttachments = nullptr,
    407             .colorAttachmentCount = 1,
    408             .pColorAttachments = &attachmentReference,
    409             .pResolveAttachments = nullptr,
    410             .pDepthStencilAttachment = nullptr,
    411             .preserveAttachmentCount = 0,
    412             .pPreserveAttachments = nullptr,
    413     };
    414     const VkRenderPassCreateInfo renderPassCreateInfo = {
    415             .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
    416             .pNext = nullptr,
    417             .flags = 0,
    418             .attachmentCount = 1,
    419             .pAttachments = &attachmentDescription,
    420             .subpassCount = 1,
    421             .pSubpasses = &subpassDescription,
    422             .dependencyCount = 0,
    423             .pDependencies = nullptr,
    424     };
    425     VK_CALL(vkCreateRenderPass(mDeviceInfo->device(), &renderPassCreateInfo, nullptr,
    426                                &mRenderPass));
    427 
    428     return VK_TEST_SUCCESS;
    429 }
    430 
    431 VkTestResult Renderer::createFrameBuffers() {
    432     uint32_t swapchainLength = mSwapchainInfo->swapchainLength();
    433     std::vector<VkImage> images(swapchainLength, VK_NULL_HANDLE);
    434     VK_CALL(vkGetSwapchainImagesKHR(mDeviceInfo->device(), mSwapchainInfo->swapchain(),
    435                                     &swapchainLength, images.data()));
    436 
    437     mImageViews.resize(swapchainLength, VK_NULL_HANDLE);
    438     for (uint32_t i = 0; i < swapchainLength; ++i) {
    439         const VkImageViewCreateInfo imageViewCreateInfo = {
    440                 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
    441                 .pNext = nullptr,
    442                 .flags = 0,
    443                 .image = images[i],
    444                 .viewType = VK_IMAGE_VIEW_TYPE_2D,
    445                 .format = mSwapchainInfo->format(),
    446                 .components =
    447                         {
    448                                 .r = VK_COMPONENT_SWIZZLE_R,
    449                                 .g = VK_COMPONENT_SWIZZLE_G,
    450                                 .b = VK_COMPONENT_SWIZZLE_B,
    451                                 .a = VK_COMPONENT_SWIZZLE_A,
    452                         },
    453                 .subresourceRange =
    454                         {
    455                                 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
    456                                 .baseMipLevel = 0,
    457                                 .levelCount = 1,
    458                                 .baseArrayLayer = 0,
    459                                 .layerCount = 1,
    460                         },
    461         };
    462         VK_CALL(vkCreateImageView(mDeviceInfo->device(), &imageViewCreateInfo, nullptr,
    463                                   &mImageViews[i]));
    464     }
    465 
    466     mFramebuffers.resize(swapchainLength, VK_NULL_HANDLE);
    467     for (uint32_t i = 0; i < swapchainLength; ++i) {
    468         const VkFramebufferCreateInfo framebufferCreateInfo = {
    469                 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
    470                 .pNext = nullptr,
    471                 .flags = 0,
    472                 .renderPass = mRenderPass,
    473                 .attachmentCount = 1,
    474                 .pAttachments = &mImageViews[i],
    475                 .width = mSwapchainInfo->displaySize().width,
    476                 .height = mSwapchainInfo->displaySize().height,
    477                 .layers = 1,
    478         };
    479         VK_CALL(vkCreateFramebuffer(mDeviceInfo->device(), &framebufferCreateInfo, nullptr,
    480                                     &mFramebuffers[i]));
    481     }
    482 
    483     return VK_TEST_SUCCESS;
    484 }
    485 
    486 VkTestResult Renderer::createVertexBuffers() {
    487     const uint32_t queueFamilyIndex = mDeviceInfo->queueFamilyIndex();
    488     const VkBufferCreateInfo bufferCreateInfo = {
    489             .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
    490             .pNext = nullptr,
    491             .flags = 0,
    492             .size = sizeof(vertexData),
    493             .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
    494             .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
    495             .queueFamilyIndexCount = 1,
    496             .pQueueFamilyIndices = &queueFamilyIndex,
    497     };
    498     VK_CALL(vkCreateBuffer(mDeviceInfo->device(), &bufferCreateInfo, nullptr, &mVertexBuffer));
    499 
    500     VkMemoryRequirements memoryRequirements;
    501     vkGetBufferMemoryRequirements(mDeviceInfo->device(), mVertexBuffer, &memoryRequirements);
    502 
    503     VkPhysicalDeviceMemoryProperties memoryProperties;
    504     vkGetPhysicalDeviceMemoryProperties(mDeviceInfo->gpu(), &memoryProperties);
    505 
    506     int32_t typeIndex = -1;
    507     for (int32_t i = 0, typeBits = memoryRequirements.memoryTypeBits; i < 32; ++i) {
    508         if ((typeBits & 1) == 1) {
    509             if ((memoryProperties.memoryTypes[i].propertyFlags &
    510                  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
    511                 typeIndex = i;
    512                 break;
    513             }
    514         }
    515         typeBits >>= 1;
    516     }
    517     ASSERT(typeIndex != -1);
    518 
    519     VkMemoryAllocateInfo memoryAllocateInfo = {
    520             .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
    521             .pNext = nullptr,
    522             .allocationSize = memoryRequirements.size,
    523             .memoryTypeIndex = static_cast<uint32_t>(typeIndex),
    524     };
    525     VK_CALL(vkAllocateMemory(mDeviceInfo->device(), &memoryAllocateInfo, nullptr, &mDeviceMemory));
    526 
    527     void* data;
    528     VK_CALL(vkMapMemory(mDeviceInfo->device(), mDeviceMemory, 0, sizeof(vertexData), 0, &data));
    529 
    530     memcpy(data, vertexData, sizeof(vertexData));
    531     vkUnmapMemory(mDeviceInfo->device(), mDeviceMemory);
    532 
    533     VK_CALL(vkBindBufferMemory(mDeviceInfo->device(), mVertexBuffer, mDeviceMemory, 0));
    534 
    535     return VK_TEST_SUCCESS;
    536 }
    537 
    538 VkTestResult Renderer::loadShaderFromFile(const char* filePath, VkShaderModule* const outShader) {
    539     ASSERT(filePath);
    540 
    541     AAsset* file = AAssetManager_open(mAssetManager, filePath, AASSET_MODE_BUFFER);
    542     ASSERT(file);
    543 
    544     size_t fileLength = AAsset_getLength(file);
    545     std::vector<char> fileContent(fileLength);
    546     AAsset_read(file, fileContent.data(), fileLength);
    547     AAsset_close(file);
    548 
    549     const VkShaderModuleCreateInfo shaderModuleCreateInfo = {
    550             .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
    551             .pNext = nullptr,
    552             .flags = 0,
    553             .codeSize = fileLength,
    554             .pCode = (const uint32_t*)(fileContent.data()),
    555     };
    556     VK_CALL(vkCreateShaderModule(mDeviceInfo->device(), &shaderModuleCreateInfo, nullptr,
    557                                  outShader));
    558 
    559     return VK_TEST_SUCCESS;
    560 }
    561 
    562 VkTestResult Renderer::createGraphicsPipeline() {
    563     const VkPushConstantRange pushConstantRange = {
    564             .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
    565             .offset = 0,
    566             .size = 3 * sizeof(float),
    567     };
    568     const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
    569             .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
    570             .pNext = nullptr,
    571             .flags = 0,
    572             .setLayoutCount = 0,
    573             .pSetLayouts = nullptr,
    574             .pushConstantRangeCount = 1,
    575             .pPushConstantRanges = &pushConstantRange,
    576     };
    577     VK_CALL(vkCreatePipelineLayout(mDeviceInfo->device(), &pipelineLayoutCreateInfo, nullptr,
    578                                    &mPipelineLayout));
    579 
    580     ASSERT(!loadShaderFromFile("shaders/tri.vert.spv", &mVertexShader));
    581     ASSERT(!loadShaderFromFile("shaders/tri.frag.spv", &mFragmentShader));
    582 
    583     const VkPipelineShaderStageCreateInfo shaderStages[2] =
    584             {{
    585                      .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
    586                      .pNext = nullptr,
    587                      .flags = 0,
    588                      .stage = VK_SHADER_STAGE_VERTEX_BIT,
    589                      .module = mVertexShader,
    590                      .pName = "main",
    591                      .pSpecializationInfo = nullptr,
    592              },
    593              {
    594                      .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
    595                      .pNext = nullptr,
    596                      .flags = 0,
    597                      .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
    598                      .module = mFragmentShader,
    599                      .pName = "main",
    600                      .pSpecializationInfo = nullptr,
    601              }};
    602     const VkViewport viewports = {
    603             .x = 0.0f,
    604             .y = 0.0f,
    605             .width = (float)mSwapchainInfo->displaySize().width,
    606             .height = (float)mSwapchainInfo->displaySize().height,
    607             .minDepth = 0.0f,
    608             .maxDepth = 1.0f,
    609     };
    610     const VkRect2D scissor = {
    611             .offset =
    612                     {
    613                             .x = 0,
    614                             .y = 0,
    615                     },
    616             .extent = mSwapchainInfo->displaySize(),
    617     };
    618     const VkPipelineViewportStateCreateInfo viewportInfo = {
    619             .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
    620             .pNext = nullptr,
    621             .flags = 0,
    622             .viewportCount = 1,
    623             .pViewports = &viewports,
    624             .scissorCount = 1,
    625             .pScissors = &scissor,
    626     };
    627     VkSampleMask sampleMask = ~0u;
    628     const VkPipelineMultisampleStateCreateInfo multisampleInfo = {
    629             .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
    630             .pNext = nullptr,
    631             .flags = 0,
    632             .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
    633             .sampleShadingEnable = VK_FALSE,
    634             .minSampleShading = 0,
    635             .pSampleMask = &sampleMask,
    636             .alphaToCoverageEnable = VK_FALSE,
    637             .alphaToOneEnable = VK_FALSE,
    638     };
    639     const VkPipelineColorBlendAttachmentState attachmentStates = {
    640             .blendEnable = VK_FALSE,
    641             .srcColorBlendFactor = (VkBlendFactor)0,
    642             .dstColorBlendFactor = (VkBlendFactor)0,
    643             .colorBlendOp = (VkBlendOp)0,
    644             .srcAlphaBlendFactor = (VkBlendFactor)0,
    645             .dstAlphaBlendFactor = (VkBlendFactor)0,
    646             .alphaBlendOp = (VkBlendOp)0,
    647             .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
    648                     VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
    649     };
    650     const VkPipelineColorBlendStateCreateInfo colorBlendInfo = {
    651             .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
    652             .pNext = nullptr,
    653             .flags = 0,
    654             .logicOpEnable = VK_FALSE,
    655             .logicOp = VK_LOGIC_OP_COPY,
    656             .attachmentCount = 1,
    657             .pAttachments = &attachmentStates,
    658             .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
    659     };
    660     const VkPipelineRasterizationStateCreateInfo rasterInfo = {
    661             .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
    662             .pNext = nullptr,
    663             .flags = 0,
    664             .depthClampEnable = VK_FALSE,
    665             .rasterizerDiscardEnable = VK_FALSE,
    666             .polygonMode = VK_POLYGON_MODE_FILL,
    667             .cullMode = VK_CULL_MODE_NONE,
    668             .frontFace = VK_FRONT_FACE_CLOCKWISE,
    669             .depthBiasEnable = VK_FALSE,
    670             .depthBiasConstantFactor = 0,
    671             .depthBiasClamp = 0,
    672             .depthBiasSlopeFactor = 0,
    673             .lineWidth = 1,
    674     };
    675     const VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {
    676             .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
    677             .pNext = nullptr,
    678             .flags = 0,
    679             .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
    680             .primitiveRestartEnable = VK_FALSE,
    681     };
    682     const VkVertexInputBindingDescription vertexInputBindingDescription = {
    683             .binding = 0,
    684             .stride = 3 * sizeof(float),
    685             .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
    686     };
    687     const VkVertexInputAttributeDescription vertexInputAttributeDescription = {
    688             .location = 0,
    689             .binding = 0,
    690             .format = VK_FORMAT_R32G32B32_SFLOAT,
    691             .offset = 0,
    692     };
    693     const VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
    694             .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
    695             .pNext = nullptr,
    696             .flags = 0,
    697             .vertexBindingDescriptionCount = 1,
    698             .pVertexBindingDescriptions = &vertexInputBindingDescription,
    699             .vertexAttributeDescriptionCount = 1,
    700             .pVertexAttributeDescriptions = &vertexInputAttributeDescription,
    701     };
    702     const VkGraphicsPipelineCreateInfo pipelineCreateInfo = {
    703             .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
    704             .pNext = nullptr,
    705             .flags = 0,
    706             .stageCount = 2,
    707             .pStages = shaderStages,
    708             .pVertexInputState = &vertexInputInfo,
    709             .pInputAssemblyState = &inputAssemblyInfo,
    710             .pTessellationState = nullptr,
    711             .pViewportState = &viewportInfo,
    712             .pRasterizationState = &rasterInfo,
    713             .pMultisampleState = &multisampleInfo,
    714             .pDepthStencilState = nullptr,
    715             .pColorBlendState = &colorBlendInfo,
    716             .pDynamicState = nullptr,
    717             .layout = mPipelineLayout,
    718             .renderPass = mRenderPass,
    719             .subpass = 0,
    720             .basePipelineHandle = VK_NULL_HANDLE,
    721             .basePipelineIndex = 0,
    722     };
    723     VK_CALL(vkCreateGraphicsPipelines(mDeviceInfo->device(), VK_NULL_HANDLE, 1, &pipelineCreateInfo,
    724                                       nullptr, &mPipeline));
    725 
    726     vkDestroyShaderModule(mDeviceInfo->device(), mVertexShader, nullptr);
    727     vkDestroyShaderModule(mDeviceInfo->device(), mFragmentShader, nullptr);
    728     mVertexShader = VK_NULL_HANDLE;
    729     mFragmentShader = VK_NULL_HANDLE;
    730 
    731     return VK_TEST_SUCCESS;
    732 }
    733 
    734 VkTestResult Renderer::init(JNIEnv* env, jobject jAssetManager) {
    735     mAssetManager = AAssetManager_fromJava(env, jAssetManager);
    736     ASSERT(mAssetManager);
    737 
    738     ASSERT(!createRenderPass());
    739 
    740     ASSERT(!createFrameBuffers());
    741 
    742     ASSERT(!createVertexBuffers());
    743 
    744     ASSERT(!createGraphicsPipeline());
    745 
    746     const VkCommandPoolCreateInfo commandPoolCreateInfo = {
    747             .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
    748             .pNext = nullptr,
    749             .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
    750             .queueFamilyIndex = mDeviceInfo->queueFamilyIndex(),
    751     };
    752     VK_CALL(vkCreateCommandPool(mDeviceInfo->device(), &commandPoolCreateInfo, nullptr,
    753                                 &mCommandPool));
    754 
    755     uint32_t swapchainLength = mSwapchainInfo->swapchainLength();
    756     mCommandBuffers.resize(swapchainLength, VK_NULL_HANDLE);
    757     const VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
    758             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
    759             .pNext = nullptr,
    760             .commandPool = mCommandPool,
    761             .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
    762             .commandBufferCount = swapchainLength,
    763     };
    764     VK_CALL(vkAllocateCommandBuffers(mDeviceInfo->device(), &commandBufferAllocateInfo,
    765                                      mCommandBuffers.data()));
    766 
    767     for (uint32_t i = 0; i < swapchainLength; ++i) {
    768         const VkCommandBufferBeginInfo commandBufferBeginInfo = {
    769                 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    770                 .pNext = nullptr,
    771                 .flags = 0,
    772                 .pInheritanceInfo = nullptr,
    773         };
    774         VK_CALL(vkBeginCommandBuffer(mCommandBuffers[i], &commandBufferBeginInfo));
    775 
    776         const VkClearValue clearVals = {
    777                 .color.float32[0] = 0.0f,
    778                 .color.float32[1] = 0.0f,
    779                 .color.float32[2] = 0.0f,
    780                 .color.float32[3] = 1.0f,
    781         };
    782         const VkRenderPassBeginInfo renderPassBeginInfo = {
    783                 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
    784                 .pNext = nullptr,
    785                 .renderPass = mRenderPass,
    786                 .framebuffer = mFramebuffers[i],
    787                 .renderArea =
    788                         {
    789                                 .offset =
    790                                         {
    791                                                 .x = 0,
    792                                                 .y = 0,
    793                                         },
    794                                 .extent = mSwapchainInfo->displaySize(),
    795                         },
    796                 .clearValueCount = 1,
    797                 .pClearValues = &clearVals,
    798         };
    799         vkCmdBeginRenderPass(mCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
    800 
    801         vkCmdBindPipeline(mCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, mPipeline);
    802 
    803         VkDeviceSize offset = 0;
    804         vkCmdBindVertexBuffers(mCommandBuffers[i], 0, 1, &mVertexBuffer, &offset);
    805 
    806         vkCmdPushConstants(mCommandBuffers[i], mPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
    807                            3 * sizeof(float), &fragData[0]);
    808         vkCmdDraw(mCommandBuffers[i], 4, 1, 0, 0);
    809 
    810         vkCmdPushConstants(mCommandBuffers[i], mPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
    811                            3 * sizeof(float), &fragData[3]);
    812         vkCmdDraw(mCommandBuffers[i], 4, 1, 2, 0);
    813 
    814         vkCmdPushConstants(mCommandBuffers[i], mPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
    815                            3 * sizeof(float), &fragData[6]);
    816         vkCmdDraw(mCommandBuffers[i], 4, 1, 6, 0);
    817 
    818         vkCmdPushConstants(mCommandBuffers[i], mPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
    819                            3 * sizeof(float), &fragData[9]);
    820         vkCmdDraw(mCommandBuffers[i], 4, 1, 8, 0);
    821 
    822         vkCmdEndRenderPass(mCommandBuffers[i]);
    823 
    824         VK_CALL(vkEndCommandBuffer(mCommandBuffers[i]));
    825     }
    826 
    827     const VkFenceCreateInfo fenceCreateInfo = {
    828             .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
    829             .pNext = nullptr,
    830             .flags = 0,
    831     };
    832     VK_CALL(vkCreateFence(mDeviceInfo->device(), &fenceCreateInfo, nullptr, &mFence));
    833 
    834     const VkSemaphoreCreateInfo semaphoreCreateInfo = {
    835             .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
    836             .pNext = nullptr,
    837             .flags = 0,
    838     };
    839     VK_CALL(vkCreateSemaphore(mDeviceInfo->device(), &semaphoreCreateInfo, nullptr, &mSemaphore));
    840 
    841     return VK_TEST_SUCCESS;
    842 }
    843 
    844 VkTestResult Renderer::drawFrame() {
    845     uint32_t nextIndex;
    846     VK_CALL(vkAcquireNextImageKHR(mDeviceInfo->device(), mSwapchainInfo->swapchain(), UINT64_MAX,
    847                                   mSemaphore, VK_NULL_HANDLE, &nextIndex));
    848 
    849     VK_CALL(vkResetFences(mDeviceInfo->device(), 1, &mFence));
    850 
    851     VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    852     const VkSubmitInfo submitInfo = {
    853             .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
    854             .pNext = nullptr,
    855             .waitSemaphoreCount = 1,
    856             .pWaitSemaphores = &mSemaphore,
    857             .pWaitDstStageMask = &waitStageMask,
    858             .commandBufferCount = 1,
    859             .pCommandBuffers = &mCommandBuffers[nextIndex],
    860             .signalSemaphoreCount = 0,
    861             .pSignalSemaphores = nullptr,
    862     };
    863     VK_CALL(vkQueueSubmit(mDeviceInfo->queue(), 1, &submitInfo, mFence))
    864 
    865     VK_CALL(vkWaitForFences(mDeviceInfo->device(), 1, &mFence, VK_TRUE, 100000000));
    866 
    867     const VkSwapchainKHR swapchain = mSwapchainInfo->swapchain();
    868     const VkPresentInfoKHR presentInfo = {
    869             .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
    870             .pNext = nullptr,
    871             .waitSemaphoreCount = 0,
    872             .pWaitSemaphores = nullptr,
    873             .swapchainCount = 1,
    874             .pSwapchains = &swapchain,
    875             .pImageIndices = &nextIndex,
    876             .pResults = nullptr,
    877     };
    878     VkResult ret = vkQueuePresentKHR(mDeviceInfo->queue(), &presentInfo);
    879     if (ret == VK_SUBOPTIMAL_KHR) {
    880         return VK_TEST_SUCCESS_SUBOPTIMAL;
    881     }
    882 
    883     return ret == VK_SUCCESS ? VK_TEST_SUCCESS : VK_TEST_ERROR;
    884 }
    885