Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Graphics/Archiver/src/Archiver_Vk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@ void SerializedPipelineStateImpl::PatchShadersVk(const CreateInfoType& CreateInf
{
ShaderStageInfoVk& Src{ShaderStages[i]};
PipelineStateVkImpl::ShaderStageInfo& Dst{ShaderStagesVk[i]};
Dst.Type = Src.Type;
Dst.Shaders = std::move(Src.Shaders);
Dst.SPIRVs = std::move(Src.SPIRVs);
Dst.Type = Src.Type;
Dst.Shaders = std::move(Src.Shaders);
Dst.SPIRVs = std::move(Src.SPIRVs);
Dst.ShaderResources = std::move(Src.ShaderResources);
}

IPipelineResourceSignature** ppSignatures = CreateInfo.ppResourceSignatures;
Expand Down
18 changes: 18 additions & 0 deletions Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
#include "HashUtils.hpp"
#include "ManagedVulkanObject.hpp"

// Push constants data storage (max size is typically 128-256 bytes, use 256 for safety)
#define DILIGENT_MAX_PUSH_CONSTANTS_SIZE 256
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this constant to Constants.h, and call it DILIGENT_MAX_INLINE_CONSTANTS_SIZE / MAX_INLINE_CONSTANTS_SIZE similar to other constants.
It is already used in D3D11 and D3D12, so let's make it unified.
Can you submit this as separate PR?


namespace Diligent
{

Expand Down Expand Up @@ -374,6 +377,8 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBase<EngineVkImplTr
const Box& DstBox,
RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode);

void SetPushConstants(const void* pData, Uint32 Offset, Uint32 Size);

virtual void DILIGENT_CALL_TYPE GenerateMips(ITextureView* pTexView) override final;

size_t GetNumCommandsInCtx() const { return m_State.NumCommands; }
Expand Down Expand Up @@ -514,11 +519,18 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBase<EngineVkImplTr
/// Current graphics PSO uses no depth/render targets.
bool NullRenderTargets = false;

/// Flag indicating if push constants have been updated since last draw/dispatch
bool PushConstantsDirty = false;

Uint32 NumCommands = 0;

VkPipelineBindPoint vkPipelineBindPoint = VK_PIPELINE_BIND_POINT_MAX_ENUM;
} m_State;

// Push constants data storage
std::array<Uint8, DILIGENT_MAX_PUSH_CONSTANTS_SIZE> m_PushConstantsData = {};
Uint32 m_PushConstantsDataSize = 0; // Actual size of valid push constants data

// Graphics/mesh, compute, ray tracing
static constexpr Uint32 NUM_PIPELINE_BIND_POINTS = 3;

Expand Down Expand Up @@ -555,6 +567,12 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBase<EngineVkImplTr
__forceinline ResourceBindInfo& GetBindInfo(PIPELINE_TYPE Type);

__forceinline void CommitDescriptorSets(ResourceBindInfo& BindInfo, Uint32 CommitSRBMask);

void UpdateInlineConstantBuffers(ResourceBindInfo& BindInfo);

// Commits push constants to the command buffer if they are dirty
void CommitPushConstants();

#ifdef DILIGENT_DEVELOPMENT
void DvpValidateCommittedShaderResources(ResourceBindInfo& BindInfo);
#endif
Expand Down
45 changes: 44 additions & 1 deletion Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,28 @@ namespace Diligent
class RenderDeviceVkImpl;
class PipelineResourceSignatureVkImpl;

/// Push constant information extracted from shaders or selected from inline constants
struct PushConstantInfoVk
{
VkShaderStageFlags StageFlags = 0;
Uint32 Size = 0;
Uint32 SignatureIndex = ~0u; // Index of the signature containing the push constant (~0u if none)
Uint32 ResourceIndex = ~0u; // Resource index within the signature (~0u if none)
};

static constexpr Uint32 INVALID_PUSH_CONSTANT_INDEX = ~0u;

/// Implementation of the Diligent::PipelineLayoutVk class
class PipelineLayoutVk
{
public:
PipelineLayoutVk();
~PipelineLayoutVk();

void Create(RenderDeviceVkImpl* pDeviceVk, RefCntAutoPtr<PipelineResourceSignatureVkImpl> ppSignatures[], Uint32 SignatureCount) noexcept(false);
void Create(RenderDeviceVkImpl* pDeviceVk,
RefCntAutoPtr<PipelineResourceSignatureVkImpl> ppSignatures[],
Uint32 SignatureCount,
const PushConstantInfoVk& PushConstant = {}) noexcept(false);
void Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask);

