From a3b66aec1f1f2f250436dff4bab124f0f57abb72 Mon Sep 17 00:00:00 2001 From: flyinghead Date: Tue, 6 Jul 2021 13:22:54 +0200 Subject: [PATCH] libretro: win32 support. build fix. --- .github/workflows/c-cpp.yml | 2 +- CMakeLists.txt | 52 ++++-- core/hw/pvr/Renderer_if.cpp | 2 +- core/rend/dx9/d3d_overlay.cpp | 1 + core/rend/gles/gles.cpp | 3 +- core/windows/fault_handler.cpp | 194 ++++++++++++++++++++ core/windows/fault_handler.h | 20 ++ core/windows/winmain.cpp | 194 ++------------------ core/wsi/switcher.cpp | 2 + shell/libretro/libretro.cpp | 29 ++- shell/libretro/libretro_core_options.h | 34 ---- shell/libretro/libretro_core_options_intl.h | 99 +++++----- 12 files changed, 348 insertions(+), 284 deletions(-) create mode 100644 core/windows/fault_handler.cpp create mode 100644 core/windows/fault_handler.h diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 739b8aa62..8c4a7fbf5 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -79,7 +79,7 @@ jobs: - name: CMake run: | - cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE=artifact ${{ matrix.config.cmakeArgs }} + cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE=artifact -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=artifact ${{ matrix.config.cmakeArgs }} cmake --build build --config Release --parallel 2 - name: Unit Tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 725282e62..a1f5c8cef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,16 +55,23 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/core/version.h.in" "${CMAKE_CURRENT_ if(LIBRETRO) add_library(${PROJECT_NAME} SHARED core/emulator.cpp) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") + set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "flycast_libretro") + set(CMAKE_SHARED_LIBRARY_PREFIX "") target_compile_definitions(${PROJECT_NAME} PRIVATE LIBRETRO) if(ANDROID OR USE_GLES) target_compile_definitions(${PROJECT_NAME} PRIVATE GLES GLES3 HAVE_OPENGLES HAVE_OPENGLES3) + target_link_libraries(${PROJECT_NAME} PRIVATE "-lGLESv3") elseif(USE_GLES2) target_compile_definitions(${PROJECT_NAME} PRIVATE GLES GLES2 HAVE_OPENGLES HAVE_OPENGLES2) + target_link_libraries(${PROJECT_NAME} PRIVATE "-lGLESv2") else() target_compile_definitions(${PROJECT_NAME} PRIVATE HAVE_OPENGL) if(NOT APPLE) target_compile_definitions(${PROJECT_NAME} PRIVATE HAVE_OIT) endif() + if(WIN32) + target_link_libraries(${PROJECT_NAME} PRIVATE "-lopengl32") + endif() endif() elseif(ANDROID) add_library(${PROJECT_NAME} SHARED core/emulator.cpp) @@ -641,11 +648,14 @@ if(NOT LIBRETRO) core/input/mapping.h) endif() -target_sources(${PROJECT_NAME} PRIVATE - core/linux/common.cpp) - -if(NOT WIN32) +if(WIN32) + target_sources(${PROJECT_NAME} PRIVATE + core/windows/fault_handler.cpp + core/windows/fault_handler.h + core/windows/win_vmem.cpp) +else() target_sources(${PROJECT_NAME} PRIVATE + core/linux/common.cpp core/linux/context.cpp core/linux/posix_vmem.cpp) endif() @@ -869,11 +879,10 @@ if(USE_VULKAN AND NOT APPLE) endif() endif() -if(WIN32) +# TODO +if(WIN32 AND NOT LIBRETRO) target_sources(${PROJECT_NAME} PRIVATE core/rend/dx9/comptr.h - core/rend/dx9/d3d_overlay.h - core/rend/dx9/d3d_overlay.cpp core/rend/dx9/d3d_renderer.h core/rend/dx9/d3d_renderer.cpp core/rend/dx9/d3d_shaders.h @@ -881,15 +890,20 @@ if(WIN32) core/rend/dx9/d3d_texture.h core/rend/dx9/d3d_texture.cpp core/rend/dx9/dxcontext.h - core/rend/dx9/dxcontext.cpp - core/rend/dx9/imgui_impl_dx9.h - core/rend/dx9/imgui_impl_dx9.cpp) - if(NOT MINGW) - target_include_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Include") - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - target_link_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Lib/x64") - else() - target_link_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Lib/x86") + core/rend/dx9/dxcontext.cpp) + if(NOT LIBRETRO) + target_sources(${PROJECT_NAME} PRIVATE + core/rend/dx9/d3d_overlay.h + core/rend/dx9/d3d_overlay.cpp + core/rend/dx9/imgui_impl_dx9.h + core/rend/dx9/imgui_impl_dx9.cpp) + if(NOT MINGW) + target_include_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Include") + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + target_link_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Lib/x64") + else() + target_link_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Lib/x86") + endif() endif() endif() target_link_libraries(${PROJECT_NAME} PRIVATE d3d9 d3dx9) @@ -1055,10 +1069,8 @@ if(NOT LIBRETRO) core/windows/winmain.cpp core/windows/xinput_gamepad.h) endif() - target_sources(${PROJECT_NAME} PRIVATE - core/windows/win_vmem.cpp - shell/windows/flycast.rc) - + target_sources(${PROJECT_NAME} PRIVATE shell/windows/flycast.rc) + target_link_libraries(${PROJECT_NAME} PRIVATE dsound opengl32 winmm ws2_32 wsock32 xinput9_1_0) endif() endif() diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index b08367c03..d8715a081 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -274,7 +274,7 @@ static void rend_create_renderer() renderer = rend_OITVulkan(); break; #endif -#ifdef _WIN32 +#if defined(_WIN32) && !defined(LIBRETRO) case RenderType::DirectX9: renderer = rend_DirectX9(); break; diff --git a/core/rend/dx9/d3d_overlay.cpp b/core/rend/dx9/d3d_overlay.cpp index 71a912b54..d68001539 100644 --- a/core/rend/dx9/d3d_overlay.cpp +++ b/core/rend/dx9/d3d_overlay.cpp @@ -17,6 +17,7 @@ along with Flycast. If not, see . */ #include "d3d_overlay.h" +#include "rend/osd.h" #include "rend/gui.h" #include #include diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 19a32be7e..790c1ff75 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -482,7 +482,7 @@ void findGLVersion() } } #endif - NOTICE_LOG(RENDERER, "GL %s version %d.%d", gl.is_gles ? "ES" : "", gl.gl_major, gl.gl_minor); + NOTICE_LOG(RENDERER, "Open GL%s version %d.%d", gl.is_gles ? "ES" : "", gl.gl_major, gl.gl_minor); } struct ShaderUniforms_t ShaderUniforms; @@ -1150,6 +1150,7 @@ bool RenderFrame(int width, int height) else { #ifdef LIBRETRO + glBindFramebuffer(GL_FRAMEBUFFER, glsm_get_current_framebuffer()); gl.ofbo.width = width; gl.ofbo.height = height; glViewport(0, 0, width, height); diff --git a/core/windows/fault_handler.cpp b/core/windows/fault_handler.cpp new file mode 100644 index 000000000..7991d0af8 --- /dev/null +++ b/core/windows/fault_handler.cpp @@ -0,0 +1,194 @@ +/* + This file is part of Flycast. + + Flycast 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. + + Flycast 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 Flycast. If not, see . +*/ +#include "fault_handler.h" +#include "hw/sh4/dyna/blockmanager.h" +#include "hw/sh4/dyna/ngen.h" + +bool VramLockedWrite(u8* address); +bool BM_LockedWrite(u8* address); + +static void readContext(const EXCEPTION_POINTERS *ep, host_context_t &context) +{ +#if HOST_CPU == CPU_X86 + context.pc = ep->ContextRecord->Eip; + context.esp = ep->ContextRecord->Esp; + context.eax = ep->ContextRecord->Eax; + context.ecx = ep->ContextRecord->Ecx; +#elif HOST_CPU == CPU_X64 + context.pc = ep->ContextRecord->Rip; + context.rsp = ep->ContextRecord->Rsp; + context.r9 = ep->ContextRecord->R9; + context.rcx = ep->ContextRecord->Rcx; +#endif +} + +static void writeContext(EXCEPTION_POINTERS *ep, const host_context_t &context) +{ +#if HOST_CPU == CPU_X86 + ep->ContextRecord->Eip = context.pc; + ep->ContextRecord->Esp = context.esp; + ep->ContextRecord->Eax = context.eax; + ep->ContextRecord->Ecx = context.ecx; +#elif HOST_CPU == CPU_X64 + ep->ContextRecord->Rip = context.pc; + ep->ContextRecord->Rsp = context.rsp; + ep->ContextRecord->R9 = context.r9; + ep->ContextRecord->Rcx = context.rcx; +#endif +} + +LONG exceptionHandler(EXCEPTION_POINTERS *ep) +{ + u32 dwCode = ep->ExceptionRecord->ExceptionCode; + + if (dwCode != EXCEPTION_ACCESS_VIOLATION) + return EXCEPTION_CONTINUE_SEARCH; + + EXCEPTION_RECORD* pExceptionRecord = ep->ExceptionRecord; + u8* address = (u8 *)pExceptionRecord->ExceptionInformation[1]; + + //printf("[EXC] During access to : 0x%X\n", address); + + // code protection in RAM + if (bm_RamWriteAccess(address)) + return EXCEPTION_CONTINUE_EXECUTION; + // texture protection in VRAM + if (VramLockedWrite(address)) + return EXCEPTION_CONTINUE_EXECUTION; + // FPCB jump table protection + if (BM_LockedWrite(address)) + return EXCEPTION_CONTINUE_EXECUTION; + + host_context_t context; + readContext(ep, context); +#if FEAT_SHREC == DYNAREC_JIT + // fast mem access rewriting + if (ngen_Rewrite(context, address)) + { + writeContext(ep, context); + return EXCEPTION_CONTINUE_EXECUTION; + } +#endif + + ERROR_LOG(COMMON, "[GPF] PC %p unhandled access to %p", (void *)context.pc, address); + os_DebugBreak(); + + return EXCEPTION_CONTINUE_SEARCH; +} + +#ifdef _WIN64 + +typedef union _UNWIND_CODE { + struct { + u8 CodeOffset; + u8 UnwindOp : 4; + u8 OpInfo : 4; + }; + USHORT FrameOffset; +} UNWIND_CODE, *PUNWIND_CODE; + +typedef struct _UNWIND_INFO { + u8 Version : 3; + u8 Flags : 5; + u8 SizeOfProlog; + u8 CountOfCodes; + u8 FrameRegister : 4; + u8 FrameOffset : 4; + //ULONG ExceptionHandler; + UNWIND_CODE UnwindCode[1]; + /* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1]; + * union { + * OPTIONAL ULONG ExceptionHandler; + * OPTIONAL ULONG FunctionEntry; + * }; + * OPTIONAL ULONG ExceptionData[]; */ +} UNWIND_INFO, *PUNWIND_INFO; + +static RUNTIME_FUNCTION Table[1]; +static _UNWIND_INFO unwind_info[1]; + +PRUNTIME_FUNCTION +seh_callback( +_In_ DWORD64 ControlPc, +_In_opt_ PVOID Context +) { + unwind_info[0].Version = 1; + unwind_info[0].Flags = UNW_FLAG_UHANDLER; + /* We don't use the unwinding info so fill the structure with 0 values. */ + unwind_info[0].SizeOfProlog = 0; + unwind_info[0].CountOfCodes = 0; + unwind_info[0].FrameOffset = 0; + unwind_info[0].FrameRegister = 0; + /* Add the exception handler. */ + +// unwind_info[0].ExceptionHandler = + // (DWORD)((u8 *)__gnat_SEH_error_handler - CodeCache); + /* Set its scope to the entire program. */ + Table[0].BeginAddress = 0;// (CodeCache - (u8*)__ImageBase); + Table[0].EndAddress = /*(CodeCache - (u8*)__ImageBase) +*/ CODE_SIZE + TEMP_CODE_SIZE; + Table[0].UnwindData = (DWORD)((u8 *)unwind_info - CodeCache); + INFO_LOG(COMMON, "TABLE CALLBACK"); + //for (;;); + return Table; +} + +void setup_seh() +{ + /* Get the base of the module. */ + //u8* __ImageBase = (u8*)GetModuleHandle(NULL); + /* Current version is always 1 and we are registering an + exception handler. */ + unwind_info[0].Version = 1; + unwind_info[0].Flags = UNW_FLAG_NHANDLER; + /* We don't use the unwinding info so fill the structure with 0 values. */ + unwind_info[0].SizeOfProlog = 0; + unwind_info[0].CountOfCodes = 1; + unwind_info[0].FrameOffset = 0; + unwind_info[0].FrameRegister = 0; + /* Add the exception handler. */ + + unwind_info[0].UnwindCode[0].CodeOffset = 0; + unwind_info[0].UnwindCode[0].UnwindOp = 2;// UWOP_ALLOC_SMALL; + unwind_info[0].UnwindCode[0].OpInfo = 0x20 / 8; + + //unwind_info[0].ExceptionHandler = + //(DWORD)((u8 *)__gnat_SEH_error_handler - CodeCache); + /* Set its scope to the entire program. */ + Table[0].BeginAddress = 0;// (CodeCache - (u8*)__ImageBase); + Table[0].EndAddress = /*(CodeCache - (u8*)__ImageBase) +*/ CODE_SIZE + TEMP_CODE_SIZE; + Table[0].UnwindData = (DWORD)((u8 *)unwind_info - CodeCache); + /* Register the unwind information. */ + RtlAddFunctionTable(Table, 1, (DWORD64)CodeCache); + + //verify(RtlInstallFunctionTableCallback((unat)CodeCache | 0x3, (DWORD64)CodeCache, CODE_SIZE + TEMP_CODE_SIZE, seh_callback, 0, 0)); +} +#endif + +double os_GetSeconds() +{ + static double qpfd = []() { + LARGE_INTEGER qpf; + QueryPerformanceFrequency(&qpf); + return 1.0 / qpf.QuadPart; }(); + + LARGE_INTEGER time_now; + + QueryPerformanceCounter(&time_now); + static LARGE_INTEGER time_now_base = time_now; + + return (time_now.QuadPart - time_now_base.QuadPart) * qpfd; +} diff --git a/core/windows/fault_handler.h b/core/windows/fault_handler.h new file mode 100644 index 000000000..f3be4ae17 --- /dev/null +++ b/core/windows/fault_handler.h @@ -0,0 +1,20 @@ +/* + This file is part of Flycast. + + Flycast 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. + + Flycast 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 Flycast. If not, see . +*/ +#include + +LONG exceptionHandler(EXCEPTION_POINTERS *ep); +void setup_seh(); diff --git a/core/windows/winmain.cpp b/core/windows/winmain.cpp index 9d0bad075..de76e40da 100644 --- a/core/windows/winmain.cpp +++ b/core/windows/winmain.cpp @@ -1,10 +1,25 @@ +/* + This file is part of Flycast. + + Flycast 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. + + Flycast 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 Flycast. If not, see . +*/ #include "oslib/oslib.h" #include "oslib/audiostream.h" #include "imgread/common.h" #include "stdclass.h" #include "cfg/cfg.h" #include "win_keyboard.h" -#include "hw/sh4/dyna/blockmanager.h" #include "log/LogManager.h" #include "wsi/context.h" #if defined(USE_SDL) @@ -15,10 +30,9 @@ #include "hw/maple/maple_devs.h" #include "emulator.h" #include "rend/mainui.h" -#include "hw/sh4/dyna/ngen.h" -#include "oslib/host_context.h" #include "../shell/windows/resource.h" #include "rawinput.h" +#include "fault_handler.h" #include #include @@ -117,9 +131,6 @@ static PCHAR* return argv; } -bool VramLockedWrite(u8* address); -bool BM_LockedWrite(u8* address); - #ifndef USE_SDL static std::shared_ptr mouse; @@ -186,74 +197,6 @@ void os_SetupInput() rawinput::init(); } -static void readContext(const EXCEPTION_POINTERS *ep, host_context_t &context) -{ -#if HOST_CPU == CPU_X86 - context.pc = ep->ContextRecord->Eip; - context.esp = ep->ContextRecord->Esp; - context.eax = ep->ContextRecord->Eax; - context.ecx = ep->ContextRecord->Ecx; -#elif HOST_CPU == CPU_X64 - context.pc = ep->ContextRecord->Rip; - context.rsp = ep->ContextRecord->Rsp; - context.r9 = ep->ContextRecord->R9; - context.rcx = ep->ContextRecord->Rcx; -#endif -} - -static void writeContext(EXCEPTION_POINTERS *ep, const host_context_t &context) -{ -#if HOST_CPU == CPU_X86 - ep->ContextRecord->Eip = context.pc; - ep->ContextRecord->Esp = context.esp; - ep->ContextRecord->Eax = context.eax; - ep->ContextRecord->Ecx = context.ecx; -#elif HOST_CPU == CPU_X64 - ep->ContextRecord->Rip = context.pc; - ep->ContextRecord->Rsp = context.rsp; - ep->ContextRecord->R9 = context.r9; - ep->ContextRecord->Rcx = context.rcx; -#endif -} -static LONG exceptionHandler(EXCEPTION_POINTERS *ep) -{ - u32 dwCode = ep->ExceptionRecord->ExceptionCode; - - if (dwCode != EXCEPTION_ACCESS_VIOLATION) - return EXCEPTION_CONTINUE_SEARCH; - - EXCEPTION_RECORD* pExceptionRecord = ep->ExceptionRecord; - u8* address = (u8 *)pExceptionRecord->ExceptionInformation[1]; - - //printf("[EXC] During access to : 0x%X\n", address); - - // code protection in RAM - if (bm_RamWriteAccess(address)) - return EXCEPTION_CONTINUE_EXECUTION; - // texture protection in VRAM - if (VramLockedWrite(address)) - return EXCEPTION_CONTINUE_EXECUTION; - // FPCB jump table protection - if (BM_LockedWrite(address)) - return EXCEPTION_CONTINUE_EXECUTION; - - host_context_t context; - readContext(ep, context); -#if FEAT_SHREC == DYNAREC_JIT - // fast mem access rewriting - if (ngen_Rewrite(context, address)) - { - writeContext(ep, context); - return EXCEPTION_CONTINUE_EXECUTION; - } -#endif - - ERROR_LOG(COMMON, "[GPF] PC %p unhandled access to %p", (void *)context.pc, address); - os_DebugBreak(); - - return EXCEPTION_CONTINUE_SEARCH; -} - static void setupPath() { @@ -705,94 +648,6 @@ static void reserveBottomMemory() OutputDebugStringA(buffer); #endif } - -#ifdef _WIN64 - -typedef union _UNWIND_CODE { - struct { - u8 CodeOffset; - u8 UnwindOp : 4; - u8 OpInfo : 4; - }; - USHORT FrameOffset; -} UNWIND_CODE, *PUNWIND_CODE; - -typedef struct _UNWIND_INFO { - u8 Version : 3; - u8 Flags : 5; - u8 SizeOfProlog; - u8 CountOfCodes; - u8 FrameRegister : 4; - u8 FrameOffset : 4; - //ULONG ExceptionHandler; - UNWIND_CODE UnwindCode[1]; - /* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1]; - * union { - * OPTIONAL ULONG ExceptionHandler; - * OPTIONAL ULONG FunctionEntry; - * }; - * OPTIONAL ULONG ExceptionData[]; */ -} UNWIND_INFO, *PUNWIND_INFO; - -static RUNTIME_FUNCTION Table[1]; -static _UNWIND_INFO unwind_info[1]; - -PRUNTIME_FUNCTION -seh_callback( -_In_ DWORD64 ControlPc, -_In_opt_ PVOID Context -) { - unwind_info[0].Version = 1; - unwind_info[0].Flags = UNW_FLAG_UHANDLER; - /* We don't use the unwinding info so fill the structure with 0 values. */ - unwind_info[0].SizeOfProlog = 0; - unwind_info[0].CountOfCodes = 0; - unwind_info[0].FrameOffset = 0; - unwind_info[0].FrameRegister = 0; - /* Add the exception handler. */ - -// unwind_info[0].ExceptionHandler = - // (DWORD)((u8 *)__gnat_SEH_error_handler - CodeCache); - /* Set its scope to the entire program. */ - Table[0].BeginAddress = 0;// (CodeCache - (u8*)__ImageBase); - Table[0].EndAddress = /*(CodeCache - (u8*)__ImageBase) +*/ CODE_SIZE + TEMP_CODE_SIZE; - Table[0].UnwindData = (DWORD)((u8 *)unwind_info - CodeCache); - INFO_LOG(COMMON, "TABLE CALLBACK"); - //for (;;); - return Table; -} -static void setup_seh() -{ - /* Get the base of the module. */ - //u8* __ImageBase = (u8*)GetModuleHandle(NULL); - /* Current version is always 1 and we are registering an - exception handler. */ - unwind_info[0].Version = 1; - unwind_info[0].Flags = UNW_FLAG_NHANDLER; - /* We don't use the unwinding info so fill the structure with 0 values. */ - unwind_info[0].SizeOfProlog = 0; - unwind_info[0].CountOfCodes = 1; - unwind_info[0].FrameOffset = 0; - unwind_info[0].FrameRegister = 0; - /* Add the exception handler. */ - - unwind_info[0].UnwindCode[0].CodeOffset = 0; - unwind_info[0].UnwindCode[0].UnwindOp = 2;// UWOP_ALLOC_SMALL; - unwind_info[0].UnwindCode[0].OpInfo = 0x20 / 8; - - //unwind_info[0].ExceptionHandler = - //(DWORD)((u8 *)__gnat_SEH_error_handler - CodeCache); - /* Set its scope to the entire program. */ - Table[0].BeginAddress = 0;// (CodeCache - (u8*)__ImageBase); - Table[0].EndAddress = /*(CodeCache - (u8*)__ImageBase) +*/ CODE_SIZE + TEMP_CODE_SIZE; - Table[0].UnwindData = (DWORD)((u8 *)unwind_info - CodeCache); - /* Register the unwind information. */ - RtlAddFunctionTable(Table, 1, (DWORD64)CodeCache); - - //verify(RtlInstallFunctionTableCallback((unat)CodeCache | 0x3, (DWORD64)CodeCache, CODE_SIZE + TEMP_CODE_SIZE, seh_callback, 0, 0)); -} -#endif - static void findKeyboardLayout() { HKL keyboardLayout = GetKeyboardLayout(0); @@ -885,21 +740,6 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi return 0; } -double os_GetSeconds() -{ - static double qpfd = []() { - LARGE_INTEGER qpf; - QueryPerformanceFrequency(&qpf); - return 1.0 / qpf.QuadPart; }(); - - LARGE_INTEGER time_now; - - QueryPerformanceCounter(&time_now); - static LARGE_INTEGER time_now_base = time_now; - - return (time_now.QuadPart - time_now_base.QuadPart) * qpfd; -} - void os_DebugBreak() { __debugbreak(); diff --git a/core/wsi/switcher.cpp b/core/wsi/switcher.cpp index 8f72ce68e..985b651b4 100644 --- a/core/wsi/switcher.cpp +++ b/core/wsi/switcher.cpp @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License along with Flycast. If not, see . */ +#ifndef LIBRETRO #include "context.h" #include "rend/gui.h" #include "cfg/option.h" @@ -64,3 +65,4 @@ void TermRenderApi() #endif theGLContext.Term(); } +#endif diff --git a/shell/libretro/libretro.cpp b/shell/libretro/libretro.cpp index 0daf12074..557cd5cd1 100644 --- a/shell/libretro/libretro.cpp +++ b/shell/libretro/libretro.cpp @@ -72,6 +72,9 @@ char* strdup(const char *str) #include "rend/osd.h" #include "cfg/option.h" #include "wsi/gl_context.h" +#ifdef _WIN32 +#include "windows/fault_handler.h" +#endif constexpr char slash = path_default_slash_c(); @@ -281,8 +284,13 @@ void retro_init() if (!_vmem_reserve()) ERROR_LOG(VMEM, "Cannot reserve memory space"); -#ifdef WIN32 -#error TODO +#ifdef _WIN32 +#ifdef _WIN64 + AddVectoredExceptionHandler(1, exceptionHandler); + setup_seh(); +#else + SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&exceptionHandler); +#endif #else void install_fault_handler(); install_fault_handler(); @@ -776,9 +784,11 @@ void retro_run() { dc_run(nullptr); } - // TODO Widescreen + int width = config::RenderResolution * 4 / 3; + if (config::Widescreen && !config::Rotate90) + width = width * 4 / 3; #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) || defined(HAVE_VULKAN) - video_cb(is_dupe ? 0 : RETRO_HW_FRAME_BUFFER_VALID, config::RenderResolution * 4 / 3, config::RenderResolution, 0); + video_cb(is_dupe ? 0 : RETRO_HW_FRAME_BUFFER_VALID, width, config::RenderResolution, 0); #endif if (!config::ThreadedRendering) is_dupe = true; @@ -1255,8 +1265,10 @@ static void retro_vk_context_reset() ERROR_LOG(RENDERER, "Get Vulkan HW interface failed"); return; } - // TODO Widescreen - theVulkanContext.SetWindowSize(config::RenderResolution * 4 / 3, config::RenderResolution); + int width = config::RenderResolution * 4 / 3; + if (config::Widescreen && !config::Rotate90) + width = width * 4 / 3; + theVulkanContext.SetWindowSize(width, config::RenderResolution); theVulkanContext.Init((retro_hw_render_interface_vulkan *)vulkan); } @@ -1343,12 +1355,15 @@ static bool set_opengl_hw_render(u32 preferred) params.context_type = (retro_hw_context_type)preferred; params.major = 3; params.minor = 0; + config::RendererType = RenderType::OpenGL; } #elif defined(HAVE_GL3) params.context_type = (retro_hw_context_type)preferred; params.major = 3; params.minor = 0; + config::RendererType = RenderType::OpenGL; #endif + config::RendererType.commit(); if (glsm_ctl(GLSM_CTL_STATE_CONTEXT_INIT, ¶ms)) return true; @@ -1362,6 +1377,8 @@ static bool set_opengl_hw_render(u32 preferred) params.major = 0; params.minor = 0; #endif + config::RendererType = RenderType::OpenGL; + config::RendererType.commit(); return glsm_ctl(GLSM_CTL_STATE_CONTEXT_INIT, ¶ms); #else return false; diff --git a/shell/libretro/libretro_core_options.h b/shell/libretro/libretro_core_options.h index 82e3fa5fb..a552e1788 100644 --- a/shell/libretro/libretro_core_options.h +++ b/shell/libretro/libretro_core_options.h @@ -194,27 +194,6 @@ extern "C" { }, struct retro_core_option_definition option_defs_us[] = { -#if ((FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X86) || (HOST_CPU == CPU_ARM) || (HOST_CPU == CPU_ARM64) || (HOST_CPU == CPU_X64)) && defined(TARGET_NO_JIT) - { - CORE_OPTION_NAME "_cpu_mode", - "CPU Mode (Restart)", - "", - { -#if (FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X86) || (HOST_CPU == CPU_ARM) || (HOST_CPU == CPU_ARM64) || (HOST_CPU == CPU_X64) - { "dynamic_recompiler", "Dynamic Recompiler" }, -#endif -#ifdef TARGET_NO_JIT - { "generic_recompiler", "Generic Recompiler" }, -#endif - { NULL, NULL }, - }, -#if (FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X86) || (HOST_CPU == CPU_ARM) || (HOST_CPU == CPU_ARM64) || (HOST_CPU == CPU_X64) - "dynamic_recompiler", -#elif defined(TARGET_NO_JIT) - "generic_recompiler", -#endif - }, -#endif { CORE_OPTION_NAME "_boot_to_bios", "Boot to BIOS (Restart)", @@ -226,19 +205,6 @@ struct retro_core_option_definition option_defs_us[] = { }, "disabled", }, - { - CORE_OPTION_NAME "_system", - "System Type (Restart)", - "", - { - { "auto", "Auto" }, - { "dreamcast", "Dreamcast" }, - { "naomi", "NAOMI" }, - { "atomiswave", "Atomiswave" }, - { NULL, NULL }, - }, - "auto", - }, { CORE_OPTION_NAME "_hle_bios", "HLE BIOS", diff --git a/shell/libretro/libretro_core_options_intl.h b/shell/libretro/libretro_core_options_intl.h index cb9813a77..01809107c 100644 --- a/shell/libretro/libretro_core_options_intl.h +++ b/shell/libretro/libretro_core_options_intl.h @@ -202,23 +202,6 @@ extern "C" { }, struct retro_core_option_definition option_defs_tr[] = { -#if ((FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X86) || (HOST_CPU == CPU_ARM) || (HOST_CPU == CPU_ARM64) || (HOST_CPU == CPU_X64)) && defined(TARGET_NO_JIT) - { - CORE_OPTION_NAME "_cpu_mode", - "CPU Modu (Yeniden Başlatma Gerektirir)", - "", - { -#if (FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X86) || (HOST_CPU == CPU_ARM) || (HOST_CPU == CPU_ARM64) || (HOST_CPU == CPU_X64) - { "dynamic_recompiler", "Dinamik Yeniden Derleyici" }, -#endif -#ifdef TARGET_NO_JIT - { "generic_recompiler", "Jenerik Yeniden Derleyici" }, -#endif - { NULL, NULL }, - }, - NULL, - }, -#endif { CORE_OPTION_NAME "_boot_to_bios", "BIOS'a önyükleme (Yeniden Başlatma Gerektirir)", @@ -228,19 +211,6 @@ struct retro_core_option_definition option_defs_tr[] = { }, NULL, }, - { - CORE_OPTION_NAME "_system", - "Sistem Tipi (Yeniden Başlatma Gerektirir)", - "", - { - { "auto", "Otomatik" }, - { "dreamcast", "Dreamcast" }, - { "naomi", "NAOMI" }, - { "atomiswave", "Atomiswave" }, - { NULL, NULL }, - }, - NULL, - }, { CORE_OPTION_NAME "_hle_bios", "HLE BIOS", @@ -313,6 +283,15 @@ struct retro_core_option_definition option_defs_tr[] = { }, NULL, }, + { + CORE_OPTION_NAME "_fog", + "Fog Effects", + "", + { + { NULL, NULL }, + }, + NULL, + }, { CORE_OPTION_NAME "_volume_modifier_enable", "Hacim Değiştirici", @@ -331,14 +310,20 @@ struct retro_core_option_definition option_defs_tr[] = { }, NULL, }, + { + CORE_OPTION_NAME "_widescreen_cheats", + "Widescreen Cheats (Restart)", + "Activates cheats that allow certain games to display in widescreen format.", + { + { NULL, NULL }, + }, + NULL, + }, { CORE_OPTION_NAME "_cable_type", "Kablo Tipi", "", { - { "TV (RGB)", NULL }, - { "TV (Composite)", NULL }, - { "VGA (RGB)", NULL }, { NULL, NULL }, }, NULL, @@ -348,11 +333,11 @@ struct retro_core_option_definition option_defs_tr[] = { "Yayın", "", { - { "Default", "Varsayılan" }, - { "PAL_M", "PAL-M (Brazil)" }, - { "PAL_N", "PAL-N (Argentina, Paraguay, Uruguay)" }, { "NTSC", NULL }, { "PAL", "PAL (World)" }, + { "PAL_N", "PAL-N (Argentina, Paraguay, Uruguay)" }, + { "PAL_M", "PAL-M (Brazil)" }, + { "Default", "Varsayılan" }, { NULL, NULL }, }, NULL, @@ -362,8 +347,8 @@ struct retro_core_option_definition option_defs_tr[] = { "Kare Hızı", "Emülatörün ön uçla nasıl etkileşimde bulunduğunu etkiler. 'Tam Hız' - emülatör, bir kare oluşturulduğunda, kontrolü RetroArch'a geri döndürür. 'Normal' - emülatör, V-blank kesmesi her üretildiğinde kontrolü RetroArch'a döndürür. Çoğu durumda 'Tam Hız' kullanılmalıdır. 'Normal' bazı sistemlerde kare ilerleme hızını iyileştirebilir, ancak ekran statik olduğunda (örneğin, yükleme/duraklatma ekranları) yanıt vermeyen girişe neden olabilir.", { - { "fullspeed", "Tam Hız" }, { "normal", "Normal" }, + { "fullspeed", "Tam Hız" }, { NULL, NULL }, }, NULL, @@ -373,10 +358,10 @@ struct retro_core_option_definition option_defs_tr[] = { "Bölge", "", { - { "Default", "Varsayılan" }, { "Japan", NULL }, { "USA", NULL }, { "Europe", NULL }, + { "Default", "Varsayılan" }, { NULL, NULL }, }, NULL, @@ -386,13 +371,13 @@ struct retro_core_option_definition option_defs_tr[] = { "Dil", "", { - { "Default", "Varsayılan" }, { "Japanese", NULL }, { "English", NULL }, { "German", NULL }, { "French", NULL }, { "Spanish", NULL }, { "Italian", NULL }, + { "Default", "Varsayılan" }, { NULL, NULL }, }, NULL, @@ -402,9 +387,8 @@ struct retro_core_option_definition option_defs_tr[] = { "DIV Eşleştirme (performans, daha az doğru)", "", { - { "disabled", NULL }, - { "enabled", NULL }, { "auto", "Otomatik" }, + { "disabled", NULL }, { NULL, NULL }, }, NULL, @@ -456,6 +440,24 @@ struct retro_core_option_definition option_defs_tr[] = { }, NULL, }, + { + CORE_OPTION_NAME "_anisotropic_filtering", + "Anisotropic Filtering", + "Enhance the quality of textures on surfaces that are at oblique viewing angles with respect to the camera.", + { + { NULL, NULL }, + }, + NULL, + }, + { + CORE_OPTION_NAME "_pvr2_filtering", + "PowerVR2 Post-processing Filter", + "Post-process the rendered image to simulate effects specific to the PowerVR2 GPU and analog video signals.", + { + { NULL, NULL }, + }, + NULL, + }, #ifdef HAVE_TEXUPSCALE { CORE_OPTION_NAME "_texupscale", @@ -508,9 +510,18 @@ struct retro_core_option_definition option_defs_tr[] = { NULL, }, { - CORE_OPTION_NAME "_synchronous_rendering", - "Senkronize İşleme", - "", + CORE_OPTION_NAME "_auto_skip_frame", + "Auto Skip Frame", + "Automatically skip frames when the emulator is running slow. Note: This setting only applies when 'Threaded Rendering' is enabled.", + { + { NULL, NULL }, + }, + NULL + }, + { + CORE_OPTION_NAME "_delay_frame_swapping", + "Delay Frame Swapping", + "Useful to avoid flashing screens or glitchy videos. Not recommended on slow platforms. Note: This setting only applies when 'Threaded Rendering' is enabled.", { { NULL, NULL }, },