diff --git a/pcsx2/GS/parallel-gs/gs/gs_interface.cpp b/pcsx2/GS/parallel-gs/gs/gs_interface.cpp index 7b94936f3..2d02e3f22 100644 --- a/pcsx2/GS/parallel-gs/gs/gs_interface.cpp +++ b/pcsx2/GS/parallel-gs/gs/gs_interface.cpp @@ -1538,16 +1538,14 @@ uint32_t GSInterface::drawing_kick_update_texture(FBFeedbackMode feedback_mode, // It tends to look very broken, especially when using SSAA textures. int u_offset = std::abs(uv_bb.x - bb.x); int v_offset = std::abs(uv_bb.y - bb.y); - int u_size = uv_bb.z - uv_bb.x; - int v_size = uv_bb.w - uv_bb.y; - int x_size = bb.z - bb.x; - int y_size = bb.w - bb.y; + /* For linear filter, UV bb is generally 2 extra pixels; + * fewer on an axis sampled on texel centres, or at the + * texture's edge. The bias is a few taps. */ + int u_extra = (uv_bb.z - uv_bb.x) - (bb.z - bb.x); + int v_extra = (uv_bb.w - uv_bb.y) - (bb.w - bb.y); - // For linear filter, UV bb is generally 2 extra pixels. - u_size -= 2; - v_size -= 2; - - if (u_offset <= 1 && v_offset <= 1 && u_size == x_size && v_size == y_size) + if (u_offset <= 4 && v_offset <= 4 && + u_extra >= 0 && u_extra <= 2 && v_extra >= 0 && v_extra <= 2) long_term_cache_texture = false; } } diff --git a/tests/swdraw/build.sh b/tests/swdraw/build.sh index e5334889e..b02db338e 100644 --- a/tests/swdraw/build.sh +++ b/tests/swdraw/build.sh @@ -33,7 +33,7 @@ SCRATCH=$(mktemp -d) trap 'rm -rf "$SCRATCH"' EXIT failed=0 for c in aa1_small aa1_triangle aa1_triangle_2x aa1_line aa1_line_2x mip_tw8 mip_tw11 mip_tw11_2x \ - display_large display_large_2x frame_ct32 frame_after_t4 frame_ct32_2x frame_after_t4_2x copy_then_upload readback_t4hh dest_alpha many_copies upload_short upload_whole upload_split upload_clut_between readback_parts column_passes alpha_under_depth alpha_under_depth_wide alpha_under_depth_strip alpha_under_depth_big mip_shaded alpha_dirtied_parked depth_narrowed width_overwritten palette_engulfed block_offset_read engulfed_alpha palette_bilinear palette_bilinear_drawn palette_shaded big_triangles present points nine_frames fb_wrap uv_huge offset_reload vram_wrap_read frame_on_depth dirty_whole_target wrap_gradient depth_texture_far move_width_change frame_on_depth32 depth_states shuffle_left_of_offset split_clear_no_display frame_low frame_low_odd frame_low_odd_2x \ + display_large display_large_2x frame_ct32 frame_after_t4 frame_ct32_2x frame_after_t4_2x copy_then_upload readback_t4hh dest_alpha many_copies upload_short upload_whole upload_split upload_clut_between readback_parts column_passes alpha_under_depth alpha_under_depth_wide alpha_under_depth_strip alpha_under_depth_big mip_shaded alpha_dirtied_parked depth_narrowed width_overwritten blur_in_place palette_engulfed block_offset_read engulfed_alpha palette_bilinear palette_bilinear_drawn palette_shaded big_triangles present points nine_frames fb_wrap uv_huge offset_reload vram_wrap_read frame_on_depth dirty_whole_target wrap_gradient depth_texture_far move_width_change frame_on_depth32 depth_states shuffle_left_of_offset split_clear_no_display frame_low frame_low_odd frame_low_odd_2x \ gif_nloop_past_data dual_blend date_no_depth_full t4_from_target t4_from_target_page t4_from_target_shaded texture_rewind draw_once \ feedback_chain feedback_own_pixel feedback_runs; do if ! timeout 300 "$DIR/swdraw" "$CORE" "$SCRATCH" "$c" > "$SCRATCH/$c.out" 2>&1; then diff --git a/tests/swdraw/main.c b/tests/swdraw/main.c index a119a2f78..586907a5b 100644 --- a/tests/swdraw/main.c +++ b/tests/swdraw/main.c @@ -3260,6 +3260,67 @@ static void case_width_overwritten(void) s_expect_run[1] = 0x80405060ul; } +/* A buffer 320x224 at page 140, five pages wide, laid down once in a + * colour; every frame after, ten sprites a column of 32 each read it + * as a texture, linear, a texel to the side of where they draw, and + * draw it back into itself brightened (highlight), until it is white; + * its first rows are read back: white. On paraLLEl-GS the columns are + * one render pass, the blur in place reading the buffer as it was + * before the pass, not one a column, each waiting for the last. */ +static void case_blur_in_place(void) +{ + unsigned i, draw, rb; + s_smode1_hi = 0x7; /* NTSC, for a display every renderer shows */ + s_smode1_lo = 0x40834504u; + qw(0x8000u, 0x10000000u, 0xEu, 0); + qw(1, 0, GS_PRMODECONT, 0); + qw(0, 0, GS_XYOFFSET, 0); + qw(2047u << 16, 2047u << 16, GS_SCISSOR, 0); + qw((1u << 16) | (1u << 17), 0, GS_TEST_1, 0); /* ZTE, ZTST always */ + qw(8u, 1, GS_ZBUF_1, 0); /* ZMSK */ + qw(140u | (5u << 16), 0, GS_FRAME_1, 0); + qw(6, 0, GS_PRIM, 0); + qw(0xFF202020u, 0x3f800000u, GS_RGBAQ, 0); + qw(0, 0, GS_XYZ2, 0); + qw((unsigned)XY(160, 224), 0, GS_XYZ2, 0); + qw(0xFF303030u, 0x3f800000u, GS_RGBAQ, 0); + qw((unsigned)XY(160, 0), 0, GS_XYZ2, 0); + qw((unsigned)XY(320, 224), 0, GS_XYZ2, 0); + s_qw[0][0] = (s_qw_count - 1) | 0x8000u; + kick(0, s_qw_count, 0); + draw = s_qw_count; + qw(0x8000u, 0x10000000u, 0xEu, 0); + qw(140u | (5u << 16), 0, GS_FRAME_1, 0); + qw(0x1180u | (5u << 14) | (9u << 26), 2u | (1u << 2) | (2u << 3), GS_TEX0_1, 0); /* 512x256, TCC, highlight */ + qw(1u << 5, 0, GS_TEX1_1, 0); /* MMAG linear */ + qw(0, 0, GS_CLAMP_1, 0); + qw(6 | 0x10 | 0x100, 0, GS_PRIM, 0); /* sprite, TME, FST */ + s_bump_qw = s_qw_count; /* a sprite's first colour: bumped, drawn with the second */ + qw(0x10808080u, 0x3f800000u, GS_RGBAQ, 0); + for (i = 0; i < 10; i++) + { + qw(0x10808080u, 0x3f800000u, GS_RGBAQ, 0); /* unity, plus 0x10 a frame */ + qw((unsigned)XY(i * 32 + 1, 0) + 0x00080008u, 0, GS_UV, 0); + qw((unsigned)XY(i * 32, 0), 0, GS_XYZ2, 0); + qw((unsigned)XY(i * 32 + 33, 224) + 0x00080008u, 0, GS_UV, 0); + qw((unsigned)XY(i * 32 + 32, 224), 0, GS_XYZ2, 0); + } + s_qw[draw][0] = (s_qw_count - draw - 1) | 0x8000u; + rb = s_qw_count; + qw(4 | 0x8000u, 0x10000000u, 0xEu, 0); + qw(140u | (5u << 16), 0, GS_BITBLTBUF, 0); /* SBP page 140, SBW 5 */ + qw(0, 0, GS_TRXPOS, 0); + qw(128, 16, GS_TRXREG, 0); + qw(1, 0, GS_TRXDIR, 0); /* local to host */ + s_loop = 1; + s_loop_kick = s_kick_count; + kick(draw, rb - draw, 1); + kick(rb, s_qw_count - rb, 0); + readback(128 * 16 / 4); + s_run_frames = 60; + s_expect_run[0] = 0xFFFFFFFFul; +} + static const struct { const char* name; void (*build)(void); const char* scale; } s_cases[] = { { "aa1_small", case_aa1_small, "1" }, { "stream_ct32", case_stream_ct32, "1" }, @@ -3306,6 +3367,7 @@ static const struct { const char* name; void (*build)(void); const char* scale; { "alpha_dirtied_parked", case_alpha_dirtied_parked, "1" }, { "depth_narrowed", case_depth_narrowed, "1" }, { "width_overwritten", case_width_overwritten, "1" }, + { "blur_in_place", case_blur_in_place, "1" }, { "palette_engulfed", case_palette_engulfed, "1" }, { "block_offset_read", case_block_offset_read, "1" }, { "engulfed_alpha", case_engulfed_alpha, "1" }, diff --git a/tests/vknegotiate/build.sh b/tests/vknegotiate/build.sh index 2b406e9e4..177e0f985 100755 --- a/tests/vknegotiate/build.sh +++ b/tests/vknegotiate/build.sh @@ -236,6 +236,32 @@ if [ -z "$vk" ] || [ "$vk" != "$pgs" ] || [ "$vk" != "$sw" ] || [ -n "$copies" ] fi echo " a buffer overwritten at two widths in turn: the same picture on every renderer, no image copy a frame" +# A buffer blurred in place every frame, a column of 32 at a time, each +# column a sprite reading the buffer linear a texel to the side of where +# it draws (blur_in_place): the readback on every renderer, and on +# paraLLEl-GS the columns in one render pass. paraLLEl-GS reads such a +# blur's source as it was before the pass rather than ending the pass +# at every column whose page the last one wrote. +c=blur_in_place +"$SCRATCH/swdraw" --bios "$SCRATCH/$c.bin" $c +for renderer in Vulkan "Software (HW)"; do + if ! VN_EXPECT_RUN=ffffffff VN_IDLE_BIOS=1 LRPS2_BIOS="$SCRATCH/$c.bin" VN_RENDERER="$renderer" \ + timeout 300 "$DIR/vknegotiate" "$CORE" "$SCRATCH" v2 > "$SCRATCH/$c.log" 2>&1; then + rm -rf "$SCRATCH" + echo " FAIL: $c, $renderer" + exit 1 + fi +done +VN_COUNT_CALLS=1 VN_FRAMES=40 VN_EXPECT_RUN=ffffffff VN_IDLE_BIOS=1 LRPS2_BIOS="$SCRATCH/$c.bin" VN_RENDERER=paraLLEl-GS \ + timeout 300 "$DIR/vknegotiate" "$CORE" "$SCRATCH" v2 > "$SCRATCH/$c.log" 2>&1 || true +passes=$(sed -n 's/.*run 40: calls.* dispatch_ind=\([0-9]*\).*/\1/p' "$SCRATCH/$c.log") +if ! grep -q "vknegotiate v2: ok" "$SCRATCH/$c.log" || [ -z "$passes" ] || [ "$passes" -gt 2 ]; then + rm -rf "$SCRATCH" + echo " FAIL: $c: a frame of ten blur columns on paraLLEl-GS is ${passes:-no} render passes" + exit 1 +fi +echo " a buffer blurred in place a column at a time: $passes render passes a frame on paraLLEl-GS" + # A palette drawn into a buffer one page wide, whose page a wider buffer # drawn every frame takes without drawing over the palette: an indexed # read through the palette gets it, on both renderers, and still after a