Added missing launcher
[mupen64plus-pandora.git] / source / rice_gles / src / Video.cpp
1 /*
2 Copyright (C) 2002 Rice1964
3 Copyright (C) 2009-2011 Richard Goedeken
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 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
48 static void (*l_DebugCallback)(void *, int, const char *) = NULL;
49 static void *l_DebugCallContext = NULL;
50 static int l_PluginInit = 0;
51
52 //=======================================================
53 // global variables
54
55 PluginStatus  status;
56 GFX_INFO      g_GraphicsInfo;
57 CCritSect     g_CritialSection;
58
59 unsigned int   g_dwRamSize = 0x400000;
60 unsigned int  *g_pRDRAMu32 = NULL;
61 signed char   *g_pRDRAMs8 = NULL;
62 unsigned char *g_pRDRAMu8 = NULL;
63
64 RECT frameWriteByCPURect;
65 std::vector<RECT> frameWriteByCPURects;
66 RECT frameWriteByCPURectArray[20][20];
67 bool frameWriteByCPURectFlag[20][20];
68 std::vector<uint32> frameWriteRecord;
69
70 void (*renderCallback)(int) = NULL;
71
72 /* definitions of pointers to Core config functions */
73 ptr_ConfigOpenSection      ConfigOpenSection = NULL;
74 ptr_ConfigSetParameter     ConfigSetParameter = NULL;
75 ptr_ConfigGetParameter     ConfigGetParameter = NULL;
76 ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
77 ptr_ConfigSetDefaultInt    ConfigSetDefaultInt = NULL;
78 ptr_ConfigSetDefaultFloat  ConfigSetDefaultFloat = NULL;
79 ptr_ConfigSetDefaultBool   ConfigSetDefaultBool = NULL;
80 ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
81 ptr_ConfigGetParamInt      ConfigGetParamInt = NULL;
82 ptr_ConfigGetParamFloat    ConfigGetParamFloat = NULL;
83 ptr_ConfigGetParamBool     ConfigGetParamBool = NULL;
84 ptr_ConfigGetParamString   ConfigGetParamString = NULL;
85
86 ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
87 ptr_ConfigGetUserConfigPath     ConfigGetUserConfigPath = NULL;
88 ptr_ConfigGetUserDataPath       ConfigGetUserDataPath = NULL;
89 ptr_ConfigGetUserCachePath      ConfigGetUserCachePath = NULL;
90
91 /* definitions of pointers to Core video extension functions */
92 ptr_VidExt_Init                  CoreVideo_Init = NULL;
93 ptr_VidExt_Quit                  CoreVideo_Quit = NULL;
94 ptr_VidExt_ListFullscreenModes   CoreVideo_ListFullscreenModes = NULL;
95 ptr_VidExt_SetVideoMode          CoreVideo_SetVideoMode = NULL;
96 ptr_VidExt_SetCaption            CoreVideo_SetCaption = NULL;
97 ptr_VidExt_ToggleFullScreen      CoreVideo_ToggleFullScreen = NULL;
98 ptr_VidExt_ResizeWindow          CoreVideo_ResizeWindow = NULL;
99 ptr_VidExt_GL_GetProcAddress     CoreVideo_GL_GetProcAddress = NULL;
100 ptr_VidExt_GL_SetAttribute       CoreVideo_GL_SetAttribute = NULL;
101 ptr_VidExt_GL_GetAttribute       CoreVideo_GL_GetAttribute = NULL;
102 ptr_VidExt_GL_SwapBuffers        CoreVideo_GL_SwapBuffers = NULL;
103
104 // For Fameskip
105 float mspervi = 1000.0f/60.0f;  //default is shortest frame
106 float numvi = 0.0f;
107
108
109 //---------------------------------------------------------------------------------------
110 // Forward function declarations
111
112 extern "C" EXPORT void CALL RomClosed(void);
113
114 //---------------------------------------------------------------------------------------
115 // Static (local) functions
116 static 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
134 static 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
163 static 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
282 static 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
305 static 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     }
344 printf("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();
350 printf("bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen);\n");
351         bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen);
352         if (!res)
353         {
354 printf("!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     }
368 printf("VideoInit finished\n");
369     g_CritialSection.Unlock();
370     return true;
371 }
372
373 static 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
405 void 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
539 void TriggerDPInterrupt(void)
540 {
541     *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_DP;
542     g_GraphicsInfo.CheckInterrupts();
543 }
544
545 void TriggerSPInterrupt(void)
546 {
547     *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_SP;
548     g_GraphicsInfo.CheckInterrupts();
549 }
550
551 void _VIDEO_DisplayTemporaryMessage(const char *Message)
552 {
553 }
554
555 void 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
576 extern "C" {
577 #endif
578
579 /* Mupen64Plus plugin functions */
580 EXPORT 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
669 EXPORT 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
692 EXPORT 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
718 EXPORT void CALL ChangeWindow (void)
719 {
720     if( status.ToToggleFullScreen )
721         status.ToToggleFullScreen = FALSE;
722     else
723         status.ToToggleFullScreen = TRUE;
724 }
725
726 //---------------------------------------------------------------------------------------
727
728 EXPORT void CALL MoveScreen (int xpos, int ypos)
729
730 }
731
732 //---------------------------------------------------------------------------------------
733 EXPORT void CALL RomClosed(void)
734 {
735     TRACE0("To stop video");
736     Ini_StoreRomOptions(&g_curRomInfo);
737     StopVideo();
738     TRACE0("Video is stopped");
739 }
740
741 EXPORT 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 //---------------------------------------------------------------------------------------
771 EXPORT 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
793 EXPORT void CALL ViStatusChanged(void)
794 {
795     g_CritialSection.Lock();
796     SetVIScales();
797     CRender::g_pRender->UpdateClipRectangle();
798     g_CritialSection.Unlock();
799 }
800
801 //---------------------------------------------------------------------------------------
802 EXPORT void CALL ViWidthChanged(void)
803 {
804     g_CritialSection.Lock();
805     SetVIScales();
806     CRender::g_pRender->UpdateClipRectangle();
807     g_CritialSection.Unlock();
808 }
809
810 EXPORT 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
837 EXPORT 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
847 EXPORT 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
861 EXPORT 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
887 EXPORT 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
907 EXPORT void CALL FBWrite(uint32 addr, uint32 size)
908 {
909     g_pFrameBufferManager->FrameBufferWriteByCPU(addr, size);
910 }
911
912 /************************************************************************
913 Function: FBGetFrameBufferInfo
914 Purpose:  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
927 input:    FrameBufferInfo pinfo[6]
928           pinfo is pointed to a FrameBufferInfo structure which to be
929           filled in by this function
930 output:   Values are return in the FrameBufferInfo structure
931           Plugin can return up to 6 frame buffer info
932  ************************************************************************/
933
934 EXPORT 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
971 EXPORT void CALL ShowCFB(void)
972 {
973     status.toShowCFB = true;
974 }
975
976 //void ReadScreen2( void *dest, int *width, int *height, int bFront )
977 EXPORT 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
1005 EXPORT void CALL SetRenderingCallback(void (*callback)(int))
1006 {
1007     renderCallback = callback;
1008 }
1009
1010 #ifdef __cplusplus
1011 }
1012 #endif
1013