Add Vulkan triangle integration path
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
#include "XCEngine/RHI/Vulkan/VulkanCommandList.h"
|
||||
|
||||
#include "XCEngine/RHI/Vulkan/VulkanBuffer.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanDevice.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanResourceView.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
@@ -12,7 +16,7 @@ namespace {
|
||||
VkImageLayout ToVulkanImageLayout(ResourceStates state) {
|
||||
switch (state) {
|
||||
case ResourceStates::RenderTarget:
|
||||
return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
case ResourceStates::CopySrc:
|
||||
return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
case ResourceStates::CopyDst:
|
||||
@@ -32,7 +36,7 @@ VkImageLayout ToVulkanImageLayout(ResourceStates state) {
|
||||
VkAccessFlags ToVulkanAccessMask(ResourceStates state) {
|
||||
switch (state) {
|
||||
case ResourceStates::RenderTarget:
|
||||
return VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
case ResourceStates::CopySrc:
|
||||
return VK_ACCESS_TRANSFER_READ_BIT;
|
||||
case ResourceStates::CopyDst:
|
||||
@@ -51,6 +55,7 @@ VkAccessFlags ToVulkanAccessMask(ResourceStates state) {
|
||||
VkPipelineStageFlags ToVulkanStageMask(ResourceStates state) {
|
||||
switch (state) {
|
||||
case ResourceStates::RenderTarget:
|
||||
return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
case ResourceStates::CopySrc:
|
||||
case ResourceStates::CopyDst:
|
||||
return VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
@@ -96,6 +101,9 @@ bool VulkanCommandList::Initialize(VulkanDevice* device) {
|
||||
}
|
||||
|
||||
void VulkanCommandList::Shutdown() {
|
||||
EndActiveRenderPass();
|
||||
DestroyTransientFramebuffers();
|
||||
|
||||
if (m_commandPool != VK_NULL_HANDLE && m_device != nullptr) {
|
||||
if (m_commandBuffer != VK_NULL_HANDLE) {
|
||||
vkFreeCommandBuffers(m_device->GetDevice(), m_commandPool, 1, &m_commandBuffer);
|
||||
@@ -107,6 +115,7 @@ void VulkanCommandList::Shutdown() {
|
||||
m_commandPool = VK_NULL_HANDLE;
|
||||
m_currentColorTarget = nullptr;
|
||||
m_currentDepthTarget = nullptr;
|
||||
m_currentPipelineState = nullptr;
|
||||
m_device = nullptr;
|
||||
}
|
||||
|
||||
@@ -116,6 +125,13 @@ void VulkanCommandList::Reset() {
|
||||
}
|
||||
|
||||
vkResetCommandPool(m_device->GetDevice(), m_commandPool, 0);
|
||||
DestroyTransientFramebuffers();
|
||||
|
||||
m_currentPipelineState = nullptr;
|
||||
m_currentPrimitiveTopology = PrimitiveTopology::TriangleList;
|
||||
m_renderPassActive = false;
|
||||
m_hasViewport = false;
|
||||
m_hasScissor = false;
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
@@ -124,6 +140,13 @@ void VulkanCommandList::Reset() {
|
||||
}
|
||||
|
||||
void VulkanCommandList::Close() {
|
||||
EndActiveRenderPass();
|
||||
|
||||
auto* colorView = static_cast<VulkanResourceView*>(m_currentColorTarget);
|
||||
if (colorView != nullptr && colorView->GetTexture() != nullptr) {
|
||||
TransitionTexture(colorView->GetTexture(), ResourceStates::Present);
|
||||
}
|
||||
|
||||
if (m_commandBuffer != VK_NULL_HANDLE) {
|
||||
vkEndCommandBuffer(m_commandBuffer);
|
||||
}
|
||||
@@ -134,6 +157,10 @@ void VulkanCommandList::TransitionTexture(VulkanTexture* texture, ResourceStates
|
||||
return;
|
||||
}
|
||||
|
||||
if (texture->GetState() == newState) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier = {};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = ToVulkanImageLayout(texture->GetState());
|
||||
@@ -164,7 +191,7 @@ void VulkanCommandList::TransitionTexture(VulkanTexture* texture, ResourceStates
|
||||
void VulkanCommandList::TransitionBarrier(RHIResourceView* resource, ResourceStates stateBefore, ResourceStates stateAfter) {
|
||||
(void)stateBefore;
|
||||
auto* view = static_cast<VulkanResourceView*>(resource);
|
||||
if (view != nullptr) {
|
||||
if (view != nullptr && view->GetTexture() != nullptr) {
|
||||
TransitionTexture(view->GetTexture(), stateAfter);
|
||||
}
|
||||
}
|
||||
@@ -178,6 +205,7 @@ void VulkanCommandList::BeginRenderPass(class RHIRenderPass* renderPass, class R
|
||||
}
|
||||
|
||||
void VulkanCommandList::EndRenderPass() {
|
||||
EndActiveRenderPass();
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetShader(RHIShader* shader) {
|
||||
@@ -185,7 +213,7 @@ void VulkanCommandList::SetShader(RHIShader* shader) {
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetPipelineState(RHIPipelineState* pso) {
|
||||
(void)pso;
|
||||
m_currentPipelineState = static_cast<VulkanPipelineState*>(pso);
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetGraphicsDescriptorSets(uint32_t firstSet, uint32_t count, RHIDescriptorSet** descriptorSets, RHIPipelineLayout* pipelineLayout) {
|
||||
@@ -203,25 +231,44 @@ void VulkanCommandList::SetComputeDescriptorSets(uint32_t firstSet, uint32_t cou
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetPrimitiveTopology(PrimitiveTopology topology) {
|
||||
(void)topology;
|
||||
m_currentPrimitiveTopology = topology;
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetViewport(const Viewport& viewport) {
|
||||
(void)viewport;
|
||||
m_viewport.x = viewport.topLeftX;
|
||||
// Match the RHI viewport convention used by D3D12/OpenGL, where the origin is top-left.
|
||||
m_viewport.y = viewport.topLeftY + viewport.height;
|
||||
m_viewport.width = viewport.width;
|
||||
m_viewport.height = -viewport.height;
|
||||
m_viewport.minDepth = viewport.minDepth;
|
||||
m_viewport.maxDepth = viewport.maxDepth;
|
||||
m_hasViewport = true;
|
||||
vkCmdSetViewport(m_commandBuffer, 0, 1, &m_viewport);
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetViewports(uint32_t count, const Viewport* viewports) {
|
||||
(void)count;
|
||||
(void)viewports;
|
||||
if (count == 0 || viewports == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetViewport(viewports[0]);
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetScissorRect(const Rect& rect) {
|
||||
(void)rect;
|
||||
m_scissor.offset.x = rect.left;
|
||||
m_scissor.offset.y = rect.top;
|
||||
m_scissor.extent.width = static_cast<uint32_t>(rect.right - rect.left);
|
||||
m_scissor.extent.height = static_cast<uint32_t>(rect.bottom - rect.top);
|
||||
m_hasScissor = true;
|
||||
vkCmdSetScissor(m_commandBuffer, 0, 1, &m_scissor);
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetScissorRects(uint32_t count, const Rect* rects) {
|
||||
(void)count;
|
||||
(void)rects;
|
||||
if (count == 0 || rects == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetScissorRect(rects[0]);
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetRenderTargets(uint32_t count, RHIResourceView** renderTargets, RHIResourceView* depthStencil) {
|
||||
@@ -238,31 +285,65 @@ void VulkanCommandList::SetBlendFactor(const float factor[4]) {
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetVertexBuffers(uint32_t startSlot, uint32_t count, RHIResourceView** buffers, const uint64_t* offsets, const uint32_t* strides) {
|
||||
(void)startSlot;
|
||||
(void)count;
|
||||
(void)buffers;
|
||||
(void)offsets;
|
||||
(void)strides;
|
||||
if (count == 0 || buffers == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<VkBuffer> nativeBuffers;
|
||||
std::vector<VkDeviceSize> nativeOffsets;
|
||||
nativeBuffers.reserve(count);
|
||||
nativeOffsets.reserve(count);
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
auto* view = static_cast<VulkanResourceView*>(buffers[i]);
|
||||
if (view == nullptr || !view->IsValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nativeBuffers.push_back(view->GetBuffer());
|
||||
nativeOffsets.push_back(view->GetBufferOffset() + (offsets != nullptr ? offsets[i] : 0));
|
||||
(void)strides;
|
||||
}
|
||||
|
||||
if (!nativeBuffers.empty()) {
|
||||
vkCmdBindVertexBuffers(
|
||||
m_commandBuffer,
|
||||
startSlot,
|
||||
static_cast<uint32_t>(nativeBuffers.size()),
|
||||
nativeBuffers.data(),
|
||||
nativeOffsets.data());
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanCommandList::SetIndexBuffer(RHIResourceView* buffer, uint64_t offset) {
|
||||
(void)buffer;
|
||||
(void)offset;
|
||||
auto* view = static_cast<VulkanResourceView*>(buffer);
|
||||
if (view == nullptr || !view->IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
vkCmdBindIndexBuffer(
|
||||
m_commandBuffer,
|
||||
view->GetBuffer(),
|
||||
view->GetBufferOffset() + offset,
|
||||
ToVulkanIndexType(view->GetFormat()));
|
||||
}
|
||||
|
||||
void VulkanCommandList::Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance) {
|
||||
(void)vertexCount;
|
||||
(void)instanceCount;
|
||||
(void)startVertex;
|
||||
(void)startInstance;
|
||||
if (!EnsureGraphicsRenderPass()) {
|
||||
return;
|
||||
}
|
||||
|
||||
vkCmdBindPipeline(m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_currentPipelineState->GetPipeline());
|
||||
vkCmdDraw(m_commandBuffer, vertexCount, instanceCount, startVertex, startInstance);
|
||||
}
|
||||
|
||||
void VulkanCommandList::DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) {
|
||||
(void)indexCount;
|
||||
(void)instanceCount;
|
||||
(void)startIndex;
|
||||
(void)baseVertex;
|
||||
(void)startInstance;
|
||||
if (!EnsureGraphicsRenderPass()) {
|
||||
return;
|
||||
}
|
||||
|
||||
vkCmdBindPipeline(m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_currentPipelineState->GetPipeline());
|
||||
vkCmdDrawIndexed(m_commandBuffer, indexCount, instanceCount, startIndex, baseVertex, startInstance);
|
||||
}
|
||||
|
||||
void VulkanCommandList::Clear(float r, float g, float b, float a, uint32_t buffers) {
|
||||
@@ -273,8 +354,10 @@ void VulkanCommandList::Clear(float r, float g, float b, float a, uint32_t buffe
|
||||
return;
|
||||
}
|
||||
|
||||
EndActiveRenderPass();
|
||||
|
||||
VulkanTexture* texture = colorView->GetTexture();
|
||||
TransitionTexture(texture, ResourceStates::RenderTarget);
|
||||
TransitionTexture(texture, ResourceStates::CopyDst);
|
||||
|
||||
VkClearColorValue clearColor = {};
|
||||
clearColor.float32[0] = r;
|
||||
@@ -297,7 +380,7 @@ void VulkanCommandList::Clear(float r, float g, float b, float a, uint32_t buffe
|
||||
1,
|
||||
&range);
|
||||
|
||||
TransitionTexture(texture, ResourceStates::Present);
|
||||
TransitionTexture(texture, ResourceStates::RenderTarget);
|
||||
}
|
||||
|
||||
void VulkanCommandList::ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) {
|
||||
@@ -322,5 +405,81 @@ void VulkanCommandList::Dispatch(uint32_t x, uint32_t y, uint32_t z) {
|
||||
(void)z;
|
||||
}
|
||||
|
||||
bool VulkanCommandList::EnsureGraphicsRenderPass() {
|
||||
if (m_renderPassActive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_currentPipelineState == nullptr || !m_currentPipelineState->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* colorView = static_cast<VulkanResourceView*>(m_currentColorTarget);
|
||||
if (colorView == nullptr || colorView->GetTexture() == nullptr || colorView->GetImageView() == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VulkanTexture* texture = colorView->GetTexture();
|
||||
TransitionTexture(texture, ResourceStates::RenderTarget);
|
||||
|
||||
VkFramebufferCreateInfo framebufferInfo = {};
|
||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferInfo.renderPass = m_currentPipelineState->GetRenderPass();
|
||||
framebufferInfo.attachmentCount = 1;
|
||||
const VkImageView attachment = colorView->GetImageView();
|
||||
framebufferInfo.pAttachments = &attachment;
|
||||
framebufferInfo.width = texture->GetWidth();
|
||||
framebufferInfo.height = texture->GetHeight();
|
||||
framebufferInfo.layers = 1;
|
||||
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
if (vkCreateFramebuffer(m_device->GetDevice(), &framebufferInfo, nullptr, &framebuffer) != VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
m_transientFramebuffers.push_back(framebuffer);
|
||||
|
||||
VkRenderPassBeginInfo renderPassInfo = {};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
renderPassInfo.renderPass = m_currentPipelineState->GetRenderPass();
|
||||
renderPassInfo.framebuffer = framebuffer;
|
||||
renderPassInfo.renderArea.offset = { 0, 0 };
|
||||
renderPassInfo.renderArea.extent = { texture->GetWidth(), texture->GetHeight() };
|
||||
renderPassInfo.clearValueCount = 0;
|
||||
renderPassInfo.pClearValues = nullptr;
|
||||
|
||||
vkCmdBeginRenderPass(m_commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
if (m_hasViewport) {
|
||||
vkCmdSetViewport(m_commandBuffer, 0, 1, &m_viewport);
|
||||
}
|
||||
if (m_hasScissor) {
|
||||
vkCmdSetScissor(m_commandBuffer, 0, 1, &m_scissor);
|
||||
}
|
||||
|
||||
m_renderPassActive = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanCommandList::EndActiveRenderPass() {
|
||||
if (m_renderPassActive && m_commandBuffer != VK_NULL_HANDLE) {
|
||||
vkCmdEndRenderPass(m_commandBuffer);
|
||||
m_renderPassActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanCommandList::DestroyTransientFramebuffers() {
|
||||
if (m_device == nullptr) {
|
||||
m_transientFramebuffers.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
for (VkFramebuffer framebuffer : m_transientFramebuffers) {
|
||||
if (framebuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyFramebuffer(m_device->GetDevice(), framebuffer, nullptr);
|
||||
}
|
||||
}
|
||||
m_transientFramebuffers.clear();
|
||||
}
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
|
||||
Reference in New Issue
Block a user