Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Root/Push constants #22

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

alelievr
Copy link
Contributor

Hello,

I added D3D12 Root constant and Vulkan's push constant to the command buffer API. I don't really have experience writing metal code so I'm not sure what I did works (and I can't test either).

# Conflicts:
#	src/FlyCube/CommandList/DXCommandList.h

Fix root constants

# Conflicts:
#	src/FlyCube/CommandList/DXCommandList.h
@andrejnau
Copy link
Owner

I don't really have experience writing metal code so I'm not sure what I did works (and I can't test either).

No need to worry about metal, just place assert(false) there instead of implementation. I will handle it later.

If you're interested, there are 2 problems with the metal

  1. SPIRV-Cross does not automatically emit push constants blocks, when [[vk::push_constant]] is used in hlsl.
  2. You cannot just create new MTLRenderCommandEncoder/MTLComputeCommandEncoder, set constants, and endEncoding. You need to track constants changes and apply before echo draw/dispatch.

@@ -104,5 +104,7 @@ class CommandList : public QueryInterface {
uint32_t query_count,
const std::shared_ptr<Resource>& dst_buffer,
uint64_t dst_offset) = 0;
virtual void SetGraphicsConstant(uint32_t root_parameter_index, uint32_t value, uint32_t byte_offset) = 0;
Copy link
Owner

Choose a reason for hiding this comment

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

It is better to use PushConstants, to match it with [[vk::push_constant]] in hlsl.
void PushConstants(ShaderType shader_type, uint32_t dst_offset, const void* data, uint32_t size)

In Vulkan we can have at most 1 push_constant block in each shader, I suggest to add the same limitation in FlyCube. In this case ShaderType + active Pipeline will probably be enough to find root_parameter_index in DirectX12 implementation.

In my opinion PushConstants is enough to for all cases, but I don't mind having PushConstant as well.
void PushConstant(ShaderType shader_type, uint32_t dst_offset, uint32_t value)

@@ -732,6 +732,16 @@ void DXCommandList::ResolveQueryData(const std::shared_ptr<QueryHeap>& query_hea
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0));
}

void DXCommandList::SetGraphicsConstant(uint32_t root_parameter_index, uint32_t value, uint32_t byte_offset)
Copy link
Owner

Choose a reason for hiding this comment

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

In the current implementation, how do you know which root_parameter_index value you need to pass?

Copy link
Contributor Author

@alelievr alelievr Mar 1, 2025

Choose a reason for hiding this comment

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

The root parameter index is the index of the binding set/layout set in the list given to CreateBindingSetLayout or CreateBindingSet.

void VKCommandList::SetGraphicsConstant(uint32_t root_parameter_index, uint32_t value, uint32_t byte_offset)
{
decltype(auto) pipeline_layout = m_state->GetPipelineLayout();
m_command_list->pushConstants(pipeline_layout,
Copy link
Owner

Choose a reason for hiding this comment

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

You also need to specify pipeline_layout_info.pPushConstantRanges in VKBindingSetLayout. But it probably won't work without information about push constant size.

@@ -408,6 +408,7 @@ struct BindKey {
uint32_t space = 0;
uint32_t count = 1;
uint32_t remapped_slot = ~0;
bool is_root_constant = false;
Copy link
Owner

Choose a reason for hiding this comment

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

I suggest to use ViewType::kPushConstant instead.

Copy link
Owner

Choose a reason for hiding this comment

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

Actually no, it's better to use ViewType::kConstantBuffer. Because ShaderReflection must be able to distinguish ViewType::kPushConstant from ViewType::kConstantBuffer, but there is no way to do so in dxil, since dxc ignore [[vk::push_constant]] when compile to dxil.

But since we still need to pass the size for push_constant, it is better to pass it separately from the BindKey.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I use ViewType::kConstantBuffer instead of this boolean, how can I know if the root BindKey should go to a root constant?

Copy link
Owner

Choose a reason for hiding this comment

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

For example, we can separate them.

struct PushConstant {
    ShaderType shader_type = ShaderType::kUnknown;
    uint32_t size = 0;
};

std::shared_ptr<BindingSetLayout> CreateBindingSetLayout(const std::vector<BindKey>& descs, const std::vector<PushConstant>& push_constants = {});

Copy link
Owner

Choose a reason for hiding this comment

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

Not sure what is best to use, just ShaderType or BindKey.

  1. ShaderType
    At most 1 push constant per shader stage to match Vulkan limitation.
    Slot and space are 0 because spirv do not save bindings when [[vk::push_constant]] is used.
  2. BindKey
    Allow multiple push constant in DirectX12 and Metal, but Vulkan still supports at most 1 push constant per shader stage at slot/space 0 with using [[vk::push_constant]].
    More flexible, but harder to use in Vulkan.

@andrejnau
Copy link
Owner

  1. SPIRV-Cross does not automatically emit push constants blocks, when [[vk::push_constant]] is used in hlsl.

According to the documentation, MTL*CommandEncoder::set*Bytes implicitly creates a buffer and stores the transferred data into it. It seems that there is no equivalent of push_constant in MSL, so it is correct that SPIRV-Cross generates a buffer binding for [[vk::push_constant]].

@andrejnau andrejnau force-pushed the master branch 2 times, most recently from 3df3b1a to 9acb37f Compare February 25, 2025 09:15
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants