1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-13 16:08:50 +01:00

[dxvk] Introduce DxvkGraphicsPipelineShaderState

And factor out a bunch of related code.
This commit is contained in:
Philip Rebohle 2022-07-31 00:24:16 +02:00
parent 30fa9df868
commit 63420c0cd7
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 164 additions and 86 deletions

View File

@ -601,6 +601,112 @@ namespace dxvk {
} }
DxvkGraphicsPipelineShaderState::DxvkGraphicsPipelineShaderState() {
}
DxvkGraphicsPipelineShaderState::DxvkGraphicsPipelineShaderState(
const DxvkGraphicsPipelineShaders& shaders,
const DxvkGraphicsPipelineStateInfo& state)
: vsInfo (getCreateInfo(shaders, shaders.vs, state)),
tcsInfo (getCreateInfo(shaders, shaders.tcs, state)),
tesInfo (getCreateInfo(shaders, shaders.tes, state)),
gsInfo (getCreateInfo(shaders, shaders.gs, state)),
fsInfo (getCreateInfo(shaders, shaders.fs, state)) {
}
bool DxvkGraphicsPipelineShaderState::eq(const DxvkGraphicsPipelineShaderState& other) const {
return vsInfo.eq(other.vsInfo)
&& tcsInfo.eq(other.tcsInfo)
&& tesInfo.eq(other.tesInfo)
&& gsInfo.eq(other.gsInfo)
&& fsInfo.eq(other.fsInfo);
}
size_t DxvkGraphicsPipelineShaderState::hash() const {
DxvkHashState hash;
hash.add(vsInfo.hash());
hash.add(tcsInfo.hash());
hash.add(tesInfo.hash());
hash.add(gsInfo.hash());
hash.add(fsInfo.hash());
return hash;
}
DxvkShaderModuleCreateInfo DxvkGraphicsPipelineShaderState::getCreateInfo(
const DxvkGraphicsPipelineShaders& shaders,
const Rc<DxvkShader>& shader,
const DxvkGraphicsPipelineStateInfo& state) {
DxvkShaderModuleCreateInfo info;
if (shader == nullptr)
return info;
// Fix up fragment shader outputs for dual-source blending
const DxvkShaderCreateInfo& shaderInfo = shader->info();
if (shaderInfo.stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
info.fsDualSrcBlend = state.useDualSourceBlending();
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if ((shaderInfo.outputMask & (1u << i)) && state.writesRenderTarget(i))
info.rtSwizzles[i] = state.omSwizzle[i].mapping();
}
}
// Deal with undefined shader inputs
uint32_t consumedInputs = shaderInfo.inputMask;
uint32_t providedInputs = 0;
if (shaderInfo.stage == VK_SHADER_STAGE_VERTEX_BIT) {
for (uint32_t i = 0; i < state.il.attributeCount(); i++)
providedInputs |= 1u << state.ilAttributes[i].location();
} else if (shaderInfo.stage != VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
auto prevStage = getPrevStageShader(shaders, shaderInfo.stage);
providedInputs = prevStage->info().outputMask;
} else {
// Technically not correct, but this
// would need a lot of extra care
providedInputs = consumedInputs;
}
info.undefinedInputs = (providedInputs & consumedInputs) ^ consumedInputs;
return info;
}
Rc<DxvkShader> DxvkGraphicsPipelineShaderState::getPrevStageShader(
const DxvkGraphicsPipelineShaders& shaders,
const VkShaderStageFlagBits stage) {
if (stage == VK_SHADER_STAGE_VERTEX_BIT)
return nullptr;
if (stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
return shaders.tcs;
Rc<DxvkShader> result = shaders.vs;
if (stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
return result;
if (shaders.tes != nullptr)
result = shaders.tes;
if (stage == VK_SHADER_STAGE_GEOMETRY_BIT)
return result;
if (shaders.gs != nullptr)
result = shaders.gs;
return result;
}
DxvkPipelineSpecConstantState::DxvkPipelineSpecConstantState() { DxvkPipelineSpecConstantState::DxvkPipelineSpecConstantState() {
} }
@ -888,7 +994,8 @@ namespace dxvk {
// Remapping fragment shader outputs would require spec constants // Remapping fragment shader outputs would require spec constants
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (writesRenderTarget(state, i) && !util::isIdentityMapping(state.omSwizzle[i].mapping())) if ((m_fsOut & (1u << i)) && state.writesRenderTarget(i)
&& !util::isIdentityMapping(state.omSwizzle[i].mapping()))
return false; return false;
} }
@ -978,6 +1085,7 @@ namespace dxvk {
} }
// Set up pipeline state // Set up pipeline state
DxvkGraphicsPipelineShaderState shState(m_shaders, state);
DxvkGraphicsPipelineVertexInputState viState(m_device, state, m_shaders.vs.ptr()); DxvkGraphicsPipelineVertexInputState viState(m_device, state, m_shaders.vs.ptr());
DxvkGraphicsPipelinePreRasterizationState prState(m_device, state, m_shaders.gs.ptr()); DxvkGraphicsPipelinePreRasterizationState prState(m_device, state, m_shaders.gs.ptr());
DxvkGraphicsPipelineFragmentShaderState fsState(m_device, state); DxvkGraphicsPipelineFragmentShaderState fsState(m_device, state);
@ -993,16 +1101,16 @@ namespace dxvk {
if (m_shaders.fs != nullptr) if (m_shaders.fs != nullptr)
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, m_fsLibrary->getModuleIdentifier(), &scState.scInfo); stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, m_fsLibrary->getModuleIdentifier(), &scState.scInfo);
} else { } else {
stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, getShaderCode(m_shaders.vs, state), &scState.scInfo); stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, getShaderCode(m_shaders.vs, shState.vsInfo), &scState.scInfo);
if (m_shaders.tcs != nullptr) if (m_shaders.tcs != nullptr)
stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, getShaderCode(m_shaders.tcs, state), &scState.scInfo); stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, getShaderCode(m_shaders.tcs, shState.tcsInfo), &scState.scInfo);
if (m_shaders.tes != nullptr) if (m_shaders.tes != nullptr)
stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, getShaderCode(m_shaders.tes, state), &scState.scInfo); stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, getShaderCode(m_shaders.tes, shState.tesInfo), &scState.scInfo);
if (m_shaders.gs != nullptr) if (m_shaders.gs != nullptr)
stageInfo.addStage(VK_SHADER_STAGE_GEOMETRY_BIT, getShaderCode(m_shaders.gs, state), &scState.scInfo); stageInfo.addStage(VK_SHADER_STAGE_GEOMETRY_BIT, getShaderCode(m_shaders.gs, shState.gsInfo), &scState.scInfo);
if (m_shaders.fs != nullptr) if (m_shaders.fs != nullptr)
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, getShaderCode(m_shaders.fs, state), &scState.scInfo); stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, getShaderCode(m_shaders.fs, shState.fsInfo), &scState.scInfo);
} }
VkPipelineDynamicStateCreateInfo dyInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; VkPipelineDynamicStateCreateInfo dyInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
@ -1053,82 +1161,11 @@ namespace dxvk {
SpirvCodeBuffer DxvkGraphicsPipeline::getShaderCode( SpirvCodeBuffer DxvkGraphicsPipeline::getShaderCode(
const Rc<DxvkShader>& shader, const Rc<DxvkShader>& shader,
const DxvkGraphicsPipelineStateInfo& state) const { const DxvkShaderModuleCreateInfo& info) const {
auto vk = m_device->vkd();
const DxvkShaderCreateInfo& shaderInfo = shader->info();
DxvkShaderModuleCreateInfo info;
// Fix up fragment shader outputs for dual-source blending
if (shaderInfo.stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
info.fsDualSrcBlend = state.useDualSourceBlending();
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (writesRenderTarget(state, i))
info.rtSwizzles[i] = state.omSwizzle[i].mapping();
}
}
// Deal with undefined shader inputs
uint32_t consumedInputs = shaderInfo.inputMask;
uint32_t providedInputs = 0;
if (shaderInfo.stage == VK_SHADER_STAGE_VERTEX_BIT) {
for (uint32_t i = 0; i < state.il.attributeCount(); i++)
providedInputs |= 1u << state.ilAttributes[i].location();
} else if (shaderInfo.stage != VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
auto prevStage = getPrevStageShader(shaderInfo.stage);
providedInputs = prevStage->info().outputMask;
} else {
// Technically not correct, but this
// would need a lot of extra care
providedInputs = consumedInputs;
}
info.undefinedInputs = (providedInputs & consumedInputs) ^ consumedInputs;
return shader->getCode(m_bindings, info); return shader->getCode(m_bindings, info);
} }
Rc<DxvkShader> DxvkGraphicsPipeline::getPrevStageShader(VkShaderStageFlagBits stage) const {
if (stage == VK_SHADER_STAGE_VERTEX_BIT)
return nullptr;
if (stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
return m_shaders.tcs;
Rc<DxvkShader> result = m_shaders.vs;
if (stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
return result;
if (m_shaders.tes != nullptr)
result = m_shaders.tes;
if (stage == VK_SHADER_STAGE_GEOMETRY_BIT)
return result;
if (m_shaders.gs != nullptr)
result = m_shaders.gs;
return result;
}
bool DxvkGraphicsPipeline::writesRenderTarget(
const DxvkGraphicsPipelineStateInfo& state,
uint32_t target) const {
if (!(m_fsOut & (1u << target)))
return false;
if (!state.omBlend[target].colorWriteMask())
return false;
VkFormat rtFormat = state.rt.getColorFormat(target);
return rtFormat != VK_FORMAT_UNDEFINED;
}
uint32_t DxvkGraphicsPipeline::computeSpecConstantMask() const { uint32_t DxvkGraphicsPipeline::computeSpecConstantMask() const {
uint32_t mask = m_shaders.vs->getSpecConstantMask(); uint32_t mask = m_shaders.vs->getSpecConstantMask();

View File

@ -19,6 +19,8 @@ namespace dxvk {
class DxvkStateCache; class DxvkStateCache;
class DxvkPipelineManager; class DxvkPipelineManager;
class DxvkPipelineWorkers; class DxvkPipelineWorkers;
struct DxvkGraphicsPipelineShaders;
struct DxvkPipelineStats; struct DxvkPipelineStats;
/** /**
@ -187,6 +189,42 @@ namespace dxvk {
}; };
/**
* \brief Shader create info state for graphics pipelines
*
* Can only be used when all pipeline state is known.
*/
struct DxvkGraphicsPipelineShaderState {
DxvkGraphicsPipelineShaderState();
DxvkGraphicsPipelineShaderState(
const DxvkGraphicsPipelineShaders& shaders,
const DxvkGraphicsPipelineStateInfo& state);
DxvkShaderModuleCreateInfo vsInfo;
DxvkShaderModuleCreateInfo tcsInfo;
DxvkShaderModuleCreateInfo tesInfo;
DxvkShaderModuleCreateInfo gsInfo;
DxvkShaderModuleCreateInfo fsInfo;
bool eq(const DxvkGraphicsPipelineShaderState& other) const;
size_t hash() const;
private:
DxvkShaderModuleCreateInfo getCreateInfo(
const DxvkGraphicsPipelineShaders& shaders,
const Rc<DxvkShader>& shader,
const DxvkGraphicsPipelineStateInfo& state);
Rc<DxvkShader> getPrevStageShader(
const DxvkGraphicsPipelineShaders& shaders,
const VkShaderStageFlagBits stage);
};
/** /**
* \brief Specialization constant state for pipelines * \brief Specialization constant state for pipelines
* *
@ -475,14 +513,7 @@ namespace dxvk {
SpirvCodeBuffer getShaderCode( SpirvCodeBuffer getShaderCode(
const Rc<DxvkShader>& shader, const Rc<DxvkShader>& shader,
const DxvkGraphicsPipelineStateInfo& state) const; const DxvkShaderModuleCreateInfo& info) const;
Rc<DxvkShader> getPrevStageShader(
VkShaderStageFlagBits stage) const;
bool writesRenderTarget(
const DxvkGraphicsPipelineStateInfo& state,
uint32_t target) const;
uint32_t computeSpecConstantMask() const; uint32_t computeSpecConstantMask() const;

View File

@ -769,6 +769,16 @@ namespace dxvk {
util::isDualSourceBlendFactor(omBlend[0].dstAlphaBlendFactor())); util::isDualSourceBlendFactor(omBlend[0].dstAlphaBlendFactor()));
} }
bool writesRenderTarget(
uint32_t target) const {
if (!omBlend[target].colorWriteMask())
return false;
VkFormat rtFormat = rt.getColorFormat(target);
return rtFormat != VK_FORMAT_UNDEFINED;
}
DxvkIaInfo ia; DxvkIaInfo ia;
DxvkIlInfo il; DxvkIlInfo il;
DxvkRsInfo rs; DxvkRsInfo rs;