Add Vulkan quad integration path
This commit is contained in:
@@ -155,6 +155,10 @@ add_library(XCEngine STATIC
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanCommon.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanCommon.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanBuffer.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanBuffer.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanTexture.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanTexture.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanSampler.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanDescriptorPool.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanDescriptorSet.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanPipelineLayout.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanPipelineState.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanPipelineState.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanResourceView.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanResourceView.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanFence.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanFence.h
|
||||||
@@ -165,6 +169,10 @@ add_library(XCEngine STATIC
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanScreenshot.h
|
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/RHI/Vulkan/VulkanScreenshot.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanBuffer.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanBuffer.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanTexture.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanTexture.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanSampler.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanDescriptorPool.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanDescriptorSet.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanPipelineLayout.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanPipelineState.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanPipelineState.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanResourceView.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanResourceView.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanCommandQueue.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/Vulkan/VulkanCommandQueue.cpp
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "XCEngine/RHI/RHIEnums.h"
|
#include "XCEngine/RHI/RHIEnums.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
@@ -245,6 +246,162 @@ inline VkSampleCountFlagBits ToVulkanSampleCount(uint32_t sampleCount) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline VkDescriptorType ToVulkanDescriptorType(DescriptorType type) {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::CBV:
|
||||||
|
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
case DescriptorType::SRV:
|
||||||
|
return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||||
|
case DescriptorType::UAV:
|
||||||
|
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||||
|
case DescriptorType::Sampler:
|
||||||
|
return VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
|
default:
|
||||||
|
return VK_DESCRIPTOR_TYPE_MAX_ENUM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkShaderStageFlags ToVulkanShaderStageFlags(uint32_t visibility) {
|
||||||
|
switch (static_cast<ShaderVisibility>(visibility)) {
|
||||||
|
case ShaderVisibility::Vertex:
|
||||||
|
return VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
case ShaderVisibility::Geometry:
|
||||||
|
return VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||||
|
case ShaderVisibility::Pixel:
|
||||||
|
return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
case ShaderVisibility::Amplification:
|
||||||
|
case ShaderVisibility::Mesh:
|
||||||
|
case ShaderVisibility::Hull:
|
||||||
|
case ShaderVisibility::Domain:
|
||||||
|
case ShaderVisibility::All:
|
||||||
|
default:
|
||||||
|
return VK_SHADER_STAGE_ALL_GRAPHICS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkFilter ToVulkanMinFilter(FilterMode filter) {
|
||||||
|
switch (filter) {
|
||||||
|
case FilterMode::Point:
|
||||||
|
case FilterMode::ComparisonPoint:
|
||||||
|
case FilterMode::MinimumPoint:
|
||||||
|
case FilterMode::MaximumPoint:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
default:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkFilter ToVulkanMagFilter(FilterMode filter) {
|
||||||
|
switch (filter) {
|
||||||
|
case FilterMode::Point:
|
||||||
|
case FilterMode::ComparisonPoint:
|
||||||
|
case FilterMode::MinimumPoint:
|
||||||
|
case FilterMode::MaximumPoint:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
default:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkSamplerMipmapMode ToVulkanSamplerMipmapMode(FilterMode filter) {
|
||||||
|
switch (filter) {
|
||||||
|
case FilterMode::Point:
|
||||||
|
case FilterMode::ComparisonPoint:
|
||||||
|
case FilterMode::MinimumPoint:
|
||||||
|
case FilterMode::MaximumPoint:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
default:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool UsesVulkanSamplerAnisotropy(FilterMode filter) {
|
||||||
|
return filter == FilterMode::Anisotropic ||
|
||||||
|
filter == FilterMode::ComparisonAnisotropic ||
|
||||||
|
filter == FilterMode::MinimumAnisotropic ||
|
||||||
|
filter == FilterMode::MaximumAnisotropic;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool UsesVulkanComparisonSampling(FilterMode filter) {
|
||||||
|
return filter == FilterMode::ComparisonPoint ||
|
||||||
|
filter == FilterMode::ComparisonLinear ||
|
||||||
|
filter == FilterMode::ComparisonAnisotropic;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkSamplerAddressMode ToVulkanSamplerAddressMode(TextureAddressMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case TextureAddressMode::Wrap:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
case TextureAddressMode::Mirror:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||||
|
case TextureAddressMode::Clamp:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
case TextureAddressMode::Border:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||||
|
case TextureAddressMode::MirrorOnce:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||||
|
default:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkBorderColor ToVulkanBorderColor(float r, float g, float b, float a) {
|
||||||
|
const bool opaqueBlack = std::fabs(r) < 0.0001f &&
|
||||||
|
std::fabs(g) < 0.0001f &&
|
||||||
|
std::fabs(b) < 0.0001f &&
|
||||||
|
std::fabs(a - 1.0f) < 0.0001f;
|
||||||
|
if (opaqueBlack) {
|
||||||
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool opaqueWhite = std::fabs(r - 1.0f) < 0.0001f &&
|
||||||
|
std::fabs(g - 1.0f) < 0.0001f &&
|
||||||
|
std::fabs(b - 1.0f) < 0.0001f &&
|
||||||
|
std::fabs(a - 1.0f) < 0.0001f;
|
||||||
|
if (opaqueWhite) {
|
||||||
|
return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VkImageViewType ToVulkanImageViewType(ResourceViewDimension dimension, TextureType textureType) {
|
||||||
|
switch (dimension) {
|
||||||
|
case ResourceViewDimension::Texture1D:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_1D;
|
||||||
|
case ResourceViewDimension::Texture1DArray:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||||
|
case ResourceViewDimension::Texture2DArray:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||||
|
case ResourceViewDimension::Texture3D:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_3D;
|
||||||
|
case ResourceViewDimension::TextureCube:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||||
|
case ResourceViewDimension::TextureCubeArray:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||||
|
case ResourceViewDimension::Texture2D:
|
||||||
|
case ResourceViewDimension::Unknown:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (textureType) {
|
||||||
|
case TextureType::Texture1D:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_1D;
|
||||||
|
case TextureType::Texture2DArray:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||||
|
case TextureType::Texture3D:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_3D;
|
||||||
|
case TextureType::TextureCube:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_CUBE;
|
||||||
|
case TextureType::TextureCubeArray:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||||
|
case TextureType::Texture2D:
|
||||||
|
default:
|
||||||
|
return VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline uint32_t ResolveVulkanApiMajor(uint32_t apiVersion) {
|
inline uint32_t ResolveVulkanApiMajor(uint32_t apiVersion) {
|
||||||
return VK_API_VERSION_MAJOR(apiVersion);
|
return VK_API_VERSION_MAJOR(apiVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
42
engine/include/XCEngine/RHI/Vulkan/VulkanDescriptorPool.h
Normal file
42
engine/include/XCEngine/RHI/Vulkan/VulkanDescriptorPool.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XCEngine/RHI/RHIDescriptorPool.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanCommon.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class VulkanDescriptorSet;
|
||||||
|
|
||||||
|
class VulkanDescriptorPool : public RHIDescriptorPool {
|
||||||
|
public:
|
||||||
|
VulkanDescriptorPool() = default;
|
||||||
|
~VulkanDescriptorPool() override;
|
||||||
|
|
||||||
|
bool Initialize(VkDevice device, const DescriptorPoolDesc& desc);
|
||||||
|
bool Initialize(const DescriptorPoolDesc& desc) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
void* GetNativeHandle() override { return m_descriptorPool; }
|
||||||
|
|
||||||
|
uint32_t GetDescriptorCount() const override { return m_descriptorCount; }
|
||||||
|
DescriptorHeapType GetType() const override { return m_type; }
|
||||||
|
|
||||||
|
RHIDescriptorSet* AllocateSet(const DescriptorSetLayoutDesc& layout) override;
|
||||||
|
void FreeSet(RHIDescriptorSet* set) override;
|
||||||
|
|
||||||
|
VkDevice GetDevice() const { return m_device; }
|
||||||
|
VkDescriptorPool GetDescriptorPool() const { return m_descriptorPool; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE;
|
||||||
|
DescriptorHeapType m_type = DescriptorHeapType::CBV_SRV_UAV;
|
||||||
|
uint32_t m_descriptorCount = 0;
|
||||||
|
std::vector<VulkanDescriptorSet*> m_allocatedSets;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
63
engine/include/XCEngine/RHI/Vulkan/VulkanDescriptorSet.h
Normal file
63
engine/include/XCEngine/RHI/Vulkan/VulkanDescriptorSet.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XCEngine/RHI/RHIDescriptorSet.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanCommon.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class VulkanDescriptorPool;
|
||||||
|
|
||||||
|
class VulkanDescriptorSet : public RHIDescriptorSet {
|
||||||
|
public:
|
||||||
|
VulkanDescriptorSet() = default;
|
||||||
|
~VulkanDescriptorSet() override;
|
||||||
|
|
||||||
|
bool Initialize(
|
||||||
|
VkDevice device,
|
||||||
|
VulkanDescriptorPool* pool,
|
||||||
|
VkDescriptorSetLayout layout,
|
||||||
|
VkDescriptorSet descriptorSet,
|
||||||
|
const DescriptorSetLayoutDesc& desc);
|
||||||
|
|
||||||
|
void Shutdown() override;
|
||||||
|
void Bind() override;
|
||||||
|
void Unbind() override;
|
||||||
|
|
||||||
|
void Update(uint32_t offset, RHIResourceView* view) override;
|
||||||
|
void UpdateSampler(uint32_t offset, RHISampler* sampler) override;
|
||||||
|
void WriteConstant(uint32_t binding, const void* data, size_t size, size_t offset = 0) override;
|
||||||
|
|
||||||
|
uint32_t GetBindingCount() const override { return static_cast<uint32_t>(m_bindings.size()); }
|
||||||
|
const DescriptorSetLayoutBinding* GetBindings() const override {
|
||||||
|
return m_bindings.empty() ? nullptr : m_bindings.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GetConstantBufferData() override {
|
||||||
|
return m_constantBufferData.empty() ? nullptr : m_constantBufferData.data();
|
||||||
|
}
|
||||||
|
size_t GetConstantBufferSize() const override { return m_constantBufferData.size(); }
|
||||||
|
bool IsConstantDirty() const override { return m_constantDirty; }
|
||||||
|
void MarkConstantClean() override { m_constantDirty = false; }
|
||||||
|
|
||||||
|
VkDescriptorSet GetDescriptorSet() const { return m_descriptorSet; }
|
||||||
|
VkDescriptorSetLayout GetDescriptorSetLayout() const { return m_descriptorSetLayout; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const DescriptorSetLayoutBinding* FindBinding(uint32_t binding) const;
|
||||||
|
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VulkanDescriptorPool* m_pool = nullptr;
|
||||||
|
VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
|
||||||
|
std::vector<DescriptorSetLayoutBinding> m_bindings;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> m_bindingToIndex;
|
||||||
|
std::vector<uint8_t> m_constantBufferData;
|
||||||
|
bool m_constantDirty = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
40
engine/include/XCEngine/RHI/Vulkan/VulkanPipelineLayout.h
Normal file
40
engine/include/XCEngine/RHI/Vulkan/VulkanPipelineLayout.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XCEngine/RHI/RHIPipelineLayout.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanCommon.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class VulkanPipelineLayout : public RHIPipelineLayout {
|
||||||
|
public:
|
||||||
|
VulkanPipelineLayout() = default;
|
||||||
|
~VulkanPipelineLayout() override;
|
||||||
|
|
||||||
|
bool Initialize(VkDevice device, const RHIPipelineLayoutDesc& desc);
|
||||||
|
bool Initialize(const RHIPipelineLayoutDesc& desc) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
void* GetNativeHandle() override { return m_pipelineLayout; }
|
||||||
|
|
||||||
|
VkPipelineLayout GetPipelineLayout() const { return m_pipelineLayout; }
|
||||||
|
const RHIPipelineLayoutDesc& GetDesc() const { return m_desc; }
|
||||||
|
bool UsesSetLayouts() const { return m_desc.setLayoutCount > 0 && m_desc.setLayouts != nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void PrepareExplicitLayouts(const RHIPipelineLayoutDesc& desc);
|
||||||
|
void PrepareFlatLayouts(const RHIPipelineLayoutDesc& desc);
|
||||||
|
bool CreateNativeSetLayouts();
|
||||||
|
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
RHIPipelineLayoutDesc m_desc = {};
|
||||||
|
std::vector<DescriptorSetLayoutDesc> m_setLayouts;
|
||||||
|
std::vector<std::vector<DescriptorSetLayoutBinding>> m_setLayoutBindings;
|
||||||
|
std::vector<VkDescriptorSetLayout> m_nativeSetLayouts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -51,6 +51,7 @@ private:
|
|||||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
||||||
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
VkRenderPass m_renderPass = VK_NULL_HANDLE;
|
VkRenderPass m_renderPass = VK_NULL_HANDLE;
|
||||||
|
bool m_ownsPipelineLayout = false;
|
||||||
InputLayoutDesc m_inputLayoutDesc = {};
|
InputLayoutDesc m_inputLayoutDesc = {};
|
||||||
RasterizerDesc m_rasterizerDesc = {};
|
RasterizerDesc m_rasterizerDesc = {};
|
||||||
BlendDesc m_blendDesc = {};
|
BlendDesc m_blendDesc = {};
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public:
|
|||||||
~VulkanResourceView() override;
|
~VulkanResourceView() override;
|
||||||
|
|
||||||
bool InitializeAsRenderTarget(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc);
|
bool InitializeAsRenderTarget(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc);
|
||||||
|
bool InitializeAsShaderResource(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc);
|
||||||
bool InitializeAsVertexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc);
|
bool InitializeAsVertexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc);
|
||||||
bool InitializeAsIndexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc);
|
bool InitializeAsIndexBuffer(VulkanBuffer* buffer, const ResourceViewDesc& desc);
|
||||||
|
|
||||||
|
|||||||
31
engine/include/XCEngine/RHI/Vulkan/VulkanSampler.h
Normal file
31
engine/include/XCEngine/RHI/Vulkan/VulkanSampler.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XCEngine/RHI/RHISampler.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanCommon.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
class VulkanSampler : public RHISampler {
|
||||||
|
public:
|
||||||
|
VulkanSampler() = default;
|
||||||
|
~VulkanSampler() override;
|
||||||
|
|
||||||
|
bool Initialize(VkDevice device, const SamplerDesc& desc);
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
void Bind(unsigned int unit) override;
|
||||||
|
void Unbind(unsigned int unit) override;
|
||||||
|
|
||||||
|
void* GetNativeHandle() override { return m_sampler != VK_NULL_HANDLE ? &m_sampler : nullptr; }
|
||||||
|
unsigned int GetID() override { return 0; }
|
||||||
|
|
||||||
|
VkSampler GetSampler() const { return m_sampler; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VkSampler m_sampler = VK_NULL_HANDLE;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -20,13 +20,23 @@ public:
|
|||||||
uint32_t height,
|
uint32_t height,
|
||||||
Format format,
|
Format format,
|
||||||
VkFormat vkFormat);
|
VkFormat vkFormat);
|
||||||
|
bool InitializeOwnedImage(
|
||||||
|
VkDevice device,
|
||||||
|
VkImage image,
|
||||||
|
VkDeviceMemory memory,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
uint32_t mipLevels,
|
||||||
|
Format format,
|
||||||
|
TextureType textureType,
|
||||||
|
VkFormat vkFormat);
|
||||||
|
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
uint32_t GetWidth() const override { return m_width; }
|
uint32_t GetWidth() const override { return m_width; }
|
||||||
uint32_t GetHeight() const override { return m_height; }
|
uint32_t GetHeight() const override { return m_height; }
|
||||||
uint32_t GetDepth() const override { return 1; }
|
uint32_t GetDepth() const override { return 1; }
|
||||||
uint32_t GetMipLevels() const override { return 1; }
|
uint32_t GetMipLevels() const override { return m_mipLevels; }
|
||||||
Format GetFormat() const override { return m_format; }
|
Format GetFormat() const override { return m_format; }
|
||||||
TextureType GetTextureType() const override { return m_textureType; }
|
TextureType GetTextureType() const override { return m_textureType; }
|
||||||
|
|
||||||
@@ -39,17 +49,21 @@ public:
|
|||||||
void SetName(const std::string& name) override { m_name = name; }
|
void SetName(const std::string& name) override { m_name = name; }
|
||||||
|
|
||||||
VkImage GetImage() const { return m_image; }
|
VkImage GetImage() const { return m_image; }
|
||||||
|
VkDeviceMemory GetMemory() const { return m_memory; }
|
||||||
VkFormat GetVkFormat() const { return m_vkFormat; }
|
VkFormat GetVkFormat() const { return m_vkFormat; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
VkImage m_image = VK_NULL_HANDLE;
|
VkImage m_image = VK_NULL_HANDLE;
|
||||||
|
VkDeviceMemory m_memory = VK_NULL_HANDLE;
|
||||||
uint32_t m_width = 0;
|
uint32_t m_width = 0;
|
||||||
uint32_t m_height = 0;
|
uint32_t m_height = 0;
|
||||||
|
uint32_t m_mipLevels = 1;
|
||||||
Format m_format = Format::Unknown;
|
Format m_format = Format::Unknown;
|
||||||
TextureType m_textureType = TextureType::Texture2D;
|
TextureType m_textureType = TextureType::Texture2D;
|
||||||
ResourceStates m_state = ResourceStates::Common;
|
ResourceStates m_state = ResourceStates::Common;
|
||||||
VkFormat m_vkFormat = VK_FORMAT_UNDEFINED;
|
VkFormat m_vkFormat = VK_FORMAT_UNDEFINED;
|
||||||
|
bool m_ownsImage = false;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "XCEngine/RHI/Vulkan/VulkanCommandList.h"
|
#include "XCEngine/RHI/Vulkan/VulkanCommandList.h"
|
||||||
|
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanBuffer.h"
|
#include "XCEngine/RHI/Vulkan/VulkanBuffer.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanDescriptorSet.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanDevice.h"
|
#include "XCEngine/RHI/Vulkan/VulkanDevice.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanPipelineLayout.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanResourceView.h"
|
#include "XCEngine/RHI/Vulkan/VulkanResourceView.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
|
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
|
||||||
@@ -217,17 +219,66 @@ void VulkanCommandList::SetPipelineState(RHIPipelineState* pso) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommandList::SetGraphicsDescriptorSets(uint32_t firstSet, uint32_t count, RHIDescriptorSet** descriptorSets, RHIPipelineLayout* pipelineLayout) {
|
void VulkanCommandList::SetGraphicsDescriptorSets(uint32_t firstSet, uint32_t count, RHIDescriptorSet** descriptorSets, RHIPipelineLayout* pipelineLayout) {
|
||||||
(void)firstSet;
|
if (count == 0 || descriptorSets == nullptr || m_commandBuffer == VK_NULL_HANDLE) {
|
||||||
(void)count;
|
return;
|
||||||
(void)descriptorSets;
|
}
|
||||||
(void)pipelineLayout;
|
|
||||||
|
VkPipelineLayout nativePipelineLayout = VK_NULL_HANDLE;
|
||||||
|
if (pipelineLayout != nullptr) {
|
||||||
|
nativePipelineLayout = static_cast<VulkanPipelineLayout*>(pipelineLayout)->GetPipelineLayout();
|
||||||
|
} else if (m_currentPipelineState != nullptr) {
|
||||||
|
nativePipelineLayout = m_currentPipelineState->GetPipelineLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nativePipelineLayout == VK_NULL_HANDLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VkDescriptorSet> nativeSets;
|
||||||
|
nativeSets.reserve(count);
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
auto* descriptorSet = static_cast<VulkanDescriptorSet*>(descriptorSets[i]);
|
||||||
|
if (descriptorSet == nullptr || descriptorSet->GetDescriptorSet() == VK_NULL_HANDLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nativeSets.push_back(descriptorSet->GetDescriptorSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(
|
||||||
|
m_commandBuffer,
|
||||||
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
nativePipelineLayout,
|
||||||
|
firstSet,
|
||||||
|
static_cast<uint32_t>(nativeSets.size()),
|
||||||
|
nativeSets.data(),
|
||||||
|
0,
|
||||||
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommandList::SetComputeDescriptorSets(uint32_t firstSet, uint32_t count, RHIDescriptorSet** descriptorSets, RHIPipelineLayout* pipelineLayout) {
|
void VulkanCommandList::SetComputeDescriptorSets(uint32_t firstSet, uint32_t count, RHIDescriptorSet** descriptorSets, RHIPipelineLayout* pipelineLayout) {
|
||||||
(void)firstSet;
|
if (count == 0 || descriptorSets == nullptr || m_commandBuffer == VK_NULL_HANDLE || pipelineLayout == nullptr) {
|
||||||
(void)count;
|
return;
|
||||||
(void)descriptorSets;
|
}
|
||||||
(void)pipelineLayout;
|
|
||||||
|
std::vector<VkDescriptorSet> nativeSets;
|
||||||
|
nativeSets.reserve(count);
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
auto* descriptorSet = static_cast<VulkanDescriptorSet*>(descriptorSets[i]);
|
||||||
|
if (descriptorSet == nullptr || descriptorSet->GetDescriptorSet() == VK_NULL_HANDLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nativeSets.push_back(descriptorSet->GetDescriptorSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(
|
||||||
|
m_commandBuffer,
|
||||||
|
VK_PIPELINE_BIND_POINT_COMPUTE,
|
||||||
|
static_cast<VulkanPipelineLayout*>(pipelineLayout)->GetPipelineLayout(),
|
||||||
|
firstSet,
|
||||||
|
static_cast<uint32_t>(nativeSets.size()),
|
||||||
|
nativeSets.data(),
|
||||||
|
0,
|
||||||
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanCommandList::SetPrimitiveTopology(PrimitiveTopology topology) {
|
void VulkanCommandList::SetPrimitiveTopology(PrimitiveTopology topology) {
|
||||||
|
|||||||
140
engine/src/RHI/Vulkan/VulkanDescriptorPool.cpp
Normal file
140
engine/src/RHI/Vulkan/VulkanDescriptorPool.cpp
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include "XCEngine/RHI/Vulkan/VulkanDescriptorPool.h"
|
||||||
|
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanDescriptorSet.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::vector<VkDescriptorSetLayoutBinding> BuildVulkanLayoutBindings(const DescriptorSetLayoutDesc& layout) {
|
||||||
|
std::vector<VkDescriptorSetLayoutBinding> bindings;
|
||||||
|
bindings.reserve(layout.bindingCount);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < layout.bindingCount; ++i) {
|
||||||
|
const DescriptorSetLayoutBinding& binding = layout.bindings[i];
|
||||||
|
VkDescriptorSetLayoutBinding vkBinding = {};
|
||||||
|
vkBinding.binding = binding.binding;
|
||||||
|
vkBinding.descriptorType = ToVulkanDescriptorType(static_cast<DescriptorType>(binding.type));
|
||||||
|
vkBinding.descriptorCount = binding.count > 0 ? binding.count : 1u;
|
||||||
|
vkBinding.stageFlags = ToVulkanShaderStageFlags(binding.visibility);
|
||||||
|
bindings.push_back(vkBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
VulkanDescriptorPool::~VulkanDescriptorPool() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanDescriptorPool::Initialize(VkDevice device, const DescriptorPoolDesc& desc) {
|
||||||
|
if (device == VK_NULL_HANDLE || desc.descriptorCount == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
|
m_type = desc.type;
|
||||||
|
m_descriptorCount = desc.descriptorCount;
|
||||||
|
|
||||||
|
std::vector<VkDescriptorPoolSize> poolSizes;
|
||||||
|
switch (desc.type) {
|
||||||
|
case DescriptorHeapType::CBV_SRV_UAV:
|
||||||
|
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, desc.descriptorCount });
|
||||||
|
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, desc.descriptorCount });
|
||||||
|
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, desc.descriptorCount });
|
||||||
|
break;
|
||||||
|
case DescriptorHeapType::Sampler:
|
||||||
|
poolSizes.push_back({ VK_DESCRIPTOR_TYPE_SAMPLER, desc.descriptorCount });
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorPoolCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||||
|
createInfo.maxSets = desc.descriptorCount;
|
||||||
|
createInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
|
||||||
|
createInfo.pPoolSizes = poolSizes.data();
|
||||||
|
|
||||||
|
return vkCreateDescriptorPool(device, &createInfo, nullptr, &m_descriptorPool) == VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanDescriptorPool::Initialize(const DescriptorPoolDesc& desc) {
|
||||||
|
return Initialize(static_cast<VkDevice>(desc.device), desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorPool::Shutdown() {
|
||||||
|
m_allocatedSets.clear();
|
||||||
|
|
||||||
|
if (m_descriptorPool != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorPool(m_device, m_descriptorPool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_descriptorPool = VK_NULL_HANDLE;
|
||||||
|
m_device = VK_NULL_HANDLE;
|
||||||
|
m_type = DescriptorHeapType::CBV_SRV_UAV;
|
||||||
|
m_descriptorCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHIDescriptorSet* VulkanDescriptorPool::AllocateSet(const DescriptorSetLayoutDesc& layout) {
|
||||||
|
if (m_device == VK_NULL_HANDLE || m_descriptorPool == VK_NULL_HANDLE) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<VkDescriptorSetLayoutBinding> vkBindings = BuildVulkanLayoutBindings(layout);
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
|
||||||
|
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
layoutInfo.bindingCount = static_cast<uint32_t>(vkBindings.size());
|
||||||
|
layoutInfo.pBindings = vkBindings.empty() ? nullptr : vkBindings.data();
|
||||||
|
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
if (vkCreateDescriptorSetLayout(m_device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetAllocateInfo allocateInfo = {};
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
allocateInfo.descriptorPool = m_descriptorPool;
|
||||||
|
allocateInfo.descriptorSetCount = 1;
|
||||||
|
allocateInfo.pSetLayouts = &descriptorSetLayout;
|
||||||
|
|
||||||
|
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
||||||
|
if (vkAllocateDescriptorSets(m_device, &allocateInfo, &descriptorSet) != VK_SUCCESS) {
|
||||||
|
vkDestroyDescriptorSetLayout(m_device, descriptorSetLayout, nullptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* set = new VulkanDescriptorSet();
|
||||||
|
if (!set->Initialize(m_device, this, descriptorSetLayout, descriptorSet, layout)) {
|
||||||
|
set->Shutdown();
|
||||||
|
delete set;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_allocatedSets.push_back(set);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorPool::FreeSet(RHIDescriptorSet* set) {
|
||||||
|
if (set == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* vulkanSet = static_cast<VulkanDescriptorSet*>(set);
|
||||||
|
auto it = std::find(m_allocatedSets.begin(), m_allocatedSets.end(), vulkanSet);
|
||||||
|
if (it != m_allocatedSets.end()) {
|
||||||
|
m_allocatedSets.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete vulkanSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
155
engine/src/RHI/Vulkan/VulkanDescriptorSet.cpp
Normal file
155
engine/src/RHI/Vulkan/VulkanDescriptorSet.cpp
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
#include "XCEngine/RHI/Vulkan/VulkanDescriptorSet.h"
|
||||||
|
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanDescriptorPool.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanResourceView.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanSampler.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
VulkanDescriptorSet::~VulkanDescriptorSet() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanDescriptorSet::Initialize(
|
||||||
|
VkDevice device,
|
||||||
|
VulkanDescriptorPool* pool,
|
||||||
|
VkDescriptorSetLayout layout,
|
||||||
|
VkDescriptorSet descriptorSet,
|
||||||
|
const DescriptorSetLayoutDesc& desc) {
|
||||||
|
if (device == VK_NULL_HANDLE || pool == nullptr || layout == VK_NULL_HANDLE || descriptorSet == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
|
m_pool = pool;
|
||||||
|
m_descriptorSetLayout = layout;
|
||||||
|
m_descriptorSet = descriptorSet;
|
||||||
|
if (desc.bindingCount > 0 && desc.bindings != nullptr) {
|
||||||
|
m_bindings.assign(desc.bindings, desc.bindings + desc.bindingCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_bindings.size(); ++i) {
|
||||||
|
m_bindingToIndex[m_bindings[i].binding] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSet::Shutdown() {
|
||||||
|
if (m_descriptorSet != VK_NULL_HANDLE &&
|
||||||
|
m_pool != nullptr &&
|
||||||
|
m_pool->GetDevice() != VK_NULL_HANDLE &&
|
||||||
|
m_pool->GetDescriptorPool() != VK_NULL_HANDLE) {
|
||||||
|
vkFreeDescriptorSets(m_pool->GetDevice(), m_pool->GetDescriptorPool(), 1, &m_descriptorSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_descriptorSetLayout != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorSetLayout(m_device, m_descriptorSetLayout, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = VK_NULL_HANDLE;
|
||||||
|
m_pool = nullptr;
|
||||||
|
m_descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
m_descriptorSet = VK_NULL_HANDLE;
|
||||||
|
m_bindings.clear();
|
||||||
|
m_bindingToIndex.clear();
|
||||||
|
m_constantBufferData.clear();
|
||||||
|
m_constantDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSet::Bind() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSet::Unbind() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
|
||||||
|
if (m_device == VK_NULL_HANDLE || m_descriptorSet == VK_NULL_HANDLE || view == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DescriptorSetLayoutBinding* binding = FindBinding(offset);
|
||||||
|
if (binding == nullptr ||
|
||||||
|
static_cast<DescriptorType>(binding->type) != DescriptorType::SRV) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* vulkanView = static_cast<VulkanResourceView*>(view);
|
||||||
|
if (vulkanView == nullptr || vulkanView->GetImageView() == VK_NULL_HANDLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorImageInfo imageInfo = {};
|
||||||
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
imageInfo.imageView = vulkanView->GetImageView();
|
||||||
|
|
||||||
|
VkWriteDescriptorSet write = {};
|
||||||
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
write.dstSet = m_descriptorSet;
|
||||||
|
write.dstBinding = offset;
|
||||||
|
write.descriptorCount = 1;
|
||||||
|
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||||
|
write.pImageInfo = &imageInfo;
|
||||||
|
|
||||||
|
vkUpdateDescriptorSets(m_device, 1, &write, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
|
||||||
|
if (m_device == VK_NULL_HANDLE || m_descriptorSet == VK_NULL_HANDLE || sampler == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DescriptorSetLayoutBinding* binding = FindBinding(offset);
|
||||||
|
if (binding == nullptr ||
|
||||||
|
static_cast<DescriptorType>(binding->type) != DescriptorType::Sampler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* vulkanSampler = static_cast<VulkanSampler*>(sampler);
|
||||||
|
if (vulkanSampler == nullptr || vulkanSampler->GetSampler() == VK_NULL_HANDLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorImageInfo imageInfo = {};
|
||||||
|
imageInfo.sampler = vulkanSampler->GetSampler();
|
||||||
|
|
||||||
|
VkWriteDescriptorSet write = {};
|
||||||
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
write.dstSet = m_descriptorSet;
|
||||||
|
write.dstBinding = offset;
|
||||||
|
write.descriptorCount = 1;
|
||||||
|
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
|
write.pImageInfo = &imageInfo;
|
||||||
|
|
||||||
|
vkUpdateDescriptorSets(m_device, 1, &write, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDescriptorSet::WriteConstant(uint32_t binding, const void* data, size_t size, size_t offset) {
|
||||||
|
(void)binding;
|
||||||
|
|
||||||
|
if (data == nullptr || size == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_constantBufferData.size() < offset + size) {
|
||||||
|
m_constantBufferData.resize(offset + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(m_constantBufferData.data() + offset, data, size);
|
||||||
|
m_constantDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DescriptorSetLayoutBinding* VulkanDescriptorSet::FindBinding(uint32_t binding) const {
|
||||||
|
auto it = m_bindingToIndex.find(binding);
|
||||||
|
if (it == m_bindingToIndex.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &m_bindings[it->second];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -3,14 +3,19 @@
|
|||||||
#include "XCEngine/RHI/Vulkan/VulkanBuffer.h"
|
#include "XCEngine/RHI/Vulkan/VulkanBuffer.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanCommandList.h"
|
#include "XCEngine/RHI/Vulkan/VulkanCommandList.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanCommandQueue.h"
|
#include "XCEngine/RHI/Vulkan/VulkanCommandQueue.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanDescriptorPool.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanDescriptorSet.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanFence.h"
|
#include "XCEngine/RHI/Vulkan/VulkanFence.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanPipelineLayout.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanResourceView.h"
|
#include "XCEngine/RHI/Vulkan/VulkanResourceView.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanSampler.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanSwapChain.h"
|
#include "XCEngine/RHI/Vulkan/VulkanSwapChain.h"
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
|
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
@@ -29,6 +34,261 @@ std::wstring ResolveVendorName(uint32_t vendorId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkImageType ToVulkanImageType(TextureType type) {
|
||||||
|
switch (type) {
|
||||||
|
case TextureType::Texture1D:
|
||||||
|
return VK_IMAGE_TYPE_1D;
|
||||||
|
case TextureType::Texture3D:
|
||||||
|
return VK_IMAGE_TYPE_3D;
|
||||||
|
case TextureType::Texture2D:
|
||||||
|
case TextureType::Texture2DArray:
|
||||||
|
case TextureType::TextureCube:
|
||||||
|
case TextureType::TextureCubeArray:
|
||||||
|
default:
|
||||||
|
return VK_IMAGE_TYPE_2D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageLayout ToImageLayout(ResourceStates state) {
|
||||||
|
switch (state) {
|
||||||
|
case ResourceStates::RenderTarget:
|
||||||
|
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
case ResourceStates::CopySrc:
|
||||||
|
return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
|
case ResourceStates::CopyDst:
|
||||||
|
return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
case ResourceStates::Present:
|
||||||
|
return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
case ResourceStates::PixelShaderResource:
|
||||||
|
return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
case ResourceStates::DepthWrite:
|
||||||
|
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
case ResourceStates::Common:
|
||||||
|
default:
|
||||||
|
return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkAccessFlags ToAccessMask(ResourceStates state) {
|
||||||
|
switch (state) {
|
||||||
|
case ResourceStates::RenderTarget:
|
||||||
|
return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
case ResourceStates::CopySrc:
|
||||||
|
return VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
case ResourceStates::CopyDst:
|
||||||
|
return VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
case ResourceStates::PixelShaderResource:
|
||||||
|
return VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
case ResourceStates::DepthWrite:
|
||||||
|
return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
case ResourceStates::Present:
|
||||||
|
case ResourceStates::Common:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineStageFlags ToStageMask(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;
|
||||||
|
case ResourceStates::PixelShaderResource:
|
||||||
|
return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
|
case ResourceStates::DepthWrite:
|
||||||
|
return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||||
|
case ResourceStates::Present:
|
||||||
|
return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||||
|
case ResourceStates::Common:
|
||||||
|
default:
|
||||||
|
return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageUsageFlags ResolveTextureUsageFlags(const TextureDesc& desc) {
|
||||||
|
const Format format = static_cast<Format>(desc.format);
|
||||||
|
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
|
if ((GetImageAspectMask(format) & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
|
||||||
|
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||||
|
} else {
|
||||||
|
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
}
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BeginSingleUseCommands(VkDevice device, uint32_t queueFamilyIndex, VkCommandPool& commandPool, VkCommandBuffer& commandBuffer) {
|
||||||
|
VkCommandPoolCreateInfo poolInfo = {};
|
||||||
|
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
poolInfo.queueFamilyIndex = queueFamilyIndex;
|
||||||
|
poolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
|
||||||
|
|
||||||
|
if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo allocateInfo = {};
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
allocateInfo.commandPool = commandPool;
|
||||||
|
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
allocateInfo.commandBufferCount = 1;
|
||||||
|
if (vkAllocateCommandBuffers(device, &allocateInfo, &commandBuffer) != VK_SUCCESS) {
|
||||||
|
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||||
|
commandPool = VK_NULL_HANDLE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo beginInfo = {};
|
||||||
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
|
||||||
|
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
|
||||||
|
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||||
|
commandPool = VK_NULL_HANDLE;
|
||||||
|
commandBuffer = VK_NULL_HANDLE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndSingleUseCommands(VkDevice device, VkQueue queue, VkCommandPool commandPool, VkCommandBuffer commandBuffer) {
|
||||||
|
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {
|
||||||
|
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
|
||||||
|
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSubmitInfo submitInfo = {};
|
||||||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &commandBuffer;
|
||||||
|
|
||||||
|
const bool success = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE) == VK_SUCCESS &&
|
||||||
|
vkQueueWaitIdle(queue) == VK_SUCCESS;
|
||||||
|
|
||||||
|
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
|
||||||
|
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionImage(
|
||||||
|
VkCommandBuffer commandBuffer,
|
||||||
|
VkImage image,
|
||||||
|
Format format,
|
||||||
|
ResourceStates before,
|
||||||
|
ResourceStates after,
|
||||||
|
uint32_t mipLevels,
|
||||||
|
uint32_t arraySize) {
|
||||||
|
VkImageMemoryBarrier barrier = {};
|
||||||
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
barrier.oldLayout = ToImageLayout(before);
|
||||||
|
barrier.newLayout = ToImageLayout(after);
|
||||||
|
barrier.srcAccessMask = ToAccessMask(before);
|
||||||
|
barrier.dstAccessMask = ToAccessMask(after);
|
||||||
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.image = image;
|
||||||
|
barrier.subresourceRange.aspectMask = GetImageAspectMask(format);
|
||||||
|
barrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
barrier.subresourceRange.levelCount = mipLevels > 0 ? mipLevels : 1u;
|
||||||
|
barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
barrier.subresourceRange.layerCount = arraySize > 0 ? arraySize : 1u;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
commandBuffer,
|
||||||
|
ToStageMask(before),
|
||||||
|
ToStageMask(after),
|
||||||
|
0,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UploadTextureData(
|
||||||
|
VulkanDevice* device,
|
||||||
|
VulkanTexture* texture,
|
||||||
|
const TextureDesc& desc,
|
||||||
|
const void* initialData,
|
||||||
|
size_t initialDataSize,
|
||||||
|
uint32_t rowPitch) {
|
||||||
|
if (device == nullptr || texture == nullptr || initialData == nullptr || initialDataSize == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Format format = static_cast<Format>(desc.format);
|
||||||
|
const uint32_t pixelSize = GetFormatSize(format);
|
||||||
|
if (pixelSize == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferDesc stagingDesc = {};
|
||||||
|
stagingDesc.size = initialDataSize;
|
||||||
|
stagingDesc.stride = 1;
|
||||||
|
stagingDesc.bufferType = static_cast<uint32_t>(BufferType::Vertex);
|
||||||
|
|
||||||
|
VulkanBuffer stagingBuffer;
|
||||||
|
if (!stagingBuffer.Initialize(
|
||||||
|
device,
|
||||||
|
stagingDesc,
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stagingBuffer.SetData(initialData, initialDataSize);
|
||||||
|
|
||||||
|
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||||
|
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||||
|
if (!BeginSingleUseCommands(device->GetDevice(), device->GetGraphicsQueueFamilyIndex(), commandPool, commandBuffer)) {
|
||||||
|
stagingBuffer.Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionImage(
|
||||||
|
commandBuffer,
|
||||||
|
texture->GetImage(),
|
||||||
|
format,
|
||||||
|
ResourceStates::Common,
|
||||||
|
ResourceStates::CopyDst,
|
||||||
|
desc.mipLevels,
|
||||||
|
desc.arraySize);
|
||||||
|
|
||||||
|
VkBufferImageCopy copyRegion = {};
|
||||||
|
copyRegion.bufferOffset = 0;
|
||||||
|
copyRegion.bufferRowLength = rowPitch > 0 ? rowPitch / pixelSize : 0;
|
||||||
|
copyRegion.bufferImageHeight = 0;
|
||||||
|
copyRegion.imageSubresource.aspectMask = GetImageAspectMask(format);
|
||||||
|
copyRegion.imageSubresource.mipLevel = 0;
|
||||||
|
copyRegion.imageSubresource.baseArrayLayer = 0;
|
||||||
|
copyRegion.imageSubresource.layerCount = desc.arraySize > 0 ? desc.arraySize : 1u;
|
||||||
|
copyRegion.imageExtent.width = desc.width;
|
||||||
|
copyRegion.imageExtent.height = desc.height;
|
||||||
|
copyRegion.imageExtent.depth = desc.depth > 0 ? desc.depth : 1u;
|
||||||
|
|
||||||
|
vkCmdCopyBufferToImage(
|
||||||
|
commandBuffer,
|
||||||
|
stagingBuffer.GetBuffer(),
|
||||||
|
texture->GetImage(),
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
1,
|
||||||
|
©Region);
|
||||||
|
|
||||||
|
TransitionImage(
|
||||||
|
commandBuffer,
|
||||||
|
texture->GetImage(),
|
||||||
|
format,
|
||||||
|
ResourceStates::CopyDst,
|
||||||
|
ResourceStates::PixelShaderResource,
|
||||||
|
desc.mipLevels,
|
||||||
|
desc.arraySize);
|
||||||
|
|
||||||
|
const bool submitted = EndSingleUseCommands(device->GetDevice(), device->GetGraphicsQueue(), commandPool, commandBuffer);
|
||||||
|
stagingBuffer.Shutdown();
|
||||||
|
return submitted;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
VulkanDevice::~VulkanDevice() {
|
VulkanDevice::~VulkanDevice() {
|
||||||
@@ -233,16 +493,91 @@ RHIBuffer* VulkanDevice::CreateBuffer(const BufferDesc& desc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RHITexture* VulkanDevice::CreateTexture(const TextureDesc& desc) {
|
RHITexture* VulkanDevice::CreateTexture(const TextureDesc& desc) {
|
||||||
(void)desc;
|
const Format format = static_cast<Format>(desc.format);
|
||||||
|
const VkFormat vkFormat = ToVulkanFormat(format);
|
||||||
|
if (m_device == VK_NULL_HANDLE ||
|
||||||
|
vkFormat == VK_FORMAT_UNDEFINED ||
|
||||||
|
desc.width == 0 ||
|
||||||
|
desc.height == 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageCreateInfo imageInfo = {};
|
||||||
|
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
imageInfo.imageType = ToVulkanImageType(static_cast<TextureType>(desc.textureType));
|
||||||
|
imageInfo.extent.width = desc.width;
|
||||||
|
imageInfo.extent.height = desc.height;
|
||||||
|
imageInfo.extent.depth = desc.depth > 0 ? desc.depth : 1u;
|
||||||
|
imageInfo.mipLevels = desc.mipLevels > 0 ? desc.mipLevels : 1u;
|
||||||
|
imageInfo.arrayLayers = desc.arraySize > 0 ? desc.arraySize : 1u;
|
||||||
|
imageInfo.format = vkFormat;
|
||||||
|
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
imageInfo.usage = ResolveTextureUsageFlags(desc);
|
||||||
|
imageInfo.samples = ToVulkanSampleCount(desc.sampleCount > 0 ? desc.sampleCount : 1u);
|
||||||
|
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
VkImage image = VK_NULL_HANDLE;
|
||||||
|
if (vkCreateImage(m_device, &imageInfo, nullptr, &image) != VK_SUCCESS) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMemoryRequirements memoryRequirements = {};
|
||||||
|
vkGetImageMemoryRequirements(m_device, image, &memoryRequirements);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocateInfo = {};
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
allocateInfo.allocationSize = memoryRequirements.size;
|
||||||
|
allocateInfo.memoryTypeIndex = FindMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
if (allocateInfo.memoryTypeIndex == UINT32_MAX) {
|
||||||
|
vkDestroyImage(m_device, image, nullptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||||
|
if (vkAllocateMemory(m_device, &allocateInfo, nullptr, &memory) != VK_SUCCESS) {
|
||||||
|
vkDestroyImage(m_device, image, nullptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vkBindImageMemory(m_device, image, memory, 0) != VK_SUCCESS) {
|
||||||
|
vkFreeMemory(m_device, memory, nullptr);
|
||||||
|
vkDestroyImage(m_device, image, nullptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* texture = new VulkanTexture();
|
||||||
|
if (!texture->InitializeOwnedImage(
|
||||||
|
m_device,
|
||||||
|
image,
|
||||||
|
memory,
|
||||||
|
desc.width,
|
||||||
|
desc.height,
|
||||||
|
imageInfo.mipLevels,
|
||||||
|
format,
|
||||||
|
static_cast<TextureType>(desc.textureType),
|
||||||
|
vkFormat)) {
|
||||||
|
delete texture;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
RHITexture* VulkanDevice::CreateTexture(const TextureDesc& desc, const void* initialData, size_t initialDataSize, uint32_t rowPitch) {
|
RHITexture* VulkanDevice::CreateTexture(const TextureDesc& desc, const void* initialData, size_t initialDataSize, uint32_t rowPitch) {
|
||||||
(void)desc;
|
auto texture = std::unique_ptr<VulkanTexture>(static_cast<VulkanTexture*>(CreateTexture(desc)));
|
||||||
(void)initialData;
|
if (!texture) {
|
||||||
(void)initialDataSize;
|
|
||||||
(void)rowPitch;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialData != nullptr && initialDataSize > 0) {
|
||||||
|
if (!UploadTextureData(this, texture.get(), desc, initialData, initialDataSize, rowPitch)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
texture->SetState(ResourceStates::PixelShaderResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
RHISwapChain* VulkanDevice::CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) {
|
RHISwapChain* VulkanDevice::CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) {
|
||||||
@@ -289,7 +624,12 @@ RHIPipelineState* VulkanDevice::CreatePipelineState(const GraphicsPipelineDesc&
|
|||||||
}
|
}
|
||||||
|
|
||||||
RHIPipelineLayout* VulkanDevice::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) {
|
RHIPipelineLayout* VulkanDevice::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) {
|
||||||
(void)desc;
|
auto* pipelineLayout = new VulkanPipelineLayout();
|
||||||
|
if (pipelineLayout->Initialize(m_device, desc)) {
|
||||||
|
return pipelineLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pipelineLayout;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +638,12 @@ RHIFence* VulkanDevice::CreateFence(const FenceDesc& desc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RHISampler* VulkanDevice::CreateSampler(const SamplerDesc& desc) {
|
RHISampler* VulkanDevice::CreateSampler(const SamplerDesc& desc) {
|
||||||
(void)desc;
|
auto* sampler = new VulkanSampler();
|
||||||
|
if (sampler->Initialize(m_device, desc)) {
|
||||||
|
return sampler;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete sampler;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,14 +665,17 @@ RHIFramebuffer* VulkanDevice::CreateFramebuffer(class RHIRenderPass* renderPass,
|
|||||||
}
|
}
|
||||||
|
|
||||||
RHIDescriptorPool* VulkanDevice::CreateDescriptorPool(const DescriptorPoolDesc& desc) {
|
RHIDescriptorPool* VulkanDevice::CreateDescriptorPool(const DescriptorPoolDesc& desc) {
|
||||||
(void)desc;
|
auto* pool = new VulkanDescriptorPool();
|
||||||
|
if (pool->Initialize(m_device, desc)) {
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pool;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RHIDescriptorSet* VulkanDevice::CreateDescriptorSet(RHIDescriptorPool* pool, const DescriptorSetLayoutDesc& layout) {
|
RHIDescriptorSet* VulkanDevice::CreateDescriptorSet(RHIDescriptorPool* pool, const DescriptorSetLayoutDesc& layout) {
|
||||||
(void)pool;
|
return pool != nullptr ? pool->AllocateSet(layout) : nullptr;
|
||||||
(void)layout;
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RHIResourceView* VulkanDevice::CreateVertexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
RHIResourceView* VulkanDevice::CreateVertexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
||||||
@@ -366,8 +714,12 @@ RHIResourceView* VulkanDevice::CreateDepthStencilView(RHITexture* texture, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
RHIResourceView* VulkanDevice::CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) {
|
RHIResourceView* VulkanDevice::CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) {
|
||||||
(void)texture;
|
auto* view = new VulkanResourceView();
|
||||||
(void)desc;
|
if (view->InitializeAsShaderResource(m_device, static_cast<VulkanTexture*>(texture), desc)) {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete view;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
190
engine/src/RHI/Vulkan/VulkanPipelineLayout.cpp
Normal file
190
engine/src/RHI/Vulkan/VulkanPipelineLayout.cpp
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#include "XCEngine/RHI/Vulkan/VulkanPipelineLayout.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void AppendSyntheticSetLayout(
|
||||||
|
std::vector<DescriptorSetLayoutDesc>& setLayouts,
|
||||||
|
std::vector<std::vector<DescriptorSetLayoutBinding>>& setLayoutBindings,
|
||||||
|
DescriptorType type,
|
||||||
|
uint32_t count) {
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayoutBindings.emplace_back();
|
||||||
|
setLayoutBindings.back().push_back({
|
||||||
|
0,
|
||||||
|
static_cast<uint32_t>(type),
|
||||||
|
count,
|
||||||
|
static_cast<uint32_t>(ShaderVisibility::All)
|
||||||
|
});
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc setLayout = {};
|
||||||
|
setLayout.bindingCount = 1;
|
||||||
|
setLayout.bindings = setLayoutBindings.back().data();
|
||||||
|
setLayouts.push_back(setLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
VulkanPipelineLayout::~VulkanPipelineLayout() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanPipelineLayout::Initialize(VkDevice device, const RHIPipelineLayoutDesc& desc) {
|
||||||
|
if (device == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
|
m_desc = desc;
|
||||||
|
m_setLayouts.clear();
|
||||||
|
m_setLayoutBindings.clear();
|
||||||
|
m_nativeSetLayouts.clear();
|
||||||
|
|
||||||
|
if (desc.setLayoutCount > 0 && desc.setLayouts != nullptr) {
|
||||||
|
PrepareExplicitLayouts(desc);
|
||||||
|
} else {
|
||||||
|
PrepareFlatLayouts(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreateNativeSetLayouts()) {
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
createInfo.setLayoutCount = static_cast<uint32_t>(m_nativeSetLayouts.size());
|
||||||
|
createInfo.pSetLayouts = m_nativeSetLayouts.empty() ? nullptr : m_nativeSetLayouts.data();
|
||||||
|
|
||||||
|
if (vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) {
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanPipelineLayout::Initialize(const RHIPipelineLayoutDesc& desc) {
|
||||||
|
(void)desc;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanPipelineLayout::PrepareExplicitLayouts(const RHIPipelineLayoutDesc& desc) {
|
||||||
|
m_desc.constantBufferCount = 0;
|
||||||
|
m_desc.textureCount = 0;
|
||||||
|
m_desc.samplerCount = 0;
|
||||||
|
m_desc.uavCount = 0;
|
||||||
|
|
||||||
|
m_setLayouts.resize(desc.setLayoutCount);
|
||||||
|
m_setLayoutBindings.resize(desc.setLayoutCount);
|
||||||
|
|
||||||
|
for (uint32_t setIndex = 0; setIndex < desc.setLayoutCount; ++setIndex) {
|
||||||
|
const DescriptorSetLayoutDesc& srcSetLayout = desc.setLayouts[setIndex];
|
||||||
|
auto& dstBindings = m_setLayoutBindings[setIndex];
|
||||||
|
if (srcSetLayout.bindingCount > 0 && srcSetLayout.bindings != nullptr) {
|
||||||
|
dstBindings.assign(srcSetLayout.bindings, srcSetLayout.bindings + srcSetLayout.bindingCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc dstSetLayout = {};
|
||||||
|
dstSetLayout.bindingCount = srcSetLayout.bindingCount;
|
||||||
|
dstSetLayout.bindings = dstBindings.empty() ? nullptr : dstBindings.data();
|
||||||
|
m_setLayouts[setIndex] = dstSetLayout;
|
||||||
|
|
||||||
|
for (const DescriptorSetLayoutBinding& binding : dstBindings) {
|
||||||
|
switch (static_cast<DescriptorType>(binding.type)) {
|
||||||
|
case DescriptorType::CBV:
|
||||||
|
m_desc.constantBufferCount += binding.count;
|
||||||
|
break;
|
||||||
|
case DescriptorType::SRV:
|
||||||
|
m_desc.textureCount += binding.count;
|
||||||
|
break;
|
||||||
|
case DescriptorType::UAV:
|
||||||
|
m_desc.uavCount += binding.count;
|
||||||
|
break;
|
||||||
|
case DescriptorType::Sampler:
|
||||||
|
m_desc.samplerCount += binding.count;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_desc.setLayouts = m_setLayouts.empty() ? nullptr : m_setLayouts.data();
|
||||||
|
m_desc.setLayoutCount = static_cast<uint32_t>(m_setLayouts.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanPipelineLayout::PrepareFlatLayouts(const RHIPipelineLayoutDesc& desc) {
|
||||||
|
AppendSyntheticSetLayout(m_setLayouts, m_setLayoutBindings, DescriptorType::CBV, desc.constantBufferCount);
|
||||||
|
AppendSyntheticSetLayout(m_setLayouts, m_setLayoutBindings, DescriptorType::SRV, desc.textureCount);
|
||||||
|
AppendSyntheticSetLayout(m_setLayouts, m_setLayoutBindings, DescriptorType::UAV, desc.uavCount);
|
||||||
|
AppendSyntheticSetLayout(m_setLayouts, m_setLayoutBindings, DescriptorType::Sampler, desc.samplerCount);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_setLayouts.size(); ++i) {
|
||||||
|
m_setLayouts[i].bindingCount = static_cast<uint32_t>(m_setLayoutBindings[i].size());
|
||||||
|
m_setLayouts[i].bindings = m_setLayoutBindings[i].empty() ? nullptr : m_setLayoutBindings[i].data();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_desc.setLayouts = m_setLayouts.empty() ? nullptr : m_setLayouts.data();
|
||||||
|
m_desc.setLayoutCount = static_cast<uint32_t>(m_setLayouts.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanPipelineLayout::CreateNativeSetLayouts() {
|
||||||
|
m_nativeSetLayouts.reserve(m_setLayouts.size());
|
||||||
|
|
||||||
|
for (const DescriptorSetLayoutDesc& setLayout : m_setLayouts) {
|
||||||
|
std::vector<VkDescriptorSetLayoutBinding> vkBindings;
|
||||||
|
vkBindings.reserve(setLayout.bindingCount);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < setLayout.bindingCount; ++i) {
|
||||||
|
const DescriptorSetLayoutBinding& binding = setLayout.bindings[i];
|
||||||
|
VkDescriptorSetLayoutBinding vkBinding = {};
|
||||||
|
vkBinding.binding = binding.binding;
|
||||||
|
vkBinding.descriptorType = ToVulkanDescriptorType(static_cast<DescriptorType>(binding.type));
|
||||||
|
vkBinding.descriptorCount = binding.count > 0 ? binding.count : 1u;
|
||||||
|
vkBinding.stageFlags = ToVulkanShaderStageFlags(binding.visibility);
|
||||||
|
vkBindings.push_back(vkBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
|
||||||
|
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
layoutInfo.bindingCount = static_cast<uint32_t>(vkBindings.size());
|
||||||
|
layoutInfo.pBindings = vkBindings.empty() ? nullptr : vkBindings.data();
|
||||||
|
|
||||||
|
VkDescriptorSetLayout nativeLayout = VK_NULL_HANDLE;
|
||||||
|
if (vkCreateDescriptorSetLayout(m_device, &layoutInfo, nullptr, &nativeLayout) != VK_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_nativeSetLayouts.push_back(nativeLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanPipelineLayout::Shutdown() {
|
||||||
|
if (m_pipelineLayout != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
|
}
|
||||||
|
m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
for (VkDescriptorSetLayout nativeSetLayout : m_nativeSetLayouts) {
|
||||||
|
if (nativeSetLayout != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorSetLayout(m_device, nativeSetLayout, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_nativeSetLayouts.clear();
|
||||||
|
|
||||||
|
m_desc = {};
|
||||||
|
m_setLayouts.clear();
|
||||||
|
m_setLayoutBindings.clear();
|
||||||
|
m_device = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
#include "XCEngine/RHI/Vulkan/VulkanPipelineState.h"
|
||||||
|
|
||||||
#include "XCEngine/RHI/Vulkan/VulkanDevice.h"
|
#include "XCEngine/RHI/Vulkan/VulkanDevice.h"
|
||||||
|
#include "XCEngine/RHI/Vulkan/VulkanPipelineLayout.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -129,6 +130,11 @@ bool VulkanPipelineState::Initialize(VulkanDevice* device, const GraphicsPipelin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* externalPipelineLayout = static_cast<VulkanPipelineLayout*>(desc.pipelineLayout);
|
||||||
|
if (externalPipelineLayout != nullptr) {
|
||||||
|
m_pipelineLayout = externalPipelineLayout->GetPipelineLayout();
|
||||||
|
m_ownsPipelineLayout = false;
|
||||||
|
} else {
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
if (vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) {
|
if (vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) {
|
||||||
@@ -136,6 +142,8 @@ bool VulkanPipelineState::Initialize(VulkanDevice* device, const GraphicsPipelin
|
|||||||
vkDestroyShaderModule(m_device, vertexModule, nullptr);
|
vkDestroyShaderModule(m_device, vertexModule, nullptr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
m_ownsPipelineLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
VkAttachmentDescription colorAttachment = {};
|
VkAttachmentDescription colorAttachment = {};
|
||||||
colorAttachment.format = ToVulkanFormat(static_cast<Format>(m_renderTargetFormats[0]));
|
colorAttachment.format = ToVulkanFormat(static_cast<Format>(m_renderTargetFormats[0]));
|
||||||
@@ -164,8 +172,11 @@ bool VulkanPipelineState::Initialize(VulkanDevice* device, const GraphicsPipelin
|
|||||||
renderPassInfo.pSubpasses = &subpass;
|
renderPassInfo.pSubpasses = &subpass;
|
||||||
|
|
||||||
if (vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass) != VK_SUCCESS) {
|
if (vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass) != VK_SUCCESS) {
|
||||||
|
if (m_ownsPipelineLayout) {
|
||||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
|
}
|
||||||
m_pipelineLayout = VK_NULL_HANDLE;
|
m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
m_ownsPipelineLayout = false;
|
||||||
vkDestroyShaderModule(m_device, fragmentModule, nullptr);
|
vkDestroyShaderModule(m_device, fragmentModule, nullptr);
|
||||||
vkDestroyShaderModule(m_device, vertexModule, nullptr);
|
vkDestroyShaderModule(m_device, vertexModule, nullptr);
|
||||||
return false;
|
return false;
|
||||||
@@ -372,12 +383,15 @@ void VulkanPipelineState::Shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_pipelineLayout != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
if (m_pipelineLayout != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||||
|
if (m_ownsPipelineLayout) {
|
||||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
|
}
|
||||||
m_pipelineLayout = VK_NULL_HANDLE;
|
m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_deviceOwner = nullptr;
|
m_deviceOwner = nullptr;
|
||||||
m_device = VK_NULL_HANDLE;
|
m_device = VK_NULL_HANDLE;
|
||||||
|
m_ownsPipelineLayout = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace RHI
|
} // namespace RHI
|
||||||
|
|||||||
@@ -24,8 +24,33 @@ bool VulkanResourceView::InitializeAsRenderTarget(VkDevice device, VulkanTexture
|
|||||||
VkImageViewCreateInfo viewInfo = {};
|
VkImageViewCreateInfo viewInfo = {};
|
||||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
viewInfo.image = texture->GetImage();
|
viewInfo.image = texture->GetImage();
|
||||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
viewInfo.viewType = ToVulkanImageViewType(m_dimension, texture->GetTextureType());
|
||||||
viewInfo.format = texture->GetVkFormat();
|
viewInfo.format = m_format != Format::Unknown ? ToVulkanFormat(m_format) : texture->GetVkFormat();
|
||||||
|
viewInfo.subresourceRange.aspectMask = GetImageAspectMask(texture->GetFormat());
|
||||||
|
viewInfo.subresourceRange.baseMipLevel = desc.mipLevel;
|
||||||
|
viewInfo.subresourceRange.levelCount = 1;
|
||||||
|
viewInfo.subresourceRange.baseArrayLayer = desc.firstArraySlice;
|
||||||
|
viewInfo.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
return vkCreateImageView(device, &viewInfo, nullptr, &m_imageView) == VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanResourceView::InitializeAsShaderResource(VkDevice device, VulkanTexture* texture, const ResourceViewDesc& desc) {
|
||||||
|
if (device == VK_NULL_HANDLE || texture == nullptr || texture->GetImage() == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
|
m_texture = texture;
|
||||||
|
m_viewType = ResourceViewType::ShaderResource;
|
||||||
|
m_dimension = desc.dimension != ResourceViewDimension::Unknown ? desc.dimension : ResourceViewDimension::Texture2D;
|
||||||
|
m_format = desc.format != 0 ? static_cast<Format>(desc.format) : texture->GetFormat();
|
||||||
|
|
||||||
|
VkImageViewCreateInfo viewInfo = {};
|
||||||
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
viewInfo.image = texture->GetImage();
|
||||||
|
viewInfo.viewType = ToVulkanImageViewType(m_dimension, texture->GetTextureType());
|
||||||
|
viewInfo.format = m_format != Format::Unknown ? ToVulkanFormat(m_format) : texture->GetVkFormat();
|
||||||
viewInfo.subresourceRange.aspectMask = GetImageAspectMask(texture->GetFormat());
|
viewInfo.subresourceRange.aspectMask = GetImageAspectMask(texture->GetFormat());
|
||||||
viewInfo.subresourceRange.baseMipLevel = desc.mipLevel;
|
viewInfo.subresourceRange.baseMipLevel = desc.mipLevel;
|
||||||
viewInfo.subresourceRange.levelCount = 1;
|
viewInfo.subresourceRange.levelCount = 1;
|
||||||
@@ -80,6 +105,7 @@ bool VulkanResourceView::IsValid() const {
|
|||||||
return m_buffer != nullptr && m_buffer->GetBuffer() != VK_NULL_HANDLE;
|
return m_buffer != nullptr && m_buffer->GetBuffer() != VK_NULL_HANDLE;
|
||||||
case ResourceViewType::RenderTarget:
|
case ResourceViewType::RenderTarget:
|
||||||
case ResourceViewType::DepthStencil:
|
case ResourceViewType::DepthStencil:
|
||||||
|
case ResourceViewType::ShaderResource:
|
||||||
return m_imageView != VK_NULL_HANDLE;
|
return m_imageView != VK_NULL_HANDLE;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
56
engine/src/RHI/Vulkan/VulkanSampler.cpp
Normal file
56
engine/src/RHI/Vulkan/VulkanSampler.cpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include "XCEngine/RHI/Vulkan/VulkanSampler.h"
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
|
||||||
|
VulkanSampler::~VulkanSampler() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanSampler::Initialize(VkDevice device, const SamplerDesc& desc) {
|
||||||
|
if (device == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
|
|
||||||
|
VkSamplerCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
createInfo.magFilter = ToVulkanMagFilter(static_cast<FilterMode>(desc.filter));
|
||||||
|
createInfo.minFilter = ToVulkanMinFilter(static_cast<FilterMode>(desc.filter));
|
||||||
|
createInfo.mipmapMode = ToVulkanSamplerMipmapMode(static_cast<FilterMode>(desc.filter));
|
||||||
|
createInfo.addressModeU = ToVulkanSamplerAddressMode(static_cast<TextureAddressMode>(desc.addressU));
|
||||||
|
createInfo.addressModeV = ToVulkanSamplerAddressMode(static_cast<TextureAddressMode>(desc.addressV));
|
||||||
|
createInfo.addressModeW = ToVulkanSamplerAddressMode(static_cast<TextureAddressMode>(desc.addressW));
|
||||||
|
createInfo.mipLodBias = desc.mipLodBias;
|
||||||
|
createInfo.anisotropyEnable = UsesVulkanSamplerAnisotropy(static_cast<FilterMode>(desc.filter)) ? VK_TRUE : VK_FALSE;
|
||||||
|
createInfo.maxAnisotropy = desc.maxAnisotropy > 0 ? static_cast<float>(desc.maxAnisotropy) : 1.0f;
|
||||||
|
createInfo.compareEnable = UsesVulkanComparisonSampling(static_cast<FilterMode>(desc.filter)) ? VK_TRUE : VK_FALSE;
|
||||||
|
createInfo.compareOp = ToVulkanCompareOp(static_cast<ComparisonFunc>(desc.comparisonFunc));
|
||||||
|
createInfo.minLod = desc.minLod;
|
||||||
|
createInfo.maxLod = desc.maxLod;
|
||||||
|
createInfo.borderColor = ToVulkanBorderColor(desc.borderColorR, desc.borderColorG, desc.borderColorB, desc.borderColorA);
|
||||||
|
createInfo.unnormalizedCoordinates = VK_FALSE;
|
||||||
|
|
||||||
|
return vkCreateSampler(device, &createInfo, nullptr, &m_sampler) == VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanSampler::Shutdown() {
|
||||||
|
if (m_sampler != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||||
|
vkDestroySampler(m_device, m_sampler, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sampler = VK_NULL_HANDLE;
|
||||||
|
m_device = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanSampler::Bind(unsigned int unit) {
|
||||||
|
(void)unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanSampler::Unbind(unsigned int unit) {
|
||||||
|
(void)unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RHI
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -61,12 +61,20 @@ bool VulkanSwapChain::CreateSwapChainResources() {
|
|||||||
vkGetPhysicalDeviceSurfaceFormatsKHR(m_device->GetPhysicalDevice(), m_surface, &formatCount, formats.data());
|
vkGetPhysicalDeviceSurfaceFormatsKHR(m_device->GetPhysicalDevice(), m_surface, &formatCount, formats.data());
|
||||||
|
|
||||||
VkSurfaceFormatKHR selectedFormat = formats[0];
|
VkSurfaceFormatKHR selectedFormat = formats[0];
|
||||||
|
for (const VkSurfaceFormatKHR& candidate : formats) {
|
||||||
|
if (candidate.format == VK_FORMAT_R8G8B8A8_UNORM) {
|
||||||
|
selectedFormat = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedFormat.format != VK_FORMAT_R8G8B8A8_UNORM) {
|
||||||
for (const VkSurfaceFormatKHR& candidate : formats) {
|
for (const VkSurfaceFormatKHR& candidate : formats) {
|
||||||
if (candidate.format == VK_FORMAT_B8G8R8A8_UNORM) {
|
if (candidate.format == VK_FORMAT_B8G8R8A8_UNORM) {
|
||||||
selectedFormat = candidate;
|
selectedFormat = candidate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
m_surfaceFormat = selectedFormat.format;
|
m_surfaceFormat = selectedFormat.format;
|
||||||
|
|
||||||
if ((capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0 ||
|
if ((capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0 ||
|
||||||
|
|||||||
@@ -18,21 +18,62 @@ bool VulkanTexture::InitializeSwapChainImage(
|
|||||||
m_image = image;
|
m_image = image;
|
||||||
m_width = width;
|
m_width = width;
|
||||||
m_height = height;
|
m_height = height;
|
||||||
|
m_mipLevels = 1;
|
||||||
m_format = format;
|
m_format = format;
|
||||||
m_vkFormat = vkFormat;
|
m_vkFormat = vkFormat;
|
||||||
m_textureType = TextureType::Texture2D;
|
m_textureType = TextureType::Texture2D;
|
||||||
m_state = ResourceStates::Common;
|
m_state = ResourceStates::Common;
|
||||||
|
m_ownsImage = false;
|
||||||
return m_image != VK_NULL_HANDLE;
|
return m_image != VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VulkanTexture::InitializeOwnedImage(
|
||||||
|
VkDevice device,
|
||||||
|
VkImage image,
|
||||||
|
VkDeviceMemory memory,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
uint32_t mipLevels,
|
||||||
|
Format format,
|
||||||
|
TextureType textureType,
|
||||||
|
VkFormat vkFormat) {
|
||||||
|
if (device == VK_NULL_HANDLE || image == VK_NULL_HANDLE || memory == VK_NULL_HANDLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
|
m_image = image;
|
||||||
|
m_memory = memory;
|
||||||
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
m_mipLevels = mipLevels;
|
||||||
|
m_format = format;
|
||||||
|
m_vkFormat = vkFormat;
|
||||||
|
m_textureType = textureType;
|
||||||
|
m_state = ResourceStates::Common;
|
||||||
|
m_ownsImage = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanTexture::Shutdown() {
|
void VulkanTexture::Shutdown() {
|
||||||
|
if (m_ownsImage && m_image != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImage(m_device, m_image, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_memory != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||||
|
vkFreeMemory(m_device, m_memory, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
m_image = VK_NULL_HANDLE;
|
m_image = VK_NULL_HANDLE;
|
||||||
|
m_memory = VK_NULL_HANDLE;
|
||||||
m_device = VK_NULL_HANDLE;
|
m_device = VK_NULL_HANDLE;
|
||||||
m_width = 0;
|
m_width = 0;
|
||||||
m_height = 0;
|
m_height = 0;
|
||||||
|
m_mipLevels = 1;
|
||||||
m_format = Format::Unknown;
|
m_format = Format::Unknown;
|
||||||
m_vkFormat = VK_FORMAT_UNDEFINED;
|
m_vkFormat = VK_FORMAT_UNDEFINED;
|
||||||
m_state = ResourceStates::Common;
|
m_state = ResourceStates::Common;
|
||||||
|
m_ownsImage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace RHI
|
} // namespace RHI
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ set(PACKAGE_DIR ${CMAKE_SOURCE_DIR}/tests/opengl/package)
|
|||||||
|
|
||||||
get_filename_component(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. ABSOLUTE)
|
get_filename_component(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. ABSOLUTE)
|
||||||
|
|
||||||
|
find_package(Vulkan QUIET)
|
||||||
|
|
||||||
add_executable(rhi_integration_quad
|
add_executable(rhi_integration_quad
|
||||||
main.cpp
|
main.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../fixtures/RHIIntegrationFixture.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/../fixtures/RHIIntegrationFixture.cpp
|
||||||
@@ -33,6 +35,60 @@ target_link_libraries(rhi_integration_quad PRIVATE
|
|||||||
GTest::gtest
|
GTest::gtest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(Vulkan_FOUND)
|
||||||
|
set(XCENGINE_GLSLANG_VALIDATOR_HINT "$ENV{VULKAN_SDK}")
|
||||||
|
find_program(
|
||||||
|
XCENGINE_GLSLANG_VALIDATOR
|
||||||
|
NAMES glslangValidator glslangValidator.exe
|
||||||
|
HINTS
|
||||||
|
"${XCENGINE_GLSLANG_VALIDATOR_HINT}/Bin"
|
||||||
|
"${Vulkan_ROOT}/Bin")
|
||||||
|
|
||||||
|
if(NOT XCENGINE_GLSLANG_VALIDATOR)
|
||||||
|
file(GLOB XCENGINE_VULKAN_BIN_DIRS "D:/VulkanSDK/*/Bin")
|
||||||
|
if(XCENGINE_VULKAN_BIN_DIRS)
|
||||||
|
list(SORT XCENGINE_VULKAN_BIN_DIRS COMPARE NATURAL ORDER DESCENDING)
|
||||||
|
foreach(XCENGINE_VULKAN_BIN_DIR IN LISTS XCENGINE_VULKAN_BIN_DIRS)
|
||||||
|
find_program(
|
||||||
|
XCENGINE_GLSLANG_VALIDATOR
|
||||||
|
NAMES glslangValidator glslangValidator.exe
|
||||||
|
PATHS "${XCENGINE_VULKAN_BIN_DIR}"
|
||||||
|
NO_DEFAULT_PATH)
|
||||||
|
if(XCENGINE_GLSLANG_VALIDATOR)
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT XCENGINE_GLSLANG_VALIDATOR)
|
||||||
|
message(FATAL_ERROR "glslangValidator not found for Vulkan quad shaders")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(QUAD_VULKAN_VERTEX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Res/Shader/quad_vulkan.vert)
|
||||||
|
set(QUAD_VULKAN_FRAGMENT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/Res/Shader/quad_vulkan.frag)
|
||||||
|
|
||||||
|
add_custom_command(TARGET rhi_integration_quad PRE_BUILD
|
||||||
|
COMMAND ${XCENGINE_GLSLANG_VALIDATOR}
|
||||||
|
-V
|
||||||
|
-S
|
||||||
|
vert
|
||||||
|
-o
|
||||||
|
$<TARGET_FILE_DIR:rhi_integration_quad>/quad_vulkan.vert.spv
|
||||||
|
${QUAD_VULKAN_VERTEX_SOURCE}
|
||||||
|
COMMAND ${XCENGINE_GLSLANG_VALIDATOR}
|
||||||
|
-V
|
||||||
|
-S
|
||||||
|
frag
|
||||||
|
-o
|
||||||
|
$<TARGET_FILE_DIR:rhi_integration_quad>/quad_vulkan.frag.spv
|
||||||
|
${QUAD_VULKAN_FRAGMENT_SOURCE}
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
target_link_libraries(rhi_integration_quad PRIVATE Vulkan::Vulkan)
|
||||||
|
target_compile_definitions(rhi_integration_quad PRIVATE XCENGINE_SUPPORT_VULKAN)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(rhi_integration_quad PRIVATE
|
target_compile_definitions(rhi_integration_quad PRIVATE
|
||||||
UNICODE
|
UNICODE
|
||||||
_UNICODE
|
_UNICODE
|
||||||
|
|||||||
11
tests/RHI/integration/quad/Res/Shader/quad_vulkan.frag
Normal file
11
tests/RHI/integration/quad/Res/Shader/quad_vulkan.frag
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) uniform texture2D uTexture;
|
||||||
|
layout(set = 1, binding = 0) uniform sampler uSampler;
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
fragColor = texture(sampler2D(uTexture, uSampler), vTexCoord);
|
||||||
|
}
|
||||||
11
tests/RHI/integration/quad/Res/Shader/quad_vulkan.vert
Normal file
11
tests/RHI/integration/quad/Res/Shader/quad_vulkan.vert
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 aPosition;
|
||||||
|
layout(location = 1) in vec2 aTexCoord;
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = aPosition;
|
||||||
|
vTexCoord = aTexCoord;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -53,6 +54,27 @@ std::filesystem::path ResolveRuntimePath(const char* relativePath) {
|
|||||||
return GetExecutableDirectory() / relativePath;
|
return GetExecutableDirectory() / relativePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> LoadBinaryFileRelative(const char* filename) {
|
||||||
|
const std::filesystem::path path = ResolveRuntimePath(filename);
|
||||||
|
std::ifstream file(path, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::streamsize size = file.tellg();
|
||||||
|
if (size <= 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> bytes(static_cast<size_t>(size));
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
if (!file.read(reinterpret_cast<char*>(bytes.data()), size)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
const char kQuadHlsl[] = R"(
|
const char kQuadHlsl[] = R"(
|
||||||
Texture2D gTexture : register(t0);
|
Texture2D gTexture : register(t0);
|
||||||
SamplerState gSampler : register(s0);
|
SamplerState gSampler : register(s0);
|
||||||
@@ -104,7 +126,16 @@ void main() {
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
const char* GetScreenshotFilename(RHIType type) {
|
const char* GetScreenshotFilename(RHIType type) {
|
||||||
return type == RHIType::D3D12 ? "quad_d3d12.ppm" : "quad_opengl.ppm";
|
switch (type) {
|
||||||
|
case RHIType::D3D12:
|
||||||
|
return "quad_d3d12.ppm";
|
||||||
|
case RHIType::OpenGL:
|
||||||
|
return "quad_opengl.ppm";
|
||||||
|
case RHIType::Vulkan:
|
||||||
|
return "quad_vulkan.ppm";
|
||||||
|
default:
|
||||||
|
return "quad_unknown.ppm";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RHITexture* LoadQuadTexture(RHIDevice* device) {
|
RHITexture* LoadQuadTexture(RHIDevice* device) {
|
||||||
@@ -190,7 +221,7 @@ GraphicsPipelineDesc CreateQuadPipelineDesc(RHIType type, RHIPipelineLayout* pip
|
|||||||
desc.fragmentShader.sourceLanguage = ShaderLanguage::HLSL;
|
desc.fragmentShader.sourceLanguage = ShaderLanguage::HLSL;
|
||||||
desc.fragmentShader.entryPoint = L"MainPS";
|
desc.fragmentShader.entryPoint = L"MainPS";
|
||||||
desc.fragmentShader.profile = L"ps_5_0";
|
desc.fragmentShader.profile = L"ps_5_0";
|
||||||
} else {
|
} else if (type == RHIType::OpenGL) {
|
||||||
desc.vertexShader.source.assign(kQuadVertexShader, kQuadVertexShader + strlen(kQuadVertexShader));
|
desc.vertexShader.source.assign(kQuadVertexShader, kQuadVertexShader + strlen(kQuadVertexShader));
|
||||||
desc.vertexShader.sourceLanguage = ShaderLanguage::GLSL;
|
desc.vertexShader.sourceLanguage = ShaderLanguage::GLSL;
|
||||||
desc.vertexShader.profile = L"vs_4_30";
|
desc.vertexShader.profile = L"vs_4_30";
|
||||||
@@ -198,6 +229,14 @@ GraphicsPipelineDesc CreateQuadPipelineDesc(RHIType type, RHIPipelineLayout* pip
|
|||||||
desc.fragmentShader.source.assign(kQuadFragmentShader, kQuadFragmentShader + strlen(kQuadFragmentShader));
|
desc.fragmentShader.source.assign(kQuadFragmentShader, kQuadFragmentShader + strlen(kQuadFragmentShader));
|
||||||
desc.fragmentShader.sourceLanguage = ShaderLanguage::GLSL;
|
desc.fragmentShader.sourceLanguage = ShaderLanguage::GLSL;
|
||||||
desc.fragmentShader.profile = L"fs_4_30";
|
desc.fragmentShader.profile = L"fs_4_30";
|
||||||
|
} else if (type == RHIType::Vulkan) {
|
||||||
|
desc.vertexShader.source = LoadBinaryFileRelative("quad_vulkan.vert.spv");
|
||||||
|
desc.vertexShader.sourceLanguage = ShaderLanguage::SPIRV;
|
||||||
|
desc.vertexShader.entryPoint = L"main";
|
||||||
|
|
||||||
|
desc.fragmentShader.source = LoadBinaryFileRelative("quad_vulkan.frag.spv");
|
||||||
|
desc.fragmentShader.sourceLanguage = ShaderLanguage::SPIRV;
|
||||||
|
desc.fragmentShader.entryPoint = L"main";
|
||||||
}
|
}
|
||||||
|
|
||||||
return desc;
|
return desc;
|
||||||
@@ -342,9 +381,34 @@ void QuadTest::InitializeQuadResources() {
|
|||||||
ASSERT_NE(mSamplerSet, nullptr);
|
ASSERT_NE(mSamplerSet, nullptr);
|
||||||
mSamplerSet->UpdateSampler(0, mSampler);
|
mSamplerSet->UpdateSampler(0, mSampler);
|
||||||
|
|
||||||
|
DescriptorSetLayoutBinding pipelineTextureBinding = {};
|
||||||
|
pipelineTextureBinding.binding = 0;
|
||||||
|
pipelineTextureBinding.type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||||
|
pipelineTextureBinding.count = 1;
|
||||||
|
pipelineTextureBinding.visibility = static_cast<uint32_t>(ShaderVisibility::Pixel);
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc textureSetLayout = {};
|
||||||
|
textureSetLayout.bindings = &pipelineTextureBinding;
|
||||||
|
textureSetLayout.bindingCount = 1;
|
||||||
|
|
||||||
|
DescriptorSetLayoutBinding pipelineSamplerBinding = {};
|
||||||
|
pipelineSamplerBinding.binding = 0;
|
||||||
|
pipelineSamplerBinding.type = static_cast<uint32_t>(DescriptorType::Sampler);
|
||||||
|
pipelineSamplerBinding.count = 1;
|
||||||
|
pipelineSamplerBinding.visibility = static_cast<uint32_t>(ShaderVisibility::Pixel);
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc samplerSetLayout = {};
|
||||||
|
samplerSetLayout.bindings = &pipelineSamplerBinding;
|
||||||
|
samplerSetLayout.bindingCount = 1;
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc setLayouts[] = {
|
||||||
|
textureSetLayout,
|
||||||
|
samplerSetLayout,
|
||||||
|
};
|
||||||
|
|
||||||
RHIPipelineLayoutDesc pipelineLayoutDesc = {};
|
RHIPipelineLayoutDesc pipelineLayoutDesc = {};
|
||||||
pipelineLayoutDesc.textureCount = 1;
|
pipelineLayoutDesc.setLayouts = setLayouts;
|
||||||
pipelineLayoutDesc.samplerCount = 1;
|
pipelineLayoutDesc.setLayoutCount = 2;
|
||||||
mPipelineLayout = GetDevice()->CreatePipelineLayout(pipelineLayoutDesc);
|
mPipelineLayout = GetDevice()->CreatePipelineLayout(pipelineLayoutDesc);
|
||||||
ASSERT_NE(mPipelineLayout, nullptr);
|
ASSERT_NE(mPipelineLayout, nullptr);
|
||||||
|
|
||||||
@@ -510,6 +574,9 @@ TEST_P(QuadTest, RenderQuad) {
|
|||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(D3D12, QuadTest, ::testing::Values(RHIType::D3D12));
|
INSTANTIATE_TEST_SUITE_P(D3D12, QuadTest, ::testing::Values(RHIType::D3D12));
|
||||||
INSTANTIATE_TEST_SUITE_P(OpenGL, QuadTest, ::testing::Values(RHIType::OpenGL));
|
INSTANTIATE_TEST_SUITE_P(OpenGL, QuadTest, ::testing::Values(RHIType::OpenGL));
|
||||||
|
#if defined(XCENGINE_SUPPORT_VULKAN)
|
||||||
|
INSTANTIATE_TEST_SUITE_P(Vulkan, QuadTest, ::testing::Values(RHIType::Vulkan));
|
||||||
|
#endif
|
||||||
|
|
||||||
GTEST_API_ int main(int argc, char** argv) {
|
GTEST_API_ int main(int argc, char** argv) {
|
||||||
Logger::Get().Initialize();
|
Logger::Get().Initialize();
|
||||||
|
|||||||
Reference in New Issue
Block a user