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