Compare commits

...

5 Commits

Author SHA1 Message Date
CamilleLaVey 630ec82441 fix build 2026-02-15 22:23:46 -04:00
CamilleLaVey 1a2dadcb2e [vulkan] Unique representation logic fix. 2026-02-15 22:15:58 -04:00
CamilleLaVey 57aab352b4 [vulkan] Rework line rasterization handle 2026-02-15 20:32:00 -04:00
CamilleLaVey 7fdbc33aaf [vulkan] Extending conversative rasterization detection and handling 2026-02-15 19:37:02 -04:00
CamilleLaVey 6408867c6c [vulkan] Fix conditional rendering enable 2026-02-15 17:58:16 -04:00
9 changed files with 223 additions and 26 deletions

View File

@ -711,20 +711,62 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.depthBiasClamp = 0.0f,
.depthBiasSlopeFactor = 0.0f,
.lineWidth = 1.0f,
// TODO(alekpop): Transfer from regs
};
const bool smooth_lines_supported =
device.IsExtLineRasterizationSupported() && device.SupportsSmoothLines();
const bool stippled_lines_supported =
device.IsExtLineRasterizationSupported() && device.SupportsStippledRectangularLines();
const bool line_rasterization_supported = device.IsExtLineRasterizationSupported();
const bool any_stippled_lines_supported =
line_rasterization_supported &&
(device.SupportsStippledRectangularLines() || device.SupportsStippledBresenhamLines() ||
device.SupportsStippledSmoothLines());
const bool line_stipple_dynamic_state_supported =
IsLine(input_assembly_topology) && any_stippled_lines_supported;
const bool supports_rectangular_lines =
line_rasterization_supported && device.SupportsRectangularLines();
const bool supports_bresenham_lines =
line_rasterization_supported && device.SupportsBresenhamLines();
const bool supports_smooth_lines = line_rasterization_supported && device.SupportsSmoothLines();
VkLineRasterizationModeEXT line_rasterization_mode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
if (line_rasterization_supported) {
if (key.state.smooth_lines != 0) {
if (supports_smooth_lines) {
line_rasterization_mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
} else if (supports_rectangular_lines) {
line_rasterization_mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
} else if (supports_bresenham_lines) {
line_rasterization_mode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
}
} else {
if (supports_rectangular_lines) {
line_rasterization_mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
} else if (supports_bresenham_lines) {
line_rasterization_mode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
} else if (supports_smooth_lines) {
line_rasterization_mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
}
}
}
const bool stippled_lines_supported = [&]() {
if (!line_rasterization_supported || !dynamic.line_stipple_enable) {
return false;
}
switch (line_rasterization_mode) {
case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT:
return device.SupportsStippledRectangularLines();
case VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT:
return device.SupportsStippledBresenhamLines();
case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT:
return device.SupportsStippledSmoothLines();
default:
return false;
}
}();
VkPipelineRasterizationLineStateCreateInfoEXT line_state{
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT,
.pNext = nullptr,
.lineRasterizationMode = key.state.smooth_lines != 0 && smooth_lines_supported
? VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT
: VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT,
.stippledLineEnable =
(dynamic.line_stipple_enable && stippled_lines_supported) ? VK_TRUE : VK_FALSE,
.lineRasterizationMode = line_rasterization_mode,
.stippledLineEnable = stippled_lines_supported ? VK_TRUE : VK_FALSE,
.lineStippleFactor = key.state.line_stipple_factor,
.lineStipplePattern = static_cast<uint16_t>(key.state.line_stipple_pattern),
};
@ -732,11 +774,21 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT,
.pNext = nullptr,
.flags = 0,
.conservativeRasterizationMode = key.state.conservative_raster_enable != 0
? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT
: VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT,
.conservativeRasterizationMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT,
.extraPrimitiveOverestimationSize = 0.0f,
};
const bool conservative_requested = key.state.conservative_raster_enable != 0;
if (conservative_requested) {
const bool is_point_topology = input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
const bool is_line_topology = IsLine(input_assembly_topology);
const bool needs_point_or_line_support = is_point_topology || is_line_topology;
const bool supports_requested_topology =
!needs_point_or_line_support || device.SupportsConservativePointAndLineRasterization();
conservative_raster.conservativeRasterizationMode =
supports_requested_topology ? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT
: VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
}
const bool preserve_provoking_vertex_for_xfb =
!key.state.xfb_enabled || device.IsTransformFeedbackProvokingVertexPreserved();
const bool use_last_provoking_vertex =
@ -830,12 +882,15 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.pAttachments = cb_attachments.data(),
.blendConstants = {}
};
static_vector<VkDynamicState, 34> dynamic_states{
static_vector<VkDynamicState, 35> dynamic_states{
VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE,
VK_DYNAMIC_STATE_LINE_WIDTH,
};
if (line_stipple_dynamic_state_supported) {
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_STIPPLE_EXT);
}
if (key.state.extended_dynamic_state) {
static constexpr std::array extended{
VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT,

View File

@ -1212,13 +1212,18 @@ struct QueryCacheRuntimeImpl {
conditional_resolve_pass = std::make_unique<ConditionalRenderingResolvePass>(
device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
VkBufferUsageFlags conditional_usage =
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
if (device.IsExtConditionalRendering()) {
conditional_usage |= VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT;
}
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = sizeof(u32),
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT,
.usage = conditional_usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,

View File

@ -173,6 +173,55 @@ DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances,
}
return params;
}
bool IsLineRasterizationTopology(const Device& device, Maxwell::PrimitiveTopology topology) {
const VkPrimitiveTopology vk_topology = MaxwellToVK::PrimitiveTopology(device, topology);
return vk_topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST ||
vk_topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
}
VkLineRasterizationModeEXT SelectLineRasterizationMode(const Device& device, bool smooth_lines) {
const bool supports_rectangular_lines = device.SupportsRectangularLines();
const bool supports_bresenham_lines = device.SupportsBresenhamLines();
const bool supports_smooth_lines = device.SupportsSmoothLines();
if (smooth_lines) {
if (supports_smooth_lines) {
return VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
}
if (supports_rectangular_lines) {
return VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
}
if (supports_bresenham_lines) {
return VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
}
} else {
if (supports_rectangular_lines) {
return VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
}
if (supports_bresenham_lines) {
return VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
}
if (supports_smooth_lines) {
return VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
}
}
return VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
}
bool SupportsStippleForMode(const Device& device, VkLineRasterizationModeEXT mode) {
switch (mode) {
case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT:
return device.SupportsStippledRectangularLines();
case VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT:
return device.SupportsStippledBresenhamLines();
case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT:
return device.SupportsStippledSmoothLines();
default:
return false;
}
}
} // Anonymous namespace
RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@ -1026,6 +1075,7 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateDepthBounds(regs);
UpdateStencilFaces(regs);
UpdateLineWidth(regs);
UpdateLineStipple(regs);
// EDS1: CullMode, DepthCompare, FrontFace, StencilOp, DepthBoundsTest, DepthTest, DepthWrite, StencilTest
if (device.IsExtExtendedDynamicStateSupported()) {
@ -1370,6 +1420,33 @@ void RasterizerVulkan::UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs) {
scheduler.Record([width](vk::CommandBuffer cmdbuf) { cmdbuf.SetLineWidth(width); });
}
void RasterizerVulkan::UpdateLineStipple(Tegra::Engines::Maxwell3D::Regs& regs) {
if (!state_tracker.TouchLineStipple()) {
return;
}
if (!device.IsExtLineRasterizationSupported()) {
return;
}
const auto topology = maxwell3d->draw_manager->GetDrawState().topology;
if (!IsLineRasterizationTopology(device, topology)) {
return;
}
const VkLineRasterizationModeEXT mode =
SelectLineRasterizationMode(device, regs.line_anti_alias_enable != 0);
if (regs.line_stipple_enable == 0 || !SupportsStippleForMode(device, mode)) {
return;
}
scheduler.Record(
[factor = regs.line_stipple_params.factor,
pattern = static_cast<u16>(regs.line_stipple_params.pattern)](vk::CommandBuffer cmdbuf) {
cmdbuf.SetLineStippleEXT(factor, pattern);
});
}
void RasterizerVulkan::UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs) {
if (!state_tracker.TouchCullMode()) {
return;

View File

@ -168,6 +168,7 @@ private:
void UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateLineStipple(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);

View File

@ -40,6 +40,7 @@ Flags MakeInvalidationFlags() {
StencilWriteMask,
StencilCompare,
LineWidth,
LineStipple,
CullMode,
DepthBoundsEnable,
DepthTestEnable,
@ -119,6 +120,13 @@ void SetupDirtyStencilProperties(Tables& tables) {
void SetupDirtyLineWidth(Tables& tables) {
tables[0][OFF(line_width_smooth)] = LineWidth;
tables[0][OFF(line_width_aliased)] = LineWidth;
tables[0][OFF(line_anti_alias_enable)] = LineWidth;
}
void SetupDirtyLineStipple(Tables& tables) {
tables[0][OFF(line_stipple_enable)] = LineStipple;
FillBlock(tables[0], OFF(line_stipple_params), NUM(line_stipple_params), LineStipple);
tables[1][OFF(line_anti_alias_enable)] = LineStipple;
}
void SetupDirtyCullMode(Tables& tables) {
@ -226,6 +234,7 @@ void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
SetupDirtyDepthBounds(tables);
SetupDirtyStencilProperties(tables);
SetupDirtyLineWidth(tables);
SetupDirtyLineStipple(tables);
SetupDirtyCullMode(tables);
SetupDirtyStateEnable(tables);
SetupDirtyDepthCompareOp(tables);

View File

@ -42,6 +42,7 @@ enum : u8 {
StencilWriteMask,
StencilCompare,
LineWidth,
LineStipple,
CullMode,
DepthBoundsEnable,
@ -177,6 +178,10 @@ public:
return Exchange(Dirty::LineWidth, false);
}
bool TouchLineStipple() const {
return Exchange(Dirty::LineStipple, false);
}
bool TouchCullMode() {
return Exchange(Dirty::CullMode, false);
}

View File

@ -1068,6 +1068,11 @@ bool Device::GetSuitability(bool requires_swapchain) {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR;
SetNext(next, properties.push_descriptor);
}
if (extensions.conservative_rasterization) {
properties.conservative_rasterization.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT;
SetNext(next, properties.conservative_rasterization);
}
if (extensions.subgroup_size_control || features.subgroup_size_control.subgroupSizeControl) {
properties.subgroup_size_control.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;
@ -1224,6 +1229,20 @@ void Device::RemoveUnsuitableExtensions() {
features.provoking_vertex,
VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
// VK_EXT_line_rasterization
extensions.line_rasterization = features.line_rasterization.rectangularLines ||
features.line_rasterization.bresenhamLines ||
features.line_rasterization.smoothLines;
RemoveExtensionFeatureIfUnsuitable(extensions.line_rasterization,
features.line_rasterization,
VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
// VK_EXT_conditional_rendering
extensions.conditional_rendering = features.conditional_rendering.conditionalRendering;
RemoveExtensionFeatureIfUnsuitable(extensions.conditional_rendering,
features.conditional_rendering,
VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME);
// VK_EXT_multi_draw
extensions.multi_draw = features.multi_draw.multiDraw;

View File

@ -48,6 +48,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
// Define all features which may be used by the implementation and require an extension here.
#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \
FEATURE(EXT, ConditionalRendering, CONDITIONAL_RENDERING, conditional_rendering) \
FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \
FEATURE(EXT, DepthBiasControl, DEPTH_BIAS_CONTROL, depth_bias_control) \
FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
@ -73,7 +74,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
// Define miscellaneous extensions which may be used by the implementation here.
#define FOR_EACH_VK_EXTENSION(EXTENSION) \
EXTENSION(EXT, CONDITIONAL_RENDERING, conditional_rendering) \
EXTENSION(EXT, CONSERVATIVE_RASTERIZATION, conservative_rasterization) \
EXTENSION(EXT, DEPTH_RANGE_UNRESTRICTED, depth_range_unrestricted) \
EXTENSION(EXT, MEMORY_BUDGET, memory_budget) \
@ -436,7 +436,7 @@ public:
return extensions.viewport_array2;
}
/// Returns true if the device supporst VK_EXT_DESCRIPTOR_INDEXING
/// Returns true if the device supporst VK_EXT_descriptor_indexing.
bool isExtDescriptorIndexingSupported() const {
return extensions.descriptor_indexing;
}
@ -616,12 +616,12 @@ public:
return features.format_a4b4g4r4.formatA4B4G4R4;
}
/// Returns true if the device supports VK_EXT_filter_cubic
/// Returns true if the device supports VK_EXT_filter_cubic.
bool IsExtFilterCubicSupported() const {
return extensions.filter_cubic;
}
/// Returns true if the device supports VK_QCOM_filter_cubic_weights
/// Returns true if the device supports VK_QCOM_filter_cubic_weights.
bool IsQcomFilterCubicWeightsSupported() const {
return extensions.filter_cubic_weights;
}
@ -632,23 +632,36 @@ public:
}
bool SupportsRectangularLines() const {
return features.line_rasterization.rectangularLines != VK_FALSE;
return features.line_rasterization.rectangularLines;
}
bool SupportsBresenhamLines() const {
return features.line_rasterization.bresenhamLines;
}
bool SupportsSmoothLines() const {
return features.line_rasterization.smoothLines != VK_FALSE;
return features.line_rasterization.smoothLines;
}
bool SupportsStippledRectangularLines() const {
return features.line_rasterization.stippledRectangularLines != VK_FALSE;
return features.line_rasterization.stippledRectangularLines;
}
bool SupportsStippledBresenhamLines() const {
return features.line_rasterization.stippledBresenhamLines;
}
bool SupportsStippledSmoothLines() const {
return features.line_rasterization.stippledSmoothLines;
}
/// Returns true if the device supports AlphaToOne.
bool SupportsAlphaToOne() const {
return features.features.alphaToOne != VK_FALSE;
return features.features.alphaToOne;
}
/// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation
/// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation.
bool IsExtShaderDemoteToHelperInvocationSupported() const {
return extensions.shader_demote_to_helper_invocation;
}
@ -657,6 +670,12 @@ public:
bool IsExtConservativeRasterizationSupported() const {
return extensions.conservative_rasterization;
}
/// Returns true if the device supports conservative rasterization for points and lines.
bool SupportsConservativePointAndLineRasterization() const {
return extensions.conservative_rasterization &&
properties.conservative_rasterization.conservativePointAndLineRasterization;
}
/// Returns true if the device supports VK_EXT_provoking_vertex.
bool IsExtProvokingVertexSupported() const {
@ -668,10 +687,15 @@ public:
return extensions.shader_atomic_int64;
}
bool IsExtConditionalRendering() const {
/// Returns true if the device supports VK_EXT_conditional_rendering.
bool IsExtConditionalRenderingSupported() const {
return extensions.conditional_rendering;
}
bool IsExtConditionalRendering() const {
return IsExtConditionalRenderingSupported();
}
bool HasTimelineSemaphore() const;
/// Returns the minimum supported version of SPIR-V.
@ -966,6 +990,7 @@ private:
VkPhysicalDeviceSubgroupProperties subgroup_properties{};
VkPhysicalDeviceFloatControlsProperties float_controls{};
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservative_rasterization{};
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};

View File

@ -152,6 +152,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkCmdSetFrontFaceEXT);
X(vkCmdSetLogicOpEXT);
X(vkCmdSetPatchControlPointsEXT);
X(vkCmdSetLineStippleEXT);
X(vkCmdSetLineWidth);
X(vkCmdSetPrimitiveTopologyEXT);
X(vkCmdSetStencilOpEXT);