ps3: add a PS3 display server, switch resolutions through it

Screen resolution on PS3 lived in the ps3 context driver: a list of
resolution ids it probed for at init (leaked on every reinit - the
malloc'd list was never freed), stepped through with left/right on
the menu entry and applied with OK by reinitialising the driver. On
PSL1GHT that did nothing at all: the RSX driver configures the video
output itself, from the mode the system menu has it in, and never
looked at the chosen id.

dispserv_ps3 is now the display server for __PS3__. It lists the
modes the connected display takes (480, 576, 960x1080, 720, the
1080-line scalers, 1080), marks the one in use, and switches between
them. The menu entry now opens the same resolution dropdown the
desktop platforms use, and Start resets to the system menu's mode as
it does elsewhere. A choice is stored in current_resolution_id - the
video output resolution id, as before, so existing configs keep
their modes - and the video driver is reinitialised to configure the
output in it; picking the mode already in use reinitialises nothing.
A refresh-rate-only set_resolution (the autoswitch) is refused.

ps3_display_server_resolution() is what configures the output: the
chosen mode when the display takes it, otherwise the system menu's.
The RSX driver's rsx_init_screen now uses it in place of the system
mode, which makes the setting work on PSL1GHT; the PSGL context uses
it for its device size in place of the unchecked stored id, so a
choice the current display cannot show (a config moved to another
TV) falls back instead of failing.

The mode table and those rules are in dispserv_ps3_modes.c, which
takes the display's answers through a callback and so has no SDK
dependency. The context driver loses its list and its output
size/prev/next callbacks, and global_t loses the list, count, check,
idx and initial fields nothing reads any more.

Test: samples/gfx/dispserv_ps3 links the real server and mode rules
against stubbed PSL1GHT video output queries (declared in the tree's
PS3 stub <sysutil/video.h>, now carrying PSL1GHT's layouts) for
displays taking different sets of modes with the system menu in each:
the list is exactly what the display takes with the mode in use
marked; each entry, through the label the menu prints and the parse
the menu does, selects its mode, stores its id, reinitialises once
(never for the mode in use) and reports its rate and size; the mode
the driver configures follows the choice and falls back to the system
mode for one the display lacks or an unknown id; refresh-only and
unavailable modes are refused without touching anything. Wired into
Linux-samples-gfx (ASan + UBSan); compile-matrix gains a PSL1GHT
syntax lane for the server.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-09-26 04:45:01 +02:00
1 parent 8e386c7642
commit ffa4ec336a
18 files changed
+858 -173

No files matched your search

+22
View File
@@ -660,6 +660,28 @@ jobs:
timeout 60 ./dispserv_gx_test
make clean
- name: Build and run dispserv_ps3_test (ASan + UBSan)
shell: bash
working-directory: samples/gfx/dispserv_ps3
run: |
set -eu
# The PS3 display server (dispserv_ps3.c and the mode rules in
# dispserv_ps3_modes.c), linked as they ship against stubbed
# PSL1GHT video output queries, for displays taking different
# sets of modes with the system menu in each: the list holds
# exactly what the display takes with the mode in use marked,
# each entry - through the menu's label and parse - selects
# that mode and reinitialises the driver once, and
# ps3_display_server_resolution(), which the RSX driver
# configures the output from, follows the choice (before, the
# RSX driver ignored the setting and kept the system menu's
# mode) and falls back to the system mode when the display
# does not take it.
make clean all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./dispserv_ps3_test
make clean
- name: X11 window poll sends no requests (Xvfb, ASan + UBSan)
shell: bash
run: |
@@ -515,6 +515,7 @@ check "gekko: mem2_manager" "$HOSTOFF $GEKKO_INC -DGEKKO -DHW_RVL -DRARCH_CON
check "gekko: dispserv_gx" "$HOSTOFF $GEKKO_INC -DGEKKO -DHW_RVL -DRARCH_CONSOLE $CDECL" gfx/display_servers/dispserv_gx.c
check "gamecube: dispserv_gx" "$HOSTOFF $GEKKO_INC -DGEKKO -DRARCH_CONSOLE $CDECL" gfx/display_servers/dispserv_gx.c
check "gekko: dispserv_gx_modes" "$HOSTOFF $GEKKO_INC -DGEKKO -DHW_RVL -DRARCH_CONSOLE $CDECL" gfx/display_servers/dispserv_gx_modes.c
check "psl1ght: dispserv_ps3" "$HOSTOFF -Itools/platform_stubs/ps3 -D__PS3__ -D__PSL1GHT__ -DRARCH_CONSOLE $CDECL" gfx/display_servers/dispserv_ps3.c gfx/display_servers/dispserv_ps3_modes.c
check "3ds: ctr_input" "$HOSTOFF -Itools/platform_stubs/ctr -D_3DS -D__3DS__ -DARM11 -DRARCH_CONSOLE $CDECL" input/drivers/ctr_input.c
PSP_DEFS="$HOSTOFF -Itools/platform_stubs/psp -DPSP -D_POSIX_C_SOURCE=199309L -DRARCH_CONSOLE"
check "psp: psp_input" "$PSP_DEFS $CDECL" input/drivers/psp_input.c
+192
View File
@@ -0,0 +1,192 @@
/* RetroArch - A frontend for libretro.
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
/* Display server for the PS3. It lists the video output modes the
* connected display takes (dispserv_ps3_modes.c), marks the one in
* use, and switches between them. The output itself is configured by
* whoever owns the frame buffers - the RSX driver on PSL1GHT, the PSGL
* context on the Cell SDK - at init, from
* ps3_display_server_resolution(); so a switch stores the choice in
* current_resolution_id and reinitialises the video driver, which
* comes back up in it.
*
* Only whole modes can be switched: a set_resolution without dims
* (the refresh rate autoswitch) fails. */
#include <stdlib.h>
#ifdef __PSL1GHT__
#include <sysutil/video.h>
typedef videoState ps3_video_state_t;
#define PS3_VIDEO_GET_STATE(s) videoGetState(0, 0, (s))
#define PS3_VIDEO_AVAILABLE(id) videoGetResolutionAvailability( \
VIDEO_PRIMARY, (id), VIDEO_ASPECT_AUTO, 0)
#else
#include <sysutil/sysutil_sysparam.h>
typedef CellVideoOutState ps3_video_state_t;
#define PS3_VIDEO_GET_STATE(s) cellVideoOutGetState( \
CELL_VIDEO_OUT_PRIMARY, 0, (s))
#define PS3_VIDEO_AVAILABLE(id) cellVideoOutGetResolutionAvailability( \
CELL_VIDEO_OUT_PRIMARY, (id), CELL_VIDEO_OUT_ASPECT_AUTO, 0)
#endif
#include "dispserv_ps3.h"
#include "../../command.h"
#include "../../retroarch.h"
#include "../../verbosity.h"
/* Nothing to keep; any non-NULL pointer marks the server as up */
static char ps3_display_server_state;
static bool ps3_display_server_available(void *user, unsigned id)
{
return PS3_VIDEO_AVAILABLE(id) ? true : false;
}
/* The mode the system menu has the output in, 0 when unreadable */
static unsigned ps3_display_server_system_id(void)
{
ps3_video_state_t state;
if (PS3_VIDEO_GET_STATE(&state) != 0)
return PS3_MODE_ID_SYSTEM;
return state.displayMode.resolution;
}
unsigned ps3_display_server_resolution(unsigned system_id)
{
global_t *global = global_get_ptr();
return ps3_modes_effective(ps3_display_server_available, NULL,
global->console.screen.resolutions.current.id, system_id);
}
static unsigned ps3_display_server_in_use(void)
{
return ps3_display_server_resolution(ps3_display_server_system_id());
}
static void *ps3_display_server_init(void)
{
return &ps3_display_server_state;
}
static void ps3_display_server_destroy(void *data) { }
static void *ps3_display_server_get_resolution_list(void *data,
unsigned *len)
{
unsigned count;
video_display_config_t *list;
global_t *global = global_get_ptr();
unsigned current = global->console.screen.resolutions.current.id;
unsigned system = ps3_display_server_system_id();
count = ps3_modes_list(ps3_display_server_available, NULL,
current, system, NULL, 0);
if (!count || !(list = (video_display_config_t*)
malloc(count * sizeof(*list))))
{
*len = 0;
return NULL;
}
*len = ps3_modes_list(ps3_display_server_available, NULL,
current, system, list, count);
return list;
}
static bool ps3_display_server_set_resolution(void *data,
unsigned dims, int int_hz, float hz, int center,
int monitor_index, int xoffset, int padjust)
{
int id;
global_t *global = global_get_ptr();
/* No dims is a refresh rate change on its own, which the video
* output cannot make without changing the mode */
if (!VIDEO_SCALE_W(dims) || !VIDEO_SCALE_H(dims))
return false;
if ((id = ps3_modes_find(ps3_display_server_available, NULL, dims)) < 0)
{
RARCH_WARN("[PS3] The display does not take %ux%u.\n",
VIDEO_SCALE_W(dims), VIDEO_SCALE_H(dims));
return false;
}
if ((unsigned)id == ps3_display_server_in_use())
{
/* Already there; store it so the choice outlives a change to
* the system menu's mode */
global->console.screen.resolutions.current.id = (unsigned)id;
return true;
}
global->console.screen.resolutions.current.id = (unsigned)id;
/* PAL60 temporal conversion only applies to 576 (PSGL) */
if (dims != VIDEO_SCALE_PACK(720, 576))
{
global->console.screen.pal_enable = false;
global->console.screen.pal60_enable = false;
}
/* The output is configured at video init, with the frame buffers
* sized for it */
command_event(CMD_EVENT_REINIT, NULL);
return true;
}
static float ps3_display_server_get_refresh_rate(void *data)
{
return ps3_modes_hz(ps3_display_server_in_use());
}
static void ps3_display_server_get_video_output_size(void *data,
unsigned *dims, char *s, size_t len)
{
*dims = ps3_modes_dims(ps3_display_server_in_use());
}
const video_display_server_t dispserv_ps3 = {
ps3_display_server_init,
ps3_display_server_destroy,
NULL, /* set_window_opacity */
NULL, /* set_window_progress */
NULL, /* set_window_decorations */
ps3_display_server_set_resolution,
ps3_display_server_get_resolution_list,
NULL, /* get_output_options */
NULL, /* set_screen_orientation */
NULL, /* get_screen_orientation */
ps3_display_server_get_refresh_rate,
ps3_display_server_get_video_output_size,
NULL, /* get_video_output_prev */
NULL, /* get_video_output_next */
NULL, /* get_metrics */
NULL, /* get_flags */
NULL, /* get_scanline */
NULL, /* wait_vblank */
NULL, /* modeline_list_outputs */
NULL, /* modeline_open */
NULL, /* modeline_close */
NULL, /* modeline_caps */
NULL, /* modeline_enum */
NULL, /* modeline_add */
NULL, /* modeline_update */
NULL, /* modeline_delete */
NULL, /* modeline_set */
NULL, /* modeline_flush */
NULL, /* get_edid */
NULL, /* idle_wait */
"ps3"
};
+33
View File
@@ -0,0 +1,33 @@
/* RetroArch - A frontend for libretro.
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DISPSERV_PS3_H
#define __DISPSERV_PS3_H
#include <retro_common_api.h>
#include "dispserv_ps3_modes.h"
RETRO_BEGIN_DECLS
/* The video output resolution id to configure: the one chosen in the
* menu (current_resolution_id) when the display takes it, otherwise
* system_id - the mode the system menu has the output in, which the
* caller reads from the output state (0 when it has none). Shared by
* the RSX driver and the PSGL context, which configure the output. */
unsigned ps3_display_server_resolution(unsigned system_id);
RETRO_END_DECLS
#endif
+113
View File
@@ -0,0 +1,113 @@
/* RetroArch - A frontend for libretro.
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "dispserv_ps3_modes.h"
typedef struct ps3_mode
{
unsigned char id;
unsigned short width;
unsigned short height;
} ps3_mode_t;
/* The order the list shows them in, as the old context-driver list
* did: SD, the 1080-line horizontal scalers under 720p, then 1080 */
static const ps3_mode_t ps3_mode_table[] = {
{ 4, 720, 480 }, /* 480 */
{ 5, 720, 576 }, /* 576 */
{ 13, 960, 1080 },
{ 2, 1280, 720 }, /* 720 */
{ 12, 1280, 1080 },
{ 11, 1440, 1080 },
{ 10, 1600, 1080 },
{ 1, 1920, 1080 } /* 1080 */
};
#define PS3_MODE_COUNT (sizeof(ps3_mode_table) / sizeof(ps3_mode_table[0]))
#define PS3_MODE_ID_576 5
static const ps3_mode_t *ps3_modes_lookup(unsigned id)
{
unsigned i;
for (i = 0; i < PS3_MODE_COUNT; i++)
if (ps3_mode_table[i].id == id)
return &ps3_mode_table[i];
return NULL;
}
unsigned ps3_modes_dims(unsigned id)
{
const ps3_mode_t *m = ps3_modes_lookup(id);
if (!m)
return 0;
return VIDEO_SCALE_PACK(m->width, m->height);
}
float ps3_modes_hz(unsigned id)
{
return (id == PS3_MODE_ID_576) ? 50.0f : 59.94f;
}
unsigned ps3_modes_effective(ps3_mode_available_t avail, void *user,
unsigned current_id, unsigned system_id)
{
if ( current_id != PS3_MODE_ID_SYSTEM
&& ps3_modes_lookup(current_id)
&& avail(user, current_id))
return current_id;
return ps3_modes_lookup(system_id) ? system_id : PS3_MODE_ID_SYSTEM;
}
int ps3_modes_find(ps3_mode_available_t avail, void *user, unsigned dims)
{
unsigned i;
for (i = 0; i < PS3_MODE_COUNT; i++)
if ( VIDEO_SCALE_PACK(ps3_mode_table[i].width,
ps3_mode_table[i].height) == dims
&& avail(user, ps3_mode_table[i].id))
return ps3_mode_table[i].id;
return -1;
}
unsigned ps3_modes_list(ps3_mode_available_t avail, void *user,
unsigned current_id, unsigned system_id,
video_display_config_t *out, unsigned max)
{
unsigned i;
unsigned count = 0;
unsigned in_use = ps3_modes_effective(avail, user, current_id, system_id);
for (i = 0; i < PS3_MODE_COUNT; i++)
{
const ps3_mode_t *m = &ps3_mode_table[i];
if (!avail(user, m->id))
continue;
if (out && count < max)
{
video_display_config_t *cfg = &out[count];
memset(cfg, 0, sizeof(*cfg));
cfg->dims = VIDEO_SCALE_PACK(m->width, m->height);
cfg->bpp = 32;
cfg->refreshrate_float = ps3_modes_hz(m->id);
cfg->refreshrate = (unsigned)cfg->refreshrate_float;
cfg->idx = m->id;
cfg->current = (m->id == in_use);
}
count++;
}
return count;
}
+67
View File
@@ -0,0 +1,67 @@
/* RetroArch - A frontend for libretro.
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
/* The PS3 video output modes RetroArch offers and the rules for which
* one is in use. Nothing here touches an SDK: whether the display
* takes a mode comes in through a callback (dispserv_ps3.c asks the
* video output), so the Cell SDK and PSL1GHT builds share it and a
* host build can test it.
*
* A mode is named by its video output resolution id, the value both
* SDKs use (CELL_VIDEO_OUT_RESOLUTION_* / VIDEO_RESOLUTION_*: 1080 is
* 1, 720 is 2, 480 is 4, 576 is 5, 1600x1080 to 960x1080 are 10 to
* 13). That id is what current_resolution_id stores in the config;
* 0 there means "whatever the system menu is set to". */
#ifndef __DISPSERV_PS3_MODES_H
#define __DISPSERV_PS3_MODES_H
#include <stddef.h>
#include <retro_common_api.h>
#include <boolean.h>
#include "../video_display_server.h"
RETRO_BEGIN_DECLS
#define PS3_MODE_ID_SYSTEM 0
/* Whether the display takes the mode with this resolution id */
typedef bool (*ps3_mode_available_t)(void *user, unsigned id);
/* The mode's size as VIDEO_SCALE_PACKed dims, 0 for an unknown id. */
unsigned ps3_modes_dims(unsigned id);
/* The field rate the video output runs the mode at. */
float ps3_modes_hz(unsigned id);
/* The id in use: the stored one when it is a known mode the display
* takes, otherwise system_id (the system menu's mode; 0 if unknown). */
unsigned ps3_modes_effective(ps3_mode_available_t avail, void *user,
unsigned current_id, unsigned system_id);
/* The id of an available mode of exactly these dims, or -1. */
int ps3_modes_find(ps3_mode_available_t avail, void *user, unsigned dims);
/* The available modes, smallest first, with the one in use marked
* current. Writes at most max entries to out and returns how many
* there are in total; out may be NULL to count. */
unsigned ps3_modes_list(ps3_mode_available_t avail, void *user,
unsigned current_id, unsigned system_id,
video_display_config_t *out, unsigned max);
RETRO_END_DECLS
#endif
+8 -3
View File
@@ -51,6 +51,7 @@
#include "../../retroarch.h"
#ifdef HAVE_THREADS
#include "../video_thread_wrapper.h"
#include "../display_servers/dispserv_ps3.h"
#endif
#define RSX_MAX_BUFFERS 2
@@ -1319,6 +1320,7 @@ static gcmContextData *rsx_init_screen(rsx_t* gcm)
videoState state;
videoConfiguration vconfig;
videoResolution res; /* Screen Resolution */
unsigned resolution;
/* Context to keep track of the RSX buffer. */
gcmContextData *context = NULL;
static gcmContextData *saved_context = NULL;
@@ -1356,13 +1358,16 @@ static gcmContextData *rsx_init_screen(rsx_t* gcm)
if (state.state != 0)
goto error;
/* Get the current resolution */
if (videoGetResolution(state.displayMode.resolution, &res) != 0)
/* The mode chosen through the display server when the display
* takes it, otherwise the one the system menu has it in */
resolution = ps3_display_server_resolution(state.displayMode.resolution);
if (videoGetResolution(resolution, &res) != 0)
goto error;
/* Configure the buffer format to xRGB */
memset(&vconfig, 0, sizeof(videoConfiguration));
vconfig.resolution = state.displayMode.resolution;
vconfig.resolution = resolution;
vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
vconfig.pitch = res.width * sizeof(u32);
vconfig.aspect = state.displayMode.aspect;
+8 -146
View File
@@ -34,6 +34,7 @@
#include <rsx/rsx.h>
#endif
#include "../../frontend/frontend_driver.h"
#include "../display_servers/dispserv_ps3.h"
#if defined(HAVE_PSGL)
#include "../common/gl_common.h"
#include "../common/gl2_common.h"
@@ -56,88 +57,6 @@ static enum gfx_ctx_api ps3_api = GFX_CTX_RSX_API;
static enum gfx_ctx_api ps3_api = GFX_CTX_NONE;
#endif
static unsigned gfx_ctx_ps3_get_resolution(unsigned idx)
{
CellVideoOutResolution resolution;
cellVideoOutGetResolution(idx, &resolution);
return VIDEO_SCALE_PACK(resolution.width, resolution.height);
}
static void gfx_ctx_ps3_get_available_resolutions(void)
{
unsigned i;
uint32_t videomode[] = {
CELL_VIDEO_OUT_RESOLUTION_480,
CELL_VIDEO_OUT_RESOLUTION_576,
CELL_VIDEO_OUT_RESOLUTION_960x1080,
CELL_VIDEO_OUT_RESOLUTION_720,
CELL_VIDEO_OUT_RESOLUTION_1280x1080,
CELL_VIDEO_OUT_RESOLUTION_1440x1080,
CELL_VIDEO_OUT_RESOLUTION_1600x1080,
CELL_VIDEO_OUT_RESOLUTION_1080
};
uint32_t resolution_count = 0;
bool defaultresolution = true;
uint16_t num_videomodes = sizeof(videomode) / sizeof(uint32_t);
global_t *global = global_get_ptr();
if (global->console.screen.resolutions.check)
return;
for (i = 0; i < num_videomodes; i++)
{
if (cellVideoOutGetResolutionAvailability(
CELL_VIDEO_OUT_PRIMARY, videomode[i],
CELL_VIDEO_OUT_ASPECT_AUTO, 0))
resolution_count++;
}
global->console.screen.resolutions.count = 0;
global->console.screen.resolutions.list =
malloc(resolution_count * sizeof(uint32_t));
/* NULL-check: the resolutions.list[...] writes in the loop
* below and the '...list[...current.idx]' read at line ~138
* would NULL-deref on OOM. Void-returning function; leaving
* resolutions.check == false means the next call will retry
* (which is desired - an OOM here is transient and we want
* to populate the list once memory is available). */
if (!global->console.screen.resolutions.list)
return;
for (i = 0; i < num_videomodes; i++)
{
if (cellVideoOutGetResolutionAvailability(
CELL_VIDEO_OUT_PRIMARY,
videomode[i],
CELL_VIDEO_OUT_ASPECT_AUTO, 0))
{
global->console.screen.resolutions.list[
global->console.screen.resolutions.count++] = videomode[i];
global->console.screen.resolutions.initial.id = videomode[i];
if (global->console.screen.resolutions.current.id == videomode[i])
{
defaultresolution = false;
global->console.screen.resolutions.current.idx =
global->console.screen.resolutions.count-1;
}
}
}
/* In case we didn't specify a resolution -
* make the last resolution
that was added to the list (the highest resolution)
the default resolution */
if (global->console.screen.resolutions.current.id > num_videomodes || defaultresolution)
{
global->console.screen.resolutions.current.idx = resolution_count - 1;
global->console.screen.resolutions.current.id = global->console.screen.resolutions.list[global->console.screen.resolutions.current.idx];
}
global->console.screen.resolutions.check = true;
}
static void gfx_ctx_ps3_set_swap_interval(void *data, int interval)
{
#if defined(HAVE_PSGL)
@@ -199,6 +118,7 @@ static void *gfx_ctx_ps3_init(void *video_driver)
#ifdef HAVE_PSGL
PSGLdeviceParameters params;
PSGLinitOptions options;
unsigned dims;
#endif
global_t *global = global_get_ptr();
gfx_ctx_ps3_data_t *ps3 = (gfx_ctx_ps3_data_t*)
@@ -224,10 +144,10 @@ static void *gfx_ctx_ps3_init(void *video_driver)
params.depthFormat = GL_NONE;
params.multisamplingMode = GL_MULTISAMPLING_NONE_SCE;
if (global->console.screen.resolutions.current.id)
/* The mode the display server has chosen, if the display takes
* it; without one PSGL keeps the system menu's mode */
if ((dims = ps3_modes_dims(ps3_display_server_resolution(0))))
{
unsigned dims = gfx_ctx_ps3_get_resolution(
global->console.screen.resolutions.current.id);
params.enable |= PSGL_DEVICE_PARAMETERS_WIDTH_HEIGHT;
params.width = VIDEO_SCALE_W(dims);
params.height = VIDEO_SCALE_H(dims);
@@ -261,8 +181,6 @@ static void *gfx_ctx_ps3_init(void *video_driver)
CELL_VIDEO_OUT_PRIMARY, CELL_VIDEO_OUT_RESOLUTION_576,
CELL_VIDEO_OUT_ASPECT_AUTO, 0);
gfx_ctx_ps3_get_available_resolutions();
return ps3;
}
@@ -321,62 +239,6 @@ static bool gfx_ctx_ps3_bind_api(void *data,
return false;
}
static void gfx_ctx_ps3_get_video_output_size(void *data,
unsigned *dims, char *desc, size_t desc_len)
{
global_t *global = global_get_ptr();
if (!global)
return;
*dims = gfx_ctx_ps3_get_resolution(
global->console.screen.resolutions.current.id);
if (*dims == VIDEO_SCALE_PACK(720, 576))
{
if (global->console.screen.pal_enable)
global->console.screen.pal60_enable = true;
}
else
{
global->console.screen.pal_enable = false;
global->console.screen.pal60_enable = false;
}
}
static void gfx_ctx_ps3_get_video_output_prev(void *data)
{
global_t *global = global_get_ptr();
if (!global)
return;
if (global->console.screen.resolutions.current.idx)
{
global->console.screen.resolutions.current.idx--;
global->console.screen.resolutions.current.id =
global->console.screen.resolutions.list
[global->console.screen.resolutions.current.idx];
}
}
static void gfx_ctx_ps3_get_video_output_next(void *data)
{
global_t *global = global_get_ptr();
if (!global)
return;
if (global->console.screen.resolutions.current.idx + 1 <
global->console.screen.resolutions.count)
{
global->console.screen.resolutions.current.idx++;
global->console.screen.resolutions.current.id =
global->console.screen.resolutions.list
[global->console.screen.resolutions.current.idx];
}
}
static uint32_t gfx_ctx_ps3_get_flags(void *data)
{
uint32_t flags = 0;
@@ -399,9 +261,9 @@ const gfx_ctx_driver_t gfx_ctx_ps3 = {
gfx_ctx_ps3_set_video_mode,
gfx_ctx_ps3_get_video_size,
NULL, /* get_refresh_rate */
gfx_ctx_ps3_get_video_output_size,
gfx_ctx_ps3_get_video_output_prev,
gfx_ctx_ps3_get_video_output_next,
NULL, /* get_video_output_size: dispserv_ps3 */
NULL, /* get_video_output_prev */
NULL, /* get_video_output_next */
NULL, /* get_metrics */
NULL,
NULL, /* update_title */
+1
View File
@@ -253,6 +253,7 @@ extern const video_display_server_t dispserv_apple;
extern const video_display_server_t dispserv_sdl2;
extern const video_display_server_t dispserv_sdl3;
extern const video_display_server_t dispserv_gx;
extern const video_display_server_t dispserv_ps3;
RETRO_END_DECLS
+2
View File
@@ -1774,6 +1774,8 @@ void* video_display_server_init(enum rarch_display_type type)
current_display_server = &dispserv_apple;
#elif defined(GEKKO)
current_display_server = &dispserv_gx;
#elif defined(__PS3__)
current_display_server = &dispserv_ps3;
#else
current_display_server = &dispserv_null;
#endif
+2
View File
@@ -324,6 +324,8 @@ VIDEO CONTEXT
#elif defined(__EMSCRIPTEN__)
#include "../gfx/drivers_context/emscriptenegl_ctx.c"
#elif defined(__PS3__)
#include "../gfx/display_servers/dispserv_ps3_modes.c"
#include "../gfx/display_servers/dispserv_ps3.c"
#include "../gfx/drivers_context/ps3_ctx.c"
#endif
+1 -4
View File
@@ -8603,7 +8603,7 @@ static int generic_dropdown_box_list(size_t idx, unsigned lbl)
static int action_ok_video_resolution(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#if defined(PS2) || defined(__PS3__)
#if defined(PS2)
unsigned dims = 0;
char desc[64] = {0};
@@ -8613,9 +8613,6 @@ static int action_ok_video_resolution(const char *path,
char msg[128];
msg[0] = '\0';
#if defined(_WIN32) || defined(__PS3__)
generic_action_ok_command(CMD_EVENT_REINIT);
#endif
video_driver_set_video_mode(dims, true);
{
if (*desc)
+2 -5
View File
@@ -628,7 +628,6 @@ static int action_start_video_resolution(
const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
{
#if defined(GEKKO) || defined(PS2) || !defined(__PSL1GHT__) && !defined(__PS3__)
unsigned dims = 0;
char desc[64] = {0};
global_t *global = global_get_ptr();
@@ -640,7 +639,7 @@ static int action_start_video_resolution(
{
size_t _len;
char msg[128];
#if defined(GEKKO) || defined(PS2)
#if defined(GEKKO) || defined(PS2) || defined(__PS3__)
bool fullscreen = true;
#else
/* The window state the frontend is in, as driver init reads it */
@@ -649,9 +648,8 @@ static int action_start_video_resolution(
#endif
msg[0] = '\0';
#if defined(_WIN32) || !defined(__PSL1GHT__) && !defined(__PS3__)
/* PS3: the video output is configured at video init */
generic_action_ok_command(CMD_EVENT_REINIT);
#endif
video_driver_set_video_mode(dims, fullscreen);
#ifdef GEKKO
if (!VIDEO_SCALE_W(dims) || !VIDEO_SCALE_H(dims))
@@ -670,7 +668,6 @@ static int action_start_video_resolution(
runloop_msg_queue_push(msg, _len, 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
#endif
return 0;
}
+1 -1
View File
@@ -11552,7 +11552,7 @@ unsigned menu_displaylist_build_list(
PARSE_ONLY_UINT, false) == 0)
count++;
#if defined(PS2) || defined(__PS3__)
#if defined(PS2)
if (true)
#else
if (video_display_server_has_resolution_list())
+1 -10
View File
@@ -279,19 +279,10 @@ typedef struct global
{
struct
{
uint32_t *list;
unsigned count;
struct
{
unsigned idx;
unsigned id;
unsigned id; /* current_resolution_id */
} current;
struct
{
unsigned idx;
unsigned id;
} initial;
bool check;
} resolutions;
unsigned gamma_correction;
unsigned int flicker_filter_index;
+42
View File
@@ -0,0 +1,42 @@
TARGET := dispserv_ps3_test
# Links the real display server and its mode rules. dispserv_ps3.c
# reaches PSL1GHT for two video output queries; the tree's PS3 stub
# <sysutil/video.h> declares them in PSL1GHT's layouts and the test
# defines them, to plug the console into a display taking any modes.
REPO_ROOT := ../../..
SOURCES := dispserv_ps3_test.c \
$(REPO_ROOT)/gfx/display_servers/dispserv_ps3.c \
$(REPO_ROOT)/gfx/display_servers/dispserv_ps3_modes.c
CFLAGS += -Wall -std=gnu99 -g -O0 \
-D__PS3__ -D__PSL1GHT__ \
-I$(REPO_ROOT)/tools/platform_stubs/ps3 \
-I$(REPO_ROOT) \
-I$(REPO_ROOT)/libretro-common/include
# Objects stay here: the tree's own gfx/display_servers/*.o belong
# to the console build (griffin for PSL1GHT).
OBJS := $(notdir $(SOURCES:.c=.o))
vpath %.c $(sort $(dir $(SOURCES)))
ifneq ($(SANITIZER),)
CFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)
LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)
endif
LDFLAGS += -lm
all: $(TARGET)
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
$(TARGET): $(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS)
clean:
rm -f $(TARGET) $(OBJS)
.PHONY: all clean
@@ -0,0 +1,322 @@
/* Copyright (C) 2010-2026 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (dispserv_ps3_test.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Contract test for the PS3 display server
* (gfx/display_servers/dispserv_ps3.c + dispserv_ps3_modes.c), linked
* as they ship against stubbed PSL1GHT video output queries.
*
* For displays taking different sets of modes (SD only, a 720p set, a
* full 1080 set, a PAL SD set), with the system menu in each mode, it
* checks that:
* - the resolution list offers exactly the modes the display takes,
* with the one in use marked current: the stored choice when the
* display takes it, otherwise the system menu's mode;
* - each entry, taken through the menu's own round trip - the label
* menu_displaylist.c prints, parsed back the way
* action_cb_push_dropdown_item_resolution does - selects exactly
* that mode: current_resolution_id becomes its resolution id, the
* video driver is reinitialised once (not at all when the mode is
* already the one in use), and the refresh rate and output size
* reported are the ones listed;
* - ps3_display_server_resolution(), which the RSX driver and the
* PSGL context configure the output from, gives the choice when
* the display takes it and the system menu's mode otherwise -
* before this the RSX driver ignored the setting entirely;
* - a set_resolution with no dims (the refresh rate autoswitch) and
* one naming a mode the display does not take both fail without
* touching the stored id or reinitialising anything;
* - the ids the config stores keep meaning the modes they did. */
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysutil/video.h>
#include "gfx/display_servers/dispserv_ps3.h"
#include "command.h"
#include "retroarch.h"
static int failures;
#define CHECK(cond, ...) do { \
if (!(cond)) { \
failures++; \
printf("FAIL %s:%d: ", __FILE__, __LINE__); \
printf(__VA_ARGS__); \
printf("\n"); \
} \
} while (0)
/* ---- stubbed video output ---- */
static unsigned available_mask; /* bit n: resolution id n */
static unsigned system_id;
static int state_fails;
int32_t videoGetState(int32_t videoOut, int32_t deviceIndex, videoState *state)
{
memset(state, 0, sizeof(*state));
if (state_fails)
return -1;
state->displayMode.resolution = (uint8_t)system_id;
return 0;
}
int32_t videoGetResolutionAvailability(uint32_t videoOut, uint32_t resolutionId,
uint32_t aspect, uint32_t option)
{
return (resolutionId < 32 && (available_mask & (1u << resolutionId)))
? 1 : 0;
}
/* ---- stubbed RetroArch ---- */
static global_t g_global;
static unsigned reinits;
global_t *global_get_ptr(void) { return &g_global; }
bool command_event(enum event_command action, void *data)
{
if (action == CMD_EVENT_REINIT)
reinits++;
return true;
}
void RARCH_WARN(const char *fmt, ...) { (void)fmt; }
/* ---- the menu's round trip ---- */
/* menu_displaylist.c, DISPLAYLIST_DROPDOWN_LIST_RESOLUTION */
static void menu_label(char *s, size_t len, const video_display_config_t *c)
{
snprintf(s, len, "%dx%d (%.3f Hz)%s%s",
VIDEO_SCALE_W(c->dims), VIDEO_SCALE_H(c->dims),
c->refreshrate_float,
c->interlaced ? "[i]" : "",
c->dblscan ? "[d]" : "");
}
/* menu_cbs_ok.c, action_cb_push_dropdown_item_resolution */
static bool menu_parse(const char *path, unsigned *dims, float *hz)
{
char *end = NULL;
unsigned width, height;
width = (unsigned)strtoul(path, &end, 0);
if (end == path || *end != 'x')
return false;
++end;
height = (unsigned)strtoul(end, &end, 0);
*dims = VIDEO_SCALE_PACK(width, height);
while (*end == ' ' || *end == '(')
++end;
*hz = (float)strtod(end, NULL);
return true;
}
/* ---- tests ---- */
#define BIT(id) (1u << (id))
typedef struct
{
const char *name;
unsigned mask;
unsigned count;
} display_t;
static const display_t displays[] = {
{ "SD 480", BIT(4), 1 },
{ "PAL SD", BIT(4) | BIT(5), 2 },
{ "HD 720", BIT(4) | BIT(2), 2 },
{ "Full HD", BIT(4) | BIT(5) | BIT(2) | BIT(1)
| BIT(10) | BIT(11) | BIT(12) | BIT(13), 8 },
};
static const unsigned all_ids[] = { 4, 5, 13, 2, 12, 11, 10, 1 };
static video_display_config_t *get_list(void *data, unsigned *n)
{
*n = 0;
return (video_display_config_t*)dispserv_ps3.get_resolution_list(data, n);
}
static void test_table_ids(void)
{
CHECK(ps3_modes_dims(1) == VIDEO_SCALE_PACK(1920, 1080), "id 1");
CHECK(ps3_modes_dims(2) == VIDEO_SCALE_PACK(1280, 720), "id 2");
CHECK(ps3_modes_dims(4) == VIDEO_SCALE_PACK( 720, 480), "id 4");
CHECK(ps3_modes_dims(5) == VIDEO_SCALE_PACK( 720, 576), "id 5");
CHECK(ps3_modes_dims(10) == VIDEO_SCALE_PACK(1600, 1080), "id 10");
CHECK(ps3_modes_dims(11) == VIDEO_SCALE_PACK(1440, 1080), "id 11");
CHECK(ps3_modes_dims(12) == VIDEO_SCALE_PACK(1280, 1080), "id 12");
CHECK(ps3_modes_dims(13) == VIDEO_SCALE_PACK( 960, 1080), "id 13");
CHECK(ps3_modes_dims(0) == 0 && ps3_modes_dims(3) == 0
&& ps3_modes_dims(0x81) == 0, "unknown ids have dims");
CHECK(ps3_modes_hz(5) == 50.0f && fabsf(ps3_modes_hz(1) - 59.94f) < 0.001f,
"rates");
}
static void test_display(void *data, const display_t *d)
{
unsigned s, i, n;
available_mask = d->mask;
/* The system menu in each mode the display takes */
for (s = 0; s < sizeof(all_ids) / sizeof(all_ids[0]); s++)
{
video_display_config_t *list;
if (!(d->mask & BIT(all_ids[s])))
continue;
system_id = all_ids[s];
g_global.console.screen.resolutions.current.id = 0;
CHECK(ps3_display_server_resolution(system_id) == system_id,
"%s: no choice does not give the system mode", d->name);
list = get_list(data, &n);
CHECK(list && n == d->count, "%s: %u entries, want %u",
d->name, n, d->count);
if (!list)
continue;
for (i = 0; i < n; i++)
{
CHECK(d->mask & BIT(list[i].idx), "%s: lists id %u it lacks",
d->name, list[i].idx);
CHECK(list[i].current == (list[i].idx == system_id),
"%s: id %u current=%d with system %u", d->name,
list[i].idx, list[i].current, system_id);
}
for (i = 0; i < n; i++)
{
char label[64];
unsigned dims, m, j, out = 0;
float hz;
bool in_use = (list[i].idx
== ps3_display_server_resolution(system_id));
video_display_config_t *after;
menu_label(label, sizeof(label), &list[i]);
CHECK(menu_parse(label, &dims, &hz), "unparsable '%s'", label);
reinits = 0;
CHECK(dispserv_ps3.set_resolution(data, dims, (int)floor(hz), hz,
0, 0, 0, 0), "%s: '%s' refused", d->name, label);
CHECK(g_global.console.screen.resolutions.current.id
== list[i].idx, "%s: '%s' stored %u, want %u", d->name,
label, g_global.console.screen.resolutions.current.id,
list[i].idx);
CHECK(reinits == (in_use ? 0u : 1u),
"%s: '%s' reinitialised %u times", d->name, label, reinits);
CHECK(ps3_display_server_resolution(system_id) == list[i].idx,
"%s: '%s' is not what the driver configures", d->name,
label);
CHECK(fabsf(dispserv_ps3.get_refresh_rate(data)
- list[i].refreshrate_float) < 0.0001f,
"%s: '%s' reports another rate", d->name, label);
dispserv_ps3.get_video_output_size(data, &out, NULL, 0);
CHECK(out == list[i].dims, "%s: '%s' reports %ux%u", d->name,
label, VIDEO_SCALE_W(out), VIDEO_SCALE_H(out));
after = get_list(data, &m);
if (after)
{
unsigned cur = 0;
for (j = 0; j < m; j++)
if (after[j].current)
cur++;
CHECK(cur == 1 && after[i].current,
"%s: after '%s' the wrong entry is current",
d->name, label);
free(after);
}
}
free(list);
}
}
static void test_fallbacks(void *data)
{
unsigned dims = 0;
available_mask = BIT(4) | BIT(2);
system_id = 2;
/* A stored choice the display does not take (moved to another TV) */
g_global.console.screen.resolutions.current.id = 1;
CHECK(ps3_display_server_resolution(system_id) == 2,
"unavailable choice not replaced by the system mode");
dispserv_ps3.get_video_output_size(data, &dims, NULL, 0);
CHECK(dims == VIDEO_SCALE_PACK(1280, 720), "reports the lost choice");
/* A stored id that names no mode */
g_global.console.screen.resolutions.current.id = 0x81;
CHECK(ps3_display_server_resolution(system_id) == 2, "id 0x81 used");
/* Output state unreadable: the list still marks nothing wrongly */
g_global.console.screen.resolutions.current.id = 0;
state_fails = 1;
CHECK(ps3_display_server_resolution(0) == 0, "invented a mode");
state_fails = 0;
g_global.console.screen.resolutions.current.id = 4;
reinits = 0;
CHECK(!dispserv_ps3.set_resolution(data, 0, 50, 50.0f, 0, 0, 0, 0),
"refresh-rate-only switch accepted");
CHECK(!dispserv_ps3.set_resolution(data, VIDEO_SCALE_PACK(1920, 1080),
59, 59.94f, 0, 0, 0, 0), "1080 accepted on a 720 display");
CHECK(!dispserv_ps3.set_resolution(data, VIDEO_SCALE_PACK(640, 480),
59, 59.94f, 0, 0, 0, 0), "640x480 accepted");
CHECK(reinits == 0, "a refused switch reinitialised");
CHECK(g_global.console.screen.resolutions.current.id == 4,
"a refused switch changed the stored id");
}
int main(void)
{
unsigned i;
void *data = dispserv_ps3.init();
CHECK(data != NULL, "init returned NULL");
CHECK(dispserv_ps3.ident && !strcmp(dispserv_ps3.ident, "ps3"), "ident");
test_table_ids();
for (i = 0; i < sizeof(displays) / sizeof(displays[0]); i++)
test_display(data, &displays[i]);
test_fallbacks(data);
dispserv_ps3.destroy(data);
if (failures)
{
printf("%d failure(s)\n", failures);
return 1;
}
printf("[pass] dispserv_ps3_test\n");
return 0;
}
+40 -4
View File
@@ -1,10 +1,46 @@
/* Empty on purpose. defines/ps3_defines.h includes <sysutil/video.h>
* unconditionally, so it has to exist for anything to parse against
* these stubs; nothing compiled against them uses it yet. Declare what
* a file needs as one arrives. */
/* PSL1GHT <sysutil/video.h>, the part of it compiled against here:
* the video output queries gfx/display_servers/dispserv_ps3.c makes,
* in PSL1GHT's layouts and values (stdint types for its u8/u16/s32).
* defines/ps3_defines.h includes this unconditionally. Declare what a
* file needs as one arrives. */
#ifndef PS3STUB_SYSUTIL_VIDEO_H
#define PS3STUB_SYSUTIL_VIDEO_H
#include <stdint.h>
#define VIDEO_PRIMARY 0
#define VIDEO_ASPECT_AUTO 0
#define VIDEO_RESOLUTION_1080 1
#define VIDEO_RESOLUTION_720 2
#define VIDEO_RESOLUTION_480 4
#define VIDEO_RESOLUTION_576 5
#define VIDEO_RESOLUTION_1600x1080 10
#define VIDEO_RESOLUTION_1440x1080 11
#define VIDEO_RESOLUTION_1280x1080 12
#define VIDEO_RESOLUTION_960x1080 13
typedef struct _videodisplaymode
{
uint8_t resolution;
uint8_t scanMode;
uint8_t conversion;
uint8_t aspect;
uint8_t padding[2];
uint16_t refreshRates;
} videoDisplayMode;
typedef struct _videostate
{
uint8_t state;
uint8_t colorSpace;
uint8_t padding[6];
videoDisplayMode displayMode;
} videoState;
int32_t videoGetState(int32_t videoOut, int32_t deviceIndex,
videoState *state);
int32_t videoGetResolutionAvailability(uint32_t videoOut,
uint32_t resolutionId, uint32_t aspect, uint32_t option);
#endif