mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Preserve field masks in wide flat overlay geometry
This commit is contained in:
@@ -48,3 +48,9 @@ integer fallback bounds and precise vertex bounds, with one row for rounding.
|
||||
Tests compare native and enhanced masked pixels with unmasked images when
|
||||
precise positions cross the integer bounds, including negative coordinates.
|
||||
A tiny precise triangle must submit three row clips rather than 256.
|
||||
|
||||
Flat overlay rectangles also submit one-row geometry while field masking is
|
||||
active. This keeps the mask when a wide backend intentionally replaces its
|
||||
scissor. Non-interlaced overlays retain the original geometry and policy.
|
||||
A backend fixture that ignores the scissor tests both field parities, original
|
||||
progressive behavior, and clip restoration. This is not Vulkan driver testing.
|
||||
|
||||
@@ -198,8 +198,20 @@ void gr_draw_shaded_textured_triangle(int x0, int y0, int u0, int v0, uint32_t c
|
||||
GR_TRIANGLE_ROWS(gr_min(y0, gr_min(y1, y2)), gr_max(y0, gr_max(y1, y2)), g_b->draw_shaded_textured_triangle(x0, y0, u0, v0, c0, x1, y1, u1, v1, c1,
|
||||
x2, y2, u2, v2, c2, clut_x, clut_y, texpage, raw));
|
||||
}
|
||||
/* Wide flat-overlay backends intentionally replace the clip with a full
|
||||
* surface scissor. Submit row-height geometry too, so the field mask survives
|
||||
* that path while ordinary full-screen overlays keep their existing policy. */
|
||||
static void gr_draw_flat_rect_row(int x, int w, uint16_t c) {
|
||||
int x1, y1, x2, y2;
|
||||
g_b->get_draw_area(&x1, &y1, &x2, &y2);
|
||||
g_b->draw_flat_rect(x, y1, w, 1, c);
|
||||
}
|
||||
void gr_draw_flat_rect(int x, int y, int w, int h, uint16_t c) {
|
||||
GR_RASTER_ROWS(y, y + h - 1, g_b->draw_flat_rect(x, y, w, h, c));
|
||||
if (gpu_raster_skipped_row() < 0) {
|
||||
g_b->draw_flat_rect(x, y, w, h, c);
|
||||
return;
|
||||
}
|
||||
GR_RASTER_ROWS(y, y + h - 1, gr_draw_flat_rect_row(x, w, c));
|
||||
}
|
||||
void gr_draw_textured_rect(int x, int y, int w, int h, int u, int v,
|
||||
uint16_t clut_x, uint16_t clut_y, uint16_t texpage) {
|
||||
|
||||
@@ -2790,8 +2790,8 @@ static void vkb_draw_gouraud_triangle(int x0,int y0,uint16_t c0,int x1,int y1,ui
|
||||
/* Full-screen-overlay wide pass (pause gray-filter / load fade): draw a flat
|
||||
* rect covering the FULL wide width [0, wide_w) x [y, y+h) directly into the
|
||||
* active wide surface (positions already wide-space, u_xoff = 0). Mirrors GL's
|
||||
* wide_flat_rect_direct: full-width scissor (the overlay must dim the
|
||||
* revealed margins too), while preserving the draw-area Y band. The 6 verts are consumed privately (s_vbase bumped)
|
||||
* wide_flat_rect_direct: full-surface scissor (the overlay must dim the
|
||||
* revealed margins too). The 6 verts are consumed privately (s_vbase bumped)
|
||||
* so they never join a canonical batch. */
|
||||
static void wide_overlay_rect(int y, int h, uint16_t c, int semi) {
|
||||
if (s_wide_cur < 0 || !s_ready) return;
|
||||
@@ -2803,9 +2803,12 @@ static void wide_overlay_rect(int y, int h, uint16_t c, int semi) {
|
||||
push_vert(x0, fy0, col); push_vert(x1, fy1, col); push_vert(x0, fy1, col);
|
||||
s_vbase += s_vcount; s_vcount = 0; /* consume privately */
|
||||
int blend = (semi < 0) ? 0 : (semi + 1);
|
||||
int S = s_scale;
|
||||
VkCommandBuffer cb = begin_oneshot();
|
||||
/* Keep the full width and current Y clip, including interlaced row clips. */
|
||||
wide_pass_begin(cb);
|
||||
/* Overlay covers the whole surface: override the band scissor. */
|
||||
VkRect2D sc = { { 0, 0 }, { (uint32_t)(s_wide_w * S), (uint32_t)(VRAM_H * S) } };
|
||||
p_vkCmdSetScissor(cb, 0, 1, &sc);
|
||||
bind_masked(cb, 0, 0, blend, s_mask_check, s_mask_set);
|
||||
GeoPush gp = { px_shift(), 0.0f, (float)s_wide_w / 2.0f };
|
||||
p_vkCmdPushConstants(cb, s_pl_geo, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof gp, &gp);
|
||||
|
||||
@@ -21,10 +21,17 @@ static void mock_triangle(int x0,int y0,int x1,int y1,int x2,int y2,uint16_t c)
|
||||
++mock_submissions;if(!mock_pc || !mock_pq)++mock_bad;
|
||||
mock_pc=mock_pq=0; /* GPU backends consume these per submission. */
|
||||
}
|
||||
/* Wide overlay paths can deliberately ignore the draw-area scissor. */
|
||||
static unsigned overlay_rows[32];
|
||||
static void mock_flat_overlay(int x,int y,int w,int h,uint16_t c) {
|
||||
(void)x;(void)w;(void)c;
|
||||
for (int row=y; row<y+h && row<32; ++row)
|
||||
if (row>=0) ++overlay_rows[row];
|
||||
}
|
||||
static const GpuRenderBackend mock_backend={
|
||||
.name="metadata fixture",.get_draw_area=sw_get_draw_area,.set_draw_area=sw_set_draw_area,
|
||||
.set_precise_triangle=mock_precise,.set_perspective_triangle=mock_perspective,
|
||||
.draw_flat_triangle=mock_triangle
|
||||
.draw_flat_triangle=mock_triangle,.draw_flat_rect=mock_flat_overlay
|
||||
};
|
||||
/* This fixture keeps optional widescreen presentation disabled. */
|
||||
int g_ws_bd_stretch_pct, g_ws_bd_stretch_on;
|
||||
@@ -153,6 +160,17 @@ int main(void) {
|
||||
gr_set_perspective_triangle(1,1.0f,1.0f,1.0f);
|
||||
gr_draw_flat_triangle(0,8,1,8,0,9,0x7FFF);
|
||||
CHECK(mock_submissions==3 && mock_bad==0 && !mock_pc && !mock_pq);
|
||||
for (int skip=-1; skip<=1; ++skip) {
|
||||
memset(overlay_rows,0,sizeof overlay_rows); skipped_row=skip;
|
||||
gr_set_draw_area(0,4,31,15);
|
||||
gr_draw_flat_rect(0,0,32,20,0x7FFF);
|
||||
for (int y=0; y<32; ++y) {
|
||||
unsigned expected = skip<0 ? y<20 : (y>=4 && y<=15 && (y&1)!=skip);
|
||||
CHECK(overlay_rows[y] == expected);
|
||||
}
|
||||
int x1,y1,x2,y2; gr_get_draw_area(&x1,&y1,&x2,&y2);
|
||||
CHECK(x1==0 && y1==4 && x2==31 && y2==15);
|
||||
}
|
||||
gr_set_backend(GR_BACKEND_SOFTWARE);
|
||||
if (failures) return 1;
|
||||
puts("PASS: field predicate, all raster primitives, clipping, transfers, mode switch, scales 1/4");
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
source_path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).parents[1] / "src" / "gpu_vk_renderer.c"
|
||||
source = source_path.read_text(encoding="utf-8")
|
||||
source = (Path(__file__).parents[1] / "src" / "gpu_vk_renderer.c").read_text()
|
||||
setter = re.search(
|
||||
r"static void vkb_set_draw_area\(.*?\n\}", source, flags=re.DOTALL
|
||||
)
|
||||
@@ -23,14 +21,3 @@ assert tex_flush < state_write and geo_flush < state_write, (
|
||||
)
|
||||
|
||||
print("Vulkan draw-area batch-boundary test passed")
|
||||
|
||||
# Native-wide overlays must retain the same vertical clip as other geometry.
|
||||
# This source guard is not a substitute for Vulkan driver/pixel qualification.
|
||||
wide = re.search(r"static void wide_pass_begin\(.*?\n\}", source, flags=re.DOTALL)
|
||||
overlay = re.search(r"static void wide_overlay_rect\(.*?\n\}", source, flags=re.DOTALL)
|
||||
assert wide and overlay, "wide render helpers not found"
|
||||
assert "s_da_y1" in wide[0] and "s_da_y2" in wide[0]
|
||||
assert "p_vkCmdSetScissor" in wide[0]
|
||||
assert "wide_pass_begin(cb);" in overlay[0]
|
||||
assert "p_vkCmdSetScissor" not in overlay[0], "overlay overrides the draw-area Y clip"
|
||||
print("Vulkan wide-overlay clip source guard passed")
|
||||
|
||||
Reference in New Issue
Block a user