[Vulkan v2] Present framebuffer clearing

This commit is contained in:
Triang3l 2019-08-11 23:53:24 +03:00
parent 490f3de853
commit 470f9946d6
2 changed files with 192 additions and 30 deletions

View File

@ -9,8 +9,10 @@
#include "xenia/ui/vk/vulkan_context.h"
#include <cstdlib>
#include <vector>
#include "xenia/base/cvar.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/platform.h"
@ -18,6 +20,9 @@
#include "xenia/ui/vk/vulkan_util.h"
#include "xenia/ui/window.h"
DEFINE_bool(vk_random_clear_color, false,
"Randomize presentation framebuffer clear color.", "Vulkan");
namespace xe {
namespace ui {
namespace vk {
@ -32,6 +37,7 @@ bool VulkanContext::Initialize() {
auto instance = provider->GetInstance();
auto physical_device = provider->GetPhysicalDevice();
auto device = provider->GetDevice();
auto graphics_queue_family = provider->GetGraphicsQueueFamily();
context_lost_ = false;
@ -98,8 +104,7 @@ bool VulkanContext::Initialize() {
// FIXME(Triang3l): Separate present queue not supported - would require
// deferring VkDevice creation because vkCreateDevice needs all used queues.
VkBool32 surface_supported = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device,
provider->GetGraphicsQueueFamily(),
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, graphics_queue_family,
surface_, &surface_supported);
if (!surface_supported) {
XELOGE(
@ -156,14 +161,17 @@ bool VulkanContext::Initialize() {
return false;
}
// Prefer RGB8.
surface_format_ = surface_formats[0];
for (uint32_t i = 0; i < surface_format_count; ++i) {
surface_format_ = surface_formats[i];
if (surface_format_.format == VK_FORMAT_UNDEFINED) {
const VkSurfaceFormatKHR& surface_format = surface_formats[i];
if (surface_format.format == VK_FORMAT_UNDEFINED) {
surface_format_.format = VK_FORMAT_R8G8B8A8_UNORM;
surface_format_.colorSpace = surface_format.colorSpace;
break;
}
if (surface_format_.format == VK_FORMAT_R8G8B8A8_UNORM ||
surface_format_.format == VK_FORMAT_B8G8R8A8_UNORM) {
if (surface_format.format == VK_FORMAT_R8G8B8A8_UNORM ||
surface_format.format == VK_FORMAT_B8G8R8A8_UNORM) {
surface_format_ = surface_format;
break;
}
}
@ -215,7 +223,93 @@ bool VulkanContext::Initialize() {
return false;
}
// TODO(Triang3l): Presentation render pass.
// Create the render pass for drawing to the presentation image.
VkAttachmentDescription render_pass_attachment;
render_pass_attachment.flags = 0;
render_pass_attachment.format = surface_format_.format;
render_pass_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
render_pass_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
render_pass_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
render_pass_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
render_pass_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
render_pass_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
render_pass_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference render_pass_attachment_reference;
render_pass_attachment_reference.attachment = 0;
render_pass_attachment_reference.layout =
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription render_pass_subpass = {};
render_pass_subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
render_pass_subpass.colorAttachmentCount = 1;
render_pass_subpass.pColorAttachments = &render_pass_attachment_reference;
VkSubpassDependency render_pass_dependencies[2];
render_pass_dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
render_pass_dependencies[0].dstSubpass = 0;
render_pass_dependencies[0].srcStageMask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
render_pass_dependencies[0].dstStageMask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
render_pass_dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
render_pass_dependencies[0].dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
render_pass_dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
render_pass_dependencies[1].srcSubpass = 0;
render_pass_dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
render_pass_dependencies[1].srcStageMask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
render_pass_dependencies[1].dstStageMask =
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
render_pass_dependencies[1].srcAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
render_pass_dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
render_pass_dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo render_pass_create_info;
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
render_pass_create_info.pNext = nullptr;
render_pass_create_info.flags = 0;
render_pass_create_info.attachmentCount = 1;
render_pass_create_info.pAttachments = &render_pass_attachment;
render_pass_create_info.subpassCount = 1;
render_pass_create_info.pSubpasses = &render_pass_subpass;
render_pass_create_info.dependencyCount =
uint32_t(xe::countof(render_pass_dependencies));
render_pass_create_info.pDependencies = render_pass_dependencies;
if (vkCreateRenderPass(device, &render_pass_create_info, nullptr,
&present_render_pass_) != VK_SUCCESS) {
XELOGE("Failed to create the presentation Vulkan render pass");
Shutdown();
return false;
}
// Create the command buffers for drawing to the presentation image.
VkCommandPoolCreateInfo command_pool_create_info;
command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
command_pool_create_info.pNext = nullptr;
command_pool_create_info.flags =
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
command_pool_create_info.queueFamilyIndex = graphics_queue_family;
if (vkCreateCommandPool(device, &command_pool_create_info, nullptr,
&present_command_pool_) != VK_SUCCESS) {
XELOGE("Failed to create the presentation Vulkan command pool");
Shutdown();
return false;
}
VkCommandBufferAllocateInfo command_buffer_allocate_info;
command_buffer_allocate_info.sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.pNext = nullptr;
command_buffer_allocate_info.commandPool = present_command_pool_;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
command_buffer_allocate_info.commandBufferCount =
uint32_t(xe::countof(present_command_buffers_));
if (vkAllocateCommandBuffers(device, &command_buffer_allocate_info,
present_command_buffers_) != VK_SUCCESS) {
XELOGE("Failed to create the presentation Vulkan command buffers");
Shutdown();
return false;
}
// Initialize the immediate mode drawer if not offscreen.
immediate_drawer_ = std::make_unique<VulkanImmediateDrawer>(this);
@ -247,6 +341,11 @@ void VulkanContext::Shutdown() {
immediate_drawer_.reset();
util::DestroyAndNullHandle(vkDestroyCommandPool, device,
present_command_pool_);
util::DestroyAndNullHandle(vkDestroyRenderPass, device,
present_render_pass_);
util::DestroyAndNullHandle(vkDestroySemaphore, device,
semaphore_draw_complete_);
util::DestroyAndNullHandle(vkDestroySemaphore, device,
@ -263,8 +362,7 @@ void VulkanContext::Shutdown() {
void VulkanContext::DestroySwapchainImages() {
auto device = GetVulkanProvider()->GetDevice();
for (auto& image : swapchain_images_) {
// TODO(Triang3l): Destroy the framebuffer.
// vkDestroyFramebuffer(device, image.framebuffer, nullptr);
vkDestroyFramebuffer(device, image.framebuffer, nullptr);
vkDestroyImageView(device, image.image_view, nullptr);
}
swapchain_images_.clear();
@ -399,33 +497,49 @@ void VulkanContext::BeginSwap() {
return;
}
swapchain_images_.reserve(swapchain_image_count);
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
image_view_create_info.pNext = nullptr;
image_view_create_info.flags = 0;
image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
image_view_create_info.format = surface_format_.format;
image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.subresourceRange.aspectMask =
VK_IMAGE_ASPECT_COLOR_BIT;
image_view_create_info.subresourceRange.baseMipLevel = 0;
image_view_create_info.subresourceRange.levelCount = 1;
image_view_create_info.subresourceRange.baseArrayLayer = 0;
image_view_create_info.subresourceRange.layerCount = 1;
VkFramebufferCreateInfo framebuffer_create_info;
framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebuffer_create_info.pNext = nullptr;
framebuffer_create_info.flags = 0;
framebuffer_create_info.renderPass = present_render_pass_;
framebuffer_create_info.attachmentCount = 1;
framebuffer_create_info.width = swapchain_extent_.width;
framebuffer_create_info.height = swapchain_extent_.height;
framebuffer_create_info.layers = 1;
for (uint32_t i = 0; i < swapchain_image_count; ++i) {
SwapchainImage swapchain_image;
swapchain_image.image = swapchain_images[i];
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
image_view_create_info.pNext = nullptr;
image_view_create_info.flags = 0;
image_view_create_info.image = swapchain_image.image;
image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
image_view_create_info.format = surface_format_.format;
image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.subresourceRange.aspectMask =
VK_IMAGE_ASPECT_COLOR_BIT;
image_view_create_info.subresourceRange.baseMipLevel = 0;
image_view_create_info.subresourceRange.levelCount = 1;
image_view_create_info.subresourceRange.baseArrayLayer = 0;
image_view_create_info.subresourceRange.layerCount = 1;
if (vkCreateImageView(device, &image_view_create_info, nullptr,
&swapchain_image.image_view) != VK_SUCCESS) {
XELOGE("Failed to create a Vulkan swapchain image view");
context_lost_ = true;
return;
}
// TODO(Triang3l): Create the VkFramebuffer.
framebuffer_create_info.pAttachments = &swapchain_image.image_view;
if (vkCreateFramebuffer(device, &framebuffer_create_info, nullptr,
&swapchain_image.framebuffer) != VK_SUCCESS) {
XELOGE("Failed to create a Vulkan swapchain framebuffer");
vkDestroyImageView(device, swapchain_image.image_view, nullptr);
context_lost_ = true;
return;
}
// Add now so it's complete if DestroySwapchainImages is called.
swapchain_images_.push_back(swapchain_image);
}
@ -438,7 +552,43 @@ void VulkanContext::BeginSwap() {
return;
}
}
// TODO(Triang3l): Begin the pass.
// Begin drawing to the present image.
VkCommandBuffer command_buffer = GetPresentCommandBuffer();
VkCommandBufferBeginInfo command_buffer_begin_info;
command_buffer_begin_info.sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
command_buffer_begin_info.pNext = nullptr;
command_buffer_begin_info.flags =
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
command_buffer_begin_info.pInheritanceInfo = nullptr;
vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
// TODO(Triang3l): Handle vkBeginCommandBuffer failure.
VkClearValue clear_value;
if (cvars::vk_random_clear_color) {
clear_value.color.float32[0] =
rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
clear_value.color.float32[1] = 1.0f;
clear_value.color.float32[2] = 0.0f;
} else {
clear_value.color.float32[0] = 238.0f / 255.0f;
clear_value.color.float32[1] = 238.0f / 255.0f;
clear_value.color.float32[2] = 238.0f / 255.0f;
}
clear_value.color.float32[3] = 1.0f;
VkRenderPassBeginInfo render_pass_begin_info;
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin_info.pNext = nullptr;
render_pass_begin_info.renderPass = present_render_pass_;
render_pass_begin_info.framebuffer =
swapchain_images_[swapchain_acquired_image_index_].framebuffer;
render_pass_begin_info.renderArea.offset.x = 0;
render_pass_begin_info.renderArea.offset.y = 0;
render_pass_begin_info.renderArea.extent = swapchain_extent_;
render_pass_begin_info.clearValueCount = 1;
render_pass_begin_info.pClearValues = &clear_value;
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info,
VK_SUBPASS_CONTENTS_INLINE);
}
}
@ -451,16 +601,18 @@ void VulkanContext::EndSwap() {
auto queue = provider->GetGraphicsQueue();
if (target_window_ != nullptr) {
// TODO(Triang3l): End the pass.
// Present.
VkCommandBuffer command_buffer = GetPresentCommandBuffer();
vkCmdEndRenderPass(command_buffer);
vkEndCommandBuffer(command_buffer);
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = nullptr;
submit_info.pWaitDstStageMask = nullptr;
submit_info.commandBufferCount = 0;
submit_info.pCommandBuffers = nullptr;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &semaphore_draw_complete_;
if (vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {

View File

@ -54,6 +54,12 @@ class VulkanContext : public GraphicsContext {
uint32_t GetCurrentQueueFrame() { return current_queue_frame_; }
void AwaitAllFramesCompletion();
const VkSurfaceFormatKHR& GetSurfaceFormat() const { return surface_format_; }
VkCommandBuffer GetPresentCommandBuffer() const {
return present_command_buffers_[current_queue_frame_];
}
private:
friend class VulkanProvider;
@ -87,6 +93,10 @@ class VulkanContext : public GraphicsContext {
VkSemaphore semaphore_present_complete_ = VK_NULL_HANDLE;
VkSemaphore semaphore_draw_complete_ = VK_NULL_HANDLE;
VkRenderPass present_render_pass_ = VK_NULL_HANDLE;
VkCommandPool present_command_pool_ = VK_NULL_HANDLE;
VkCommandBuffer present_command_buffers_[kQueuedFrames] = {};
std::unique_ptr<VulkanImmediateDrawer> immediate_drawer_ = nullptr;
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;