diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 822c0d5f..21468988 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -5401,6 +5401,7 @@ namespace dxvk { pRsState->conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT; pRsState->sampleCount = 0; pRsState->flatShading = VK_FALSE; + pRsState->lineMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; } diff --git a/src/d3d11/d3d11_rasterizer.cpp b/src/d3d11/d3d11_rasterizer.cpp index 4a441f70..f3c31694 100644 --- a/src/d3d11/d3d11_rasterizer.cpp +++ b/src/d3d11/d3d11_rasterizer.cpp @@ -38,6 +38,7 @@ namespace dxvk { m_state.conservativeMode = DecodeConservativeRasterizationMode(desc.ConservativeRaster); m_state.sampleCount = VkSampleCountFlags(desc.ForcedSampleCount); m_state.flatShading = VK_FALSE; + m_state.lineMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; m_depthBias.depthBiasConstant = float(desc.DepthBias); m_depthBias.depthBiasSlope = desc.SlopeScaledDepthBias; diff --git a/src/dxvk/dxvk_constant_state.h b/src/dxvk/dxvk_constant_state.h index f6fea430..dec4ec94 100644 --- a/src/dxvk/dxvk_constant_state.h +++ b/src/dxvk/dxvk_constant_state.h @@ -127,6 +127,7 @@ namespace dxvk { VkConservativeRasterizationModeEXT conservativeMode; VkSampleCountFlags sampleCount; VkBool32 flatShading; + VkLineRasterizationModeEXT lineMode; }; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 0a3b7177..f2a1e862 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2540,7 +2540,8 @@ namespace dxvk { rs.polygonMode, rs.sampleCount, rs.conservativeMode, - rs.flatShading); + rs.flatShading, + rs.lineMode); if (!m_state.gp.state.rs.eq(rsInfo)) { m_flags.set(DxvkContextFlag::GpDirtyPipelineState); diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 3a768299..0f2216ea 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -459,7 +459,9 @@ namespace dxvk { DxvkGraphicsPipelinePreRasterizationState::DxvkGraphicsPipelinePreRasterizationState( const DxvkDevice* device, const DxvkGraphicsPipelineStateInfo& state, - const DxvkShader* gs) { + const DxvkShader* tes, + const DxvkShader* gs, + const DxvkShader* fs) { // Set up tessellation state tsInfo.patchControlPoints = state.ia.patchVertexCount(); @@ -495,6 +497,27 @@ namespace dxvk { rsConservativeInfo.conservativeRasterizationMode = state.rs.conservativeMode(); rsConservativeInfo.extraPrimitiveOverestimationSize = 0.0f; } + + // Set up line rasterization mode as requested by the application. + if (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering(state, tes, gs)) { + rsLineInfo.pNext = std::exchange(rsInfo.pNext, &rsLineInfo); + rsLineInfo.lineRasterizationMode = state.rs.lineMode(); + + if (rsLineInfo.lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT) { + // This line width matches expected D3D behaviour, hard-code this + // so that we don't need to introduce an extra bit of render state. + rsInfo.lineWidth = 1.4f; + } else { + // Vulkan does not allow alphaToCoverage or sample rate shading + // in combination with smooth lines. Override the line mode to + // rectangular to fix this, but keep the width fixed at 1.0. + bool needsOverride = state.ms.enableAlphaToCoverage() + || (fs && fs->flags().test(DxvkShaderFlag::HasSampleRateShading)); + + if (needsOverride) + rsLineInfo.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT; + } + } } @@ -521,6 +544,9 @@ namespace dxvk { && rsConservativeInfo.extraPrimitiveOverestimationSize == other.rsConservativeInfo.extraPrimitiveOverestimationSize; } + if (eq) + eq = rsLineInfo.lineRasterizationMode == other.rsLineInfo.lineRasterizationMode; + return eq; } @@ -541,10 +567,35 @@ namespace dxvk { hash.add(rsConservativeInfo.conservativeRasterizationMode); hash.add(bit::cast(rsConservativeInfo.extraPrimitiveOverestimationSize)); + + hash.add(rsLineInfo.lineRasterizationMode); return hash; } + bool DxvkGraphicsPipelinePreRasterizationState::isLineRendering( + const DxvkGraphicsPipelineStateInfo& state, + const DxvkShader* tes, + const DxvkShader* gs) { + bool isLineRendering = state.rs.polygonMode() == VK_POLYGON_MODE_LINE; + + if (gs) { + isLineRendering |= gs->info().outputTopology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + } else if (tes) { + isLineRendering |= tes->info().outputTopology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + } else { + VkPrimitiveTopology topology = state.ia.primitiveTopology(); + + isLineRendering |= topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST + || topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP + || topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY + || topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY; + } + + return isLineRendering; + } + + DxvkGraphicsPipelineFragmentShaderState::DxvkGraphicsPipelineFragmentShaderState() { } @@ -1078,11 +1129,13 @@ namespace dxvk { if (!m_vsLibrary || !m_fsLibrary) return false; - // Certain rasterization states cannot be set dynamically, - // so we're assuming defaults for them, most notably the - // polygon mode and conservative rasterization settings + // We do not implement setting certain rarely used render + // states dynamically since they are generally not used + bool isLineRendering = DxvkGraphicsPipelinePreRasterizationState::isLineRendering(state, m_shaders.tes.ptr(), m_shaders.gs.ptr()); + 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 + || (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering)) return false; if (m_shaders.tcs != nullptr) { diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 4c03c041..262b3901 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -168,7 +168,9 @@ namespace dxvk { DxvkGraphicsPipelinePreRasterizationState( const DxvkDevice* device, const DxvkGraphicsPipelineStateInfo& state, - const DxvkShader* gs); + const DxvkShader* tes, + const DxvkShader* gs, + const DxvkShader* fs); VkPipelineViewportStateCreateInfo vpInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; VkPipelineTessellationStateCreateInfo tsInfo = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO }; @@ -176,10 +178,17 @@ namespace dxvk { VkPipelineRasterizationDepthClipStateCreateInfoEXT rsDepthClipInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT }; VkPipelineRasterizationStateStreamCreateInfoEXT rsXfbStreamInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT }; VkPipelineRasterizationConservativeStateCreateInfoEXT rsConservativeInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT }; + VkPipelineRasterizationLineStateCreateInfoEXT rsLineInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT }; bool eq(const DxvkGraphicsPipelinePreRasterizationState& other) const; size_t hash() const; + + static bool isLineRendering( + const DxvkGraphicsPipelineStateInfo& state, + const DxvkShader* tes, + const DxvkShader* gs); + }; @@ -406,7 +415,7 @@ namespace dxvk { : shState(shaders, state), dyState(device, state, flags), viState(device, state, shaders.vs.ptr()), - prState(device, state, shaders.gs.ptr()), + prState(device, state, shaders.tes.ptr(), shaders.gs.ptr(), shaders.fs.ptr()), fsState(device, state), foState(device, state, shaders.fs.ptr()), scState(specConstantMask, state.sc) { } diff --git a/src/dxvk/dxvk_graphics_state.h b/src/dxvk/dxvk_graphics_state.h index 24c7dbb3..73f39c0c 100644 --- a/src/dxvk/dxvk_graphics_state.h +++ b/src/dxvk/dxvk_graphics_state.h @@ -223,13 +223,15 @@ namespace dxvk { VkPolygonMode polygonMode, VkSampleCountFlags sampleCount, VkConservativeRasterizationModeEXT conservativeMode, - VkBool32 flatShading) + VkBool32 flatShading, + VkLineRasterizationModeEXT lineMode) : m_depthClipEnable (uint16_t(depthClipEnable)), m_depthBiasEnable (uint16_t(depthBiasEnable)), m_polygonMode (uint16_t(polygonMode)), m_sampleCount (uint16_t(sampleCount)), m_conservativeMode(uint16_t(conservativeMode)), m_flatShading (uint16_t(flatShading)), + m_lineMode (uint16_t(lineMode)), m_reserved (0) { } VkBool32 depthClipEnable() const { @@ -256,6 +258,10 @@ namespace dxvk { return VkBool32(m_flatShading); } + VkLineRasterizationModeEXT lineMode() const { + return VkLineRasterizationModeEXT(m_lineMode); + } + bool eq(const DxvkRsInfo& other) const { return !std::memcmp(this, &other, sizeof(*this)); } @@ -268,7 +274,8 @@ namespace dxvk { uint16_t m_sampleCount : 5; uint16_t m_conservativeMode : 2; uint16_t m_flatShading : 1; - uint16_t m_reserved : 4; + uint16_t m_lineMode : 2; + uint16_t m_reserved : 2; }; diff --git a/src/dxvk/dxvk_shader.h b/src/dxvk/dxvk_shader.h index ead2d345..bb962a2b 100644 --- a/src/dxvk/dxvk_shader.h +++ b/src/dxvk/dxvk_shader.h @@ -62,6 +62,8 @@ namespace dxvk { uint32_t patchVertexCount = 0; /// Transform feedback vertex strides uint32_t xfbStrides[MaxNumXfbBuffers] = { }; + /// Output primitive topology + VkPrimitiveTopology outputTopology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; }; diff --git a/src/dxvk/dxvk_state_cache_types.h b/src/dxvk/dxvk_state_cache_types.h index e5882593..e7c386bd 100644 --- a/src/dxvk/dxvk_state_cache_types.h +++ b/src/dxvk/dxvk_state_cache_types.h @@ -142,7 +142,7 @@ namespace dxvk { VkPolygonMode(m_polygonMode), VkSampleCountFlags(m_sampleCount), VkConservativeRasterizationModeEXT(m_conservativeMode), - VK_FALSE); + VK_FALSE, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT); } }; @@ -168,7 +168,7 @@ namespace dxvk { VkPolygonMode(m_polygonMode), VkSampleCountFlags(m_sampleCount), VkConservativeRasterizationModeEXT(m_conservativeMode), - VK_FALSE); + VK_FALSE, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT); } }; diff --git a/src/dxvk/dxvk_swapchain_blitter.cpp b/src/dxvk/dxvk_swapchain_blitter.cpp index f71bd732..c19188cb 100644 --- a/src/dxvk/dxvk_swapchain_blitter.cpp +++ b/src/dxvk/dxvk_swapchain_blitter.cpp @@ -125,6 +125,7 @@ namespace dxvk { rsState.conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT; rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT; rsState.flatShading = VK_FALSE; + rsState.lineMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; ctx->setRasterizerState(rsState); DxvkMultisampleState msState; diff --git a/src/dxvk/hud/dxvk_hud.cpp b/src/dxvk/hud/dxvk_hud.cpp index 2fc34655..88efa405 100644 --- a/src/dxvk/hud/dxvk_hud.cpp +++ b/src/dxvk/hud/dxvk_hud.cpp @@ -28,6 +28,7 @@ namespace dxvk::hud { m_rsState.conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT; m_rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT; m_rsState.flatShading = VK_FALSE; + m_rsState.lineMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; m_blendMode.enableBlending = VK_TRUE; m_blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;