diff --git a/hw/xbox/nv2a/pgraph/vk/draw.c b/hw/xbox/nv2a/pgraph/vk/draw.c index 0e5d2aff7d..8dabf9325b 100644 --- a/hw/xbox/nv2a/pgraph/vk/draw.c +++ b/hw/xbox/nv2a/pgraph/vk/draw.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/fast-hash.h" #include "renderer.h" +#include void pgraph_vk_draw_begin(NV2AState *d) { @@ -810,21 +811,13 @@ static void create_pipeline(PGRAPHState *pg) // FIXME: Handle in shader? } - float lineWidth = 1.0f; - if(r->physical_device_features.wideLines == VK_TRUE) - { - lineWidth = MIN(r->device_props.limits.lineWidthRange[1], - MAX(r->device_props.limits.lineWidthRange[0], - (float)pg->surface_scale_factor)); - } - VkPipelineRasterizationStateCreateInfo rasterizer = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .depthClampEnable = VK_TRUE, .rasterizerDiscardEnable = VK_FALSE, .polygonMode = pgraph_polygon_mode_vk_map[r->shader_binding->state .polygon_front_mode], - .lineWidth = lineWidth, + .lineWidth = 1.0f, .frontFace = (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) & NV_PGRAPH_SETUPRASTER_FRONTFACE) ? VK_FRONT_FACE_COUNTER_CLOCKWISE : @@ -953,12 +946,23 @@ static void create_pipeline(PGRAPHState *pg) .blendConstants[3] = blend_constant[3], }; - VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, + VkDynamicState dynamic_states[3] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + int num_dynamic_states = 2; + + snode->has_dynamic_line_width = + (r->physical_device_features.wideLines == VK_TRUE) + && (r->shader_binding->state.polygon_front_mode == POLY_MODE_LINE || + r->shader_binding->state.primitive_mode == PRIM_TYPE_LINES || + r->shader_binding->state.primitive_mode == PRIM_TYPE_LINE_LOOP || + r->shader_binding->state.primitive_mode == PRIM_TYPE_LINE_STRIP); + if (snode->has_dynamic_line_width) { + dynamic_states[num_dynamic_states++] = VK_DYNAMIC_STATE_LINE_WIDTH; + } VkPipelineDynamicStateCreateInfo dynamic_state = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .dynamicStateCount = ARRAY_SIZE(dynamic_states), + .dynamicStateCount = num_dynamic_states, .pDynamicStates = dynamic_states, }; @@ -1428,6 +1432,21 @@ static void begin_pre_draw(PGRAPHState *pg) pgraph_vk_ensure_command_buffer(pg); } +static float clamp_line_width_to_device_limits(PGRAPHState *pg, float width) +{ + PGRAPHVkState *r = pg->vk_renderer_state; + + float min_width = r->device_props.limits.lineWidthRange[0]; + float max_width = r->device_props.limits.lineWidthRange[1]; + float granularity = r->device_props.limits.lineWidthGranularity; + + if (granularity != 0.0f) { + float steps = roundf((width - min_width) / granularity); + width = min_width + steps * granularity; + } + return fminf(fmaxf(min_width, width), max_width); +} + static void begin_draw(PGRAPHState *pg) { PGRAPHVkState *r = pg->vk_renderer_state; @@ -1499,6 +1518,12 @@ static void begin_draw(PGRAPHState *pg) .extent.height = scissor_height, }; vkCmdSetScissor(r->command_buffer, 0, 1, &scissor); + + if (r->pipeline_binding->has_dynamic_line_width) { + float line_width = + clamp_line_width_to_device_limits(pg, pg->surface_scale_factor); + vkCmdSetLineWidth(r->command_buffer, line_width); + } } if (!pg->clearing) { diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index 354275da31..1009fe589c 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -77,6 +77,7 @@ typedef struct PipelineBinding { VkPipeline pipeline; VkRenderPass render_pass; unsigned int draw_time; + bool has_dynamic_line_width; } PipelineBinding; enum Buffer {