From 4d36c637dd492393ff83eb54897b316b2316ced2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Ondra=C4=8Dka?= Date: Mon, 20 Oct 2025 14:56:04 +0200 Subject: [PATCH] r300: program explicit scissor around viewport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pavel Ondračka Reviewed-by: Marek Olšák Part-of: --- src/gallium/drivers/r300/r300_context.c | 3 +++ src/gallium/drivers/r300/r300_context.h | 2 ++ src/gallium/drivers/r300/r300_emit.c | 24 ++++++++++++------- src/gallium/drivers/r300/r300_render.c | 8 ++++++- src/gallium/drivers/r300/r300_state.c | 31 ++++++++++++++++++++++++- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c index 93f1cd81655..1adb2363630 100644 --- a/src/gallium/drivers/r300/r300_context.c +++ b/src/gallium/drivers/r300/r300_context.c @@ -416,6 +416,9 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, r300_init_render_functions(r300); r300_init_states(&r300->context); + r300->viewport_scissor.maxx = 16384; + r300->viewport_scissor.maxy = 16384; + r300->uploader = u_upload_create(&r300->context, 128 * 1024, PIPE_BIND_CUSTOM, PIPE_USAGE_STREAM, 0); r300->context.stream_uploader = u_upload_create(&r300->context, 1024 * 1024, diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h index f3ca1995334..ce5ce00db65 100644 --- a/src/gallium/drivers/r300/r300_context.h +++ b/src/gallium/drivers/r300/r300_context.h @@ -545,6 +545,7 @@ struct r300_context { struct pipe_stencil_ref stencil_ref; struct pipe_viewport_state viewport; + struct pipe_scissor_state viewport_scissor; /* Stream locations for SWTCL. */ int stream_loc_notcl[16]; @@ -563,6 +564,7 @@ struct r300_context { int sprite_coord_enable; /* Whether we are drawing points, to disable sprite coord if not */ bool is_point; + bool scissor_enabled; /* Whether two-sided color selection is enabled (AKA light_twoside). */ bool two_sided_color; bool flatshade; diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index b598b1918cf..c629e4fb829 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -863,20 +863,28 @@ void r300_emit_scissor_state(struct r300_context* r300, unsigned size, void* state) { struct pipe_scissor_state* scissor = (struct pipe_scissor_state*)state; + struct pipe_scissor_state final = r300->viewport_scissor; CS_LOCALS(r300); + if (r300->scissor_enabled && scissor) { + final.minx = MAX2(final.minx, scissor->minx); + final.miny = MAX2(final.miny, scissor->miny); + final.maxx = MIN2(final.maxx, scissor->maxx); + final.maxy = MIN2(final.maxy, scissor->maxy); + } + BEGIN_CS(size); OUT_CS_REG_SEQ(R300_SC_CLIPRECT_TL_0, 2); if (r300->screen->caps.is_r500) { - OUT_CS((scissor->minx << R300_CLIPRECT_X_SHIFT) | - (scissor->miny << R300_CLIPRECT_Y_SHIFT)); - OUT_CS(((scissor->maxx - 1) << R300_CLIPRECT_X_SHIFT) | - ((scissor->maxy - 1) << R300_CLIPRECT_Y_SHIFT)); + OUT_CS((final.minx << R300_CLIPRECT_X_SHIFT) | + (final.miny << R300_CLIPRECT_Y_SHIFT)); + OUT_CS(((final.maxx - 1) << R300_CLIPRECT_X_SHIFT) | + ((final.maxy - 1) << R300_CLIPRECT_Y_SHIFT)); } else { - OUT_CS(((scissor->minx + 1440) << R300_CLIPRECT_X_SHIFT) | - ((scissor->miny + 1440) << R300_CLIPRECT_Y_SHIFT)); - OUT_CS(((scissor->maxx + 1440-1) << R300_CLIPRECT_X_SHIFT) | - ((scissor->maxy + 1440-1) << R300_CLIPRECT_Y_SHIFT)); + OUT_CS(((final.minx + 1440) << R300_CLIPRECT_X_SHIFT) | + ((final.miny + 1440) << R300_CLIPRECT_Y_SHIFT)); + OUT_CS(((final.maxx + 1440-1) << R300_CLIPRECT_X_SHIFT) | + ((final.maxy + 1440-1) << R300_CLIPRECT_Y_SHIFT)); } END_CS; } diff --git a/src/gallium/drivers/r300/r300_render.c b/src/gallium/drivers/r300/r300_render.c index c9c243c1853..ee99933ac52 100644 --- a/src/gallium/drivers/r300/r300_render.c +++ b/src/gallium/drivers/r300/r300_render.c @@ -1160,10 +1160,13 @@ void r300_blitter_draw_rectangle(struct blitter_context *blitter, struct r300_context *r300 = r300_context(util_blitter_get_pipe(blitter)); unsigned last_sprite_coord_enable = r300->sprite_coord_enable; unsigned last_is_point = r300->is_point; + /* We othewise always scissor to the viewport, but blits ignore it. */ + struct pipe_scissor_state last_vp_scissor = r300->viewport_scissor; + r300->viewport_scissor = (struct pipe_scissor_state){0, 0, 16384, 16384}; unsigned width = x2 - x1; unsigned height = y2 - y1; unsigned vertex_size = !r300->draw ? 8 : 4; - unsigned dwords = 13 + vertex_size + + unsigned dwords = 15 + vertex_size + (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY ? 7 : 0); CS_LOCALS(r300); @@ -1202,6 +1205,7 @@ void r300_blitter_draw_rectangle(struct blitter_context *blitter, BEGIN_CS(dwords); /* Set up GA. */ OUT_CS_REG(R300_GA_POINT_SIZE, (height * 6) | ((width * 6) << 16)); + OUT_CS_REG(R300_SC_CLIP_RULE, r300->scissor_enabled ? 0xAAAA : 0xFFFF); if (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY) { /* Set up the GA to generate texcoords. */ @@ -1242,9 +1246,11 @@ done: /* Restore the state. */ r300_mark_atom_dirty(r300, &r300->rs_state); r300_mark_atom_dirty(r300, &r300->viewport_state); + r300_mark_atom_dirty(r300, &r300->scissor_state); r300->sprite_coord_enable = last_sprite_coord_enable; r300->is_point = last_is_point; + r300->viewport_scissor = last_vp_scissor; } void r300_init_render_functions(struct r300_context *r300) diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c index 897b4f09840..abcf8c9bc60 100644 --- a/src/gallium/drivers/r300/r300_state.c +++ b/src/gallium/drivers/r300/r300_state.c @@ -41,6 +41,20 @@ r300_mark_atom_dirty(r300, &(atom)); \ } +static void +r300_get_scissor_from_viewport(const struct pipe_viewport_state *vp, + struct pipe_scissor_state *scissor) +{ + /* SC_CLIP_*_A/B fields are 13 bits. */ + unsigned max_scissor = 16384; + float half_w = fabsf(vp->scale[0]); + float half_h = fabsf(vp->scale[1]); + scissor->minx = CLAMP(-half_w + vp->translate[0], 0, max_scissor); + scissor->maxx = CLAMP(half_w + vp->translate[0], 0, max_scissor); + scissor->miny = CLAMP(-half_h + vp->translate[1], 0, max_scissor); + scissor->maxy = CLAMP(half_h + vp->translate[1], 0, max_scissor); +} + static void r300_delete_vs_state(struct pipe_context* pipe, void* shader); static void r300_delete_fs_state(struct pipe_context* pipe, void* shader); @@ -1329,7 +1343,8 @@ static void* r300_create_rs_state(struct pipe_context* pipe, rs->color_control = R300_SHADE_MODEL_SMOOTH; } - clip_rule = state->scissor ? 0xAAAA : 0xFFFF; + /* We always clip, either to the user specified settings or the viewport. */ + clip_rule = 0xAAAA; /* Point sprites coord mode */ if (rs->rs.sprite_coord_enable) { @@ -1419,6 +1434,7 @@ static void r300_bind_rs_state(struct pipe_context* pipe, void* state) bool last_msaa_enable = r300->msaa_enable; bool last_flatshade = r300->flatshade; bool last_clip_halfz = r300->clip_halfz; + bool last_scissor_enabled = r300->scissor_enabled; if (r300->draw && rs) { draw_set_rasterizer_state(r300->draw, &rs->rs_draw, state); @@ -1431,6 +1447,7 @@ static void r300_bind_rs_state(struct pipe_context* pipe, void* state) r300->msaa_enable = rs->rs.multisample; r300->flatshade = rs->rs.flatshade; r300->clip_halfz = rs->rs.clip_halfz; + r300->scissor_enabled = rs->rs.scissor; } else { r300->polygon_offset_enabled = false; r300->sprite_coord_enable = 0; @@ -1438,6 +1455,7 @@ static void r300_bind_rs_state(struct pipe_context* pipe, void* state) r300->msaa_enable = false; r300->flatshade = false; r300->clip_halfz = false; + r300->scissor_enabled = false; } UPDATE_STATE(state, r300->rs_state); @@ -1463,6 +1481,10 @@ static void r300_bind_rs_state(struct pipe_context* pipe, void* state) if (r300->screen->caps.has_tcl && last_clip_halfz != r300->clip_halfz) { r300_mark_atom_dirty(r300, &r300->vs_state); } + + if (last_scissor_enabled != r300->scissor_enabled) { + r300_mark_atom_dirty(r300, &r300->scissor_state); + } } /* Free rasterizer state. */ @@ -1769,6 +1791,13 @@ static void r300_set_viewport_states(struct pipe_context* pipe, r300->viewport = *state; + struct pipe_scissor_state vp_scissor; + r300_get_scissor_from_viewport(state, &vp_scissor); + if (memcmp(&vp_scissor, &r300->viewport_scissor, sizeof(vp_scissor)) != 0) { + r300->viewport_scissor = vp_scissor; + r300_mark_atom_dirty(r300, &r300->scissor_state); + } + if (r300->draw) { draw_set_viewport_states(r300->draw, start_slot, num_viewports, state); viewport->vte_control = R300_VTX_XY_FMT | R300_VTX_Z_FMT;