diff --git a/Assets/dll/freetype.dll b/Assets/dll/freetype.dll deleted file mode 100644 index a415cf32051..00000000000 Binary files a/Assets/dll/freetype.dll and /dev/null differ diff --git a/Assets/dll/libgcc_s_seh-1.dll b/Assets/dll/libgcc_s_seh-1.dll deleted file mode 100644 index df7e7815d0a..00000000000 Binary files a/Assets/dll/libgcc_s_seh-1.dll and /dev/null differ diff --git a/Assets/dll/libmupen64plus-audio-bkm.so b/Assets/dll/libmupen64plus-audio-bkm.so new file mode 100644 index 00000000000..34f02b5d738 Binary files /dev/null and b/Assets/dll/libmupen64plus-audio-bkm.so differ diff --git a/Assets/dll/libmupen64plus-input-bkm.so b/Assets/dll/libmupen64plus-input-bkm.so new file mode 100644 index 00000000000..82252bf6b49 Binary files /dev/null and b/Assets/dll/libmupen64plus-input-bkm.so differ diff --git a/Assets/dll/libmupen64plus-rsp-cxd4-sse2.so b/Assets/dll/libmupen64plus-rsp-cxd4-sse2.so new file mode 100644 index 00000000000..64c99685484 Binary files /dev/null and b/Assets/dll/libmupen64plus-rsp-cxd4-sse2.so differ diff --git a/Assets/dll/libmupen64plus-rsp-hle.so b/Assets/dll/libmupen64plus-rsp-hle.so new file mode 100644 index 00000000000..2fce36c6fdc Binary files /dev/null and b/Assets/dll/libmupen64plus-rsp-hle.so differ diff --git a/Assets/dll/libmupen64plus-video-GLideN64.so b/Assets/dll/libmupen64plus-video-GLideN64.so new file mode 100644 index 00000000000..fb75f94150a Binary files /dev/null and b/Assets/dll/libmupen64plus-video-GLideN64.so differ diff --git a/Assets/dll/libmupen64plus-video-angrylion-plus.so b/Assets/dll/libmupen64plus-video-angrylion-plus.so new file mode 100644 index 00000000000..6691423e2dd Binary files /dev/null and b/Assets/dll/libmupen64plus-video-angrylion-plus.so differ diff --git a/Assets/dll/libmupen64plus.so b/Assets/dll/libmupen64plus.so new file mode 100644 index 00000000000..3addc8055e0 Binary files /dev/null and b/Assets/dll/libmupen64plus.so differ diff --git a/Assets/dll/libstdc++-6.dll b/Assets/dll/libstdc++-6.dll deleted file mode 100644 index 53193c267f6..00000000000 Binary files a/Assets/dll/libstdc++-6.dll and /dev/null differ diff --git a/Assets/dll/mupen64plus-input-bkm.dll b/Assets/dll/mupen64plus-input-bkm.dll index 780222ab22e..4c5d753a4cf 100644 Binary files a/Assets/dll/mupen64plus-input-bkm.dll and b/Assets/dll/mupen64plus-input-bkm.dll differ diff --git a/Assets/dll/mupen64plus-rsp-cxd4-sse2.dll b/Assets/dll/mupen64plus-rsp-cxd4-sse2.dll index 168a920bffb..6a01524043d 100644 Binary files a/Assets/dll/mupen64plus-rsp-cxd4-sse2.dll and b/Assets/dll/mupen64plus-rsp-cxd4-sse2.dll differ diff --git a/Assets/dll/mupen64plus-rsp-hle.dll b/Assets/dll/mupen64plus-rsp-hle.dll index abf75397916..419ad0be98c 100644 Binary files a/Assets/dll/mupen64plus-rsp-hle.dll and b/Assets/dll/mupen64plus-rsp-hle.dll differ diff --git a/Assets/dll/mupen64plus-video-GLideN64.dll b/Assets/dll/mupen64plus-video-GLideN64.dll index 648ec174649..66316c9f2cd 100644 Binary files a/Assets/dll/mupen64plus-video-GLideN64.dll and b/Assets/dll/mupen64plus-video-GLideN64.dll differ diff --git a/Assets/dll/mupen64plus-video-angrylion-plus.dll b/Assets/dll/mupen64plus-video-angrylion-plus.dll new file mode 100644 index 00000000000..0dcd0f0b469 Binary files /dev/null and b/Assets/dll/mupen64plus-video-angrylion-plus.dll differ diff --git a/Assets/dll/mupen64plus-video-glide64mk2.dll b/Assets/dll/mupen64plus-video-glide64mk2.dll deleted file mode 100644 index 3a3e7acaf52..00000000000 Binary files a/Assets/dll/mupen64plus-video-glide64mk2.dll and /dev/null differ diff --git a/Assets/dll/mupen64plus.dll b/Assets/dll/mupen64plus.dll index d890e8d89b1..75a5cdc1669 100644 Binary files a/Assets/dll/mupen64plus.dll and b/Assets/dll/mupen64plus.dll differ diff --git a/ExternalProjects/BizHawk.SrcGen.SettingsUtil/DefaultSetterGenerator.cs b/ExternalProjects/BizHawk.SrcGen.SettingsUtil/DefaultSetterGenerator.cs index bfb95e166ec..7cd28fcaa32 100644 --- a/ExternalProjects/BizHawk.SrcGen.SettingsUtil/DefaultSetterGenerator.cs +++ b/ExternalProjects/BizHawk.SrcGen.SettingsUtil/DefaultSetterGenerator.cs @@ -14,13 +14,13 @@ public class DefaultSetterGenerator : ISourceGenerator { public class SyntaxReceiver : ISyntaxContextReceiver { - public readonly List<(ClassDeclarationSyntax, SemanticModel)> ClassDeclarations = new(); + public readonly List<(TypeDeclarationSyntax, SemanticModel)> TypeDeclarations = new(); public void OnVisitSyntaxNode(GeneratorSyntaxContext context) { - if (context.Node is ClassDeclarationSyntax cds) + if (context.Node is TypeDeclarationSyntax cds) { - ClassDeclarations.Add((cds, context.SemanticModel)); + TypeDeclarations.Add((cds, context.SemanticModel)); } } } @@ -94,12 +94,12 @@ namespace BizHawk.Common public static partial class SettingsUtil {"); - foreach (var (cds, semanticModel) in syntaxReceiver.ClassDeclarations) + foreach (var (tds, semanticModel) in syntaxReceiver.TypeDeclarations) { - if (cds.AttributeLists.SelectMany(e => e.Attributes) + if (tds.AttributeLists.SelectMany(e => e.Attributes) .Any(e => e.Name.NormalizeWhitespace().ToFullString() == "CoreSettings")) { - var symbol = semanticModel.GetDeclaredSymbol(cds, context.CancellationToken); + var symbol = semanticModel.GetDeclaredSymbol(tds, context.CancellationToken); if (symbol is not null) // probably never happens? { CreateDefaultSetter(source, symbol); diff --git a/References/BizHawk.SrcGen.SettingsUtil.dll b/References/BizHawk.SrcGen.SettingsUtil.dll index 02a042e57e0..3b809ab94eb 100644 Binary files a/References/BizHawk.SrcGen.SettingsUtil.dll and b/References/BizHawk.SrcGen.SettingsUtil.dll differ diff --git a/libmupen64plus/mupen64plus-audio-bkm/main.c b/libmupen64plus/mupen64plus-audio-bkm/main.c index c4fc2388c7c..9106c8d68c4 100644 --- a/libmupen64plus/mupen64plus-audio-bkm/main.c +++ b/libmupen64plus/mupen64plus-audio-bkm/main.c @@ -26,6 +26,7 @@ #include #include #include +#include #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_types.h" @@ -36,6 +37,24 @@ #include "main.h" #include "osal_dynamiclib.h" +#ifdef max +#undef max +#endif +#define max(a, b) __extension__ ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a > _b ? _a : _b; \ +}) + +#ifdef min +#undef min +#endif +#define min(a, b) __extension__ ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a < _b ? _a : _b; \ +}) + /* This sets default frequency what is used if rom doesn't want to change it. Probably only game that needs this is Zelda: Ocarina Of Time Master Quest *NOTICE* We should try to find out why Demos' frequencies are always wrong diff --git a/libmupen64plus/mupen64plus-core/projects/msvc/mupen64plus-core.vcxproj b/libmupen64plus/mupen64plus-core/projects/msvc/mupen64plus-core.vcxproj index a8b2f2571a5..086e849e94b 100644 --- a/libmupen64plus/mupen64plus-core/projects/msvc/mupen64plus-core.vcxproj +++ b/libmupen64plus/mupen64plus-core/projects/msvc/mupen64plus-core.vcxproj @@ -62,7 +62,7 @@ Disabled ..\..\src;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;%(AdditionalIncludeDirectories) - DBG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_OSD;M64P_PARALLEL;%(PreprocessorDefinitions) + DBG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;M64P_OSD;M64P_PARALLEL;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebugDLL @@ -87,7 +87,7 @@ ..\..\src;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;%(AdditionalIncludeDirectories) - DBG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_OSD;M64P_PARALLEL;%(PreprocessorDefinitions) + DBG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;M64P_OSD;M64P_PARALLEL;%(PreprocessorDefinitions) MultiThreadedDLL @@ -241,4 +241,4 @@ - \ No newline at end of file + diff --git a/libmupen64plus/mupen64plus-core/src/main/main.c b/libmupen64plus/mupen64plus-core/src/main/main.c index bda4aa13084..9ca27824eaa 100644 --- a/libmupen64plus/mupen64plus-core/src/main/main.c +++ b/libmupen64plus/mupen64plus-core/src/main/main.c @@ -453,7 +453,7 @@ m64p_error main_core_state_query(m64p_core_param param, int *rval) case M64CORE_AUDIO_VOLUME: { if (!g_EmulatorRunning) - return M64ERR_INVALID_STATE; + return M64ERR_INVALID_STATE; return main_volume_get_level(rval); } case M64CORE_AUDIO_MUTE: @@ -481,7 +481,7 @@ m64p_error main_core_state_set(m64p_core_param param, int val) if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; if (val == M64EMU_STOPPED) - { + { /* this stop function is asynchronous. The emulator may not terminate until later */ main_stop(); return M64ERR_SUCCESS; @@ -493,7 +493,7 @@ m64p_error main_core_state_set(m64p_core_param param, int val) return M64ERR_SUCCESS; } else if (val == M64EMU_PAUSED) - { + { if (!main_is_paused()) main_toggle_pause(); return M64ERR_SUCCESS; @@ -687,7 +687,7 @@ void new_vi(void) double VILimitMilliseconds = 1000.0 / ROM_PARAMS.vilimit; double AdjustedLimit = VILimitMilliseconds * 100.0 / l_SpeedFactor; // adjust for selected emulator speed int time; - + start_section(IDLE_SECTION); VI_Counter++; @@ -701,10 +701,10 @@ void new_vi(void) return; } CurrentFPSTime = SDL_GetTicks(); - + Dif = CurrentFPSTime - LastFPSTime; - - if (Dif < AdjustedLimit) + + if (Dif < AdjustedLimit) { CalculatedTime = (unsigned int) (CounterTime + AdjustedLimit * VI_Counter); time = (int)(CalculatedTime - CurrentFPSTime); @@ -716,12 +716,12 @@ void new_vi(void) CurrentFPSTime = CurrentFPSTime + time; } - if (CurrentFPSTime - CounterTime >= 1000.0 ) + if (CurrentFPSTime - CounterTime >= 1000.0 ) { CounterTime = SDL_GetTicks(); VI_Counter = 0 ; } - + LastFPSTime = CurrentFPSTime ; */ end_section(IDLE_SECTION); @@ -840,7 +840,7 @@ void main_stop(void) { /* note: this operation is asynchronous. It may be called from a thread other than the main emulator thread, and may return before the emulator is completely stopped */ - if (!g_EmulatorRunning) + if (!g_EmulatorRunning) return; //DebugMessage(M64MSG_STATUS, "Stopping emulation."); @@ -859,19 +859,20 @@ void main_stop(void) osd_delete_message(l_msgVol); l_msgVol = NULL; } + DebugMessage(M64MSG_INFO, "stopping the emulator via main_stop...\n"); stop = 1; //if (rompause) //{ // rompause = 0; ReleaseSemaphore(rompausesem, 1, NULL); StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING); - //} + //} #ifdef DBG if(g_DebuggerActive) { debugger_step(); } -#endif +#endif } /********************************************************************************************************* @@ -881,4 +882,3 @@ int main(int argc, char *argv[]) { return 1; } - diff --git a/libmupen64plus/mupen64plus-input-bkm/config.h b/libmupen64plus/mupen64plus-input-bkm/config.h new file mode 100644 index 00000000000..8a71319d1f9 --- /dev/null +++ b/libmupen64plus/mupen64plus-input-bkm/config.h @@ -0,0 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - api/config.h * + * Mupen64Plus homepage: https://mupen64plus.org/ * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This file contains the Core configuration functions + */ + +#include "m64p_types.h" + +/* these functions are only to be used within the Core library */ + +m64p_error ConfigInit(const char *ConfigDirOverride, const char *DataDirOverride); +m64p_error ConfigShutdown(void); diff --git a/libmupen64plus/mupen64plus-input-bkm/m64p_common.h b/libmupen64plus/mupen64plus-input-bkm/m64p_common.h new file mode 100644 index 00000000000..3e80db6e098 --- /dev/null +++ b/libmupen64plus/mupen64plus-input-bkm/m64p_common.h @@ -0,0 +1,90 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_common.h * + * Mupen64Plus homepage: https://mupen64plus.org/ * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This header file defines typedefs for function pointers to common Core + * and plugin functions, for use by the front-end and plugin modules to attach + * to the dynamic libraries. + */ + +#if !defined(M64P_COMMON_H) +#define M64P_COMMON_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* PluginGetVersion() + * + * This function retrieves version information from a library. This + * function is the same for the core library and the plugins. + */ +typedef m64p_error (*ptr_PluginGetVersion)(m64p_plugin_type *, int *, int *, const char **, int *); +#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *, int *, int *, const char **, int *); +#endif + +/* CoreGetAPIVersions() + * + * This function retrieves API version information from the core. + */ +typedef m64p_error (*ptr_CoreGetAPIVersions)(int *, int *, int *, int *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL CoreGetAPIVersions(int *, int *, int *, int *); +#endif + +/* CoreErrorMessage() + * + * This function returns a pointer to a NULL-terminated string giving a + * human-readable description of the error. +*/ +typedef const char * (*ptr_CoreErrorMessage)(m64p_error); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL CoreErrorMessage(m64p_error); +#endif + +/* PluginStartup() + * + * This function initializes a plugin for use by allocating memory, creating + * data structures, and loading the configuration data. +*/ +typedef m64p_error (*ptr_PluginStartup)(m64p_dynlib_handle, void *, void (*)(void *, int, const char *)); +#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle, void *, void (*)(void *, int, const char *)); +#endif + +/* PluginShutdown() + * + * This function destroys data structures and releases memory allocated by + * the plugin library. +*/ +typedef m64p_error (*ptr_PluginShutdown)(void); +#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL PluginShutdown(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #define M64P_COMMON_H */ + diff --git a/libmupen64plus/mupen64plus-input-bkm/m64p_config.h b/libmupen64plus/mupen64plus-input-bkm/m64p_config.h new file mode 100644 index 00000000000..0c11b11c278 --- /dev/null +++ b/libmupen64plus/mupen64plus-input-bkm/m64p_config.h @@ -0,0 +1,312 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_config.h * + * Mupen64Plus homepage: https://mupen64plus.org/ * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This header file defines typedefs for function pointers to the Core's + * configuration handling functions. + */ + +#if !defined(M64P_CONFIG_H) +#define M64P_CONFIG_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ConfigListSections() + * + * This function is called to enumerate the list of Sections in the Mupen64Plus + * configuration file. It is expected that there will be a section named "Core" + * for core-specific configuration data, "Graphics" for common graphics options, + * and one or more sections for each plugin library. + */ +typedef m64p_error (*ptr_ConfigListSections)(void *, void (*)(void *, const char *)); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigListSections(void *, void (*)(void *, const char *)); +#endif + +/* ConfigOpenSection() + * + * This function is used to give a configuration section handle to the front-end + * which may be used to read or write configuration parameter values in a given + * section of the configuration file. + */ +typedef m64p_error (*ptr_ConfigOpenSection)(const char *, m64p_handle *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigOpenSection(const char *, m64p_handle *); +#endif + +/* ConfigListParameters() + * + * This function is called to enumerate the list of Parameters in a given + * Section of the Mupen64Plus configuration file. + */ +typedef m64p_error (*ptr_ConfigListParameters)(m64p_handle, void *, void (*)(void *, const char *, m64p_type)); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigListParameters(m64p_handle, void *, void (*)(void *, const char *, m64p_type)); +#endif + +/* ConfigSaveFile() + * + * This function saves the entire current Mupen64Plus configuration to disk. + */ +typedef m64p_error (*ptr_ConfigSaveFile)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSaveFile(void); +#endif + +/* ConfigSaveSection() + * + * This function saves one section of the current Mupen64Plus configuration to disk. + */ +typedef m64p_error (*ptr_ConfigSaveSection)(const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSaveSection(const char *); +#endif + +/* ConfigHasUnsavedChanges() + * + * This function determines if a given Section (or all sections) of the Mupen64Plus Core configuration file has been modified since it was last saved or loaded. + */ +typedef int (*ptr_ConfigHasUnsavedChanges)(const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT int CALL ConfigHasUnsavedChanges(const char *); +#endif + +/* ConfigDeleteSection() + * + * This function deletes a section from the Mupen64Plus configuration data. + */ +typedef m64p_error (*ptr_ConfigDeleteSection)(const char *SectionName); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigDeleteSection(const char *SectionName); +#endif + +/* ConfigRevertChanges() + * + * This function reverts changes previously made to one section of the configuration file, so that it will match with the configuration at the last time that it was loaded from or saved to disk. + */ +typedef m64p_error (*ptr_ConfigRevertChanges)(const char *SectionName); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigRevertChanges(const char *SectionName); +#endif + +/* ConfigSetParameter() + * + * This function sets the value of one of the emulator's configuration + * parameters. + */ +typedef m64p_error (*ptr_ConfigSetParameter)(m64p_handle, const char *, m64p_type, const void *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSetParameter(m64p_handle, const char *, m64p_type, const void *); +#endif + +/* ConfigSetParameterHelp() + * + * This function sets the help string of one of the emulator's configuration + * parameters. + */ +typedef m64p_error (*ptr_ConfigSetParameterHelp)(m64p_handle, const char *, const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSetParameterHelp(m64p_handle, const char *, const char *); +#endif + +/* ConfigGetParameter() + * + * This function retrieves the value of one of the emulator's parameters. + */ +typedef m64p_error (*ptr_ConfigGetParameter)(m64p_handle, const char *, m64p_type, void *, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigGetParameter(m64p_handle, const char *, m64p_type, void *, int); +#endif + +/* ConfigGetParameterType() + * + * This function retrieves the type of one of the emulator's parameters. + */ +typedef m64p_error (*ptr_ConfigGetParameterType)(m64p_handle, const char *, m64p_type *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigGetParameterType(m64p_handle, const char *, m64p_type *); +#endif + +/* ConfigGetParameterHelp() + * + * This function retrieves the help information about one of the emulator's + * parameters. + */ +typedef const char * (*ptr_ConfigGetParameterHelp)(m64p_handle, const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetParameterHelp(m64p_handle, const char *); +#endif + +/* ConfigSetDefault***() + * + * These functions are used to set the value of a configuration parameter if it + * is not already present in the configuration file. This may happen if a new + * user runs the emulator, or an upgraded module uses a new parameter, or the + * user deletes his or her configuration file. If the parameter is already + * present in the given section of the configuration file, then no action will + * be taken and this function will return successfully. + */ +typedef m64p_error (*ptr_ConfigSetDefaultInt)(m64p_handle, const char *, int, const char *); +typedef m64p_error (*ptr_ConfigSetDefaultFloat)(m64p_handle, const char *, float, const char *); +typedef m64p_error (*ptr_ConfigSetDefaultBool)(m64p_handle, const char *, int, const char *); +typedef m64p_error (*ptr_ConfigSetDefaultString)(m64p_handle, const char *, const char *, const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSetDefaultInt(m64p_handle, const char *, int, const char *); +EXPORT m64p_error CALL ConfigSetDefaultFloat(m64p_handle, const char *, float, const char *); +EXPORT m64p_error CALL ConfigSetDefaultBool(m64p_handle, const char *, int, const char *); +EXPORT m64p_error CALL ConfigSetDefaultString(m64p_handle, const char *, const char *, const char *); +#endif + +/* ConfigGetParam***() + * + * These functions retrieve the value of one of the emulator's parameters in + * the given section, and return the value directly to the calling function. If + * an errors occurs (such as an invalid Section handle, or invalid + * configuration parameter name), then an error will be sent to the front-end + * via the DebugCallback() function, and either a 0 (zero) or an empty string + * will be returned. + */ +typedef int (*ptr_ConfigGetParamInt)(m64p_handle, const char *); +typedef float (*ptr_ConfigGetParamFloat)(m64p_handle, const char *); +typedef int (*ptr_ConfigGetParamBool)(m64p_handle, const char *); +typedef const char * (*ptr_ConfigGetParamString)(m64p_handle, const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT int CALL ConfigGetParamInt(m64p_handle, const char *); +EXPORT float CALL ConfigGetParamFloat(m64p_handle, const char *); +EXPORT int CALL ConfigGetParamBool(m64p_handle, const char *); +EXPORT const char * CALL ConfigGetParamString(m64p_handle, const char *); +#endif + +/* ConfigGetSharedDataFilepath() + * + * This function is provided to allow a plugin to retrieve a full pathname to a + * given shared data file. This type of file is intended to be shared among + * multiple users on a system, so it is likely to be read-only. + */ +typedef const char * (*ptr_ConfigGetSharedDataFilepath)(const char *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetSharedDataFilepath(const char *); +#endif + +/* ConfigGetUserConfigPath() + * + * This function may be used by the plugins or front-end to get a path to the + * directory for storing user-specific configuration files. This will be the + * directory where "mupen64plus.cfg" is located. + */ +typedef const char * (*ptr_ConfigGetUserConfigPath)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetUserConfigPath(void); +#endif + +/* ConfigGetUserDataPath() + * + * This function may be used by the plugins or front-end to get a path to the + * directory for storing user-specific data files. This may be used to store + * files such as screenshots, saved game states, or hi-res textures. + */ +typedef const char * (*ptr_ConfigGetUserDataPath)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetUserDataPath(void); +#endif + +/* ConfigGetUserCachePath() + * + * This function may be used by the plugins or front-end to get a path to the + * directory for storing cached user-specific data files. Files in this + * directory may be deleted by the user to save space, so critical information + * should not be stored here. This directory may be used to store files such + * as the ROM browser cache. + */ +typedef const char * (*ptr_ConfigGetUserCachePath)(void); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT const char * CALL ConfigGetUserCachePath(void); +#endif + +/* ConfigExternalOpen() + * + * This function reads the contents of the config file into memory + * and returns M64ERR_SUCCESS if successful. + */ +typedef m64p_error (*ptr_ConfigExternalOpen)(const char *, m64p_handle *); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigExternalOpen(const char *, m64p_handle *); +#endif + +/* ConfigExternalClose() + * + * Frees the memory pointer created by ConfigExternalOpen. + */ +typedef m64p_error (*ptr_ConfigExternalClose)(m64p_handle); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigExternalClose(m64p_handle); +#endif + +/* ConfigExternalGetParameter() + * + * This functions allows a plugin to leverage the built-in ini parser to read + * any cfg/ini file. It will return M64ERR_SUCCESS if the item was found. + */ +typedef m64p_error (*ptr_ConfigExternalGetParameter)(m64p_handle, const char *, const char *, char *, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigExternalGetParameter(m64p_handle, const char *, const char *, char *, int); +#endif + +/* ConfigSendNetplayConfig() + * + * This function allows plugins to take advantage of the netplay TCP connection + * to send configuration data to the netplay server. + */ + +typedef m64p_error (*ptr_ConfigSendNetplayConfig)(char*, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigSendNetplayConfig(char*, int); +#endif + +/* ConfigReceiveNetplayConfig() + * + * This function allows plugins to take advantage of the netplay TCP connection + * to receive configuration data from the netplay server. + */ + +typedef m64p_error (*ptr_ConfigReceiveNetplayConfig)(char*, int); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigReceiveNetplayConfig(char*, int); +#endif + +/* ConfigOverrideUserPaths() + * + * This function allows overriding the paths returned by + * ConfigGetUserDataPath and ConfigGetUserCachePath + */ +typedef m64p_error (*ptr_ConfigOverrideUserPaths)(const char*, const char*); +#if defined(M64P_CORE_PROTOTYPES) +EXPORT m64p_error CALL ConfigOverrideUserPaths(const char*, const char*); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* #define M64P_CONFIG_H */ diff --git a/libmupen64plus/mupen64plus-input-bkm/m64p_plugin.h b/libmupen64plus/mupen64plus-input-bkm/m64p_plugin.h new file mode 100644 index 00000000000..76671fd32c9 --- /dev/null +++ b/libmupen64plus/mupen64plus-input-bkm/m64p_plugin.h @@ -0,0 +1,302 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_plugin.h * + * Mupen64Plus homepage: https://mupen64plus.org/ * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if !defined(M64P_PLUGIN_H) +#define M64P_PLUGIN_H + +#include "m64p_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*** Controller plugin's ****/ +#define PLUGIN_NONE 1 +#define PLUGIN_MEMPAK 2 +#define PLUGIN_RUMBLE_PAK 3 /* not implemented for non raw data */ +#define PLUGIN_TRANSFER_PAK 4 /* not implemented for non raw data */ +#define PLUGIN_RAW 5 /* the controller plugin is passed in raw data */ +#define PLUGIN_BIO_PAK 6 + +/***** Structures *****/ +typedef struct { + unsigned char * RDRAM; + unsigned char * DMEM; + unsigned char * IMEM; + + unsigned int * MI_INTR_REG; + + unsigned int * SP_MEM_ADDR_REG; + unsigned int * SP_DRAM_ADDR_REG; + unsigned int * SP_RD_LEN_REG; + unsigned int * SP_WR_LEN_REG; + unsigned int * SP_STATUS_REG; + unsigned int * SP_DMA_FULL_REG; + unsigned int * SP_DMA_BUSY_REG; + unsigned int * SP_PC_REG; + unsigned int * SP_SEMAPHORE_REG; + + unsigned int * DPC_START_REG; + unsigned int * DPC_END_REG; + unsigned int * DPC_CURRENT_REG; + unsigned int * DPC_STATUS_REG; + unsigned int * DPC_CLOCK_REG; + unsigned int * DPC_BUFBUSY_REG; + unsigned int * DPC_PIPEBUSY_REG; + unsigned int * DPC_TMEM_REG; + + void (*CheckInterrupts)(void); + void (*ProcessDlistList)(void); + void (*ProcessAlistList)(void); + void (*ProcessRdpList)(void); + void (*ShowCFB)(void); +} RSP_INFO; + +typedef struct { + unsigned char * HEADER; /* This is the rom header (first 40h bytes of the rom) */ + unsigned char * RDRAM; + unsigned char * DMEM; + unsigned char * IMEM; + + unsigned int * MI_INTR_REG; + + unsigned int * DPC_START_REG; + unsigned int * DPC_END_REG; + unsigned int * DPC_CURRENT_REG; + unsigned int * DPC_STATUS_REG; + unsigned int * DPC_CLOCK_REG; + unsigned int * DPC_BUFBUSY_REG; + unsigned int * DPC_PIPEBUSY_REG; + unsigned int * DPC_TMEM_REG; + + unsigned int * VI_STATUS_REG; + unsigned int * VI_ORIGIN_REG; + unsigned int * VI_WIDTH_REG; + unsigned int * VI_INTR_REG; + unsigned int * VI_V_CURRENT_LINE_REG; + unsigned int * VI_TIMING_REG; + unsigned int * VI_V_SYNC_REG; + unsigned int * VI_H_SYNC_REG; + unsigned int * VI_LEAP_REG; + unsigned int * VI_H_START_REG; + unsigned int * VI_V_START_REG; + unsigned int * VI_V_BURST_REG; + unsigned int * VI_X_SCALE_REG; + unsigned int * VI_Y_SCALE_REG; + + void (*CheckInterrupts)(void); + + /* The GFX_INFO.version parameter was added in version 2.5.1 of the core. + Plugins should ensure the core is at least this version before + attempting to read GFX_INFO.version. */ + unsigned int version; + /* SP_STATUS_REG and RDRAM_SIZE were added in version 2 of GFX_INFO.version. + Plugins should only attempt to read these values if GFX_INFO.version is at least 2. */ + + /* The RSP plugin should set (HALT | BROKE | TASKDONE) *before* calling ProcessDList. + It should not modify SP_STATUS_REG after ProcessDList has returned. + This will allow the GFX plugin to unset these bits if it needs. */ + unsigned int * SP_STATUS_REG; + const unsigned int * RDRAM_SIZE; +} GFX_INFO; + +typedef struct { + unsigned char * RDRAM; + unsigned char * DMEM; + unsigned char * IMEM; + + unsigned int * MI_INTR_REG; + + unsigned int * AI_DRAM_ADDR_REG; + unsigned int * AI_LEN_REG; + unsigned int * AI_CONTROL_REG; + unsigned int * AI_STATUS_REG; + unsigned int * AI_DACRATE_REG; + unsigned int * AI_BITRATE_REG; + + void (*CheckInterrupts)(void); +} AUDIO_INFO; + +/*** Controller types ****/ +#define CONT_TYPE_STANDARD 0 +#define CONT_TYPE_VRU 1 + +typedef struct { + int Present; + int RawData; + int Plugin; + int Type; +} CONTROL; + +typedef union { + unsigned int Value; + struct { + unsigned R_DPAD : 1; + unsigned L_DPAD : 1; + unsigned D_DPAD : 1; + unsigned U_DPAD : 1; + unsigned START_BUTTON : 1; + unsigned Z_TRIG : 1; + unsigned B_BUTTON : 1; + unsigned A_BUTTON : 1; + + unsigned R_CBUTTON : 1; + unsigned L_CBUTTON : 1; + unsigned D_CBUTTON : 1; + unsigned U_CBUTTON : 1; + unsigned R_TRIG : 1; + unsigned L_TRIG : 1; + unsigned Reserved1 : 1; + unsigned Reserved2 : 1; + + signed X_AXIS : 8; + signed Y_AXIS : 8; + }; +} BUTTONS; + +typedef struct { + CONTROL *Controls; /* A pointer to an array of 4 controllers .. eg: + CONTROL Controls[4]; */ +} CONTROL_INFO; + +/* common plugin function pointer types */ +typedef void (*ptr_RomClosed)(void); +typedef int (*ptr_RomOpen)(void); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT int CALL RomOpen(void); +EXPORT void CALL RomClosed(void); +#endif + +/* video plugin function pointer types */ +typedef void (*ptr_ChangeWindow)(void); +typedef int (*ptr_InitiateGFX)(GFX_INFO Gfx_Info); +typedef void (*ptr_MoveScreen)(int x, int y); +typedef void (*ptr_ProcessDList)(void); +typedef void (*ptr_ProcessRDPList)(void); +typedef void (*ptr_ShowCFB)(void); +typedef void (*ptr_UpdateScreen)(void); +typedef void (*ptr_ViStatusChanged)(void); +typedef void (*ptr_ViWidthChanged)(void); +typedef void (*ptr_ReadScreen2)(void *dest, int *width, int *height, int front); +typedef void (*ptr_SetRenderingCallback)(void (*callback)(int)); +typedef void (*ptr_ResizeVideoOutput)(int width, int height); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT void CALL ChangeWindow(void); +EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info); +EXPORT void CALL MoveScreen(int x, int y); +EXPORT void CALL ProcessDList(void); +EXPORT void CALL ProcessRDPList(void); +EXPORT void CALL ShowCFB(void); +EXPORT void CALL UpdateScreen(void); +EXPORT void CALL ViStatusChanged(void); +EXPORT void CALL ViWidthChanged(void); +EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int front); +EXPORT void CALL SetRenderingCallback(void (*callback)(int)); +EXPORT void CALL ResizeVideoOutput(int width, int height); +#endif + +/* frame buffer plugin spec extension */ +typedef struct +{ + unsigned int addr; + unsigned int size; + unsigned int width; + unsigned int height; +} FrameBufferInfo; +typedef void (*ptr_FBRead)(unsigned int addr); +typedef void (*ptr_FBWrite)(unsigned int addr, unsigned int size); +typedef void (*ptr_FBGetFrameBufferInfo)(void *p); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT void CALL FBRead(unsigned int addr); +EXPORT void CALL FBWrite(unsigned int addr, unsigned int size); +EXPORT void CALL FBGetFrameBufferInfo(void *p); +#endif + +/* audio plugin function pointers */ +typedef void (*ptr_AiDacrateChanged)(int SystemType); +typedef void (*ptr_AiLenChanged)(void); +typedef int (*ptr_InitiateAudio)(AUDIO_INFO Audio_Info); +typedef void (*ptr_ProcessAList)(void); +typedef void (*ptr_SetSpeedFactor)(int percent); +typedef void (*ptr_VolumeUp)(void); +typedef void (*ptr_VolumeDown)(void); +typedef int (*ptr_VolumeGetLevel)(void); +typedef void (*ptr_VolumeSetLevel)(int level); +typedef void (*ptr_VolumeMute)(void); +typedef const char * (*ptr_VolumeGetString)(void); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT void CALL AiDacrateChanged(int SystemType); +EXPORT void CALL AiLenChanged(void); +EXPORT int CALL InitiateAudio(AUDIO_INFO Audio_Info); +EXPORT void CALL ProcessAList(void); +EXPORT void CALL SetSpeedFactor(int percent); +EXPORT void CALL VolumeUp(void); +EXPORT void CALL VolumeDown(void); +EXPORT int CALL VolumeGetLevel(void); +EXPORT void CALL VolumeSetLevel(int level); +EXPORT void CALL VolumeMute(void); +EXPORT const char * CALL VolumeGetString(void); +#endif + +/* input plugin function pointers */ +typedef void (*ptr_ControllerCommand)(int Control, unsigned char *Command); +typedef void (*ptr_GetKeys)(int Control, BUTTONS *Keys); +typedef void (*ptr_InitiateControllers)(CONTROL_INFO ControlInfo); +typedef void (*ptr_ReadController)(int Control, unsigned char *Command); +typedef void (*ptr_SDL_KeyDown)(int keymod, int keysym); +typedef void (*ptr_SDL_KeyUp)(int keymod, int keysym); +typedef void (*ptr_RenderCallback)(void); +typedef void (*ptr_SendVRUWord)(uint16_t length, uint16_t *word, uint8_t lang); +typedef void (*ptr_SetMicState)(int state); +typedef void (*ptr_ReadVRUResults)(uint16_t *error_flags, uint16_t *num_results, uint16_t *mic_level, uint16_t *voice_level, uint16_t *voice_length, uint16_t *matches); +typedef void (*ptr_ClearVRUWords)(uint8_t length); +typedef void (*ptr_SetVRUWordMask)(uint8_t length, uint8_t *mask); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT void CALL ControllerCommand(int Control, unsigned char *Command); +EXPORT void CALL GetKeys(int Control, BUTTONS *Keys); +EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo); +EXPORT void CALL ReadController(int Control, unsigned char *Command); +EXPORT void CALL SDL_KeyDown(int keymod, int keysym); +EXPORT void CALL SDL_KeyUp(int keymod, int keysym); +EXPORT void CALL RenderCallback(void); +EXPORT void CALL SendVRUWord(uint16_t length, uint16_t *word, uint8_t lang); +EXPORT void CALL SetMicState(int state); +EXPORT void CALL ReadVRUResults(uint16_t *error_flags, uint16_t *num_results, uint16_t *mic_level, uint16_t *voice_level, uint16_t *voice_length, uint16_t *matches); +EXPORT void CALL ClearVRUWords(uint8_t length); +EXPORT void CALL SetVRUWordMask(uint8_t length, uint8_t *mask); +#endif + +/* RSP plugin function pointers */ +typedef unsigned int (*ptr_DoRspCycles)(unsigned int Cycles); +typedef void (*ptr_InitiateRSP)(RSP_INFO Rsp_Info, unsigned int *CycleCount); +#if defined(M64P_PLUGIN_PROTOTYPES) +EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles); +EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* M64P_PLUGIN_H */ + + diff --git a/libmupen64plus/mupen64plus-input-bkm/m64p_types.h b/libmupen64plus/mupen64plus-input-bkm/m64p_types.h new file mode 100644 index 00000000000..088f0117f10 --- /dev/null +++ b/libmupen64plus/mupen64plus-input-bkm/m64p_types.h @@ -0,0 +1,462 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - m64p_types.h * + * Mupen64Plus homepage: https://mupen64plus.org/ * + * Copyright (C) 2012 CasualJames * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if !defined(M64P_TYPES_H) +#define M64P_TYPES_H + +/* ----------------------------------------- */ +/* Platform-specific stuff */ +/* ----------------------------------------- */ + +/* necessary headers */ +#include +#if defined(WIN32) + #include +#endif + +/* DLL handles and function declaration specifiers */ +#if defined(WIN32) + #define IMPORT extern "C" __declspec(dllimport) + #define EXPORT __declspec(dllexport) + #define CALL __cdecl + typedef HMODULE m64p_dynlib_handle; +#else + #define IMPORT extern "C" + #define EXPORT __attribute__((visibility("default"))) + #define CALL + typedef void * m64p_dynlib_handle; +#endif + +/* ----------------------------------------- */ +/* Structures and Types for Core library API */ +/* ----------------------------------------- */ + +typedef void * m64p_handle; + +/* Generic function pointer returned from osal_dynlib_getproc (and the like) + * Don't use it directly, cast to proper type before using it. + */ +typedef void (*m64p_function)(void); + +typedef void (*m64p_frame_callback)(unsigned int FrameIndex); +typedef void (*m64p_input_callback)(void); +typedef void (*m64p_audio_callback)(void); +typedef void (*m64p_vi_callback)(void); + +typedef enum { + M64TYPE_INT = 1, + M64TYPE_FLOAT, + M64TYPE_BOOL, + M64TYPE_STRING +} m64p_type; + +typedef enum { + M64MSG_ERROR = 1, + M64MSG_WARNING, + M64MSG_INFO, + M64MSG_STATUS, + M64MSG_VERBOSE +} m64p_msg_level; + +typedef enum { + M64ERR_SUCCESS = 0, + M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */ + M64ERR_ALREADY_INIT, /* InitMupen64Plus() was called twice */ + M64ERR_INCOMPATIBLE, /* API versions between components are incompatible */ + M64ERR_INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */ + M64ERR_INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */ + M64ERR_INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */ + M64ERR_NO_MEMORY, /* Memory allocation failed */ + M64ERR_FILES, /* Error opening, creating, reading, or writing to a file */ + M64ERR_INTERNAL, /* Internal error (bug) */ + M64ERR_INVALID_STATE, /* Current program state does not allow operation */ + M64ERR_PLUGIN_FAIL, /* A plugin function returned a fatal error */ + M64ERR_SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */ + M64ERR_UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */ + M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */ +} m64p_error; + +typedef enum { + M64CAPS_DYNAREC = 1, + M64CAPS_DEBUGGER = 2, + M64CAPS_CORE_COMPARE = 4 +} m64p_core_caps; + +typedef enum { + M64PLUGIN_NULL = 0, + M64PLUGIN_RSP = 1, + M64PLUGIN_GFX, + M64PLUGIN_AUDIO, + M64PLUGIN_INPUT, + M64PLUGIN_CORE +} m64p_plugin_type; + +typedef enum { + M64EMU_STOPPED = 1, + M64EMU_RUNNING, + M64EMU_PAUSED +} m64p_emu_state; + +typedef enum { + M64VIDEO_NONE = 1, + M64VIDEO_WINDOWED, + M64VIDEO_FULLSCREEN +} m64p_video_mode; + +typedef enum { + M64VIDEOFLAG_SUPPORT_RESIZING = 1 +} m64p_video_flags; + +typedef enum { + M64CORE_EMU_STATE = 1, + M64CORE_VIDEO_MODE, + M64CORE_SAVESTATE_SLOT, + M64CORE_SPEED_FACTOR, + M64CORE_SPEED_LIMITER, + M64CORE_VIDEO_SIZE, + M64CORE_AUDIO_VOLUME, + M64CORE_AUDIO_MUTE, + M64CORE_INPUT_GAMESHARK, + M64CORE_STATE_LOADCOMPLETE, + M64CORE_STATE_SAVECOMPLETE, + M64CORE_SCREENSHOT_CAPTURED, +} m64p_core_param; + +typedef enum { + M64CMD_NOP = 0, + M64CMD_ROM_OPEN, + M64CMD_ROM_CLOSE, + M64CMD_ROM_GET_HEADER, + M64CMD_ROM_GET_SETTINGS, + M64CMD_EXECUTE, + M64CMD_STOP, + M64CMD_PAUSE, + M64CMD_RESUME, + M64CMD_CORE_STATE_QUERY, + M64CMD_STATE_LOAD, + M64CMD_STATE_SAVE, + M64CMD_STATE_SET_SLOT, + M64CMD_SEND_SDL_KEYDOWN, + M64CMD_SEND_SDL_KEYUP, + M64CMD_SET_FRAME_CALLBACK, + M64CMD_TAKE_NEXT_SCREENSHOT, + M64CMD_CORE_STATE_SET, + M64CMD_READ_SCREEN, + M64CMD_RESET, + M64CMD_ADVANCE_FRAME, + M64CMD_SET_MEDIA_LOADER, + M64CMD_NETPLAY_INIT, + M64CMD_NETPLAY_CONTROL_PLAYER, + M64CMD_NETPLAY_GET_VERSION, + M64CMD_NETPLAY_CLOSE, + M64CMD_PIF_OPEN, + M64CMD_ROM_SET_SETTINGS, + M64CMD_DISK_OPEN, + M64CMD_DISK_CLOSE +} m64p_command; + +typedef struct { + uint32_t address; + int value; +} m64p_cheat_code; + +typedef struct { + /* Frontend-defined callback data. */ + void* cb_data; + + /* Allow the frontend to specify the GB cart ROM file to load + * cb_data: points to frontend-defined callback data. + * controller_num: (0-3) tell the frontend which controller is about to load a GB cart + * Returns a NULL-terminated string owned by the core specifying the GB cart ROM filename to load. + * Empty or NULL string results in no GB cart being loaded (eg. empty transferpak). + */ + char* (*get_gb_cart_rom)(void* cb_data, int controller_num); + + /* Allow the frontend to specify the GB cart RAM file to load + * cb_data: points to frontend-defined callback data. + * controller_num: (0-3) tell the frontend which controller is about to load a GB cart + * Returns a NULL-terminated string owned by the core specifying the GB cart RAM filename to load + * Empty or NULL string results in the core generating a default save file with empty content. + */ + char* (*get_gb_cart_ram)(void* cb_data, int controller_num); + + /* Allow the frontend to know what DD IPL ROM region file to load + * cb_data: points to frontend-defined callback data. + * region: a region from m64p_system_type + */ + void (*set_dd_rom_region)(void* cb_data, uint8_t region); + + /* Allow the frontend to specify the DD IPL ROM file to load + * cb_data: points to frontend-defined callback data. + * Returns a NULL-terminated string owned by the core specifying the DD IPL ROM filename to load + * Empty or NULL string results in disabled 64DD. + */ + char* (*get_dd_rom)(void* cb_data); + + /* Allow the frontend to specify the DD disk file to load + * cb_data: points to frontend-defined callback data. + * Returns a NULL-terminated string owned by the core specifying the DD disk filename to load + * Empty or NULL string results in no DD disk being loaded (eg. empty disk drive). + */ + char* (*get_dd_disk)(void* cb_data); +} m64p_media_loader; + +/* ----------------------------------------- */ +/* Structures to hold ROM image information */ +/* ----------------------------------------- */ + +typedef enum +{ + SYSTEM_NTSC = 0, + SYSTEM_PAL, + SYSTEM_MPAL +} m64p_system_type; + +typedef enum +{ + SAVETYPE_EEPROM_4K = 0, + SAVETYPE_EEPROM_4KB = 0, // Preserve inaccurate/misleading name + SAVETYPE_EEPROM_16K = 1, + SAVETYPE_EEPROM_16KB = 1, // Preserve inaccurate/misleading name + SAVETYPE_SRAM = 2, + SAVETYPE_FLASH_RAM = 3, + SAVETYPE_CONTROLLER_PAK = 4, + SAVETYPE_CONTROLLER_PACK = 4, // Preserve inaccurate/off-brand name + SAVETYPE_NONE = 5, +} m64p_rom_save_type; + +typedef enum +{ + DDREGION_JAPAN = 0, + DDREGION_US = 1, + DDREGION_DEV = 2, + DDREGION_UNKNOWN = 3, +} m64p_disk_region; + +typedef struct +{ + uint8_t init_PI_BSB_DOM1_LAT_REG; /* 0x00 */ + uint8_t init_PI_BSB_DOM1_PGS_REG; /* 0x01 */ + uint8_t init_PI_BSB_DOM1_PWD_REG; /* 0x02 */ + uint8_t init_PI_BSB_DOM1_PGS_REG2; /* 0x03 */ + uint32_t ClockRate; /* 0x04 */ + uint32_t PC; /* 0x08 */ + uint32_t Release; /* 0x0C */ + uint32_t CRC1; /* 0x10 */ + uint32_t CRC2; /* 0x14 */ + uint32_t Unknown[2]; /* 0x18 */ + uint8_t Name[20]; /* 0x20 */ + uint32_t unknown; /* 0x34 */ + uint32_t Manufacturer_ID; /* 0x38 */ + uint16_t Cartridge_ID; /* 0x3C - Game serial number */ + uint8_t Country_code; /* 0x3E */ + uint8_t Version; /* 0x3F */ +} m64p_rom_header; + +typedef struct +{ + char goodname[256]; + char MD5[33]; + unsigned char savetype; + unsigned char status; /* Rom status on a scale from 0-5. */ + unsigned char players; /* Local players 0-4, 2/3/4 way Netplay indicated by 5/6/7. */ + unsigned char rumble; /* 0 - No, 1 - Yes boolean for rumble support. */ + unsigned char transferpak; /* 0 - No, 1 - Yes boolean for transfer pak support. */ + unsigned char mempak; /* 0 - No, 1 - Yes boolean for memory pak support. */ + unsigned char biopak; /* 0 - No, 1 - Yes boolean for bio pak support. */ + unsigned char disableextramem; /* 0 - No, 1 - Yes boolean for disabling 4MB expansion RAM pack */ + unsigned int countperop; /* Number of CPU cycles per instruction. */ + unsigned int sidmaduration; /* Default SI DMA duration */ + unsigned int aidmamodifier; /* Percentage modifier for AI DMA duration */ +} m64p_rom_settings; + +/* ----------------------------------------- */ +/* Structures and Types for the Debugger */ +/* ----------------------------------------- */ + +typedef enum { + M64P_DBG_RUN_STATE = 1, + M64P_DBG_PREVIOUS_PC, + M64P_DBG_NUM_BREAKPOINTS, + M64P_DBG_CPU_DYNACORE, + M64P_DBG_CPU_NEXT_INTERRUPT +} m64p_dbg_state; + +typedef enum { + M64P_DBG_RUNSTATE_PAUSED = 0, + M64P_DBG_RUNSTATE_STEPPING, + M64P_DBG_RUNSTATE_RUNNING +} m64p_dbg_runstate; + +typedef enum { + M64P_DBG_MEM_TYPE = 1, + M64P_DBG_MEM_FLAGS, + M64P_DBG_MEM_HAS_RECOMPILED, + M64P_DBG_MEM_NUM_RECOMPILED, + M64P_DBG_RECOMP_OPCODE = 16, + M64P_DBG_RECOMP_ARGS, + M64P_DBG_RECOMP_ADDR +} m64p_dbg_mem_info; + +typedef enum { + M64P_MEM_NOMEM = 0, + M64P_MEM_NOTHING, + M64P_MEM_RDRAM, + M64P_MEM_RDRAMREG, + M64P_MEM_RSPMEM, + M64P_MEM_RSPREG, + M64P_MEM_RSP, + M64P_MEM_DP, + M64P_MEM_DPS, + M64P_MEM_VI, + M64P_MEM_AI, + M64P_MEM_PI, + M64P_MEM_RI, + M64P_MEM_SI, + M64P_MEM_FLASHRAMSTAT, + M64P_MEM_ROM, + M64P_MEM_PIF, + M64P_MEM_MI, + M64P_MEM_BREAKPOINT +} m64p_dbg_mem_type; + +typedef enum { + M64P_MEM_FLAG_READABLE = 0x01, + M64P_MEM_FLAG_WRITABLE = 0x02, + M64P_MEM_FLAG_READABLE_EMUONLY = 0x04, /* the EMUONLY flags signify that emulated code can read/write here, but debugger cannot */ + M64P_MEM_FLAG_WRITABLE_EMUONLY = 0x08 +} m64p_dbg_mem_flags; + +typedef enum { + M64P_DBG_PTR_RDRAM = 1, + M64P_DBG_PTR_PI_REG, + M64P_DBG_PTR_SI_REG, + M64P_DBG_PTR_VI_REG, + M64P_DBG_PTR_RI_REG, + M64P_DBG_PTR_AI_REG +} m64p_dbg_memptr_type; + +typedef enum { + M64P_CPU_PC = 1, + M64P_CPU_REG_REG, + M64P_CPU_REG_HI, + M64P_CPU_REG_LO, + M64P_CPU_REG_COP0, + M64P_CPU_REG_COP1_DOUBLE_PTR, + M64P_CPU_REG_COP1_SIMPLE_PTR, + M64P_CPU_REG_COP1_FGR_64, + M64P_CPU_TLB +} m64p_dbg_cpu_data; + +typedef enum { + M64P_BKP_CMD_ADD_ADDR = 1, + M64P_BKP_CMD_ADD_STRUCT, + M64P_BKP_CMD_REPLACE, + M64P_BKP_CMD_REMOVE_ADDR, + M64P_BKP_CMD_REMOVE_IDX, + M64P_BKP_CMD_ENABLE, + M64P_BKP_CMD_DISABLE, + M64P_BKP_CMD_CHECK +} m64p_dbg_bkp_command; + +#define M64P_MEM_INVALID 0xFFFFFFFF /* invalid memory read will return this */ + +#define BREAKPOINTS_MAX_NUMBER 128 + +typedef enum { + M64P_BKP_FLAG_ENABLED = 0x01, + M64P_BKP_FLAG_READ = 0x02, + M64P_BKP_FLAG_WRITE = 0x04, + M64P_BKP_FLAG_EXEC = 0x08, + M64P_BKP_FLAG_LOG = 0x10 /* Log to the console when this breakpoint hits */ +} m64p_dbg_bkp_flags; + +#define BPT_CHECK_FLAG(a, b) ((a.flags & b) == b) +#define BPT_SET_FLAG(a, b) a.flags = (a.flags | b); +#define BPT_CLEAR_FLAG(a, b) a.flags = (a.flags & (~b)); +#define BPT_TOGGLE_FLAG(a, b) a.flags = (a.flags ^ b); + +typedef struct { + uint32_t address; + uint32_t endaddr; + unsigned int flags; +} m64p_breakpoint; + +/* ------------------------------------------------- */ +/* Structures and Types for Core Video Extension API */ +/* ------------------------------------------------- */ + +typedef struct { + unsigned int uiWidth; + unsigned int uiHeight; +} m64p_2d_size; + +typedef enum { + M64P_GL_DOUBLEBUFFER = 1, + M64P_GL_BUFFER_SIZE, + M64P_GL_DEPTH_SIZE, + M64P_GL_RED_SIZE, + M64P_GL_GREEN_SIZE, + M64P_GL_BLUE_SIZE, + M64P_GL_ALPHA_SIZE, + M64P_GL_SWAP_CONTROL, + M64P_GL_MULTISAMPLEBUFFERS, + M64P_GL_MULTISAMPLESAMPLES, + M64P_GL_CONTEXT_MAJOR_VERSION, + M64P_GL_CONTEXT_MINOR_VERSION, + M64P_GL_CONTEXT_PROFILE_MASK +} m64p_GLattr; + +typedef enum { + M64P_GL_CONTEXT_PROFILE_CORE, + M64P_GL_CONTEXT_PROFILE_COMPATIBILITY, + M64P_GL_CONTEXT_PROFILE_ES +} m64p_GLContextType; + +typedef enum { + M64P_RENDER_OPENGL = 0, + M64P_RENDER_VULKAN +} m64p_render_mode; + +typedef struct { + unsigned int Functions; + m64p_error (*VidExtFuncInit)(void); + m64p_error (*VidExtFuncQuit)(void); + m64p_error (*VidExtFuncListModes)(m64p_2d_size *, int *); + m64p_error (*VidExtFuncListRates)(m64p_2d_size, int *, int *); + m64p_error (*VidExtFuncSetMode)(int, int, int, int, int); + m64p_error (*VidExtFuncSetModeWithRate)(int, int, int, int, int, int); + m64p_function (*VidExtFuncGLGetProc)(const char*); + m64p_error (*VidExtFuncGLSetAttr)(m64p_GLattr, int); + m64p_error (*VidExtFuncGLGetAttr)(m64p_GLattr, int *); + m64p_error (*VidExtFuncGLSwapBuf)(void); + m64p_error (*VidExtFuncSetCaption)(const char *); + m64p_error (*VidExtFuncToggleFS)(void); + m64p_error (*VidExtFuncResizeWindow)(int, int); + uint32_t (*VidExtFuncGLGetDefaultFramebuffer)(void); + m64p_error (*VidExtFuncInitWithRenderMode)(m64p_render_mode); + m64p_error (*VidExtFuncVKGetSurface)(void**, void*); + m64p_error (*VidExtFuncVKGetInstanceExtensions)(const char**[], uint32_t*); +} m64p_video_extension_functions; + +#endif /* define M64P_TYPES_H */ + diff --git a/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_unix.c b/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_unix.c new file mode 100644 index 00000000000..b3b7ba52dc6 --- /dev/null +++ b/libmupen64plus/mupen64plus-input-bkm/osal_dynamiclib_unix.c @@ -0,0 +1,37 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - osal/dynamiclib_unix.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include + +#include "m64p_types.h" +#include "osal_dynamiclib.h" + +void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) +{ + if (pccProcedureName == NULL) + return NULL; + + return dlsym(LibHandle, pccProcedureName); +} + + diff --git a/libmupen64plus/mupen64plus-input-bkm/plugin.c b/libmupen64plus/mupen64plus-input-bkm/plugin.c index 8e1a15965e0..a46328fe6f7 100644 --- a/libmupen64plus/mupen64plus-input-bkm/plugin.c +++ b/libmupen64plus/mupen64plus-input-bkm/plugin.c @@ -25,6 +25,7 @@ #include #include #include +#include #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_types.h" @@ -39,6 +40,24 @@ #include +#ifdef max +#undef max +#endif +#define max(a, b) __extension__ ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a > _b ? _a : _b; \ +}) + +#ifdef min +#undef min +#endif +#define min(a, b) __extension__ ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a < _b ? _a : _b; \ +}) + /* global data definitions */ SController controller[4]; // 4 controllers @@ -49,7 +68,7 @@ static int l_PluginInit = 0; /* Callbacks for data flow out of mupen */ static int (*l_inputCallback)(int i) = NULL; -static int (*l_setrumbleCallback)(int i, int on) = NULL; +static void (*l_setrumbleCallback)(int i, int on) = NULL; static int romopen = 0; // is a rom opened @@ -77,7 +96,7 @@ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Con void (*DebugCallback)(void *, int, const char *)) { ptr_CoreGetAPIVersions CoreAPIVersionFunc; - + int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion; if (l_PluginInit) @@ -186,7 +205,7 @@ EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *Plugi if (APIVersion != NULL) *APIVersion = INPUT_PLUGIN_API_VERSION; - + if (PluginNamePtr != NULL) *PluginNamePtr = PLUGIN_NAME; @@ -194,7 +213,7 @@ EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *Plugi { *Capabilities = 0; } - + return M64ERR_SUCCESS; } @@ -336,7 +355,7 @@ EXPORT void CALL ReadController(int Control, unsigned char *Command) int value; if(Control == -1) return; - + switch(Command[2]) { case RD_RESETCONTROLLER: @@ -448,4 +467,4 @@ EXPORT void CALL SetControllerPakType(int idx, int type) EXPORT void CALL SetControllerConnected(int idx, int connected) { controller[idx].control->Present = connected; -} \ No newline at end of file +} diff --git a/libmupen64plus/mupen64plus-input-bkm/plugin.h b/libmupen64plus/mupen64plus-input-bkm/plugin.h index 65d08331ac2..09001819016 100644 --- a/libmupen64plus/mupen64plus-input-bkm/plugin.h +++ b/libmupen64plus/mupen64plus-input-bkm/plugin.h @@ -27,6 +27,7 @@ #define M64P_PLUGIN_PROTOTYPES 1 #include "m64p_plugin.h" #include "m64p_config.h" +#include // Some stuff from n-rage plugin #define RD_GETSTATUS 0x00 // get status @@ -55,7 +56,7 @@ typedef struct { CONTROL *control; // pointer to CONTROL struct in Core library - BOOL rumbling; + bool rumbling; } SController; /* global data definitions */ diff --git a/libmupen64plus/mupen64plus-input-bkm/version.h b/libmupen64plus/mupen64plus-input-bkm/version.h index 1814c41ee63..b4d131bf5fe 100644 --- a/libmupen64plus/mupen64plus-input-bkm/version.h +++ b/libmupen64plus/mupen64plus-input-bkm/version.h @@ -28,10 +28,9 @@ #define PLUGIN_NAME "Mupen64Plus Bizhawk Input Plugin" #define PLUGIN_VERSION 0x016305 -#define INPUT_PLUGIN_API_VERSION 0x020000 -#define CONFIG_API_VERSION 0x020000 +#define INPUT_PLUGIN_API_VERSION 0x20101 +#define CONFIG_API_VERSION 0x020302 #define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff) #endif /* #define VERSION_H */ - diff --git a/src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs b/src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs index 2e195f31c03..df5b4c68e53 100644 --- a/src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs +++ b/src/BizHawk.Bizware.Graphics/OpenGL/SDL2OpenGLContext.cs @@ -1,4 +1,4 @@ -// #define DEBUG_OPENGL +#define DEBUG_OPENGL #if DEBUG_OPENGL using System.Runtime.InteropServices; @@ -198,13 +198,13 @@ public SDL2OpenGLContext(IntPtr nativeWindowhandle, int majorVersion, int minorV } } - public SDL2OpenGLContext(int majorVersion, int minorVersion, bool coreProfile) + public SDL2OpenGLContext(int majorVersion, int minorVersion, bool coreProfile, int width=1, int height=1) { // offscreen contexts are shared (as we want to send texture from it over to our control's context) // make sure to set the current graphics control context before creating this context SetAttributes(majorVersion, minorVersion, coreProfile, shareContext: true); - _sdlWindow = SDL_CreateWindow(null, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1, 1, + _sdlWindow = SDL_CreateWindow(null, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL_WindowFlags.SDL_WINDOW_HIDDEN); if (_sdlWindow == IntPtr.Zero) { @@ -280,4 +280,4 @@ public void SwapBuffers() SDL_GL_SwapWindow(_sdlWindow); } } -} \ No newline at end of file +} diff --git a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/OpenGLProvider.cs b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/OpenGLProvider.cs index b4793c7e8d4..03d634e307b 100644 --- a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/OpenGLProvider.cs +++ b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/OpenGLProvider.cs @@ -1,5 +1,6 @@ using BizHawk.Bizware.Graphics; using BizHawk.Emulation.Common; +using SDL2; namespace BizHawk.Client.EmuHawk { @@ -11,8 +12,12 @@ public class OpenGLProvider : IOpenGLProvider public bool SupportsGLVersion(int major, int minor) => OpenGLVersion.SupportsVersion(major, minor); - public object RequestGLContext(int major, int minor, bool coreProfile) - => new SDL2OpenGLContext(major, minor, coreProfile); + public object RequestGLContext(int major, int minor, bool coreProfile, int width=1, int height=1) + { + var ret = new SDL2OpenGLContext(major, minor, coreProfile, width, height); + ret.SetVsync(false); + return ret; + } public void ReleaseGLContext(object context) => ((SDL2OpenGLContext)context).Dispose(); @@ -25,5 +30,16 @@ public void DeactivateGLContext() public IntPtr GetGLProcAddress(string proc) => SDL2OpenGLContext.GetGLProcAddress(proc); + + public int GLGetAttribute(SDL.SDL_GLattr attribute) + { + _ = SDL.SDL_GL_GetAttribute(attribute, out int value); + return value; + } + + public void SwapBuffers(object context) + { + ((SDL2OpenGLContext)context).SwapBuffers(); + } } } diff --git a/src/BizHawk.Common/IImportResolver.cs b/src/BizHawk.Common/IImportResolver.cs index 017b4a784bf..e6a8eb74b97 100644 --- a/src/BizHawk.Common/IImportResolver.cs +++ b/src/BizHawk.Common/IImportResolver.cs @@ -44,6 +44,8 @@ public void Dispose() GC.SuppressFinalize(this); } + public IntPtr GetHandle() => _p; + ~DynamicLibraryImportResolver() { DisposeHelper(); diff --git a/src/BizHawk.Emulation.Common/Interfaces/IOpenGLProvider.cs b/src/BizHawk.Emulation.Common/Interfaces/IOpenGLProvider.cs index 10ba1498a50..c26d9de1517 100644 --- a/src/BizHawk.Emulation.Common/Interfaces/IOpenGLProvider.cs +++ b/src/BizHawk.Emulation.Common/Interfaces/IOpenGLProvider.cs @@ -1,3 +1,5 @@ +using SDL2; + namespace BizHawk.Emulation.Common { /// @@ -17,7 +19,7 @@ public interface IOpenGLProvider /// The requested OpenGL context will be shared with the current context /// Note: creating a context implicitly makes that created context current /// - public object RequestGLContext(int major, int minor, bool coreProfile); + public object RequestGLContext(int major, int minor, bool coreProfile, int width=1, int height=1); /// /// Frees this OpenGL context @@ -40,5 +42,13 @@ public interface IOpenGLProvider /// The user must make a context active before using this /// public IntPtr GetGLProcAddress(string proc); + + /// + /// Gets the current value for in the current OpenGL context + /// + /// The attribute to check + public int GLGetAttribute(SDL.SDL_GLattr attribute); + + public void SwapBuffers(object context); } } diff --git a/src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index f92e5268a81..f8474009fd3 100644 --- a/src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/src/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -75,5 +75,8 @@ + + Mupen64.cs + diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IDebuggable.cs new file mode 100644 index 00000000000..7d9db7185e0 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IDebuggable.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : IDebuggable +{ + public IDictionary GetCpuFlagsAndRegisters() + { + var ret = new Dictionary(); + + var pcPointer = Mupen64Api.DebugGetCPUDataPtr(Mupen64Api.m64p_dbg_cpu_data.PC); + ret.Add("PC", Marshal.ReadInt32(pcPointer)); + + var regPointer = Mupen64Api.DebugGetCPUDataPtr(Mupen64Api.m64p_dbg_cpu_data.REG_REG); + for (int i = 0; i < 32; i++) + { + ret.Add($"REG {i}", Marshal.ReadInt64(regPointer, 8 * i)); + } + + var hiPointer = Mupen64Api.DebugGetCPUDataPtr(Mupen64Api.m64p_dbg_cpu_data.REG_HI); + ret.Add("REG HI", Marshal.ReadInt64(hiPointer)); + + var loPointer = Mupen64Api.DebugGetCPUDataPtr(Mupen64Api.m64p_dbg_cpu_data.REG_LO); + ret.Add("REG LO", Marshal.ReadInt64(loPointer)); + + var cop0Pointer = Mupen64Api.DebugGetCPUDataPtr(Mupen64Api.m64p_dbg_cpu_data.REG_COP0); + for (int i = 0; i < 32; i++) + { + ret.Add($"COP0 {i}", Marshal.ReadInt32(cop0Pointer, 4 * i)); + } + + var cop1DoublePointer = Mupen64Api.DebugGetCPUDataPtr(Mupen64Api.m64p_dbg_cpu_data.REG_COP1_DOUBLE_PTR); + for (int i = 0; i < 32; i++) + { + ret.Add($"COP1 Double {i}", Marshal.ReadInt64(cop1DoublePointer, 8 * i)); + } + + var cop1SimplePointer = Mupen64Api.DebugGetCPUDataPtr(Mupen64Api.m64p_dbg_cpu_data.REG_COP1_SIMPLE_PTR); + for (int i = 0; i < 32; i++) + { + ret.Add($"COP1 Simple {i}", Marshal.ReadInt32(cop1SimplePointer, 4 * i)); + } + + var cop1FgrPointer = Mupen64Api.DebugGetCPUDataPtr(Mupen64Api.m64p_dbg_cpu_data.REG_COP1_FGR_64); + ret.Add("COP1 FGR", Marshal.ReadInt64(cop1FgrPointer)); + + // TLB? + + return ret; + } + + [FeatureNotImplemented] // could probably be implemented, just a bit annoying + public void SetCpuRegister(string register, int value) => throw new NotImplementedException(); + + // TODO: currently nonfunctional, need to do something similar to the old implementation probably + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem([ "System Bus" ]); + public bool CanStep(StepType type) + { + return type switch + { + StepType.Into => true, + _ => false + }; + } + + public void Step(StepType type) + { + switch (type) + { + case StepType.Into: + Mupen64Api.DebugSetRunState(Mupen64Api.m64p_dbg_runstate.PAUSED); // no-op when already paused + Mupen64Api.CoreDoCommand(Mupen64Api.m64p_command.ADVANCE_FRAME, 0, IntPtr.Zero); // no-op when already frame advancing + Mupen64Api.DebugStep(); + break; + + default: + throw new NotImplementedException(); + } + } + + [FeatureNotImplemented] // can probably implement this for pure interpreter at least, but is it worth it? + public long TotalExecutedCycles => throw new NotImplementedException(); +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IDisassemblable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IDisassemblable.cs new file mode 100644 index 00000000000..3a6dbb78fd0 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IDisassemblable.cs @@ -0,0 +1,32 @@ +using System.Buffers; +using System.Collections.Generic; +using System.Text; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : IDisassemblable +{ + public string Cpu { get; set; } = "R4300"; + + public string PCRegisterName => "PC"; + + public IEnumerable AvailableCpus { get; } = [ "R4300" ]; + + public string Disassemble(MemoryDomain m, uint addr, out int length) + { + uint instruction = m.PeekUint(addr, m.EndianType is MemoryDomain.Endian.Big); + length = 4; + + byte[] opBuffer = ArrayPool.Shared.Rent(128); + byte[] argsBuffer = ArrayPool.Shared.Rent(128); + Mupen64Api.DebugDecodeOp(instruction, opBuffer, argsBuffer, (int)addr); + string op = Encoding.UTF8.GetString(opBuffer, 0, Array.IndexOf(opBuffer, 0)); + string args = Encoding.UTF8.GetString(argsBuffer, 0, Array.IndexOf(argsBuffer, 0)); + + ArrayPool.Shared.Return(opBuffer); + ArrayPool.Shared.Return(argsBuffer); + + return $"{op}: {args}"; + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IInputPollable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IInputPollable.cs new file mode 100644 index 00000000000..b21abdbf402 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IInputPollable.cs @@ -0,0 +1,12 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : IInputPollable +{ + public int LagCount { get; set; } + + public bool IsLagFrame { get; set; } + + public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IMemoryDomains.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IMemoryDomains.cs new file mode 100644 index 00000000000..50208f577c1 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IMemoryDomains.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 +{ + private MemoryDomainList _memoryDomains; + + private void SetupMemoryDomains() + { + List memoryDomains = [ ]; + + foreach (Mupen64Api.m64p_dbg_memptr_type memoryDomain in Enum.GetValues(typeof(Mupen64Api.m64p_dbg_memptr_type))) + { + memoryDomains.Add(new MemoryDomainIntPtr( + Enum.GetName(typeof(Mupen64Api.m64p_dbg_memptr_type), memoryDomain), + MemoryDomain.Endian.Big, + Mupen64Api.DebugMemGetPointer(memoryDomain), + (long)Mupen64Api.DebugMemGetSize(memoryDomain), + true, + 4)); + } + + memoryDomains.Add(new MemoryDomainDelegate + ( + "System Bus", + uint.MaxValue, + MemoryDomain.Endian.Big, + address => Mupen64Api.DebugMemRead8((uint)address), + (address, value) => Mupen64Api.DebugMemWrite8((uint)address, value), + 4 + )); + + _memoryDomains = new MemoryDomainList(memoryDomains); + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IRegionable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IRegionable.cs new file mode 100644 index 00000000000..b5461d162df --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IRegionable.cs @@ -0,0 +1,22 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : IRegionable +{ + private DisplayType _region; + + public DisplayType Region + { + get => _region; + private init + { + _region = value; + VsyncNumerator = _region switch + { + DisplayType.PAL => 50, + _ => 60 + }; + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISaveRam.cs new file mode 100644 index 00000000000..5a9802e4f1e --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISaveRam.cs @@ -0,0 +1,31 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : ISaveRam +{ + public byte[] CloneSaveRam() + { + int saveRamSize = 0; + Mupen64Api.GetSaveRamSize(ref saveRamSize); + byte[] saveRamBuffer = new byte[saveRamSize]; + + Mupen64Api.GetSaveRam(saveRamBuffer); + + return saveRamBuffer; + } + + public void StoreSaveRam(byte[] data) + { + int saveRamSize = 0; + Mupen64Api.GetSaveRamSize(ref saveRamSize); + if (saveRamSize != data.Length) + { + throw new InvalidOperationException($"Core expects a savestate of size {saveRamSize}, but got {data.Length} bytes!"); + } + + Mupen64Api.PutSaveRam(data); + } + + public bool SaveRamModified => true; +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISettable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISettable.cs new file mode 100644 index 00000000000..9617e523dc2 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISettable.cs @@ -0,0 +1,105 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : ISettable +{ + private SyncSettings _syncSettings; + + public enum CoreType + { + [Display(Name = "Pure Interpreter")] + PureInterpreter = 0, + [Display(Name = "Cached Interpreter")] + CachedInterpreter = 1, + [Display(Name = "Dynamic Recompiler (DynaRec)")] + Dynarec = 2, + } + + public enum N64ControllerPakType + { + [Display(Name = "None")] + NoPak, + [Display(Name = "Memory Card")] + MemoryCard, + [Display(Name = "Rumble Pak")] + RumblePak, + [Display(Name = "Transfer Pak")] + TransferPak, + } + + [CoreSettings] + public record class SyncSettings + { + [DisplayName("Video Plugin name")] + [Description("Name of the video plugin to use, e.g. \"angrylion-plus\"")] + [DefaultValue("GLideN64")] + public string VideoPlugin { get; set; } + + [DisplayName("Rsp Plugin name")] + [Description("Name of the rsp plugin to use, e.g. \"hle\"")] + [DefaultValue("hle")] + public string RspPlugin { get; set; } + + [Description("The mode to run the cpu in")] + [DefaultValue(CoreType.Dynarec)] + [TypeConverter(typeof(DescribableEnumConverter))] + public CoreType CoreType { get; set; } + + [Description("Disable 4MB expansion RAM pack. May be necessary for some games")] + [DefaultValue(false)] + public bool DisableExpansionSlot { get; set; } + + [Description("Whether a controller is connected in port 1")] + [DefaultValue(true)] + public bool Port1Connected { get; set; } + [Description("Whether a controller is connected in port 2")] + [DefaultValue(false)] + public bool Port2Connected { get; set; } + [Description("Whether a controller is connected in port 3")] + [DefaultValue(false)] + public bool Port3Connected { get; set; } + [Description("Whether a controller is connected in port 4")] + [DefaultValue(false)] + public bool Port4Connected { get; set; } + + [Description("The type of expansion pak inserted into the expansion port of the controller connected to port 1")] + [DefaultValue(N64ControllerPakType.NoPak)] + [TypeConverter(typeof(DescribableEnumConverter))] + public N64ControllerPakType Port1PakType { get; set; } + [Description("The type of expansion pak inserted into the expansion port of the controller connected to port 2")] + [DefaultValue(N64ControllerPakType.NoPak)] + [TypeConverter(typeof(DescribableEnumConverter))] + public N64ControllerPakType Port2PakType { get; set; } + [Description("The type of expansion pak inserted into the expansion port of the controller connected to port 3")] + [DefaultValue(N64ControllerPakType.NoPak)] + [TypeConverter(typeof(DescribableEnumConverter))] + public N64ControllerPakType Port3PakType { get; set; } + [Description("The type of expansion pak inserted into the expansion port of the controller connected to port 4")] + [DefaultValue(N64ControllerPakType.NoPak)] + [TypeConverter(typeof(DescribableEnumConverter))] + public N64ControllerPakType Port4PakType { get; set; } + + public SyncSettings() => SettingsUtil.SetDefaultValues(this); + } + + public object GetSettings() => null; + + public SyncSettings GetSyncSettings() + { + return _syncSettings with { }; + } + + public PutSettingsDirtyBits PutSettings(object o) => throw new InvalidOperationException("This core does not have any (non-sync) settings"); + + public PutSettingsDirtyBits PutSyncSettings(SyncSettings o) + { + var ret = PutSettingsDirtyBits.None; + if (_syncSettings != o) ret = PutSettingsDirtyBits.RebootCore; + _syncSettings = o; + return ret; + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISoundProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISoundProvider.cs new file mode 100644 index 00000000000..df00b55f449 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ISoundProvider.cs @@ -0,0 +1,41 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 +{ + private const int BIZHAWK_OUTPUT_SAMPLERATE = 44100; + private SDLResampler _resampler; + private int _currentInputRate; + private short[] _audioBuffer = [ ]; + + private void InitSound(int sourceRate) + { + _currentInputRate = sourceRate; + _resampler = new SDLResampler(sourceRate, BIZHAWK_OUTPUT_SAMPLERATE); + } + + private void UpdateAudio(bool renderSound) + { + int newAudioRate = AudioPluginApi.GetAudioRate(); + if (newAudioRate != _currentInputRate) + { + _resampler.ChangeRate(newAudioRate, BIZHAWK_OUTPUT_SAMPLERATE); + _currentInputRate = newAudioRate; + } + + int audioBufferSize = AudioPluginApi.GetBufferSize(); + if (_audioBuffer.Length < audioBufferSize) + { + _audioBuffer = new short[audioBufferSize]; + } + + if (audioBufferSize > 0) + { + Console.WriteLine($"reading and enqueuing {audioBufferSize} samples"); + AudioPluginApi.ReadAudioBuffer(_audioBuffer); + if (renderSound) + _resampler.EnqueueSamples(_audioBuffer, audioBufferSize / 2); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IStatable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IStatable.cs new file mode 100644 index 00000000000..614780aa031 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IStatable.cs @@ -0,0 +1,40 @@ +using System.IO; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : IStatable +{ + private const int SAVESTATE_SIZE = 16788288 + 1024 + 4 + 4096; + private readonly byte[] _savestateBuffer = new byte[SAVESTATE_SIZE]; + + public bool AvoidRewind => false; + + public void SaveStateBinary(BinaryWriter writer) + { + writer.Write(Frame); + writer.Write(LagCount); + writer.Write(IsLagFrame); + + Mupen64Api.SaveSavestate(_savestateBuffer); + writer.Write(_savestateBuffer, 0, SAVESTATE_SIZE); + } + + public void LoadStateBinary(BinaryReader reader) + { + Frame = reader.ReadInt32(); + LagCount = reader.ReadInt32(); + IsLagFrame = reader.ReadBoolean(); + + bool success = reader.Read(_savestateBuffer, 0, SAVESTATE_SIZE) == SAVESTATE_SIZE; + if (success) + { + success = Mupen64Api.LoadSavestate(_savestateBuffer); + } + + if (!success) + { + Console.Error.WriteLine("Failed to load mupen savestate!"); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ITraceable.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ITraceable.cs new file mode 100644 index 00000000000..5aa25ec481f --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.ITraceable.cs @@ -0,0 +1,37 @@ +using System.Text; +using BizHawk.Common; +using BizHawk.Emulation.Common; +using static BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64.Mupen64Api.m64p_dbg_runstate; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : ITraceable +{ + public string Header => "R3400: PC, mnemonic, operands"; + + private readonly Mupen64Api.dbg_frontend_init _debuggerInitCallback; + private readonly Mupen64Api.dbg_frontend_update _traceCallback; + + private void DebuggerInitCallback() => Mupen64Api.DebugSetRunState(RUNNING); + + private void TraceCallback(uint pc) + { + if (Sink is null) return; + + string disassembly = this.Disassemble(_memoryDomains.SystemBus, pc, out _); + var registerInfo = GetCpuFlagsAndRegisters(); + StringBuilder registerStringBuilder = new(); + registerStringBuilder.Append($"PC:{registerInfo["PC"].Value.ToString($"X{registerInfo["PC"].BitSize / 4}")}"); + foreach (var (registerName, registerValue) in registerInfo) + { + if (registerName.Contains("REG")) + { + registerStringBuilder.Append($" {registerName}:{registerValue.Value.ToString($"X{registerValue.BitSize / 4}")}"); + } + + } + Sink.Put(new TraceInfo(disassembly, registerStringBuilder.ToString())); + } + + public ITraceSink Sink { get; set; } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IVideoProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IVideoProvider.cs new file mode 100644 index 00000000000..f4914858fd8 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.IVideoProvider.cs @@ -0,0 +1,53 @@ +using System.Diagnostics; +using System.Threading; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 : IVideoProvider +{ + public int[] GetVideoBuffer() + { + return _videoBuffer; + } + + public int VirtualWidth => BufferWidth; + public int VirtualHeight => BufferHeight; + public int BufferWidth { get; private set; } + public int BufferHeight { get; private set; } + public int VsyncNumerator { get; private init; } + public int VsyncDenominator => 1; + public int BackgroundColor => 0; + + private readonly Mupen64Api.m64p_frame_callback _frameCallback; + + private int[] _videoBuffer = [ ]; + private byte[] _retVideoBuffer = [ ]; + + private readonly EventWaitHandle _frameFinished = new AutoResetEvent(false); + + private void FrameCallback(uint frameIndex) + { + int width = 0; + int height = 0; + VideoPluginApi.ReadScreen2(IntPtr.Zero, ref width, ref height, 1); + Debug.Assert(width <= BufferWidth); + Debug.Assert(height <= BufferHeight); + + Array.Clear(_videoBuffer, width * height, _videoBuffer.Length - width * height); + + VideoPluginApi.ReadScreen2(_retVideoBuffer, ref width, ref height, 1); + // the returned video buffer is in format RGB888 and also flipped vertically + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++) + { + byte r = _retVideoBuffer[3*(height-y-1) * width + 3*x]; + byte g = _retVideoBuffer[3*(height-y-1) * width + 3*x + 1]; + byte b = _retVideoBuffer[3*(height-y-1) * width + 3*x + 2]; + int argb = (r << 16) | (g << 8) | (b << 0); + _videoBuffer[y * width + x] = argb; + } + + _frameFinished.Set(); + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.VideoExtensions.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.VideoExtensions.cs new file mode 100644 index 00000000000..067adaa0a5b --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.VideoExtensions.cs @@ -0,0 +1,153 @@ +using System.Collections.Generic; +using SDL2; +using static BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64.Mupen64Api; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public partial class Mupen64 +{ + private static SDL.SDL_GLattr MupenToSDLAttribute(m64p_GLattr value) + { + return value switch + { + m64p_GLattr.DOUBLEBUFFER => SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, + m64p_GLattr.BUFFER_SIZE => SDL.SDL_GLattr.SDL_GL_BUFFER_SIZE, + m64p_GLattr.DEPTH_SIZE => SDL.SDL_GLattr.SDL_GL_DEPTH_SIZE, + m64p_GLattr.RED_SIZE => SDL.SDL_GLattr.SDL_GL_RED_SIZE, + m64p_GLattr.GREEN_SIZE => SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, + m64p_GLattr.BLUE_SIZE => SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, + m64p_GLattr.ALPHA_SIZE => SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, + m64p_GLattr.MULTISAMPLEBUFFERS => SDL.SDL_GLattr.SDL_GL_MULTISAMPLEBUFFERS, + m64p_GLattr.MULTISAMPLESAMPLES => SDL.SDL_GLattr.SDL_GL_MULTISAMPLESAMPLES, + m64p_GLattr.CONTEXT_MAJOR_VERSION => SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, + m64p_GLattr.CONTEXT_MINOR_VERSION => SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, + m64p_GLattr.CONTEXT_PROFILE_MASK => SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, + _ => (SDL.SDL_GLattr)(-1) + }; + } + + private readonly Dictionary GLAttributes = [ ]; + + private static m64p_error VidExt_Init() + { + return m64p_error.SUCCESS; + } + + private static m64p_error VidExt_Quit() + { + return m64p_error.SUCCESS; + } + + private static m64p_error VidExt_ListFullscreenModes(m64p_2d_size[] sizeArray, ref int numSizes) + { + return m64p_error.UNSUPPORTED; + } + + private static m64p_error VidExt_ListFullscreenRates(m64p_2d_size size, ref int numRates, int[] rates) + { + return m64p_error.UNSUPPORTED; + } + + private m64p_error VidExt_SetVideoMode(int width, int height, int bitsPerPixel, m64p_video_mode screenMode, m64p_video_flags flags) + { + isRenderThread = true; + Console.WriteLine($"Attempted to SetVideoMode, width {width}, height {height}, bpp {bitsPerPixel}, screenMode {screenMode}, flags {flags}"); + if (_glContext is not null) + _openGLProvider.ReleaseGLContext(_glContext); + if (!GLAttributes.TryGetValue(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, out int major)) major = 2; + if (!GLAttributes.TryGetValue(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, out int minor)) minor = 1; + bool coreProfile = GLAttributes.TryGetValue(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, out int profile) && (SDL.SDL_GLprofile)profile == SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE; + _glContext = _openGLProvider.RequestGLContext(major, minor, coreProfile, width, height); + + BufferWidth = width; + BufferHeight = height; + if (_videoBuffer.Length < width * height) + { + _videoBuffer = new int[width * height]; + _retVideoBuffer = new byte[width * height * 3]; + } + + return m64p_error.SUCCESS; + } + + private m64p_error VidExt_SetVideoModeWithRate(int width, int height, int refreshRate, int bitsPerPixel, m64p_video_mode screenMode, m64p_video_flags flags) + { + return VidExt_SetVideoMode(width, height, bitsPerPixel, screenMode, flags); + } + + private IntPtr VidExt_GL_GetProcAddress(string proc) + { + return _openGLProvider.GetGLProcAddress(proc); + } + + private m64p_error VidExt_GL_SetAttribute(m64p_GLattr attr, int value) + { + // TODO: this only supports version and profile right now; are others important? + var attribute = MupenToSDLAttribute(attr); + if (attribute == (SDL.SDL_GLattr)(-1)) + return m64p_error.INPUT_INVALID; + + GLAttributes[attribute] = value; + + return m64p_error.SUCCESS; + } + + private m64p_error VidExt_GL_GetAttribute(m64p_GLattr attr, ref int pValue) + { + var attribute = MupenToSDLAttribute(attr); + if (attribute == (SDL.SDL_GLattr)(-1)) + return m64p_error.INPUT_INVALID; + + pValue = GLAttributes.TryGetValue(attribute, out int value) ? value : _openGLProvider.GLGetAttribute(attribute); + + return m64p_error.SUCCESS; + } + + [ThreadStatic] + private static bool isRenderThread; + + private m64p_error VidExt_GL_SwapBuffers() + { + if (isRenderThread) + _openGLProvider.SwapBuffers(_glContext); + + Console.WriteLine("SwapBuffers was called."); + + return m64p_error.SUCCESS; + } + + private static m64p_error VidExt_SetCaption(string title) + { + return m64p_error.UNSUPPORTED; + } + + private static m64p_error VidExt_ToggleFullScreen() + { + return m64p_error.UNSUPPORTED; + } + + private static m64p_error VidExt_ResizeWindow(int width, int height) + { + return m64p_error.UNSUPPORTED; + } + + private static uint VidExt_GL_GetDefaultFramebuffer() + { + return 0; + } + + private static m64p_error VidExt_InitWithRenderMode(m64p_render_mode renderMode) + { + return renderMode is m64p_render_mode.OPENGL ? m64p_error.SUCCESS : m64p_error.UNSUPPORTED; + } + + private static m64p_error VidExt_VK_GetSurface(ref IntPtr surface, IntPtr instance) + { + return m64p_error.UNSUPPORTED; + } + + private static m64p_error VidExt_VK_GetInstanceExtensions(ref IntPtr extensions, ref uint numExtensions) + { + return m64p_error.UNSUPPORTED; + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.cs new file mode 100644 index 00000000000..a1d39aee36a --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64.cs @@ -0,0 +1,319 @@ +using System.Runtime.InteropServices; +using System.Threading; +using BizHawk.BizInvoke; +using BizHawk.Common; +using BizHawk.Emulation.Common; +using static BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64.Mupen64Api; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +[PortedCore(CoreNames.Mupen64Plus, "", "2.6.0", "https://github.com/mupen64plus/mupen64plus-core", isReleased: false)] +public partial class Mupen64 : IEmulator +{ + private readonly IOpenGLProvider _openGLProvider; + private object _glContext; + + private readonly Mupen64Api Mupen64Api; + private readonly IntPtr Mupen64ApiHandle; + + private readonly Mupen64VideoPluginApi VideoPluginApi; + private readonly IntPtr VideoPluginApiHandle; + + private readonly Mupen64AudioPluginApi AudioPluginApi; + private readonly IntPtr AudioPluginApiHandle; + + private readonly Mupen64InputPluginApi InputPluginApi; + private readonly IntPtr InputPluginApiHandle; + + private readonly Mupen64PluginApi RspPluginApi; + private readonly IntPtr RspPluginApiHandle; + + private readonly m64p_video_extension_functions_managed _videoExtensionFunctionsManaged; + private readonly Thread _coreThread; + private IController _controller; + private bool _disposed; + + private void DebugCallback(IntPtr context, int level, string message) + { + Console.WriteLine($"DEBUG CALLBACK {level}: {message}"); + } + + private readonly DebugCallback _debugCallback; + private readonly Mupen64InputPluginApi.InputCallback _inputCallback; + private readonly Mupen64InputPluginApi.RumbleCallback _rumbleCallback; + + [CoreConstructor(VSystemID.Raw.N64)] + public Mupen64(CoreLoadParameters loadParameters) + { + _openGLProvider = loadParameters.Comm.OpenGLProvider; + _syncSettings = loadParameters.SyncSettings ?? new SyncSettings(); + + var rom = loadParameters.Roms[0]; + + byte countryCode = rom.RomData[0x3E]; + // taken from mupen64 source + Region = countryCode switch + { + // PAL codes + 0x44 or 0x46 or 0x49 or 0x50 or 0x53 or 0x55 or 0x58 or 0x59 => DisplayType.PAL, + // NTSC codes + _ => DisplayType.NTSC, + }; + + (Mupen64Api, Mupen64ApiHandle) = LoadLib("mupen64plus"); + + _stateCallback = StateChanged; + _debugCallback = DebugCallback; + _traceCallback = TraceCallback; + _debuggerInitCallback = DebuggerInitCallback; + Mupen64Api.DebugSetCallbacks(_debuggerInitCallback, _traceCallback, null); + + var error = Mupen64Api.CoreStartup(FRONTEND_API_VERSION, null, null, IntPtr.Zero, _debugCallback, IntPtr.Zero, _stateCallback); + Console.WriteLine(error.ToString()); + + IntPtr coreConfigSection = IntPtr.Zero; + Mupen64Api.ConfigOpenSection("Core", ref coreConfigSection); + unsafe + { + var coreType = _syncSettings.CoreType; + Mupen64Api.ConfigSetParameter(coreConfigSection, "R4300Emulator", m64p_type.INT, (IntPtr)(&coreType)); + bool disableExtraMem = _syncSettings.DisableExpansionSlot; + Mupen64Api.ConfigSetParameter(coreConfigSection, "DisableExtraMem", m64p_type.BOOL, (IntPtr)(&disableExtraMem)); + bool randomizeInterrupt = false; + Mupen64Api.ConfigSetParameter(coreConfigSection, "RandomizeInterrupt", m64p_type.BOOL, (IntPtr)(&randomizeInterrupt)); + bool enableDebugger = true; + Mupen64Api.ConfigSetParameter(coreConfigSection, "EnableDebugger", m64p_type.BOOL, (IntPtr)(&enableDebugger)); + } + + _videoExtensionFunctionsManaged = new m64p_video_extension_functions_managed + { + VidExt_Init = VidExt_Init, + VidExt_Quit = VidExt_Quit, + VidExt_ListFullscreenModes = VidExt_ListFullscreenModes, + VidExt_ListFullscreenRates = VidExt_ListFullscreenRates, + VidExt_SetVideoMode = VidExt_SetVideoMode, + VidExt_SetVideoModeWithRate = VidExt_SetVideoModeWithRate, + VidExt_GL_GetProcAddress = VidExt_GL_GetProcAddress, + VidExt_GL_SetAttribute = VidExt_GL_SetAttribute, + VidExt_GL_GetAttribute = VidExt_GL_GetAttribute, + VidExt_GL_SwapBuffers = VidExt_GL_SwapBuffers, + VidExt_SetCaption = VidExt_SetCaption, + VidExt_ToggleFullScreen = VidExt_ToggleFullScreen, + VidExt_ResizeWindow = VidExt_ResizeWindow, + VidExt_GL_GetDefaultFramebuffer = VidExt_GL_GetDefaultFramebuffer, + VidExt_InitWithRenderMode = VidExt_InitWithRenderMode, + VidExt_VK_GetSurface = VidExt_VK_GetSurface, + VidExt_VK_GetInstanceExtensions = VidExt_VK_GetInstanceExtensions, + }; + var videoExtensions = new m64p_video_extension_functions(_videoExtensionFunctionsManaged); + error = Mupen64Api.CoreOverrideVidExt(ref videoExtensions); + Console.WriteLine(error.ToString()); + + error = Mupen64Api.CoreDoCommand(m64p_command.ROM_OPEN, rom.RomData.Length, rom.RomData); + Console.WriteLine(error.ToString()); + + var videoPluginName = $"mupen64plus-video-{_syncSettings.VideoPlugin}"; + (VideoPluginApi, VideoPluginApiHandle) = LoadLib(videoPluginName); + error = VideoPluginApi.PluginStartup(Mupen64ApiHandle, IntPtr.Zero, IntPtr.Zero); + Console.WriteLine(error.ToString()); + error = Mupen64Api.CoreAttachPlugin(m64p_plugin_type.GFX, VideoPluginApiHandle); + Console.WriteLine(error.ToString()); + + (AudioPluginApi, AudioPluginApiHandle) = LoadLib("mupen64plus-audio-bkm"); + error = AudioPluginApi.PluginStartup(Mupen64ApiHandle, IntPtr.Zero, IntPtr.Zero); + Console.WriteLine(error.ToString()); + error = Mupen64Api.CoreAttachPlugin(m64p_plugin_type.AUDIO, AudioPluginApiHandle); + Console.WriteLine(error.ToString()); + + (InputPluginApi, InputPluginApiHandle) = LoadLib("mupen64plus-input-bkm"); + error = InputPluginApi.PluginStartup(Mupen64ApiHandle, IntPtr.Zero, IntPtr.Zero); + Console.WriteLine(error.ToString()); + error = Mupen64Api.CoreAttachPlugin(m64p_plugin_type.INPUT, InputPluginApiHandle); + Console.WriteLine(error.ToString()); + + var rspPluginName = $"mupen64plus-rsp-{_syncSettings.RspPlugin}"; + (RspPluginApi, RspPluginApiHandle) = LoadLib(rspPluginName); + error = RspPluginApi.PluginStartup(Mupen64ApiHandle, IntPtr.Zero, IntPtr.Zero); + Console.WriteLine(error.ToString()); + error = Mupen64Api.CoreAttachPlugin(m64p_plugin_type.RSP, RspPluginApiHandle); + Console.WriteLine(error.ToString()); + + _frameCallback = FrameCallback; + error = Mupen64Api.CoreDoCommand(m64p_command.SET_FRAME_CALLBACK, 0, Marshal.GetFunctionPointerForDelegate(_frameCallback)); + Console.WriteLine(error.ToString()); + + ControllerDefinition = Mupen64Controller.MakeControllerDefinition(_syncSettings); + _inputCallback = InputCallback; + _rumbleCallback = RumbleCallback; + InputPluginApi.SetInputCallback(_inputCallback); + InputPluginApi.SetRumbleCallback(_rumbleCallback); + InputPluginApi.SetControllerConnected(0, _syncSettings.Port1Connected); + InputPluginApi.SetControllerConnected(1, _syncSettings.Port2Connected); + InputPluginApi.SetControllerConnected(2, _syncSettings.Port3Connected); + InputPluginApi.SetControllerConnected(3, _syncSettings.Port4Connected); + InputPluginApi.SetControllerPakType(0, _syncSettings.Port1PakType); + InputPluginApi.SetControllerPakType(1, _syncSettings.Port1PakType); + InputPluginApi.SetControllerPakType(2, _syncSettings.Port1PakType); + InputPluginApi.SetControllerPakType(3, _syncSettings.Port1PakType); + + InitSound(AudioPluginApi.GetAudioRate()); + + var serviceProvider = new BasicServiceProvider(this); + serviceProvider.Register(_resampler); + if (_syncSettings.CoreType == CoreType.Dynarec) + { + serviceProvider.Unregister(); + serviceProvider.Unregister(); + } + + Mupen64Api.CoreStateSet(m64p_core_param.SPEED_LIMITER, 0); + _coreThread = new Thread(RunEmulator) {IsBackground = true}; + _coreThread.Start(); + _frameFinished.WaitOne(); + + SetupMemoryDomains(); + serviceProvider.Register(_memoryDomains); + ServiceProvider = serviceProvider; + } + + public IEmulatorServiceProvider ServiceProvider { get; } + public ControllerDefinition ControllerDefinition { get; } + + public bool FrameAdvance(IController controller, bool render, bool renderSound = true) + { + _controller = controller; + // if a tracer is active (Sink != null), set debug mode to stepping so the trace callback gets called + Mupen64Api.DebugSetRunState(Sink is null ? m64p_dbg_runstate.RUNNING : m64p_dbg_runstate.STEPPING); + Mupen64Api.DebugStep(); // make sure we aren't stuck in paused debugger state (from stepping); no-op if not stepping + // m64p_emu_state retState = 0; + // var retStatePointer = &retState; + // Mupen64Api.CoreDoCommand(m64p_command.M64CMD_CORE_STATE_QUERY, (int)m64p_core_param.M64CORE_EMU_STATE, (IntPtr)retStatePointer); + // Console.WriteLine($"Current state: {retState}"); + + if (controller.IsPressed("Reset")) + { + Mupen64Api.CoreDoCommand(m64p_command.RESET, 0, IntPtr.Zero); + } + else if (controller.IsPressed("Power")) + { + Mupen64Api.CoreDoCommand(m64p_command.RESET, 1, IntPtr.Zero); + } + + IsLagFrame = true; + var error = Mupen64Api.CoreDoCommand(m64p_command.ADVANCE_FRAME, 0, IntPtr.Zero); + Console.WriteLine(error.ToString()); + _frameFinished.WaitOne(); + UpdateAudio(renderSound); + Frame++; + if (IsLagFrame) LagCount++; + + return true; + } + + public int Frame { get; private set; } + public string SystemId => VSystemID.Raw.N64; + public bool DeterministicEmulation => true; // XD + + public void ResetCounters() + { + Frame = 0; + LagCount = 0; + IsLagFrame = false; + } + + public void Dispose() + { + if (_disposed) return; + _disposed = true; + + Console.WriteLine("entering dispose..."); + Mupen64Api.CoreDoCommand(m64p_command.STOP, 0, IntPtr.Zero); + // the stop command requires trying to advance an additional frame before the core actually stops, as the core is currently paused + var error = Mupen64Api.CoreDoCommand(m64p_command.ADVANCE_FRAME, 0, IntPtr.Zero); + Console.WriteLine(error.ToString()); + // don't use Thread.Join, see #3220 + while (_coreThread.IsAlive) + { + Thread.Sleep(1); + } + + Mupen64Api.CoreDetachPlugin(m64p_plugin_type.GFX); + VideoPluginApi.PluginShutdown(); + OSTailoredCode.LinkedLibManager.FreeByPtr(VideoPluginApiHandle); + + Mupen64Api.CoreDetachPlugin(m64p_plugin_type.AUDIO); + AudioPluginApi.PluginShutdown(); + OSTailoredCode.LinkedLibManager.FreeByPtr(AudioPluginApiHandle); + + Mupen64Api.CoreDetachPlugin(m64p_plugin_type.INPUT); + InputPluginApi.PluginShutdown(); + OSTailoredCode.LinkedLibManager.FreeByPtr(InputPluginApiHandle); + + Mupen64Api.CoreDetachPlugin(m64p_plugin_type.RSP); + RspPluginApi.PluginShutdown(); + OSTailoredCode.LinkedLibManager.FreeByPtr(RspPluginApiHandle); + + Mupen64Api.CoreDoCommand(m64p_command.ROM_CLOSE, 0, IntPtr.Zero); + Mupen64Api.CoreShutdown(); + OSTailoredCode.LinkedLibManager.FreeByPtr(Mupen64ApiHandle); + + if (_glContext is not null) + _openGLProvider.ReleaseGLContext(_glContext); + } + + private bool _hasPaused; + private readonly StateCallback _stateCallback; + private void StateChanged(IntPtr context2, m64p_core_param paramChanged, int newValue) + { + Console.WriteLine($"State changed! Param {paramChanged}, new value {newValue}"); + + if (paramChanged == m64p_core_param.EMU_STATE) + { + var newState = (m64p_emu_state)newValue; + if (newState == m64p_emu_state.RUNNING) + { + if (_hasPaused) return; + _hasPaused = true; + // can't actually send the pause command here because it'll immediately get overwritten again + // luckily the frame advance command is effectively the same; just pauses after the next frame + Mupen64Api.CoreDoCommand(m64p_command.ADVANCE_FRAME, 0, IntPtr.Zero); + } + } + } + + private void RunEmulator() => Mupen64Api.CoreDoCommand(m64p_command.EXECUTE, 0, IntPtr.Zero); + + private static (T Lib, IntPtr NativeHandle) LoadLib(string name) where T : class + { + var resolver = new DynamicLibraryImportResolver(OSTailoredCode.IsUnixHost ? $"lib{name}.so" : $"{name}.dll", hasLimitedLifetime: false); + return (BizInvoker.GetInvoker(resolver, CallingConventionAdapters.Native), resolver.GetHandle()); + } + + private Mupen64InputPluginApi.InputState InputCallback(int controller) + { + IsLagFrame = false; + InputCallbacks.Call(); + + controller++; + var ret = new Mupen64InputPluginApi.InputState(); + if (controller == 1 && _syncSettings.Port1Connected || controller == 2 && _syncSettings.Port2Connected + || controller == 3 && _syncSettings.Port3Connected || controller == 4 && _syncSettings.Port4Connected) + { + ret.X_AXIS = (sbyte) _controller.AxisValue($"P{controller} X Axis"); + ret.Y_AXIS = (sbyte) _controller.AxisValue($"P{controller} Y Axis"); + } + + for (int index = 0; index < Mupen64Controller.BoolButtons.Length; index++) + { + if (_controller.IsPressed($"P{controller} {Mupen64Controller.BoolButtons[index]}")) ret.boolButtons |= (Mupen64InputPluginApi.BoolButtons)(1 << index); + } + + return ret; + } + + private void RumbleCallback(int controller, bool on) + { + controller++; + _controller.SetHapticChannelStrength($"P{controller} Rumble Pak", on ? int.MaxValue : 0); + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64Api.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64Api.cs new file mode 100644 index 00000000000..cddab4c102f --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64Api.cs @@ -0,0 +1,333 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using BizHawk.BizInvoke; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public abstract class Mupen64Api +{ + public const int FRONTEND_API_VERSION = 0x020106; + + public enum m64p_error + { + SUCCESS = 0, + NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */ + ALREADY_INIT, /* InitMupen64Plus() was called twice */ + INCOMPATIBLE, /* API versions between components are incompatible */ + INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */ + INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */ + INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */ + NO_MEMORY, /* Memory allocation failed */ + FILES, /* Error opening, creating, reading, or writing to a file */ + INTERNAL, /* Internal error (bug) */ + INVALID_STATE, /* Current program state does not allow operation */ + PLUGIN_FAIL, /* A plugin function returned a fatal error */ + SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */ + UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */ + WRONG_TYPE /* A given input type parameter cannot be used for desired operation */ + } + + public enum m64p_command + { + NOP = 0, + ROM_OPEN, + ROM_CLOSE, + ROM_GET_HEADER, + ROM_GET_SETTINGS, + EXECUTE, + STOP, + PAUSE, + RESUME, + CORE_STATE_QUERY, + STATE_LOAD, + STATE_SAVE, + STATE_SET_SLOT, + SEND_SDL_KEYDOWN, + SEND_SDL_KEYUP, + SET_FRAME_CALLBACK, + TAKE_NEXT_SCREENSHOT, + CORE_STATE_SET, + READ_SCREEN, + RESET, + ADVANCE_FRAME + } + + public enum m64p_plugin_type + { + NULL = 0, + RSP = 1, + GFX, + AUDIO, + INPUT, + CORE + } + + public enum m64p_core_param + { + EMU_STATE = 1, + VIDEO_MODE, + SAVESTATE_SLOT, + SPEED_FACTOR, + SPEED_LIMITER, + VIDEO_SIZE, + AUDIO_VOLUME, + AUDIO_MUTE, + INPUT_GAMESHARK, + STATE_LOADCOMPLETE, + STATE_SAVECOMPLETE + } + + public enum m64p_emu_state + { + STOPPED = 1, + RUNNING, + PAUSED + } + + [StructLayout(LayoutKind.Sequential)] + public struct m64p_2d_size + { + public uint uiWidth; + public uint uiHeight; + } + + public enum m64p_video_mode + { + NONE = 1, + WINDOWED, + FULLSCREEN + } + + public enum m64p_video_flags + { + SUPPORT_RESIZING = 1 + } + + public enum m64p_GLattr + { + DOUBLEBUFFER = 1, + BUFFER_SIZE, + DEPTH_SIZE, + RED_SIZE, + GREEN_SIZE, + BLUE_SIZE, + ALPHA_SIZE, + SWAP_CONTROL, + MULTISAMPLEBUFFERS, + MULTISAMPLESAMPLES, + CONTEXT_MAJOR_VERSION, + CONTEXT_MINOR_VERSION, + CONTEXT_PROFILE_MASK + } + + public enum m64p_render_mode + { + OPENGL = 0, + VULKAN + } + + public enum m64p_dbg_memptr_type + { + RDRAM = 1, + PI_REG, + SI_REG, + VI_REG, + RI_REG, + AI_REG + } + + public enum m64p_type { + INT = 1, + FLOAT, + BOOL, + STRING + } + + public enum m64p_dbg_runstate + { + PAUSED = 0, + STEPPING, + RUNNING + } + + public enum m64p_dbg_cpu_data + { + PC = 1, + REG_REG, + REG_HI, + REG_LO, + REG_COP0, + REG_COP1_DOUBLE_PTR, + REG_COP1_SIMPLE_PTR, + REG_COP1_FGR_64, + TLB + } + + private const int VidExtFunctions = 17; + public delegate m64p_error VidExtFuncInit(); + public delegate m64p_error VidExtFuncQuit(); + public delegate m64p_error VidExtFuncListModes(m64p_2d_size[] sizeArray, ref int numSizes); + public delegate m64p_error VidExtFuncListRates(m64p_2d_size size, ref int numRates, int[] rates); + public delegate m64p_error VidExtFuncSetMode(int width, int height, int bitsPerPixel, m64p_video_mode screenMode, m64p_video_flags flags); + public delegate m64p_error VidExtFuncSetModeWithRate(int width, int height, int refreshRate, int bitsPerPixel, m64p_video_mode screenMode, m64p_video_flags flags); + public delegate IntPtr VidExtFuncGLGetProc(string proc); + public delegate m64p_error VidExtFuncGLSetAttr(m64p_GLattr attr, int value); + public delegate m64p_error VidExtFuncGLGetAttr(m64p_GLattr attr, ref int pValue); + public delegate m64p_error VidExtFuncGLSwapBuf(); + public delegate m64p_error VidExtFuncSetCaption(string title); + public delegate m64p_error VidExtFuncToggleFS(); + public delegate m64p_error VidExtFuncResizeWindow(int width, int height); + public delegate uint VidExtFuncGLGetDefaultFramebuffer(); + public delegate m64p_error VidExtFuncInitWithRenderMode(m64p_render_mode renderMode); + public delegate m64p_error VidExtFuncVKGetSurface(ref IntPtr surface, IntPtr instance); + public delegate m64p_error VidExtFuncVKGetInstanceExtensions(ref IntPtr extensions, ref uint numExtensions); + + [StructLayout(LayoutKind.Sequential)] + public sealed class m64p_video_extension_functions_managed + { + public VidExtFuncInit VidExt_Init; + public VidExtFuncQuit VidExt_Quit; + public VidExtFuncListModes VidExt_ListFullscreenModes; + public VidExtFuncListRates VidExt_ListFullscreenRates; + public VidExtFuncSetMode VidExt_SetVideoMode; + public VidExtFuncSetModeWithRate VidExt_SetVideoModeWithRate; + public VidExtFuncGLGetProc VidExt_GL_GetProcAddress; + public VidExtFuncGLSetAttr VidExt_GL_SetAttribute; + public VidExtFuncGLGetAttr VidExt_GL_GetAttribute; + public VidExtFuncGLSwapBuf VidExt_GL_SwapBuffers; + public VidExtFuncSetCaption VidExt_SetCaption; + public VidExtFuncToggleFS VidExt_ToggleFullScreen; + public VidExtFuncResizeWindow VidExt_ResizeWindow; + public VidExtFuncGLGetDefaultFramebuffer VidExt_GL_GetDefaultFramebuffer; + public VidExtFuncInitWithRenderMode VidExt_InitWithRenderMode; + public VidExtFuncVKGetSurface VidExt_VK_GetSurface; + public VidExtFuncVKGetInstanceExtensions VidExt_VK_GetInstanceExtensions; + + private static List FieldsInOrder; + + public IEnumerable AllDelegatesInMemoryOrder() + { + FieldsInOrder ??= typeof(m64p_video_extension_functions_managed) + .GetFields() + .OrderBy(BizInvokerUtilities.ComputeFieldOffset) + .ToList(); + return FieldsInOrder + .Select(f => (Delegate)f.GetValue(this)); + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct m64p_video_extension_functions + { + private uint Functions; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = VidExtFunctions)] + private IntPtr[] ExtensionFunctions; + + public m64p_video_extension_functions(m64p_video_extension_functions_managed extensionFunctionsManaged) + { + ExtensionFunctions = extensionFunctionsManaged.AllDelegatesInMemoryOrder() + .Select(Marshal.GetFunctionPointerForDelegate) + .ToArray(); + Functions = (uint)ExtensionFunctions.Length; + if (Functions != VidExtFunctions) + throw new InvalidOperationException($"{nameof(m64p_video_extension_functions_managed)} needs to have {VidExtFunctions} function pointers set, but got {Functions}."); + } + } + + public delegate void m64p_frame_callback(uint frameIndex); + public delegate void StateCallback(IntPtr context2, m64p_core_param paramChanged, int newValue); + public delegate void DebugCallback(IntPtr context, int level, string message); + + public delegate void dbg_frontend_init(); + public delegate void dbg_frontend_update(uint pc); + public delegate void dbg_frontend_vi(); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error CoreStartup(int apiVersion, string configPath, string dataPath, IntPtr context, DebugCallback debugCallback, IntPtr context2, StateCallback stateCallback); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error CoreShutdown(); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error CoreAttachPlugin(m64p_plugin_type pluginType, IntPtr pluginLibHandle); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error CoreDetachPlugin(m64p_plugin_type pluginType); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error CoreDoCommand(m64p_command command, int paramInt, IntPtr paramPtr); + + public unsafe m64p_error CoreDoCommand(m64p_command command, int arrayLength, byte[] array) + { + fixed (byte* arrayPointer = array) + return CoreDoCommand(command, arrayLength, (IntPtr)arrayPointer); + } + public unsafe m64p_error CoreDoCommand(m64p_command command, int paramInt, string paramString) + { + byte[] bytes = Encoding.UTF8.GetBytes(paramString); + fixed (byte* bytePointer = bytes) + return CoreDoCommand(command, paramInt, (IntPtr)bytePointer); + } + public unsafe m64p_error CoreStateSet(m64p_core_param parameter, int value) + { + int* valuePointer = &value; + return CoreDoCommand(m64p_command.CORE_STATE_SET, (int)parameter, (IntPtr)valuePointer); + } + + [BizImport(CallingConvention.Cdecl, Compatibility = true)] + public abstract m64p_error CoreOverrideVidExt(ref m64p_video_extension_functions videoFunctionStruct); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error GetSaveRamSize(ref int size); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error GetSaveRam(byte[] buffer); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error PutSaveRam(byte[] buffer); + + [BizImport(CallingConvention.Cdecl)] + public abstract IntPtr DebugMemGetPointer(m64p_dbg_memptr_type memPtrType); + + [BizImport(CallingConvention.Cdecl)] + public abstract ulong DebugMemGetSize(m64p_dbg_memptr_type memPtrType); + + [BizImport(CallingConvention.Cdecl)] + public abstract byte DebugMemRead8(uint address); + + [BizImport(CallingConvention.Cdecl)] + public abstract uint DebugMemRead32(uint address); + + [BizImport(CallingConvention.Cdecl)] + public abstract void DebugMemWrite8(uint address, byte value); + + [BizImport(CallingConvention.Cdecl)] + public abstract IntPtr DebugGetCPUDataPtr(m64p_dbg_cpu_data cpuDataType); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error ConfigOpenSection(string sectionName, ref IntPtr configSectionHandle); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error ConfigSetParameter(IntPtr configSectionHandle, string paramName, m64p_type paramType, IntPtr paramValue); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error DebugSetCallbacks(dbg_frontend_init dbgFrontendInit, dbg_frontend_update dbgFrontendUpdate, dbg_frontend_vi dbgFrontendVi); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error DebugSetRunState(m64p_dbg_runstate runstate); + + [BizImport(CallingConvention.Cdecl)] + public abstract m64p_error DebugStep(); + + [BizImport(CallingConvention.Cdecl)] + public abstract void DebugDecodeOp(uint instruction, byte[] op, byte[] args, int pc); + + [BizImport(CallingConvention.Cdecl)] + public abstract void SaveSavestate(byte[] buffer); + + [BizImport(CallingConvention.Cdecl)] + public abstract bool LoadSavestate(byte[] buffer); +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64AudioPluginApi.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64AudioPluginApi.cs new file mode 100644 index 00000000000..38d711fd4e5 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64AudioPluginApi.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public abstract class Mupen64AudioPluginApi : Mupen64PluginApi +{ + [BizImport(CallingConvention.Cdecl)] + public abstract void ReadAudioBuffer(short[] dest); + + [BizImport(CallingConvention.Cdecl)] + public abstract int GetBufferSize(); + + [BizImport(CallingConvention.Cdecl)] + public abstract int GetAudioRate(); +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64Controller.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64Controller.cs new file mode 100644 index 00000000000..5c23f3d9dba --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64Controller.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Linq; +using BizHawk.Common; +using BizHawk.Common.CollectionExtensions; +using BizHawk.Emulation.Common; +using static BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64.Mupen64.N64ControllerPakType; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public class Mupen64Controller +{ + public static readonly string[] BoolButtons = + [ + "DPad R", "DPad L", "DPad D", "DPad U", "Start", "Z", "B", "A", "C Right", "C Left", "C Down", "C Up", "R", "L" + ]; + + private static readonly Dictionary DisplayButtonOrder = new() + { + ["DPad U"] = 0, + ["DPad D"] = 1, + ["DPad L"] = 2, + ["DPad R"] = 3, + ["Start"] = 4, + ["Z"] = 5, + ["B"] = 6, + ["A"] = 7, + ["C Up"] = 8, + ["C Down"] = 9, + ["C Left"] = 10, + ["C Right"] = 11, + ["L"] = 12, + ["R"] = 13, + }; + + public static ControllerDefinition MakeControllerDefinition(Mupen64.SyncSettings syncSettings) + { + var controllerDefinition = new ControllerDefinition("Nintendo 64 Controller"); + controllerDefinition.BoolButtons.AddRange([ "Reset", "Power" ]); + if (syncSettings.Port1Connected) AddN64StandardController(controllerDefinition, 1, syncSettings.Port1PakType == RumblePak); + if (syncSettings.Port2Connected) AddN64StandardController(controllerDefinition, 2, syncSettings.Port2PakType == RumblePak); + if (syncSettings.Port3Connected) AddN64StandardController(controllerDefinition, 3, syncSettings.Port3PakType == RumblePak); + if (syncSettings.Port4Connected) AddN64StandardController(controllerDefinition, 4, syncSettings.Port4PakType == RumblePak); + controllerDefinition.MakeImmutable(); + + return controllerDefinition; + + static void AddN64StandardController(ControllerDefinition def, int player, bool hasRumblePak) + { + def.BoolButtons.AddRange(BoolButtons.OrderBy(b => DisplayButtonOrder[b]).Select(button => $"P{player} {button}")); + def.AddXYPair( + $"P{player} {{0}} Axis", + AxisPairOrientation.RightAndUp, + (-128).RangeTo(127), + 0, + new CircularAxisConstraint("Natural Circle", $"P{player} Y Axis", 127.0f) + ); + if (hasRumblePak) def.HapticsChannels.Add($"P{player} Rumble Pak"); + } + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64InputPluginApi.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64InputPluginApi.cs new file mode 100644 index 00000000000..eac1f82f643 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64InputPluginApi.cs @@ -0,0 +1,50 @@ +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public abstract class Mupen64InputPluginApi : Mupen64PluginApi +{ + [Flags] + public enum BoolButtons : ushort + { + R_DPAD = 1 << 0, + L_DPAD = 1 << 1, + D_DPAD = 1 << 2, + U_DPAD = 1 << 3, + START_BUTTON = 1 << 4, + Z_TRIG = 1 << 5, + B_BUTTON = 1 << 6, + A_BUTTON = 1 << 7, + R_CBUTTON = 1 << 8, + L_CBUTTON = 1 << 9, + D_CBUTTON = 1 << 10, + U_CBUTTON = 1 << 11, + R_TRIG = 1 << 12, + L_TRIG = 1 << 13, + + } + + [StructLayout(LayoutKind.Sequential)] + public struct InputState + { + public BoolButtons boolButtons; + public sbyte X_AXIS; + public sbyte Y_AXIS; + } + + public delegate InputState InputCallback(int controller); + public delegate void RumbleCallback(int controller, bool on); + + [BizImport(CallingConvention.Cdecl)] + public abstract void SetInputCallback(InputCallback inputCallback); + + [BizImport(CallingConvention.Cdecl)] + public abstract void SetRumbleCallback(RumbleCallback rumbleCallback); + + [BizImport(CallingConvention.Cdecl)] + public abstract void SetControllerConnected(int idx, bool connected); + + [BizImport(CallingConvention.Cdecl)] + public abstract void SetControllerPakType(int idx, Mupen64.N64ControllerPakType type); +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64PluginApi.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64PluginApi.cs new file mode 100644 index 00000000000..e8f31c3f19f --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64PluginApi.cs @@ -0,0 +1,21 @@ +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public abstract class Mupen64PluginApi +{ + [BizImport(CallingConvention.Cdecl)] + public abstract Mupen64Api.m64p_error PluginStartup(IntPtr coreLibHandle, IntPtr context, IntPtr debugCallback); + + [BizImport(CallingConvention.Cdecl)] + public abstract Mupen64Api.m64p_error PluginShutdown(); + + [BizImport(CallingConvention.Cdecl)] + public abstract unsafe Mupen64Api.m64p_error PluginGetVersion(ref Mupen64Api.m64p_plugin_type pluginType, ref int pluginVersion, ref int apiVersion, char** pluginNamePtr, ref int capabilities); + + public unsafe Mupen64Api.m64p_error PluginGetVersion(ref Mupen64Api.m64p_plugin_type pluginType, ref int pluginVersion, ref int apiVersion, ref int capabilities) + { + return PluginGetVersion(ref pluginType, ref pluginVersion, ref apiVersion, null, ref capabilities); + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64VideoPluginApi.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64VideoPluginApi.cs new file mode 100644 index 00000000000..424d69fed96 --- /dev/null +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Mupen64/Mupen64VideoPluginApi.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; +using BizHawk.BizInvoke; + +namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Mupen64; + +public abstract class Mupen64VideoPluginApi : Mupen64PluginApi +{ + [BizImport(CallingConvention.Cdecl)] + public abstract void ReadScreen2(IntPtr dest, ref int width, ref int height, int front); + + public unsafe void ReadScreen2(byte[] dest, ref int width, ref int height, int front) + { + fixed (byte* destPointer = dest) + ReadScreen2((IntPtr)destPointer, ref width, ref height, front); + } +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs index 00246257af1..fb1048d549f 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs @@ -6,7 +6,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 { - [PortedCore(CoreNames.Mupen64Plus, "", "2.0", "https://code.google.com/p/mupen64plus/", singleInstance: true)] + [PortedCore(CoreNames.Mupen64Plus + "b", "", "2.0", "https://code.google.com/p/mupen64plus/", singleInstance: true)] public partial class N64 : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IDisassemblable, IRegionable, ISettable {