nv2a/gl: y-flipped rendering to framebuffer object

Render scenes upside-down to framebuffer objects (FBO). The strange thing
about rendering to OpenGL FBO is that it follows the bottom-left triangle
rasterization rule with common PC GPUs. At least Intel and AMD. NVIDIA to
be tested. My raster-rule-test github gist demonstrates this.

This commit flips coordinates in y-direction, which effectively turns the
bottom-left rule into top-left rule needed for Xbox compatibility.

This (together with the previous commit) fixes Midtown Madness 3 Seine
water rectangular seam rendering artifacts (and the remaining seams are
present with Xbox hardware too.) May fix similar artifacts in other games.
This commit is contained in:
coldhex 2025-05-20 22:19:33 +03:00 committed by mborgerson
parent a316d74872
commit ce936bccdd
6 changed files with 27 additions and 36 deletions

View File

@ -68,7 +68,7 @@ void pgraph_gl_init_display(NV2AState *d)
"{\n"
" vec2 texCoord = gl_FragCoord.xy/display_size;\n"
" float rel = display_size.y/textureSize(tex, 0).y/line_offset;\n"
" texCoord.y = 1 + rel*(texCoord.y - 1);"
" texCoord.y = rel*(1.0f - texCoord.y);"
" out_Color.rgba = texture(tex, texCoord);\n"
" if (pvideo_enable) {\n"
" vec2 screenCoord = gl_FragCoord.xy - 0.5;\n"

View File

@ -92,7 +92,6 @@ void pgraph_gl_clear_surface(NV2AState *d, uint32_t parameter)
scissor_height = ymax - ymin + 1;
pgraph_apply_anti_aliasing_factor(pg, &xmin, &ymin);
pgraph_apply_anti_aliasing_factor(pg, &scissor_width, &scissor_height);
ymin = pg->surface_binding_dim.height - (ymin + scissor_height);
NV2A_DPRINTF("Translated clear rect to %d,%d - %d,%d\n", xmin, ymin,
xmin + scissor_width - 1, ymin + scissor_height - 1);
@ -204,9 +203,10 @@ void pgraph_gl_draw_begin(NV2AState *d)
}
/* Front-face select */
/* Winding is reverse here because clip-space y-coordinates are inverted */
glFrontFace(pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER)
& NV_PGRAPH_SETUPRASTER_FRONTFACE
? GL_CCW : GL_CW);
? GL_CW : GL_CCW);
/* Polygon offset */
/* FIXME: GL implementation-specific, maybe do this in VS? */
@ -340,7 +340,6 @@ void pgraph_gl_draw_begin(NV2AState *d)
pgraph_apply_anti_aliasing_factor(pg, &xmin, &ymin);
pgraph_apply_anti_aliasing_factor(pg, &scissor_width, &scissor_height);
ymin = pg->surface_binding_dim.height - (ymin + scissor_height);
pgraph_apply_scaling_factor(pg, &xmin, &ymin);
pgraph_apply_scaling_factor(pg, &scissor_width, &scissor_height);

View File

