| // Copyright 2020 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 "vulkan_window.h" |
| |
| #include <stdio.h> |
| |
| #include "tests/common/utils.h" |
| #include "tests/common/vk_app_state.h" |
| #include "tests/common/vk_device_surface_info.h" |
| #include "tests/common/vk_surface.h" |
| #include "tests/common/vk_swapchain.h" |
| #include "tests/common/vk_swapchain_queue.h" |
| #include "vulkan_device.h" |
| |
| bool |
| VulkanWindow::init(VulkanDevice * device, const VulkanWindow::Config & config) |
| { |
| device_ = device; |
| |
| // Allocate display surface, and determine whether it's possible to directly |
| // render to the swapchain with it. |
| const vk_surface_config_t surface_config = { |
| .instance = device->vk_instance(), |
| .physical_device = device->vk_physical_device(), |
| .queue_family_index = device->graphics_queue_family(), |
| .allocator = device->vk_allocator(), |
| .window_width = config.window_width, |
| .window_height = config.window_height, |
| .window_title = config.app_name, |
| }; |
| surface_ = vk_surface_create(&surface_config); |
| if (!surface_) |
| return false; // NOTE: error message already sent to stderr. |
| |
| VkSurfaceKHR window_surface = vk_surface_get_surface_khr(surface_); |
| VkImageUsageFlags image_usage = 0; |
| |
| // Check that rendering directly to the swapchain is supported |
| |
| if (config.require_swapchain_image_shader_storage) |
| image_usage |= VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
| |
| if (config.require_swapchain_transfers) |
| image_usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
| |
| VkFormat wanted_format = config.wanted_format; |
| |
| const vk_swapchain_config_t swapchain_config = { |
| .instance = device_->vk_instance(), |
| .device = device_->vk_device(), |
| .physical_device = device_->vk_physical_device(), |
| .allocator = device_->vk_allocator(), |
| |
| .present_queue_family = device_->graphics_queue_family(), |
| .present_queue_index = 0, |
| |
| .surface_khr = window_surface, |
| |
| .max_frames = 3, |
| .pixel_format = wanted_format, |
| .disable_vsync = config.disable_vsync, |
| .image_usage_flags = image_usage, |
| .staging_mode = config.require_swapchain_image_shader_storage |
| ? VK_SWAPCHAIN_STAGING_MODE_IF_NEEDED |
| : VK_SWAPCHAIN_STAGING_MODE_NONE, |
| }; |
| swapchain_ = vk_swapchain_create(&swapchain_config); |
| |
| // Sanity check. |
| VkSurfaceFormatKHR surface_format = vk_swapchain_get_format(swapchain_); |
| if (wanted_format != VK_FORMAT_UNDEFINED && surface_format.format != wanted_format) |
| { |
| fprintf(stderr, "WARNING: Could not find wanted pixel format, colors may be wrong!\n"); |
| } |
| |
| if (config.verbose) |
| vk_swapchain_print(swapchain_); |
| |
| info_.image_count = vk_swapchain_get_image_count(swapchain_); |
| info_.extent = vk_swapchain_get_extent(swapchain_); |
| info_.surface = window_surface; |
| info_.surface_format = surface_format; |
| |
| if (config.enable_swapchain_queue) |
| { |
| vk_swapchain_queue_config_t queue_config = { |
| .swapchain = swapchain_, |
| .queue_family = device_->graphics_queue_family(), |
| .queue_index = 0u, |
| .device = device_->vk_device(), |
| .allocator = device_->vk_allocator(), |
| |
| .enable_framebuffers = config.enable_framebuffers, |
| .sync_semaphores_count = config.sync_semaphores_count, |
| }; |
| swapchain_queue_ = vk_swapchain_queue_create(&queue_config); |
| } |
| |
| return true; |
| } |
| |
| VulkanWindow::~VulkanWindow() |
| { |
| if (swapchain_queue_) |
| vk_swapchain_queue_destroy(swapchain_queue_); |
| |
| if (swapchain_) |
| vk_swapchain_destroy(swapchain_); |
| |
| if (surface_) |
| vk_surface_destroy(surface_); |
| } |
| |
| bool |
| VulkanWindow::acquireSwapchainImage() |
| { |
| ASSERT_MSG(!swapchain_queue_, "Calling this method requires enable_swapchain_queue=false"); |
| return vk_swapchain_acquire_next_image(swapchain_, &image_index_); |
| } |
| |
| void |
| VulkanWindow::presentSwapchainImage() |
| { |
| ASSERT_MSG(!swapchain_queue_, "Calling this method requires enable_swapchain_queue=false"); |
| vk_swapchain_present_image(swapchain_); |
| } |
| |
| bool |
| VulkanWindow::acquireSwapchainQueueImage() |
| { |
| ASSERT_MSG(swapchain_queue_, "Calling this method requires enable_swapchain_queue=true"); |
| |
| swapchain_queue_image_ = vk_swapchain_queue_acquire_next_image(swapchain_queue_); |
| if (!swapchain_queue_image_) |
| return false; |
| |
| image_index_ = vk_swapchain_queue_get_index(swapchain_queue_); |
| return true; |
| } |
| |
| void |
| VulkanWindow::presentSwapchainQueueImage() |
| { |
| ASSERT_MSG(swapchain_queue_, "Calling this method requires enable_swapchain_queue=true"); |
| vk_swapchain_queue_submit_and_present_image(swapchain_queue_); |
| } |
| |
| bool |
| VulkanWindow::handleUserEvents() |
| { |
| return vk_surface_poll_events(surface_); |
| } |
| |
| void |
| VulkanWindow::waitIdle() |
| { |
| vkDeviceWaitIdle(device_->vk_device()); |
| } |