1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-03 13:24:20 +01:00

[dxvk] Fix push constant compatibility for pipeline libraries

When linking pipelines, all pipeline libraries are required to declare
the exact same set of push constants, even for stages not part of the
respective libraries.

This invalidates all fossilize databases.
This commit is contained in:
Philip Rebohle 2024-04-26 19:06:51 +02:00
parent 462165da19
commit 2970645f33
13 changed files with 84 additions and 73 deletions

View File

@ -336,7 +336,7 @@ namespace dxvk {
} }
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count) { uint32_t SetupRenderStateBlock(SpirvModule& spvModule) {
uint32_t floatType = spvModule.defFloatType(32); uint32_t floatType = spvModule.defFloatType(32);
uint32_t uintType = spvModule.defIntType(32, 0); uint32_t uintType = spvModule.defIntType(32, 0);
uint32_t vec3Type = spvModule.defVectorType(floatType, 3); uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
@ -357,7 +357,7 @@ namespace dxvk {
floatType, floatType,
}}; }};
uint32_t rsStruct = spvModule.defStructTypeUnique(count, rsMembers.data()); uint32_t rsStruct = spvModule.defStructTypeUnique(rsMembers.size(), rsMembers.data());
uint32_t rsBlock = spvModule.newVar( uint32_t rsBlock = spvModule.newVar(
spvModule.defPointerType(rsStruct, spv::StorageClassPushConstant), spvModule.defPointerType(rsStruct, spv::StorageClassPushConstant),
spv::StorageClassPushConstant); spv::StorageClassPushConstant);
@ -369,9 +369,6 @@ namespace dxvk {
uint32_t memberIdx = 0; uint32_t memberIdx = 0;
auto SetMemberName = [&](const char* name, uint32_t offset) { auto SetMemberName = [&](const char* name, uint32_t offset) {
if (memberIdx >= count)
return;
spvModule.setDebugMemberName (rsStruct, memberIdx, name); spvModule.setDebugMemberName (rsStruct, memberIdx, name);
spvModule.memberDecorateOffset (rsStruct, memberIdx, offset); spvModule.memberDecorateOffset (rsStruct, memberIdx, offset);
memberIdx++; memberIdx++;
@ -781,8 +778,6 @@ namespace dxvk {
uint32_t m_inputMask = 0u; uint32_t m_inputMask = 0u;
uint32_t m_outputMask = 0u; uint32_t m_outputMask = 0u;
uint32_t m_flatShadingMask = 0u; uint32_t m_flatShadingMask = 0u;
uint32_t m_pushConstOffset = 0u;
uint32_t m_pushConstSize = 0u;
DxsoProgramType m_programType; DxsoProgramType m_programType;
D3D9FFShaderKeyVS m_vsKey; D3D9FFShaderKeyVS m_vsKey;
@ -892,8 +887,8 @@ namespace dxvk {
info.inputMask = m_inputMask; info.inputMask = m_inputMask;
info.outputMask = m_outputMask; info.outputMask = m_outputMask;
info.flatShadingInputs = m_flatShadingMask; info.flatShadingInputs = m_flatShadingMask;
info.pushConstOffset = m_pushConstOffset; info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
info.pushConstSize = m_pushConstSize; info.pushConstSize = sizeof(D3D9RenderStateInfo);
return new DxvkShader(info, m_module.compile()); return new DxvkShader(info, m_module.compile());
} }
@ -1384,20 +1379,7 @@ namespace dxvk {
void D3D9FFShaderCompiler::setupRenderStateInfo() { void D3D9FFShaderCompiler::setupRenderStateInfo() {
uint32_t count; m_rsBlock = SetupRenderStateBlock(m_module);
if (m_programType == DxsoProgramType::PixelShader) {
m_pushConstOffset = 0;
m_pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
count = 5;
}
else {
m_pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
m_pushConstSize = sizeof(float) * 6;
count = 11;
}
m_rsBlock = SetupRenderStateBlock(m_module, count);
} }

View File

@ -59,7 +59,7 @@ namespace dxvk {
void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx); void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx);
// Returns a render state block // Returns a render state block
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count); uint32_t SetupRenderStateBlock(SpirvModule& spvModule);
struct D3D9PointSizeInfoVS { struct D3D9PointSizeInfoVS {
uint32_t defaultValue; uint32_t defaultValue;

View File

@ -134,7 +134,7 @@ namespace dxvk {
info.stage = VK_SHADER_STAGE_COMPUTE_BIT; info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
info.bindingCount = bindings.size(); info.bindingCount = bindings.size();
info.bindings = bindings.data(); info.bindings = bindings.data();
info.pushConstOffset = 0; info.pushConstStages = VK_SHADER_STAGE_COMPUTE_BIT;
info.pushConstSize = sizeof(VkExtent2D); info.pushConstSize = sizeof(VkExtent2D);
return new DxvkShader(info, std::move(code)); return new DxvkShader(info, std::move(code));

View File

@ -257,14 +257,13 @@ namespace dxvk {
info.outputMask = m_outputMask; info.outputMask = m_outputMask;
info.uniformSize = m_immConstData.size(); info.uniformSize = m_immConstData.size();
info.uniformData = m_immConstData.data(); info.uniformData = m_immConstData.data();
info.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
info.pushConstSize = sizeof(DxbcPushConstants);
info.outputTopology = m_outputTopology; info.outputTopology = m_outputTopology;
if (m_programInfo.type() == DxbcProgramType::HullShader) if (m_programInfo.type() == DxbcProgramType::HullShader)
info.patchVertexCount = m_hs.vertexCountIn; info.patchVertexCount = m_hs.vertexCountIn;
if (m_programInfo.type() == DxbcProgramType::PixelShader && m_ps.pushConstantId)
info.pushConstSize = sizeof(DxbcPushConstants);
if (m_moduleInfo.xfb) { if (m_moduleInfo.xfb) {
info.xfbRasterizedStream = m_moduleInfo.xfb->rasterizedStream; info.xfbRasterizedStream = m_moduleInfo.xfb->rasterizedStream;

View File

@ -228,8 +228,8 @@ namespace dxvk {
info.bindings = m_bindings.data(); info.bindings = m_bindings.data();
info.inputMask = m_inputMask; info.inputMask = m_inputMask;
info.outputMask = m_outputMask; info.outputMask = m_outputMask;
info.pushConstOffset = m_pushConstOffset; info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
info.pushConstSize = m_pushConstSize; info.pushConstSize = sizeof(D3D9RenderStateInfo);
if (m_programInfo.type() == DxsoProgramTypes::PixelShader) if (m_programInfo.type() == DxsoProgramTypes::PixelShader)
info.flatShadingInputs = m_ps.flatShadingMask; info.flatShadingInputs = m_ps.flatShadingMask;
@ -3561,30 +3561,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
void DxsoCompiler::setupRenderStateInfo() { void DxsoCompiler::setupRenderStateInfo() {
uint32_t count; m_rsBlock = SetupRenderStateBlock(m_module);
// Only need alpha ref for PS 3.
// No FF fog component.
if (m_programInfo.type() == DxsoProgramType::PixelShader) {
if (m_programInfo.majorVersion() == 3) {
m_pushConstOffset = offsetof(D3D9RenderStateInfo, alphaRef);
m_pushConstSize = sizeof(float);
}
else {
m_pushConstOffset = 0;
m_pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
}
count = 5;
}
else {
m_pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
// Point scale never triggers on programmable
m_pushConstSize = sizeof(float) * 3;
count = 8;
}
m_rsBlock = SetupRenderStateBlock(m_module, count);
} }

View File

@ -344,8 +344,6 @@ namespace dxvk {
// covers vertex input and fragment output. // covers vertex input and fragment output.
uint32_t m_inputMask = 0u; uint32_t m_inputMask = 0u;
uint32_t m_outputMask = 0u; uint32_t m_outputMask = 0u;
uint32_t m_pushConstOffset = 0u;
uint32_t m_pushConstSize = 0u;
/////////////////////////////////// ///////////////////////////////////
// Shader-specific data structures // Shader-specific data structures

View File

@ -4984,7 +4984,7 @@ namespace dxvk {
// Mark compute resources and push constants as dirty // Mark compute resources and push constants as dirty
m_descriptorState.dirtyStages(VK_SHADER_STAGE_COMPUTE_BIT); m_descriptorState.dirtyStages(VK_SHADER_STAGE_COMPUTE_BIT);
if (newPipeline->getBindings()->layout().getPushConstantRange().size) if (newPipeline->getBindings()->layout().getPushConstantRange(true).size)
m_flags.set(DxvkContextFlag::DirtyPushConstants); m_flags.set(DxvkContextFlag::DirtyPushConstants);
m_flags.clr(DxvkContextFlag::CpDirtyPipelineState); m_flags.clr(DxvkContextFlag::CpDirtyPipelineState);
@ -5058,7 +5058,7 @@ namespace dxvk {
m_descriptorState.dirtyStages(VK_SHADER_STAGE_ALL_GRAPHICS); m_descriptorState.dirtyStages(VK_SHADER_STAGE_ALL_GRAPHICS);
if (newPipeline->getBindings()->layout().getPushConstantRange().size) if (newPipeline->getBindings()->layout().getPushConstantRange(true).size)
m_flags.set(DxvkContextFlag::DirtyPushConstants); m_flags.set(DxvkContextFlag::DirtyPushConstants);
m_flags.clr(DxvkContextFlag::GpDirtyPipeline); m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
@ -5926,15 +5926,18 @@ namespace dxvk {
? m_state.gp.pipeline->getBindings() ? m_state.gp.pipeline->getBindings()
: m_state.cp.pipeline->getBindings(); : m_state.cp.pipeline->getBindings();
VkPushConstantRange pushConstRange = bindings->layout().getPushConstantRange(); // Optimized pipelines may have push constants trimmed, so look up
// the exact layout used for the currently bound pipeline.
bool independentSets = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
&& m_flags.test(DxvkContextFlag::GpIndependentSets);
VkPushConstantRange pushConstRange = bindings->layout().getPushConstantRange(independentSets);
if (!pushConstRange.size) if (!pushConstRange.size)
return; return;
// Push constants should be compatible between complete and
// independent layouts, so always ask for the complete one
m_cmd->cmdPushConstants( m_cmd->cmdPushConstants(
bindings->getPipelineLayout(false), bindings->getPipelineLayout(independentSets),
pushConstRange.stageFlags, pushConstRange.stageFlags,
pushConstRange.offset, pushConstRange.offset,
pushConstRange.size, pushConstRange.size,

View File

@ -205,7 +205,7 @@ namespace dxvk {
DxvkBindingLayout::DxvkBindingLayout(VkShaderStageFlags stages) DxvkBindingLayout::DxvkBindingLayout(VkShaderStageFlags stages)
: m_pushConst { 0, 0, 0 }, m_stages(stages) { : m_pushConst { 0, 0, 0 }, m_pushConstStages(0), m_stages(stages) {
} }
@ -249,11 +249,17 @@ namespace dxvk {
} }
void DxvkBindingLayout::addPushConstantStage(VkShaderStageFlagBits stage) {
m_pushConstStages |= stage;
}
void DxvkBindingLayout::merge(const DxvkBindingLayout& layout) { void DxvkBindingLayout::merge(const DxvkBindingLayout& layout) {
for (uint32_t i = 0; i < layout.m_bindings.size(); i++) for (uint32_t i = 0; i < layout.m_bindings.size(); i++)
m_bindings[i].merge(layout.m_bindings[i]); m_bindings[i].merge(layout.m_bindings[i]);
addPushConstantRange(layout.m_pushConst); addPushConstantRange(layout.m_pushConst);
m_pushConstStages |= layout.m_pushConstStages;
} }
@ -266,6 +272,9 @@ namespace dxvk {
return false; return false;
} }
if (m_pushConstStages != other.m_pushConstStages)
return false;
if (m_pushConst.stageFlags != other.m_pushConst.stageFlags if (m_pushConst.stageFlags != other.m_pushConst.stageFlags
|| m_pushConst.offset != other.m_pushConst.offset || m_pushConst.offset != other.m_pushConst.offset
|| m_pushConst.size != other.m_pushConst.size) || m_pushConst.size != other.m_pushConst.size)
@ -282,6 +291,7 @@ namespace dxvk {
for (uint32_t i = 0; i < m_bindings.size(); i++) for (uint32_t i = 0; i < m_bindings.size(); i++)
hash.add(m_bindings[i].hash()); hash.add(m_bindings[i].hash());
hash.add(m_pushConstStages);
hash.add(m_pushConst.stageFlags); hash.add(m_pushConst.stageFlags);
hash.add(m_pushConst.offset); hash.add(m_pushConst.offset);
hash.add(m_pushConst.size); hash.add(m_pushConst.size);
@ -334,15 +344,16 @@ namespace dxvk {
} }
// Create pipeline layout objects // Create pipeline layout objects
VkPushConstantRange pushConst = m_layout.getPushConstantRange(); VkPushConstantRange pushConstComplete = m_layout.getPushConstantRange(false);
VkPushConstantRange pushConstIndependent = m_layout.getPushConstantRange(true);
VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
pipelineLayoutInfo.setLayoutCount = setCount; pipelineLayoutInfo.setLayoutCount = setCount;
pipelineLayoutInfo.pSetLayouts = setLayouts.data(); pipelineLayoutInfo.pSetLayouts = setLayouts.data();
if (pushConst.stageFlags && pushConst.size) { if (pushConstComplete.stageFlags && pushConstComplete.size) {
pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConst; pipelineLayoutInfo.pPushConstantRanges = &pushConstComplete;
} }
// If the full set is defined, create a layout without INDEPENDENT_SET_BITS // If the full set is defined, create a layout without INDEPENDENT_SET_BITS
@ -356,6 +367,11 @@ namespace dxvk {
if (m_device->canUseGraphicsPipelineLibrary() && (m_layout.getStages() & VK_SHADER_STAGE_ALL_GRAPHICS)) { if (m_device->canUseGraphicsPipelineLibrary() && (m_layout.getStages() & VK_SHADER_STAGE_ALL_GRAPHICS)) {
pipelineLayoutInfo.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT; pipelineLayoutInfo.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT;
if (pushConstIndependent.stageFlags && pushConstIndependent.size) {
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstIndependent;
}
if (vk->vkCreatePipelineLayout(vk->device(), &pipelineLayoutInfo, nullptr, &m_independentLayout)) if (vk->vkCreatePipelineLayout(vk->device(), &pipelineLayoutInfo, nullptr, &m_independentLayout))
throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout"); throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout");
} }

View File

@ -292,8 +292,19 @@ namespace dxvk {
* \brief Retrieves push constant range * \brief Retrieves push constant range
* \returns Push constant range * \returns Push constant range
*/ */
VkPushConstantRange getPushConstantRange() const { VkPushConstantRange getPushConstantRange(bool independent) const {
return m_pushConst; VkPushConstantRange result = m_pushConst;
if (!independent) {
result.stageFlags &= m_pushConstStages;
if (!result.stageFlags) {
result.offset = 0;
result.size = 0;
}
}
return result;
} }
/** /**
@ -324,6 +335,12 @@ namespace dxvk {
*/ */
void addPushConstantRange(VkPushConstantRange range); void addPushConstantRange(VkPushConstantRange range);
/**
* \brief Adds a stage that actively uses push constants
* \param [in] stage Shader stage
*/
void addPushConstantStage(VkShaderStageFlagBits stage);
/** /**
* \brief Merges binding layouts * \brief Merges binding layouts
* *
@ -353,6 +370,7 @@ namespace dxvk {
std::array<DxvkBindingList, DxvkDescriptorSets::SetCount> m_bindings; std::array<DxvkBindingList, DxvkDescriptorSets::SetCount> m_bindings;
VkPushConstantRange m_pushConst; VkPushConstantRange m_pushConst;
VkShaderStageFlags m_pushConstStages;
VkShaderStageFlags m_stages; VkShaderStageFlags m_stages;
}; };

View File

@ -59,8 +59,8 @@ namespace dxvk {
if (info.pushConstSize) { if (info.pushConstSize) {
VkPushConstantRange pushConst; VkPushConstantRange pushConst;
pushConst.stageFlags = info.stage; pushConst.stageFlags = info.pushConstStages;
pushConst.offset = info.pushConstOffset; pushConst.offset = 0;
pushConst.size = info.pushConstSize; pushConst.size = info.pushConstSize;
m_bindings.addPushConstantRange(pushConst); m_bindings.addPushConstantRange(pushConst);
@ -75,6 +75,8 @@ namespace dxvk {
// Run an analysis pass over the SPIR-V code to gather some // Run an analysis pass over the SPIR-V code to gather some
// info that we may need during pipeline compilation. // info that we may need during pipeline compilation.
bool usesPushConstants = false;
std::vector<BindingOffsets> bindingOffsets; std::vector<BindingOffsets> bindingOffsets;
std::vector<uint32_t> varIds; std::vector<uint32_t> varIds;
std::vector<uint32_t> sampleMaskIds; std::vector<uint32_t> sampleMaskIds;
@ -154,6 +156,9 @@ namespace dxvk {
if (std::find(sampleMaskIds.begin(), sampleMaskIds.end(), ins.arg(2)) != sampleMaskIds.end()) if (std::find(sampleMaskIds.begin(), sampleMaskIds.end(), ins.arg(2)) != sampleMaskIds.end())
m_flags.set(DxvkShaderFlag::ExportsSampleMask); m_flags.set(DxvkShaderFlag::ExportsSampleMask);
} }
if (ins.arg(3) == spv::StorageClassPushConstant)
usesPushConstants = true;
} }
// Ignore the actual shader code, there's nothing interesting for us in there. // Ignore the actual shader code, there's nothing interesting for us in there.
@ -169,6 +174,11 @@ namespace dxvk {
m_bindingOffsets.push_back(info); m_bindingOffsets.push_back(info);
} }
// Set flag for stages that actually use push constants
// so that they can be trimmed for optimized pipelines.
if (usesPushConstants)
m_bindings.addPushConstantStage(info.stage);
// Don't set pipeline library flag if the shader // Don't set pipeline library flag if the shader
// doesn't actually support pipeline libraries // doesn't actually support pipeline libraries
m_needsLibraryCompile = canUsePipelineLibrary(true); m_needsLibraryCompile = canUsePipelineLibrary(true);

View File

@ -52,7 +52,7 @@ namespace dxvk {
/// Flat shading input mask /// Flat shading input mask
uint32_t flatShadingInputs = 0; uint32_t flatShadingInputs = 0;
/// Push constant range /// Push constant range
uint32_t pushConstOffset = 0; VkShaderStageFlags pushConstStages = 0;
uint32_t pushConstSize = 0; uint32_t pushConstSize = 0;
/// Uniform buffer data /// Uniform buffer data
uint32_t uniformSize = 0; uint32_t uniformSize = 0;

View File

@ -329,6 +329,8 @@ namespace dxvk {
DxvkShaderCreateInfo vsInfo; DxvkShaderCreateInfo vsInfo;
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vsInfo.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
vsInfo.pushConstSize = sizeof(PresenterArgs);
vsInfo.outputMask = 0x1; vsInfo.outputMask = 0x1;
m_vs = new DxvkShader(vsInfo, std::move(vsCode)); m_vs = new DxvkShader(vsInfo, std::move(vsCode));
@ -336,6 +338,7 @@ namespace dxvk {
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fsInfo.bindingCount = fsBindings.size(); fsInfo.bindingCount = fsBindings.size();
fsInfo.bindings = fsBindings.data(); fsInfo.bindings = fsBindings.data();
fsInfo.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
fsInfo.pushConstSize = sizeof(PresenterArgs); fsInfo.pushConstSize = sizeof(PresenterArgs);
fsInfo.inputMask = 0x1; fsInfo.inputMask = 0x1;
fsInfo.outputMask = 0x1; fsInfo.outputMask = 0x1;

View File

@ -183,14 +183,17 @@ namespace dxvk::hud {
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vsInfo.bindingCount = vsBindings.size(); vsInfo.bindingCount = vsBindings.size();
vsInfo.bindings = vsBindings.data(); vsInfo.bindings = vsBindings.data();
vsInfo.outputMask = 0x3; vsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT;
vsInfo.pushConstSize = sizeof(HudTextPushConstants); vsInfo.pushConstSize = sizeof(HudTextPushConstants);
vsInfo.outputMask = 0x3;
result.vert = new DxvkShader(vsInfo, std::move(vsCode)); result.vert = new DxvkShader(vsInfo, std::move(vsCode));
DxvkShaderCreateInfo fsInfo; DxvkShaderCreateInfo fsInfo;
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fsInfo.bindingCount = fsBindings.size(); fsInfo.bindingCount = fsBindings.size();
fsInfo.bindings = fsBindings.data(); fsInfo.bindings = fsBindings.data();
fsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT;
fsInfo.pushConstSize = sizeof(HudTextPushConstants);
fsInfo.inputMask = 0x3; fsInfo.inputMask = 0x3;
fsInfo.outputMask = 0x1; fsInfo.outputMask = 0x1;
result.frag = new DxvkShader(fsInfo, std::move(fsCode)); result.frag = new DxvkShader(fsInfo, std::move(fsCode));
@ -212,6 +215,7 @@ namespace dxvk::hud {
DxvkShaderCreateInfo vsInfo; DxvkShaderCreateInfo vsInfo;
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vsInfo.outputMask = 0x1; vsInfo.outputMask = 0x1;
vsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
vsInfo.pushConstSize = sizeof(HudGraphPushConstants); vsInfo.pushConstSize = sizeof(HudGraphPushConstants);
result.vert = new DxvkShader(vsInfo, std::move(vsCode)); result.vert = new DxvkShader(vsInfo, std::move(vsCode));
@ -221,6 +225,7 @@ namespace dxvk::hud {
fsInfo.bindings = fsBindings.data(); fsInfo.bindings = fsBindings.data();
fsInfo.inputMask = 0x1; fsInfo.inputMask = 0x1;
fsInfo.outputMask = 0x1; fsInfo.outputMask = 0x1;
fsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
fsInfo.pushConstSize = sizeof(HudGraphPushConstants); fsInfo.pushConstSize = sizeof(HudGraphPushConstants);
result.frag = new DxvkShader(fsInfo, std::move(fsCode)); result.frag = new DxvkShader(fsInfo, std::move(fsCode));