From ebcc77c6c82e6457df9f7f769820fd5da0d6a0ce Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Wed, 2 Jun 2021 14:37:41 -0700 Subject: [PATCH] nv2a: Fix window clip coordinate transform --- hw/xbox/nv2a/pgraph.c | 68 ++++++------------------------------------- hw/xbox/nv2a/psh.c | 57 ++++++++++++++++-------------------- hw/xbox/nv2a/psh.h | 1 - 3 files changed, 34 insertions(+), 92 deletions(-) diff --git a/hw/xbox/nv2a/pgraph.c b/hw/xbox/nv2a/pgraph.c index a0fb982503..39e72f42e9 100644 --- a/hw/xbox/nv2a/pgraph.c +++ b/hw/xbox/nv2a/pgraph.c @@ -3622,34 +3622,22 @@ static void pgraph_shader_update_constants(PGRAPHState *pg, /* Clipping regions */ for (i = 0; i < 8; i++) { - if (pg->shader_binding->clip_region_loc[i] == -1) { - break; - } - uint32_t x = pg->regs[NV_PGRAPH_WINDOWCLIPX0 + i * 4]; unsigned int x_min = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMIN); unsigned int x_max = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMAX); - - /* Adjust y-coordinates for the OpenGL viewport: translate coordinates - * to have the origin at the bottom-left of the surface (as opposed to - * top-left), and flip y-min and y-max accordingly. - */ - // FIXME: Check uint32_t y = pg->regs[NV_PGRAPH_WINDOWCLIPY0 + i * 4]; - unsigned int y_min = pg->surface_binding_dim.clip_height - + pg->surface_binding_dim.clip_y - - 1 - - GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX); - unsigned int y_max = pg->surface_binding_dim.clip_height - + pg->surface_binding_dim.clip_y - - 1 - - GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN); - + unsigned int y_min = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN); + unsigned int y_max = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX); pgraph_apply_anti_aliasing_factor(pg, &x_min, &y_min); pgraph_apply_anti_aliasing_factor(pg, &x_max, &y_max); + /* Translate for the GL viewport origin */ + unsigned int y_min_xlat = MAX(pg->surface_binding_dim.height - y_max - 1, 0); + unsigned int y_max_xlat = MIN(pg->surface_binding_dim.height - y_min - 1, + pg->surface_binding_dim.height); + glUniform4i(pg->shader_binding->clip_region_loc[i], - x_min, y_min, x_max + 1, y_max + 1); + x_min, y_min_xlat, x_max, y_max_xlat); } } @@ -3759,6 +3747,7 @@ static void pgraph_bind_shaders(PGRAPHState *pg) /* register combiner stuff */ state.psh.window_clip_exclusive = pg->regs[NV_PGRAPH_SETUPRASTER] & NV_PGRAPH_SETUPRASTER_WINDOWCLIPTYPE; + assert(!state.psh.window_clip_exclusive); /* FIXME: Untested */ state.psh.combiner_control = pg->regs[NV_PGRAPH_COMBINECTL]; state.psh.shader_stage_program = pg->regs[NV_PGRAPH_SHADERPROG]; state.psh.other_stage_input = pg->regs[NV_PGRAPH_SHADERCTL]; @@ -3859,45 +3848,6 @@ static void pgraph_bind_shaders(PGRAPHState *pg) } } - /* Window clip - * - * Optimization note: very quickly check to ignore any repeated or zero-size - * clipping regions. Note that if region number 7 is valid, but the rest are - * not, we will still add all of them. Clip regions seem to be typically - * front-loaded (meaning the first one or two regions are populated, and the - * following are zeroed-out), so let's avoid adding any more complicated - * masking or copying logic here for now unless we discover a valid case. - */ - assert(!state.psh.window_clip_exclusive); /* FIXME: Untested */ - state.psh.window_clip_count = 0; - uint32_t last_x = 0, last_y = 0; - - for (i = 0; i < 8; i++) { - const uint32_t x = pg->regs[NV_PGRAPH_WINDOWCLIPX0 + i * 4]; - const uint32_t y = pg->regs[NV_PGRAPH_WINDOWCLIPY0 + i * 4]; - const uint32_t x_min = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMIN); - const uint32_t x_max = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMAX); - const uint32_t y_min = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN); - const uint32_t y_max = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX); - - /* Check for zero width or height clipping region */ - if ((x_min == x_max) || (y_min == y_max)) { - continue; - } - - /* Check for in-order duplicate regions */ - if ((x == last_x) && (y == last_y)) { - continue; - } - - NV2A_DPRINTF("Clipping Region %d: min=(%d, %d) max=(%d, %d)\n", - i, x_min, y_min, x_max, y_max); - - state.psh.window_clip_count = i + 1; - last_x = x; - last_y = y; - } - /* Copy content of enabled combiner stages */ int num_stages = pg->regs[NV_PGRAPH_COMBINECTL] & 0xFF; for (i = 0; i < num_stages; i++) { diff --git a/hw/xbox/nv2a/psh.c b/hw/xbox/nv2a/psh.c index 1adc54757d..92c00957a8 100644 --- a/hw/xbox/nv2a/psh.c +++ b/hw/xbox/nv2a/psh.c @@ -609,38 +609,31 @@ static MString* psh_convert(struct PixelShader *ps) /* Window Clipping */ MString *clip = mstring_new(); - if (ps->state.window_clip_count != 0) { - mstring_append_fmt(preflight, "uniform ivec4 clipRegion[%d];\n", - ps->state.window_clip_count); - mstring_append_fmt(clip, "/* Window-clip (%s) */\n", - ps->state.window_clip_exclusive ? - "Exclusive" : "Inclusive"); - if (!ps->state.window_clip_exclusive) { - mstring_append(clip, "bool clipContained = false;\n"); - } - mstring_append_fmt(clip, "for (int i = 0; i < %d; i++) {\n", - ps->state.window_clip_count); - mstring_append(clip, " bvec4 clipTest = bvec4(lessThan(gl_FragCoord.xy, clipRegion[i].xy),\n" - " greaterThan(gl_FragCoord.xy, clipRegion[i].zw));\n" - " if (!any(clipTest)) {\n"); - if (ps->state.window_clip_exclusive) { - /* Pixel in clip region = exclude by discarding */ - mstring_append(clip, " discard;\n"); - assert(false); /* Untested */ - } else { - /* Pixel in clip region = mark pixel as contained and leave */ - mstring_append(clip, " clipContained = true;\n" - " break;\n"); - } - mstring_append(clip, " }\n" - "}\n"); - /* Check for inclusive window clip */ - if (!ps->state.window_clip_exclusive) { - mstring_append(clip, "if (!clipContained) { discard; }\n"); - } - } else if (ps->state.window_clip_exclusive) { - /* Clip everything */ - mstring_append(clip, "discard;\n"); + mstring_append(preflight, "uniform ivec4 clipRegion[8];\n"); + mstring_append_fmt(clip, "/* Window-clip (%s) */\n", + ps->state.window_clip_exclusive ? + "Exclusive" : "Inclusive"); + if (!ps->state.window_clip_exclusive) { + mstring_append(clip, "bool clipContained = false;\n"); + } + mstring_append(clip, "for (int i = 0; i < 8; i++) {\n" + " bvec4 clipTest = bvec4(lessThan(gl_FragCoord.xy-0.5, clipRegion[i].xy),\n" + " greaterThan(gl_FragCoord.xy-0.5, clipRegion[i].zw));\n" + " if (!any(clipTest)) {\n"); + if (ps->state.window_clip_exclusive) { + /* Pixel in clip region = exclude by discarding */ + mstring_append(clip, " discard;\n"); + assert(false); /* Untested */ + } else { + /* Pixel in clip region = mark pixel as contained and leave */ + mstring_append(clip, " clipContained = true;\n" + " break;\n"); + } + mstring_append(clip, " }\n" + "}\n"); + /* Check for inclusive window clip */ + if (!ps->state.window_clip_exclusive) { + mstring_append(clip, "if (!clipContained) { discard; }\n"); } /* calculate perspective-correct inputs */ diff --git a/hw/xbox/nv2a/psh.h b/hw/xbox/nv2a/psh.h index 7a7baf7c74..753483a909 100644 --- a/hw/xbox/nv2a/psh.h +++ b/hw/xbox/nv2a/psh.h @@ -60,7 +60,6 @@ typedef struct PshState { enum PshAlphaFunc alpha_func; bool window_clip_exclusive; - unsigned int window_clip_count; } PshState; MString *psh_translate(const PshState state);