1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-04-01 09:25:24 +02:00

[dxvk] Consider point-mode tessellation for GS topology

This commit is contained in:
Philip Rebohle 2025-03-14 23:59:12 +01:00
parent aa637d6286
commit 0dec617c4e
2 changed files with 42 additions and 35 deletions

View File

@ -44,6 +44,19 @@ namespace dxvk {
} }
VkPrimitiveTopology determinePreGsTopology(
const DxvkGraphicsPipelineShaders& shaders,
const DxvkGraphicsPipelineStateInfo& state) {
if (shaders.tcs && shaders.tcs->flags().test(DxvkShaderFlag::TessellationPoints))
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
if (shaders.tes)
return shaders.tes->info().outputTopology;
return state.ia.primitiveTopology();
}
DxvkGraphicsPipelineVertexInputState::DxvkGraphicsPipelineVertexInputState() { DxvkGraphicsPipelineVertexInputState::DxvkGraphicsPipelineVertexInputState() {
} }
@ -52,13 +65,13 @@ namespace dxvk {
DxvkGraphicsPipelineVertexInputState::DxvkGraphicsPipelineVertexInputState( DxvkGraphicsPipelineVertexInputState::DxvkGraphicsPipelineVertexInputState(
const DxvkDevice* device, const DxvkDevice* device,
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkShader* vs) { const DxvkGraphicsPipelineShaders& shaders) {
std::array<uint32_t, MaxNumVertexBindings> viBindingMap = { }; std::array<uint32_t, MaxNumVertexBindings> viBindingMap = { };
iaInfo.topology = state.ia.primitiveTopology(); iaInfo.topology = state.ia.primitiveTopology();
iaInfo.primitiveRestartEnable = state.ia.primitiveRestart(); iaInfo.primitiveRestartEnable = state.ia.primitiveRestart();
uint32_t attrMask = vs->info().inputMask; uint32_t attrMask = shaders.vs->info().inputMask;
uint32_t bindingMask = 0; uint32_t bindingMask = 0;
// Find out which bindings are used based on the attribute mask // Find out which bindings are used based on the attribute mask
@ -244,10 +257,10 @@ namespace dxvk {
DxvkGraphicsPipelineFragmentOutputState::DxvkGraphicsPipelineFragmentOutputState( DxvkGraphicsPipelineFragmentOutputState::DxvkGraphicsPipelineFragmentOutputState(
const DxvkDevice* device, const DxvkDevice* device,
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkShader* fs) { const DxvkGraphicsPipelineShaders& shaders) {
// Set up color formats and attachment blend states. Disable the write // Set up color formats and attachment blend states. Disable the write
// mask for any attachment that the fragment shader does not write to. // mask for any attachment that the fragment shader does not write to.
uint32_t fsOutputMask = fs ? fs->info().outputMask : 0u; uint32_t fsOutputMask = shaders.fs ? shaders.fs->info().outputMask : 0u;
// Dual-source blending can only write to one render target // Dual-source blending can only write to one render target
if (state.useDualSourceBlending()) if (state.useDualSourceBlending())
@ -331,13 +344,13 @@ namespace dxvk {
: VK_SAMPLE_COUNT_1_BIT; : VK_SAMPLE_COUNT_1_BIT;
} }
if (fs && fs->flags().test(DxvkShaderFlag::HasSampleRateShading)) { if (shaders.fs && shaders.fs->flags().test(DxvkShaderFlag::HasSampleRateShading)) {
msInfo.sampleShadingEnable = VK_TRUE; msInfo.sampleShadingEnable = VK_TRUE;
msInfo.minSampleShading = 1.0f; msInfo.minSampleShading = 1.0f;
} }
// Alpha to coverage is not supported with sample mask exports. // Alpha to coverage is not supported with sample mask exports.
cbUseDynamicAlphaToCoverage = !fs || !fs->flags().test(DxvkShaderFlag::ExportsSampleMask); cbUseDynamicAlphaToCoverage = !shaders.fs || !shaders.fs->flags().test(DxvkShaderFlag::ExportsSampleMask);
msSampleMask = state.ms.sampleMask() & ((1u << msInfo.rasterizationSamples) - 1); msSampleMask = state.ms.sampleMask() & ((1u << msInfo.rasterizationSamples) - 1);
msInfo.pSampleMask = &msSampleMask; msInfo.pSampleMask = &msSampleMask;
@ -518,9 +531,7 @@ namespace dxvk {
DxvkGraphicsPipelinePreRasterizationState::DxvkGraphicsPipelinePreRasterizationState( DxvkGraphicsPipelinePreRasterizationState::DxvkGraphicsPipelinePreRasterizationState(
const DxvkDevice* device, const DxvkDevice* device,
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkShader* tes, const DxvkGraphicsPipelineShaders& shaders) {
const DxvkShader* gs,
const DxvkShader* fs) {
// Set up tessellation state // Set up tessellation state
tsInfo.patchControlPoints = state.ia.patchVertexCount(); tsInfo.patchControlPoints = state.ia.patchVertexCount();
@ -532,7 +543,7 @@ namespace dxvk {
// Set up rasterized stream depending on geometry shader state. // Set up rasterized stream depending on geometry shader state.
// Rasterizing stream 0 is default behaviour in all situations. // Rasterizing stream 0 is default behaviour in all situations.
int32_t streamIndex = gs ? gs->info().xfbRasterizedStream : 0; int32_t streamIndex = shaders.gs ? shaders.gs->info().xfbRasterizedStream : 0;
if (streamIndex > 0) { if (streamIndex > 0) {
rsXfbStreamInfo.pNext = std::exchange(rsInfo.pNext, &rsXfbStreamInfo); rsXfbStreamInfo.pNext = std::exchange(rsInfo.pNext, &rsXfbStreamInfo);
@ -558,7 +569,7 @@ namespace dxvk {
} }
// Set up line rasterization mode as requested by the application. // Set up line rasterization mode as requested by the application.
if (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering(state, tes, gs)) { if (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering(shaders, state)) {
rsLineInfo.pNext = std::exchange(rsInfo.pNext, &rsLineInfo); rsLineInfo.pNext = std::exchange(rsInfo.pNext, &rsLineInfo);
rsLineInfo.lineRasterizationMode = state.rs.lineMode(); rsLineInfo.lineRasterizationMode = state.rs.lineMode();
@ -571,7 +582,7 @@ namespace dxvk {
// in combination with smooth lines. Override the line mode to // in combination with smooth lines. Override the line mode to
// rectangular to fix this, but keep the width fixed at 1.0. // rectangular to fix this, but keep the width fixed at 1.0.
bool needsOverride = state.ms.enableAlphaToCoverage() bool needsOverride = state.ms.enableAlphaToCoverage()
|| (fs && fs->flags().test(DxvkShaderFlag::HasSampleRateShading)); || (shaders.fs && shaders.fs->flags().test(DxvkShaderFlag::HasSampleRateShading));
if (needsOverride) if (needsOverride)
rsLineInfo.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT; rsLineInfo.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
@ -633,15 +644,14 @@ namespace dxvk {
bool DxvkGraphicsPipelinePreRasterizationState::isLineRendering( bool DxvkGraphicsPipelinePreRasterizationState::isLineRendering(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineShaders& shaders,
const DxvkShader* tes, const DxvkGraphicsPipelineStateInfo& state) {
const DxvkShader* gs) {
bool isLineRendering = state.rs.polygonMode() == VK_POLYGON_MODE_LINE; bool isLineRendering = state.rs.polygonMode() == VK_POLYGON_MODE_LINE;
if (gs) { if (shaders.gs) {
isLineRendering |= gs->info().outputTopology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST; isLineRendering |= shaders.gs->info().outputTopology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
} else if (tes) { } else if (shaders.tes) {
isLineRendering |= tes->info().outputTopology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST; isLineRendering |= shaders.tes->info().outputTopology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
} else { } else {
VkPrimitiveTopology topology = state.ia.primitiveTopology(); VkPrimitiveTopology topology = state.ia.primitiveTopology();
@ -874,7 +884,7 @@ namespace dxvk {
// Fix up input topology for geometry shaders as necessary // Fix up input topology for geometry shaders as necessary
if (shaderInfo.stage == VK_SHADER_STAGE_GEOMETRY_BIT) { if (shaderInfo.stage == VK_SHADER_STAGE_GEOMETRY_BIT) {
VkPrimitiveTopology iaTopology = shaders.tes ? shaders.tes->info().outputTopology : state.ia.primitiveTopology(); VkPrimitiveTopology iaTopology = determinePreGsTopology(shaders, state);
info.inputTopology = determineGsInputTopology(shaderInfo.inputTopology, iaTopology); info.inputTopology = determineGsInputTopology(shaderInfo.inputTopology, iaTopology);
} }
@ -1207,7 +1217,7 @@ namespace dxvk {
// We do not implement setting certain rarely used render // We do not implement setting certain rarely used render
// states dynamically since they are generally not used // states dynamically since they are generally not used
bool isLineRendering = DxvkGraphicsPipelinePreRasterizationState::isLineRendering(state, m_shaders.tes.ptr(), m_shaders.gs.ptr()); bool isLineRendering = DxvkGraphicsPipelinePreRasterizationState::isLineRendering(m_shaders, state);
if (state.rs.polygonMode() != VK_POLYGON_MODE_FILL if (state.rs.polygonMode() != VK_POLYGON_MODE_FILL
|| state.rs.conservativeMode() != VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT || state.rs.conservativeMode() != VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT
@ -1235,7 +1245,7 @@ namespace dxvk {
if (m_shaders.gs != nullptr) { if (m_shaders.gs != nullptr) {
// If the geometry shader's input topology is not compatible with // If the geometry shader's input topology is not compatible with
// the topology set to the pipeline, we need to patch the GS. // the topology set to the pipeline, we need to patch the GS.
VkPrimitiveTopology iaTopology = m_shaders.tes ? m_shaders.tes->info().outputTopology : state.ia.primitiveTopology(); VkPrimitiveTopology iaTopology = determinePreGsTopology(m_shaders, state);
VkPrimitiveTopology gsTopology = m_shaders.gs->info().inputTopology; VkPrimitiveTopology gsTopology = m_shaders.gs->info().inputTopology;
if (determineGsInputTopology(gsTopology, iaTopology) != gsTopology) if (determineGsInputTopology(gsTopology, iaTopology) != gsTopology)
@ -1306,8 +1316,8 @@ namespace dxvk {
VkPipeline DxvkGraphicsPipeline::getBasePipeline( VkPipeline DxvkGraphicsPipeline::getBasePipeline(
const DxvkGraphicsPipelineStateInfo& state) { const DxvkGraphicsPipelineStateInfo& state) {
DxvkGraphicsPipelineVertexInputState viState(m_device, state, m_shaders.vs.ptr()); DxvkGraphicsPipelineVertexInputState viState(m_device, state, m_shaders);
DxvkGraphicsPipelineFragmentOutputState foState(m_device, state, m_shaders.fs.ptr()); DxvkGraphicsPipelineFragmentOutputState foState(m_device, state, m_shaders);
DxvkGraphicsPipelineBaseInstanceKey key; DxvkGraphicsPipelineBaseInstanceKey key;
key.viLibrary = m_manager->createVertexInputLibrary(viState); key.viLibrary = m_manager->createVertexInputLibrary(viState);

View File

@ -50,7 +50,7 @@ namespace dxvk {
DxvkGraphicsPipelineVertexInputState( DxvkGraphicsPipelineVertexInputState(
const DxvkDevice* device, const DxvkDevice* device,
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkShader* vs); const DxvkGraphicsPipelineShaders& shaders);
VkPipelineInputAssemblyStateCreateInfo iaInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; VkPipelineInputAssemblyStateCreateInfo iaInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
VkPipelineVertexInputStateCreateInfo viInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; VkPipelineVertexInputStateCreateInfo viInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
@ -109,7 +109,7 @@ namespace dxvk {
DxvkGraphicsPipelineFragmentOutputState( DxvkGraphicsPipelineFragmentOutputState(
const DxvkDevice* device, const DxvkDevice* device,
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkShader* fs); const DxvkGraphicsPipelineShaders& shaders);
VkPipelineRenderingCreateInfo rtInfo = { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO }; VkPipelineRenderingCreateInfo rtInfo = { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO };
VkPipelineColorBlendStateCreateInfo cbInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; VkPipelineColorBlendStateCreateInfo cbInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
@ -170,9 +170,7 @@ namespace dxvk {
DxvkGraphicsPipelinePreRasterizationState( DxvkGraphicsPipelinePreRasterizationState(
const DxvkDevice* device, const DxvkDevice* device,
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkShader* tes, const DxvkGraphicsPipelineShaders& shaders);
const DxvkShader* gs,
const DxvkShader* fs);
VkPipelineViewportStateCreateInfo vpInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; VkPipelineViewportStateCreateInfo vpInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
VkPipelineTessellationStateCreateInfo tsInfo = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO }; VkPipelineTessellationStateCreateInfo tsInfo = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO };
@ -187,9 +185,8 @@ namespace dxvk {
size_t hash() const; size_t hash() const;
static bool isLineRendering( static bool isLineRendering(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineShaders& shaders,
const DxvkShader* tes, const DxvkGraphicsPipelineStateInfo& state);
const DxvkShader* gs);
}; };
@ -413,10 +410,10 @@ namespace dxvk {
uint32_t specConstantMask) uint32_t specConstantMask)
: shState(shaders, state), : shState(shaders, state),
dyState(device, state, flags), dyState(device, state, flags),
viState(device, state, shaders.vs.ptr()), viState(device, state, shaders),
prState(device, state, shaders.tes.ptr(), shaders.gs.ptr(), shaders.fs.ptr()), prState(device, state, shaders),
fsState(device, state), fsState(device, state),
foState(device, state, shaders.fs.ptr()), foState(device, state, shaders),
scState(specConstantMask, state.sc) { } scState(specConstantMask, state.sc) { }
DxvkGraphicsPipelineShaderState shState; DxvkGraphicsPipelineShaderState shState;