X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Fmupen64plus-core%2Fsrc%2Fplugin%2Fplugin.c;fp=source%2Fmupen64plus-core%2Fsrc%2Fplugin%2Fplugin.c;h=ac4929af49e3f9cf3eab858998945a12a7ad65db;hb=451ab91e3827a6384981b3300e2a7000d2eaba58;hp=0000000000000000000000000000000000000000;hpb=a2ab25365b5b0dddbee476d695d8a31151407581;p=mupen64plus-pandora.git diff --git a/source/mupen64plus-core/src/plugin/plugin.c b/source/mupen64plus-core/src/plugin/plugin.c new file mode 100644 index 0000000..ac4929a --- /dev/null +++ b/source/mupen64plus-core/src/plugin/plugin.c @@ -0,0 +1,545 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - plugin.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2002 Hacktarux * + * Copyright (C) 2009 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "plugin.h" + +#include "api/callbacks.h" +#include "api/m64p_common.h" +#include "api/m64p_plugin.h" +#include "api/m64p_types.h" + +#include "main/rom.h" +#include "main/version.h" +#include "memory/memory.h" + +#include "osal/dynamiclib.h" + +#include "dummy_audio.h" +#include "dummy_video.h" +#include "dummy_input.h" +#include "dummy_rsp.h" + +CONTROL Controls[4]; + +/* global function pointers - initialized on core startup */ +gfx_plugin_functions gfx; +audio_plugin_functions audio; +input_plugin_functions input; +rsp_plugin_functions rsp; + +/* local data structures and functions */ +static const gfx_plugin_functions dummy_gfx = { + dummyvideo_PluginGetVersion, + dummyvideo_ChangeWindow, + dummyvideo_InitiateGFX, + dummyvideo_MoveScreen, + dummyvideo_ProcessDList, + dummyvideo_ProcessRDPList, + dummyvideo_RomClosed, + dummyvideo_RomOpen, + dummyvideo_ShowCFB, + dummyvideo_UpdateScreen, + dummyvideo_ViStatusChanged, + dummyvideo_ViWidthChanged, + dummyvideo_ReadScreen2, + dummyvideo_SetRenderingCallback, + dummyvideo_ResizeVideoOutput, + dummyvideo_FBRead, + dummyvideo_FBWrite, + dummyvideo_FBGetFrameBufferInfo +}; + +static const audio_plugin_functions dummy_audio = { + dummyaudio_PluginGetVersion, + dummyaudio_AiDacrateChanged, + dummyaudio_AiLenChanged, + dummyaudio_InitiateAudio, + dummyaudio_ProcessAList, + dummyaudio_RomClosed, + dummyaudio_RomOpen, + dummyaudio_SetSpeedFactor, + dummyaudio_VolumeUp, + dummyaudio_VolumeDown, + dummyaudio_VolumeGetLevel, + dummyaudio_VolumeSetLevel, + dummyaudio_VolumeMute, + dummyaudio_VolumeGetString +}; + +static const input_plugin_functions dummy_input = { + dummyinput_PluginGetVersion, + dummyinput_ControllerCommand, + dummyinput_GetKeys, + dummyinput_InitiateControllers, + dummyinput_ReadController, + dummyinput_RomClosed, + dummyinput_RomOpen, + dummyinput_SDL_KeyDown, + dummyinput_SDL_KeyUp +}; + +static const rsp_plugin_functions dummy_rsp = { + dummyrsp_PluginGetVersion, + dummyrsp_DoRspCycles, + dummyrsp_InitiateRSP, + dummyrsp_RomClosed +}; + +static GFX_INFO gfx_info; +static AUDIO_INFO audio_info; +static CONTROL_INFO control_info; +static RSP_INFO rsp_info; + +static int l_RspAttached = 0; +static int l_InputAttached = 0; +static int l_AudioAttached = 0; +static int l_GfxAttached = 0; + +static unsigned int dummy; + +/* local functions */ +static void EmptyFunc(void) +{ +} + +// Handy macro to avoid code bloat when loading symbols +#define GET_FUNC(type, field, name) \ + ((field = (type)osal_dynlib_getproc(plugin_handle, name)) != NULL) + +// code to handle backwards-compatibility to video plugins with API_VERSION < 02.1.0. This API version introduced a boolean +// flag in the rendering callback, which told the core whether or not the current screen has been freshly redrawn since the +// last time the callback was called. +static void (*l_mainRenderCallback)(int) = NULL; +static ptr_SetRenderingCallback l_old1SetRenderingCallback = NULL; + +static void backcompat_videoRenderCallback(int unused) // this function will be called by the video plugin as the render callback +{ + if (l_mainRenderCallback != NULL) + l_mainRenderCallback(1); // assume screen is always freshly redrawn (otherwise screenshots won't work w/ OSD enabled) +} + +static void backcompat_setRenderCallbackIntercept(void (*callback)(int)) +{ + l_mainRenderCallback = callback; +} + +static void plugin_disconnect_gfx(void) +{ + gfx = dummy_gfx; + l_GfxAttached = 0; + l_mainRenderCallback = NULL; +} + +static m64p_error plugin_connect_gfx(m64p_dynlib_handle plugin_handle) +{ + /* attach the Video plugin function pointers */ + if (plugin_handle != NULL) + { + m64p_plugin_type PluginType; + int PluginVersion, APIVersion; + + if (l_GfxAttached) + return M64ERR_INVALID_STATE; + + /* set function pointers for required functions */ + if (!GET_FUNC(ptr_PluginGetVersion, gfx.getVersion, "PluginGetVersion") || + !GET_FUNC(ptr_ChangeWindow, gfx.changeWindow, "ChangeWindow") || + !GET_FUNC(ptr_InitiateGFX, gfx.initiateGFX, "InitiateGFX") || + !GET_FUNC(ptr_MoveScreen, gfx.moveScreen, "MoveScreen") || + !GET_FUNC(ptr_ProcessDList, gfx.processDList, "ProcessDList") || + !GET_FUNC(ptr_ProcessRDPList, gfx.processRDPList, "ProcessRDPList") || + !GET_FUNC(ptr_RomClosed, gfx.romClosed, "RomClosed") || + !GET_FUNC(ptr_RomOpen, gfx.romOpen, "RomOpen") || + !GET_FUNC(ptr_ShowCFB, gfx.showCFB, "ShowCFB") || + !GET_FUNC(ptr_UpdateScreen, gfx.updateScreen, "UpdateScreen") || + !GET_FUNC(ptr_ViStatusChanged, gfx.viStatusChanged, "ViStatusChanged") || + !GET_FUNC(ptr_ViWidthChanged, gfx.viWidthChanged, "ViWidthChanged") || + !GET_FUNC(ptr_ReadScreen2, gfx.readScreen, "ReadScreen2") || + !GET_FUNC(ptr_SetRenderingCallback, gfx.setRenderingCallback, "SetRenderingCallback") || + !GET_FUNC(ptr_FBRead, gfx.fBRead, "FBRead") || + !GET_FUNC(ptr_FBWrite, gfx.fBWrite, "FBWrite") || + !GET_FUNC(ptr_FBGetFrameBufferInfo, gfx.fBGetFrameBufferInfo, "FBGetFrameBufferInfo")) + { + DebugMessage(M64MSG_ERROR, "broken Video plugin; function(s) not found."); + plugin_disconnect_gfx(); + return M64ERR_INPUT_INVALID; + } + + /* set function pointers for optional functions */ + gfx.resizeVideoOutput = (ptr_ResizeVideoOutput) osal_dynlib_getproc(plugin_handle, "ResizeVideoOutput"); + + /* check the version info */ + (*gfx.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); + if (PluginType != M64PLUGIN_GFX || (APIVersion & 0xffff0000) != (GFX_API_VERSION & 0xffff0000)) + { + DebugMessage(M64MSG_ERROR, "incompatible Video plugin"); + plugin_disconnect_gfx(); + return M64ERR_INCOMPATIBLE; + } + + /* handle backwards-compatibility */ + if (APIVersion < 0x020100) + { + DebugMessage(M64MSG_WARNING, "Fallback for Video plugin API (%02i.%02i.%02i) < 2.1.0. Screenshots may contain On Screen Display text", VERSION_PRINTF_SPLIT(APIVersion)); + // tell the video plugin to make its rendering callback to me (it's old, and doesn't have the bScreenRedrawn flag) + gfx.setRenderingCallback(backcompat_videoRenderCallback); + l_old1SetRenderingCallback = gfx.setRenderingCallback; // save this just for future use + gfx.setRenderingCallback = (ptr_SetRenderingCallback) backcompat_setRenderCallbackIntercept; + } + if (APIVersion < 0x20200 || gfx.resizeVideoOutput == NULL) + { + DebugMessage(M64MSG_WARNING, "Fallback for Video plugin API (%02i.%02i.%02i) < 2.2.0. Resizable video will not work", VERSION_PRINTF_SPLIT(APIVersion)); + gfx.resizeVideoOutput = dummyvideo_ResizeVideoOutput; + } + + l_GfxAttached = 1; + } + else + plugin_disconnect_gfx(); + + return M64ERR_SUCCESS; +} + +static m64p_error plugin_start_gfx(void) +{ + /* fill in the GFX_INFO data structure */ + gfx_info.HEADER = (unsigned char *) rom; + gfx_info.RDRAM = (unsigned char *) rdram; + gfx_info.DMEM = (unsigned char *) SP_DMEM; + gfx_info.IMEM = (unsigned char *) SP_IMEM; + gfx_info.MI_INTR_REG = &(MI_register.mi_intr_reg); + gfx_info.DPC_START_REG = &(dpc_register.dpc_start); + gfx_info.DPC_END_REG = &(dpc_register.dpc_end); + gfx_info.DPC_CURRENT_REG = &(dpc_register.dpc_current); + gfx_info.DPC_STATUS_REG = &(dpc_register.dpc_status); + gfx_info.DPC_CLOCK_REG = &(dpc_register.dpc_clock); + gfx_info.DPC_BUFBUSY_REG = &(dpc_register.dpc_bufbusy); + gfx_info.DPC_PIPEBUSY_REG = &(dpc_register.dpc_pipebusy); + gfx_info.DPC_TMEM_REG = &(dpc_register.dpc_tmem); + gfx_info.VI_STATUS_REG = &(vi_register.vi_status); + gfx_info.VI_ORIGIN_REG = &(vi_register.vi_origin); + gfx_info.VI_WIDTH_REG = &(vi_register.vi_width); + gfx_info.VI_INTR_REG = &(vi_register.vi_v_intr); + gfx_info.VI_V_CURRENT_LINE_REG = &(vi_register.vi_current); + gfx_info.VI_TIMING_REG = &(vi_register.vi_burst); + gfx_info.VI_V_SYNC_REG = &(vi_register.vi_v_sync); + gfx_info.VI_H_SYNC_REG = &(vi_register.vi_h_sync); + gfx_info.VI_LEAP_REG = &(vi_register.vi_leap); + gfx_info.VI_H_START_REG = &(vi_register.vi_h_start); + gfx_info.VI_V_START_REG = &(vi_register.vi_v_start); + gfx_info.VI_V_BURST_REG = &(vi_register.vi_v_burst); + gfx_info.VI_X_SCALE_REG = &(vi_register.vi_x_scale); + gfx_info.VI_Y_SCALE_REG = &(vi_register.vi_y_scale); + gfx_info.CheckInterrupts = EmptyFunc; + + /* call the audio plugin */ + if (!gfx.initiateGFX(gfx_info)) + return M64ERR_PLUGIN_FAIL; + + return M64ERR_SUCCESS; +} + +static void plugin_disconnect_audio(void) +{ + audio = dummy_audio; + l_AudioAttached = 0; +} + +static m64p_error plugin_connect_audio(m64p_dynlib_handle plugin_handle) +{ + /* attach the Audio plugin function pointers */ + if (plugin_handle != NULL) + { + m64p_plugin_type PluginType; + int PluginVersion, APIVersion; + + if (l_AudioAttached) + return M64ERR_INVALID_STATE; + + if (!GET_FUNC(ptr_PluginGetVersion, audio.getVersion, "PluginGetVersion") || + !GET_FUNC(ptr_AiDacrateChanged, audio.aiDacrateChanged, "AiDacrateChanged") || + !GET_FUNC(ptr_AiLenChanged, audio.aiLenChanged, "AiLenChanged") || + !GET_FUNC(ptr_InitiateAudio, audio.initiateAudio, "InitiateAudio") || + !GET_FUNC(ptr_ProcessAList, audio.processAList, "ProcessAList") || + !GET_FUNC(ptr_RomOpen, audio.romOpen, "RomOpen") || + !GET_FUNC(ptr_RomClosed, audio.romClosed, "RomClosed") || + !GET_FUNC(ptr_SetSpeedFactor, audio.setSpeedFactor, "SetSpeedFactor") || + !GET_FUNC(ptr_VolumeUp, audio.volumeUp, "VolumeUp") || + !GET_FUNC(ptr_VolumeDown, audio.volumeDown, "VolumeDown") || + !GET_FUNC(ptr_VolumeGetLevel, audio.volumeGetLevel, "VolumeGetLevel") || + !GET_FUNC(ptr_VolumeSetLevel, audio.volumeSetLevel, "VolumeSetLevel") || + !GET_FUNC(ptr_VolumeMute, audio.volumeMute, "VolumeMute") || + !GET_FUNC(ptr_VolumeGetString, audio.volumeGetString, "VolumeGetString")) + { + DebugMessage(M64MSG_ERROR, "broken Audio plugin; function(s) not found."); + plugin_disconnect_audio(); + return M64ERR_INPUT_INVALID; + } + + /* check the version info */ + (*audio.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); + if (PluginType != M64PLUGIN_AUDIO || (APIVersion & 0xffff0000) != (AUDIO_API_VERSION & 0xffff0000)) + { + DebugMessage(M64MSG_ERROR, "incompatible Audio plugin"); + plugin_disconnect_audio(); + return M64ERR_INCOMPATIBLE; + } + + l_AudioAttached = 1; + } + else + plugin_disconnect_audio(); + + return M64ERR_SUCCESS; +} + +static m64p_error plugin_start_audio(void) +{ + /* fill in the AUDIO_INFO data structure */ + audio_info.RDRAM = (unsigned char *) rdram; + audio_info.DMEM = (unsigned char *) SP_DMEM; + audio_info.IMEM = (unsigned char *) SP_IMEM; + audio_info.MI_INTR_REG = &(MI_register.mi_intr_reg); + audio_info.AI_DRAM_ADDR_REG = &(ai_register.ai_dram_addr); + audio_info.AI_LEN_REG = &(ai_register.ai_len); + audio_info.AI_CONTROL_REG = &(ai_register.ai_control); + audio_info.AI_STATUS_REG = &dummy; + audio_info.AI_DACRATE_REG = &(ai_register.ai_dacrate); + audio_info.AI_BITRATE_REG = &(ai_register.ai_bitrate); + audio_info.CheckInterrupts = EmptyFunc; + + /* call the audio plugin */ + if (!audio.initiateAudio(audio_info)) + return M64ERR_PLUGIN_FAIL; + + return M64ERR_SUCCESS; +} + +static void plugin_disconnect_input(void) +{ + input = dummy_input; + l_InputAttached = 0; +} + +static m64p_error plugin_connect_input(m64p_dynlib_handle plugin_handle) +{ + /* attach the Input plugin function pointers */ + if (plugin_handle != NULL) + { + m64p_plugin_type PluginType; + int PluginVersion, APIVersion; + + if (l_InputAttached) + return M64ERR_INVALID_STATE; + + if (!GET_FUNC(ptr_PluginGetVersion, input.getVersion, "PluginGetVersion") || + !GET_FUNC(ptr_ControllerCommand, input.controllerCommand, "ControllerCommand") || + !GET_FUNC(ptr_GetKeys, input.getKeys, "GetKeys") || + !GET_FUNC(ptr_InitiateControllers, input.initiateControllers, "InitiateControllers") || + !GET_FUNC(ptr_ReadController, input.readController, "ReadController") || + !GET_FUNC(ptr_RomOpen, input.romOpen, "RomOpen") || + !GET_FUNC(ptr_RomClosed, input.romClosed, "RomClosed") || + !GET_FUNC(ptr_SDL_KeyDown, input.keyDown, "SDL_KeyDown") || + !GET_FUNC(ptr_SDL_KeyUp, input.keyUp, "SDL_KeyUp")) + { + DebugMessage(M64MSG_ERROR, "broken Input plugin; function(s) not found."); + plugin_disconnect_input(); + return M64ERR_INPUT_INVALID; + } + + /* check the version info */ + (*input.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); + if (PluginType != M64PLUGIN_INPUT || (APIVersion & 0xffff0000) != (INPUT_API_VERSION & 0xffff0000)) + { + DebugMessage(M64MSG_ERROR, "incompatible Input plugin"); + plugin_disconnect_input(); + return M64ERR_INCOMPATIBLE; + } + + l_InputAttached = 1; + } + else + plugin_disconnect_input(); + + return M64ERR_SUCCESS; +} + +static m64p_error plugin_start_input(void) +{ + int i; + + /* fill in the CONTROL_INFO data structure */ + control_info.Controls = Controls; + for (i=0; i<4; i++) + { + Controls[i].Present = 0; + Controls[i].RawData = 0; + Controls[i].Plugin = PLUGIN_NONE; + } + + /* call the input plugin */ + input.initiateControllers(control_info); + + return M64ERR_SUCCESS; +} + +static void plugin_disconnect_rsp(void) +{ + rsp = dummy_rsp; + l_RspAttached = 0; +} + +static m64p_error plugin_connect_rsp(m64p_dynlib_handle plugin_handle) +{ + /* attach the RSP plugin function pointers */ + if (plugin_handle != NULL) + { + m64p_plugin_type PluginType; + int PluginVersion, APIVersion; + + if (l_RspAttached) + return M64ERR_INVALID_STATE; + + if (!GET_FUNC(ptr_PluginGetVersion, rsp.getVersion, "PluginGetVersion") || + !GET_FUNC(ptr_DoRspCycles, rsp.doRspCycles, "DoRspCycles") || + !GET_FUNC(ptr_InitiateRSP, rsp.initiateRSP, "InitiateRSP") || + !GET_FUNC(ptr_RomClosed, rsp.romClosed, "RomClosed")) + { + DebugMessage(M64MSG_ERROR, "broken RSP plugin; function(s) not found."); + plugin_disconnect_rsp(); + return M64ERR_INPUT_INVALID; + } + + /* check the version info */ + (*rsp.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); + if (PluginType != M64PLUGIN_RSP || (APIVersion & 0xffff0000) != (RSP_API_VERSION & 0xffff0000)) + { + DebugMessage(M64MSG_ERROR, "incompatible RSP plugin"); + plugin_disconnect_rsp(); + return M64ERR_INCOMPATIBLE; + } + + l_RspAttached = 1; + } + else + plugin_disconnect_rsp(); + + return M64ERR_SUCCESS; +} + +static m64p_error plugin_start_rsp(void) +{ + /* fill in the RSP_INFO data structure */ + rsp_info.RDRAM = (unsigned char *) rdram; + rsp_info.DMEM = (unsigned char *) SP_DMEM; + rsp_info.IMEM = (unsigned char *) SP_IMEM; + rsp_info.MI_INTR_REG = &MI_register.mi_intr_reg; + rsp_info.SP_MEM_ADDR_REG = &sp_register.sp_mem_addr_reg; + rsp_info.SP_DRAM_ADDR_REG = &sp_register.sp_dram_addr_reg; + rsp_info.SP_RD_LEN_REG = &sp_register.sp_rd_len_reg; + rsp_info.SP_WR_LEN_REG = &sp_register.sp_wr_len_reg; + rsp_info.SP_STATUS_REG = &sp_register.sp_status_reg; + rsp_info.SP_DMA_FULL_REG = &sp_register.sp_dma_full_reg; + rsp_info.SP_DMA_BUSY_REG = &sp_register.sp_dma_busy_reg; + rsp_info.SP_PC_REG = &rsp_register.rsp_pc; + rsp_info.SP_SEMAPHORE_REG = &sp_register.sp_semaphore_reg; + rsp_info.DPC_START_REG = &dpc_register.dpc_start; + rsp_info.DPC_END_REG = &dpc_register.dpc_end; + rsp_info.DPC_CURRENT_REG = &dpc_register.dpc_current; + rsp_info.DPC_STATUS_REG = &dpc_register.dpc_status; + rsp_info.DPC_CLOCK_REG = &dpc_register.dpc_clock; + rsp_info.DPC_BUFBUSY_REG = &dpc_register.dpc_bufbusy; + rsp_info.DPC_PIPEBUSY_REG = &dpc_register.dpc_pipebusy; + rsp_info.DPC_TMEM_REG = &dpc_register.dpc_tmem; + rsp_info.CheckInterrupts = EmptyFunc; + rsp_info.ProcessDlistList = gfx.processDList; + rsp_info.ProcessAlistList = audio.processAList; + rsp_info.ProcessRdpList = gfx.processRDPList; + rsp_info.ShowCFB = gfx.showCFB; + + /* call the RSP plugin */ + rsp.initiateRSP(rsp_info, NULL); + + return M64ERR_SUCCESS; +} + +/* global functions */ +m64p_error plugin_connect(m64p_plugin_type type, m64p_dynlib_handle plugin_handle) +{ + switch(type) + { + case M64PLUGIN_GFX: + if (plugin_handle != NULL && (l_AudioAttached || l_InputAttached || l_RspAttached)) + DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); + return plugin_connect_gfx(plugin_handle); + case M64PLUGIN_AUDIO: + if (plugin_handle != NULL && (l_InputAttached || l_RspAttached)) + DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); + return plugin_connect_audio(plugin_handle); + case M64PLUGIN_INPUT: + if (plugin_handle != NULL && (l_RspAttached)) + DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); + return plugin_connect_input(plugin_handle); + case M64PLUGIN_RSP: + return plugin_connect_rsp(plugin_handle); + default: + return M64ERR_INPUT_INVALID; + } + + return M64ERR_INTERNAL; +} + +m64p_error plugin_start(m64p_plugin_type type) +{ + switch(type) + { + case M64PLUGIN_RSP: + return plugin_start_rsp(); + case M64PLUGIN_GFX: + return plugin_start_gfx(); + case M64PLUGIN_AUDIO: + return plugin_start_audio(); + case M64PLUGIN_INPUT: + return plugin_start_input(); + default: + return M64ERR_INPUT_INVALID; + } + + return M64ERR_INTERNAL; +} + +m64p_error plugin_check(void) +{ + if (!l_GfxAttached) + DebugMessage(M64MSG_WARNING, "No video plugin attached. There will be no video output."); + if (!l_RspAttached) + DebugMessage(M64MSG_WARNING, "No RSP plugin attached. The video output will be corrupted."); + if (!l_AudioAttached) + DebugMessage(M64MSG_WARNING, "No audio plugin attached. There will be no sound output."); + if (!l_InputAttached) + DebugMessage(M64MSG_WARNING, "No input plugin attached. You won't be able to control the game."); + + return M64ERR_SUCCESS; +} +