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 */
4779static int OGC_VideoInit (_THIS );
4880static 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+
50183static 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)
169280void 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
184305void * OGC_video_get_xfb (_THIS )
0 commit comments