mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Gate WipEout local viewport native-wide to split frames
This commit is contained in:
@@ -212,6 +212,10 @@ void psx_ws_sprite_tag(struct CPUState* cpu);
|
||||
* by this; 0 when native-wide is inactive). */
|
||||
int ws_native_wide_active(void);
|
||||
int ws_nw_extra(void);
|
||||
int ws_nw_present_width(void);
|
||||
void gpu_ws_set_netplay_local_viewport(int enabled, int slot);
|
||||
int gpu_ws_netplay_local_viewport_base_x(void);
|
||||
int gpu_ws_netplay_local_viewport_width(void);
|
||||
/* True when the current frame must present at native 4:3 (FMV video or a
|
||||
* full-2D menu/title screen), so the squash is suppressed and content drawn
|
||||
* pixel-native. The present path uses the same predicate to pillarbox. */
|
||||
|
||||
+162
-25
@@ -128,6 +128,7 @@ static int ws_engaged(void) { return ws_mode != 0; }
|
||||
|
||||
/* Forward decls: defined later but used by psx_ws_backdrop_x above them. */
|
||||
static int32_t ws_scale_about(int32_t x, int32_t ax);
|
||||
static int32_t ws_disp_x(void);
|
||||
static int32_t ws_disp_w(void);
|
||||
static void ws_clear_all_reveal_margins(void);
|
||||
|
||||
@@ -349,8 +350,48 @@ int ws_native_wide_active(void) {
|
||||
static int ws_native_wide_configured(void) {
|
||||
return ws_mode == 2 && ws_cfg_num * 3 > ws_cfg_den * 4;
|
||||
}
|
||||
|
||||
static int ws_local_viewport_cfg = 0;
|
||||
static int ws_local_viewport_slot = 0;
|
||||
static int ws_local_viewport_draw_target(int *base_x);
|
||||
static int ws_vertical_split_active(void);
|
||||
void gpu_ws_set_netplay_local_viewport(int enabled, int slot) {
|
||||
ws_local_viewport_cfg = enabled ? 1 : 0;
|
||||
ws_local_viewport_slot = slot == 1 ? 1 : 0;
|
||||
ws_nw_sync_target();
|
||||
}
|
||||
|
||||
static int ws_local_viewport_layout(int *base_x, int *source_w,
|
||||
int *wide_w, int *offset) {
|
||||
if (!ws_local_viewport_cfg || !ws_native_wide_configured() ||
|
||||
!ws_vertical_split_active())
|
||||
return 0;
|
||||
GpuDisplayInfo di;
|
||||
gpu_get_display_info(&di);
|
||||
if (di.disabled || di.depth24 || di.width < 2 || di.height == 0)
|
||||
return 0;
|
||||
if ((di.width & 1u) != 0)
|
||||
return 0;
|
||||
|
||||
int src_w = (int)di.width / 2;
|
||||
int target_w = ((int)di.height * ws_cfg_num + ws_cfg_den / 2) / ws_cfg_den;
|
||||
if (target_w < src_w)
|
||||
target_w = src_w;
|
||||
int off = (target_w - src_w) / 2;
|
||||
int final_w = src_w + off * 2;
|
||||
|
||||
if (base_x) *base_x = (int)di.display_x + (ws_local_viewport_slot ? src_w : 0);
|
||||
if (source_w) *source_w = src_w;
|
||||
if (wide_w) *wide_w = final_w;
|
||||
if (offset) *offset = off;
|
||||
return final_w > src_w && off > 0;
|
||||
}
|
||||
|
||||
static int ws_nw_configured_offset(void) {
|
||||
if (!ws_native_wide_configured()) return 0;
|
||||
int local_offset = 0;
|
||||
if (ws_local_viewport_layout(NULL, NULL, NULL, &local_offset))
|
||||
return local_offset;
|
||||
int numr = 3 * ws_cfg_num - 4 * ws_cfg_den;
|
||||
int w = (int)ws_disp_w();
|
||||
return (w * numr + 4 * ws_cfg_den) / (8 * ws_cfg_den);
|
||||
@@ -361,6 +402,23 @@ static int ws_nw_offset(void) {
|
||||
}
|
||||
int ws_nw_extra(void) { return 2 * ws_nw_offset(); }
|
||||
|
||||
int ws_nw_present_width(void) {
|
||||
int wide_w = 0;
|
||||
if (ws_local_viewport_layout(NULL, NULL, &wide_w, NULL))
|
||||
return wide_w;
|
||||
return (int)ws_disp_w() + ws_nw_extra();
|
||||
}
|
||||
|
||||
int gpu_ws_netplay_local_viewport_base_x(void) {
|
||||
int base = 0;
|
||||
return ws_local_viewport_layout(&base, NULL, NULL, NULL) ? base : 0;
|
||||
}
|
||||
|
||||
int gpu_ws_netplay_local_viewport_width(void) {
|
||||
int wide_w = 0;
|
||||
return ws_local_viewport_layout(NULL, NULL, &wide_w, NULL) ? wide_w : 0;
|
||||
}
|
||||
|
||||
/* Per-side X cull margin in screen/world units (the game's draw classifier
|
||||
* works in objX-camX where 1 unit ~= 1 native-4:3 screen pixel). The squash
|
||||
* shows a half-view of 160/s pixels (s = squash factor = ws_xnum/ws_xden), so
|
||||
@@ -1413,14 +1471,15 @@ int psx_ws_cull_bltz_at(const uint32_t *words, int n, int idx) {
|
||||
* x is the int16 screenX the handler was about to store. */
|
||||
int psx_ws_backdrop_x(int x) {
|
||||
if (ws_native_wide_active()) {
|
||||
int32_t X = ws_disp_x();
|
||||
int32_t W = (int32_t)ws_disp_w();
|
||||
int32_t extra = ws_nw_extra();
|
||||
int32_t cx = W / 2;
|
||||
int32_t d = (int16_t)x - cx;
|
||||
return (int)(cx + (d * (W + extra) + (d >= 0 ? W / 2 : -W / 2)) / W);
|
||||
int32_t d = (int16_t)x - X - cx;
|
||||
return (int)(X + cx + (d * (W + extra) + (d >= 0 ? W / 2 : -W / 2)) / W);
|
||||
}
|
||||
if (!ws_active()) return (int16_t)x;
|
||||
int32_t cx = ws_disp_w() / 2; /* screen centre (=160 @ 320) */
|
||||
int32_t cx = ws_disp_x() + ws_disp_w() / 2; /* screen centre (=160 @ 320) */
|
||||
return ws_scale_about((int16_t)x, cx);
|
||||
}
|
||||
|
||||
@@ -1828,8 +1887,20 @@ static int32_t ws_scale_len(int32_t w) {
|
||||
return s < 1 ? 1 : s;
|
||||
}
|
||||
|
||||
/* Horizontal display width in drawing space (e.g. 320). */
|
||||
/* Horizontal display viewport in drawing space (e.g. 320). For a selected
|
||||
* netplay-local split viewport this is that player's authored half, not the
|
||||
* whole composed display. */
|
||||
static int32_t ws_disp_x(void) {
|
||||
int base = 0;
|
||||
if (ws_local_viewport_layout(&base, NULL, NULL, NULL))
|
||||
return (int32_t)base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ws_disp_w(void) {
|
||||
int src_w = 0;
|
||||
if (ws_local_viewport_layout(NULL, &src_w, NULL, NULL))
|
||||
return (int32_t)src_w;
|
||||
GpuDisplayInfo di;
|
||||
gpu_get_display_info(&di);
|
||||
return di.width ? (int32_t)di.width : 320;
|
||||
@@ -1846,8 +1917,8 @@ static int32_t ws_disp_h(void) {
|
||||
* display; ordinary world-space rectangles remain untouched. */
|
||||
static void ws_expand_fullscreen_rect(int32_t *x, int32_t y, int *w, int h) {
|
||||
if (!ws_native_wide_active()) return;
|
||||
int W = (int)ws_disp_w(), H = (int)ws_disp_h();
|
||||
if (*x <= 0 && *x + *w >= W && y <= 0 && y + h >= H) {
|
||||
int X = (int)ws_disp_x(), W = (int)ws_disp_w(), H = (int)ws_disp_h();
|
||||
if (*x <= X && *x + *w >= X + W && y <= 0 && y + h >= H) {
|
||||
int off = ws_nw_offset();
|
||||
*x -= off;
|
||||
*w += 2 * off;
|
||||
@@ -1862,11 +1933,12 @@ static void ws_expand_fullscreen_rect(int32_t *x, int32_t y, int *w, int h) {
|
||||
* one zone, so its pieces share a pivot and stay aligned. (Full-2D menu
|
||||
* screens never reach here — they get zero squash + 4:3 pillarbox instead.) */
|
||||
static int32_t ws_hud_pivot(int32_t x, int32_t w) {
|
||||
int32_t X = ws_disp_x();
|
||||
int32_t W = ws_disp_w();
|
||||
int32_t cx = 2 * x + w; /* 2*centre, avoids losing the half */
|
||||
if (3 * cx < 2 * W) return 0;
|
||||
if (3 * cx > 4 * W) return W;
|
||||
return W / 2;
|
||||
int32_t cx = 2 * (x - X) + w; /* 2*centre, avoids losing the half */
|
||||
if (3 * cx < 2 * W) return X;
|
||||
if (3 * cx > 4 * W) return X + W;
|
||||
return X + W / 2;
|
||||
}
|
||||
|
||||
/* Automatic UI correction is deliberately tied to draw provenance, not to
|
||||
@@ -1938,8 +2010,8 @@ static int ws_auto_ui_transform_quad(int32_t vx[4], const int32_t vy[4]) {
|
||||
if (vy[i] > max_y) max_y = vy[i];
|
||||
}
|
||||
int32_t width = max_x - min_x, height = max_y - min_y;
|
||||
int32_t W = ws_disp_w(), H = ws_disp_h();
|
||||
if ((min_x <= 0 && max_x >= W && min_y <= 0 && max_y >= H) ||
|
||||
int32_t X = ws_disp_x(), W = ws_disp_w(), H = ws_disp_h();
|
||||
if ((min_x <= X && max_x >= X + W && min_y <= 0 && max_y >= H) ||
|
||||
(width > W / 2 && height > H / 4))
|
||||
return 0;
|
||||
|
||||
@@ -1953,8 +2025,8 @@ static int ws_auto_ui_transform_quad(int32_t vx[4], const int32_t vy[4]) {
|
||||
static int ws_auto_ui_transform_rect(int32_t *x, int32_t y, int *w, int h) {
|
||||
if (!x || !w || *w <= 0 || psx_ws_prim_is_tagged())
|
||||
return 0;
|
||||
int32_t W = ws_disp_w(), H = ws_disp_h();
|
||||
if ((*x <= 0 && *x + *w >= W && y <= 0 && y + h >= H) ||
|
||||
int32_t X = ws_disp_x(), W = ws_disp_w(), H = ws_disp_h();
|
||||
if ((*x <= X && *x + *w >= X + W && y <= 0 && y + h >= H) ||
|
||||
(*w > W / 2 && h > H / 4))
|
||||
return 0;
|
||||
int32_t anchor;
|
||||
@@ -2031,8 +2103,9 @@ static int32_t ws_nw_hud_shift(int32_t x, int32_t w) {
|
||||
* for live A/B: some HUD composites (Tomba's AP counter) render through
|
||||
* the tagged sprite funnel and stay inset without it. */
|
||||
if (ws_anchor_addr && !ws_nw_hud_tag_rects && psx_ws_prim_is_tagged()) return 0;
|
||||
int32_t X = ws_disp_x();
|
||||
int32_t W = ws_disp_w();
|
||||
int32_t cx = 2 * x + w; /* 2*centre, avoids losing the half */
|
||||
int32_t cx = 2 * (x - X) + w; /* 2*centre, avoids losing the half */
|
||||
if (3 * cx < 2 * W) return -off; /* left third -> pull to left edge */
|
||||
if (3 * cx > 4 * W) return off; /* right third -> push to right edge */
|
||||
return 0; /* middle third -> stay centred */
|
||||
@@ -2077,6 +2150,7 @@ static int ws_nw_backdrop_stretch_quad(int32_t *vx, const int32_t *vy) {
|
||||
if (!ws_nw_backdrop || !ws_native_wide_active()) return 0;
|
||||
int32_t extra = ws_nw_extra();
|
||||
if (extra <= 0) return 0;
|
||||
int32_t X = ws_disp_x();
|
||||
int32_t W = ws_disp_w();
|
||||
const int32_t EDGE = 24; /* slack for "touches the frame edge" */
|
||||
int32_t minx = vx[0], maxx = vx[0], miny = vy[0], maxy = vy[0];
|
||||
@@ -2087,7 +2161,7 @@ static int ws_nw_backdrop_stretch_quad(int32_t *vx, const int32_t *vy) {
|
||||
if (vy[i] > maxy) maxy = vy[i];
|
||||
}
|
||||
/* Must span the full display width and a real vertical extent. */
|
||||
if (minx > EDGE || maxx < W - EDGE || (maxy - miny) < 64) return 0;
|
||||
if (minx > X + EDGE || maxx < X + W - EDGE || (maxy - miny) < 64) return 0;
|
||||
/* Axis-aligned: every vertex X sits at either the min or the max edge, and
|
||||
* every Y at the top or bottom edge (a true screen-space rectangle). */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -2097,7 +2171,7 @@ static int ws_nw_backdrop_stretch_quad(int32_t *vx, const int32_t *vy) {
|
||||
}
|
||||
/* Stretch X about the display centre by (W+extra)/W so [0,W] -> [-off, W+off],
|
||||
* which the wide compositor (+off) maps onto the full [0, W+extra] surface. */
|
||||
int32_t cx = W / 2;
|
||||
int32_t cx = X + W / 2;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int32_t d = vx[i] - cx;
|
||||
vx[i] = cx + (d * (W + extra) + (d >= 0 ? W / 2 : -W / 2)) / W;
|
||||
@@ -2170,6 +2244,45 @@ static uint32_t texture_disable; /* bit 15 */
|
||||
static uint32_t draw_area_left, draw_area_top;
|
||||
static uint32_t draw_area_right, draw_area_bottom;
|
||||
|
||||
static int draw_area_intersects_rect(int x, int y, int w, int h) {
|
||||
if (w <= 0 || h <= 0)
|
||||
return 0;
|
||||
int r = x + w - 1;
|
||||
int b = y + h - 1;
|
||||
return !((int)draw_area_right < x ||
|
||||
(int)draw_area_left > r ||
|
||||
(int)draw_area_bottom < y ||
|
||||
(int)draw_area_top > b);
|
||||
}
|
||||
|
||||
static int ws_local_viewport_draw_target(int *base_x) {
|
||||
int base = 0, src_w = 0;
|
||||
if (!ws_local_viewport_layout(&base, &src_w, NULL, NULL))
|
||||
return 0;
|
||||
GpuDisplayInfo di;
|
||||
gpu_get_display_info(&di);
|
||||
if (draw_area_intersects_rect(base, (int)di.display_y,
|
||||
src_w, (int)di.height)) {
|
||||
if (base_x) *base_x = base;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ws_display_viewport_draw_target(int *base_x) {
|
||||
if (!ws_native_wide_active())
|
||||
return 0;
|
||||
GpuDisplayInfo di;
|
||||
gpu_get_display_info(&di);
|
||||
if (di.disabled || di.depth24 || di.width == 0 || di.height == 0)
|
||||
return 0;
|
||||
if (!draw_area_intersects_rect((int)di.display_x, (int)di.display_y,
|
||||
(int)di.width, (int)di.height))
|
||||
return 0;
|
||||
if (base_x) *base_x = (int)di.display_x;
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct GpuVerticalSplitTrace {
|
||||
uint8_t left_seen;
|
||||
uint8_t right_seen;
|
||||
@@ -2293,10 +2406,14 @@ static void split_trace_note_draw_area(void) {
|
||||
}
|
||||
}
|
||||
|
||||
int gpu_last_frame_vertical_split_screen(void) {
|
||||
static int ws_vertical_split_active(void) {
|
||||
return split_recent_left_age <= 8 && split_recent_right_age <= 8;
|
||||
}
|
||||
|
||||
int gpu_last_frame_vertical_split_screen(void) {
|
||||
return ws_vertical_split_active();
|
||||
}
|
||||
|
||||
void gpu_vertical_split_debug(int *active, int *left_age, int *right_age) {
|
||||
if (active) *active = gpu_last_frame_vertical_split_screen();
|
||||
if (left_age) *left_age = split_recent_left_age;
|
||||
@@ -2308,7 +2425,18 @@ void gpu_vertical_split_debug(int *active, int *left_age, int *right_age) {
|
||||
* disable mirroring for this draw. Called when the draw env changes. */
|
||||
static void ws_nw_sync_target(void) {
|
||||
if (!ws_native_wide_active()) { gr_wide_disable_target(); return; }
|
||||
gr_wide_configure((int)ws_disp_w() + ws_nw_extra(), ws_nw_offset());
|
||||
gr_wide_configure(ws_nw_present_width(), ws_nw_offset());
|
||||
int local_base = 0;
|
||||
if (ws_local_viewport_draw_target(&local_base)) {
|
||||
gr_wide_set_target(local_base);
|
||||
return;
|
||||
}
|
||||
if (ws_local_viewport_cfg) { gr_wide_disable_target(); return; }
|
||||
int display_base = 0;
|
||||
if (ws_display_viewport_draw_target(&display_base)) {
|
||||
gr_wide_set_target(display_base);
|
||||
return;
|
||||
}
|
||||
uint32_t base = draw_area_left;
|
||||
if (ws_is_fb_base(base)) gr_wide_set_target((int)base);
|
||||
else gr_wide_disable_target();
|
||||
@@ -3175,7 +3303,11 @@ static void raster_pixel(int32_t x, int32_t y, uint16_t color) {
|
||||
* https://github.com/mstan/psxrecomp/pull/73
|
||||
* Keep that credit with this guarded framebuffer-target variant. */
|
||||
static inline int32_t draw_area_wide_x_margin(void) {
|
||||
if (!ws_native_wide_active() || !ws_is_fb_base(draw_area_left)) return 0;
|
||||
int local_base = 0;
|
||||
if (!ws_native_wide_active()) return 0;
|
||||
if (ws_local_viewport_draw_target(&local_base)) return (int32_t)ws_nw_offset();
|
||||
if (ws_display_viewport_draw_target(NULL)) return (int32_t)ws_nw_offset();
|
||||
if (!ws_is_fb_base(draw_area_left)) return 0;
|
||||
return (int32_t)ws_nw_offset();
|
||||
}
|
||||
|
||||
@@ -3971,7 +4103,11 @@ static void gp0_exec_fill_rect(void) {
|
||||
/* Native-wide: when the game clears a display buffer, clear the full width
|
||||
* of that buffer's wide surface over the same rows — refreshing the centred
|
||||
* content region and keeping the revealed margins clean. */
|
||||
if (ws_native_wide_active() && ws_is_fb_base(dst_x)) {
|
||||
int local_base = 0;
|
||||
if (ws_native_wide_active() &&
|
||||
(ws_is_fb_base(dst_x) ||
|
||||
(ws_local_viewport_draw_target(&local_base) &&
|
||||
dst_x == (uint32_t)local_base))) {
|
||||
gr_wide_clear((int)dst_x, (int)dst_y, (int)height, color16);
|
||||
}
|
||||
}
|
||||
@@ -4362,15 +4498,15 @@ static void ws_ui_prepass_add(const uint32_t *words, uint32_t source_addr,
|
||||
}
|
||||
|
||||
int32_t width = max_x - min_x, height = max_y - min_y;
|
||||
int32_t W = ws_disp_w(), H = ws_disp_h();
|
||||
if ((min_x <= 0 && max_x >= W && min_y <= 0 && max_y >= H) ||
|
||||
int32_t X = ws_disp_x(), W = ws_disp_w(), H = ws_disp_h();
|
||||
if ((min_x <= X && max_x >= X + W && min_y <= 0 && max_y >= H) ||
|
||||
(width > W / 2 && height > H / 4))
|
||||
return;
|
||||
|
||||
WsUiPrepassItem *item = &ws_ui_prepass[ws_ui_prepass_count++];
|
||||
item->group.key =
|
||||
ws_auto_ui_group_key_words(words, op, min_y, height);
|
||||
item->group.x = min_x;
|
||||
item->group.x = min_x - X;
|
||||
item->group.width = width;
|
||||
item->group.anchor = 0;
|
||||
item->src_addr = source_addr & 0x1FFFFCu;
|
||||
@@ -4463,13 +4599,14 @@ void gpu_ws_prepass_linked_list(uint32_t start_addr) {
|
||||
ws_auto_ui_dense = ws_ui_prepass_count >= 32u && !ws_gte_game_mode_cfg;
|
||||
if (ws_ui_prepass_count == 0) return;
|
||||
|
||||
const int32_t group_origin = ws_disp_x();
|
||||
WsUiGroupItem groups[WS_UI_PREPASS_MAX];
|
||||
for (uint32_t i = 0; i < ws_ui_prepass_count; i++)
|
||||
groups[i] = ws_ui_prepass[i].group;
|
||||
ws_ui_group_assign(groups, ws_ui_prepass_count, ws_disp_w(),
|
||||
ws_auto_ui_dense);
|
||||
for (uint32_t i = 0; i < ws_ui_prepass_count; i++)
|
||||
ws_ui_prepass[i].group.anchor = groups[i].anchor;
|
||||
ws_ui_prepass[i].group.anchor = group_origin + groups[i].anchor;
|
||||
}
|
||||
|
||||
/* Per-opcode execution counters (exposed via gpu_get_opcode_stats) */
|
||||
|
||||
+33
-8
@@ -1425,6 +1425,9 @@ static bool g_ws_hud_sprt = false;
|
||||
* units include that ABI header and do not need this frontend-only setter. */
|
||||
extern "C" void gpu_ws_set_clear_reveal(int on);
|
||||
extern "C" void gpu_ws_set_precise_nclip(int on);
|
||||
extern "C" void gpu_ws_set_netplay_local_viewport(int enabled, int slot);
|
||||
extern "C" int gpu_ws_netplay_local_viewport_base_x(void);
|
||||
extern "C" int gpu_ws_netplay_local_viewport_width(void);
|
||||
extern "C" void gpu_ws_set_nw_textured_edges(int on, int scale_pct);
|
||||
extern "C" void gpu_ws_set_signed_x_bound_sites(const uint32_t*, const uint32_t*, int);
|
||||
/* Widescreen engages at game entry (fntrace_is_game_started): the BIOS boot
|
||||
@@ -1512,7 +1515,13 @@ static void refresh_widescreen_projection() {
|
||||
if (!g_ws_engaged) return;
|
||||
|
||||
const bool wide = g_video_aspect_num * 3 != g_video_aspect_den * 4;
|
||||
const int mode = wide ? (g_ws_native_wide ? 2 : 1) : 0;
|
||||
const bool local_native_wide =
|
||||
g_netplay_local_viewport == 1 && psx_netplay_active() &&
|
||||
gpu_last_frame_vertical_split_screen();
|
||||
const bool native_wide = (g_netplay_local_viewport == 1)
|
||||
? local_native_wide
|
||||
: (g_ws_native_wide != 0);
|
||||
const int mode = wide ? (native_wide ? 2 : 1) : 0;
|
||||
int proj_num = g_video_aspect_num;
|
||||
int proj_den = g_video_aspect_den;
|
||||
if (mode == 1) {
|
||||
@@ -2479,9 +2488,11 @@ static void apply_netplay_local_viewport_aspect(bool netplay_enabled) {
|
||||
if (!netplay_enabled ||
|
||||
g_netplay_local_viewport != 1 ||
|
||||
g_netplay_local_viewport_aspect == 0) {
|
||||
gpu_ws_set_netplay_local_viewport(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
gpu_ws_set_netplay_local_viewport(1, psx_netplay_local_slot());
|
||||
switch (g_netplay_local_viewport_aspect) {
|
||||
case 1:
|
||||
(void)psx_mod_set_fixed_display_aspect(16u, 9u);
|
||||
@@ -6426,6 +6437,7 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
|
||||
bool pin_43 = false; /* pillarbox this present (FMV, or a native-wide
|
||||
game frame that could not present wide) */
|
||||
bool depth24_frame = false;
|
||||
bool local_viewport_crop_applied = false;
|
||||
if (s_force_present_after_load && g_gl_active)
|
||||
gl_renderer_flush_cpu_uploads();
|
||||
{
|
||||
@@ -6480,8 +6492,11 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
|
||||
if (g_gl_active)
|
||||
gl_renderer_set_interpolation_suspended(
|
||||
fmv_frame || mdec_recently_active(2));
|
||||
const bool local_viewport_crop = netplay_local_viewport_slot() >= 0;
|
||||
bool local_viewport_crop_applied = false;
|
||||
const int local_viewport_slot = netplay_local_viewport_slot();
|
||||
const bool local_viewport_crop = local_viewport_slot >= 0;
|
||||
bool local_viewport_wide =
|
||||
local_viewport_crop && g_ws_engaged && ws_native_wide_active() &&
|
||||
gr_wide_supported() && gpu_ws_netplay_local_viewport_width() > 0;
|
||||
|
||||
/* Canonical present width. Native-wide does NOT widen the canonical read
|
||||
* (that bled across adjacent framebuffers); it composites into a separate
|
||||
@@ -6493,8 +6508,12 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
|
||||
* from the displayed buffer's surface. FMV/menu frames stay 4:3. */
|
||||
bool wide_present = (!fmv_frame && !di.depth24 && g_ws_engaged &&
|
||||
ws_native_wide_active() && gr_wide_supported() &&
|
||||
!local_viewport_crop);
|
||||
if (wide_present) present_w = w + (uint32_t)ws_nw_extra();
|
||||
(!local_viewport_crop || local_viewport_wide));
|
||||
if (wide_present) {
|
||||
present_w = local_viewport_wide
|
||||
? (uint32_t)gpu_ws_netplay_local_viewport_width()
|
||||
: (w + (uint32_t)ws_nw_extra());
|
||||
}
|
||||
|
||||
/* Native-wide invariant: canonical (320-wide) content is NEVER
|
||||
* stretched across the wide window — a game frame that cannot present
|
||||
@@ -6597,12 +6616,16 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
|
||||
* hires path if the displayed buffer has no surface yet. */
|
||||
int s = gr_scale();
|
||||
int sw = (int)present_w * s;
|
||||
int base_x = local_viewport_wide
|
||||
? gpu_ws_netplay_local_viewport_base_x()
|
||||
: (int)di.display_x;
|
||||
int n = gr_render_wide_display(sdl_pixel_buf, (int)(sw * sizeof(uint32_t)),
|
||||
(int)di.display_x, (int)di.display_y, (int)h);
|
||||
base_x, (int)di.display_y, (int)h);
|
||||
if (n > 0) {
|
||||
active_scale = s;
|
||||
} else {
|
||||
wide_present = false;
|
||||
local_viewport_wide = false;
|
||||
present_w = w;
|
||||
pres_entry->path = PRES_PATH_CANONICAL;
|
||||
pres_entry->wide_fellback = 1;
|
||||
@@ -6645,7 +6668,8 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
|
||||
|
||||
int present_px_w = (int)present_w * active_scale;
|
||||
int present_px_h = (int)h * active_scale;
|
||||
if (crop_present_to_netplay_local_viewport(sdl_pixel_buf,
|
||||
if (!local_viewport_wide &&
|
||||
crop_present_to_netplay_local_viewport(sdl_pixel_buf,
|
||||
&present_px_w,
|
||||
present_px_h)) {
|
||||
pin_43 = false;
|
||||
@@ -6709,7 +6733,7 @@ static NetplayVblankEpilogue sdl_vblank_present_body(void) {
|
||||
#ifndef PSX_SDL_NO_RENDER
|
||||
int src_w = (int)present_w * active_scale;
|
||||
int src_h = (int)h * active_scale;
|
||||
if (netplay_local_viewport_slot() >= 0 && src_w >= 2)
|
||||
if (local_viewport_crop_applied && src_w >= 2)
|
||||
src_w /= 2;
|
||||
if (g_gl_active) {
|
||||
/* OpenGL present: upload the active display rect and draw a full-screen
|
||||
@@ -12831,6 +12855,7 @@ session_reboot:
|
||||
nrc, net_cfg.local_slot, net_cfg.bind_hostport, net_cfg.peer_hostport);
|
||||
return 1;
|
||||
}
|
||||
apply_netplay_local_viewport_aspect(net_cfg.enabled);
|
||||
std::printf("psxrecomp: netplay transport=%s slot=%d input_player=%d delay=%d "
|
||||
"force_turn=%d bind=%s peer=%s session=%u\n",
|
||||
psx_netplay_transport_name(),
|
||||
|
||||
Reference in New Issue
Block a user