Rice Video Plugin for GLES1.1
[mupen64plus-pandora.git] / source / rice_gles / src / Video.cpp
CommitLineData
d07c171f 1/*
2Copyright (C) 2002 Rice1964
3Copyright (C) 2009-2011 Richard Goedeken
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include <vector>
22
23#include <stdarg.h>
24
25#include "osal_opengl.h"
26
27#define M64P_PLUGIN_PROTOTYPES 1
28#include "m64p_types.h"
29#include "m64p_common.h"
30#include "m64p_plugin.h"
31#include "osal_dynamiclib.h"
32
33#include "Config.h"
34#include "Debugger.h"
35#include "DeviceBuilder.h"
36#include "FrameBuffer.h"
37#include "GraphicsContext.h"
38#include "Render.h"
39#include "RSP_Parser.h"
40#include "TextureFilters.h"
41#include "TextureManager.h"
42#include "Video.h"
43#include "version.h"
44
45//=======================================================
46// local variables
47
48static void (*l_DebugCallback)(void *, int, const char *) = NULL;
49static void *l_DebugCallContext = NULL;
50static int l_PluginInit = 0;
51
52//=======================================================
53// global variables
54
55PluginStatus status;
56GFX_INFO g_GraphicsInfo;
57CCritSect g_CritialSection;
58
59unsigned int g_dwRamSize = 0x400000;
60unsigned int *g_pRDRAMu32 = NULL;
61signed char *g_pRDRAMs8 = NULL;
62unsigned char *g_pRDRAMu8 = NULL;
63
64RECT frameWriteByCPURect;
65std::vector<RECT> frameWriteByCPURects;
66RECT frameWriteByCPURectArray[20][20];
67bool frameWriteByCPURectFlag[20][20];
68std::vector<uint32> frameWriteRecord;
69
70void (*renderCallback)(int) = NULL;
71
72/* definitions of pointers to Core config functions */
73ptr_ConfigOpenSection ConfigOpenSection = NULL;
74ptr_ConfigSetParameter ConfigSetParameter = NULL;
75ptr_ConfigGetParameter ConfigGetParameter = NULL;
76ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
77ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
78ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
79ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
80ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
81ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
82ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
83ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
84ptr_ConfigGetParamString ConfigGetParamString = NULL;
85
86ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
87ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
88ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
89ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL;
90
91/* definitions of pointers to Core video extension functions */
92ptr_VidExt_Init CoreVideo_Init = NULL;
93ptr_VidExt_Quit CoreVideo_Quit = NULL;
94ptr_VidExt_ListFullscreenModes CoreVideo_ListFullscreenModes = NULL;
95ptr_VidExt_SetVideoMode CoreVideo_SetVideoMode = NULL;
96ptr_VidExt_SetCaption CoreVideo_SetCaption = NULL;
97ptr_VidExt_ToggleFullScreen CoreVideo_ToggleFullScreen = NULL;
98ptr_VidExt_ResizeWindow CoreVideo_ResizeWindow = NULL;
99ptr_VidExt_GL_GetProcAddress CoreVideo_GL_GetProcAddress = NULL;
100ptr_VidExt_GL_SetAttribute CoreVideo_GL_SetAttribute = NULL;
101ptr_VidExt_GL_GetAttribute CoreVideo_GL_GetAttribute = NULL;
102ptr_VidExt_GL_SwapBuffers CoreVideo_GL_SwapBuffers = NULL;
103
104// For Fameskip
105float mspervi = 1000.0f/60.0f; //default is shortest frame
106float numvi = 0.0f;
107
108
109//---------------------------------------------------------------------------------------
110// Forward function declarations
111
112extern "C" EXPORT void CALL RomClosed(void);
113
114//---------------------------------------------------------------------------------------
115// Static (local) functions
116static void ChangeWindowStep2()
117{
118 status.bDisableFPS = true;
119 windowSetting.bDisplayFullscreen = !windowSetting.bDisplayFullscreen;
120 g_CritialSection.Lock();
121 windowSetting.bDisplayFullscreen = CGraphicsContext::Get()->ToggleFullscreen();
122
123 CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER);
124 CGraphicsContext::Get()->UpdateFrame();
125 CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER);
126 CGraphicsContext::Get()->UpdateFrame();
127 CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER);
128 CGraphicsContext::Get()->UpdateFrame();
129 g_CritialSection.Unlock();
130 status.bDisableFPS = false;
131 status.ToToggleFullScreen = FALSE;
132}
133
134static void ResizeStep2(void)
135{
136 g_CritialSection.Lock();
137
138 // Delete all OpenGL textures
139 gTextureManager.CleanUp();
140 RDP_Cleanup();
141 // delete our opengl renderer
142 CDeviceBuilder::GetBuilder()->DeleteRender();
143
144 // call video extension function with updated width, height (this creates a new OpenGL context)
145 windowSetting.uDisplayWidth = status.gNewResizeWidth;
146 windowSetting.uDisplayHeight = status.gNewResizeHeight;
147 CoreVideo_ResizeWindow(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight);
148
149 // re-initialize our OpenGL graphics context state
150 bool res = CGraphicsContext::Get()->ResizeInitialize(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, !windowSetting.bDisplayFullscreen);
151 if (res)
152 {
153 // re-create the OpenGL renderer
154 CDeviceBuilder::GetBuilder()->CreateRender();
155 CRender::GetRender()->Initialize();
156 DLParser_Init();
157 }
158
159 g_CritialSection.Unlock();
160 status.ToResize = false;
161}
162
163static void UpdateScreenStep2 (void)
164{
165 status.bVIOriginIsUpdated = false;
166
167 if( status.ToToggleFullScreen && status.gDlistCount > 0 )
168 {
169 ChangeWindowStep2();
170 return;
171 }
172 if (status.ToResize && status.gDlistCount > 0)
173 {
174 ResizeStep2();
175 return;
176 }
177
178 g_CritialSection.Lock();
179
180 //framskip, count vi
181 numvi++;
182
183 if( status.bHandleN64RenderTexture )
184 g_pFrameBufferManager->CloseRenderTexture(true);
185
186 g_pFrameBufferManager->SetAddrBeDisplayed(*g_GraphicsInfo.VI_ORIGIN_REG);
187
188 if( status.gDlistCount == 0 )
189 {
190 // CPU frame buffer update
191 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG;
192 if( (*g_GraphicsInfo.VI_ORIGIN_REG & (g_dwRamSize-1) ) > width*2 && *g_GraphicsInfo.VI_H_START_REG != 0 && width != 0 )
193 {
194 SetVIScales();
195 CRender::GetRender()->DrawFrameBuffer(true);
196 CGraphicsContext::Get()->UpdateFrame();
197 }
198 g_CritialSection.Unlock();
199 return;
200 }
201
202 TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG));
203
204 if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE )
205 {
206 CGraphicsContext::Get()->UpdateFrame();
207
208 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
209 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
210 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
211 g_CritialSection.Unlock();
212 return;
213 }
214
215 TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG));
216
217 if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN )
218 {
219 if( status.bScreenIsDrawn )
220 {
221 CGraphicsContext::Get()->UpdateFrame();
222 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
223 }
224 else
225 {
226 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Skip Screen Update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
227 }
228
229 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
230 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
231 g_CritialSection.Unlock();
232 return;
233 }
234
235 if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_VI_CHANGE )
236 {
237
238 if( *g_GraphicsInfo.VI_ORIGIN_REG != status.curVIOriginReg )
239 {
240 if( *g_GraphicsInfo.VI_ORIGIN_REG < status.curDisplayBuffer || *g_GraphicsInfo.VI_ORIGIN_REG > status.curDisplayBuffer+0x2000 )
241 {
242 status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG;
243 status.curVIOriginReg = status.curDisplayBuffer;
244 //status.curRenderBuffer = NULL;
245
246 CGraphicsContext::Get()->UpdateFrame();
247 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
248 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
249 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
250 }
251 else
252 {
253 status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG;
254 status.curVIOriginReg = status.curDisplayBuffer;
255 DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, closed to the display buffer, VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);});
256 }
257 }
258 else
259 {
260 DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, the same VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);});
261 }
262
263 g_CritialSection.Unlock();
264 return;
265 }
266
267 if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_1ST_CI_CHANGE )
268 {
269 status.bVIOriginIsUpdated=true;
270 DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG);});
271 g_CritialSection.Unlock();
272 return;
273 }
274
275 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("VI is updated, No screen update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
276 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
277 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
278
279 g_CritialSection.Unlock();
280}
281
282static void ProcessDListStep2(void)
283{
284 g_CritialSection.Lock();
285 if( status.toShowCFB )
286 {
287 CRender::GetRender()->DrawFrameBuffer(true);
288 status.toShowCFB = false;
289 }
290
291 try
292 {
293 DLParser_Process((OSTask *)(g_GraphicsInfo.DMEM + 0x0FC0));
294 }
295 catch (...)
296 {
297 TRACE0("Unknown Error in ProcessDList");
298 TriggerDPInterrupt();
299 TriggerSPInterrupt();
300 }
301
302 g_CritialSection.Unlock();
303}
304
305static bool StartVideo(void)
306{
307 windowSetting.dps = windowSetting.fps = -1;
308 windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF;
309
310 g_CritialSection.Lock();
311
312 memcpy(&g_curRomInfo.romheader, g_GraphicsInfo.HEADER, sizeof(ROMHeader));
313 unsigned char *puc = (unsigned char *) &g_curRomInfo.romheader;
314 unsigned int i;
315 unsigned char temp;
316 for (i = 0; i < sizeof(ROMHeader); i += 4) /* byte-swap the ROM header */
317 {
318 temp = puc[i];
319 puc[i] = puc[i+3];
320 puc[i+3] = temp;
321 temp = puc[i+1];
322 puc[i+1] = puc[i+2];
323 puc[i+2] = temp;
324 }
325
326 ROM_GetRomNameFromHeader(g_curRomInfo.szGameName, &g_curRomInfo.romheader);
327 Ini_GetRomOptions(&g_curRomInfo);
328 char *p = (char *) g_curRomInfo.szGameName + (strlen((char *) g_curRomInfo.szGameName) -1); // -1 to skip null
329 while (p >= (char *) g_curRomInfo.szGameName)
330 {
331 if( *p == ':' || *p == '\\' || *p == '/' )
332 *p = '-';
333 p--;
334 }
335 GenerateCurrentRomOptions();
336 status.dwTvSystem = CountryCodeToTVSystem(g_curRomInfo.romheader.nCountryID);
337 if( status.dwTvSystem == TV_SYSTEM_NTSC ) {
338 status.fRatio = 0.75f;
339 mspervi=1000.0f/60.0f; //for framskipping
340 } else {
341 status.fRatio = 9/11.0f;
342 mspervi=1000.0f/50.0f;
343 }
344printf("TV system=%s, ms per VI=%f\n", (status.dwTvSystem==TV_SYSTEM_NTSC)?"NTSC":"PAL", mspervi);
345 InitExternalTextures();
346
347 try {
348 CDeviceBuilder::GetBuilder()->CreateGraphicsContext();
349 CGraphicsContext::InitWindowInfo();
350printf("bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen);\n");
351 bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen);
352 if (!res)
353 {
354printf("!res\n");
355 g_CritialSection.Unlock();
356 return false;
357 }
358 CDeviceBuilder::GetBuilder()->CreateRender();
359 CRender::GetRender()->Initialize();
360 DLParser_Init();
361 status.bGameIsRunning = true;
362 }
363 catch(...)
364 {
365 DebugMessage(M64MSG_ERROR, "Exception caught while starting video renderer");
366 throw 0;
367 }
368printf("VideoInit finished\n");
369 g_CritialSection.Unlock();
370 return true;
371}
372
373static void StopVideo()
374{
375 g_CritialSection.Lock();
376 status.bGameIsRunning = false;
377
378 try {
379 CloseExternalTextures();
380
381 // Kill all textures?
382 gTextureManager.RecycleAllTextures();
383 gTextureManager.CleanUp();
384 RDP_Cleanup();
385
386 CDeviceBuilder::GetBuilder()->DeleteRender();
387 CGraphicsContext::Get()->CleanUp();
388 CDeviceBuilder::GetBuilder()->DeleteGraphicsContext();
389 }
390 catch(...)
391 {
392 TRACE0("Some exceptions during RomClosed");
393 }
394
395 g_CritialSection.Unlock();
396 windowSetting.dps = windowSetting.fps = -1;
397 windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF;
398 status.gDlistCount = status.gFrameCount = 0;
399
400}
401
402//---------------------------------------------------------------------------------------
403// Global functions, for use by other source files in this plugin
404
405void SetVIScales()
406{
407 if( g_curRomInfo.VIHeight>0 && g_curRomInfo.VIWidth>0 )
408 {
409 windowSetting.fViWidth = windowSetting.uViWidth = g_curRomInfo.VIWidth;
410 windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.VIHeight;
411 }
412 else if( g_curRomInfo.UseCIWidthAndRatio && g_CI.dwWidth )
413 {
414 windowSetting.fViWidth = windowSetting.uViWidth = g_CI.dwWidth;
415 windowSetting.fViHeight = windowSetting.uViHeight =
416 g_curRomInfo.UseCIWidthAndRatio == USE_CI_WIDTH_AND_RATIO_FOR_NTSC ? g_CI.dwWidth/4*3 : g_CI.dwWidth/11*9;
417 }
418 else
419 {
420 float xscale, yscale;
421 uint32 val = *g_GraphicsInfo.VI_X_SCALE_REG & 0xFFF;
422 xscale = (float)val / (1<<10);
423 uint32 start = *g_GraphicsInfo.VI_H_START_REG >> 16;
424 uint32 end = *g_GraphicsInfo.VI_H_START_REG&0xFFFF;
425 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG;
426 windowSetting.fViWidth = (end-start)*xscale;
427 if( abs((int)(windowSetting.fViWidth - width) ) < 8 )
428 {
429 windowSetting.fViWidth = (float)width;
430 }
431 else
432 {
433 DebuggerAppendMsg("fViWidth = %f, Width Reg=%d", windowSetting.fViWidth, width);
434 }
435
436 val = (*g_GraphicsInfo.VI_Y_SCALE_REG & 0xFFF);// - ((*g_GraphicsInfo.VI_Y_SCALE_REG>>16) & 0xFFF);
437 if( val == 0x3FF ) val = 0x400;
438 yscale = (float)val / (1<<10);
439 start = *g_GraphicsInfo.VI_V_START_REG >> 16;
440 end = *g_GraphicsInfo.VI_V_START_REG&0xFFFF;
441 windowSetting.fViHeight = (end-start)/2*yscale;
442
443 if( yscale == 0 )
444 {
445 windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio;
446 }
447 else
448 {
449 if( *g_GraphicsInfo.VI_WIDTH_REG > 0x300 )
450 windowSetting.fViHeight *= 2;
451
452 if( windowSetting.fViWidth*status.fRatio > windowSetting.fViHeight && (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0 )
453 {
454 if( abs(int(windowSetting.fViWidth*status.fRatio - windowSetting.fViHeight)) < 8 )
455 {
456 windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio;
457 }
458 /*
459 else
460 {
461 if( abs(windowSetting.fViWidth*status.fRatio-windowSetting.fViHeight) > windowSetting.fViWidth*0.1f )
462 {
463 if( status.fRatio > 0.8 )
464 windowSetting.fViHeight = windowSetting.fViWidth*3/4;
465 //windowSetting.fViHeight = (*g_GraphicsInfo.VI_V_SYNC_REG - 0x2C)/2;
466 }
467 }
468 */
469 }
470
471 if( windowSetting.fViHeight<100 || windowSetting.fViWidth<100 )
472 {
473 //At sometime, value in VI_H_START_REG or VI_V_START_REG are 0
474 windowSetting.fViWidth = (float)*g_GraphicsInfo.VI_WIDTH_REG;
475 windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio;
476 }
477 }
478
479 windowSetting.uViWidth = (unsigned short)(windowSetting.fViWidth/4);
480 windowSetting.fViWidth = windowSetting.uViWidth *= 4;
481
482 windowSetting.uViHeight = (unsigned short)(windowSetting.fViHeight/4);
483 windowSetting.fViHeight = windowSetting.uViHeight *= 4;
484 uint16 optimizeHeight = (uint16)(windowSetting.uViWidth*status.fRatio);
485 optimizeHeight &= ~3;
486
487 uint16 optimizeHeight2 = (uint16)(windowSetting.uViWidth*3/4);
488 optimizeHeight2 &= ~3;
489
490 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
491 {
492 if( abs(windowSetting.uViHeight-optimizeHeight) <= 8 )
493 windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight;
494 else if( abs(windowSetting.uViHeight-optimizeHeight2) <= 8 )
495 windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight2;
496 }
497
498
499 if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && gRDP.scissor.right != 0 )
500 {
501 if( (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0x0 && gRDP.scissor.right == windowSetting.uViWidth )
502 {
503 // Mario Tennis
504 if( abs(int( windowSetting.fViHeight - gRDP.scissor.bottom )) < 8 )
505 {
506 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
507 }
508 else if( windowSetting.fViHeight < gRDP.scissor.bottom )
509 {
510 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
511 }
512 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
513 }
514 else if( gRDP.scissor.right == windowSetting.uViWidth - 1 && gRDP.scissor.bottom != 0 )
515 {
516 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
517 {
518 if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 )
519 {
520 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1;
521 }
522 }
523 }
524 else if( gRDP.scissor.right == windowSetting.uViWidth && gRDP.scissor.bottom != 0 && status.fRatio != 0.75 )
525 {
526 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
527 {
528 if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 )
529 {
530 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1;
531 }
532 }
533 }
534 }
535 }
536 SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight);
537}
538
539void TriggerDPInterrupt(void)
540{
541 *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_DP;
542 g_GraphicsInfo.CheckInterrupts();
543}
544
545void TriggerSPInterrupt(void)
546{
547 *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_SP;
548 g_GraphicsInfo.CheckInterrupts();
549}
550
551void _VIDEO_DisplayTemporaryMessage(const char *Message)
552{
553}
554
555void DebugMessage(int level, const char *message, ...)
556{
557 char msgbuf[1024];
558 va_list args;
559
560 if (l_DebugCallback == NULL)
561 return;
562
563 va_start(args, message);
564 vsprintf(msgbuf, message, args);
565
566 (*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
567
568 va_end(args);
569}
570
571//---------------------------------------------------------------------------------------
572// Global functions, exported for use by the core library
573
574// since these functions are exported, they need to have C-style names
575#ifdef __cplusplus
576extern "C" {
577#endif
578
579/* Mupen64Plus plugin functions */
580EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
581 void (*DebugCallback)(void *, int, const char *))
582{
583 if (l_PluginInit)
584 return M64ERR_ALREADY_INIT;
585
586 /* first thing is to set the callback function for debug info */
587 l_DebugCallback = DebugCallback;
588 l_DebugCallContext = Context;
589
590 /* attach and call the CoreGetAPIVersions function, check Config and Video Extension API versions for compatibility */
591 ptr_CoreGetAPIVersions CoreAPIVersionFunc;
592 CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
593 if (CoreAPIVersionFunc == NULL)
594 {
595 DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
596 return M64ERR_INCOMPATIBLE;
597 }
598 int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
599 (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
600 if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
601 {
602 DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
603 VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
604 return M64ERR_INCOMPATIBLE;
605 }
606 if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000))
607 {
608 DebugMessage(M64MSG_ERROR, "Emulator core Video Extension API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
609 VERSION_PRINTF_SPLIT(VidextAPIVersion), VERSION_PRINTF_SPLIT(VIDEXT_API_VERSION));
610 return M64ERR_INCOMPATIBLE;
611 }
612
613 /* Get the core config function pointers from the library handle */
614 ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
615 ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
616 ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
617 ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
618 ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
619 ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
620 ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
621 ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
622 ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
623 ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
624 ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
625
626 ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath");
627 ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath");
628 ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath");
629 ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath");
630
631 if (!ConfigOpenSection || !ConfigSetParameter || !ConfigGetParameter ||
632 !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
633 !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
634 !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
635 {
636 DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions");
637 return M64ERR_INCOMPATIBLE;
638 }
639
640 /* Get the core Video Extension function pointers from the library handle */
641 CoreVideo_Init = (ptr_VidExt_Init) osal_dynlib_getproc(CoreLibHandle, "VidExt_Init");
642 CoreVideo_Quit = (ptr_VidExt_Quit) osal_dynlib_getproc(CoreLibHandle, "VidExt_Quit");
643 CoreVideo_ListFullscreenModes = (ptr_VidExt_ListFullscreenModes) osal_dynlib_getproc(CoreLibHandle, "VidExt_ListFullscreenModes");
644 CoreVideo_SetVideoMode = (ptr_VidExt_SetVideoMode) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetVideoMode");
645 CoreVideo_SetCaption = (ptr_VidExt_SetCaption) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetCaption");
646 CoreVideo_ToggleFullScreen = (ptr_VidExt_ToggleFullScreen) osal_dynlib_getproc(CoreLibHandle, "VidExt_ToggleFullScreen");
647 CoreVideo_ResizeWindow = (ptr_VidExt_ResizeWindow) osal_dynlib_getproc(CoreLibHandle, "VidExt_ResizeWindow");
648 CoreVideo_GL_GetProcAddress = (ptr_VidExt_GL_GetProcAddress) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetProcAddress");
649 CoreVideo_GL_SetAttribute = (ptr_VidExt_GL_SetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SetAttribute");
650 CoreVideo_GL_GetAttribute = (ptr_VidExt_GL_GetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetAttribute");
651 CoreVideo_GL_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers");
652
653 if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode ||
654 !CoreVideo_ResizeWindow || !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_GL_GetProcAddress ||
655 !CoreVideo_GL_SetAttribute || !CoreVideo_GL_GetAttribute || !CoreVideo_GL_SwapBuffers)
656 {
657 DebugMessage(M64MSG_ERROR, "Couldn't connect to Core video extension functions");
658 return M64ERR_INCOMPATIBLE;
659 }
660
661 /* open config section handles and set parameter default values */
662 if (!InitConfiguration())
663 return M64ERR_INTERNAL;
664
665 l_PluginInit = 1;
666 return M64ERR_SUCCESS;
667}
668
669EXPORT m64p_error CALL PluginShutdown(void)
670{
671 if (!l_PluginInit)
672 return M64ERR_NOT_INIT;
673
674 if( status.bGameIsRunning )
675 {
676 RomClosed();
677 }
678 if (bIniIsChanged)
679 {
680 WriteIniFile();
681 TRACE0("Write back INI file");
682 }
683
684 /* reset some local variables */
685 l_DebugCallback = NULL;
686 l_DebugCallContext = NULL;
687
688 l_PluginInit = 0;
689 return M64ERR_SUCCESS;
690}
691
692EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
693{
694 /* set version info */
695 if (PluginType != NULL)
696 *PluginType = M64PLUGIN_GFX;
697
698 if (PluginVersion != NULL)
699 *PluginVersion = PLUGIN_VERSION;
700
701 if (APIVersion != NULL)
702 *APIVersion = VIDEO_PLUGIN_API_VERSION;
703
704 if (PluginNamePtr != NULL)
705 *PluginNamePtr = PLUGIN_NAME;
706
707 if (Capabilities != NULL)
708 {
709 *Capabilities = 0;
710 }
711
712 return M64ERR_SUCCESS;
713}
714
715//-------------------------------------------------------------------------------------
716
717
718EXPORT void CALL ChangeWindow (void)
719{
720 if( status.ToToggleFullScreen )
721 status.ToToggleFullScreen = FALSE;
722 else
723 status.ToToggleFullScreen = TRUE;
724}
725
726//---------------------------------------------------------------------------------------
727
728EXPORT void CALL MoveScreen (int xpos, int ypos)
729{
730}
731
732//---------------------------------------------------------------------------------------
733EXPORT void CALL RomClosed(void)
734{
735 TRACE0("To stop video");
736 Ini_StoreRomOptions(&g_curRomInfo);
737 StopVideo();
738 TRACE0("Video is stopped");
739}
740
741EXPORT int CALL RomOpen(void)
742{
743 /* Read RiceVideoLinux.ini file, set up internal variables by reading values from core configuration API */
744 LoadConfiguration();
745
746 if( g_CritialSection.IsLocked() )
747 {
748 g_CritialSection.Unlock();
749 TRACE0("g_CritialSection is locked when game is starting, unlock it now.");
750 }
751 status.bDisableFPS=false;
752
753 g_dwRamSize = 0x800000;
754
755#ifdef DEBUGGER
756 if( debuggerPause )
757 {
758 debuggerPause = FALSE;
759 usleep(100 * 1000);
760 }
761#endif
762
763 if (!StartVideo())
764 return 0;
765
766 return 1;
767}
768
769
770//---------------------------------------------------------------------------------------
771EXPORT void CALL UpdateScreen(void)
772{
773 if(options.bShowFPS)
774 {
775 static unsigned int lastTick=0;
776 static int frames=0;
777 unsigned int nowTick = SDL_GetTicks();
778 frames++;
779 if(lastTick + 5000 <= nowTick)
780 {
781 char caption[200];
782 sprintf(caption, "%s v%i.%i.%i - %.3f VI/S", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION), frames/5.0);
783 CoreVideo_SetCaption(caption);
784 frames = 0;
785 lastTick = nowTick;
786 }
787 }
788 UpdateScreenStep2();
789}
790
791//---------------------------------------------------------------------------------------
792
793EXPORT void CALL ViStatusChanged(void)
794{
795 g_CritialSection.Lock();
796 SetVIScales();
797 CRender::g_pRender->UpdateClipRectangle();
798 g_CritialSection.Unlock();
799}
800
801//---------------------------------------------------------------------------------------
802EXPORT void CALL ViWidthChanged(void)
803{
804 g_CritialSection.Lock();
805 SetVIScales();
806 CRender::g_pRender->UpdateClipRectangle();
807 g_CritialSection.Unlock();
808}
809
810EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info)
811{
812 memset(&status, 0, sizeof(status));
813 memcpy(&g_GraphicsInfo, &Gfx_Info, sizeof(GFX_INFO));
814
815 g_pRDRAMu8 = Gfx_Info.RDRAM;
816 g_pRDRAMu32 = (uint32*)Gfx_Info.RDRAM;
817 g_pRDRAMs8 = (signed char *)Gfx_Info.RDRAM;
818
819 windowSetting.fViWidth = 320;
820 windowSetting.fViHeight = 240;
821 status.ToToggleFullScreen = FALSE;
822 status.ToResize = false;
823 status.bDisableFPS=false;
824
825 if (!InitConfiguration())
826 {
827 DebugMessage(M64MSG_ERROR, "Failed to read configuration data");
828 return FALSE;
829 }
830
831 CGraphicsContext::InitWindowInfo();
832 CGraphicsContext::InitDeviceParameters();
833
834 return(TRUE);
835}
836
837EXPORT void CALL ResizeVideoOutput(int width, int height)
838{
839 // save the new window resolution. actual resizing operation is asynchronous (it happens later)
840 status.gNewResizeWidth = width;
841 status.gNewResizeHeight = height;
842 status.ToResize = true;
843}
844
845//---------------------------------------------------------------------------------------
846
847EXPORT void CALL ProcessRDPList(void)
848{
849 try
850 {
851 RDP_DLParser_Process();
852 }
853 catch (...)
854 {
855 TRACE0("Unknown Error in ProcessRDPList");
856 TriggerDPInterrupt();
857 TriggerSPInterrupt();
858 }
859}
860
861EXPORT void CALL ProcessDList(void)
862{
863 ProcessDListStep2();
864}
865
866//---------------------------------------------------------------------------------------
867
868/******************************************************************
869 Function: FrameBufferRead
870 Purpose: This function is called to notify the dll that the
871 frame buffer memory is beening read at the given address.
872 DLL should copy content from its render buffer to the frame buffer
873 in N64 RDRAM
874 DLL is responsible to maintain its own frame buffer memory addr list
875 DLL should copy 4KB block content back to RDRAM frame buffer.
876 Emulator should not call this function again if other memory
877 is read within the same 4KB range
878
879 Since depth buffer is also being watched, the reported addr
880 may belong to depth buffer
881 input: addr rdram address
882 val val
883 size 1 = uint8, 2 = uint16, 4 = uint32
884 output: none
885*******************************************************************/
886
887EXPORT void CALL FBRead(uint32 addr)
888{
889 g_pFrameBufferManager->FrameBufferReadByCPU(addr);
890}
891
892
893/******************************************************************
894 Function: FrameBufferWrite
895 Purpose: This function is called to notify the dll that the
896 frame buffer has been modified by CPU at the given address.
897
898 Since depth buffer is also being watched, the reported addr
899 may belong to depth buffer
900
901 input: addr rdram address
902 val val
903 size 1 = uint8, 2 = uint16, 4 = uint32
904 output: none
905*******************************************************************/
906
907EXPORT void CALL FBWrite(uint32 addr, uint32 size)
908{
909 g_pFrameBufferManager->FrameBufferWriteByCPU(addr, size);
910}
911
912/************************************************************************
913Function: FBGetFrameBufferInfo
914Purpose: This function is called by the emulator core to retrieve frame
915 buffer information from the video plugin in order to be able
916 to notify the video plugin about CPU frame buffer read/write
917 operations
918
919 size:
920 = 1 byte
921 = 2 word (16 bit) <-- this is N64 default depth buffer format
922 = 4 dword (32 bit)
923
924 when frame buffer information is not available yet, set all values
925 in the FrameBufferInfo structure to 0
926
927input: FrameBufferInfo pinfo[6]
928 pinfo is pointed to a FrameBufferInfo structure which to be
929 filled in by this function
930output: Values are return in the FrameBufferInfo structure
931 Plugin can return up to 6 frame buffer info
932 ************************************************************************/
933
934EXPORT void CALL FBGetFrameBufferInfo(void *p)
935{
936 FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
937 memset(pinfo,0,sizeof(FrameBufferInfo)*6);
938
939 //if( g_ZI.dwAddr == 0 )
940 //{
941 // memset(pinfo,0,sizeof(FrameBufferInfo)*6);
942 //}
943 //else
944 {
945 for (int i=0; i<5; i++ )
946 {
947 if( status.gDlistCount-g_RecentCIInfo[i].lastUsedFrame > 30 || g_RecentCIInfo[i].lastUsedFrame == 0 )
948 {
949 //memset(&pinfo[i],0,sizeof(FrameBufferInfo));
950 }
951 else
952 {
953 pinfo[i].addr = g_RecentCIInfo[i].dwAddr;
954 pinfo[i].size = 2;
955 pinfo[i].width = g_RecentCIInfo[i].dwWidth;
956 pinfo[i].height = g_RecentCIInfo[i].dwHeight;
957 TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", g_RecentCIInfo[i].dwAddr, g_RecentCIInfo[i].dwWidth, g_RecentCIInfo[i].dwHeight));
958 pinfo[5].width = g_RecentCIInfo[i].dwWidth;
959 pinfo[5].height = g_RecentCIInfo[i].dwHeight;
960 }
961 }
962
963 pinfo[5].addr = g_ZI.dwAddr;
964 //pinfo->size = g_RecentCIInfo[5].dwSize;
965 pinfo[5].size = 2;
966 TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", pinfo[5].addr, pinfo[5].width, pinfo[5].height));
967 }
968}
969
970// Plugin spec 1.3 functions
971EXPORT void CALL ShowCFB(void)
972{
973 status.toShowCFB = true;
974}
975
976//void ReadScreen2( void *dest, int *width, int *height, int bFront )
977EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int bFront)
978{
979 if (width == NULL || height == NULL)
980 return;
981
982 *width = windowSetting.uDisplayWidth;
983 *height = windowSetting.uDisplayHeight;
984
985 if (dest == NULL)
986 return;
987
988#if SDL_VIDEO_OPENGL
989#ifndef HAVE_GLES
990//*TODO*, what's the use of this function ? *SEB*
991 GLint oldMode;
992 glGetIntegerv( GL_READ_BUFFER, &oldMode );
993 if (bFront)
994 glReadBuffer( GL_FRONT );
995 else
996 glReadBuffer( GL_BACK );
997 glReadPixels( 0, 0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight,
998 GL_RGB, GL_UNSIGNED_BYTE, dest );
999 glReadBuffer( oldMode );
1000#endif
1001#endif
1002}
1003
1004
1005EXPORT void CALL SetRenderingCallback(void (*callback)(int))
1006{
1007 renderCallback = callback;
1008}
1009
1010#ifdef __cplusplus
1011}
1012#endif
1013