VkPipelineLayout GetVkPipelineLayout() const { return m_VkPipelineLayout; }
Expand All @@ -59,6 +73,23 @@ class PipelineLayoutVk
return m_FirstDescrSetIndex[Index];
}

// Returns true if this pipeline layout has push constants
bool HasPushConstants() const { return m_PushConstantSize > 0; }

// Returns the size of push constants in bytes
Uint32 GetPushConstantSize() const { return m_PushConstantSize; }

// Returns the shader stage flags for push constants
VkShaderStageFlags GetPushConstantStageFlags() const { return m_PushConstantStageFlags; }

// Returns the signature index containing the push constant resource
// Returns INVALID_PUSH_CONSTANT_INDEX if no push constant is selected
Uint32 GetPushConstantSignatureIndex() const { return m_PushConstantSignatureIndex; }

// Returns the resource index within the signature for push constant
// Returns INVALID_PUSH_CONSTANT_INDEX if no push constant is selected
Uint32 GetPushConstantResourceIndex() const { return m_PushConstantResourceIndex; }

private:
VulkanUtilities::PipelineLayoutWrapper m_VkPipelineLayout;

Expand All @@ -70,6 +101,18 @@ class PipelineLayoutVk
// (Maximum is MAX_RESOURCE_SIGNATURES * 2)
Uint8 m_DescrSetCount = 0;

// Push constant size in bytes
Uint32 m_PushConstantSize = 0;

// Shader stages that use push constants
VkShaderStageFlags m_PushConstantStageFlags = 0;

// Index of the signature containing the push constant resource
Uint32 m_PushConstantSignatureIndex = INVALID_PUSH_CONSTANT_INDEX;

// Resource index within the signature for push constant
Uint32 m_PushConstantResourceIndex = INVALID_PUSH_CONSTANT_INDEX;

#ifdef DILIGENT_DEBUG
Uint32 m_DbgMaxBindIndex = 0;
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace Diligent

struct SPIRVShaderResourceAttribs;
class DeviceContextVkImpl;
class BufferVkImpl;

struct ImmutableSamplerAttribsVk
{
Expand All @@ -58,6 +59,27 @@ struct ImmutableSamplerAttribsVk
};
ASSERT_SIZEOF(ImmutableSamplerAttribsVk, 8, "The struct is used in serialization and must be tightly packed");

/// Inline constant buffer attributes for Vulkan backend.
/// All inline constants are treated uniformly at PRS level - they all get:
/// - DescriptorSet binding and cache allocation
/// - Shared emulated buffer (created in the Signature, shared by all SRBs)
///
/// Push constant selection is deferred to PSO creation time. At PSO creation,
/// one inline constant may be selected to use vkCmdPushConstants based on:
/// 1. SPIR-V reflection (ResourceType::PushConstant in shader)
/// 2. First inline constant as fallback (converted via PatchShader)
struct InlineConstantBufferAttribsVk
{
Uint32 ResIndex = 0; // Resource index in the signature (used for matching)
Uint32 DescrSet = 0; // Descriptor set index
Uint32 BindingIndex = 0; // Binding index within the descriptor set
Uint32 NumConstants = 0; // Number of 32-bit constants

// Shared buffer created in the Signature (similar to D3D11)
// All SRBs reference this same buffer to reduce memory usage.
RefCntAutoPtr<BufferVkImpl> pBuffer;
};

struct PipelineResourceSignatureInternalDataVk : PipelineResourceSignatureInternalData<PipelineResourceAttribsVk, ImmutableSamplerAttribsVk>
{
Uint16 DynamicUniformBufferCount = 0;
Expand Down Expand Up @@ -134,6 +156,20 @@ class PipelineResourceSignatureVkImpl final : public PipelineResourceSignatureBa
void CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache,
VkDescriptorSet vkDynamicDescriptorSet) const;

// Updates inline constant buffers by mapping the internal buffers and copying data from the resource cache
// ResourceCache must be valid - each SRB has its own copy of inline constant data stored in the cache
// PushConstantResIndex: Resource index of the inline constant selected as push constant by PSO
// Pass ~0u if no push constant is selected from this signature
void UpdateInlineConstantBuffers(const ShaderResourceCacheVk& ResourceCache,
DeviceContextVkImpl& Ctx,
Uint32 PushConstantResIndex) const;

// Returns the number of inline constant buffers
Uint32 GetNumInlineConstantBufferAttribs() const { return m_NumInlineConstantBufferAttribs; }

