2 Copyright (C) 2002 Rice1964
3 Copyright (C) 2009-2011 Richard Goedeken
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.
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.
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.
25 #include "osal_opengl.h"
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"
35 #include "DeviceBuilder.h"
36 #include "FrameBuffer.h"
37 #include "GraphicsContext.h"
39 #include "RSP_Parser.h"
40 #include "TextureFilters.h"
41 #include "TextureManager.h"
45 //=======================================================
48 static void (*l_DebugCallback)(void *, int, const char *) = NULL;
49 static void *l_DebugCallContext = NULL;
50 static int l_PluginInit = 0;
52 //=======================================================
56 GFX_INFO g_GraphicsInfo;
57 CCritSect g_CritialSection;
59 unsigned int g_dwRamSize = 0x400000;
60 unsigned int *g_pRDRAMu32 = NULL;
61 signed char *g_pRDRAMs8 = NULL;
62 unsigned char *g_pRDRAMu8 = NULL;
64 RECT frameWriteByCPURect;
65 std::vector<RECT> frameWriteByCPURects;
66 RECT frameWriteByCPURectArray[20][20];
67 bool frameWriteByCPURectFlag[20][20];
68 std::vector<uint32> frameWriteRecord;
70 void (*renderCallback)(int) = NULL;
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;
86 ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
87 ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
88 ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
89 ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL;
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;
105 float mspervi = 1000.0f/60.0f; //default is shortest frame
107 bool skipping = false;
109 //---------------------------------------------------------------------------------------
110 // Forward function declarations
112 extern "C" EXPORT void CALL RomClosed(void);
114 //---------------------------------------------------------------------------------------
115 // Static (local) functions
116 static void ChangeWindowStep2()
118 status.bDisableFPS = true;
119 windowSetting.bDisplayFullscreen = !windowSetting.bDisplayFullscreen;
120 g_CritialSection.Lock();
121 windowSetting.bDisplayFullscreen = CGraphicsContext::Get()->ToggleFullscreen();
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;
134 static void ResizeStep2(void)
136 g_CritialSection.Lock();
138 // Delete all OpenGL textures
139 gTextureManager.CleanUp();
141 // delete our opengl renderer
142 CDeviceBuilder::GetBuilder()->DeleteRender();
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);
149 // re-initialize our OpenGL graphics context state
150 bool res = CGraphicsContext::Get()->ResizeInitialize(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, !windowSetting.bDisplayFullscreen);
153 // re-create the OpenGL renderer
154 CDeviceBuilder::GetBuilder()->CreateRender();
155 CRender::GetRender()->Initialize();
159 g_CritialSection.Unlock();
160 status.ToResize = false;
163 static void UpdateScreenStep2 (void)
165 status.bVIOriginIsUpdated = false;
167 if( status.ToToggleFullScreen && status.gDlistCount > 0 )
172 if (status.ToResize && status.gDlistCount > 0)
178 g_CritialSection.Lock();
183 if( status.bHandleN64RenderTexture )
184 g_pFrameBufferManager->CloseRenderTexture(true);
187 g_CritialSection.Unlock();
191 g_pFrameBufferManager->SetAddrBeDisplayed(*g_GraphicsInfo.VI_ORIGIN_REG);
193 if(status.gDlistCount == 0)
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 )
200 CRender::GetRender()->DrawFrameBuffer(true);
201 CGraphicsContext::Get()->UpdateFrame();
203 g_CritialSection.Unlock();
207 TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG));
209 if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE )
211 CGraphicsContext::Get()->UpdateFrame();
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();
220 TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG));
222 if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN )
224 if( status.bScreenIsDrawn )
226 CGraphicsContext::Get()->UpdateFrame();
227 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
231 DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Skip Screen Update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG));
234 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME);
235 DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG);
236 g_CritialSection.Unlock();
240 if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_VI_CHANGE )
243 if( *g_GraphicsInfo.VI_ORIGIN_REG != status.curVIOriginReg )
245 if( *g_GraphicsInfo.VI_ORIGIN_REG < status.curDisplayBuffer || *g_GraphicsInfo.VI_ORIGIN_REG > status.curDisplayBuffer+0x2000 )
247 status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG;
248 status.curVIOriginReg = status.curDisplayBuffer;
249 //status.curRenderBuffer = NULL;
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);
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);});
265 DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, the same VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);});
268 g_CritialSection.Unlock();
272 if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_1ST_CI_CHANGE )
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();
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);
284 g_CritialSection.Unlock();
287 static void ProcessDListStep2(void)
289 g_CritialSection.Lock();
290 if( status.toShowCFB )
292 CRender::GetRender()->DrawFrameBuffer(true);
293 status.toShowCFB = false;
298 DLParser_Process((OSTask *)(g_GraphicsInfo.DMEM + 0x0FC0));
302 TRACE0("Unknown Error in ProcessDList");
303 TriggerDPInterrupt();
304 TriggerSPInterrupt();
307 g_CritialSection.Unlock();
310 static bool StartVideo(void)
312 windowSetting.dps = windowSetting.fps = -1;
313 windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF;
315 g_CritialSection.Lock();
317 memcpy(&g_curRomInfo.romheader, g_GraphicsInfo.HEADER, sizeof(ROMHeader));
318 unsigned char *puc = (unsigned char *) &g_curRomInfo.romheader;
321 for (i = 0; i < sizeof(ROMHeader); i += 4) /* byte-swap the ROM header */
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)
336 if( *p == ':' || *p == '\\' || *p == '/' )
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
347 status.fRatio = 9/11.0f;
348 mspervi=1000.0f/50.0f; //for framskipping
351 InitExternalTextures();
354 CDeviceBuilder::GetBuilder()->CreateGraphicsContext();
355 CGraphicsContext::InitWindowInfo();
357 bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen);
360 g_CritialSection.Unlock();
363 CDeviceBuilder::GetBuilder()->CreateRender();
364 CRender::GetRender()->Initialize();
366 status.bGameIsRunning = true;
370 DebugMessage(M64MSG_ERROR, "Exception caught while starting video renderer");
374 g_CritialSection.Unlock();
378 static void StopVideo()
380 g_CritialSection.Lock();
381 status.bGameIsRunning = false;
384 CloseExternalTextures();
386 // Kill all textures?
387 gTextureManager.RecycleAllTextures();
388 gTextureManager.CleanUp();
391 CDeviceBuilder::GetBuilder()->DeleteRender();
392 CGraphicsContext::Get()->CleanUp();
393 CDeviceBuilder::GetBuilder()->DeleteGraphicsContext();
397 TRACE0("Some exceptions during RomClosed");
400 g_CritialSection.Unlock();
401 windowSetting.dps = windowSetting.fps = -1;
402 windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF;
403 status.gDlistCount = status.gFrameCount = 0;
407 //---------------------------------------------------------------------------------------
408 // Global functions, for use by other source files in this plugin
412 if( g_curRomInfo.VIHeight>0 && g_curRomInfo.VIWidth>0 )
414 windowSetting.fViWidth = windowSetting.uViWidth = g_curRomInfo.VIWidth;
415 windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.VIHeight;
417 else if( g_curRomInfo.UseCIWidthAndRatio && g_CI.dwWidth )
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;
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 )
434 windowSetting.fViWidth = (float)width;
438 DebuggerAppendMsg("fViWidth = %f, Width Reg=%d", windowSetting.fViWidth, width);
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;
450 windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio;
454 if( *g_GraphicsInfo.VI_WIDTH_REG > 0x300 )
455 windowSetting.fViHeight *= 2;
457 if( windowSetting.fViWidth*status.fRatio > windowSetting.fViHeight && (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0 )
459 if( abs(int(windowSetting.fViWidth*status.fRatio - windowSetting.fViHeight)) < 8 )
461 windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio;
466 if( abs(windowSetting.fViWidth*status.fRatio-windowSetting.fViHeight) > windowSetting.fViWidth*0.1f )
468 if( status.fRatio > 0.8 )
469 windowSetting.fViHeight = windowSetting.fViWidth*3/4;
470 //windowSetting.fViHeight = (*g_GraphicsInfo.VI_V_SYNC_REG - 0x2C)/2;
476 if( windowSetting.fViHeight<100 || windowSetting.fViWidth<100 )
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;
484 windowSetting.uViWidth = (unsigned short)(windowSetting.fViWidth/4);
485 windowSetting.fViWidth = windowSetting.uViWidth *= 4;
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;
492 uint16 optimizeHeight2 = (uint16)(windowSetting.uViWidth*3/4);
493 optimizeHeight2 &= ~3;
495 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
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;
504 if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && gRDP.scissor.right != 0 )
506 if( (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0x0 && gRDP.scissor.right == windowSetting.uViWidth )
509 if( abs(int( windowSetting.fViHeight - gRDP.scissor.bottom )) < 8 )
511 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
513 else if( windowSetting.fViHeight < gRDP.scissor.bottom )
515 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
517 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom;
519 else if( gRDP.scissor.right == windowSetting.uViWidth - 1 && gRDP.scissor.bottom != 0 )
521 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
523 if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 )
525 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1;
529 else if( gRDP.scissor.right == windowSetting.uViWidth && gRDP.scissor.bottom != 0 && status.fRatio != 0.75 )
531 if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 )
533 if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 )
535 windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1;
541 SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight);
544 void TriggerDPInterrupt(void)
546 *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_DP;
547 g_GraphicsInfo.CheckInterrupts();
550 void TriggerSPInterrupt(void)
552 *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_SP;
553 g_GraphicsInfo.CheckInterrupts();
556 void _VIDEO_DisplayTemporaryMessage(const char *Message)
560 void DebugMessage(int level, const char *message, ...)
565 if (l_DebugCallback == NULL)
568 va_start(args, message);
569 vsprintf(msgbuf, message, args);
571 (*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
576 //---------------------------------------------------------------------------------------
577 // Global functions, exported for use by the core library
579 // since these functions are exported, they need to have C-style names
584 /* Mupen64Plus plugin functions */
585 EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
586 void (*DebugCallback)(void *, int, const char *))
589 return M64ERR_ALREADY_INIT;
591 /* first thing is to set the callback function for debug info */
592 l_DebugCallback = DebugCallback;
593 l_DebugCallContext = Context;
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)
600 DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
601 return M64ERR_INCOMPATIBLE;
603 int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
604 (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
605 if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
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;
611 if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000))
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;
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");
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");
636 if (!ConfigOpenSection || !ConfigSetParameter || !ConfigGetParameter ||
637 !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
638 !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
639 !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
641 DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions");
642 return M64ERR_INCOMPATIBLE;
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");
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)
662 DebugMessage(M64MSG_ERROR, "Couldn't connect to Core video extension functions");
663 return M64ERR_INCOMPATIBLE;
666 /* open config section handles and set parameter default values */
667 if (!InitConfiguration())
668 return M64ERR_INTERNAL;
671 return M64ERR_SUCCESS;
674 EXPORT m64p_error CALL PluginShutdown(void)
677 return M64ERR_NOT_INIT;
679 if( status.bGameIsRunning )
686 TRACE0("Write back INI file");
689 /* reset some local variables */
690 l_DebugCallback = NULL;
691 l_DebugCallContext = NULL;
694 return M64ERR_SUCCESS;
697 EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
699 /* set version info */
700 if (PluginType != NULL)
701 *PluginType = M64PLUGIN_GFX;
703 if (PluginVersion != NULL)
704 *PluginVersion = PLUGIN_VERSION;
706 if (APIVersion != NULL)
707 *APIVersion = VIDEO_PLUGIN_API_VERSION;
709 if (PluginNamePtr != NULL)
710 *PluginNamePtr = PLUGIN_NAME;
712 if (Capabilities != NULL)
717 return M64ERR_SUCCESS;
720 //-------------------------------------------------------------------------------------
723 EXPORT void CALL ChangeWindow (void)
725 if( status.ToToggleFullScreen )
726 status.ToToggleFullScreen = FALSE;
728 status.ToToggleFullScreen = TRUE;
731 //---------------------------------------------------------------------------------------
733 EXPORT void CALL MoveScreen (int xpos, int ypos)
737 //---------------------------------------------------------------------------------------
738 EXPORT void CALL RomClosed(void)
740 TRACE0("To stop video");
741 Ini_StoreRomOptions(&g_curRomInfo);
743 TRACE0("Video is stopped");
746 EXPORT int CALL RomOpen(void)
748 /* Read RiceVideoLinux.ini file, set up internal variables by reading values from core configuration API */
751 if( g_CritialSection.IsLocked() )
753 g_CritialSection.Unlock();
754 TRACE0("g_CritialSection is locked when game is starting, unlock it now.");
756 status.bDisableFPS=false;
758 g_dwRamSize = 0x800000;
763 debuggerPause = FALSE;
775 //---------------------------------------------------------------------------------------
776 EXPORT void CALL UpdateScreen(void)
780 static unsigned int lastTick=0;
782 unsigned int nowTick = SDL_GetTicks();
784 if(lastTick + 5000 <= nowTick)
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);
796 //---------------------------------------------------------------------------------------
798 EXPORT void CALL ViStatusChanged(void)
800 g_CritialSection.Lock();
802 CRender::g_pRender->UpdateClipRectangle();
803 g_CritialSection.Unlock();
806 //---------------------------------------------------------------------------------------
807 EXPORT void CALL ViWidthChanged(void)
809 g_CritialSection.Lock();
811 CRender::g_pRender->UpdateClipRectangle();
812 g_CritialSection.Unlock();
815 EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info)
817 memset(&status, 0, sizeof(status));
818 memcpy(&g_GraphicsInfo, &Gfx_Info, sizeof(GFX_INFO));
820 g_pRDRAMu8 = Gfx_Info.RDRAM;
821 g_pRDRAMu32 = (uint32*)Gfx_Info.RDRAM;
822 g_pRDRAMs8 = (signed char *)Gfx_Info.RDRAM;
824 windowSetting.fViWidth = 320;
825 windowSetting.fViHeight = 240;
826 status.ToToggleFullScreen = FALSE;
827 status.ToResize = false;
828 status.bDisableFPS=false;
830 if (!InitConfiguration())
832 DebugMessage(M64MSG_ERROR, "Failed to read configuration data");
836 CGraphicsContext::InitWindowInfo();
837 CGraphicsContext::InitDeviceParameters();
842 EXPORT void CALL ResizeVideoOutput(int width, int height)
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;
850 //---------------------------------------------------------------------------------------
852 EXPORT void CALL ProcessRDPList(void)
856 RDP_DLParser_Process();
860 TRACE0("Unknown Error in ProcessRDPList");
861 TriggerDPInterrupt();
862 TriggerSPInterrupt();
866 EXPORT void CALL ProcessDList(void)
871 //---------------------------------------------------------------------------------------
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
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
884 Since depth buffer is also being watched, the reported addr
885 may belong to depth buffer
886 input: addr rdram address
888 size 1 = uint8, 2 = uint16, 4 = uint32
890 *******************************************************************/
892 EXPORT void CALL FBRead(uint32 addr)
894 g_pFrameBufferManager->FrameBufferReadByCPU(addr);
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.
903 Since depth buffer is also being watched, the reported addr
904 may belong to depth buffer
906 input: addr rdram address
908 size 1 = uint8, 2 = uint16, 4 = uint32
910 *******************************************************************/
912 EXPORT void CALL FBWrite(uint32 addr, uint32 size)
914 g_pFrameBufferManager->FrameBufferWriteByCPU(addr, size);
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
926 = 2 word (16 bit) <-- this is N64 default depth buffer format
929 when frame buffer information is not available yet, set all values
930 in the FrameBufferInfo structure to 0
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 ************************************************************************/
939 EXPORT void CALL FBGetFrameBufferInfo(void *p)
941 FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
942 memset(pinfo,0,sizeof(FrameBufferInfo)*6);
944 //if( g_ZI.dwAddr == 0 )
946 // memset(pinfo,0,sizeof(FrameBufferInfo)*6);
950 for (int i=0; i<5; i++ )
952 if( status.gDlistCount-g_RecentCIInfo[i].lastUsedFrame > 30 || g_RecentCIInfo[i].lastUsedFrame == 0 )
954 //memset(&pinfo[i],0,sizeof(FrameBufferInfo));
958 pinfo[i].addr = g_RecentCIInfo[i].dwAddr;
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;
968 pinfo[5].addr = g_ZI.dwAddr;
969 //pinfo->size = g_RecentCIInfo[5].dwSize;
971 TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", pinfo[5].addr, pinfo[5].width, pinfo[5].height));
975 // Plugin spec 1.3 functions
976 EXPORT void CALL ShowCFB(void)
978 status.toShowCFB = true;
981 //void ReadScreen2( void *dest, int *width, int *height, int bFront )
982 EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int bFront)
984 if (width == NULL || height == NULL)
987 *width = windowSetting.uDisplayWidth;
988 *height = windowSetting.uDisplayHeight;
995 glGetIntegerv( GL_READ_BUFFER, &oldMode );
997 glReadBuffer( GL_FRONT );
999 glReadBuffer( GL_BACK );
1000 glReadPixels( 0, 0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight,
1001 GL_RGB, GL_UNSIGNED_BYTE, dest );
1002 glReadBuffer( oldMode );
1007 EXPORT void CALL SetRenderingCallback(void (*callback)(int))
1009 renderCallback = callback;