Skip to content

Commit 4fb4eba

Browse files
mardyWinterMute
authored andcommitted
ogc: implement switching of video modes
Add the video modes supported by libogc. Since we cannot be sure that they will all be compatible with the user's TV set, only list those modes belonging to the same standard as the current default mode: this should ensure that on a NTSC system only NTSC modes will be available, and same for PAL and M-PAL.
1 parent d182d9b commit 4fb4eba

1 file changed

Lines changed: 147 additions & 26 deletions

File tree

src/video/ogc/SDL_ogcvideo.c

Lines changed: 147 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,143 @@
4343

4444
#define DEFAULT_FIFO_SIZE 256 * 1024
4545

46+
// Inverse of the VI_TVMODE macro
47+
#define VI_FORMAT_FROM_MODE(tvmode) (tvmode >> 2)
48+
49+
static const GXRModeObj *s_ntsc_modes[] = {
50+
&TVNtsc240Ds,
51+
&TVNtsc480Prog,
52+
NULL,
53+
};
54+
55+
static const GXRModeObj *s_mpal_modes[] = {
56+
&TVMpal240Ds,
57+
&TVMpal480Prog,
58+
NULL,
59+
};
60+
61+
static const GXRModeObj *s_eurgb60_modes[] = {
62+
&TVEurgb60Hz240Ds,
63+
&TVEurgb60Hz480Prog,
64+
// Also add some PAL modes, since EURGB60 supports them too
65+
&TVPal264Ds,
66+
&TVPal528Prog,
67+
&TVPal576ProgScale,
68+
NULL,
69+
};
70+
71+
static const GXRModeObj *s_pal_modes[] = {
72+
&TVPal264Ds,
73+
&TVPal528Prog,
74+
&TVPal576ProgScale,
75+
NULL,
76+
};
77+
4678
/* Initialization/Query functions */
4779
static int OGC_VideoInit(_THIS);
4880
static void OGC_VideoQuit(_THIS);
4981

