[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() {
}
@ -888,7 +994,8 @@ namespace dxvk {
// Remapping fragment shader outputs would require spec constants
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;
}
@ -978,6 +1085,7 @@ namespace dxvk {
}
// Set up pipeline state
DxvkGraphicsPipelineShaderState shState(m_shaders, state);
DxvkGraphicsPipelineVertexInputState viState(m_device, state, m_shaders.vs.ptr());
DxvkGraphicsPipelinePreRasterizationState prState(m_device, state, m_shaders.gs.ptr());
DxvkGraphicsPipelineFragmentShaderState fsState(m_device, state);
@ -993,16 +1101,16 @@ namespace dxvk {
if (m_shaders.fs != nullptr)
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, m_fsLibrary->getModuleIdentifier(), &scState.scInfo);
} 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)
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)
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)
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)
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 };
@ -1053,82 +1161,11 @@ namespace dxvk {
SpirvCodeBuffer DxvkGraphicsPipeline::getShaderCode(
const Rc<DxvkShader>& shader,
const DxvkGraphicsPipelineStateInfo& state) 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;
const DxvkShaderModuleCreateInfo& info) const {
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 mask = m_shaders.vs->getSpecConstantMask();

View File

@ -19,6 +19,8 @@ namespace dxvk {
class DxvkStateCache;
class DxvkPipelineManager;
class DxvkPipelineWorkers;
struct DxvkGraphicsPipelineShaders;
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
*
@ -475,15 +513,8 @@ namespace dxvk {
SpirvCodeBuffer getShaderCode(
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;
bool validatePipelineState(

View File

@ -769,6 +769,16 @@ namespace dxvk {
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;
DxvkIlInfo il;
DxvkRsInfo rs;