mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Rendering basics now works.
This commit is contained in:
parent
833916a906
commit
02f76ae4a8
14 changed files with 257 additions and 172 deletions
|
@ -249,6 +249,7 @@
|
|||
<ClInclude Include="Vulkan\VulkanImage.h" />
|
||||
<ClInclude Include="Vulkan\VulkanLoader.h" />
|
||||
<ClInclude Include="Vulkan\VulkanMemory.h" />
|
||||
<ClInclude Include="Vulkan\VulkanQueueRunner.h" />
|
||||
<ClInclude Include="Vulkan\VulkanRenderManager.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
|
@ -321,6 +322,7 @@
|
|||
<ClCompile Include="Vulkan\VulkanImage.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanLoader.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanMemory.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanQueueRunner.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanRenderManager.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
|
|
|
@ -75,7 +75,12 @@
|
|||
</ClInclude>
|
||||
<ClInclude Include="OSVersion.h" />
|
||||
<ClInclude Include="Hashmaps.h" />
|
||||
<ClInclude Include="Vulkan\VulkanRenderManager.h" />
|
||||
<ClInclude Include="Vulkan\VulkanRenderManager.h">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vulkan\VulkanQueueRunner.h">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
|
@ -139,7 +144,12 @@
|
|||
<ClCompile Include="MemArenaAndroid.cpp" />
|
||||
<ClCompile Include="MemArenaDarwin.cpp" />
|
||||
<ClCompile Include="OSVersion.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanRenderManager.cpp" />
|
||||
<ClCompile Include="Vulkan\VulkanRenderManager.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\VulkanQueueRunner.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Crypto">
|
||||
|
@ -155,4 +165,4 @@
|
|||
<UniqueIdentifier>{c14d66ef-5f7c-4565-975a-72774e7ccfb9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
0
Common/Vulkan/VulkanQueueRunner.cpp
Normal file
0
Common/Vulkan/VulkanQueueRunner.cpp
Normal file
6
Common/Vulkan/VulkanQueueRunner.h
Normal file
6
Common/Vulkan/VulkanQueueRunner.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
class VulkanQueueRunner {
|
||||
public:
|
||||
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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<VkRenderData> commands;
|
||||
std::vector<TransitionRequest> 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<VKRStep *> steps_;
|
||||
|
||||
// Execution time state
|
||||
VulkanContext *vulkan_;
|
||||
std::thread submissionThread;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable condVar_;
|
||||
std::vector<VKRStep *> steps_;
|
||||
std::vector<VKRStep *> stepsOnThread_;
|
||||
VKRStep *curRenderStep_;
|
||||
VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE;
|
||||
|
||||
// Swap chain management
|
||||
struct SwapchainImageData {
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
|
@ -339,8 +366,7 @@ private:
|
|||
std::vector<VkFramebuffer> framebuffers_;
|
||||
std::vector<SwapchainImageData> 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;
|
||||
};
|
||||
|
|
|
@ -809,7 +809,7 @@ void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) {
|
|||
}
|
||||
|
||||
void FramebufferManagerCommon::CopyDisplayToOutput() {
|
||||
DownloadFramebufferOnSwitch(currentRenderVfb_);
|
||||
// DownloadFramebufferOnSwitch(currentRenderVfb_);
|
||||
|
||||
currentRenderVfb_ = 0;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue