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