82+
static void init_display_mode(SDL_DisplayMode *mode, const GXRModeObj *vmode)
83+
{
84+
u32 format = VI_FORMAT_FROM_MODE(vmode->viTVMode);
85+
86+
/* Use a fake 32-bpp desktop mode */
87+
SDL_zero(*mode);
88+
mode->format = SDL_PIXELFORMAT_ARGB8888;
89+
mode->w = vmode->fbWidth;
90+
mode->h = vmode->efbHeight;
91+
switch (format) {
92+
case VI_DEBUG:
93+
case VI_NTSC:
94+
case VI_EURGB60:
95+
case VI_MPAL:
96+
mode->refresh_rate = 60;
97+
break;
98+
case VI_PAL:
99+
case VI_DEBUG_PAL:
100+
mode->refresh_rate = 50;
101+
break;
102+
}
103+
mode->driverdata = (GXRModeObj*)vmode;
104+
}
105+
106+
static void add_supported_modes(SDL_VideoDisplay *display, u32 tv_format)
107+
{
108+
const GXRModeObj **gx_modes;
109+
SDL_DisplayMode mode;
110+
111+
switch (tv_format) {
112+
case VI_DEBUG:
113+
case VI_NTSC:
114+
gx_modes = s_ntsc_modes;
115+
break;
116+
case VI_MPAL:
117+
gx_modes = s_mpal_modes;
118+
break;
119+
case VI_EURGB60:
120+
gx_modes = s_eurgb60_modes;
121+
break;
122+
case VI_PAL:
123+
case VI_DEBUG_PAL:
124+
gx_modes = s_pal_modes;
125+
break;
126+
default:
127+
return;
128+
}
129+
130+
while (*gx_modes) {
131+
init_display_mode(&mode, *gx_modes);
132+
SDL_AddDisplayMode(display, &mode);
133+
gx_modes++;
134+
}
135+
}
136+
137+
static void setup_video_mode(_THIS, GXRModeObj *vmode)
138+
{
139+
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
140+
141+
VIDEO_SetBlack(true);
142+
VIDEO_Configure(vmode);
143+
144+
/* Allocate the XFB */
145+
videodata->xfb[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
146+
videodata->xfb[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
147+
148+
VIDEO_ClearFrameBuffer(vmode, videodata->xfb[0], COLOR_BLACK);
149+
VIDEO_SetNextFramebuffer(videodata->xfb[0]);
150+
VIDEO_SetBlack(false);
151+
VIDEO_Flush();
152+
153+
VIDEO_WaitVSync();
154+
if (vmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
155+
156+
/* Setup the EFB -> XFB copy operation */
157+
GX_SetDispCopySrc(0, 0, vmode->fbWidth, vmode->efbHeight);
158+
GX_SetDispCopyDst(vmode->fbWidth, vmode->xfbHeight);
159+
GX_SetDispCopyYScale((f32)vmode->xfbHeight / (f32)vmode->efbHeight);
160+
GX_SetCopyFilter(vmode->aa, vmode->sample_pattern, GX_FALSE, vmode->vfilter);
161+
GX_SetFieldMode(vmode->field_rendering,
162+
((vmode->viHeight == 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
163+
164+
OGC_draw_init(vmode->fbWidth, vmode->efbHeight);
165+
}
166+
167+
static int OGC_SetDisplayMode(_THIS, SDL_VideoDisplay *display,
168+
SDL_DisplayMode *mode)
169+
{
170+
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
171+
/* The GX video mode is stored in the driverdata pointer */
172+
GXRModeObj *vmode = mode->driverdata;
173+
174+
if (videodata->xfb[0])
175+
free(MEM_K1_TO_K0(videodata->xfb[0]));
176+
if (videodata->xfb[1])
177+
free(MEM_K1_TO_K0(videodata->xfb[1]));
178+
179+
setup_video_mode(_this, vmode);
180+
return 0;
181+
}
182+
50183
static void OGC_ShowWindow(_THIS, SDL_Window *window)
51184
{
52185
SDL_SetMouseFocus(window);
@@ -85,6 +218,7 @@ static SDL_VideoDevice *OGC_CreateDevice(void)
85218
/* Set the function pointers */
86219
device->VideoInit = OGC_VideoInit;
87220
device->VideoQuit = OGC_VideoQuit;
221+
device->SetDisplayMode = OGC_SetDisplayMode;
88222
device->PumpEvents = OGC_PumpEvents;
89223
device->ShowWindow = OGC_ShowWindow;
90224
device->CreateWindowFramebuffer = SDL_OGC_CreateWindowFramebuffer;
@@ -111,52 +245,29 @@ int OGC_VideoInit(_THIS)
111245
VIDEO_Init();
112246

113247
vmode = VIDEO_GetPreferredMode(NULL);
114-
VIDEO_Configure(vmode);
115-
116-
/* Allocate the XFB */
117-
videodata->xfb[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
118-
videodata->xfb[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
119-
120-
VIDEO_ClearFrameBuffer(vmode, videodata->xfb[0], COLOR_BLACK);
121-
VIDEO_SetNextFramebuffer(videodata->xfb[0]);
122-
VIDEO_SetBlack(false);
123-
VIDEO_Flush();
124248

125249
videodata->gp_fifo = memalign(32, DEFAULT_FIFO_SIZE);
126250
memset(videodata->gp_fifo, 0, DEFAULT_FIFO_SIZE);
127251
GX_Init(videodata->gp_fifo, DEFAULT_FIFO_SIZE);
128252

129-
/* Setup the EFB -> XFB copy operation */
130-
GX_SetDispCopySrc(0, 0, vmode->fbWidth, vmode->efbHeight);
131-
GX_SetDispCopyDst(vmode->fbWidth, vmode->xfbHeight);
132-
GX_SetDispCopyYScale((f32)vmode->xfbHeight / (f32)vmode->efbHeight);
133-
GX_SetCopyFilter(vmode->aa, vmode->sample_pattern, GX_FALSE, vmode->vfilter);
253+
setup_video_mode(_this, vmode);
134254
GX_SetCopyClear(background, GX_MAX_Z24);
135255

136-
GX_SetFieldMode(vmode->field_rendering,
137-
((vmode->viHeight == 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
138256
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
139257
GX_SetCullMode(GX_CULL_NONE);
140258
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
141259

142260
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
143261

144-
OGC_draw_init(vmode->fbWidth, vmode->efbHeight);
145-
146262
GX_Flush();
147263

148-
/* Use a fake 32-bpp desktop mode */
149-
SDL_zero(mode);
150-
mode.format = SDL_PIXELFORMAT_ARGB8888;
151-
mode.w = vmode->fbWidth;
152-
mode.h = vmode->efbHeight;
153-
mode.refresh_rate = 60;
154-
mode.driverdata = NULL;
264+
init_display_mode(&mode, vmode);
155265
if (SDL_AddBasicVideoDisplay(&mode) < 0) {
156266
return -1;
157267
}
158268

159269
SDL_AddDisplayMode(&_this->displays[0], &mode);
270+
add_supported_modes(&_this->displays[0], VI_FORMAT_FROM_MODE(vmode->viTVMode));
160271

161272
videodata->vmode = vmode;
162273

@@ -169,6 +280,7 @@ int OGC_VideoInit(_THIS)
169280
void OGC_VideoQuit(_THIS)
170281
{
171282
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
283+
SDL_VideoDisplay *display;
172284

173285
#ifdef __wii__
174286
OGC_QuitMouse(_this);
@@ -179,6 +291,15 @@ void OGC_VideoQuit(_THIS)
179291
free(MEM_K1_TO_K0(videodata->xfb[0]));
180292
if (videodata->xfb[1])
181293
free(MEM_K1_TO_K0(videodata->xfb[1]));
294+
295+
/* During shutdown, SDL_ResetDisplayModes() will be called and will invoke
296+
* SDL_free() on driverdata. Nullify the pointers in order to avoid a
297+
* crash, since we didn't actually allocate this memory. */
298+
display = &_this->displays[0];
299+
for (int i = display->num_display_modes; i--;) {
300+
display->display_modes[i].driverdata = NULL;
301+
}
302+
display->desktop_mode.driverdata = NULL;
182303
}
183304

184305
void *OGC_video_get_xfb(_THIS)

0 commit comments

Comments
 (0)