| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gtest/gtest.h" |
| |
| #if defined(MAGMA_USE_SHIM) |
| #include "vulkan_shim.h" |
| #else |
| #include <vulkan/vulkan.h> |
| #endif |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <vector> |
| |
| #include "magma_util/dlog.h" |
| #include "magma_util/macros.h" |
| |
| namespace { |
| |
| class VulkanTest { |
| public: |
| static bool CheckExtensions(); |
| |
| bool Initialize(); |
| bool Exec(); |
| |
| private: |
| bool InitVulkan(); |
| bool InitImage(); |
| |
| bool is_initialized_ = false; |
| VkPhysicalDevice vk_physical_device_; |
| VkDevice vk_device_; |
| VkQueue vk_queue_; |
| VkImage vk_image_; |
| VkDeviceMemory vk_device_memory_; |
| VkCommandPool vk_command_pool_; |
| VkCommandBuffer vk_command_buffer_; |
| }; |
| |
| bool VulkanTest::CheckExtensions() |
| { |
| uint32_t count; |
| VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); |
| if (result != VK_SUCCESS) |
| return DRETF(false, "vkEnumerateInstanceExtensionProperties returned %d\n", result); |
| |
| std::vector<VkExtensionProperties> extension_properties(count); |
| result = vkEnumerateInstanceExtensionProperties(nullptr, &count, extension_properties.data()); |
| if (result != VK_SUCCESS) |
| return DRETF(false, "vkEnumerateInstanceExtensionProperties returned %d\n", result); |
| |
| uint32_t found_count = 0; |
| |
| for (auto& prop : extension_properties) { |
| DLOG("extension name %s version %u", prop.extensionName, prop.specVersion); |
| if (strcmp(prop.extensionName, VK_GOOGLE_IMAGE_USAGE_SCANOUT_EXTENSION_NAME) == 0) |
| found_count++; |
| } |
| |
| return found_count == 1; |
| } |
| |
| bool VulkanTest::Initialize() |
| { |
| if (is_initialized_) |
| return false; |
| |
| if (!InitVulkan()) |
| return DRETF(false, "failed to initialize Vulkan"); |
| |
| is_initialized_ = true; |
| |
| return true; |
| } |
| |
| bool VulkanTest::InitVulkan() |
| { |
| std::vector<const char*> enabled_extensions{VK_GOOGLE_IMAGE_USAGE_SCANOUT_EXTENSION_NAME}; |
| VkInstanceCreateInfo create_info{ |
| VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0, // VkInstanceCreateFlags flags; |
| nullptr, // const VkApplicationInfo* pApplicationInfo; |
| 0, // uint32_t enabledLayerCount; |
| nullptr, // const char* const* ppEnabledLayerNames; |
| static_cast<uint32_t>(enabled_extensions.size()), |
| enabled_extensions.data(), |
| }; |
| VkAllocationCallbacks* allocation_callbacks = nullptr; |
| VkInstance instance; |
| VkResult result; |
| |
| if ((result = vkCreateInstance(&create_info, allocation_callbacks, &instance)) != VK_SUCCESS) |
| return DRETF(false, "vkCreateInstance failed %d", result); |
| |
| DLOG("vkCreateInstance succeeded"); |
| |
| uint32_t physical_device_count; |
| if ((result = vkEnumeratePhysicalDevices(instance, &physical_device_count, nullptr)) != |
| VK_SUCCESS) |
| return DRETF(false, "vkEnumeratePhysicalDevices failed %d", result); |
| |
| if (physical_device_count < 1) |
| return DRETF(false, "unexpected physical_device_count %d", physical_device_count); |
| |
| DLOG("vkEnumeratePhysicalDevices returned count %d", physical_device_count); |
| |
| std::vector<VkPhysicalDevice> physical_devices(physical_device_count); |
| if ((result = vkEnumeratePhysicalDevices(instance, &physical_device_count, |
| physical_devices.data())) != VK_SUCCESS) |
| return DRETF(false, "vkEnumeratePhysicalDevices failed %d", result); |
| |
| for (auto device : physical_devices) { |
| VkPhysicalDeviceProperties properties; |
| vkGetPhysicalDeviceProperties(device, &properties); |
| DLOG("PHYSICAL DEVICE: %s", properties.deviceName); |
| DLOG("apiVersion 0x%x", properties.apiVersion); |
| DLOG("driverVersion 0x%x", properties.driverVersion); |
| DLOG("vendorID 0x%x", properties.vendorID); |
| DLOG("deviceID 0x%x", properties.deviceID); |
| DLOG("deviceType 0x%x", properties.deviceType); |
| } |
| |
| uint32_t queue_family_count; |
| vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[0], &queue_family_count, nullptr); |
| |
| if (queue_family_count < 1) |
| return DRETF(false, "invalid queue_family_count %d", queue_family_count); |
| |
| std::vector<VkQueueFamilyProperties> queue_family_properties(queue_family_count); |
| vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[0], &queue_family_count, |
| queue_family_properties.data()); |
| |
| int32_t queue_family_index = -1; |
| for (uint32_t i = 0; i < queue_family_count; i++) { |
| if (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { |
| queue_family_index = i; |
| break; |
| } |
| } |
| |
| if (queue_family_index < 0) |
| return DRETF(false, "couldn't find an appropriate queue"); |
| |
| float queue_priorities[1] = {0.0}; |
| |
| VkDeviceQueueCreateInfo queue_create_info = {.sType = |
| VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, |
| .pNext = nullptr, |
| .flags = 0, |
| .queueFamilyIndex = 0, |
| .queueCount = 1, |
| .pQueuePriorities = queue_priorities}; |
| VkDeviceCreateInfo createInfo = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, |
| .pNext = nullptr, |
| .flags = 0, |
| .queueCreateInfoCount = 1, |
| .pQueueCreateInfos = &queue_create_info, |
| .enabledLayerCount = 0, |
| .ppEnabledLayerNames = nullptr, |
| .enabledExtensionCount = 0, |
| .ppEnabledExtensionNames = nullptr, |
| .pEnabledFeatures = nullptr}; |
| VkDevice vkdevice; |
| |
| if ((result = vkCreateDevice(physical_devices[0], &createInfo, |
| nullptr /* allocationcallbacks */, &vkdevice)) != VK_SUCCESS) |
| return DRETF(false, "vkCreateDevice failed: %d", result); |
| |
| vk_physical_device_ = physical_devices[0]; |
| vk_device_ = vkdevice; |
| |
| vkGetDeviceQueue(vkdevice, queue_family_index, 0, &vk_queue_); |
| |
| return true; |
| } |
| |
| bool VulkanTest::Exec() |
| { |
| VkResult result; |
| |
| VkImageCreateInfo image_create_info = { |
| .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| .pNext = nullptr, |
| .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, |
| .imageType = VK_IMAGE_TYPE_2D, |
| .format = VK_FORMAT_R8G8B8A8_UNORM, |
| .extent = VkExtent3D{64, 64, 1}, |
| .mipLevels = 1, |
| .arrayLayers = 1, |
| .samples = VK_SAMPLE_COUNT_1_BIT, |
| .tiling = VK_IMAGE_TILING_OPTIMAL, |
| .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| VK_IMAGE_USAGE_SCANOUT_BIT_GOOGLE, |
| .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| .queueFamilyIndexCount = 0, // not used since not sharing |
| .pQueueFamilyIndices = nullptr, // not used since not sharing |
| .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| }; |
| |
| result = vkCreateImage(vk_device_, &image_create_info, nullptr, &vk_image_); |
| if (result != VK_SUCCESS) |
| return DRETF(false, "vkCreateImage failed: %d", result); |
| |
| DLOG("scanout tiling image created"); |
| |
| vkDestroyImage(vk_device_, vk_image_, nullptr); |
| |
| DLOG("scanout tiling image destroyed"); |
| |
| return true; |
| } |
| |
| TEST(VulkanExtension, Scanout) |
| { |
| ASSERT_TRUE(VulkanTest::CheckExtensions()); |
| VulkanTest test; |
| ASSERT_TRUE(test.Initialize()); |
| ASSERT_TRUE(test.Exec()); |
| } |
| |
| } // namespace |