@ -924,12 +924,8 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
pgraph_apply_scaling_factor(pg, &x_min, &y_min);
pgraph_apply_scaling_factor(pg, &x_max, &y_max);
/* Translate for the GL viewport origin */
int y_min_xlat = MAX((int)max_gl_height - (int)y_max, 0);
int y_max_xlat = MIN((int)max_gl_height - (int)y_min, max_gl_height);
glUniform4i(r->shader_binding->clip_region_loc[i],
x_min, y_min_xlat, x_max, y_max_xlat);
x_min, y_min, x_max, y_max);
}
for (i = 0; i < 8; ++i) {

View File

@ -137,11 +137,7 @@ static void init_render_to_texture(PGRAPHState *pg)
"layout(location = 0) out vec4 out_Color;\n"
"void main()\n"
"{\n"
" vec2 texCoord;\n"
" texCoord.x = gl_FragCoord.x;\n"
" texCoord.y = (surface_size.y - gl_FragCoord.y)\n"
" + (textureSize(tex,0).y - surface_size.y);\n"
" texCoord /= textureSize(tex,0).xy;\n"
" vec2 texCoord = gl_FragCoord.xy / textureSize(tex, 0).xy;\n"
" out_Color.rgba = texture(tex, texCoord);\n"
"}\n";
@ -298,7 +294,7 @@ static void render_surface_to_texture_slow(NV2AState *d,
size_t bufsize = width * height * surface->fmt.bytes_per_pixel;
uint8_t *buf = g_malloc(bufsize);
surface_download_to_buffer(d, surface, false, true, false, buf);
surface_download_to_buffer(d, surface, false, false, false, buf);
width = texture_shape->width;
height = texture_shape->height;
@ -738,7 +734,7 @@ static void surface_download(NV2AState *d, SurfaceBinding *surface, bool force)
nv2a_profile_inc_counter(NV2A_PROF_SURF_DOWNLOAD);
surface_download_to_buffer(d, surface, true, true, true,
surface_download_to_buffer(d, surface, true, false, true,
d->vram_ptr + surface->vram_addr);
memory_region_set_client_dirty(d->vram, surface->vram_addr,
@ -875,20 +871,26 @@ void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface,
surface->fmt.bytes_per_pixel);
}
/* FIXME: Replace this flip/scaling */
/* FIXME: Replace this scaling */
// This is VRAM so we can't do this inplace!
uint8_t *flipped_buf = (uint8_t *)g_malloc(
surface->height * surface->width * surface->fmt.bytes_per_pixel);
unsigned int irow;
for (irow = 0; irow < surface->height; irow++) {
memcpy(&flipped_buf[surface->width * (surface->height - irow - 1)
* surface->fmt.bytes_per_pixel],
&buf[surface->pitch * irow],
surface->width * surface->fmt.bytes_per_pixel);
uint8_t *optimal_buf = buf;
unsigned int optimal_pitch = surface->width * surface->fmt.bytes_per_pixel;
if (surface->pitch != optimal_pitch) {
optimal_buf = (uint8_t *)g_malloc(surface->height * optimal_pitch);
uint8_t *src = buf;
uint8_t *dst = optimal_buf;
unsigned int irow;
for (irow = 0; irow < surface->height; irow++) {
memcpy(dst, src, optimal_pitch);
src += surface->pitch;
dst += optimal_pitch;
}
}
uint8_t *gl_read_buf = flipped_buf;
uint8_t *gl_read_buf = optimal_buf;
unsigned int width = surface->width, height = surface->height;
if (pg->surface_scale_factor > 1) {
@ -896,7 +898,7 @@ void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface,
pg->scale_buf = (uint8_t *)g_realloc(
pg->scale_buf, width * height * surface->fmt.bytes_per_pixel);
gl_read_buf = pg->scale_buf;
uint8_t *out = gl_read_buf, *in = flipped_buf;
uint8_t *out = gl_read_buf, *in = optimal_buf;
surface_copy_expand(out, in, surface->width, surface->height,
surface->fmt.bytes_per_pixel,
d->pgraph.surface_scale_factor);
@ -915,7 +917,9 @@ void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface,
height, 0, surface->fmt.gl_format, surface->fmt.gl_type,
gl_read_buf);
glPixelStorei(GL_UNPACK_ALIGNMENT, prev_unpack_alignment);
g_free(flipped_buf);
if (optimal_buf != buf) {
g_free(optimal_buf);
}
if (surface->swizzle) {
g_free(buf);
}

View File

@ -479,10 +479,6 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
" oPos.xy *= oPos.w;\n"
);
if (!state->vulkan) {
mstring_append(body, " oPos.y = -oPos.y;\n");
}
/* FIXME: Testing */
if (state->point_params_enable) {
mstring_append_fmt(uniforms, "%sfloat pointParams[8];\n", u);

View File

@ -839,8 +839,4 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version,
*/
" oPos.xyz *= oPos.w;\n"
);
if (!vulkan) {
mstring_append(body, " oPos.y = -oPos.y;\n");
}
}