diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index 58a8fac99a..07fc66510c 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -249,6 +249,7 @@
+
@@ -321,6 +322,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index c3ae5eea9e..413f08cb8b 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -75,7 +75,12 @@
-
+
+ Vulkan
+
+
+ Vulkan
+
@@ -139,7 +144,12 @@
-
+
+ Vulkan
+
+
+ Vulkan
+
@@ -155,4 +165,4 @@
{c14d66ef-5f7c-4565-975a-72774e7ccfb9}
-
+
\ No newline at end of file
diff --git a/Common/Vulkan/VulkanQueueRunner.cpp b/Common/Vulkan/VulkanQueueRunner.cpp
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Common/Vulkan/VulkanQueueRunner.h b/Common/Vulkan/VulkanQueueRunner.h
new file mode 100644
index 0000000000..9da875a95c
--- /dev/null
+++ b/Common/Vulkan/VulkanQueueRunner.h
@@ -0,0 +1,6 @@
+#pragma once
+
+class VulkanQueueRunner {
+public:
+
+};
\ No newline at end of file
diff --git a/Common/Vulkan/VulkanRenderManager.cpp b/Common/Vulkan/VulkanRenderManager.cpp
index eab92174aa..a2e2d7fd1f 100644
--- a/Common/Vulkan/VulkanRenderManager.cpp
+++ b/Common/Vulkan/VulkanRenderManager.cpp
@@ -141,13 +141,12 @@ void VulkanRenderManager::CreateBackbuffers() {
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
- res = vkCreateImageView(vulkan_->GetDevice(),
- &color_image_view, NULL, &sc_buffer.view);
+ res = vkCreateImageView(vulkan_->GetDevice(), &color_image_view, NULL, &sc_buffer.view);
swapchainImages_.push_back(sc_buffer);
assert(res == VK_SUCCESS);
}
delete[] swapchainImages;
- current_buffer = -1;
+ curSwapchainImage_ = -1;
InitDepthStencilBuffer(cmdInit); // Must be before InitBackbufferRenderPass.
InitBackbufferRenderPass(); // Must be before InitFramebuffers.
@@ -186,7 +185,6 @@ VulkanRenderManager::~VulkanRenderManager() {
}
framebuffers_.clear();
for (int i = 0; i < ARRAY_SIZE(renderPasses_); i++) {
- // vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]);
vkDestroyRenderPass(device, renderPasses_[i], nullptr);
}
}
@@ -201,14 +199,13 @@ void VulkanRenderManager::ThreadFunc() {
}
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);
+ VkResult res = vkAcquireNextImageKHR(device, vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, (VkFence)VK_NULL_HANDLE, &curSwapchainImage_);
assert(res == VK_SUCCESS);
// Make sure the very last command buffer from the frame before the previous has been fully executed.
@@ -243,7 +240,7 @@ void VulkanRenderManager::EndFrame() {
FrameData &frame = frameData_[vulkan_->GetCurFrame()];
- TransitionToPresent(frame.mainCmd, swapchainImages_[current_buffer].image);
+ TransitionToPresent(frame.mainCmd, swapchainImages_[curSwapchainImage_].image);
VkResult res = vkEndCommandBuffer(frame.mainCmd);
assert(res == VK_SUCCESS);
@@ -281,7 +278,7 @@ void VulkanRenderManager::EndFrame() {
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
present.swapchainCount = 1;
present.pSwapchains = &swapchain;
- present.pImageIndices = ¤t_buffer;
+ present.pImageIndices = &curSwapchainImage_;
present.pWaitSemaphores = &renderingCompleteSemaphore;
present.waitSemaphoreCount = 1;
present.pResults = nullptr;
@@ -296,6 +293,14 @@ void VulkanRenderManager::Sync() {
}
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil) {
+ // Eliminate dupes.
+ if (steps_.size() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) {
+ if (color != VKRRenderPassAction::CLEAR && depth != VKRRenderPassAction::CLEAR) {
+ // We don't move to a new step, this bind was unnecessary.
+ return;
+ }
+ }
+
VKRStep *step = new VKRStep{ VKRStepType::RENDER };
// This is what queues up new passes, and can end previous ones.
step->render.framebuffer = fb;
@@ -304,7 +309,10 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
step->render.clearColor = clearColor;
step->render.clearDepth = clearDepth;
step->render.clearStencil = clearStencil;
+ step->render.numDraws = 0;
+ step->render.finalColorLayout = !fb ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
steps_.push_back(step);
+
curRenderStep_ = step;
curWidth_ = fb ? fb->width : vulkan_->GetBackbufferWidth();
curHeight_ = fb ? fb->height : vulkan_->GetBackbufferHeight();
@@ -579,34 +587,20 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
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++) {
+ for (int i = (int)steps_.size() - 1; i >= 0; i--) {
if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == fb) {
- if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED)
+ // If this framebuffer was rendered to earlier in this frame, make sure to pre-transition it to the correct layout.
+ if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- else
- Crash(); // May need to shadow the framebuffer?
+ break;
+ }
+ else {
+ // May need to shadow the framebuffer if we re-order passes later.
+ }
}
}
- /*
- VkAccessFlags srcAccessMask;
- VkPipelineStageFlags srcStage;
- switch (fb->color.layout) {
- case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
- srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
- srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- break;
- case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
- srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
- break;
- }
- TransitionImageLayout2(transitionCmdBuf, fb->color.image, VK_IMAGE_ASPECT_COLOR_BIT,
- fb->color.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
- srcStage, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
- srcAccessMask, VK_ACCESS_SHADER_READ_BIT);
- fb->color.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- */
+ curRenderStep_->preTransitions.push_back({ fb, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL });
return fb->color.imageView;
}
@@ -633,7 +627,7 @@ void VulkanRenderManager::Flush() {
// 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(cmd, swapchainImages_[current_buffer].image);
+ TransitionFromPresent(cmd, swapchainImages_[curSwapchainImage_].image);
// Optimizes renderpasses, then sequences them.
for (int i = 0; i < stepsOnThread_.size(); i++) {
@@ -658,8 +652,60 @@ void VulkanRenderManager::Flush() {
}
void VulkanRenderManager::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd) {
+ // TODO: If there are multiple, we can transition them together.
+ for (const auto &iter : step.preTransitions) {
+ if (iter.fb->color.layout != iter.targetLayout) {
+ VkImageMemoryBarrier barrier{};
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier.oldLayout = iter.fb->color.layout;
+ barrier.subresourceRange.layerCount = 1;
+ barrier.subresourceRange.levelCount = 1;
+ barrier.image = iter.fb->color.image;
+ barrier.srcAccessMask = 0;
+ VkPipelineStageFlags srcStage;
+ VkPipelineStageFlags dstStage;
+ switch (barrier.oldLayout) {
+ case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+ barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+ srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ break;
+ case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+ barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ break;
+ default:
+ Crash();
+ break;
+ }
+ barrier.newLayout = iter.targetLayout;
+ switch (barrier.newLayout) {
+ case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ break;
+ default:
+ Crash();
+ break;
+ }
+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+
+ vkCmdPipelineBarrier(cmd, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
+ iter.fb->color.layout = barrier.newLayout;
+ }
+ }
+
PerformBindFramebufferAsRenderTarget(step, cmd);
+
+ VKRFramebuffer *fb = step.render.framebuffer;
+
auto &commands = step.commands;
+
+ // TODO: Dynamic state commands (SetViewport, SetScissor, SetBlendConstants, SetStencil*) are only
+ // valid when a pipeline is bound with those as dynamic state. So we need to add some state tracking here
+ // for this to be correct. This is a bit of a pain but also will let us eliminate redundant calls.
+
for (const auto &c : commands) {
switch (c.cmd) {
case VKRRenderCommand::VIEWPORT:
@@ -733,6 +779,41 @@ void VulkanRenderManager::PerformRenderPass(const VKRStep &step, VkCommandBuffer
}
}
vkCmdEndRenderPass(cmd);
+
+ // Transition the framebuffer if requested.
+ if (fb && step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
+ VkImageMemoryBarrier barrier{};
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier.oldLayout = fb->color.layout;
+ barrier.subresourceRange.layerCount = 1;
+ barrier.subresourceRange.levelCount = 1;
+ barrier.image = fb->color.image;
+ barrier.srcAccessMask = 0;
+ switch (barrier.oldLayout) {
+ case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+ barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+ break;
+ case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+ barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ break;
+ default:
+ Crash();
+ }
+ barrier.newLayout = step.render.finalColorLayout;
+ switch (barrier.newLayout) {
+ case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ break;
+ default:
+ Crash();
+ }
+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+
+ // we're between passes so it's OK.
+ // ARM Best Practices guide recommends these stage bits.
+ vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
+ fb->color.layout = barrier.newLayout;
+ }
}
void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &step, VkCommandBuffer cmd) {
@@ -747,7 +828,7 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st
h = fb->height;
prevLayout = fb->color.layout;
} else {
- framebuf = framebuffers_[current_buffer];
+ framebuf = framebuffers_[curSwapchainImage_];
w = vulkan_->GetBackbufferWidth();
h = vulkan_->GetBackbufferHeight();
}
@@ -792,56 +873,51 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st
// Now, if the image needs transitioning, let's transition.
// The backbuffer does not, that's handled by VulkanContext.
if (step.render.framebuffer->color.layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
- VkImageMemoryBarrier barrier{};
- barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- barrier.oldLayout = fb->color.layout;
- barrier.subresourceRange.layerCount = 1;
- barrier.subresourceRange.levelCount = 1;
- barrier.image = fb->color.image;
- barrier.srcAccessMask = 0;
+ VkAccessFlags srcAccessMask;
+ VkPipelineStageFlags srcStage;
switch (fb->color.layout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
- barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
}
- barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
- barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- // TODO: Double-check these flags. Should be fine.
- vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
- fb->color.layout = barrier.newLayout;
+
+ TransitionImageLayout2(cmd, fb->color.image, VK_IMAGE_ASPECT_COLOR_BIT,
+ fb->color.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ srcStage, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
+ fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
if (fb->depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
- VkImageMemoryBarrier barrier{};
- barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- barrier.oldLayout = fb->depth.layout;
- barrier.subresourceRange.layerCount = 1;
- barrier.subresourceRange.levelCount = 1;
- barrier.image = fb->depth.image;
- barrier.srcAccessMask = 0;
+ VkAccessFlags srcAccessMask;
+ VkPipelineStageFlags srcStage;
switch (fb->depth.layout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
- barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
}
- barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
- barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
- // TODO: Double-check these flags. Should be fine.
- vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
- fb->depth.layout = barrier.newLayout;
+ TransitionImageLayout2(cmd, fb->color.image, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
+ fb->color.layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ srcStage, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+ srcAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT);
+ fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
renderPass = renderPasses_[RPIndex(step.render.color, step.render.depthStencil)];
@@ -856,7 +932,7 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st
numClearVals = 2;
}
} else {
- renderPass = GetSurfaceRenderPass();
+ renderPass = GetBackbufferRenderpass();
numClearVals = 2; // We don't bother with a depth buffer here.
clearVal[1].depthStencil.depth = 0.0f;
clearVal[1].depthStencil.stencil = 0;
diff --git a/Common/Vulkan/VulkanRenderManager.h b/Common/Vulkan/VulkanRenderManager.h
index 490fea3e1b..e46072a223 100644
--- a/Common/Vulkan/VulkanRenderManager.h
+++ b/Common/Vulkan/VulkanRenderManager.h
@@ -97,10 +97,16 @@ enum class VKRRenderPassAction {
KEEP,
};
+struct TransitionRequest {
+ VKRFramebuffer *fb;
+ VkImageLayout targetLayout;
+};
+
struct VKRStep {
VKRStep(VKRStepType _type) : stepType(_type) {}
VKRStepType stepType;
std::vector commands;
+ std::vector preTransitions;
union {
struct {
VKRFramebuffer *framebuffer;
@@ -221,6 +227,15 @@ public:
curRenderStep_->commands.push_back(data);
}
+ void SetStencilParams(uint8_t writeMask, uint8_t compareMask, uint8_t refValue) {
+ _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
+ VkRenderData data{ VKRRenderCommand::STENCIL };
+ data.stencil.stencilWriteMask = writeMask;
+ data.stencil.stencilCompareMask = compareMask;
+ data.stencil.stencilRef = refValue;
+ curRenderStep_->commands.push_back(data);
+ }
+
void SetBlendFactor(float color[4]) {
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
VkRenderData data{ VKRRenderCommand::BLEND };
@@ -230,7 +245,7 @@ public:
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) {
+ void Draw(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count) {
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
VkRenderData data{ VKRRenderCommand::DRAW };
data.draw.count = count;
@@ -246,10 +261,11 @@ public:
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) {
+ void DrawIndexed(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, int numInstances, VkIndexType indexType) {
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
VkRenderData data{ VKRRenderCommand::DRAW_INDEXED };
data.drawIndexed.count = count;
+ data.drawIndexed.instances = numInstances;
data.drawIndexed.pipeline = pipeline;
data.drawIndexed.pipelineLayout = layout;
data.drawIndexed.ds = descSet;
@@ -272,15 +288,19 @@ public:
void Sync();
VkCommandBuffer GetInitCmd();
- VkCommandBuffer GetSurfaceCommandBuffer() {
- return frameData_[vulkan_->GetCurFrame()].mainCmd;
- }
- VkRenderPass GetSurfaceRenderPass() const {
+ VkRenderPass GetBackbufferRenderpass() const {
return backbufferRenderPass_;
}
VkRenderPass GetRenderPass(int i) const {
return renderPasses_[i];
}
+ VkRenderPass GetCompatibleRenderpass() const {
+ if (curRenderStep_ && curRenderStep_->render.framebuffer != nullptr) {
+ return GetRenderPass(0);
+ } else {
+ return backbufferRenderPass_;
+ }
+ }
void CreateBackbuffers();
void DestroyBackbuffers();
@@ -304,13 +324,15 @@ private:
static void SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect);
static void SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect);
+ // Permanent objects
VkSemaphore acquireSemaphore_;
VkSemaphore renderingCompleteSemaphore;
-
+ VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE;
// Renderpasses, all combinations of preserving or clearing or dont-care-ing fb contents.
// TODO: Create these on demand.
VkRenderPass renderPasses_[9];
+ // Per-frame data, round-robin so we can overlap submission with execution of the previous frame.
struct FrameData {
VkFence fence;
VkCommandPool cmdPool;
@@ -320,18 +342,23 @@ private:
};
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
- VulkanContext *vulkan_;
+ // Submission time state
int curWidth_;
int curHeight_;
bool insideFrame_ = false;
+ VKRStep *curRenderStep_;
+ VKRFramebuffer *boundFramebuffer_;
+ std::vector steps_;
+ // Execution time state
+ VulkanContext *vulkan_;
std::thread submissionThread;
std::mutex mutex_;
std::condition_variable condVar_;
- std::vector steps_;
std::vector stepsOnThread_;
- VKRStep *curRenderStep_;
+ VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE;
+ // Swap chain management
struct SwapchainImageData {
VkImage image;
VkImageView view;
@@ -339,8 +366,7 @@ private:
std::vector framebuffers_;
std::vector swapchainImages_;
uint32_t swapchainImageCount_;
- uint32_t current_buffer = 0;
- VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE;
+ uint32_t curSwapchainImage_ = 0;
struct DepthBufferInfo {
VkFormat format = VK_FORMAT_UNDEFINED;
VkImage image = VK_NULL_HANDLE;
@@ -348,7 +374,4 @@ private:
VkImageView view = VK_NULL_HANDLE;
};
DepthBufferInfo depth_;
- // Interpreter state
- VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE;
- // VkRenderPass curRenderPass_ = VK_NULL_HANDLE;
};
diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp
index 266d48a480..c10f7ac653 100644
--- a/GPU/Common/FramebufferCommon.cpp
+++ b/GPU/Common/FramebufferCommon.cpp
@@ -809,7 +809,7 @@ void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) {
}
void FramebufferManagerCommon::CopyDisplayToOutput() {
- DownloadFramebufferOnSwitch(currentRenderVfb_);
+ // DownloadFramebufferOnSwitch(currentRenderVfb_);
currentRenderVfb_ = 0;
diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp
index 896067b97e..692ce13ec2 100644
--- a/GPU/Vulkan/DrawEngineVulkan.cpp
+++ b/GPU/Vulkan/DrawEngineVulkan.cpp
@@ -23,6 +23,7 @@
#include "profiler/profiler.h"
#include "Common/MemoryUtil.h"
+#include "Common/Vulkan/VulkanRenderManager.h"
#include "Core/MemMap.h"
#include "Core/Host.h"
#include "Core/System.h"
@@ -275,7 +276,6 @@ void DrawEngineVulkan::DeviceRestore(VulkanContext *vulkan) {
}
void DrawEngineVulkan::BeginFrame() {
- lastCmd_ = VK_NULL_HANDLE;
lastPipeline_ = nullptr;
FrameData *frame = &frame_[curFrame_];
@@ -644,19 +644,12 @@ void DrawEngineVulkan::DoFlush() {
// TODO: Should be enough to update this once per frame?
gpuStats.numTrackedVertexArrays = (int)vai_.size();
- /*
- VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER);
- if (cmd != lastCmd_) {
- lastPipeline_ = nullptr;
- lastCmd_ = cmd;
- // Since we have a new cmdbuf, dirty our dynamic state so it gets re-set.
- gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE);
- }*/
- VkCommandBuffer cmd = VK_NULL_HANDLE;
-
- VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::CURRENT_RENDERPASS);
- if (!rp)
- Crash();
+ VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
+
+ // HACK: These two lines should only execute if we started on a new render pass.
+ lastPipeline_ = nullptr;
+ // Since we have a new cmdbuf, dirty our dynamic state so it gets re-set.
+ // gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE);
FrameData *frame = &frame_[curFrame_];
@@ -873,26 +866,28 @@ void DrawEngineVulkan::DoFlush() {
sampler = nullSampler_;
}
- if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
+ VulkanPipeline *pipeline = lastPipeline_;
+ if (!lastPipeline_ || !gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform);
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
- VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS);
- VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true);
+ Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
+ VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
+ pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true);
if (!pipeline) {
// Already logged, let's bail out.
return;
}
if (pipeline != lastPipeline_) {
- vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline);
if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) {
gstate_c.Dirty(DIRTY_BLEND_STATE);
}
lastPipeline_ = pipeline;
}
- ApplyDrawStateLate(cmd, false, 0, pipeline->useBlendConstant);
+ ApplyDrawStateLate(renderManager, false, 0, pipeline->useBlendConstant);
gstate_c.Clean(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
+ lastPipeline_ = pipeline;
}
lastPrim_ = prim;
@@ -902,28 +897,22 @@ void DrawEngineVulkan::DoFlush() {
VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf);
{
- PROFILE_THIS_SCOPE("vkdraw");
+ PROFILE_THIS_SCOPE("renderman_q");
const uint32_t dynamicUBOOffsets[3] = {
baseUBOOffset, lightUBOOffset, boneUBOOffset,
};
- vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets);
+ // vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets);
int stride = dec_->GetDecVtxFmt().stride;
- VkDeviceSize offsets[1] = { vbOffset };
if (useElements) {
if (!ibuf)
ibOffset = (uint32_t)frame->pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf);
- // TODO (maybe): Avoid rebinding vertex/index buffers if the vertex size stays the same by using the offset arguments.
- // Not sure if actually worth it, binding buffers should be fast.
- vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets);
- vkCmdBindIndexBuffer(cmd, ibuf, ibOffset, VK_INDEX_TYPE_UINT16);
int numInstances = (gstate_c.bezier || gstate_c.spline) ? numPatches : 1;
- vkCmdDrawIndexed(cmd, vertexCount, numInstances, 0, 0, 0);
+ renderManager->DrawIndexed(pipeline->pipeline, pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, numInstances, VK_INDEX_TYPE_UINT16);
} else {
- vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets);
- vkCmdDraw(cmd, vertexCount, 1, 0, 0);
+ renderManager->Draw(pipeline->pipeline, pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, vertexCount);
}
}
} else {
@@ -977,27 +966,28 @@ void DrawEngineVulkan::DoFlush() {
if (sampler == VK_NULL_HANDLE)
sampler = nullSampler_;
}
-
+ VulkanPipeline *pipeline = lastPipeline_;
if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform);
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
- VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS);
- VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false);
+ Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
+ VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
+ pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false);
if (!pipeline) {
// Already logged, let's bail out.
return;
}
if (pipeline != lastPipeline_) {
- vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); // TODO: Avoid if same as last draw.
if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) {
gstate_c.Dirty(DIRTY_BLEND_STATE);
}
lastPipeline_ = pipeline;
}
- ApplyDrawStateLate(cmd, false, 0, pipeline->useBlendConstant);
+ ApplyDrawStateLate(renderManager, false, 0, pipeline->useBlendConstant);
gstate_c.Clean(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
+ lastPipeline_ = pipeline;
}
lastPrim_ = prim;
@@ -1011,25 +1001,19 @@ void DrawEngineVulkan::DoFlush() {
baseUBOOffset, lightUBOOffset, boneUBOOffset,
};
- PROFILE_THIS_SCOPE("vkdrawsoft");
- vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets);
+ PROFILE_THIS_SCOPE("renderman_q");
if (drawIndexed) {
VkBuffer vbuf, ibuf;
vbOffset = (uint32_t)frame->pushVertex->Push(drawBuffer, maxIndex * sizeof(TransformedVertex), &vbuf);
ibOffset = (uint32_t)frame->pushIndex->Push(inds, sizeof(short) * numTrans, &ibuf);
VkDeviceSize offsets[1] = { vbOffset };
- // TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments
- vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets);
- vkCmdBindIndexBuffer(cmd, ibuf, ibOffset, VK_INDEX_TYPE_UINT16);
- vkCmdDrawIndexed(cmd, numTrans, 1, 0, 0, 0);
+ renderManager->DrawIndexed(pipeline->pipeline, pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, numTrans, 1, VK_INDEX_TYPE_UINT16);
} else {
VkBuffer vbuf;
vbOffset = (uint32_t)frame->pushVertex->Push(drawBuffer, numTrans * sizeof(TransformedVertex), &vbuf);
VkDeviceSize offsets[1] = { vbOffset };
- // TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments
- vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets);
- vkCmdDraw(cmd, numTrans, 1, 0, 0);
+ renderManager->Draw(pipeline->pipeline, pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, numTrans);
}
} else if (result.action == SW_CLEAR) {
// Note: we won't get here if the clear is alpha but not color, or color but not alpha.
diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h
index 098a16a5f6..5ecd84ad61 100644
--- a/GPU/Vulkan/DrawEngineVulkan.h
+++ b/GPU/Vulkan/DrawEngineVulkan.h
@@ -113,6 +113,8 @@ public:
u8 flags = 0;
};
+class VulkanRenderManager;
+
// Handles transform, lighting and drawing.
class DrawEngineVulkan : public DrawEngineCommon {
public:
@@ -161,6 +163,10 @@ public:
void DirtyAllUBOs();
+ void DirtyPipeline() {
+ lastPipeline_ = nullptr;
+ }
+
VulkanPushBuffer *GetPushBufferForTextureData() {
return frame_[curFrame_].pushUBO;
}
@@ -171,7 +177,7 @@ public:
private:
struct FrameData;
- void ApplyDrawStateLate(VkCommandBuffer cmd, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant);
+ void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant);
void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
void InitDeviceObjects();
@@ -191,7 +197,6 @@ private:
// We use a single descriptor set layout for all PSP draws.
VkDescriptorSetLayout descriptorSetLayout_;
VkPipelineLayout pipelineLayout_;
- VkCommandBuffer lastCmd_ = VK_NULL_HANDLE;
VulkanPipeline *lastPipeline_;
VkDescriptorSet lastDs_ = VK_NULL_HANDLE;
diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp
index 96e08b8923..3422f8a117 100644
--- a/GPU/Vulkan/FramebufferVulkan.cpp
+++ b/GPU/Vulkan/FramebufferVulkan.cpp
@@ -132,8 +132,8 @@ void FramebufferManagerVulkan::InitDeviceObjects() {
assert(vsBasicTex_ != VK_NULL_HANDLE);
// Prime the 2D pipeline cache.
- vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_);
- vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS), vsBasicTex_, fsBasicTex_);
+ // vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_);
+ // vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_);
VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp
index dc390ef2af..3e919eec92 100644
--- a/GPU/Vulkan/StateMappingVulkan.cpp
+++ b/GPU/Vulkan/StateMappingVulkan.cpp
@@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/Vulkan/VulkanLoader.h"
+#include "Common/Vulkan/VulkanRenderManager.h"
#include "math/dataconv.h"
#include "GPU/Math3D.h"
@@ -369,7 +370,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
}
}
-void DrawEngineVulkan::ApplyDrawStateLate(VkCommandBuffer cmd, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant) {
+void DrawEngineVulkan::ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant) {
// At this point, we know if the vertices are full alpha or not.
// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
if (!gstate.isModeClear()) {
@@ -386,24 +387,15 @@ void DrawEngineVulkan::ApplyDrawStateLate(VkCommandBuffer cmd, bool applyStencil
}
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
- vkCmdSetScissor(cmd, 0, 1, &dynState_.scissor);
- vkCmdSetViewport(cmd, 0, 1, &dynState_.viewport);
+ renderManager->SetScissor(dynState_.scissor);
+ renderManager->SetViewport(dynState_.viewport);
}
- if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) {
- if (dynState_.useStencil) {
- vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilWriteMask);
- vkCmdSetStencilCompareMask(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilCompareMask);
- if (!applyStencilRef) {
- vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilRef);
- }
- }
- }
- if (applyStencilRef) {
- vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, stencilRef);
+ if ((gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE) && dynState_.useStencil) || applyStencilRef) {
+ renderManager->SetStencilParams(dynState_.stencilWriteMask, dynState_.stencilCompareMask, applyStencilRef ? stencilRef : dynState_.stencilRef);
}
if (gstate_c.IsDirty(DIRTY_BLEND_STATE) && useBlendConstant) {
float bc[4];
Uint8x4ToFloat4(bc, dynState_.blendColor);
- vkCmdSetBlendConstants(cmd, bc);
+ renderManager->SetBlendFactor(bc);
}
}
diff --git a/GPU/Vulkan/StateMappingVulkan.h b/GPU/Vulkan/StateMappingVulkan.h
index e4b67a3b57..f1d8013f69 100644
--- a/GPU/Vulkan/StateMappingVulkan.h
+++ b/GPU/Vulkan/StateMappingVulkan.h
@@ -57,7 +57,4 @@ struct VulkanPipelineRasterStateKey {
size_t size = sizeof(VulkanPipelineRasterStateKey);
return memcmp(this, &other, size) < 0;
}
-};
-
-class ShaderManagerVulkan;
-void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
+};
\ No newline at end of file
diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h
index 5e18ad9927..fdb68a3849 100644
--- a/ext/native/thin3d/thin3d.h
+++ b/ext/native/thin3d/thin3d.h
@@ -321,9 +321,9 @@ enum class NativeObject {
BACKBUFFER_COLOR_TEX,
BACKBUFFER_DEPTH_TEX,
FEATURE_LEVEL,
- BACKBUFFER_RENDERPASS,
COMPATIBLE_RENDERPASS,
- CURRENT_RENDERPASS,
+ BACKBUFFER_RENDERPASS,
+ FRAMEBUFFER_RENDERPASS,
INIT_COMMANDBUFFER,
BOUND_TEXTURE_IMAGEVIEW,
RENDER_MANAGER,
diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp
index bb5e9dc64b..967b27c85e 100644
--- a/ext/native/thin3d/thin3d_vulkan.cpp
+++ b/ext/native/thin3d/thin3d_vulkan.cpp
@@ -452,16 +452,13 @@ public:
uintptr_t GetNativeObject(NativeObject obj) override {
switch (obj) {
- case NativeObject::COMPATIBLE_RENDERPASS:
+ case NativeObject::FRAMEBUFFER_RENDERPASS:
// Return a representative renderpass.
- if (curRenderPass_ == renderManager_.GetSurfaceRenderPass())
- return (uintptr_t)curRenderPass_;
- else
- return (uintptr_t)renderManager_.GetRenderPass(0);
+ return (uintptr_t)renderManager_.GetRenderPass(0);
case NativeObject::BACKBUFFER_RENDERPASS:
- return (uintptr_t)renderManager_.GetSurfaceRenderPass();
- case NativeObject::CURRENT_RENDERPASS:
- return (uintptr_t)curRenderPass_;
+ return (uintptr_t)renderManager_.GetBackbufferRenderpass();
+ case NativeObject::COMPATIBLE_RENDERPASS:
+ return (uintptr_t)renderManager_.GetCompatibleRenderpass();
case NativeObject::INIT_COMMANDBUFFER:
return (uintptr_t)renderManager_.GetInitCmd();
case NativeObject::BOUND_TEXTURE_IMAGEVIEW:
@@ -470,6 +467,7 @@ public:
case NativeObject::RENDER_MANAGER:
return (uintptr_t)&renderManager_;
default:
+ Crash();
return 0;
}
}
@@ -521,9 +519,6 @@ private:
VulkanPushBuffer *push_ = nullptr;
DeviceCaps caps_{};
-
- VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE;
- VkRenderPass curRenderPass_ = VK_NULL_HANDLE;
};
static int GetBpp(VkFormat format) {
@@ -907,7 +902,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
info.pViewportState = &vs; // Must set viewport and scissor counts even if we set the actual state dynamically.
info.layout = pipelineLayout_;
info.subpass = 0;
- info.renderPass = renderManager_.GetSurfaceRenderPass();
+ info.renderPass = renderManager_.GetBackbufferRenderpass();
// OK, need to create a new pipeline.
VkResult result = vkCreateGraphicsPipelines(device_, pipelineCache_, 1, &info, nullptr, &pipeline->vkpipeline);
@@ -1134,7 +1129,7 @@ void VKContext::DrawIndexed(int vertexCount, int offset) {
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
- renderManager_.DrawIndexed(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, vertexCount, VK_INDEX_TYPE_UINT32);
+ renderManager_.DrawIndexed(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, vertexCount, 1, VK_INDEX_TYPE_UINT32);
}
void VKContext::DrawUP(const void *vdata, int vertexCount) {
@@ -1151,11 +1146,6 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) {
// TODO: We should avoid this function as much as possible, instead use renderpass on-load clearing.
void VKContext::Clear(int clearMask, uint32_t colorval, float depthVal, int stencilVal) {
- if (!curRenderPass_) {
- ELOG("Clear: Need an active render pass");
- return;
- }
-
int mask = 0;
if (clearMask & FBChannel::FB_COLOR_BIT)
mask |= VK_IMAGE_ASPECT_COLOR_BIT;
@@ -1315,7 +1305,7 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne
if (channelBit & FBChannel::FB_COLOR_BIT) aspect |= VK_IMAGE_ASPECT_COLOR_BIT;
if (channelBit & FBChannel::FB_DEPTH_BIT) aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
if (channelBit & FBChannel::FB_STENCIL_BIT) aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
- renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment);
+ boundImageView_[0] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment);
}
uintptr_t VKContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) {