Add formal compute pipeline creation API
This commit is contained in:
@@ -72,6 +72,7 @@ public:
|
||||
RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override;
|
||||
RHIShader* CreateShader(const ShaderCompileDesc& desc) override;
|
||||
RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) override;
|
||||
RHIPipelineState* CreateComputePipelineState(const ComputePipelineDesc& desc) override;
|
||||
RHIPipelineLayout* CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) override;
|
||||
RHIFence* CreateFence(const FenceDesc& desc) override;
|
||||
RHISampler* CreateSampler(const SamplerDesc& desc) override;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_4.h>
|
||||
#include <wrl/client.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "../RHIPipelineState.h"
|
||||
@@ -31,7 +32,9 @@ public:
|
||||
void SetTopology(uint32_t topologyType) override;
|
||||
void SetRenderTargetFormats(uint32_t count, const uint32_t* formats, uint32_t depthFormat) override;
|
||||
void SetSampleCount(uint32_t count) override;
|
||||
void SetSampleQuality(uint32_t quality) override;
|
||||
void SetComputeShader(RHIShader* shader) override;
|
||||
void SetOwnedComputeShader(std::unique_ptr<class D3D12Shader> shader);
|
||||
void SetRootSignature(ID3D12RootSignature* rootSignature);
|
||||
|
||||
// State query
|
||||
@@ -95,6 +98,7 @@ private:
|
||||
uint32_t m_renderTargetFormats[8] = { 0 };
|
||||
uint32_t m_depthStencilFormat = 0;
|
||||
uint32_t m_sampleCount = 1;
|
||||
uint32_t m_sampleQuality = 0;
|
||||
|
||||
// Shader bytecodes (set externally)
|
||||
D3D12_SHADER_BYTECODE m_vsBytecode = {};
|
||||
@@ -102,6 +106,7 @@ private:
|
||||
D3D12_SHADER_BYTECODE m_gsBytecode = {};
|
||||
D3D12_SHADER_BYTECODE m_csBytecode = {};
|
||||
class RHIShader* m_computeShader = nullptr;
|
||||
std::unique_ptr<class D3D12Shader> m_ownedComputeShader;
|
||||
ComPtr<ID3D12RootSignature> m_rootSignature;
|
||||
|
||||
// D3D12 resources
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override;
|
||||
RHIShader* CreateShader(const ShaderCompileDesc& desc) override;
|
||||
RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) override;
|
||||
RHIPipelineState* CreateComputePipelineState(const ComputePipelineDesc& desc) override;
|
||||
RHIPipelineLayout* CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) override;
|
||||
RHIFence* CreateFence(const FenceDesc& desc) override;
|
||||
RHISampler* CreateSampler(const SamplerDesc& desc) override;
|
||||
|
||||
@@ -84,7 +84,9 @@ public:
|
||||
void SetTopology(uint32_t topologyType) override;
|
||||
void SetRenderTargetFormats(uint32_t count, const uint32_t* formats, uint32_t depthFormat) override;
|
||||
void SetSampleCount(uint32_t count) override;
|
||||
void SetSampleQuality(uint32_t quality) override;
|
||||
void SetComputeShader(RHIShader* shader) override;
|
||||
void SetOwnedComputeShader(std::unique_ptr<class OpenGLShader> shader);
|
||||
|
||||
// State query
|
||||
const RasterizerDesc& GetRasterizerState() const override { return m_rasterizerDesc; }
|
||||
@@ -142,6 +144,7 @@ private:
|
||||
unsigned int m_computeProgram = 0;
|
||||
class RHIShader* m_computeShader = nullptr;
|
||||
std::unique_ptr<class OpenGLShader> m_graphicsShader;
|
||||
std::unique_ptr<class OpenGLShader> m_ownedComputeShader;
|
||||
bool m_programAttached = false;
|
||||
|
||||
// OpenGL specific state
|
||||
|
||||
@@ -77,6 +77,10 @@ public:
|
||||
virtual RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) = 0;
|
||||
virtual RHIShader* CreateShader(const ShaderCompileDesc& desc) = 0;
|
||||
virtual RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) = 0;
|
||||
virtual RHIPipelineState* CreateComputePipelineState(const ComputePipelineDesc& desc) {
|
||||
(void)desc;
|
||||
return nullptr;
|
||||
}
|
||||
virtual RHIPipelineLayout* CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) = 0;
|
||||
virtual RHIFence* CreateFence(const FenceDesc& desc) = 0;
|
||||
virtual RHISampler* CreateSampler(const SamplerDesc& desc) = 0;
|
||||
|
||||
@@ -46,6 +46,12 @@ struct ShaderCompileMacro {
|
||||
};
|
||||
|
||||
enum class ShaderLanguage : uint8_t;
|
||||
enum class ShaderBinaryBackend : uint8_t {
|
||||
Unknown = 0,
|
||||
D3D12,
|
||||
OpenGL,
|
||||
Vulkan
|
||||
};
|
||||
|
||||
struct ShaderCompileDesc {
|
||||
std::wstring fileName;
|
||||
@@ -55,6 +61,8 @@ struct ShaderCompileDesc {
|
||||
std::wstring entryPoint;
|
||||
std::wstring profile;
|
||||
std::vector<ShaderCompileMacro> macros;
|
||||
ShaderBinaryBackend compiledBinaryBackend = ShaderBinaryBackend::Unknown;
|
||||
std::vector<uint8_t> compiledBinary;
|
||||
};
|
||||
|
||||
struct InputElementDesc {
|
||||
@@ -327,6 +335,11 @@ struct GraphicsPipelineDesc {
|
||||
uint32_t sampleQuality = 0;
|
||||
};
|
||||
|
||||
struct ComputePipelineDesc {
|
||||
ShaderCompileDesc computeShader;
|
||||
RHIPipelineLayout* pipelineLayout = nullptr;
|
||||
};
|
||||
|
||||
struct RHIDeviceDesc {
|
||||
bool enableDebugLayer = false;
|
||||
bool enableGPUValidation = false;
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) override;
|
||||
RHIShader* CreateShader(const ShaderCompileDesc& desc) override;
|
||||
RHIPipelineState* CreatePipelineState(const GraphicsPipelineDesc& desc) override;
|
||||
RHIPipelineState* CreateComputePipelineState(const ComputePipelineDesc& desc) override;
|
||||
RHIPipelineLayout* CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) override;
|
||||
RHIFence* CreateFence(const FenceDesc& desc) override;
|
||||
RHISampler* CreateSampler(const SamplerDesc& desc) override;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "XCEngine/RHI/RHIPipelineState.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanCommon.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
@@ -15,6 +17,10 @@ public:
|
||||
~VulkanPipelineState() override;
|
||||
|
||||
bool Initialize(VulkanDevice* device, const GraphicsPipelineDesc& desc);
|
||||
bool InitializeCompute(
|
||||
VulkanDevice* device,
|
||||
RHIPipelineLayout* pipelineLayout,
|
||||
std::unique_ptr<VulkanShader> shader);
|
||||
|
||||
void SetInputLayout(const InputLayoutDesc& layout) override;
|
||||
void SetRasterizerState(const RasterizerDesc& state) override;
|
||||
@@ -23,7 +29,9 @@ public:
|
||||
void SetTopology(uint32_t topologyType) override;
|
||||
void SetRenderTargetFormats(uint32_t count, const uint32_t* formats, uint32_t depthFormat) override;
|
||||
void SetSampleCount(uint32_t count) override;
|
||||
void SetSampleQuality(uint32_t quality) override;
|
||||
void SetComputeShader(RHIShader* shader) override;
|
||||
void SetOwnedComputeShader(std::unique_ptr<VulkanShader> shader);
|
||||
|
||||
const RasterizerDesc& GetRasterizerState() const override { return m_rasterizerDesc; }
|
||||
const BlendDesc& GetBlendState() const override { return m_blendDesc; }
|
||||
@@ -31,7 +39,7 @@ public:
|
||||
const InputLayoutDesc& GetInputLayout() const override { return m_inputLayoutDesc; }
|
||||
PipelineStateHash GetHash() const override;
|
||||
RHIShader* GetComputeShader() const override { return m_computeShader; }
|
||||
bool HasComputeShader() const override { return m_computeShader != nullptr; }
|
||||
bool HasComputeShader() const override { return m_hasComputeShader; }
|
||||
|
||||
bool IsValid() const override { return m_isConfigured; }
|
||||
void EnsureValid() override;
|
||||
@@ -52,6 +60,7 @@ public:
|
||||
|
||||
private:
|
||||
bool EnsurePipelineLayout(const GraphicsPipelineDesc& desc);
|
||||
bool EnsurePipelineLayout(RHIPipelineLayout* pipelineLayout);
|
||||
bool CreateGraphicsPipeline(const GraphicsPipelineDesc& desc);
|
||||
bool CreateComputePipeline();
|
||||
|
||||
@@ -71,6 +80,8 @@ private:
|
||||
uint32_t m_depthStencilFormat = 0;
|
||||
uint32_t m_sampleCount = 1;
|
||||
RHIShader* m_computeShader = nullptr;
|
||||
std::unique_ptr<VulkanShader> m_ownedComputeShader;
|
||||
bool m_hasComputeShader = false;
|
||||
bool m_isConfigured = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ uint64_t GetVolumeTraceSteadyMs();
|
||||
void LogVolumeTraceRendering(const std::string& message);
|
||||
|
||||
bool HasShaderPayload(const ShaderCompileDesc& desc) {
|
||||
return !desc.source.empty() || !desc.fileName.empty();
|
||||
return !desc.source.empty() || !desc.fileName.empty() || !desc.compiledBinary.empty();
|
||||
}
|
||||
|
||||
bool ShouldTraceVolumetricShaderCompile(const ShaderCompileDesc& desc) {
|
||||
@@ -94,6 +94,23 @@ bool CompileD3D12Shader(const ShaderCompileDesc& desc, D3D12Shader& shader) {
|
||||
const char* entryPointPtr = entryPoint.empty() ? nullptr : entryPoint.c_str();
|
||||
const char* profilePtr = profile.empty() ? nullptr : profile.c_str();
|
||||
|
||||
if (desc.compiledBinaryBackend == ShaderBinaryBackend::D3D12 &&
|
||||
!desc.compiledBinary.empty()) {
|
||||
const bool compiled = shader.InitializeFromBytecode(
|
||||
desc.compiledBinary.data(),
|
||||
desc.compiledBinary.size(),
|
||||
profilePtr);
|
||||
if (traceShaderCompile) {
|
||||
const uint64_t compileEndMs = GetVolumeTraceSteadyMs();
|
||||
LogVolumeTraceRendering(
|
||||
std::string("D3D12 shader compile ") + (compiled ? "cache-hit" : "cache-hit-failed") +
|
||||
" steady_ms=" + std::to_string(compileEndMs) +
|
||||
" total_ms=" + std::to_string(compileEndMs - compileStartMs) + " " +
|
||||
DescribeShaderCompileDesc(desc));
|
||||
}
|
||||
return compiled;
|
||||
}
|
||||
|
||||
if (!desc.source.empty()) {
|
||||
std::vector<std::string> macroNames;
|
||||
std::vector<std::string> macroDefinitions;
|
||||
@@ -1228,25 +1245,7 @@ RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc, const void* init
|
||||
|
||||
RHIShader* D3D12Device::CreateShader(const ShaderCompileDesc& desc) {
|
||||
auto* shader = new D3D12Shader();
|
||||
const std::string entryPoint = NarrowAscii(desc.entryPoint);
|
||||
const std::string profile = NarrowAscii(desc.profile);
|
||||
const char* entryPointPtr = entryPoint.empty() ? nullptr : entryPoint.c_str();
|
||||
const char* profilePtr = profile.empty() ? nullptr : profile.c_str();
|
||||
|
||||
bool success = false;
|
||||
if (!desc.source.empty()) {
|
||||
success = shader->Compile(
|
||||
desc.source.data(),
|
||||
desc.source.size(),
|
||||
desc.fileName.empty() ? nullptr : desc.fileName.c_str(),
|
||||
nullptr,
|
||||
entryPointPtr,
|
||||
profilePtr);
|
||||
} else if (!desc.fileName.empty()) {
|
||||
success = shader->CompileFromFile(desc.fileName.c_str(), entryPointPtr, profilePtr);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
if (CompileD3D12Shader(desc, *shader)) {
|
||||
return shader;
|
||||
}
|
||||
delete shader;
|
||||
@@ -1524,6 +1523,33 @@ RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& d
|
||||
return pso;
|
||||
}
|
||||
|
||||
RHIPipelineState* D3D12Device::CreateComputePipelineState(const ComputePipelineDesc& desc) {
|
||||
if (!HasShaderPayload(desc.computeShader)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* pso = new D3D12PipelineState(m_device.Get());
|
||||
if (desc.pipelineLayout != nullptr) {
|
||||
auto* pipelineLayout = static_cast<D3D12PipelineLayout*>(desc.pipelineLayout);
|
||||
pso->SetRootSignature(pipelineLayout->GetRootSignature());
|
||||
}
|
||||
|
||||
D3D12Shader computeShader;
|
||||
if (!CompileD3D12Shader(desc.computeShader, computeShader)) {
|
||||
delete pso;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pso->SetComputeShaderBytecodes(computeShader.GetD3D12Bytecode());
|
||||
pso->EnsureValid();
|
||||
if (!pso->IsValid()) {
|
||||
delete pso;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pso;
|
||||
}
|
||||
|
||||
RHIPipelineLayout* D3D12Device::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) {
|
||||
auto* pipelineLayout = new D3D12PipelineLayout();
|
||||
if (!pipelineLayout->InitializeWithDevice(this, desc)) {
|
||||
|
||||
@@ -109,6 +109,7 @@ bool D3D12PipelineState::Initialize(ID3D12Device* device, const D3D12_GRAPHICS_P
|
||||
}
|
||||
m_depthStencilFormat = static_cast<uint32_t>(desc.DSVFormat);
|
||||
m_sampleCount = desc.SampleDesc.Count;
|
||||
m_sampleQuality = desc.SampleDesc.Quality;
|
||||
|
||||
// Set shader bytecodes
|
||||
m_vsBytecode = desc.VS;
|
||||
@@ -173,13 +174,21 @@ void D3D12PipelineState::SetSampleCount(uint32_t count) {
|
||||
m_sampleCount = count;
|
||||
}
|
||||
|
||||
void D3D12PipelineState::SetSampleQuality(uint32_t quality) {
|
||||
m_sampleQuality = quality;
|
||||
}
|
||||
|
||||
PipelineStateHash D3D12PipelineState::GetHash() const {
|
||||
PipelineStateHash hash = {};
|
||||
hash.blendStateHash = std::hash<uint64_t>{}(*reinterpret_cast<const uint64_t*>(&m_blendDesc));
|
||||
hash.depthStateHash = std::hash<uint64_t>{}(*reinterpret_cast<const uint64_t*>(&m_depthStencilDesc));
|
||||
hash.rasterizerStateHash = std::hash<uint64_t>{}(*reinterpret_cast<const uint64_t*>(&m_rasterizerDesc));
|
||||
hash.topologyHash = m_topologyType;
|
||||
hash.renderTargetHash = m_renderTargetCount | (m_depthStencilFormat << 8);
|
||||
hash.renderTargetHash =
|
||||
m_renderTargetCount |
|
||||
(static_cast<uint64_t>(m_depthStencilFormat) << 8) |
|
||||
(static_cast<uint64_t>(m_sampleCount) << 32) |
|
||||
(static_cast<uint64_t>(m_sampleQuality) << 48);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -190,6 +199,9 @@ void D3D12PipelineState::SetShaderBytecodes(const D3D12_SHADER_BYTECODE& vs, con
|
||||
}
|
||||
|
||||
void D3D12PipelineState::SetComputeShader(RHIShader* shader) {
|
||||
if (shader != m_ownedComputeShader.get()) {
|
||||
m_ownedComputeShader.reset();
|
||||
}
|
||||
m_computeShader = shader;
|
||||
m_csBytecode = {};
|
||||
m_computePipelineState.Reset();
|
||||
@@ -204,6 +216,11 @@ void D3D12PipelineState::SetComputeShader(RHIShader* shader) {
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12PipelineState::SetOwnedComputeShader(std::unique_ptr<D3D12Shader> shader) {
|
||||
m_ownedComputeShader = std::move(shader);
|
||||
SetComputeShader(m_ownedComputeShader.get());
|
||||
}
|
||||
|
||||
void D3D12PipelineState::SetRootSignature(ID3D12RootSignature* rootSignature) {
|
||||
m_rootSignature = rootSignature;
|
||||
}
|
||||
@@ -275,7 +292,7 @@ bool D3D12PipelineState::CreateD3D12PSO() {
|
||||
}
|
||||
desc.DSVFormat = ToD3D12(static_cast<Format>(m_depthStencilFormat));
|
||||
desc.SampleDesc.Count = m_sampleCount;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.SampleDesc.Quality = m_sampleQuality;
|
||||
desc.SampleMask = 0xffffffff;
|
||||
desc.PrimitiveTopologyType = static_cast<D3D12_PRIMITIVE_TOPOLOGY_TYPE>(m_topologyType);
|
||||
|
||||
@@ -349,6 +366,7 @@ void D3D12PipelineState::Shutdown() {
|
||||
m_pipelineState.Reset();
|
||||
m_computePipelineState.Reset();
|
||||
m_rootSignature.Reset();
|
||||
m_ownedComputeShader.reset();
|
||||
m_vsBytecode = {};
|
||||
m_psBytecode = {};
|
||||
m_gsBytecode = {};
|
||||
|
||||
@@ -136,7 +136,7 @@ uint64_t QuerySharedSystemMemoryBytes() {
|
||||
}
|
||||
|
||||
bool HasShaderPayload(const ShaderCompileDesc& desc) {
|
||||
return !desc.source.empty() || !desc.fileName.empty();
|
||||
return !desc.source.empty() || !desc.fileName.empty() || !desc.compiledBinary.empty();
|
||||
}
|
||||
|
||||
std::string SourceToString(const ShaderCompileDesc& desc) {
|
||||
@@ -594,8 +594,20 @@ bool CompileOpenGLShaderHandleFromSpirv(const ShaderCompileDesc& desc,
|
||||
GLuint& outShaderHandle,
|
||||
ShaderType& outShaderType,
|
||||
std::string* errorMessage) {
|
||||
ShaderCompileDesc spirvDesc = desc;
|
||||
SpirvTargetEnvironment targetEnvironment = SpirvTargetEnvironment::Vulkan;
|
||||
if (desc.compiledBinaryBackend == ShaderBinaryBackend::OpenGL &&
|
||||
!desc.compiledBinary.empty()) {
|
||||
spirvDesc.source = desc.compiledBinary;
|
||||
spirvDesc.sourceLanguage = ShaderLanguage::SPIRV;
|
||||
spirvDesc.fileName.clear();
|
||||
spirvDesc.compiledBinary.clear();
|
||||
spirvDesc.compiledBinaryBackend = ShaderBinaryBackend::Unknown;
|
||||
targetEnvironment = SpirvTargetEnvironment::OpenGL;
|
||||
}
|
||||
|
||||
CompiledSpirvShader compiledShader = {};
|
||||
if (!CompileSpirvShader(desc, SpirvTargetEnvironment::Vulkan, compiledShader, errorMessage)) {
|
||||
if (!CompileSpirvShader(spirvDesc, targetEnvironment, compiledShader, errorMessage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1326,7 +1338,7 @@ RHIShader* OpenGLDevice::CreateShader(const ShaderCompileDesc& desc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (desc.source.empty() && desc.fileName.empty()) {
|
||||
if (!HasShaderPayload(desc)) {
|
||||
delete shader;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1378,6 +1390,7 @@ RHIPipelineState* OpenGLDevice::CreatePipelineState(const GraphicsPipelineDesc&
|
||||
pso->SetTopology(desc.topologyType);
|
||||
pso->SetRenderTargetFormats(desc.renderTargetCount, desc.renderTargetFormats, desc.depthStencilFormat);
|
||||
pso->SetSampleCount(desc.sampleCount);
|
||||
pso->SetSampleQuality(desc.sampleQuality);
|
||||
|
||||
const bool hasVertexShader = HasShaderPayload(desc.vertexShader);
|
||||
const bool hasFragmentShader = HasShaderPayload(desc.fragmentShader);
|
||||
@@ -1422,6 +1435,21 @@ RHIPipelineState* OpenGLDevice::CreatePipelineState(const GraphicsPipelineDesc&
|
||||
return pso;
|
||||
}
|
||||
|
||||
RHIPipelineState* OpenGLDevice::CreateComputePipelineState(const ComputePipelineDesc& desc) {
|
||||
if (!HasShaderPayload(desc.computeShader) || !MakeContextCurrent()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto computeShader = std::unique_ptr<OpenGLShader>(static_cast<OpenGLShader*>(CreateShader(desc.computeShader)));
|
||||
if (computeShader == nullptr || computeShader->GetType() != ShaderType::Compute) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* pso = new OpenGLPipelineState();
|
||||
pso->SetOwnedComputeShader(std::move(computeShader));
|
||||
return pso;
|
||||
}
|
||||
|
||||
RHIPipelineLayout* OpenGLDevice::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) {
|
||||
auto* layout = new OpenGLPipelineLayout();
|
||||
if (!layout->Initialize(desc)) {
|
||||
|
||||
@@ -72,7 +72,13 @@ void OpenGLPipelineState::SetRenderTargetFormats(uint32_t count, const uint32_t*
|
||||
void OpenGLPipelineState::SetSampleCount(uint32_t count) {
|
||||
}
|
||||
|
||||
void OpenGLPipelineState::SetSampleQuality(uint32_t quality) {
|
||||
}
|
||||
|
||||
void OpenGLPipelineState::SetComputeShader(RHIShader* shader) {
|
||||
if (shader != m_ownedComputeShader.get()) {
|
||||
m_ownedComputeShader.reset();
|
||||
}
|
||||
m_computeShader = shader;
|
||||
if (shader) {
|
||||
OpenGLShader* glShader = static_cast<OpenGLShader*>(shader);
|
||||
@@ -82,6 +88,12 @@ void OpenGLPipelineState::SetComputeShader(RHIShader* shader) {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLPipelineState::SetOwnedComputeShader(std::unique_ptr<OpenGLShader> shader) {
|
||||
m_ownedComputeShader = std::move(shader);
|
||||
m_computeShader = m_ownedComputeShader.get();
|
||||
m_computeProgram = m_ownedComputeShader != nullptr ? m_ownedComputeShader->GetID() : 0;
|
||||
}
|
||||
|
||||
PipelineStateHash OpenGLPipelineState::GetHash() const {
|
||||
PipelineStateHash hash = {};
|
||||
return hash;
|
||||
@@ -89,6 +101,7 @@ PipelineStateHash OpenGLPipelineState::GetHash() const {
|
||||
|
||||
void OpenGLPipelineState::Shutdown() {
|
||||
m_graphicsShader.reset();
|
||||
m_ownedComputeShader.reset();
|
||||
m_program = 0;
|
||||
m_computeProgram = 0;
|
||||
m_computeShader = nullptr;
|
||||
|
||||
@@ -677,6 +677,21 @@ RHIPipelineState* VulkanDevice::CreatePipelineState(const GraphicsPipelineDesc&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RHIPipelineState* VulkanDevice::CreateComputePipelineState(const ComputePipelineDesc& desc) {
|
||||
auto computeShader = std::unique_ptr<VulkanShader>(static_cast<VulkanShader*>(CreateShader(desc.computeShader)));
|
||||
if (computeShader == nullptr || computeShader->GetType() != ShaderType::Compute) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* pipelineState = new VulkanPipelineState();
|
||||
if (pipelineState->InitializeCompute(this, desc.pipelineLayout, std::move(computeShader))) {
|
||||
return pipelineState;
|
||||
}
|
||||
|
||||
delete pipelineState;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RHIPipelineLayout* VulkanDevice::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) {
|
||||
auto* pipelineLayout = new VulkanPipelineLayout();
|
||||
if (pipelineLayout->Initialize(m_device, desc)) {
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace RHI {
|
||||
namespace {
|
||||
|
||||
bool HasShaderPayload(const ShaderCompileDesc& desc) {
|
||||
return !desc.source.empty() || !desc.fileName.empty();
|
||||
return !desc.source.empty() || !desc.fileName.empty() || !desc.compiledBinary.empty();
|
||||
}
|
||||
|
||||
VkShaderModule CreateShaderModule(VkDevice device, const std::vector<uint32_t>& words) {
|
||||
@@ -91,6 +91,9 @@ bool VulkanPipelineState::Initialize(VulkanDevice* device, const GraphicsPipelin
|
||||
m_renderTargetCount = desc.renderTargetCount;
|
||||
m_depthStencilFormat = desc.depthStencilFormat;
|
||||
m_sampleCount = desc.sampleCount > 0 ? desc.sampleCount : 1;
|
||||
m_computeShader = nullptr;
|
||||
m_ownedComputeShader.reset();
|
||||
m_hasComputeShader = false;
|
||||
for (uint32_t i = 0; i < 8; ++i) {
|
||||
m_renderTargetFormats[i] = desc.renderTargetFormats[i];
|
||||
}
|
||||
@@ -125,8 +128,41 @@ bool VulkanPipelineState::Initialize(VulkanDevice* device, const GraphicsPipelin
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanPipelineState::InitializeCompute(
|
||||
VulkanDevice* device,
|
||||
RHIPipelineLayout* pipelineLayout,
|
||||
std::unique_ptr<VulkanShader> shader) {
|
||||
if (device == nullptr ||
|
||||
device->GetDevice() == VK_NULL_HANDLE ||
|
||||
shader == nullptr ||
|
||||
!shader->IsValid() ||
|
||||
shader->GetType() != ShaderType::Compute) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Shutdown();
|
||||
|
||||
m_deviceOwner = device;
|
||||
m_device = device->GetDevice();
|
||||
m_ownedComputeShader = std::move(shader);
|
||||
m_computeShader = m_ownedComputeShader.get();
|
||||
m_hasComputeShader = m_computeShader != nullptr;
|
||||
|
||||
if (!EnsurePipelineLayout(pipelineLayout) || !CreateComputePipeline()) {
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_isConfigured = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanPipelineState::EnsurePipelineLayout(const GraphicsPipelineDesc& desc) {
|
||||
auto* externalPipelineLayout = static_cast<VulkanPipelineLayout*>(desc.pipelineLayout);
|
||||
return EnsurePipelineLayout(desc.pipelineLayout);
|
||||
}
|
||||
|
||||
bool VulkanPipelineState::EnsurePipelineLayout(RHIPipelineLayout* pipelineLayout) {
|
||||
auto* externalPipelineLayout = static_cast<VulkanPipelineLayout*>(pipelineLayout);
|
||||
if (externalPipelineLayout != nullptr) {
|
||||
m_pipelineLayout = externalPipelineLayout->GetPipelineLayout();
|
||||
m_ownsPipelineLayout = false;
|
||||
@@ -425,15 +461,33 @@ void VulkanPipelineState::SetSampleCount(uint32_t count) {
|
||||
m_sampleCount = count > 0 ? count : 1;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetSampleQuality(uint32_t quality) {
|
||||
(void)quality;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetComputeShader(RHIShader* shader) {
|
||||
if (m_pipeline != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||
vkDestroyPipeline(m_device, m_pipeline, nullptr);
|
||||
m_pipeline = VK_NULL_HANDLE;
|
||||
}
|
||||
m_computeShader = shader;
|
||||
if (m_computeShader != nullptr && m_pipelineLayout != VK_NULL_HANDLE) {
|
||||
m_isConfigured = true;
|
||||
if (shader != m_ownedComputeShader.get()) {
|
||||
m_ownedComputeShader.reset();
|
||||
}
|
||||
m_computeShader = shader;
|
||||
m_hasComputeShader = m_computeShader != nullptr;
|
||||
m_isConfigured = m_hasComputeShader && m_pipelineLayout != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void VulkanPipelineState::SetOwnedComputeShader(std::unique_ptr<VulkanShader> shader) {
|
||||
if (m_pipeline != VK_NULL_HANDLE && m_device != VK_NULL_HANDLE) {
|
||||
vkDestroyPipeline(m_device, m_pipeline, nullptr);
|
||||
m_pipeline = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
m_ownedComputeShader = std::move(shader);
|
||||
m_computeShader = m_ownedComputeShader.get();
|
||||
m_hasComputeShader = m_computeShader != nullptr;
|
||||
m_isConfigured = m_hasComputeShader && m_pipelineLayout != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
PipelineStateHash VulkanPipelineState::GetHash() const {
|
||||
@@ -499,7 +553,9 @@ void VulkanPipelineState::Shutdown() {
|
||||
m_deviceOwner = nullptr;
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_ownsPipelineLayout = false;
|
||||
m_ownedComputeShader.reset();
|
||||
m_computeShader = nullptr;
|
||||
m_hasComputeShader = false;
|
||||
m_isConfigured = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -756,10 +756,6 @@ TEST_F(OpenGLTestFixture, CommandList_SetComputeDescriptorSets_UsesSetAwareImage
|
||||
ASSERT_NE(descriptorSet, nullptr);
|
||||
descriptorSet->Update(0, uav);
|
||||
|
||||
GraphicsPipelineDesc pipelineDesc = {};
|
||||
RHIPipelineState* pipelineState = GetDevice()->CreatePipelineState(pipelineDesc);
|
||||
ASSERT_NE(pipelineState, nullptr);
|
||||
|
||||
ShaderCompileDesc shaderDesc = {};
|
||||
shaderDesc.sourceLanguage = ShaderLanguage::GLSL;
|
||||
static const char* computeSource = R"(
|
||||
@@ -772,9 +768,11 @@ TEST_F(OpenGLTestFixture, CommandList_SetComputeDescriptorSets_UsesSetAwareImage
|
||||
)";
|
||||
shaderDesc.source.assign(computeSource, computeSource + std::strlen(computeSource));
|
||||
shaderDesc.profile = L"cs_4_30";
|
||||
RHIShader* computeShader = GetDevice()->CreateShader(shaderDesc);
|
||||
ASSERT_NE(computeShader, nullptr);
|
||||
pipelineState->SetComputeShader(computeShader);
|
||||
ComputePipelineDesc pipelineDesc = {};
|
||||
pipelineDesc.pipelineLayout = pipelineLayout;
|
||||
pipelineDesc.computeShader = shaderDesc;
|
||||
RHIPipelineState* pipelineState = GetDevice()->CreateComputePipelineState(pipelineDesc);
|
||||
ASSERT_NE(pipelineState, nullptr);
|
||||
|
||||
CommandListDesc cmdDesc = {};
|
||||
cmdDesc.commandListType = static_cast<uint32_t>(CommandQueueType::Direct);
|
||||
@@ -815,8 +813,6 @@ TEST_F(OpenGLTestFixture, CommandList_SetComputeDescriptorSets_UsesSetAwareImage
|
||||
|
||||
cmdList->Shutdown();
|
||||
delete cmdList;
|
||||
computeShader->Shutdown();
|
||||
delete computeShader;
|
||||
pipelineState->Shutdown();
|
||||
delete pipelineState;
|
||||
descriptorSet->Shutdown();
|
||||
|
||||
@@ -8,12 +8,59 @@
|
||||
#include "XCEngine/RHI/RHIResourceView.h"
|
||||
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
using namespace XCEngine::RHI;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kWriteRedComputeSpirv[] = {
|
||||
0x07230203, 0x00010000, 0x0008000B, 0x00000017, 0x00000000, 0x00020011, 0x00000001, 0x0006000B,
|
||||
0x00000001, 0x4C534C47, 0x6474732E, 0x3035342E, 0x00000000, 0x0003000E, 0x00000000, 0x00000001,
|
||||
0x0005000F, 0x00000005, 0x00000004, 0x6E69616D, 0x00000000, 0x00060010, 0x00000004, 0x00000011,
|
||||
0x00000001, 0x00000001, 0x00000001, 0x00030003, 0x00000002, 0x000001C2, 0x00040005, 0x00000004,
|
||||
0x6E69616D, 0x00000000, 0x00040005, 0x00000009, 0x616D4975, 0x00006567, 0x00030047, 0x00000009,
|
||||
0x00000019, 0x00040047, 0x00000009, 0x00000021, 0x00000000, 0x00040047, 0x00000009, 0x00000022,
|
||||
0x00000000, 0x00040047, 0x00000016, 0x0000000B, 0x00000019, 0x00020013, 0x00000002, 0x00030021,
|
||||
0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00090019, 0x00000007, 0x00000006,
|
||||
0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x00040020, 0x00000008,
|
||||
0x00000000, 0x00000007, 0x0004003B, 0x00000008, 0x00000009, 0x00000000, 0x00040015, 0x0000000B,
|
||||
0x00000020, 0x00000001, 0x00040017, 0x0000000C, 0x0000000B, 0x00000002, 0x0004002B, 0x0000000B,
|
||||
0x0000000D, 0x00000000, 0x0005002C, 0x0000000C, 0x0000000E, 0x0000000D, 0x0000000D, 0x00040017,
|
||||
0x0000000F, 0x00000006, 0x0000000004, 0x0004002B, 0x00000006, 0x00000010, 0x3F800000, 0x0004002B,
|
||||
0x00000006, 0x00000011, 0x00000000, 0x0007002C, 0x0000000F, 0x00000012, 0x00000010, 0x00000011,
|
||||
0x00000011, 0x00000010, 0x00040015, 0x00000013, 0x00000020, 0x00000000, 0x00040017, 0x00000014,
|
||||
0x00000013, 0x00000003, 0x0004002B, 0x00000013, 0x00000015, 0x00000001, 0x0006002C, 0x00000014,
|
||||
0x00000016, 0x00000015, 0x00000015, 0x00000015, 0x00050036, 0x00000002, 0x00000004, 0x00000000,
|
||||
0x00000003, 0x000200F8, 0x00000005, 0x0004003D, 0x00000007, 0x0000000A, 0x00000009, 0x00040063,
|
||||
0x0000000A, 0x0000000E, 0x00000012, 0x000100FD, 0x00010038
|
||||
};
|
||||
|
||||
ShaderCompileDesc MakeWriteRedComputeShaderDesc() {
|
||||
ShaderCompileDesc shaderDesc = {};
|
||||
shaderDesc.sourceLanguage = ShaderLanguage::SPIRV;
|
||||
shaderDesc.profile = L"cs_6_0";
|
||||
shaderDesc.source.resize(sizeof(kWriteRedComputeSpirv));
|
||||
std::memcpy(shaderDesc.source.data(), kWriteRedComputeSpirv, sizeof(kWriteRedComputeSpirv));
|
||||
return shaderDesc;
|
||||
}
|
||||
|
||||
ShaderCompileDesc MakeWriteRedComputeShaderFromGlslDesc() {
|
||||
static const char* computeSource = R"(#version 450
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
layout(set = 0, binding = 0, rgba8) uniform writeonly image2D uImage;
|
||||
void main() {
|
||||
imageStore(uImage, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 1.0));
|
||||
}
|
||||
)";
|
||||
|
||||
ShaderCompileDesc shaderDesc = {};
|
||||
shaderDesc.sourceLanguage = ShaderLanguage::GLSL;
|
||||
shaderDesc.source.assign(computeSource, computeSource + std::strlen(computeSource));
|
||||
return shaderDesc;
|
||||
}
|
||||
|
||||
TEST_F(VulkanGraphicsFixture, CreateUnorderedAccessViewProducesValidView) {
|
||||
RHITexture* texture = m_device->CreateTexture(CreateColorTextureDesc(4, 4));
|
||||
ASSERT_NE(texture, nullptr);
|
||||
@@ -70,14 +117,11 @@ TEST_F(VulkanGraphicsFixture, DispatchWritesUavTexture) {
|
||||
ASSERT_NE(descriptorSet, nullptr);
|
||||
descriptorSet->Update(0, uav);
|
||||
|
||||
GraphicsPipelineDesc pipelineDesc = {};
|
||||
ComputePipelineDesc pipelineDesc = {};
|
||||
pipelineDesc.pipelineLayout = pipelineLayout;
|
||||
RHIPipelineState* pipelineState = m_device->CreatePipelineState(pipelineDesc);
|
||||
pipelineDesc.computeShader = MakeWriteRedComputeShaderDesc();
|
||||
RHIPipelineState* pipelineState = m_device->CreateComputePipelineState(pipelineDesc);
|
||||
ASSERT_NE(pipelineState, nullptr);
|
||||
|
||||
RHIShader* shader = CreateWriteRedComputeShader();
|
||||
ASSERT_NE(shader, nullptr);
|
||||
pipelineState->SetComputeShader(shader);
|
||||
EXPECT_TRUE(pipelineState->HasComputeShader());
|
||||
EXPECT_EQ(pipelineState->GetType(), PipelineType::Compute);
|
||||
|
||||
@@ -101,8 +145,6 @@ TEST_F(VulkanGraphicsFixture, DispatchWritesUavTexture) {
|
||||
|
||||
commandList->Shutdown();
|
||||
delete commandList;
|
||||
shader->Shutdown();
|
||||
delete shader;
|
||||
pipelineState->Shutdown();
|
||||
delete pipelineState;
|
||||
descriptorSet->Shutdown();
|
||||
@@ -154,14 +196,11 @@ TEST_F(VulkanGraphicsFixture, DispatchWritesUavTextureWithGlslComputeShader) {
|
||||
ASSERT_NE(descriptorSet, nullptr);
|
||||
descriptorSet->Update(0, uav);
|
||||
|
||||
GraphicsPipelineDesc pipelineDesc = {};
|
||||
ComputePipelineDesc pipelineDesc = {};
|
||||
pipelineDesc.pipelineLayout = pipelineLayout;
|
||||
RHIPipelineState* pipelineState = m_device->CreatePipelineState(pipelineDesc);
|
||||
pipelineDesc.computeShader = MakeWriteRedComputeShaderFromGlslDesc();
|
||||
RHIPipelineState* pipelineState = m_device->CreateComputePipelineState(pipelineDesc);
|
||||
ASSERT_NE(pipelineState, nullptr);
|
||||
|
||||
RHIShader* shader = CreateWriteRedComputeShaderFromGlsl();
|
||||
ASSERT_NE(shader, nullptr);
|
||||
pipelineState->SetComputeShader(shader);
|
||||
EXPECT_TRUE(pipelineState->HasComputeShader());
|
||||
EXPECT_EQ(pipelineState->GetType(), PipelineType::Compute);
|
||||
|
||||
@@ -185,8 +224,6 @@ TEST_F(VulkanGraphicsFixture, DispatchWritesUavTextureWithGlslComputeShader) {
|
||||
|
||||
commandList->Shutdown();
|
||||
delete commandList;
|
||||
shader->Shutdown();
|
||||
delete shader;
|
||||
pipelineState->Shutdown();
|
||||
delete pipelineState;
|
||||
descriptorSet->Shutdown();
|
||||
|
||||
@@ -165,28 +165,53 @@ TEST_P(RHITestFixture, PipelineState_EnsureValid_Compute) {
|
||||
delete pso;
|
||||
}
|
||||
|
||||
TEST_P(RHITestFixture, Device_CreateComputePipelineState_ReturnsValidComputePipeline) {
|
||||
ComputePipelineDesc desc = {};
|
||||
desc.computeShader = MakeComputeShaderDesc(GetBackendType());
|
||||
|
||||
RHIPipelineState* pso = GetDevice()->CreateComputePipelineState(desc);
|
||||
ASSERT_NE(pso, nullptr);
|
||||
EXPECT_TRUE(pso->IsValid());
|
||||
EXPECT_TRUE(pso->HasComputeShader());
|
||||
EXPECT_EQ(pso->GetType(), PipelineType::Compute);
|
||||
|
||||
pso->Shutdown();
|
||||
delete pso;
|
||||
}
|
||||
|
||||
TEST_P(RHITestFixture, Device_CreateComputePipelineState_UsesExternalPipelineLayout) {
|
||||
RHIPipelineLayoutDesc pipelineLayoutDesc = {};
|
||||
RHIPipelineLayout* pipelineLayout = GetDevice()->CreatePipelineLayout(pipelineLayoutDesc);
|
||||
ASSERT_NE(pipelineLayout, nullptr);
|
||||
|
||||
ComputePipelineDesc desc = {};
|
||||
desc.computeShader = MakeComputeShaderDesc(GetBackendType());
|
||||
desc.pipelineLayout = pipelineLayout;
|
||||
|
||||
RHIPipelineState* pso = GetDevice()->CreateComputePipelineState(desc);
|
||||
ASSERT_NE(pso, nullptr);
|
||||
EXPECT_TRUE(pso->IsValid());
|
||||
EXPECT_TRUE(pso->HasComputeShader());
|
||||
EXPECT_EQ(pso->GetType(), PipelineType::Compute);
|
||||
|
||||
pso->Shutdown();
|
||||
delete pso;
|
||||
pipelineLayout->Shutdown();
|
||||
delete pipelineLayout;
|
||||
}
|
||||
|
||||
TEST_P(RHITestFixture, CommandList_Dispatch_Basic) {
|
||||
RHICommandList* cmdList = GetDevice()->CreateCommandList({});
|
||||
ASSERT_NE(cmdList, nullptr);
|
||||
|
||||
cmdList->Reset();
|
||||
|
||||
GraphicsPipelineDesc desc = {};
|
||||
RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc);
|
||||
|
||||
ComputePipelineDesc desc = {};
|
||||
desc.computeShader = MakeComputeShaderDesc(GetBackendType());
|
||||
RHIPipelineState* pso = GetDevice()->CreateComputePipelineState(desc);
|
||||
if (pso != nullptr) {
|
||||
ShaderCompileDesc shaderDesc = MakeComputeShaderDesc(GetBackendType());
|
||||
|
||||
RHIShader* computeShader = GetDevice()->CreateShader(shaderDesc);
|
||||
if (computeShader != nullptr) {
|
||||
pso->SetComputeShader(computeShader);
|
||||
cmdList->SetPipelineState(pso);
|
||||
cmdList->Dispatch(1, 1, 1);
|
||||
|
||||
computeShader->Shutdown();
|
||||
delete computeShader;
|
||||
}
|
||||
|
||||
pso->Shutdown();
|
||||
delete pso;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user