X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Frice_gles%2Fsrc%2FVideo.cpp;fp=source%2Frice_gles%2Fsrc%2FVideo.cpp;h=9c75859afba196cdcb54c78615b82efe11db71de;hb=d07c171fa694cae985ad7045f9ce2b2f1a5699b4;hp=0000000000000000000000000000000000000000;hpb=ca22e7b76883b946060a6b40bb8709c1981e1cf6;p=mupen64plus-pandora.git diff --git a/source/rice_gles/src/Video.cpp b/source/rice_gles/src/Video.cpp new file mode 100755 index 0000000..9c75859 --- /dev/null +++ b/source/rice_gles/src/Video.cpp @@ -0,0 +1,1013 @@ +/* +Copyright (C) 2002 Rice1964 +Copyright (C) 2009-2011 Richard Goedeken + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include + +#include "osal_opengl.h" + +#define M64P_PLUGIN_PROTOTYPES 1 +#include "m64p_types.h" +#include "m64p_common.h" +#include "m64p_plugin.h" +#include "osal_dynamiclib.h" + +#include "Config.h" +#include "Debugger.h" +#include "DeviceBuilder.h" +#include "FrameBuffer.h" +#include "GraphicsContext.h" +#include "Render.h" +#include "RSP_Parser.h" +#include "TextureFilters.h" +#include "TextureManager.h" +#include "Video.h" +#include "version.h" + +//======================================================= +// local variables + +static void (*l_DebugCallback)(void *, int, const char *) = NULL; +static void *l_DebugCallContext = NULL; +static int l_PluginInit = 0; + +//======================================================= +// global variables + +PluginStatus status; +GFX_INFO g_GraphicsInfo; +CCritSect g_CritialSection; + +unsigned int g_dwRamSize = 0x400000; +unsigned int *g_pRDRAMu32 = NULL; +signed char *g_pRDRAMs8 = NULL; +unsigned char *g_pRDRAMu8 = NULL; + +RECT frameWriteByCPURect; +std::vector frameWriteByCPURects; +RECT frameWriteByCPURectArray[20][20]; +bool frameWriteByCPURectFlag[20][20]; +std::vector frameWriteRecord; + +void (*renderCallback)(int) = NULL; + +/* definitions of pointers to Core config functions */ +ptr_ConfigOpenSection ConfigOpenSection = NULL; +ptr_ConfigSetParameter ConfigSetParameter = NULL; +ptr_ConfigGetParameter ConfigGetParameter = NULL; +ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL; +ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL; +ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL; +ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL; +ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL; +ptr_ConfigGetParamInt ConfigGetParamInt = NULL; +ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL; +ptr_ConfigGetParamBool ConfigGetParamBool = NULL; +ptr_ConfigGetParamString ConfigGetParamString = NULL; + +ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL; +ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL; +ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL; +ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL; + +/* definitions of pointers to Core video extension functions */ +ptr_VidExt_Init CoreVideo_Init = NULL; +ptr_VidExt_Quit CoreVideo_Quit = NULL; +ptr_VidExt_ListFullscreenModes CoreVideo_ListFullscreenModes = NULL; +ptr_VidExt_SetVideoMode CoreVideo_SetVideoMode = NULL; +ptr_VidExt_SetCaption CoreVideo_SetCaption = NULL; +ptr_VidExt_ToggleFullScreen CoreVideo_ToggleFullScreen = NULL; +ptr_VidExt_ResizeWindow CoreVideo_ResizeWindow = NULL; +ptr_VidExt_GL_GetProcAddress CoreVideo_GL_GetProcAddress = NULL; +ptr_VidExt_GL_SetAttribute CoreVideo_GL_SetAttribute = NULL; +ptr_VidExt_GL_GetAttribute CoreVideo_GL_GetAttribute = NULL; +ptr_VidExt_GL_SwapBuffers CoreVideo_GL_SwapBuffers = NULL; + +// For Fameskip +float mspervi = 1000.0f/60.0f; //default is shortest frame +float numvi = 0.0f; + + +//--------------------------------------------------------------------------------------- +// Forward function declarations + +extern "C" EXPORT void CALL RomClosed(void); + +//--------------------------------------------------------------------------------------- +// Static (local) functions +static void ChangeWindowStep2() +{ + status.bDisableFPS = true; + windowSetting.bDisplayFullscreen = !windowSetting.bDisplayFullscreen; + g_CritialSection.Lock(); + windowSetting.bDisplayFullscreen = CGraphicsContext::Get()->ToggleFullscreen(); + + CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); + CGraphicsContext::Get()->UpdateFrame(); + CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); + CGraphicsContext::Get()->UpdateFrame(); + CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); + CGraphicsContext::Get()->UpdateFrame(); + g_CritialSection.Unlock(); + status.bDisableFPS = false; + status.ToToggleFullScreen = FALSE; +} + +static void ResizeStep2(void) +{ + g_CritialSection.Lock(); + + // Delete all OpenGL textures + gTextureManager.CleanUp(); + RDP_Cleanup(); + // delete our opengl renderer + CDeviceBuilder::GetBuilder()->DeleteRender(); + + // call video extension function with updated width, height (this creates a new OpenGL context) + windowSetting.uDisplayWidth = status.gNewResizeWidth; + windowSetting.uDisplayHeight = status.gNewResizeHeight; + CoreVideo_ResizeWindow(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); + + // re-initialize our OpenGL graphics context state + bool res = CGraphicsContext::Get()->ResizeInitialize(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, !windowSetting.bDisplayFullscreen); + if (res) + { + // re-create the OpenGL renderer + CDeviceBuilder::GetBuilder()->CreateRender(); + CRender::GetRender()->Initialize(); + DLParser_Init(); + } + + g_CritialSection.Unlock(); + status.ToResize = false; +} + +static void UpdateScreenStep2 (void) +{ + status.bVIOriginIsUpdated = false; + + if( status.ToToggleFullScreen && status.gDlistCount > 0 ) + { + ChangeWindowStep2(); + return; + } + if (status.ToResize && status.gDlistCount > 0) + { + ResizeStep2(); + return; + } + + g_CritialSection.Lock(); + + //framskip, count vi + numvi++; + + if( status.bHandleN64RenderTexture ) + g_pFrameBufferManager->CloseRenderTexture(true); + + g_pFrameBufferManager->SetAddrBeDisplayed(*g_GraphicsInfo.VI_ORIGIN_REG); + + if( status.gDlistCount == 0 ) + { + // CPU frame buffer update + uint32 width = *g_GraphicsInfo.VI_WIDTH_REG; + if( (*g_GraphicsInfo.VI_ORIGIN_REG & (g_dwRamSize-1) ) > width*2 && *g_GraphicsInfo.VI_H_START_REG != 0 && width != 0 ) + { + SetVIScales(); + CRender::GetRender()->DrawFrameBuffer(true); + CGraphicsContext::Get()->UpdateFrame(); + } + g_CritialSection.Unlock(); + return; + } + + TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG)); + + if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE ) + { + CGraphicsContext::Get()->UpdateFrame(); + + DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); + DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); + DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); + g_CritialSection.Unlock(); + return; + } + + TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG)); + + if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN ) + { + if( status.bScreenIsDrawn ) + { + CGraphicsContext::Get()->UpdateFrame(); + DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); + } + else + { + DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Skip Screen Update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); + } + + DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); + DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); + g_CritialSection.Unlock(); + return; + } + + if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_VI_CHANGE ) + { + + if( *g_GraphicsInfo.VI_ORIGIN_REG != status.curVIOriginReg ) + { + if( *g_GraphicsInfo.VI_ORIGIN_REG < status.curDisplayBuffer || *g_GraphicsInfo.VI_ORIGIN_REG > status.curDisplayBuffer+0x2000 ) + { + status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG; + status.curVIOriginReg = status.curDisplayBuffer; + //status.curRenderBuffer = NULL; + + CGraphicsContext::Get()->UpdateFrame(); + DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); + DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); + DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); + } + else + { + status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG; + status.curVIOriginReg = status.curDisplayBuffer; + DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, closed to the display buffer, VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); + } + } + else + { + DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, the same VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); + } + + g_CritialSection.Unlock(); + return; + } + + if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_1ST_CI_CHANGE ) + { + status.bVIOriginIsUpdated=true; + DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); + g_CritialSection.Unlock(); + return; + } + + DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("VI is updated, No screen update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); + DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); + DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); + + g_CritialSection.Unlock(); +} + +static void ProcessDListStep2(void) +{ + g_CritialSection.Lock(); + if( status.toShowCFB ) + { + CRender::GetRender()->DrawFrameBuffer(true); + status.toShowCFB = false; + } + + try + { + DLParser_Process((OSTask *)(g_GraphicsInfo.DMEM + 0x0FC0)); + } + catch (...) + { + TRACE0("Unknown Error in ProcessDList"); + TriggerDPInterrupt(); + TriggerSPInterrupt(); + } + + g_CritialSection.Unlock(); +} + +static bool StartVideo(void) +{ + windowSetting.dps = windowSetting.fps = -1; + windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF; + + g_CritialSection.Lock(); + + memcpy(&g_curRomInfo.romheader, g_GraphicsInfo.HEADER, sizeof(ROMHeader)); + unsigned char *puc = (unsigned char *) &g_curRomInfo.romheader; + unsigned int i; + unsigned char temp; + for (i = 0; i < sizeof(ROMHeader); i += 4) /* byte-swap the ROM header */ + { + temp = puc[i]; + puc[i] = puc[i+3]; + puc[i+3] = temp; + temp = puc[i+1]; + puc[i+1] = puc[i+2]; + puc[i+2] = temp; + } + + ROM_GetRomNameFromHeader(g_curRomInfo.szGameName, &g_curRomInfo.romheader); + Ini_GetRomOptions(&g_curRomInfo); + char *p = (char *) g_curRomInfo.szGameName + (strlen((char *) g_curRomInfo.szGameName) -1); // -1 to skip null + while (p >= (char *) g_curRomInfo.szGameName) + { + if( *p == ':' || *p == '\\' || *p == '/' ) + *p = '-'; + p--; + } + GenerateCurrentRomOptions(); + status.dwTvSystem = CountryCodeToTVSystem(g_curRomInfo.romheader.nCountryID); + if( status.dwTvSystem == TV_SYSTEM_NTSC ) { + status.fRatio = 0.75f; + mspervi=1000.0f/60.0f; //for framskipping + } else { + status.fRatio = 9/11.0f; + mspervi=1000.0f/50.0f; + } +printf("TV system=%s, ms per VI=%f\n", (status.dwTvSystem==TV_SYSTEM_NTSC)?"NTSC":"PAL", mspervi); + InitExternalTextures(); + + try { + CDeviceBuilder::GetBuilder()->CreateGraphicsContext(); + CGraphicsContext::InitWindowInfo(); +printf("bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen);\n"); + bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen); + if (!res) + { +printf("!res\n"); + g_CritialSection.Unlock(); + return false; + } + CDeviceBuilder::GetBuilder()->CreateRender(); + CRender::GetRender()->Initialize(); + DLParser_Init(); + status.bGameIsRunning = true; + } + catch(...) + { + DebugMessage(M64MSG_ERROR, "Exception caught while starting video renderer"); + throw 0; + } +printf("VideoInit finished\n"); + g_CritialSection.Unlock(); + return true; +} + +static void StopVideo() +{ + g_CritialSection.Lock(); + status.bGameIsRunning = false; + + try { + CloseExternalTextures(); + + // Kill all textures? + gTextureManager.RecycleAllTextures(); + gTextureManager.CleanUp(); + RDP_Cleanup(); + + CDeviceBuilder::GetBuilder()->DeleteRender(); + CGraphicsContext::Get()->CleanUp(); + CDeviceBuilder::GetBuilder()->DeleteGraphicsContext(); + } + catch(...) + { + TRACE0("Some exceptions during RomClosed"); + } + + g_CritialSection.Unlock(); + windowSetting.dps = windowSetting.fps = -1; + windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF; + status.gDlistCount = status.gFrameCount = 0; + +} + +//--------------------------------------------------------------------------------------- +// Global functions, for use by other source files in this plugin + +void SetVIScales() +{ + if( g_curRomInfo.VIHeight>0 && g_curRomInfo.VIWidth>0 ) + { + windowSetting.fViWidth = windowSetting.uViWidth = g_curRomInfo.VIWidth; + windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.VIHeight; + } + else if( g_curRomInfo.UseCIWidthAndRatio && g_CI.dwWidth ) + { + windowSetting.fViWidth = windowSetting.uViWidth = g_CI.dwWidth; + windowSetting.fViHeight = windowSetting.uViHeight = + g_curRomInfo.UseCIWidthAndRatio == USE_CI_WIDTH_AND_RATIO_FOR_NTSC ? g_CI.dwWidth/4*3 : g_CI.dwWidth/11*9; + } + else + { + float xscale, yscale; + uint32 val = *g_GraphicsInfo.VI_X_SCALE_REG & 0xFFF; + xscale = (float)val / (1<<10); + uint32 start = *g_GraphicsInfo.VI_H_START_REG >> 16; + uint32 end = *g_GraphicsInfo.VI_H_START_REG&0xFFFF; + uint32 width = *g_GraphicsInfo.VI_WIDTH_REG; + windowSetting.fViWidth = (end-start)*xscale; + if( abs((int)(windowSetting.fViWidth - width) ) < 8 ) + { + windowSetting.fViWidth = (float)width; + } + else + { + DebuggerAppendMsg("fViWidth = %f, Width Reg=%d", windowSetting.fViWidth, width); + } + + val = (*g_GraphicsInfo.VI_Y_SCALE_REG & 0xFFF);// - ((*g_GraphicsInfo.VI_Y_SCALE_REG>>16) & 0xFFF); + if( val == 0x3FF ) val = 0x400; + yscale = (float)val / (1<<10); + start = *g_GraphicsInfo.VI_V_START_REG >> 16; + end = *g_GraphicsInfo.VI_V_START_REG&0xFFFF; + windowSetting.fViHeight = (end-start)/2*yscale; + + if( yscale == 0 ) + { + windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; + } + else + { + if( *g_GraphicsInfo.VI_WIDTH_REG > 0x300 ) + windowSetting.fViHeight *= 2; + + if( windowSetting.fViWidth*status.fRatio > windowSetting.fViHeight && (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0 ) + { + if( abs(int(windowSetting.fViWidth*status.fRatio - windowSetting.fViHeight)) < 8 ) + { + windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; + } + /* + else + { + if( abs(windowSetting.fViWidth*status.fRatio-windowSetting.fViHeight) > windowSetting.fViWidth*0.1f ) + { + if( status.fRatio > 0.8 ) + windowSetting.fViHeight = windowSetting.fViWidth*3/4; + //windowSetting.fViHeight = (*g_GraphicsInfo.VI_V_SYNC_REG - 0x2C)/2; + } + } + */ + } + + if( windowSetting.fViHeight<100 || windowSetting.fViWidth<100 ) + { + //At sometime, value in VI_H_START_REG or VI_V_START_REG are 0 + windowSetting.fViWidth = (float)*g_GraphicsInfo.VI_WIDTH_REG; + windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; + } + } + + windowSetting.uViWidth = (unsigned short)(windowSetting.fViWidth/4); + windowSetting.fViWidth = windowSetting.uViWidth *= 4; + + windowSetting.uViHeight = (unsigned short)(windowSetting.fViHeight/4); + windowSetting.fViHeight = windowSetting.uViHeight *= 4; + uint16 optimizeHeight = (uint16)(windowSetting.uViWidth*status.fRatio); + optimizeHeight &= ~3; + + uint16 optimizeHeight2 = (uint16)(windowSetting.uViWidth*3/4); + optimizeHeight2 &= ~3; + + if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) + { + if( abs(windowSetting.uViHeight-optimizeHeight) <= 8 ) + windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight; + else if( abs(windowSetting.uViHeight-optimizeHeight2) <= 8 ) + windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight2; + } + + + if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && gRDP.scissor.right != 0 ) + { + if( (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0x0 && gRDP.scissor.right == windowSetting.uViWidth ) + { + // Mario Tennis + if( abs(int( windowSetting.fViHeight - gRDP.scissor.bottom )) < 8 ) + { + windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; + } + else if( windowSetting.fViHeight < gRDP.scissor.bottom ) + { + windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; + } + windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; + } + else if( gRDP.scissor.right == windowSetting.uViWidth - 1 && gRDP.scissor.bottom != 0 ) + { + if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) + { + if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 ) + { + windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1; + } + } + } + else if( gRDP.scissor.right == windowSetting.uViWidth && gRDP.scissor.bottom != 0 && status.fRatio != 0.75 ) + { + if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) + { + if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 ) + { + windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1; + } + } + } + } + } + SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight); +} + +void TriggerDPInterrupt(void) +{ + *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_DP; + g_GraphicsInfo.CheckInterrupts(); +} + +void TriggerSPInterrupt(void) +{ + *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_SP; + g_GraphicsInfo.CheckInterrupts(); +} + +void _VIDEO_DisplayTemporaryMessage(const char *Message) +{ +} + +void DebugMessage(int level, const char *message, ...) +{ + char msgbuf[1024]; + va_list args; + + if (l_DebugCallback == NULL) + return; + + va_start(args, message); + vsprintf(msgbuf, message, args); + + (*l_DebugCallback)(l_DebugCallContext, level, msgbuf); + + va_end(args); +} + +//--------------------------------------------------------------------------------------- +// Global functions, exported for use by the core library + +// since these functions are exported, they need to have C-style names +#ifdef __cplusplus +extern "C" { +#endif + +/* Mupen64Plus plugin functions */ +EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, + void (*DebugCallback)(void *, int, const char *)) +{ + if (l_PluginInit) + return M64ERR_ALREADY_INIT; + + /* first thing is to set the callback function for debug info */ + l_DebugCallback = DebugCallback; + l_DebugCallContext = Context; + + /* attach and call the CoreGetAPIVersions function, check Config and Video Extension API versions for compatibility */ + ptr_CoreGetAPIVersions CoreAPIVersionFunc; + CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions"); + if (CoreAPIVersionFunc == NULL) + { + DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found."); + return M64ERR_INCOMPATIBLE; + } + int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion; + (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL); + if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000)) + { + DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", + VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION)); + return M64ERR_INCOMPATIBLE; + } + if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000)) + { + DebugMessage(M64MSG_ERROR, "Emulator core Video Extension API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", + VERSION_PRINTF_SPLIT(VidextAPIVersion), VERSION_PRINTF_SPLIT(VIDEXT_API_VERSION)); + return M64ERR_INCOMPATIBLE; + } + + /* Get the core config function pointers from the library handle */ + ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection"); + ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter"); + ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter"); + ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt"); + ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat"); + ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool"); + ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString"); + ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt"); + ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat"); + ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool"); + ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString"); + + ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath"); + ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath"); + ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath"); + ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath"); + + if (!ConfigOpenSection || !ConfigSetParameter || !ConfigGetParameter || + !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString || + !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString || + !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath) + { + DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions"); + return M64ERR_INCOMPATIBLE; + } + + /* Get the core Video Extension function pointers from the library handle */ + CoreVideo_Init = (ptr_VidExt_Init) osal_dynlib_getproc(CoreLibHandle, "VidExt_Init"); + CoreVideo_Quit = (ptr_VidExt_Quit) osal_dynlib_getproc(CoreLibHandle, "VidExt_Quit"); + CoreVideo_ListFullscreenModes = (ptr_VidExt_ListFullscreenModes) osal_dynlib_getproc(CoreLibHandle, "VidExt_ListFullscreenModes"); + CoreVideo_SetVideoMode = (ptr_VidExt_SetVideoMode) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetVideoMode"); + CoreVideo_SetCaption = (ptr_VidExt_SetCaption) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetCaption"); + CoreVideo_ToggleFullScreen = (ptr_VidExt_ToggleFullScreen) osal_dynlib_getproc(CoreLibHandle, "VidExt_ToggleFullScreen"); + CoreVideo_ResizeWindow = (ptr_VidExt_ResizeWindow) osal_dynlib_getproc(CoreLibHandle, "VidExt_ResizeWindow"); + CoreVideo_GL_GetProcAddress = (ptr_VidExt_GL_GetProcAddress) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetProcAddress"); + CoreVideo_GL_SetAttribute = (ptr_VidExt_GL_SetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SetAttribute"); + CoreVideo_GL_GetAttribute = (ptr_VidExt_GL_GetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetAttribute"); + CoreVideo_GL_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers"); + + if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode || + !CoreVideo_ResizeWindow || !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_GL_GetProcAddress || + !CoreVideo_GL_SetAttribute || !CoreVideo_GL_GetAttribute || !CoreVideo_GL_SwapBuffers) + { + DebugMessage(M64MSG_ERROR, "Couldn't connect to Core video extension functions"); + return M64ERR_INCOMPATIBLE; + } + + /* open config section handles and set parameter default values */ + if (!InitConfiguration()) + return M64ERR_INTERNAL; + + l_PluginInit = 1; + return M64ERR_SUCCESS; +} + +EXPORT m64p_error CALL PluginShutdown(void) +{ + if (!l_PluginInit) + return M64ERR_NOT_INIT; + + if( status.bGameIsRunning ) + { + RomClosed(); + } + if (bIniIsChanged) + { + WriteIniFile(); + TRACE0("Write back INI file"); + } + + /* reset some local variables */ + l_DebugCallback = NULL; + l_DebugCallContext = NULL; + + l_PluginInit = 0; + return M64ERR_SUCCESS; +} + +EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) +{ + /* set version info */ + if (PluginType != NULL) + *PluginType = M64PLUGIN_GFX; + + if (PluginVersion != NULL) + *PluginVersion = PLUGIN_VERSION; + + if (APIVersion != NULL) + *APIVersion = VIDEO_PLUGIN_API_VERSION; + + if (PluginNamePtr != NULL) + *PluginNamePtr = PLUGIN_NAME; + + if (Capabilities != NULL) + { + *Capabilities = 0; + } + + return M64ERR_SUCCESS; +} + +//------------------------------------------------------------------------------------- + + +EXPORT void CALL ChangeWindow (void) +{ + if( status.ToToggleFullScreen ) + status.ToToggleFullScreen = FALSE; + else + status.ToToggleFullScreen = TRUE; +} + +//--------------------------------------------------------------------------------------- + +EXPORT void CALL MoveScreen (int xpos, int ypos) +{ +} + +//--------------------------------------------------------------------------------------- +EXPORT void CALL RomClosed(void) +{ + TRACE0("To stop video"); + Ini_StoreRomOptions(&g_curRomInfo); + StopVideo(); + TRACE0("Video is stopped"); +} + +EXPORT int CALL RomOpen(void) +{ + /* Read RiceVideoLinux.ini file, set up internal variables by reading values from core configuration API */ + LoadConfiguration(); + + if( g_CritialSection.IsLocked() ) + { + g_CritialSection.Unlock(); + TRACE0("g_CritialSection is locked when game is starting, unlock it now."); + } + status.bDisableFPS=false; + + g_dwRamSize = 0x800000; + +#ifdef DEBUGGER + if( debuggerPause ) + { + debuggerPause = FALSE; + usleep(100 * 1000); + } +#endif + + if (!StartVideo()) + return 0; + + return 1; +} + + +//--------------------------------------------------------------------------------------- +EXPORT void CALL UpdateScreen(void) +{ + if(options.bShowFPS) + { + static unsigned int lastTick=0; + static int frames=0; + unsigned int nowTick = SDL_GetTicks(); + frames++; + if(lastTick + 5000 <= nowTick) + { + char caption[200]; + sprintf(caption, "%s v%i.%i.%i - %.3f VI/S", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION), frames/5.0); + CoreVideo_SetCaption(caption); + frames = 0; + lastTick = nowTick; + } + } + UpdateScreenStep2(); +} + +//--------------------------------------------------------------------------------------- + +EXPORT void CALL ViStatusChanged(void) +{ + g_CritialSection.Lock(); + SetVIScales(); + CRender::g_pRender->UpdateClipRectangle(); + g_CritialSection.Unlock(); +} + +//--------------------------------------------------------------------------------------- +EXPORT void CALL ViWidthChanged(void) +{ + g_CritialSection.Lock(); + SetVIScales(); + CRender::g_pRender->UpdateClipRectangle(); + g_CritialSection.Unlock(); +} + +EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info) +{ + memset(&status, 0, sizeof(status)); + memcpy(&g_GraphicsInfo, &Gfx_Info, sizeof(GFX_INFO)); + + g_pRDRAMu8 = Gfx_Info.RDRAM; + g_pRDRAMu32 = (uint32*)Gfx_Info.RDRAM; + g_pRDRAMs8 = (signed char *)Gfx_Info.RDRAM; + + windowSetting.fViWidth = 320; + windowSetting.fViHeight = 240; + status.ToToggleFullScreen = FALSE; + status.ToResize = false; + status.bDisableFPS=false; + + if (!InitConfiguration()) + { + DebugMessage(M64MSG_ERROR, "Failed to read configuration data"); + return FALSE; + } + + CGraphicsContext::InitWindowInfo(); + CGraphicsContext::InitDeviceParameters(); + + return(TRUE); +} + +EXPORT void CALL ResizeVideoOutput(int width, int height) +{ + // save the new window resolution. actual resizing operation is asynchronous (it happens later) + status.gNewResizeWidth = width; + status.gNewResizeHeight = height; + status.ToResize = true; +} + +//--------------------------------------------------------------------------------------- + +EXPORT void CALL ProcessRDPList(void) +{ + try + { + RDP_DLParser_Process(); + } + catch (...) + { + TRACE0("Unknown Error in ProcessRDPList"); + TriggerDPInterrupt(); + TriggerSPInterrupt(); + } +} + +EXPORT void CALL ProcessDList(void) +{ + ProcessDListStep2(); +} + +//--------------------------------------------------------------------------------------- + +/****************************************************************** + Function: FrameBufferRead + Purpose: This function is called to notify the dll that the + frame buffer memory is beening read at the given address. + DLL should copy content from its render buffer to the frame buffer + in N64 RDRAM + DLL is responsible to maintain its own frame buffer memory addr list + DLL should copy 4KB block content back to RDRAM frame buffer. + Emulator should not call this function again if other memory + is read within the same 4KB range + + Since depth buffer is also being watched, the reported addr + may belong to depth buffer + input: addr rdram address + val val + size 1 = uint8, 2 = uint16, 4 = uint32 + output: none +*******************************************************************/ + +EXPORT void CALL FBRead(uint32 addr) +{ + g_pFrameBufferManager->FrameBufferReadByCPU(addr); +} + + +/****************************************************************** + Function: FrameBufferWrite + Purpose: This function is called to notify the dll that the + frame buffer has been modified by CPU at the given address. + + Since depth buffer is also being watched, the reported addr + may belong to depth buffer + + input: addr rdram address + val val + size 1 = uint8, 2 = uint16, 4 = uint32 + output: none +*******************************************************************/ + +EXPORT void CALL FBWrite(uint32 addr, uint32 size) +{ + g_pFrameBufferManager->FrameBufferWriteByCPU(addr, size); +} + +/************************************************************************ +Function: FBGetFrameBufferInfo +Purpose: This function is called by the emulator core to retrieve frame + buffer information from the video plugin in order to be able + to notify the video plugin about CPU frame buffer read/write + operations + + size: + = 1 byte + = 2 word (16 bit) <-- this is N64 default depth buffer format + = 4 dword (32 bit) + + when frame buffer information is not available yet, set all values + in the FrameBufferInfo structure to 0 + +input: FrameBufferInfo pinfo[6] + pinfo is pointed to a FrameBufferInfo structure which to be + filled in by this function +output: Values are return in the FrameBufferInfo structure + Plugin can return up to 6 frame buffer info + ************************************************************************/ + +EXPORT void CALL FBGetFrameBufferInfo(void *p) +{ + FrameBufferInfo * pinfo = (FrameBufferInfo *)p; + memset(pinfo,0,sizeof(FrameBufferInfo)*6); + + //if( g_ZI.dwAddr == 0 ) + //{ + // memset(pinfo,0,sizeof(FrameBufferInfo)*6); + //} + //else + { + for (int i=0; i<5; i++ ) + { + if( status.gDlistCount-g_RecentCIInfo[i].lastUsedFrame > 30 || g_RecentCIInfo[i].lastUsedFrame == 0 ) + { + //memset(&pinfo[i],0,sizeof(FrameBufferInfo)); + } + else + { + pinfo[i].addr = g_RecentCIInfo[i].dwAddr; + pinfo[i].size = 2; + pinfo[i].width = g_RecentCIInfo[i].dwWidth; + pinfo[i].height = g_RecentCIInfo[i].dwHeight; + TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", g_RecentCIInfo[i].dwAddr, g_RecentCIInfo[i].dwWidth, g_RecentCIInfo[i].dwHeight)); + pinfo[5].width = g_RecentCIInfo[i].dwWidth; + pinfo[5].height = g_RecentCIInfo[i].dwHeight; + } + } + + pinfo[5].addr = g_ZI.dwAddr; + //pinfo->size = g_RecentCIInfo[5].dwSize; + pinfo[5].size = 2; + TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", pinfo[5].addr, pinfo[5].width, pinfo[5].height)); + } +} + +// Plugin spec 1.3 functions +EXPORT void CALL ShowCFB(void) +{ + status.toShowCFB = true; +} + +//void ReadScreen2( void *dest, int *width, int *height, int bFront ) +EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int bFront) +{ + if (width == NULL || height == NULL) + return; + + *width = windowSetting.uDisplayWidth; + *height = windowSetting.uDisplayHeight; + + if (dest == NULL) + return; + +#if SDL_VIDEO_OPENGL +#ifndef HAVE_GLES +//*TODO*, what's the use of this function ? *SEB* + GLint oldMode; + glGetIntegerv( GL_READ_BUFFER, &oldMode ); + if (bFront) + glReadBuffer( GL_FRONT ); + else + glReadBuffer( GL_BACK ); + glReadPixels( 0, 0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, + GL_RGB, GL_UNSIGNED_BYTE, dest ); + glReadBuffer( oldMode ); +#endif +#endif +} + + +EXPORT void CALL SetRenderingCallback(void (*callback)(int)) +{ + renderCallback = callback; +} + +#ifdef __cplusplus +} +#endif +