Skip to content

Commit

Permalink
Finish the switch to late acquire, moving the swapchain responsibilit…
Browse files Browse the repository at this point in the history
…y to the queue runner.
  • Loading branch information
hrydgard committed Sep 17, 2022
1 parent a369252 commit 9d9f2c5
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 176 deletions.
167 changes: 167 additions & 0 deletions Common/GPU/Vulkan/VulkanQueueRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,171 @@ void VulkanQueueRunner::DestroyDeviceObjects() {
renderPasses_.Clear();
}

bool VulkanQueueRunner::CreateSwapchain(VkCommandBuffer cmdInit) {
VkResult res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, nullptr);
_dbg_assert_(res == VK_SUCCESS);

VkImage *swapchainImages = new VkImage[swapchainImageCount_];
res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, swapchainImages);
if (res != VK_SUCCESS) {
ERROR_LOG(G3D, "vkGetSwapchainImagesKHR failed");
delete[] swapchainImages;
return false;
}

for (uint32_t i = 0; i < swapchainImageCount_; i++) {
SwapchainImageData sc_buffer{};
sc_buffer.image = swapchainImages[i];

VkImageViewCreateInfo color_image_view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
color_image_view.format = vulkan_->GetSwapchainFormat();
color_image_view.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
color_image_view.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
color_image_view.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
color_image_view.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_image_view.subresourceRange.baseMipLevel = 0;
color_image_view.subresourceRange.levelCount = 1;
color_image_view.subresourceRange.baseArrayLayer = 0;
color_image_view.subresourceRange.layerCount = 1;
color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D;
color_image_view.flags = 0;
color_image_view.image = sc_buffer.image;

// We leave the images as UNDEFINED, there's no need to pre-transition them as
// the backbuffer renderpass starts out with them being auto-transitioned from UNDEFINED anyway.
// Also, turns out it's illegal to transition un-acquired images, thanks Hans-Kristian. See #11417.

res = vkCreateImageView(vulkan_->GetDevice(), &color_image_view, nullptr, &sc_buffer.view);
swapchainImages_.push_back(sc_buffer);
_dbg_assert_(res == VK_SUCCESS);
}
delete[] swapchainImages;

// Must be before InitBackbufferRenderPass.
if (InitDepthStencilBuffer(cmdInit)) {
InitBackbufferFramebuffers(vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
}
return true;
}


bool VulkanQueueRunner::InitBackbufferFramebuffers(int width, int height) {
VkResult res;
// We share the same depth buffer but have multiple color buffers, see the loop below.
VkImageView attachments[2] = { VK_NULL_HANDLE, depth_.view };

VkFramebufferCreateInfo fb_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RP_TYPE_BACKBUFFER);
fb_info.attachmentCount = 2;
fb_info.pAttachments = attachments;
fb_info.width = width;
fb_info.height = height;
fb_info.layers = 1;

framebuffers_.resize(swapchainImageCount_);

for (uint32_t i = 0; i < swapchainImageCount_; i++) {
attachments[0] = swapchainImages_[i].view;
res = vkCreateFramebuffer(vulkan_->GetDevice(), &fb_info, nullptr, &framebuffers_[i]);
_dbg_assert_(res == VK_SUCCESS);
if (res != VK_SUCCESS) {
framebuffers_.clear();
return false;
}
}

return true;
}

bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd) {
const VkFormat depth_format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat;
int aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
VkImageCreateInfo image_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = depth_format;
image_info.extent.width = vulkan_->GetBackbufferWidth();
image_info.extent.height = vulkan_->GetBackbufferHeight();
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.queueFamilyIndexCount = 0;
image_info.pQueueFamilyIndices = nullptr;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
image_info.flags = 0;

depth_.format = depth_format;

VmaAllocationCreateInfo allocCreateInfo{};
VmaAllocationInfo allocInfo{};

allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;

VkResult res = vmaCreateImage(vulkan_->Allocator(), &image_info, &allocCreateInfo, &depth_.image, &depth_.alloc, &allocInfo);
_dbg_assert_(res == VK_SUCCESS);
if (res != VK_SUCCESS)
return false;

vulkan_->SetDebugName(depth_.image, VK_OBJECT_TYPE_IMAGE, "BackbufferDepth");

TransitionImageLayout2(cmd, depth_.image, 0, 1,
aspectMask,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);

VkImageViewCreateInfo depth_view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
depth_view_info.image = depth_.image;
depth_view_info.format = depth_format;
depth_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
depth_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
depth_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
depth_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
depth_view_info.subresourceRange.aspectMask = aspectMask;
depth_view_info.subresourceRange.baseMipLevel = 0;
depth_view_info.subresourceRange.levelCount = 1;
depth_view_info.subresourceRange.baseArrayLayer = 0;
depth_view_info.subresourceRange.layerCount = 1;
depth_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
depth_view_info.flags = 0;

VkDevice device = vulkan_->GetDevice();

res = vkCreateImageView(device, &depth_view_info, NULL, &depth_.view);
_dbg_assert_(res == VK_SUCCESS);
if (res != VK_SUCCESS)
return false;

return true;
}


