Add Vulkan triangle integration path
This commit is contained in:
123
engine/src/RHI/Vulkan/VulkanBuffer.cpp
Normal file
123
engine/src/RHI/Vulkan/VulkanBuffer.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "XCEngine/RHI/Vulkan/VulkanBuffer.h"
|
||||
|
||||
#include "XCEngine/RHI/Vulkan/VulkanDevice.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
VulkanBuffer::~VulkanBuffer() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool VulkanBuffer::Initialize(VulkanDevice* device, const BufferDesc& desc, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryProperties) {
|
||||
if (device == nullptr || device->GetDevice() == VK_NULL_HANDLE || desc.size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_deviceOwner = device;
|
||||
m_device = device->GetDevice();
|
||||
m_size = desc.size;
|
||||
m_stride = desc.stride;
|
||||
m_bufferType = static_cast<BufferType>(desc.bufferType);
|
||||
|
||||
VkBufferCreateInfo bufferInfo = {};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = static_cast<VkDeviceSize>(desc.size);
|
||||
bufferInfo.usage = usageFlags;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &m_buffer) != VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkMemoryRequirements memoryRequirements = {};
|
||||
vkGetBufferMemoryRequirements(m_device, m_buffer, &memoryRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocateInfo = {};
|
||||
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocateInfo.allocationSize = memoryRequirements.size;
|
||||
allocateInfo.memoryTypeIndex = device->FindMemoryType(memoryRequirements.memoryTypeBits, memoryProperties);
|
||||
if (allocateInfo.memoryTypeIndex == UINT32_MAX) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vkAllocateMemory(m_device, &allocateInfo, nullptr, &m_memory) != VK_SUCCESS) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vkBindBufferMemory(m_device, m_buffer, m_memory, 0) != VK_SUCCESS) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanBuffer::Shutdown() {
|
||||
if (m_mappedData != nullptr && m_device != VK_NULL_HANDLE && m_memory != VK_NULL_HANDLE) {
|
||||
vkUnmapMemory(m_device, m_memory);
|
||||
m_mappedData = nullptr;
|
||||
}
|
||||
|
||||
if (m_buffer != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||
vkDestroyBuffer(m_device, m_buffer, nullptr);
|
||||
m_buffer = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (m_memory != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(m_device, m_memory, nullptr);
|
||||
m_memory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
m_deviceOwner = nullptr;
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_size = 0;
|
||||
m_stride = 0;
|
||||
m_state = ResourceStates::Common;
|
||||
}
|
||||
|
||||
void* VulkanBuffer::Map() {
|
||||
if (m_device == VK_NULL_HANDLE || m_memory == VK_NULL_HANDLE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_mappedData == nullptr) {
|
||||
if (vkMapMemory(m_device, m_memory, 0, VK_WHOLE_SIZE, 0, &m_mappedData) != VK_SUCCESS) {
|
||||
m_mappedData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return m_mappedData;
|
||||
}
|
||||
|
||||
void VulkanBuffer::Unmap() {
|
||||
if (m_mappedData != nullptr && m_device != VK_NULL_HANDLE && m_memory != VK_NULL_HANDLE) {
|
||||
vkUnmapMemory(m_device, m_memory);
|
||||
m_mappedData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanBuffer::SetData(const void* data, size_t size, size_t offset) {
|
||||
if (data == nullptr || size == 0 || offset + size > m_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool wasMapped = m_mappedData != nullptr;
|
||||
void* mappedData = Map();
|
||||
if (mappedData == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(static_cast<uint8_t*>(mappedData) + offset, data, size);
|
||||
|
||||
if (!wasMapped) {
|
||||
Unmap();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
@@ -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
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#include "XCEngine/RHI/Vulkan/VulkanDevice.h"
|
||||
|
||||
#include "XCEngine/RHI/Vulkan/VulkanBuffer.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanCommandList.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanCommandQueue.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanFence.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanResourceView.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanSwapChain.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
@@ -202,7 +205,30 @@ uint32_t VulkanDevice::FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags
|
||||
}
|
||||
|
||||
RHIBuffer* VulkanDevice::CreateBuffer(const BufferDesc& desc) {
|
||||
(void)desc;
|
||||
VkBufferUsageFlags usageFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
switch (static_cast<BufferType>(desc.bufferType)) {
|
||||
case BufferType::Index:
|
||||
usageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||
break;
|
||||
case BufferType::Constant:
|
||||
usageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
break;
|
||||
case BufferType::Vertex:
|
||||
default:
|
||||
usageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
auto* buffer = new VulkanBuffer();
|
||||
if (buffer->Initialize(
|
||||
this,
|
||||
desc,
|
||||
usageFlags,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
delete buffer;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -253,7 +279,12 @@ RHIShader* VulkanDevice::CreateShader(const ShaderCompileDesc& desc) {
|
||||
}
|
||||
|
||||
RHIPipelineState* VulkanDevice::CreatePipelineState(const GraphicsPipelineDesc& desc) {
|
||||
(void)desc;
|
||||
auto* pipelineState = new VulkanPipelineState();
|
||||
if (pipelineState->Initialize(this, desc)) {
|
||||
return pipelineState;
|
||||
}
|
||||
|
||||
delete pipelineState;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -300,14 +331,22 @@ RHIDescriptorSet* VulkanDevice::CreateDescriptorSet(RHIDescriptorPool* pool, con
|
||||
}
|
||||
|
||||
RHIResourceView* VulkanDevice::CreateVertexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
||||
(void)buffer;
|
||||
(void)desc;
|
||||
auto* view = new VulkanResourceView();
|
||||
if (view->InitializeAsVertexBuffer(static_cast<VulkanBuffer*>(buffer), desc)) {
|
||||
return view;
|
||||
}
|
||||
|
||||
delete view;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RHIResourceView* VulkanDevice::CreateIndexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
||||
(void)buffer;
|
||||
(void)desc;
|
||||
auto* view = new VulkanResourceView();
|
||||
if (view->InitializeAsIndexBuffer(static_cast<VulkanBuffer*>(buffer), desc)) {
|
||||
return view;
|
||||
}
|
||||
|
||||
delete view;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
384
engine/src/RHI/Vulkan/VulkanPipelineState.cpp
Normal file
384
engine/src/RHI/Vulkan/VulkanPipelineState.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
||||
|
||||
#include "XCEngine/RHI/Vulkan/VulkanDevice.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string NarrowAscii(const std::wstring& value) {
|
||||
std::string result;
|
||||
result.reserve(value.size());
|
||||
for (wchar_t ch : value) {
|
||||
result.push_back(static_cast<char>(ch));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LoadSpirvBytes(const ShaderCompileDesc& desc, std::vector<uint32_t>& words, std::string& entryPoint) {
|
||||
entryPoint = NarrowAscii(desc.entryPoint);
|
||||
if (entryPoint.empty()) {
|
||||
entryPoint = "main";
|
||||
}
|
||||
|
||||
if (desc.sourceLanguage != ShaderLanguage::SPIRV) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<char> bytes;
|
||||
if (!desc.source.empty()) {
|
||||
bytes.assign(desc.source.begin(), desc.source.end());
|
||||
} else if (!desc.fileName.empty()) {
|
||||
std::ifstream file(std::filesystem::path(desc.fileName), std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::streamsize fileSize = file.tellg();
|
||||
if (fileSize <= 0 || (fileSize % 4) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes.resize(static_cast<size_t>(fileSize));
|
||||
file.seekg(0, std::ios::beg);
|
||||
if (!file.read(bytes.data(), fileSize)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((bytes.size() % sizeof(uint32_t)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
words.resize(bytes.size() / sizeof(uint32_t));
|
||||
std::memcpy(words.data(), bytes.data(), bytes.size());
|
||||
return !words.empty();
|
||||
}
|
||||
|
||||
VkShaderModule CreateShaderModule(VkDevice device, const std::vector<uint32_t>& words) {
|
||||
VkShaderModuleCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = words.size() * sizeof(uint32_t);
|
||||
createInfo.pCode = words.data();
|
||||
|
||||
VkShaderModule module = VK_NULL_HANDLE;
|
||||
if (vkCreateShaderModule(device, &createInfo, nullptr, &module) != VK_SUCCESS) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
VulkanPipelineState::~VulkanPipelineState() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool VulkanPipelineState::Initialize(VulkanDevice* device, const GraphicsPipelineDesc& desc) {
|
||||
if (device == nullptr || device->GetDevice() == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_deviceOwner = device;
|
||||
m_device = device->GetDevice();
|
||||
m_inputLayoutDesc = desc.inputLayout;
|
||||
m_rasterizerDesc = desc.rasterizerState;
|
||||
m_blendDesc = desc.blendState;
|
||||
m_depthStencilDesc = desc.depthStencilState;
|
||||
m_topologyType = desc.topologyType;
|
||||
m_renderTargetCount = desc.renderTargetCount;
|
||||
m_depthStencilFormat = desc.depthStencilFormat;
|
||||
m_sampleCount = desc.sampleCount > 0 ? desc.sampleCount : 1;
|
||||
for (uint32_t i = 0; i < 8; ++i) {
|
||||
m_renderTargetFormats[i] = desc.renderTargetFormats[i];
|
||||
}
|
||||
|
||||
if (m_renderTargetCount != 1 || m_renderTargetFormats[0] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> vertexWords;
|
||||
std::vector<uint32_t> fragmentWords;
|
||||
std::string vertexEntryPoint;
|
||||
std::string fragmentEntryPoint;
|
||||
if (!LoadSpirvBytes(desc.vertexShader, vertexWords, vertexEntryPoint) ||
|
||||
!LoadSpirvBytes(desc.fragmentShader, fragmentWords, fragmentEntryPoint)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkShaderModule vertexModule = CreateShaderModule(m_device, vertexWords);
|
||||
const VkShaderModule fragmentModule = CreateShaderModule(m_device, fragmentWords);
|
||||
if (vertexModule == VK_NULL_HANDLE || fragmentModule == VK_NULL_HANDLE) {
|
||||
if (vertexModule != VK_NULL_HANDLE) {
|
||||
vkDestroyShaderModule(m_device, vertexModule, nullptr);
|
||||
}
|
||||
if (fragmentModule != VK_NULL_HANDLE) {
|
||||
vkDestroyShaderModule(m_device, fragmentModule, nullptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
if (vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) {
|
||||
vkDestroyShaderModule(m_device, fragmentModule, nullptr);
|
||||
vkDestroyShaderModule(m_device, vertexModule, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
VkAttachmentDescription colorAttachment = {};
|
||||
colorAttachment.format = ToVulkanFormat(static_cast<Format>(m_renderTargetFormats[0]));
|
||||
colorAttachment.samples = ToVulkanSampleCount(m_sampleCount);
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkAttachmentReference colorAttachmentRef = {};
|
||||
colorAttachmentRef.attachment = 0;
|
||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass = {};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorAttachmentRef;
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo = {};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassInfo.attachmentCount = 1;
|
||||
renderPassInfo.pAttachments = &colorAttachment;
|
||||
renderPassInfo.subpassCount = 1;
|
||||
renderPassInfo.pSubpasses = &subpass;
|
||||
|
||||
if (vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass) != VK_SUCCESS) {
|
||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||
m_pipelineLayout = VK_NULL_HANDLE;
|
||||
vkDestroyShaderModule(m_device, fragmentModule, nullptr);
|
||||
vkDestroyShaderModule(m_device, vertexModule, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<uint32_t, uint32_t> strideBySlot;
|
||||
for (const InputElementDesc& element : m_inputLayoutDesc.elements) {
|
||||
const uint32_t attributeSize = GetFormatSize(static_cast<Format>(element.format));
|
||||
strideBySlot[element.inputSlot] = (std::max)(strideBySlot[element.inputSlot], element.alignedByteOffset + attributeSize);
|
||||
}
|
||||
|
||||
std::vector<VkVertexInputBindingDescription> bindings;
|
||||
bindings.reserve(strideBySlot.size());
|
||||
for (const auto& entry : strideBySlot) {
|
||||
VkVertexInputBindingDescription binding = {};
|
||||
binding.binding = entry.first;
|
||||
binding.stride = entry.second;
|
||||
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
bindings.push_back(binding);
|
||||
}
|
||||
|
||||
std::vector<VkVertexInputAttributeDescription> attributes;
|
||||
attributes.reserve(m_inputLayoutDesc.elements.size());
|
||||
for (uint32_t location = 0; location < m_inputLayoutDesc.elements.size(); ++location) {
|
||||
const InputElementDesc& element = m_inputLayoutDesc.elements[location];
|
||||
VkVertexInputAttributeDescription attribute = {};
|
||||
attribute.location = location;
|
||||
attribute.binding = element.inputSlot;
|
||||
attribute.format = ToVulkanFormat(static_cast<Format>(element.format));
|
||||
attribute.offset = element.alignedByteOffset;
|
||||
attributes.push_back(attribute);
|
||||
}
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[2] = {};
|
||||
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
shaderStages[0].module = vertexModule;
|
||||
shaderStages[0].pName = vertexEntryPoint.c_str();
|
||||
|
||||
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
shaderStages[1].module = fragmentModule;
|
||||
shaderStages[1].pName = fragmentEntryPoint.c_str();
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
|
||||
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertexInputInfo.vertexBindingDescriptionCount = static_cast<uint32_t>(bindings.size());
|
||||
vertexInputInfo.pVertexBindingDescriptions = bindings.data();
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributes.size());
|
||||
vertexInputInfo.pVertexAttributeDescriptions = attributes.data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
|
||||
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
inputAssembly.topology = ToVulkanPrimitiveTopology(static_cast<PrimitiveTopologyType>(m_topologyType));
|
||||
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState = {};
|
||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewportState.viewportCount = 1;
|
||||
viewportState.scissorCount = 1;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {};
|
||||
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterizer.depthClampEnable = m_rasterizerDesc.depthClipEnable ? VK_FALSE : VK_TRUE;
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterizer.polygonMode = ToVulkanPolygonMode(static_cast<FillMode>(m_rasterizerDesc.fillMode));
|
||||
rasterizer.lineWidth = 1.0f;
|
||||
rasterizer.cullMode = ToVulkanCullMode(static_cast<CullMode>(m_rasterizerDesc.cullMode));
|
||||
rasterizer.frontFace = ToVulkanFrontFace(static_cast<FrontFace>(m_rasterizerDesc.frontFace));
|
||||
rasterizer.depthBiasEnable = m_rasterizerDesc.depthBias != 0 || m_rasterizerDesc.slopeScaledDepthBias != 0.0f;
|
||||
rasterizer.depthBiasConstantFactor = static_cast<float>(m_rasterizerDesc.depthBias);
|
||||
rasterizer.depthBiasClamp = m_rasterizerDesc.depthBiasClamp;
|
||||
rasterizer.depthBiasSlopeFactor = m_rasterizerDesc.slopeScaledDepthBias;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
||||
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisampling.rasterizationSamples = ToVulkanSampleCount(m_sampleCount);
|
||||
multisampling.sampleShadingEnable = VK_FALSE;
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
|
||||
colorBlendAttachment.colorWriteMask =
|
||||
VK_COLOR_COMPONENT_R_BIT |
|
||||
VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT;
|
||||
colorBlendAttachment.blendEnable = m_blendDesc.blendEnable ? VK_TRUE : VK_FALSE;
|
||||
colorBlendAttachment.srcColorBlendFactor = ToVulkanBlendFactor(static_cast<BlendFactor>(m_blendDesc.srcBlend));
|
||||
colorBlendAttachment.dstColorBlendFactor = ToVulkanBlendFactor(static_cast<BlendFactor>(m_blendDesc.dstBlend));
|
||||
colorBlendAttachment.colorBlendOp = ToVulkanBlendOp(static_cast<BlendOp>(m_blendDesc.blendOp));
|
||||
colorBlendAttachment.srcAlphaBlendFactor = ToVulkanBlendFactor(static_cast<BlendFactor>(m_blendDesc.srcBlendAlpha));
|
||||
colorBlendAttachment.dstAlphaBlendFactor = ToVulkanBlendFactor(static_cast<BlendFactor>(m_blendDesc.dstBlendAlpha));
|
||||
colorBlendAttachment.alphaBlendOp = ToVulkanBlendOp(static_cast<BlendOp>(m_blendDesc.blendOpAlpha));
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending = {};
|
||||
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
colorBlending.logicOpEnable = VK_FALSE;
|
||||
colorBlending.attachmentCount = 1;
|
||||
colorBlending.pAttachments = &colorBlendAttachment;
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencil = {};
|
||||
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
depthStencil.depthTestEnable = m_depthStencilDesc.depthTestEnable ? VK_TRUE : VK_FALSE;
|
||||
depthStencil.depthWriteEnable = m_depthStencilDesc.depthWriteEnable ? VK_TRUE : VK_FALSE;
|
||||
depthStencil.depthCompareOp = ToVulkanCompareOp(static_cast<ComparisonFunc>(m_depthStencilDesc.depthFunc));
|
||||
depthStencil.depthBoundsTestEnable = m_depthStencilDesc.depthBoundsEnable ? VK_TRUE : VK_FALSE;
|
||||
depthStencil.stencilTestEnable = m_depthStencilDesc.stencilEnable ? VK_TRUE : VK_FALSE;
|
||||
|
||||
VkDynamicState dynamicStates[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR
|
||||
};
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = {};
|
||||
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamicState.dynamicStateCount = static_cast<uint32_t>(std::size(dynamicStates));
|
||||
dynamicState.pDynamicStates = dynamicStates;
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipelineInfo.stageCount = 2;
|
||||
pipelineInfo.pStages = shaderStages;
|
||||
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
||||
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
||||
pipelineInfo.pViewportState = &viewportState;
|
||||
pipelineInfo.pRasterizationState = &rasterizer;
|
||||
pipelineInfo.pMultisampleState = &multisampling;
|
||||
pipelineInfo.pDepthStencilState = &depthStencil;
|
||||
pipelineInfo.pColorBlendState = &colorBlending;
|
||||
pipelineInfo.pDynamicState = &dynamicState;
|
||||
pipelineInfo.layout = m_pipelineLayout;
|
||||
pipelineInfo.renderPass = m_renderPass;
|
||||
pipelineInfo.subpass = 0;
|
||||
|
||||
const bool success = vkCreateGraphicsPipelines(
|
||||
m_device,
|
||||
VK_NULL_HANDLE,
|
||||
1,
|
||||
&pipelineInfo,
|
||||
nullptr,
|
||||
&m_pipeline) == VK_SUCCESS;
|
||||
|
||||
vkDestroyShaderModule(m_device, fragmentModule, nullptr);
|
||||
vkDestroyShaderModule(m_device, vertexModule, nullptr);
|
||||
|
||||
if (!success) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetInputLayout(const InputLayoutDesc& layout) {
|
||||
m_inputLayoutDesc = layout;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetRasterizerState(const RasterizerDesc& state) {
|
||||
m_rasterizerDesc = state;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetBlendState(const BlendDesc& state) {
|
||||
m_blendDesc = state;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetDepthStencilState(const DepthStencilStateDesc& state) {
|
||||
m_depthStencilDesc = state;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetTopology(uint32_t topologyType) {
|
||||
m_topologyType = topologyType;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetRenderTargetFormats(uint32_t count, const uint32_t* formats, uint32_t depthFormat) {
|
||||
m_renderTargetCount = count;
|
||||
m_depthStencilFormat = depthFormat;
|
||||
for (uint32_t i = 0; i < count && i < 8; ++i) {
|
||||
m_renderTargetFormats[i] = formats[i];
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetSampleCount(uint32_t count) {
|
||||
m_sampleCount = count > 0 ? count : 1;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetComputeShader(RHIShader* shader) {
|
||||
(void)shader;
|
||||
}
|
||||
|
||||
PipelineStateHash VulkanPipelineState::GetHash() const {
|
||||
PipelineStateHash hash = {};
|
||||
hash.topologyHash = m_topologyType;
|
||||
hash.renderTargetHash = m_renderTargetCount ^ (m_renderTargetFormats[0] << 8);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::Shutdown() {
|
||||
if (m_pipeline != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||
vkDestroyPipeline(m_device, m_pipeline, nullptr);
|
||||
m_pipeline = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (m_renderPass != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(m_device, m_renderPass, nullptr);
|
||||
m_renderPass = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (m_pipelineLayout != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||
m_pipelineLayout = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
m_deviceOwner = nullptr;
|
||||
m_device = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "XCEngine/RHI/Vulkan/VulkanResourceView.h"
|
||||
|
||||
#include "XCEngine/RHI/Vulkan/VulkanBuffer.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
@@ -32,6 +35,61 @@ bool VulkanResourceView::InitializeAsRenderTarget(VkDevice device, VulkanTexture
|
||||
return vkCreateImageView(device, &viewInfo, nullptr, &m_imageView) == VK_SUCCESS;
|
||||
}
|
||||
|
||||
bool VulkanResourceView::InitializeAsVertexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc) {
|
||||
if (buffer == nullptr || buffer->GetBuffer() == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_viewType = ResourceViewType::VertexBuffer;
|
||||
m_dimension = ResourceViewDimension::Buffer;
|
||||
m_format = Format::Unknown;
|
||||
m_buffer = buffer;
|
||||
m_bufferOffset = desc.bufferLocation;
|
||||
m_bufferSize = static_cast<uint32_t>(buffer->GetSize());
|
||||
m_bufferStride = desc.structureByteStride > 0 ? desc.structureByteStride : buffer->GetStride();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanResourceView::InitializeAsIndexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc) {
|
||||
if (buffer == nullptr || buffer->GetBuffer() == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_viewType = ResourceViewType::IndexBuffer;
|
||||
m_dimension = ResourceViewDimension::Buffer;
|
||||
m_format = desc.format != 0 ? static_cast<Format>(desc.format) : Format::R32_UInt;
|
||||
m_buffer = buffer;
|
||||
m_bufferOffset = desc.bufferLocation;
|
||||
m_bufferSize = static_cast<uint32_t>(buffer->GetSize());
|
||||
m_bufferStride = buffer->GetStride();
|
||||
return true;
|
||||
}
|
||||
|
||||
void* VulkanResourceView::GetNativeHandle() {
|
||||
if (m_imageView != VK_NULL_HANDLE) {
|
||||
return m_imageView;
|
||||
}
|
||||
|
||||
return m_buffer != nullptr ? m_buffer->GetNativeHandle() : nullptr;
|
||||
}
|
||||
|
||||
bool VulkanResourceView::IsValid() const {
|
||||
switch (m_viewType) {
|
||||
case ResourceViewType::VertexBuffer:
|
||||
case ResourceViewType::IndexBuffer:
|
||||
return m_buffer != nullptr && m_buffer->GetBuffer() != VK_NULL_HANDLE;
|
||||
case ResourceViewType::RenderTarget:
|
||||
case ResourceViewType::DepthStencil:
|
||||
return m_imageView != VK_NULL_HANDLE;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VkBuffer VulkanResourceView::GetBuffer() const {
|
||||
return m_buffer != nullptr ? m_buffer->GetBuffer() : VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void VulkanResourceView::Shutdown() {
|
||||
if (m_imageView != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, m_imageView, nullptr);
|
||||
@@ -39,8 +97,12 @@ void VulkanResourceView::Shutdown() {
|
||||
m_imageView = VK_NULL_HANDLE;
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_texture = nullptr;
|
||||
m_buffer = nullptr;
|
||||
m_format = Format::Unknown;
|
||||
m_dimension = ResourceViewDimension::Unknown;
|
||||
m_bufferOffset = 0;
|
||||
m_bufferSize = 0;
|
||||
m_bufferStride = 0;
|
||||
}
|
||||
|
||||
} // namespace RHI
|
||||
|
||||
Reference in New Issue
Block a user