// Returns the inline constant buffer attributes
const InlineConstantBufferAttribsVk* GetInlineConstantBufferAttribs() const { return m_InlineConstantBufferAttribs.get(); }

#ifdef DILIGENT_DEVELOPMENT
/// Verifies committed resource using the SPIRV resource attributes from the PSO.
bool DvpValidateCommittedResource(const DeviceContextVkImpl* pDeviceCtx,
Expand Down Expand Up @@ -193,6 +229,11 @@ class PipelineResourceSignatureVkImpl final : public PipelineResourceSignatureBa
// The total number storage buffers with dynamic offsets in both descriptor sets,
// accounting for array size.
Uint16 m_DynamicStorageBufferCount = 0;

// Number of inline constant buffers
Uint32 m_NumInlineConstantBufferAttribs = 0;
// Inline constant buffer attributes
std::unique_ptr<InlineConstantBufferAttribsVk[]> m_InlineConstantBufferAttribs;
};

template <> Uint32 PipelineResourceSignatureVkImpl::GetDescriptorSetIndex<PipelineResourceSignatureVkImpl::DESCRIPTOR_SET_ID_STATIC_MUTABLE>() const;
Expand Down
11 changes: 9 additions & 2 deletions Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ class PipelineStateVkImpl final : public PipelineStateBase<EngineVkImplTraits>
// Shader stage type. All shaders in the stage must have the same type.
SHADER_TYPE Type = SHADER_TYPE_UNKNOWN;

std::vector<const ShaderVkImpl*> Shaders;
std::vector<std::vector<uint32_t>> SPIRVs;
std::vector<const ShaderVkImpl*> Shaders;
std::vector<std::vector<uint32_t>> SPIRVs;
std::vector<std::shared_ptr<const SPIRVShaderResources>> ShaderResources; //This can be also updated due to push constant

friend SHADER_TYPE GetShaderStageType(const ShaderStageInfo& Stage) { return Stage.Type; }
};
Expand Down Expand Up @@ -133,6 +134,12 @@ class PipelineStateVkImpl final : public PipelineStateBase<EngineVkImplTraits>
void InitializePipeline(const ComputePipelineStateCreateInfo& CreateInfo);
void InitializePipeline(const RayTracingPipelineStateCreateInfo& CreateInfo);

bool InitPushConstantInfoFromSignatures(PushConstantInfoVk& PushConstant,
TShaderStages& ShaderStages) const noexcept(false);

void PatchShaderConvertUniformBufferToPushConstant(const PushConstantInfoVk& PushConstant,
TShaderStages& ShaderStages) const noexcept(false);

// TPipelineStateBase::Construct needs access to InitializePipeline
friend TPipelineStateBase;

Expand Down
57 changes: 53 additions & 4 deletions Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ class ShaderResourceCacheVk : public ShaderResourceCacheBase
public:
explicit ShaderResourceCacheVk(ResourceCacheContentType ContentType) noexcept :
m_TotalResources{0},
m_ContentType{static_cast<Uint32>(ContentType)}
m_ContentType{static_cast<Uint32>(ContentType)},
m_HasInlineConstants{0}
{
VERIFY_EXPR(GetContentType() == ContentType);
}
Expand All @@ -93,7 +94,7 @@ class ShaderResourceCacheVk : public ShaderResourceCacheBase
void InitializeSets(IMemoryAllocator& MemAllocator, Uint32 NumSets, const Uint32* SetSizes);
void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, DescriptorType Type, bool HasImmutableSampler);

// sizeof(Resource) == 32 (x64, msvc, Release)
// sizeof(Resource) == 40 (x64, msvc, Release)
struct Resource
{
explicit Resource(DescriptorType _Type, bool _HasImmutableSampler) noexcept :
Expand All @@ -120,6 +121,10 @@ class ShaderResourceCacheVk : public ShaderResourceCacheBase
/*16 */ Uint64 BufferBaseOffset = 0;
/*24 */ Uint64 BufferRangeSize = 0;

// For inline constants only - pointer to CPU-side staging buffer
/*32 */ void* pInlineConstantData = nullptr;
/*40 */ // End of structure

VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo() const;
VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo() const;
VkDescriptorImageInfo GetImageDescriptorWriteInfo () const;
Expand Down Expand Up @@ -245,13 +250,44 @@ class ShaderResourceCacheVk : public ShaderResourceCacheBase
Uint32 CacheOffset,
Uint32 DynamicBufferOffset);

