A multitude of fixes. The UI now works correctly, though of course ingame still broken.

This commit is contained in:
Henrik Rydgård 2017-08-22 12:55:30 +02:00
parent 0a0494ef8e
commit 833916a906
5 changed files with 241 additions and 232 deletions

View File

@ -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.

View File

@ -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, &current_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 = &current_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, &current_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;

View File

@ -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;
};

View File

@ -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;

View File

@ -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