Rendering basics now works.

This commit is contained in:
Henrik Rydgård 2017-08-22 13:25:45 +02:00
parent 833916a906
commit 02f76ae4a8
14 changed files with 257 additions and 172 deletions

View file

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

View file

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

View file

View file

@ -0,0 +1,6 @@
#pragma once
class VulkanQueueRunner {
public:
};

View file

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

View file

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

View file

@ -809,7 +809,7 @@ void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) {
}
void FramebufferManagerCommon::CopyDisplayToOutput() {
DownloadFramebufferOnSwitch(currentRenderVfb_);
// DownloadFramebufferOnSwitch(currentRenderVfb_);
currentRenderVfb_ = 0;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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