mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
A multitude of fixes. The UI now works correctly, though of course ingame still broken.
This commit is contained in:
parent
0a0494ef8e
commit
833916a906
@ -47,9 +47,9 @@ bool VulkanPushBuffer::AddBuffer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make validation happy.
|
||||
VkMemoryRequirements reqs;
|
||||
vkGetBufferMemoryRequirements(device_, info.buffer, &reqs);
|
||||
|
||||
// TODO: We really should use memoryTypeIndex here..
|
||||
|
||||
// Okay, that's the buffer. Now let's allocate some memory for it.
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "VulkanRenderManager.h"
|
||||
#include "VulkanContext.h"
|
||||
|
||||
void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color) {
|
||||
void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color) {
|
||||
VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
ici.arrayLayers = 1;
|
||||
ici.mipLevels = 1;
|
||||
@ -74,10 +74,17 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKImage &img, int w
|
||||
}
|
||||
|
||||
VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan) {
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
semaphoreCreateInfo.flags = 0;
|
||||
VkResult res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, NULL, &acquireSemaphore_);
|
||||
assert(res == VK_SUCCESS);
|
||||
res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, NULL, &renderingCompleteSemaphore);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
for (int i = 0; i < vulkan_->GetInflightFrames(); i++) {
|
||||
VkCommandPoolCreateInfo cmd_pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
|
||||
cmd_pool_info.queueFamilyIndex = vulkan_->GetGraphicsQueueFamilyIndex();
|
||||
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
|
||||
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
VkResult res = vkCreateCommandPool(vulkan_->GetDevice(), &cmd_pool_info, nullptr, &frameData_[i].cmdPool);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
@ -93,23 +100,23 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan
|
||||
frameData_[i].initCmd = cmdBuf[1];
|
||||
frameData_[i].fence = vulkan_->CreateFence(true); // So it can be instantly waited on
|
||||
}
|
||||
}
|
||||
|
||||
VkSwapchainKHR swapChain = vulkan_->GetSwapchain();
|
||||
VkResult res = vkGetSwapchainImagesKHR(vulkan->GetDevice(), swapChain, &swapchainImageCount, nullptr);
|
||||
void VulkanRenderManager::CreateBackbuffers() {
|
||||
VkResult res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, nullptr);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
ILOG("Vulkan swapchain image count: %d", swapchainImageCount);
|
||||
ILOG("Vulkan swapchain image count: %d", swapchainImageCount_);
|
||||
|
||||
VkImage* swapchainImages = new VkImage[swapchainImageCount];
|
||||
assert(swapchainImages);
|
||||
res = vkGetSwapchainImagesKHR(vulkan->GetDevice(), swapChain, &swapchainImageCount, swapchainImages);
|
||||
VkImage* swapchainImages = new VkImage[swapchainImageCount_];
|
||||
res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, swapchainImages);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
VkCommandBuffer cmdInit = frameData_[0].initCmd;
|
||||
frameData_[0].hasInitCommands = true;
|
||||
VkCommandBuffer cmdInit = GetInitCmd();
|
||||
|
||||
for (uint32_t i = 0; i < swapchainImageCount; i++) {
|
||||
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();
|
||||
@ -124,8 +131,7 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan
|
||||
color_image_view.subresourceRange.layerCount = 1;
|
||||
color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
color_image_view.flags = 0;
|
||||
|
||||
sc_buffer.image = swapchainImages[i];
|
||||
color_image_view.image = sc_buffer.image;
|
||||
|
||||
// Pre-set them to PRESENT_SRC_KHR, as the first thing we do after acquiring
|
||||
// in image to render to will be to transition them away from that.
|
||||
@ -135,33 +141,36 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
||||
0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
|
||||
|
||||
color_image_view.image = sc_buffer.image;
|
||||
|
||||
res = vkCreateImageView(vulkan_->GetDevice(),
|
||||
&color_image_view, NULL, &sc_buffer.view);
|
||||
swapchainImages_.push_back(sc_buffer);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
delete[] swapchainImages;
|
||||
current_buffer = 0;
|
||||
current_buffer = -1;
|
||||
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
semaphoreCreateInfo.flags = 0;
|
||||
res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, NULL, &acquireSemaphore_);
|
||||
assert(res == VK_SUCCESS);
|
||||
res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, NULL, &renderingCompleteSemaphore);
|
||||
assert(res == VK_SUCCESS);
|
||||
InitDepthStencilBuffer(cmdInit); // Must be before InitBackbufferRenderPass.
|
||||
InitBackbufferRenderPass(); // Must be before InitFramebuffers.
|
||||
InitBackbufferFramebuffers(vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
|
||||
InitRenderpasses();
|
||||
curWidth_ = -1;
|
||||
curHeight_ = -1;
|
||||
}
|
||||
|
||||
InitDepthStencilBuffer(cmdInit);
|
||||
InitSurfaceRenderPass();
|
||||
void VulkanRenderManager::DestroyBackbuffers() {
|
||||
VkDevice device = vulkan_->GetDevice();
|
||||
for (uint32_t i = 0; i < swapchainImageCount_; i++) {
|
||||
vulkan_->Delete().QueueDeleteImageView(swapchainImages_[i].view);
|
||||
}
|
||||
vulkan_->Delete().QueueDeleteImageView(depth_.view);
|
||||
vulkan_->Delete().QueueDeleteImage(depth_.image);
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(depth_.mem);
|
||||
swapchainImages_.clear();
|
||||
}
|
||||
|
||||
VulkanRenderManager::~VulkanRenderManager() {
|
||||
VkDevice device = vulkan_->GetDevice();
|
||||
for (uint32_t i = 0; i < swapchainImageCount; i++) {
|
||||
vkDestroyImageView(device, swapchainImages_[i].view, nullptr);
|
||||
}
|
||||
swapchainImages_.clear();
|
||||
vulkan_->WaitUntilQueueIdle();
|
||||
vkDestroySemaphore(device, acquireSemaphore_, nullptr);
|
||||
vkDestroySemaphore(device, renderingCompleteSemaphore, nullptr);
|
||||
for (int i = 0; i < vulkan_->GetInflightFrames(); i++) {
|
||||
@ -176,58 +185,64 @@ VulkanRenderManager::~VulkanRenderManager() {
|
||||
vkDestroyFramebuffer(device, framebuffers_[i], nullptr);
|
||||
}
|
||||
framebuffers_.clear();
|
||||
for (int i = 0; i < 9; i++) {
|
||||
vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]);
|
||||
for (int i = 0; i < ARRAY_SIZE(renderPasses_); i++) {
|
||||
// vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]);
|
||||
vkDestroyRenderPass(device, renderPasses_[i], nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Activate this code.
|
||||
void VulkanRenderManager::ThreadFunc() {
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
condVar_.wait(lock);
|
||||
if (steps_.size()) {
|
||||
stepsOnThread_ = std::move(steps_);
|
||||
}
|
||||
// ...
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderManager::BeginFrameWrites() {
|
||||
vulkan_->BeginFrame();
|
||||
void VulkanRenderManager::BeginFrame() {
|
||||
|
||||
VkDevice device = vulkan_->GetDevice();
|
||||
|
||||
FrameData &frameData = frameData_[vulkan_->GetCurFrame()];
|
||||
|
||||
// Get the index of the next available swapchain image, and a semaphore to block command buffer execution on.
|
||||
// Now, I wonder if we should do this early in the frame or late? Right now we do it early, which should be fine.
|
||||
VkResult res = vkAcquireNextImageKHR(device, vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, (VkFence)VK_NULL_HANDLE, ¤t_buffer);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// Make sure the very last command buffer from the frame before the previous has been fully executed.
|
||||
vkWaitForFences(device, 1, &frameData.fence, true, UINT64_MAX);
|
||||
vkResetFences(device, 1, &frameData.fence);
|
||||
|
||||
// Reset both command buffers in one fell swoop.
|
||||
// Note that on the first frame, there might already be commands so don't reset in that case.
|
||||
if (!frameData.hasInitCommands) {
|
||||
vkResetCommandPool(vulkan_->GetDevice(), frameData.cmdPool, 0);
|
||||
}
|
||||
// Must be after the fence - this performs deletes.
|
||||
vulkan_->BeginFrame();
|
||||
|
||||
VkCommandBufferBeginInfo begin = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
begin.pInheritanceInfo = nullptr;
|
||||
VkResult res = vkBeginCommandBuffer(frameData.mainCmd, &begin);
|
||||
insideFrame_ = true;
|
||||
}
|
||||
|
||||
VkCommandBuffer VulkanRenderManager::GetInitCmd() {
|
||||
FrameData &frameData = frameData_[vulkan_->GetCurFrame()];
|
||||
if (!frameData_->hasInitCommands) {
|
||||
// assert(insideFrame_ || firstFrame_);
|
||||
|
||||
int curFrame = vulkan_->GetCurFrame();
|
||||
FrameData &frameData = frameData_[curFrame];
|
||||
if (!frameData.hasInitCommands) {
|
||||
VkCommandBufferBeginInfo begin = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
begin.pInheritanceInfo = nullptr;
|
||||
VkResult res = vkBeginCommandBuffer(frameData.mainCmd, &begin);
|
||||
VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin);
|
||||
assert(res == VK_SUCCESS);
|
||||
frameData.hasInitCommands = true;
|
||||
}
|
||||
return frameData_[vulkan_->GetCurFrame()].initCmd;
|
||||
}
|
||||
|
||||
// After flush. Should probably be part of it?
|
||||
void VulkanRenderManager::EndFrame() {
|
||||
insideFrame_ = false;
|
||||
|
||||
FrameData &frame = frameData_[vulkan_->GetCurFrame()];
|
||||
|
||||
TransitionToPresent(frame.mainCmd, swapchainImages_[current_buffer].image);
|
||||
|
||||
VkResult res = vkEndCommandBuffer(frame.mainCmd);
|
||||
@ -243,10 +258,13 @@ void VulkanRenderManager::EndFrame() {
|
||||
vkEndCommandBuffer(frame.initCmd);
|
||||
cmdBufs.push_back(frame.initCmd);
|
||||
frame.hasInitCommands = false;
|
||||
ILOG("Frame %d had init commands", vulkan_->GetCurFrame());
|
||||
}
|
||||
|
||||
cmdBufs.push_back(frame.mainCmd);
|
||||
|
||||
vulkan_->EndFrame();
|
||||
|
||||
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = &acquireSemaphore_;
|
||||
@ -259,74 +277,63 @@ void VulkanRenderManager::EndFrame() {
|
||||
res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, frame.fence);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
VkSwapchainKHR swapchain = vulkan_->GetSwapchain();
|
||||
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||
present.swapchainCount = 1;
|
||||
VkSwapchainKHR swapchain = vulkan_->GetSwapchain();
|
||||
present.pSwapchains = &swapchain;
|
||||
present.pImageIndices = ¤t_buffer;
|
||||
present.pWaitSemaphores = &renderingCompleteSemaphore;
|
||||
present.waitSemaphoreCount = 1;
|
||||
present.pResults = nullptr;
|
||||
|
||||
res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present);
|
||||
// TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
|
||||
// return codes
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
vulkan_->EndFrame();
|
||||
}
|
||||
|
||||
void VulkanRenderManager::Sync() {
|
||||
|
||||
}
|
||||
|
||||
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb) {
|
||||
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil) {
|
||||
VKRStep *step = new VKRStep{ VKRStepType::RENDER };
|
||||
// This is what queues up new passes, and can end previous ones.
|
||||
step->render.framebuffer = fb;
|
||||
step->render.color = color;
|
||||
step->render.depthStencil = depth;
|
||||
step->render.clearColor = clearColor;
|
||||
step->render.clearDepth = clearDepth;
|
||||
step->render.clearStencil = clearStencil;
|
||||
steps_.push_back(step);
|
||||
curRenderStep_ = step;
|
||||
curWidth_ = fb ? fb->width : vulkan_->GetBackbufferWidth();
|
||||
curHeight_ = fb ? fb->height : vulkan_->GetBackbufferHeight();
|
||||
}
|
||||
|
||||
|
||||
void VulkanRenderManager::BeginSurfaceRenderPass(VkCommandBuffer cmd, VkClearValue clear_value) {
|
||||
FrameData &frame = frameData_[vulkan_->GetCurFrame()];
|
||||
VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp_begin.renderPass = backbufferRenderPass_;
|
||||
rp_begin.framebuffer = framebuffers_[current_buffer];
|
||||
rp_begin.renderArea.offset.x = 0;
|
||||
rp_begin.renderArea.offset.y = 0;
|
||||
rp_begin.renderArea.extent.width = curWidth_;
|
||||
rp_begin.renderArea.extent.height = curHeight_;
|
||||
rp_begin.clearValueCount = 1;
|
||||
rp_begin.pClearValues = &clear_value;
|
||||
vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
void VulkanRenderManager::EndSurfaceRenderPass(VkCommandBuffer cmd) {
|
||||
// ILOG("VulkanContext::EndSurfaceRenderPass");
|
||||
vkCmdEndRenderPass(cmd);
|
||||
}
|
||||
|
||||
void VulkanRenderManager::InitFramebuffers() {
|
||||
void VulkanRenderManager::InitBackbufferFramebuffers(int width, int height) {
|
||||
VkResult U_ASSERT_ONLY res;
|
||||
VkImageView attachments[1];
|
||||
// We share the same depth buffer but have multiple color buffers, see the loop below.
|
||||
VkImageView attachments[2] = { VK_NULL_HANDLE, depth_.view };
|
||||
|
||||
ILOG("InitFramebuffers: %dx%d", curWidth_, curHeight_);
|
||||
ILOG("InitFramebuffers: %dx%d", width, height);
|
||||
VkFramebufferCreateInfo fb_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
fb_info.renderPass = backbufferRenderPass_;
|
||||
fb_info.attachmentCount = 1;
|
||||
fb_info.attachmentCount = 2;
|
||||
fb_info.pAttachments = attachments;
|
||||
fb_info.width = curWidth_;
|
||||
fb_info.height = curHeight_;
|
||||
fb_info.width = width;
|
||||
fb_info.height = height;
|
||||
fb_info.layers = 1;
|
||||
|
||||
framebuffers_.resize(swapchainImageCount);
|
||||
framebuffers_.resize(swapchainImageCount_);
|
||||
|
||||
for (uint32_t i = 0; i < swapchainImageCount; i++) {
|
||||
for (uint32_t i = 0; i < swapchainImageCount_; i++) {
|
||||
attachments[0] = swapchainImages_[i].view;
|
||||
res = vkCreateFramebuffer(vulkan_->GetDevice(), &fb_info, nullptr, &framebuffers_[i]);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderManager::InitSurfaceRenderPass() {
|
||||
void VulkanRenderManager::InitBackbufferRenderPass() {
|
||||
VkResult U_ASSERT_ONLY res;
|
||||
|
||||
VkAttachmentDescription attachments[2];
|
||||
@ -340,6 +347,7 @@ void VulkanRenderManager::InitSurfaceRenderPass() {
|
||||
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].flags = 0;
|
||||
|
||||
assert(depth_.format != VK_FORMAT_UNDEFINED);
|
||||
attachments[1].format = depth_.format;
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
@ -392,8 +400,8 @@ void VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) {
|
||||
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 = curWidth_;
|
||||
image_info.extent.height = curHeight_;
|
||||
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;
|
||||
@ -509,64 +517,70 @@ void VulkanRenderManager::InitRenderpasses() {
|
||||
rp.pDependencies = nullptr;
|
||||
|
||||
for (int depth = 0; depth < 3; depth++) {
|
||||
switch ((RenderPassAction)depth) {
|
||||
case RenderPassAction::CLEAR: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break;
|
||||
case RenderPassAction::KEEP: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break;
|
||||
case RenderPassAction::DONT_CARE: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break;
|
||||
switch ((VKRRenderPassAction)depth) {
|
||||
case VKRRenderPassAction::CLEAR: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break;
|
||||
case VKRRenderPassAction::KEEP: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break;
|
||||
case VKRRenderPassAction::DONT_CARE: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break;
|
||||
}
|
||||
for (int color = 0; color < 3; color++) {
|
||||
switch ((RenderPassAction)color) {
|
||||
case RenderPassAction::CLEAR: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break;
|
||||
case RenderPassAction::KEEP: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break;
|
||||
case RenderPassAction::DONT_CARE: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break;
|
||||
switch ((VKRRenderPassAction)color) {
|
||||
case VKRRenderPassAction::CLEAR: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break;
|
||||
case VKRRenderPassAction::KEEP: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break;
|
||||
case VKRRenderPassAction::DONT_CARE: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break;
|
||||
}
|
||||
vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &renderPasses_[RPIndex((RenderPassAction)color, (RenderPassAction)depth)]);
|
||||
vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &renderPasses_[RPIndex((VKRRenderPassAction)color, (VKRRenderPassAction)depth)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderManager::BeginRenderPass() {
|
||||
std::unique_lock<std::mutex> lock(rpLock_);
|
||||
|
||||
VKRStep *pass = new VKRStep(VKStepType::RENDER);
|
||||
pass->stepType = VKStepType::RENDER;
|
||||
steps_.push_back(pass);
|
||||
curStep_ = steps_.back();
|
||||
}
|
||||
|
||||
void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask) {
|
||||
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
// If this is the first drawing command, merge it into the pass.
|
||||
if (curStep_->render.numDraws == 0) {
|
||||
curStep_->render.clearColor = clearColor;
|
||||
curStep_->render.clearDepth = clearZ;
|
||||
curStep_->render.clearStencil = clearStencil;
|
||||
curStep_->render.color = (clearMask & VK_IMAGE_ASPECT_COLOR_BIT) ? RenderPassAction::CLEAR : RenderPassAction::KEEP;
|
||||
curStep_->render.depthStencil = (clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) ? RenderPassAction::CLEAR : RenderPassAction::KEEP;
|
||||
if (curRenderStep_->render.numDraws == 0) {
|
||||
curRenderStep_->render.clearColor = clearColor;
|
||||
curRenderStep_->render.clearDepth = clearZ;
|
||||
curRenderStep_->render.clearStencil = clearStencil;
|
||||
curRenderStep_->render.color = (clearMask & VK_IMAGE_ASPECT_COLOR_BIT) ? VKRRenderPassAction::CLEAR : VKRRenderPassAction::KEEP;
|
||||
curRenderStep_->render.depthStencil = (clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) ? VKRRenderPassAction::CLEAR : VKRRenderPassAction::KEEP;
|
||||
} else {
|
||||
VkRenderData data{ VkRenderCmd::CLEAR };
|
||||
VkRenderData data{ VKRRenderCommand::CLEAR };
|
||||
data.clear.clearColor = clearColor;
|
||||
data.clear.clearZ = clearZ;
|
||||
data.clear.clearStencil = clearStencil;
|
||||
data.clear.clearMask = clearMask;
|
||||
curStep_->commands.push_back(data);
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPoint) {
|
||||
FrameData &frameData = frameData_[vulkan_->GetCurFrame()];
|
||||
EndCurrentRenderpass(frameData.mainCmd);
|
||||
void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, int aspectMask) {
|
||||
VKRStep *step = new VKRStep{ VKRStepType::COPY };
|
||||
step->copy.aspectMask = aspectMask;
|
||||
step->copy.src = src;
|
||||
step->copy.srcRect = srcRect;
|
||||
step->copy.dst = dst;
|
||||
step->copy.dstPos = dstPos;
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
steps_.push_back(step);
|
||||
curRenderStep_ = nullptr;
|
||||
}
|
||||
|
||||
void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkFilter filter) {
|
||||
FrameData &frameData = frameData_[vulkan_->GetCurFrame()];
|
||||
EndCurrentRenderpass(frameData.mainCmd);
|
||||
void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, int aspectMask, VkFilter filter) {
|
||||
VKRStep *step = new VKRStep{ VKRStepType::BLIT };
|
||||
step->blit.aspectMask = aspectMask;
|
||||
step->blit.src = src;
|
||||
step->blit.srcRect = srcRect;
|
||||
step->blit.dst = dst;
|
||||
step->blit.dstRect = dstRect;
|
||||
step->blit.filter = filter;
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
steps_.push_back(step);
|
||||
curRenderStep_ = nullptr;
|
||||
}
|
||||
|
||||
VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment) {
|
||||
// Should just mark the dependency and return the image.
|
||||
for (int i = 0; i < (int)steps_.size() - 1; i++) {
|
||||
if (steps_[i]->stepType == VKStepType::RENDER && steps_[i]->render.framebuffer == fb) {
|
||||
if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == fb) {
|
||||
if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED)
|
||||
steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
else
|
||||
@ -598,37 +612,43 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in
|
||||
|
||||
void VulkanRenderManager::Flush() {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(rpLock_);
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
stepsOnThread_ = std::move(steps_);
|
||||
curRenderStep_ = nullptr;
|
||||
}
|
||||
|
||||
FrameData &frameData = frameData_[vulkan_->GetCurFrame()];
|
||||
VkCommandBuffer cmd = frameData.mainCmd;
|
||||
|
||||
VkDevice device = vulkan_->GetDevice();
|
||||
|
||||
// Get the index of the next available swapchain image, and a semaphore to block command buffer execution on.
|
||||
// Now, I wonder if we should do this early in the frame or late? Right now we do it early, which should be fine.
|
||||
VkResult res = vkAcquireNextImageKHR(device, vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, VK_NULL_HANDLE, ¤t_buffer);
|
||||
VkCommandBuffer cmd = frameData.mainCmd;
|
||||
|
||||
VkCommandBufferBeginInfo begin = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
begin.pInheritanceInfo = nullptr;
|
||||
VkResult res = vkBeginCommandBuffer(cmd, &begin);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
// TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
|
||||
// return codes
|
||||
// TODO: Is it best to do this here, or combine with some other transition, or just do it right before the backbuffer bind-for-render?
|
||||
assert(res == VK_SUCCESS);
|
||||
TransitionFromPresent(frameData.mainCmd, swapchainImages_[current_buffer].image);
|
||||
TransitionFromPresent(cmd, swapchainImages_[current_buffer].image);
|
||||
|
||||
// Optimizes renderpasses, then sequences them.
|
||||
for (int i = 0; i < stepsOnThread_.size(); i++) {
|
||||
const VKRStep &step = *stepsOnThread_[i];
|
||||
switch (step.stepType) {
|
||||
case VKStepType::RENDER:
|
||||
case VKRStepType::RENDER:
|
||||
PerformRenderPass(step, cmd);
|
||||
break;
|
||||
case VKStepType::COPY:
|
||||
case VKRStepType::COPY:
|
||||
PerformCopy(step, cmd);
|
||||
break;
|
||||
case VKStepType::BLIT:
|
||||
case VKRStepType::BLIT:
|
||||
PerformBlit(step, cmd);
|
||||
break;
|
||||
case VKStepType::READBACK:
|
||||
case VKRStepType::READBACK:
|
||||
// PerformReadback
|
||||
break;
|
||||
}
|
||||
@ -642,25 +662,25 @@ void VulkanRenderManager::PerformRenderPass(const VKRStep &step, VkCommandBuffer
|
||||
auto &commands = step.commands;
|
||||
for (const auto &c : commands) {
|
||||
switch (c.cmd) {
|
||||
case VkRenderCmd::VIEWPORT:
|
||||
case VKRRenderCommand::VIEWPORT:
|
||||
vkCmdSetViewport(cmd, 0, 1, &c.viewport.vp);
|
||||
break;
|
||||
|
||||
case VkRenderCmd::SCISSOR:
|
||||
case VKRRenderCommand::SCISSOR:
|
||||
vkCmdSetScissor(cmd, 0, 1, &c.scissor.scissor);
|
||||
break;
|
||||
|
||||
case VkRenderCmd::BLEND:
|
||||
case VKRRenderCommand::BLEND:
|
||||
vkCmdSetBlendConstants(cmd, c.blendColor.color);
|
||||
break;
|
||||
|
||||
case VkRenderCmd::STENCIL:
|
||||
case VKRRenderCommand::STENCIL:
|
||||
vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilWriteMask);
|
||||
vkCmdSetStencilCompareMask(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilCompareMask);
|
||||
vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilRef);
|
||||
break;
|
||||
|
||||
case VkRenderCmd::DRAW_INDEXED:
|
||||
case VKRRenderCommand::DRAW_INDEXED:
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.drawIndexed.pipeline);
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.drawIndexed.pipelineLayout, 0, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets);
|
||||
vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, VK_INDEX_TYPE_UINT16);
|
||||
@ -668,14 +688,14 @@ void VulkanRenderManager::PerformRenderPass(const VKRStep &step, VkCommandBuffer
|
||||
vkCmdDrawIndexed(cmd, c.drawIndexed.count, c.drawIndexed.instances, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case VkRenderCmd::DRAW:
|
||||
case VKRRenderCommand::DRAW:
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.draw.pipeline);
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.draw.pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets);
|
||||
vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset);
|
||||
vkCmdDraw(cmd, c.draw.count, 1, 0, 0);
|
||||
break;
|
||||
|
||||
case VkRenderCmd::CLEAR:
|
||||
case VKRRenderCommand::CLEAR:
|
||||
{
|
||||
int numAttachments = 0;
|
||||
VkClearRect rc{};
|
||||
@ -735,21 +755,19 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st
|
||||
if (framebuf == curFramebuffer_) {
|
||||
if (framebuf == 0)
|
||||
Crash();
|
||||
if (!curRenderPass_)
|
||||
Crash();
|
||||
|
||||
// If we're asking to clear, but already bound, we'll just keep it bound but send a clear command.
|
||||
// We will try to avoid this as much as possible.
|
||||
VkClearAttachment clear[2]{};
|
||||
int count = 0;
|
||||
if (step.render.color == RenderPassAction::CLEAR) {
|
||||
if (step.render.color == VKRRenderPassAction::CLEAR) {
|
||||
clear[count].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
Uint8x4ToFloat4(clear[count].clearValue.color.float32, step.render.clearColor);
|
||||
clear[count].colorAttachment = 0;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (step.render.depthStencil == RenderPassAction::CLEAR) {
|
||||
if (step.render.depthStencil == VKRRenderPassAction::CLEAR) {
|
||||
clear[count].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
clear[count].clearValue.depthStencil.depth = step.render.clearDepth;
|
||||
clear[count].clearValue.depthStencil.stencil = step.render.clearStencil;
|
||||
@ -765,13 +783,6 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st
|
||||
return;
|
||||
}
|
||||
|
||||
// OK, we're switching framebuffers.
|
||||
if (curRenderPass_) {
|
||||
vkCmdEndRenderPass(cmd);
|
||||
curRenderPass_ = VK_NULL_HANDLE;
|
||||
curFramebuffer_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkRenderPass renderPass;
|
||||
int numClearVals = 0;
|
||||
VkClearValue clearVal[2];
|
||||
@ -835,18 +846,20 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st
|
||||
|
||||
renderPass = renderPasses_[RPIndex(step.render.color, step.render.depthStencil)];
|
||||
// ILOG("Switching framebuffer to FBO (fc=%d, cmd=%x, rp=%x)", frameNum_, (int)(uintptr_t)cmd_, (int)(uintptr_t)renderPass);
|
||||
if (step.render.color == RenderPassAction::CLEAR) {
|
||||
if (step.render.color == VKRRenderPassAction::CLEAR) {
|
||||
Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor);
|
||||
numClearVals = 1;
|
||||
}
|
||||
if (step.render.depthStencil == RenderPassAction::CLEAR) {
|
||||
if (step.render.depthStencil == VKRRenderPassAction::CLEAR) {
|
||||
clearVal[1].depthStencil.depth = step.render.clearDepth;
|
||||
clearVal[1].depthStencil.stencil = step.render.clearStencil;
|
||||
numClearVals = 2;
|
||||
}
|
||||
} else {
|
||||
renderPass = GetSurfaceRenderPass();
|
||||
numClearVals = 2;
|
||||
numClearVals = 2; // We don't bother with a depth buffer here.
|
||||
clearVal[1].depthStencil.depth = 0.0f;
|
||||
clearVal[1].depthStencil.stencil = 0;
|
||||
}
|
||||
|
||||
VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
@ -859,17 +872,9 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st
|
||||
rp_begin.clearValueCount = numClearVals;
|
||||
rp_begin.pClearValues = numClearVals ? clearVal : nullptr;
|
||||
vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
curFramebuffer_ = framebuf;
|
||||
curRenderPass_ = renderPass;
|
||||
curWidth_ = w;
|
||||
curHeight_ = h;
|
||||
}
|
||||
|
||||
void VulkanRenderManager::EndCurrentRenderpass(VkCommandBuffer cmd) {
|
||||
if (curRenderPass_) {
|
||||
vkCmdEndRenderPass(cmd);
|
||||
curRenderPass_ = nullptr;
|
||||
}
|
||||
curFramebuffer_ = framebuf;
|
||||
}
|
||||
|
||||
void VulkanRenderManager::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
@ -1020,7 +1025,7 @@ void VulkanRenderManager::PerformBlit(const VKRStep &step, VkCommandBuffer cmd)
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderManager::SetupTransitionToTransferSrc(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect) {
|
||||
void VulkanRenderManager::SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect) {
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = img.layout;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
@ -1049,7 +1054,7 @@ void VulkanRenderManager::SetupTransitionToTransferSrc(VKImage &img, VkImageMemo
|
||||
img.layout = barrier.newLayout;
|
||||
}
|
||||
|
||||
void VulkanRenderManager::SetupTransitionToTransferDst(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect) {
|
||||
void VulkanRenderManager::SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect) {
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = img.layout;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
// The cool thing is that you can Flush on a different thread than you record the commands on!
|
||||
|
||||
enum class VkRenderCmd : uint8_t {
|
||||
enum class VKRRenderCommand : uint8_t {
|
||||
STENCIL,
|
||||
BLEND,
|
||||
VIEWPORT,
|
||||
@ -26,7 +26,7 @@ enum class VkRenderCmd : uint8_t {
|
||||
};
|
||||
|
||||
struct VkRenderData {
|
||||
VkRenderCmd cmd;
|
||||
VKRRenderCommand cmd;
|
||||
union {
|
||||
struct {
|
||||
VkPipeline pipeline;
|
||||
@ -82,7 +82,7 @@ struct VkRenderData {
|
||||
};
|
||||
};
|
||||
|
||||
enum class VKStepType : uint8_t {
|
||||
enum class VKRStepType : uint8_t {
|
||||
RENDER,
|
||||
COPY,
|
||||
BLIT,
|
||||
@ -91,21 +91,21 @@ enum class VKStepType : uint8_t {
|
||||
|
||||
class VKRFramebuffer;
|
||||
|
||||
enum class RenderPassAction {
|
||||
enum class VKRRenderPassAction {
|
||||
DONT_CARE,
|
||||
CLEAR,
|
||||
KEEP,
|
||||
};
|
||||
|
||||
struct VKRStep {
|
||||
VKRStep(VKStepType _type) : stepType(_type) {}
|
||||
VKStepType stepType;
|
||||
VKRStep(VKRStepType _type) : stepType(_type) {}
|
||||
VKRStepType stepType;
|
||||
std::vector<VkRenderData> commands;
|
||||
union {
|
||||
struct {
|
||||
VKRFramebuffer *framebuffer;
|
||||
RenderPassAction color;
|
||||
RenderPassAction depthStencil;
|
||||
VKRRenderPassAction color;
|
||||
VKRRenderPassAction depthStencil;
|
||||
uint32_t clearColor;
|
||||
float clearDepth;
|
||||
int clearStencil;
|
||||
@ -137,13 +137,13 @@ struct VKRStep {
|
||||
|
||||
// Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine
|
||||
// to let them have individual non-pooled allocations. Until it's not fine. We'll see.
|
||||
struct VKImage {
|
||||
struct VKRImage {
|
||||
VkImage image;
|
||||
VkImageView imageView;
|
||||
VkDeviceMemory memory;
|
||||
VkImageLayout layout;
|
||||
};
|
||||
void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color);
|
||||
void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color);
|
||||
|
||||
class VKRFramebuffer {
|
||||
public:
|
||||
@ -175,15 +175,14 @@ public:
|
||||
vulkan_->Delete().QueueDeleteImageView(depth.imageView);
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(color.memory);
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory);
|
||||
|
||||
vulkan_->Delete().QueueDeleteFramebuffer(framebuf);
|
||||
}
|
||||
|
||||
int numShadows = 1; // TODO: Support this.
|
||||
|
||||
VkFramebuffer framebuf = VK_NULL_HANDLE;
|
||||
VKImage color{};
|
||||
VKImage depth{};
|
||||
VKRImage color{};
|
||||
VKRImage depth{};
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
@ -199,43 +198,41 @@ public:
|
||||
void ThreadFunc();
|
||||
|
||||
// Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again.
|
||||
void BeginFrameWrites();
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
|
||||
void BindFramebufferAsRenderTarget(VKRFramebuffer *fb);
|
||||
void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil);
|
||||
VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment);
|
||||
|
||||
void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPoint);
|
||||
void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkFilter filter);
|
||||
|
||||
void BeginRenderPass();
|
||||
void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, int aspectMask);
|
||||
void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, int aspectMask, VkFilter filter);
|
||||
|
||||
void SetViewport(const VkViewport &vp) {
|
||||
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
|
||||
VkRenderData data{ VkRenderCmd::VIEWPORT };
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
VkRenderData data{ VKRRenderCommand::VIEWPORT };
|
||||
data.viewport.vp = vp;
|
||||
curStep_->commands.push_back(data);
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetScissor(const VkRect2D &rc) {
|
||||
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
|
||||
VkRenderData data{ VkRenderCmd::SCISSOR };
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
VkRenderData data{ VKRRenderCommand::SCISSOR };
|
||||
data.scissor.scissor = rc;
|
||||
curStep_->commands.push_back(data);
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetBlendFactor(float color[4]) {
|
||||
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
|
||||
VkRenderData data{ VkRenderCmd::BLEND };
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
VkRenderData data{ VKRRenderCommand::BLEND };
|
||||
CopyFloat4(data.blendColor.color, color);
|
||||
curStep_->commands.push_back(data);
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask);
|
||||
|
||||
void Draw(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count) {
|
||||
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
|
||||
VkRenderData data{ VkRenderCmd::DRAW };
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
VkRenderData data{ VKRRenderCommand::DRAW };
|
||||
data.draw.count = count;
|
||||
data.draw.pipeline = pipeline;
|
||||
data.draw.pipelineLayout = layout;
|
||||
@ -245,13 +242,13 @@ public:
|
||||
data.draw.numUboOffsets = numUboOffsets;
|
||||
for (int i = 0; i < numUboOffsets; i++)
|
||||
data.draw.uboOffsets[i] = uboOffsets[i];
|
||||
curStep_->commands.push_back(data);
|
||||
curStep_->render.numDraws++;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
curRenderStep_->render.numDraws++;
|
||||
}
|
||||
|
||||
void DrawIndexed(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, VkIndexType indexType) {
|
||||
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
|
||||
VkRenderData data{ VkRenderCmd::DRAW_INDEXED };
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
VkRenderData data{ VKRRenderCommand::DRAW_INDEXED };
|
||||
data.drawIndexed.count = count;
|
||||
data.drawIndexed.pipeline = pipeline;
|
||||
data.drawIndexed.pipelineLayout = layout;
|
||||
@ -264,8 +261,8 @@ public:
|
||||
for (int i = 0; i < numUboOffsets; i++)
|
||||
data.drawIndexed.uboOffsets[i] = uboOffsets[i];
|
||||
data.drawIndexed.indexType = indexType;
|
||||
curStep_->commands.push_back(data);
|
||||
curStep_->render.numDraws++;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
curRenderStep_->render.numDraws++;
|
||||
}
|
||||
|
||||
// Can run on a different thread! Just make sure to use BeginFrameWrites.
|
||||
@ -274,12 +271,6 @@ public:
|
||||
// Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot).
|
||||
void Sync();
|
||||
|
||||
std::vector<VKRStep *> steps_;
|
||||
std::vector<VKRStep *> stepsOnThread_;
|
||||
std::mutex rpLock_;
|
||||
|
||||
VKRStep *curStep_;
|
||||
|
||||
VkCommandBuffer GetInitCmd();
|
||||
VkCommandBuffer GetSurfaceCommandBuffer() {
|
||||
return frameData_[vulkan_->GetCurFrame()].mainCmd;
|
||||
@ -291,33 +282,27 @@ public:
|
||||
return renderPasses_[i];
|
||||
}
|
||||
|
||||
void CreateBackbuffers();
|
||||
void DestroyBackbuffers();
|
||||
|
||||
private:
|
||||
void InitFramebuffers();
|
||||
void InitSurfaceRenderPass();
|
||||
void InitBackbufferFramebuffers(int width, int height);
|
||||
void InitBackbufferRenderPass();
|
||||
void InitRenderpasses();
|
||||
void InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering.
|
||||
|
||||
// The surface render pass is special because it has to acquire the backbuffer, and may thus "block".
|
||||
// Use the returned command buffer to enqueue commands that render to the backbuffer.
|
||||
// To render to other buffers first, you can submit additional commandbuffers using QueueBeforeSurfaceRender(cmd).
|
||||
void BeginSurfaceRenderPass(VkCommandBuffer cmd, VkClearValue clear_value);
|
||||
// May eventually need the ability to break and resume the backbuffer render pass in a few rare cases.
|
||||
void EndSurfaceRenderPass(VkCommandBuffer cmd);
|
||||
|
||||
void EndCurrentRenderpass(VkCommandBuffer cmd);
|
||||
|
||||
void PerformBindFramebufferAsRenderTarget(const VKRStep &pass, VkCommandBuffer cmd);
|
||||
|
||||
void PerformRenderPass(const VKRStep &pass, VkCommandBuffer cmd);
|
||||
void PerformCopy(const VKRStep &pass, VkCommandBuffer cmd);
|
||||
void PerformBlit(const VKRStep &pass, VkCommandBuffer cmd);
|
||||
|
||||
inline int RPIndex(RenderPassAction color, RenderPassAction depth) {
|
||||
inline int RPIndex(VKRRenderPassAction color, VKRRenderPassAction depth) {
|
||||
return (int)depth * 3 + (int)color;
|
||||
}
|
||||
|
||||
static void SetupTransitionToTransferSrc(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect);
|
||||
static void SetupTransitionToTransferDst(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect);
|
||||
static void SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect);
|
||||
static void SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect);
|
||||
|
||||
VkSemaphore acquireSemaphore_;
|
||||
VkSemaphore renderingCompleteSemaphore;
|
||||
@ -331,17 +316,21 @@ private:
|
||||
VkCommandPool cmdPool;
|
||||
VkCommandBuffer initCmd;
|
||||
VkCommandBuffer mainCmd;
|
||||
bool hasInitCommands;
|
||||
bool hasInitCommands = false;
|
||||
};
|
||||
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
int curWidth_;
|
||||
int curHeight_;
|
||||
bool insideFrame_ = false;
|
||||
|
||||
std::thread submissionThread;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable condVar_;
|
||||
std::vector<VKRStep *> steps_;
|
||||
std::vector<VKRStep *> stepsOnThread_;
|
||||
VKRStep *curRenderStep_;
|
||||
|
||||
struct SwapchainImageData {
|
||||
VkImage image;
|
||||
@ -349,18 +338,17 @@ private:
|
||||
};
|
||||
std::vector<VkFramebuffer> framebuffers_;
|
||||
std::vector<SwapchainImageData> swapchainImages_;
|
||||
uint32_t swapchainImageCount;
|
||||
uint32_t swapchainImageCount_;
|
||||
uint32_t current_buffer = 0;
|
||||
VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE;
|
||||
struct DepthBufferInfo {
|
||||
VkFormat format;
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkDeviceMemory mem = VK_NULL_HANDLE;
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
};
|
||||
DepthBufferInfo depth_;
|
||||
// Interpreter state
|
||||
VkFramebuffer curFramebuffer_;
|
||||
VkRenderPass curRenderPass_;
|
||||
|
||||
VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE;
|
||||
// VkRenderPass curRenderPass_ = VK_NULL_HANDLE;
|
||||
};
|
||||
|
@ -128,7 +128,6 @@ static VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugRep
|
||||
return false;
|
||||
if (msgCode == 64) // Another useless perf warning that will be seen less and less as we optimize - vkCmdClearAttachments() issued on command buffer object 0x00000195296C6D40 prior to any Draw Cmds. It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.
|
||||
return false;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string msg = message.str();
|
||||
OutputDebugStringA(msg.c_str());
|
||||
@ -197,10 +196,13 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
|
||||
draw_ = Draw::T3DCreateVulkanContext(g_Vulkan);
|
||||
bool success = draw_->CreatePresets();
|
||||
assert(success); // Doesn't fail, we include the compiler.
|
||||
return success;
|
||||
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowsVulkanContext::Shutdown() {
|
||||
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
|
||||
|
||||
delete draw_;
|
||||
draw_ = nullptr;
|
||||
|
||||
|
@ -699,6 +699,8 @@ VKContext::VKContext(VulkanContext *vulkan)
|
||||
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
frame_[i].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024);
|
||||
VkResult res = vkCreateDescriptorPool(device_, &dp, nullptr, &frame_[i].descriptorPool);
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
// binding 0 - uniform data
|
||||
@ -746,7 +748,7 @@ VKContext::~VKContext() {
|
||||
}
|
||||
|
||||
void VKContext::BeginFrame() {
|
||||
renderManager_.BeginFrameWrites();
|
||||
renderManager_.BeginFrame();
|
||||
|
||||
FrameData &frame = frame_[frameNum_];
|
||||
push_ = frame.pushBuffer;
|
||||
@ -758,8 +760,6 @@ void VKContext::BeginFrame() {
|
||||
frame.descSets_.clear();
|
||||
VkResult result = vkResetDescriptorPool(device_, frame.descriptorPool, 0);
|
||||
assert(result == VK_SUCCESS);
|
||||
|
||||
SetScissorRect(0, 0, pixel_xres, pixel_yres);
|
||||
}
|
||||
|
||||
void VKContext::WaitRenderCompletion(Framebuffer *fbo) {
|
||||
@ -1146,7 +1146,7 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) {
|
||||
VkDeviceSize offsets[1] = { vbBindOffset };
|
||||
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
|
||||
|
||||
renderManager_.Draw(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, vbBindOffset, vertexCount);
|
||||
renderManager_.Draw(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount);
|
||||
}
|
||||
|
||||
// TODO: We should avoid this function as much as possible, instead use renderpass on-load clearing.
|
||||
@ -1279,20 +1279,32 @@ void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y
|
||||
VKFramebuffer *src = (VKFramebuffer *)srcfb;
|
||||
VKFramebuffer *dst = (VKFramebuffer *)dstfb;
|
||||
|
||||
renderManager_.CopyFramebuffer(src->GetFB(), VkRect2D{ {x, y}, {(uint32_t)width, (uint32_t)height } }, dst->GetFB(), VkOffset2D{ dstX, dstY });
|
||||
int aspectMask = 0;
|
||||
if (channelBits & FBChannel::FB_COLOR_BIT) aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
renderManager_.CopyFramebuffer(src->GetFB(), VkRect2D{ {x, y}, {(uint32_t)width, (uint32_t)height } }, dst->GetFB(), VkOffset2D{ dstX, dstY }, aspectMask);
|
||||
}
|
||||
|
||||
bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) {
|
||||
VKFramebuffer *src = (VKFramebuffer *)srcfb;
|
||||
VKFramebuffer *dst = (VKFramebuffer *)dstfb;
|
||||
|
||||
renderManager_.BlitFramebuffer(src->GetFB(), VkRect2D{ {srcX1, srcY1}, {(uint32_t)(srcX2 - srcX1), (uint32_t)(srcY2 - srcY1) } }, dst->GetFB(), VkRect2D{ {dstX1, dstY1}, {(uint32_t)(dstX2 - dstX1), (uint32_t)(dstY2 - dstY1) } }, filter == FB_BLIT_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
|
||||
int aspectMask = 0;
|
||||
if (channelBits & FBChannel::FB_COLOR_BIT) aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
renderManager_.BlitFramebuffer(src->GetFB(), VkRect2D{ {srcX1, srcY1}, {(uint32_t)(srcX2 - srcX1), (uint32_t)(srcY2 - srcY1) } }, dst->GetFB(), VkRect2D{ {dstX1, dstY1}, {(uint32_t)(dstX2 - dstX1), (uint32_t)(dstY2 - dstY1) } }, aspectMask, filter == FB_BLIT_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) {
|
||||
VKFramebuffer *fb = (VKFramebuffer *)fbo;
|
||||
renderManager_.BindFramebufferAsRenderTarget(fb->GetFB());
|
||||
VKRRenderPassAction color = (VKRRenderPassAction)rp.color; // same values.
|
||||
VKRRenderPassAction depth = (VKRRenderPassAction)rp.color; // same values.
|
||||
renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, rp.clearColor, rp.clearDepth, rp.clearStencil);
|
||||
}
|
||||
|
||||
// color must be 0, for now.
|
||||
@ -1324,8 +1336,10 @@ void VKContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {
|
||||
void VKContext::HandleEvent(Event ev, int width, int height, void *param1, void *param2) {
|
||||
switch (ev) {
|
||||
case Event::LOST_BACKBUFFER:
|
||||
renderManager_.DestroyBackbuffers();
|
||||
break;
|
||||
case Event::GOT_BACKBUFFER:
|
||||
renderManager_.CreateBackbuffers();
|
||||
break;
|
||||
}
|
||||
// Noop
|
||||
|
Loading…
Reference in New Issue
Block a user