void VulkanQueueRunner::DestroyBackBuffers() {
for (auto &image : swapchainImages_) {
vulkan_->Delete().QueueDeleteImageView(image.view);
}
swapchainImages_.clear();

if (depth_.view) {
vulkan_->Delete().QueueDeleteImageView(depth_.view);
}
if (depth_.image) {
_dbg_assert_(depth_.alloc);
vulkan_->Delete().QueueDeleteImageAllocation(depth_.image, depth_.alloc);
}
depth_ = {};
for (uint32_t i = 0; i < framebuffers_.size(); i++) {
_dbg_assert_(framebuffers_[i] != VK_NULL_HANDLE);
vulkan_->Delete().QueueDeleteFramebuffer(framebuffers_[i]);
}
framebuffers_.clear();

INFO_LOG(G3D, "Backbuffers destroyed");
}

static VkAttachmentLoadOp ConvertLoadAction(VKRRenderPassLoadAction action) {
switch (action) {
case VKRRenderPassLoadAction::CLEAR: return VK_ATTACHMENT_LOAD_OP_CLEAR;
Expand Down Expand Up @@ -399,6 +564,8 @@ void VulkanQueueRunner::RunSteps(FrameData &frameData) {
_dbg_assert_(!frameData.hasPresentCommands);
if (!frameData.hasPresentCommands) {
frameData.hasPresentCommands = true;
frameData.AcquireNextImage(vulkan_);
SetBackbuffer(framebuffers_[frameData.curSwapchainImage], swapchainImages_[frameData.curSwapchainImage].image);
VkCommandBufferBeginInfo begin{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(frameData.presentCmd, &begin);
Expand Down
27 changes: 27 additions & 0 deletions Common/GPU/Vulkan/VulkanQueueRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,14 @@ class VulkanQueueRunner {
void CreateDeviceObjects();
void DestroyDeviceObjects();

// Swapchain
void DestroyBackBuffers();
bool CreateSwapchain(VkCommandBuffer cmdInit);

bool HasBackbuffers() const {
return !framebuffers_.empty();
}

// Get a render pass that's compatible with all our framebuffers.
// Note that it's precached, cannot look up in the map as this might be on another thread.
VKRRenderPass *GetCompatibleRenderPass() const {
Expand Down Expand Up @@ -298,6 +306,9 @@ class VulkanQueueRunner {
}

private:
bool InitBackbufferFramebuffers(int width, int height);
bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering.

VKRRenderPass *PerformBindFramebufferAsRenderTarget(const VKRStep &pass, VkCommandBuffer cmd);
void PerformRenderPass(const VKRStep &pass, VkCommandBuffer cmd);
void PerformCopy(const VKRStep &pass, VkCommandBuffer cmd);
Expand Down Expand Up @@ -352,4 +363,20 @@ class VulkanQueueRunner {
// Stored here to help reuse the allocation.

VulkanBarrier recordBarrier_;

// Swap chain management
struct SwapchainImageData {
VkImage image;
VkImageView view;
};
std::vector<VkFramebuffer> framebuffers_;
std::vector<SwapchainImageData> swapchainImages_;
uint32_t swapchainImageCount_ = 0;
struct DepthBufferInfo {
VkFormat format = VK_FORMAT_UNDEFINED;
VkImage image = VK_NULL_HANDLE;
VmaAllocation alloc = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
};
DepthBufferInfo depth_;
};
Loading

0 comments on commit 9d9f2c5

Please sign in to comment.