// Sets inline constant data in the resource cache
void SetInlineConstants(Uint32 DescrSetIndex,
Uint32 CacheOffset,
const void* pConstants,
Uint32 FirstConstant,
Uint32 NumConstants);

// Gets the inline constant data pointer from the resource cache
const void* GetInlineConstantData(Uint32 DescrSetIndex, Uint32 CacheOffset) const;

// Initialize inline constant buffer in the resource cache
void InitializeInlineConstantBuffer(Uint32 DescrSetIndex,
Uint32 CacheOffset,
Uint32 NumConstants,
void* pInlineConstantData);

// Sets the inline constant memory block (takes ownership, will be freed in destructor)
void SetInlineConstantMemory(IMemoryAllocator& Allocator, void* pMemory)
{
m_pInlineConstantMemory = decltype(m_pInlineConstantMemory){
pMemory,
STDDeleter<void, IMemoryAllocator>(Allocator)};
}

// Explicitly marks that this cache contains inline constants.
// This is useful when inline constant memory is initialized externally
// (e.g., during SRB cache setup) before any data is written.
void MarkHasInlineConstants()
{
m_HasInlineConstants = 1;
}

Uint32 GetNumDescriptorSets() const { return m_NumSets; }
bool HasDynamicResources() const { return m_NumDynamicBuffers > 0; }

bool HasInlineConstants() const
{
return false;
return m_HasInlineConstants;
}

ResourceCacheContentType GetContentType() const { return static_cast<ResourceCacheContentType>(m_ContentType); }
Expand Down Expand Up @@ -287,16 +323,29 @@ class ShaderResourceCacheVk : public ShaderResourceCacheBase

std::unique_ptr<void, STDDeleter<void, IMemoryAllocator>> m_pMemory;

// Memory for inline constant data (allocated separately, freed in destructor)
// All inline constants use this memory for CPU-side staging.
// Push constant selection is done at PSO level, not cache level.
std::unique_ptr<void, STDDeleter<void, IMemoryAllocator>> m_pInlineConstantMemory;

// Note: Inline constant buffers (for emulated inline constants) are stored in
// InlineConstantBufferAttribsVk::pBuffer in the PipelineResourceSignature, similar to D3D11.
// All SRBs share the same buffer to reduce memory usage.
// Push constant selection is deferred to PSO creation time.

Uint16 m_NumSets = 0;

// Total actual number of dynamic buffers (that were created with USAGE_DYNAMIC) bound in the resource cache
// regardless of the variable type. Note this variable is not equal to dynamic offsets count, which is constant.
Uint16 m_NumDynamicBuffers = 0;
Uint32 m_TotalResources : 31;
Uint32 m_TotalResources : 30;

// Indicates what types of resources are stored in the cache
const Uint32 m_ContentType : 1;

// Indicates whether the cache contains inline constants
Uint32 m_HasInlineConstants : 1;

#ifdef DILIGENT_DEBUG
// Debug array that stores flags indicating if resources in the cache have been initialized
std::vector<std::vector<bool>> m_DbgInitializedResources;
Expand Down
11 changes: 10 additions & 1 deletion Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ class ShaderVkImpl final : public ShaderBase<EngineVkImplTraits>

const std::shared_ptr<const SPIRVShaderResources>& GetShaderResources() const
{
DEV_CHECK_ERR(!IsCompiling(), "Shader resources are not available until the shader is compiled. Use GetStatus() to check the shader status.");
static const std::shared_ptr<const SPIRVShaderResources> NullShaderResource;
// NOTE: while shader is compiled asynchronously, is not available
if (IsCompiling())
return NullShaderResource;
Comment on lines +95 to +98
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not look right.
If the shader is compiling, no method should be called except for GetStatus()


return m_pShaderResources;
}

Expand All @@ -110,15 +114,20 @@ class ShaderVkImpl final : public ShaderBase<EngineVkImplTraits>
Size = m_SPIRV.size() * sizeof(m_SPIRV[0]);
}

std::shared_ptr<const SPIRVShaderResources> CreateSPIRVShaderResources(const std::vector<uint32_t>& SPIRV) noexcept(false);

private:
void Initialize(const ShaderCreateInfo& ShaderCI,
const CreateInfo& VkShaderCI) noexcept(false);

private:
std::shared_ptr<const SPIRVShaderResources> m_pShaderResources;

std::string m_CIEntryPoint;
std::string m_EntryPoint;
std::vector<uint32_t> m_SPIRV;

bool m_CILoadConstantBufferReflection = false;
};

} // namespace Diligent
Loading
Loading