Merge branch 'master' into fh/gles-dynload

This commit is contained in:
Flyinghead 2019-05-15 11:49:57 +02:00
commit 0dd555c5c8
114 changed files with 5955 additions and 3215 deletions

311
CMakeLists.txt Normal file
View File

@ -0,0 +1,311 @@
cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR)
set(TNAME reicast)
project(${TNAME})
enable_language(ASM)
set(DEBUG_CMAKE ON)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(reicast_root_path "${CMAKE_CURRENT_SOURCE_DIR}")
set(reicast_core_path "${reicast_root_path}/core")
set(reicast_shell_path "${reicast_root_path}/shell")
list(APPEND CMAKE_MODULE_PATH "${reicast_shell_path}/cmake")
include(GetGitRevisionDescription)
git_describe(GIT_VERSION --tags)
configure_file(${reicast_core_path}/version.h.in ${reicast_core_path}/version.h @ONLY)
## reicast build modules #
#
set(reicast_SRCS "")
include(config) # configure build settings, must be first
### libdreamcast.cmake #########################################################################
set(d_core ${reicast_core_path})
file(GLOB_RECURSE hw_SRCS ${d_core}/hw/*.cpp ${d_core}/hw/*.h)
file(GLOB cfg_SRCS ${d_core}/cfg/*.cpp ${d_core}/cfg/*.h)
file(GLOB rend_SRCS ${d_core}/rend/*.cpp ${d_core}/rend/*.h)
file(GLOB input_SRCS ${d_core}/input/*.cpp ${d_core}/input/*.h)
file(GLOB reios_SRCS ${d_core}/reios/*.cpp ${d_core}/reios/*.h)
file(GLOB imgread_SRCS ${d_core}/imgread/*.cpp ${d_core}/imgread/*.h)
file(GLOB profiler_SRCS ${d_core}/profiler/*.cpp ${d_core}/profiler/*.h)
file(GLOB archive_SRCS ${d_core}/archive/*.cpp ${d_core}/archive/*.h)
#### option(rend)
file(GLOB gl4_SRCS ${d_core}/rend/gl4/*.cpp ${d_core}/rend/gl4/*.h)
file(GLOB gles_SRCS ${d_core}/rend/gles/*.cpp ${d_core}/rend/gles/*.h)
set(core_SRCS
${hw_SRCS}
${cfg_SRCS}
${rend_SRCS}
${gl4_SRCS}
${gles_SRCS}
${input_SRCS}
${reios_SRCS}
${imgread_SRCS}
${profiler_SRCS}
${d_core}/archive/archive.cpp ${d_core}/archive/archive.h
${d_core}/nullDC.cpp
${d_core}/stdclass.cpp
${d_core}/dispframe.cpp
${d_core}/serialize.cpp
)
if(${BUILD_COMPILER} EQUAL ${COMPILER_GCC}) # Add Clang if NOT WIN32 *FIXME*
list(APPEND core_SRCS ${archive_SRCS})
endif()
if(${FEAT_SHREC} EQUAL ${DYNAREC_JIT})
#
if(${HOST_CPU} EQUAL ${CPU_X86})
list(APPEND core_SRCS
${d_core}/rec-x86/rec_x86_driver.cpp
${d_core}/rec-x86/rec_x86_il.cpp
${d_core}/rec-x86/rec_x86_asm.cpp # change for linux , rec_lin86_asm.S
${d_core}/rec-x86/rec_x86_ngen.h
)
elseif(${HOST_CPU} EQUAL ${CPU_ARM})
list(APPEND core_SRCS
${d_core}/rec-ARM/ngen_arm.S
${d_core}/rec-ARM/rec_arm.cpp
)
elseif(${HOST_CPU} EQUAL ${CPU_X64})
### FIXME: asm with cmake ninja+VC
if(${BUILD_COMPILER} EQUAL ${COMPILER_VC})
list(APPEND core_SRCS ${d_core}/rec-x64/msvc.asm)
endif()
list(APPEND core_SRCS ${d_core}/rec-x64/rec_x64.cpp ${d_core}/rec-x64/x64_regalloc.h)
elseif(${HOST_CPU} EQUAL ${CPU_A64})
list(APPEND core_SRCS ${d_core}/rec-ARM64/rec_arm64.cpp ${d_core}/rec-ARM64/arm64_regalloc.h)
else()
message(" FEAT_SHREC==DYNAREC_JIT && HOST_CPU Unknown Default add arch or disable rec if not avail.")
error()
endif()
#
elseif(${FEAT_SHREC} EQUAL ${DYNAREC_CPP})
list(APPEND core_SRCS ${d_core}/rec-cpp/rec_cpp.cpp)
endif()
add_definitions(/DFEAT_HAS_SOFTREND=0)
### deps.cmake #################################################################################
set(d_deps ${reicast_core_path}/deps)
include_directories ("${d_deps}")
include_directories ("${d_deps}/picotcp/include")
include_directories ("${d_deps}/picotcp/modules")
file(GLOB xbyak_H ${d_deps}/xbyak/*.h) # include headers into cmake target/project view
file(GLOB chdr_SRCS ${d_deps}/chdr/*.c)
file(GLOB lzma_SRCS ${d_deps}/lzma/*.c)
file(GLOB lz_SRCS ${d_deps}/zlib/*.c)
file(GLOB lzip_SRCS ${d_deps}/libzip/*.c)
file(GLOB lpng_SRCS ${d_deps}/libpng/*.c)
file(GLOB lelf_SRCS ${d_deps}/libelf/el*.cpp)
file(GLOB crypt_SRCS ${d_deps}/crypto/*.cpp)
file(GLOB imgui_SRCS ${d_deps}/imgui/*.cpp)
file(GLOB lws_SRCS ${d_deps}/libwebsocket/*.c)
file(GLOB picoModS ${d_deps}/picotcp/modules/*.c)
file(GLOB picoStkS ${d_deps}/picotcp/stack/*.c)
set(pico_SRCS ${picoModS} ${picoStkS})
set(deps_SRCS
${lz_SRCS}
${lpng_SRCS}
${lelf_SRCS}
${chdr_SRCS}
${crypt_SRCS}
${imgui_SRCS}
${d_deps}/xbrz/xbrz.cpp
${d_deps}/dirent/dirent.c
${d_deps}/xxhash/xxhash.c
${d_deps}/chdpsr/cdipsr.cpp # sigh, this dir is named chdpsr for some reason ...
${d_deps}/coreio/coreio.cpp
# ${d_deps}/ifaddrs/ifaddrs.c
${xbyak_H}
)
if(${BUILD_COMPILER} EQUAL ${COMPILER_GCC}) # Add Clang if NOT WIN32 *FIXME*
list(APPEND deps_SRCS
${lzip_SRCS}
${lzma_SRCS}
${pico_SRCS}
)
add_definitions(-D_7ZIP_ST -DCHD5_LZMA)
endif()
### libosd.cmake ################################################################################
set(d_aout ${reicast_core_path}/oslib)
include_directories ("${d_core}/khronos")
## I really should just glob all of the dirs and ;shrug; if guards don't do it all ##
set(osd_SRCS "")
list(APPEND osd_SRCS ${d_aout}/audiostream.cpp)
if (${HOST_OS} EQUAL ${OS_WINDOWS})
list(APPEND osd_SRCS ${d_core}/windows/winmain.cpp)
list(APPEND osd_SRCS ${d_aout}/audiobackend_directsound.cpp)
link_libraries(dsound.lib winmm.lib xinput.lib wsock32.lib opengl32.lib)
elseif (${HOST_OS} EQUAL ${OS_LINUX} OR ${HOST_OS} EQUAL ${OS_ANDROID})
list(APPEND osd_SRCS
${d_core}/linux/common.cpp
${d_core}/linux/context.cpp
${d_core}/linux/nixprof/nixprof.cpp
${d_aout}/audiobackend_oss.cpp # add option
) # todo: configure linux audio lib options
if(NOT ANDROID)
list(APPEND osd_SRCS
${d_core}/linux-dist/x11.cpp
${d_core}/linux-dist/main.cpp
${d_core}/linux-dist/evdev.cpp)
add_definitions(-DSUPPORT_X11) ## don't use GLES ?
link_libraries(X11)
else()
list(APPEND osd_SRCS
.//android-studio/reicast/src/main/jni/src/Android.cpp
.//android-studio/reicast/src/main/jni/src/utils.cpp
# .//android-studio/reicast/src/main/jni/src/XperiaPlay.c
)
endif() # ANDROID
add_definitions(-DGLES -DUSE_EVDEV)
link_libraries(pthread dl rt asound Xext GLESv2 EGL)
elseif(${HOST_OS} EQUAL ${OS_DARWIN})
#
list(APPEND objc_SRCS
./shell/apple/emulator-osx/emulator-osx/osx-main.mm
./shell/apple/emulator-osx/emulator-osx/AppDelegate.swift
./shell/apple/emulator-osx/emulator-osx/EmuGLView.swift
)
set_source_files_properties(${objc_SRCS} PROPERTIES COMPILE_FLAGS "-x objective-c++")
list(APPEND osd_SRCS ${objc_SRCS}
${d_osd}/linux/common.cpp
${d_osd}/linux/context.cpp
${d_osd}/audiobackend/audiobackend_coreaudio.cpp
# if NOT USE_SWIFT / ObjC
#${d_osd}/apple/osx_osd.cpp
)
else()
#
message("OS Unhandled")
error()
#
endif()
##
include_directories ("${reicast_core_path}")
set(reicast_SRCS ${core_SRCS} ${deps_SRCS} ${osd_SRCS})
add_executable(${TNAME}${binSuffix} ${reicast_SRCS} ${deps_SRCS})
if(APPLE)
enable_language(Swift)
set_property(TARGET ${TNAME} PROPERTY XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "./shell/apple/emulator-osx/emulator-osx/emulator-osx-Bridging-Header.h")
target_link_libraries(${TNAME}
# "-framework Cocoa"
# "-framework AppKit"
"-framework CoreData"
"-framework CoreAudio"
"-framework AudioUnit"
"-framework AudioToolbox"
"-framework Foundation"
)
#### OSX Notes, when not using xcode you have to make app bundle, edit plist and copy, convert MainMenu.xib to nib and copy,
#null@devpc:~$ /Users/null/Documents/projects/reicast-emulator/bin/RelWithDebInfo/Reicast.app/Contents/MacOS/reicast ; exit;
#2019-03-18 14:28:44.842 reicast[11468:131797] Unknown class _TtC12emulator_osx9EmuGLView in Interface Builder file at path /Users/null/Documents/projects/reicast-emulator/bin/RelWithDebInfo/Reicast.app/Contents/Resources/MainMenu.nib.
#2019-03-18 14:28:44.842 reicast[11468:131797] Unknown class _TtC12emulator_osx11AppDelegate in Interface Builder file at path /Users/null/Documents/projects/reicast-emulator/bin/RelWithDebInfo/Reicast.app/Contents/Resources/MainMenu.nib.
#2019-03-18 14:28:44.860 reicast[11468:131797] Failed to connect (window) outlet from (NSObject) to (NSWindow): missing setter or instance variable
#
endif() #APPLE
if(DEBUG_CMAKE)
message(" ------------------------------------------------")
message(" - HOST_OS: ${HOST_OS} - HOST_CPU: ${HOST_CPU} ")
message(" - host_os: ${host_os} - host_arch: ${host_arch} ")
message(" ------------------------------------------------")
message(" C Flags: ${CMAKE_C_FLAGS} ")
message(" CXX Flags: ${CMAKE_CXX_FLAGS} ")
message(" LINK_DIRS: ${LINK_DIRECTORIES}")
message("LINK_FLAGS: ${CMAKE_EXE_LINKER_FLAGS}")
message(" ------------------------------------------------\n")
endif()

220
CMakeSettings.json Normal file
View File

@ -0,0 +1,220 @@
{
"environments": [
{
"environment": "toolchain.generic",
"TOOLCHAIN_FILE": "ps4sdk.cmake"
}
],
"configurations": [
{
"name": "win-x86-Debug",
"generator": "Ninja",
"description": "TemplateDescription_Localize_x86Debug",
"configurationType": "Debug",
"inheritEnvironments": [
"msvc_x86"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
},
{
"name": "win-x86-Release",
"generator": "Ninja",
"description": "TemplateDescription_Localize_x86Release",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"msvc_x86"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
},
{
"name": "win-x64-Debug",
"generator": "Ninja",
"description": "TemplateDescription_Localize_x64Debug",
"configurationType": "Debug",
"inheritEnvironments": [
"msvc_x64_x64"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "-DNINJA=1",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
},
{
"name": "win-x64-Release",
"generator": "Ninja",
"description": "TemplateDescription_Localize_x64Release",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"msvc_x64_x64"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "-DNINJA=1",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
},
{
"name": "win-x64-Clang-RelWithDebInfo",
"generator": "Ninja",
"description": "TemplateDescription_Localize_x64Release",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"msvc_x64_x64"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"variables": [
{
"name": "CMAKE_C_COMPILER",
"value": "clang-cl.exe"
},
{
"name": "CMAKE_CXX_COMPILER",
"value": "clang-cl.exe"
}
]
},
// Console SDK's
{
"name": "PS4 SDK",
"generator": "Ninja",
"description": "TemplateDescription_Localize_PS4SDK",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"toolchain.generic"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=${projectDir}\\cmake\\ps4sdk.cmake",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
},
{
"name": "NSW SDK",
"generator": "Ninja",
"description": "TemplateDescription_Localize_PS4SDK",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"toolchain.generic"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=${projectDir}\\cmake\\devkitA64.cmake",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
},
// UWP and VS Gen (temp?)
{
"name": "uwp-x64-Release",
"generator": "Visual Studio 15 2017 Win64",
"description": "TemplateDescription_Localize_x64Release",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"msvc_x64_x64"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10",
"buildCommandArgs": "",
"ctestCommandArgs": ""
},
{
"name": "win-x64-MSBuild-Release",
"generator": "Visual Studio 15 2017 Win64",
"description": "TemplateDescription_Localize_x64Release",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"msvc_x64_x64"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
},
{
"environments": [
{
//"MINGW64_ROOT": "C:\\msys64\\mingw64",
"BIN_ROOT": "${env.MINGW64_ROOT}\\bin",
"FLAVOR": "x86_64-w64-mingw32",
"TOOLSET_VERSION": "7.3.0",
"PATH": "${env.MINGW64_ROOT}\\bin;${env.MINGW64_ROOT}\\..\\usr\\local\\bin;${env.MINGW64_ROOT}\\..\\usr\\bin;${env.MINGW64_ROOT}\\..\\bin;${env.PATH}",
"INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION};${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION}\\tr1;${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION}\\${env.FLAVOR}",
"environment": "mingw_64"
}
],
"name": "Mingw64-Release",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"mingw_64"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"intelliSenseMode": "linux-gcc-x64",
"variables": [
{
"name": "CMAKE_C_COMPILER",
"value": "${env.BIN_ROOT}\\gcc.exe"
},
{
"name": "CMAKE_CXX_COMPILER",
"value": "${env.BIN_ROOT}\\g++.exe"
}
]
},
{
"environments": [
{
//"MINGW64_ROOT": "C:\\msys64\\mingw64",
"BIN_ROOT": "${env.MINGW64_ROOT}\\bin",
"FLAVOR": "x86_64-w64-mingw32",
"TOOLSET_VERSION": "7.3.0",
"PATH": "${env.MINGW64_ROOT}\\bin;${env.MINGW64_ROOT}\\..\\usr\\local\\bin;${env.MINGW64_ROOT}\\..\\usr\\bin;${env.MINGW64_ROOT}\\..\\bin;${env.PATH}",
"INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION};${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION}\\tr1;${env.MINGW64_ROOT}\\include\\c++\\${env.TOOLSET_VERSION}\\${env.FLAVOR}",
"environment": "mingw_64"
}
],
"name": "Mingw64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [
"mingw_64"
],
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\build\\${name}\\install",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"intelliSenseMode": "linux-gcc-x64",
"variables": [
{
"name": "CMAKE_C_COMPILER",
"value": "${env.BIN_ROOT}\\gcc.exe"
},
{
"name": "CMAKE_CXX_COMPILER",
"value": "${env.BIN_ROOT}\\g++.exe"
}
]
}
]
}

1
core/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/version.h

View File

@ -21,12 +21,15 @@
#include "archive.h"
#include "7zArchive.h"
#ifndef _MSC_VER
#include "ZipArchive.h"
#endif
Archive *OpenArchive(const char *path)
{
std::string base_path(path);
#ifndef _MSC_VER
Archive *sz_archive = new SzArchive();
if (sz_archive->Open(base_path.c_str()) || sz_archive->Open((base_path + ".7z").c_str()) || sz_archive->Open((base_path + ".7Z").c_str()))
return sz_archive;
@ -36,6 +39,7 @@ Archive *OpenArchive(const char *path)
if (zip_archive->Open(base_path.c_str()) || zip_archive->Open((base_path + ".zip").c_str()) || zip_archive->Open((base_path + ".ZIP").c_str()))
return zip_archive;
delete zip_archive;
#endif
return NULL;
}

View File

@ -127,10 +127,18 @@
#define DC_PLATFORM_AURORA 6 /* Needs to be done, Uses newer 300 mhz sh4 + 150 mhz pvr mbx SoC */
//HOST_OS
#define OS_WINDOWS 0x10000001
#define OS_LINUX 0x10000002
#define OS_DARWIN 0x10000003
#define OS_IOS 0x10000004
#define OS_ANDROID 0x10000005
#define OS_UWP 0x10000011
#define OS_NSW_HOS 0x80000001
#define OS_PS4_BSD 0x80000002
//HOST_CPU
#define CPU_X86 0x20000001
@ -138,11 +146,16 @@
#define CPU_MIPS 0x20000003
#define CPU_X64 0x20000004
#define CPU_GENERIC 0x20000005 //used for pnacl, emscripten, etc
#define CPU_ARM64 0x20000006
#define CPU_PPC 0x20000006
#define CPU_PPC64 0x20000007
#define CPU_A64 0x20000008
#define CPU_MIPS64 0x20000009
//BUILD_COMPILER
#define COMPILER_VC 0x30000001
#define COMPILER_GCC 0x30000002
#define COMPILER_VC 0x30000001
#define COMPILER_GCC 0x30000002
#define COMPILER_CLANG 0x30000003
#define COMPILER_INTEL 0x30000004
//FEAT_SHREC, FEAT_AREC, FEAT_DSPREC
#define DYNAREC_NONE 0x40000001
@ -152,6 +165,8 @@
//automatic
#ifndef CMAKE_BUILD
#if defined(_WIN32) && !defined(TARGET_WIN86) && !defined(TARGET_WIN64)
#if !defined(_M_AMD64) && !defined(__x86_64__)
#define TARGET_WIN86
@ -233,6 +248,8 @@
#define FEAT_DSPREC DYNAREC_NONE
#endif
#endif // !CMAKE_BUILD
#if defined(TARGET_NO_NIXPROF)
#define FEAT_HAS_NIXPROF 0
@ -295,6 +312,21 @@
#error Dont use HOST_NO_AREC
#endif
// Compiler Related
#define COMPILER_VC_OR_CLANG_WIN32 ((BUILD_COMPILER == COMPILER_VC) || (BUILD_COMPILER == COMPILER_CLANG) && defined(WIN32))
#if BUILD_COMPILER!=COMPILER_VC
#define ATTR_USED __attribute__((used))
#define ATTR_UNUSED __attribute__((used))
#else
#define ATTR_USED
#define ATTR_UNUSED
#endif
// TARGET PLATFORM
#define RAM_SIZE_MAX (32*1024*1024)

View File

@ -5,22 +5,13 @@
#LDFLAGS := -Wl,-Map,$(notdir $@).map,--gc-sections -Wl,-O3 -Wl,--sort-common
RZDCY_SRC_DIR ?= $(call my-dir)
VERSION_SRC := $(RZDCY_SRC_DIR)/version/version.cpp
VERSION_HEADER := $(RZDCY_SRC_DIR)/version.h
RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ hw/modem/ \
RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ \
hw/mem/ hw/pvr/ hw/sh4/ hw/sh4/interpr/ hw/sh4/modules/ plugins/ profiler/ oslib/ \
hw/extdev/ hw/arm/ hw/naomi/ imgread/ ./ deps/coreio/ deps/zlib/ deps/chdr/ deps/crypto/ \
deps/libelf/ deps/chdpsr/ arm_emitter/ rend/ reios/ deps/libpng/ deps/xbrz/ \
deps/picotcp/modules/ deps/picotcp/stack/ deps/xxhash/ deps/libzip/ deps/imgui/ \
archive/ input/
ifdef CHD5_LZMA
RZDCY_MODULES += deps/lzma/
endif
ifdef CHD5_FLAC
RZDCY_MODULES += deps/flac/src/libFLAC/
endif
deps/xxhash/ deps/libzip/ deps/imgui/ archive/ input/
ifdef WEBUI
RZDCY_MODULES += webui/
@ -31,10 +22,6 @@ ifdef WEBUI
endif
endif
ifndef NO_REC
RZDCY_MODULES += hw/sh4/dyna/
endif
ifndef NOT_ARM
RZDCY_MODULES += rec-ARM/
endif
@ -66,10 +53,6 @@ else
RZDCY_MODULES += rend/norend/
endif
ifdef HAS_SOFTREND
RZDCY_MODULES += rend/soft/
endif
ifndef NO_NIXPROF
RZDCY_MODULES += linux/nixprof/
endif
@ -90,12 +73,6 @@ ifdef FOR_WINDOWS
RZDCY_MODULES += windows/
endif
RZDCY_FILES := $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cpp))
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cc))
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.c))
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.S))
RZDCY_FILES += $(VERSION_SRC)
ifdef FOR_PANDORA
RZDCY_CFLAGS := \
$(CFLAGS) -c -O3 \
@ -134,11 +111,17 @@ RZDCY_CFLAGS :=
endif
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR) -I$(RZDCY_SRC_DIR)/rend/gles -I$(RZDCY_SRC_DIR)/deps \
-I$(RZDCY_SRC_DIR)/deps/picotcp/include -I$(RZDCY_SRC_DIR)/deps/picotcp/modules \
-I$(RZDCY_SRC_DIR)/deps/vixl -I$(RZDCY_SRC_DIR)/khronos
ifdef USE_MODEM
RZDCY_CFLAGS += -DENABLE_MODEM -I$(RZDCY_SRC_DIR)/deps/picotcp/include -I$(RZDCY_SRC_DIR)/deps/picotcp/modules
RZDCY_MODULES += hw/modem/ deps/picotcp/modules/ deps/picotcp/stack/
endif
ifdef NO_REC
RZDCY_CFLAGS += -DTARGET_NO_REC
RZDCY_CFLAGS += -DTARGET_NO_REC
else
RZDCY_MODULES += hw/sh4/dyna/
endif
ifdef USE_GLES
@ -147,17 +130,30 @@ endif
ifdef HAS_SOFTREND
RZDCY_CFLAGS += -DTARGET_SOFTREND
RZDCY_MODULES += rend/soft/
endif
ifdef CHD5_FLAC
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR)/deps/flac/src/libFLAC/include/ -I$(RZDCY_SRC_DIR)/deps/flac/include
RZDCY_CFLAGS += -DCHD5_FLAC -I$(RZDCY_SRC_DIR)/deps/flac/src/libFLAC/include/ -I$(RZDCY_SRC_DIR)/deps/flac/include
RZDCY_CFLAGS += -DPACKAGE_VERSION=\"1.3.2\" -DFLAC__HAS_OGG=0 -DFLAC__NO_DLL -DHAVE_LROUND -DHAVE_STDINT_H -DHAVE_STDLIB_H -DHAVE_SYS_PARAM_H
RZDCY_MODULES += deps/flac/src/libFLAC/
endif
# 7-Zip/LZMA settings (CHDv5)
ifdef CHD5_LZMA
RZDCY_MODULES += deps/lzma/
RZDCY_CFLAGS += -D_7ZIP_ST -DCHD5_LZMA
endif
RZDCY_CXXFLAGS := $(RZDCY_CFLAGS) -fno-exceptions -fno-rtti -std=gnu++11
$(VERSION_SRC):
echo "const char *version = \"`git describe --tags --always`\";" > $(VERSION_SRC)
echo "const char *git_hash = \"`git rev-parse --short HEAD`\";" >> $(VERSION_SRC)
echo "const char *build_date = \"`date '+%Y-%m-%d %H:%M:%S %Z'`\";" >> $(VERSION_SRC)
RZDCY_FILES := $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cpp))
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cc))
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.c))
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.S))
$(VERSION_HEADER):
echo "#define REICAST_VERSION \"`git describe --tags --always`\"" > $(VERSION_HEADER)
echo "#define GIT_HASH \"`git rev-parse --short HEAD`\"" >> $(VERSION_HEADER)
echo "#define BUILD_DATE \"`date '+%Y-%m-%d %H:%M:%S %Z'`\"" >> $(VERSION_HEADER)

148
core/deps/dirent/dirent.c Normal file
View File

@ -0,0 +1,148 @@
/*
Implementation of POSIX directory browsing functions and types for Win32.
Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
History: Created March 1997. Updated June 2003 and July 2012.
Rights: See end of file.
*/
#include "dirent.h"
#include <errno.h>
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
struct DIR
{
handle_type handle; /* -1 for failed rewind */
struct _finddata_t info;
struct dirent result; /* d_name null iff first time */
char *name; /* null-terminated char string */
};
DIR *opendir(const char *name)
{
DIR *dir = 0;
if (name && name[0])
{
size_t base_length = strlen(name);
const char *all = /* search pattern must end with suitable wildcard */
strchr("/\\", name[base_length - 1]) ? "*" : "/*";
if ((dir = (DIR *)malloc(sizeof *dir)) != 0 &&
(dir->name = (char *)malloc(base_length + strlen(all) + 1)) != 0)
{
strcat(strcpy(dir->name, name), all);
if ((dir->handle =
(handle_type)_findfirst(dir->name, &dir->info)) != -1)
{
dir->result.d_name = 0;
}
else /* rollback */
{
free(dir->name);
free(dir);
dir = 0;
}
}
else /* rollback */
{
free(dir);
dir = 0;
errno = ENOMEM;
}
}
else
{
errno = EINVAL;
}
return dir;
}
int closedir(DIR *dir)
{
int result = -1;
if (dir)
{
if (dir->handle != -1)
{
result = _findclose(dir->handle);
}
free(dir->name);
free(dir);
}
if (result == -1) /* map all errors to EBADF */
{
errno = EBADF;
}
return result;
}
struct dirent *readdir(DIR *dir)
{
struct dirent *result = 0;
if (dir && dir->handle != -1)
{
if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
{
result = &dir->result;
result->d_name = dir->info.name;
}
}
else
{
errno = EBADF;
}
return result;
}
void rewinddir(DIR *dir)
{
if (dir && dir->handle != -1)
{
_findclose(dir->handle);
dir->handle = (handle_type)_findfirst(dir->name, &dir->info);
dir->result.d_name = 0;
}
else
{
errno = EBADF;
}
}
#ifdef __cplusplus
}
#endif
/*
Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose is hereby granted without fee, provided
that this copyright and permissions notice appear in all copies and
derivatives.
This software is supplied "as is" without express or implied warranty.
But that said, if there are any problems please get in touch.
*/

50
core/deps/dirent/dirent.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef DIRENT_INCLUDED
#define DIRENT_INCLUDED
/*
Declaration of POSIX directory browsing functions and types for Win32.
Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
History: Created March 1997. Updated June 2003.
Rights: See end of file.
*/
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct DIR DIR;
struct dirent
{
char *d_name;
};
DIR *opendir(const char *);
int closedir(DIR *);
struct dirent *readdir(DIR *);
void rewinddir(DIR *);
/*
Copyright Kevlin Henney, 1997, 2003. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose is hereby granted without fee, provided
that this copyright and permissions notice appear in all copies and
derivatives.
This software is supplied "as is" without express or implied warranty.
But that said, if there are any problems please get in touch.
*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,4 +1,5 @@
#include "aica.h"
#include "aica_if.h"
#include "sgc_if.h"
#include "aica_mem.h"
#include <math.h>
@ -180,6 +181,7 @@ template void WriteAicaReg<2>(u32 reg,u32 data);
s32 libAICA_Init()
{
init_mem();
aica_Init();
verify(sizeof(*CommonData)==0x508);
verify(sizeof(*DSPData)==0x15C8);
@ -203,9 +205,12 @@ s32 libAICA_Init()
return rv_ok;
}
void libAICA_Reset(bool m)
void libAICA_Reset(bool manual)
{
if (!manual)
init_mem();
sgc_Init();
aica_Reset(manual);
}
void libAICA_Term()

View File

@ -13,11 +13,12 @@
#include <time.h>
VArray2 aica_ram;
VLockedMemory aica_ram;
u32 VREG;//video reg =P
u32 ARMRST;//arm reset reg
u32 rtc_EN=0;
int dma_sched_id;
u32 RealTimeClock;
u32 GetRTC_now()
{
@ -39,9 +40,9 @@ u32 ReadMem_aica_rtc(u32 addr,u32 sz)
switch( addr & 0xFF )
{
case 0:
return settings.dreamcast.RTC>>16;
return RealTimeClock>>16;
case 4:
return settings.dreamcast.RTC &0xFFFF;
return RealTimeClock &0xFFFF;
case 8:
return 0;
}
@ -57,16 +58,16 @@ void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz)
case 0:
if (rtc_EN)
{
settings.dreamcast.RTC&=0xFFFF;
settings.dreamcast.RTC|=(data&0xFFFF)<<16;
RealTimeClock&=0xFFFF;
RealTimeClock|=(data&0xFFFF)<<16;
rtc_EN=0;
}
return;
case 4:
if (rtc_EN)
{
settings.dreamcast.RTC&=0xFFFF0000;
settings.dreamcast.RTC|= data&0xFFFF;
RealTimeClock&=0xFFFF0000;
RealTimeClock|= data&0xFFFF;
//TODO: Clean the internal timer ?
}
return;
@ -153,15 +154,12 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
//Init/res/term
void aica_Init()
{
//mmnnn ? gotta fill it w/ something
RealTimeClock = GetRTC_now();
}
void aica_Reset(bool Manual)
{
if (!Manual)
{
aica_ram.Zero();
}
aica_Init();
}
void aica_Term()

View File

@ -2,7 +2,8 @@
#include "types.h"
extern u32 VREG;
extern VArray2 aica_ram;
extern VLockedMemory aica_ram;
extern u32 RealTimeClock;
u32 ReadMem_aica_rtc(u32 addr,u32 sz);
void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz);
u32 ReadMem_aica_reg(u32 addr,u32 sz);
@ -17,4 +18,4 @@ void aica_Term();
void aica_sb_Init();
void aica_sb_Reset(bool Manual);
void aica_sb_Term();
void aica_sb_Term();

View File

@ -783,7 +783,7 @@ void sb_Init()
maple_Init();
aica_sb_Init();
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST && defined(ENABLE_MODEM)
ModemInit();
#endif
}

View File

@ -217,8 +217,10 @@ T DYNACALL ReadMem_area0(u32 addr)
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
return (T)libExtDevice_ReadMem_A0_006(addr, sz);
#else
#elif defined(ENABLE_MODEM)
return (T)ModemReadMem_A0_006(addr, sz);
#else
return (T)0;
#endif
}
//map 0x0060 to 0x006F
@ -302,7 +304,7 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
libExtDevice_WriteMem_A0_006(addr, data, sz);
#else
#elif defined(ENABLE_MODEM)
ModemWriteMem_A0_006(addr, data, sz);
#endif
}

View File

@ -4,6 +4,7 @@
#include "maple_devs.h"
#include "maple_cfg.h"
#include "cfg/cfg.h"
#include "hw/naomi/naomi_cart.h"
#define HAS_VMU
/*
@ -28,13 +29,31 @@ extern u16 kcode[4];
extern u32 vks[4];
extern s8 joyx[4],joyy[4];
extern u8 rt[4],lt[4];
extern bool naomi_test_button;
u8 GetBtFromSgn(s8 val)
{
return val+128;
}
u32 awave_button_mapping[] = {
AWAVE_SERVICE_KEY, // DC_BTN_C
AWAVE_BTN1_KEY, // DC_BTN_B
AWAVE_BTN0_KEY, // DC_BTN_A
AWAVE_START_KEY, // DC_BTN_START
AWAVE_UP_KEY, // DC_DPAD_UP
AWAVE_DOWN_KEY, // DC_DPAD_DOWN
AWAVE_LEFT_KEY, // DC_DPAD_LEFT
AWAVE_RIGHT_KEY, // DC_DPAD_RIGHT
AWAVE_TEST_KEY, // DC_BTN_Z
AWAVE_BTN3_KEY, // DC_BTN_Y
AWAVE_BTN2_KEY, // DC_BTN_X
AWAVE_COIN_KEY, // DC_BTN_D
// DC_DPAD2_UP
// DC_DPAD2_DOWN
// DC_DPAD2_LEFT
// DC_DPAD2_RIGHT
};
struct MapleConfigMap : IMapleConfigMap
{
maple_device* dev;
@ -59,17 +78,32 @@ struct MapleConfigMap : IMapleConfigMap
pjs->kcode=kcode[player_num];
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
pjs->kcode |= 0xF901;
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
if (naomi_test_button)
pjs->kcode &= ~(1 << 14);
// if (!(pjs->kcode & (1 << 9))) // Hack (Y -> service btn)
// pjs->kcode &= ~(1 << 13);
#endif
pjs->kcode |= 0xF901; // mask off DPad2, C, D and Z
pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[player_num]);
pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[player_num]);
pjs->trigger[PJTI_R]=rt[player_num];
pjs->trigger[PJTI_L]=lt[player_num];
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
pjs->kcode = 0xFFFF;
for (int i = 0; i < 16; i++)
{
if ((kcode[player_num] & (1 << i)) == 0)
pjs->kcode &= ~awave_button_mapping[i];
}
pjs->joy[PJAI_X1] = GetBtFromSgn(joyx[player_num]);
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[1].name != NULL && NaomiGameInputs->axes[1].type == Half)
{
// Driving games: put axis 2 on RT (accel) and axis 3 on LT (brake)
pjs->joy[PJAI_Y1] = rt[player_num];
pjs->joy[PJAI_X2] = lt[player_num];
}
else
{
pjs->joy[PJAI_Y1] = GetBtFromSgn(joyy[player_num]);
pjs->joy[PJAI_X2] = rt[player_num];
pjs->joy[PJAI_Y2] = lt[player_num];
}
#endif
}
void SetImage(void* img)
{
@ -77,6 +111,16 @@ struct MapleConfigMap : IMapleConfigMap
}
};
bool maple_atomiswave_coin_chute(int slot)
{
for (int i = 0; i < 16; i++)
{
if ((kcode[slot] & (1 << i)) == 0 && awave_button_mapping[i] == AWAVE_COIN_KEY)
return true;
}
return false;
}
void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num = -1)
{
if (MapleDevices[bus][port] != NULL)
@ -100,17 +144,32 @@ void mcfg_CreateAtomisWaveControllers()
// Then other devices on port 2 and 3 for analog axes, light guns, ...
mcfg_Create(MDT_SegaController, 0, 5);
mcfg_Create(MDT_SegaController, 1, 5);
// mcfg_Create(MDT_SegaController, 2, 5, 0);
// mcfg_Create(MDT_SegaController, 3, 5, 1);
// mcfg_Create(MDT_LightGun, 2, 5, 0);
// mcfg_Create(MDT_LightGun, 3, 5, 1);
// mcfg_Create(MDT_Mouse, 2, 5, 0);
// Guilty Gear Isuka (4P) needs 4 std controllers
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes)
// Maximum Speed same
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
// Sports Shooting same
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 3
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[0].name != NULL)
{
// Game needs analog axes
mcfg_Create(MDT_SegaController, 2, 5, 0);
mcfg_Create(MDT_SegaController, 3, 5, 1);
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes)
// Maximum Speed same
}
else if (settings.input.JammaSetup == 1)
{
// 4 players
mcfg_Create(MDT_SegaController, 2, 5);
mcfg_Create(MDT_SegaController, 3, 5);
}
else if (settings.input.JammaSetup == 5)
{
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
// Sports Shooting same
mcfg_Create(MDT_LightGun, 2, 5, 0);
mcfg_Create(MDT_LightGun, 3, 5, 1);
}
else if (settings.input.JammaSetup == 3)
{
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 2
mcfg_Create(MDT_Mouse, 2, 5, 0);
}
}
void mcfg_CreateDevices()

View File

@ -68,3 +68,5 @@ void mcfg_CreateAtomisWaveControllers();
void mcfg_DestroyDevices();
void mcfg_SerializeDevices(void **data, unsigned int *total_size);
void mcfg_UnserializeDevices(void **data, unsigned int *total_size);
bool maple_atomiswave_coin_chute(int slot);

View File

@ -7,6 +7,7 @@
#include "hw/naomi/naomi.h"
#include "hw/naomi/naomi_cart.h"
#include "hw/pvr/spg.h"
#include "input/gamepad.h"
#include <time.h>
#include "deps/zlib/zlib.h"
@ -198,6 +199,35 @@ struct maple_base: maple_device
*/
struct maple_sega_controller: maple_base
{
virtual u32 get_capabilities() {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xfe060f00; // 4 analog axes (0-3) X Y A B Start U D L R
}
virtual u32 transform_kcode(u32 kcode) {
return kcode;
}
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) {
switch (index)
{
case 0:
return pjs.trigger[PJTI_R]; // Right trigger
case 1:
return pjs.trigger[PJTI_L]; // Left trigger
case 2:
return pjs.joy[PJAI_X1]; // Stick X
case 3:
return pjs.joy[PJAI_Y1]; // Stick Y
default:
return 0x80; // unused
}
}
virtual MapleDeviceType get_device_type()
{
return MDT_SegaController;
@ -215,9 +245,9 @@ struct maple_sega_controller: maple_base
//struct data
//3*4
w32( 0xfe060f00);
w32( 0);
w32( 0);
w32(get_capabilities());
w32(0);
w32(0);
//1 area code
w8(0xFF);
@ -250,26 +280,26 @@ struct maple_sega_controller: maple_base
//state data
//2 key code
w16(pjs.kcode);
w16(transform_kcode(pjs.kcode));
//triggers
//1 R
w8(pjs.trigger[PJTI_R]);
w8(get_analog_axis(0, pjs));
//1 L
w8(pjs.trigger[PJTI_L]);
w8(get_analog_axis(1, pjs));
//joyx
//1
w8(pjs.joy[PJAI_X1]);
w8(get_analog_axis(2, pjs));
//joyy
//1
w8(pjs.joy[PJAI_Y1]);
w8(get_analog_axis(3, pjs));
//not used
//1
w8(0x80);
w8(get_analog_axis(4, pjs));
//1
w8(0x80);
w8(get_analog_axis(5, pjs));
}
return MDRS_DataTransfer;
@ -281,6 +311,38 @@ struct maple_sega_controller: maple_base
}
};
struct maple_atomiswave_controller: maple_sega_controller
{
virtual u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xff663f00; // 6 analog axes, X Y L2/D2(?) A B C Start U D L R
}
virtual u32 transform_kcode(u32 kcode) override {
return kcode | AWAVE_TRIGGER_KEY;
}
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
switch (index)
{
case 2:
return pjs.joy[PJAI_X1];
case 3:
return pjs.joy[PJAI_Y1];
case 4:
return pjs.joy[PJAI_X2];
case 5:
return pjs.joy[PJAI_Y2];
default:
return 0x80;
}
}
};
/*
Sega Dreamcast Visual Memory Unit
This is pretty much done (?)
@ -1267,6 +1329,10 @@ struct maple_mouse : maple_base
struct maple_lightgun : maple_base
{
virtual u32 transform_kcode(u32 kcode) {
return kcode | 0xFF01;
}
virtual MapleDeviceType get_device_type()
{
return MDT_LightGun;
@ -1315,21 +1381,13 @@ struct maple_lightgun : maple_base
PlainJoystickState pjs;
config->GetInput(&pjs);
// Also use the mouse buttons
if (!(mo_buttons & 4)) // Left button
pjs.kcode &= ~4; // A
if (!(mo_buttons & 2)) // Right button
pjs.kcode &= ~2; // B
if (!(mo_buttons & 8)) // Wheel button
pjs.kcode &= ~8; // Start
//caps
//4
w32(MFID_0_Input);
//state data
//2 key code
w16(pjs.kcode | 0xFF01);
w16(transform_kcode(pjs.kcode));
//not used
//2
@ -1355,6 +1413,13 @@ struct maple_lightgun : maple_base
}
};
struct atomiswave_lightgun : maple_lightgun
{
virtual u32 transform_kcode(u32 kcode) override {
return (kcode & AWAVE_TRIGGER_KEY) == 0 ? ~AWAVE_BTN0_KEY : ~0;
}
};
extern u16 kcode[4];
extern s8 joyx[4],joyy[4];
extern u8 rt[4], lt[4];
@ -1381,20 +1446,29 @@ static u16 getRightTriggerAxis()
return rt[0] << 8;
}
NaomiInputMapping Naomi_Mapping = {
{ getJoystickXAxis, getJoystickYAxis, getRightTriggerAxis, getLeftTriggerAxis },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0x40, 0x01, 0x02, 0x80, 0x20, 0x10, 0x08, 0x04, 0, 0x80, 0x40, 0, 0 },
// SERVICE BTN1 BTN0 START UP DOWN LEFT RIGHT BTN2 BTN3
u32 naomi_button_mapping[] = {
NAOMI_SERVICE_KEY, // DC_BTN_C
NAOMI_BTN1_KEY, // DC_BTN_B
NAOMI_BTN0_KEY, // DC_BTN_A
NAOMI_START_KEY, // DC_BTN_START
NAOMI_UP_KEY, // DC_DPAD_UP
NAOMI_DOWN_KEY, // DC_DPAD_DOWN
NAOMI_LEFT_KEY, // DC_DPAD_LEFT
NAOMI_RIGHT_KEY, // DC_DPAD_RIGHT
NAOMI_TEST_KEY, // DC_BTN_Z
NAOMI_BTN3_KEY, // DC_BTN_Y
NAOMI_BTN2_KEY, // DC_BTN_X
NAOMI_COIN_KEY, // DC_BTN_D
// DC_DPAD2_UP
// DC_DPAD2_DOWN
// DC_DPAD2_LEFT
// DC_DPAD2_RIGHT
};
/*
* Sega JVS I/O board
*/
bool coin_chute;
static bool old_coin_chute;
static int coin_count;
bool naomi_test_button = false;
static bool old_coin_chute[4];
static int coin_count[4];
struct maple_naomi_jamma;
@ -2313,63 +2387,56 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
{
JVS_STATUS1(); // report byte
LOGJVS("btns ");
JVS_OUT(naomi_test_button ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
// FIXME in-lst mapping
u8 buttons[8] = { 0 };
u32 keycode = ~kcode[0];
for (int i = 0; i < 16; i++)
if ((keycode & (1 << i)) != 0)
{
buttons[Naomi_Mapping.button_mapping_byte[i]] |= Naomi_Mapping.button_mapping_mask[i];
}
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
u16 buttons[4] = { 0 };
for (int player = 0; player < buffer_in[cmdi + 1] && first_player + player < ARRAY_SIZE(kcode); player++)
{
u8 *cur_btns = &buttons[(first_player + player) * 2];
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns[0]);
JVS_OUT(cur_btns[0]);
if (buffer_in[cmdi + 2] == 2)
u32 keycode = ~kcode[first_player + player];
for (int i = 0; i < 16; i++)
{
LOGJVS("%02x ", cur_btns[1]);
JVS_OUT(cur_btns[1]);
if ((keycode & (1 << i)) != 0)
buttons[player] |= naomi_button_mapping[i];
}
}
LOGJVS("btns ");
JVS_OUT((buttons[0] & NAOMI_TEST_KEY) ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
{
u16 cur_btns = first_player + player < ARRAY_SIZE(buttons) ? buttons[first_player + player] : 0;
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns >> 8);
JVS_OUT(cur_btns >> 8);
if (buffer_in[cmdi + 2] == 2)
{
LOGJVS("%02x ", cur_btns & 0xFF);
JVS_OUT(cur_btns);
}
}
// for (int player = 0; player < jvs_request[channel][cmdi + 1]; player++)
// {
// u32 keycode = ~kcode[player];
// if (keycode & DC_BTN_C)
// keycode |= 0xFFff;
//
// if (jvs_request[channel][cmdi + 2] == 1)
// JVS_OUT(keycode);
// else
// w16(keycode);
// }
cmdi += 3;
}
break;
case 0x21: // Read coins
{
if (coin_chute && !old_coin_chute)
coin_count++;
old_coin_chute = coin_chute;
JVS_STATUS1(); // report byte
LOGJVS("coins ");
for (int slot = 0; slot < buffer_in[cmdi + 1]; slot++)
{
if (slot == 0)
bool coin_chute = false;
u32 keycode = ~kcode[first_player + slot];
for (int i = 0; i < 16 && !coin_chute; i++)
{
LOGJVS("0:%d ", coin_count);
JVS_OUT((coin_count >> 8) & 0x3F); // status (2 highest bits, 0: normal), coin count MSB
JVS_OUT(coin_count); // coin count LSB
}
else
{
LOGJVS("%d:0 ", slot);
JVS_OUT(0);
JVS_OUT(0);
if (naomi_button_mapping[i] == NAOMI_COIN_KEY && (keycode & (1 << i)) != 0)
coin_chute = true;
}
if (coin_chute && !old_coin_chute[first_player + slot])
coin_count[first_player + slot] += 1;
old_coin_chute[first_player + slot] = coin_chute;
LOGJVS("%d:%d ", slot + 1 + first_player, coin_count[first_player + slot]);
// status (2 highest bits, 0: normal), coin count MSB
JVS_OUT((coin_count[first_player + slot] >> 8) & 0x3F);
// coin count LSB
JVS_OUT(coin_count[first_player + slot]);
}
cmdi += 2;
}
@ -2393,34 +2460,50 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
}
LOGJVS("x,y:%4x,%4x ", x, y);
JVS_OUT(x >> 8); // X, MSB
JVS_OUT(x); // X, LSB
JVS_OUT(x); // X, LSB
JVS_OUT(y >> 8); // Y, MSB
JVS_OUT(y); // Y, LSB
JVS_OUT(y); // Y, LSB
axis = 2;
}
int full_axis_count = 0;
int half_axis_count = 0;
for (; axis < buffer_in[cmdi + 1]; axis++)
{
// FIXME Need to know how many axes per player for proper mapping
u16 axis_value;
if (axis + first_player * 4 < 8 && Naomi_Mapping.axis[axis + first_player * 4] != NULL)
axis_value = Naomi_Mapping.axis[axis + first_player * 4]();
if (NaomiGameInputs != NULL
&& axis < ARRAY_SIZE(NaomiGameInputs->axes)
&& NaomiGameInputs->axes[axis].name != NULL
&& NaomiGameInputs->axes[axis].type == Half)
{
if (half_axis_count == 0)
axis_value = rt[first_player] << 8;
else if (half_axis_count == 1)
axis_value = lt[first_player] << 8;
else
axis_value = 0;
half_axis_count++;
}
else
{
switch (axis) {
switch (full_axis_count) {
case 0:
axis_value = (joyx[first_player + axis / 4] + 128) << 8;
axis_value = (joyx[first_player] + 128) << 8;
break;
case 1:
axis_value = (joyy[first_player + axis / 4] + 128) << 8;
break;
case 2:
axis_value = rt[first_player + axis / 4] << 8;
break;
case 3:
axis_value = lt[first_player + axis / 4] << 8;
axis_value = (joyy[first_player] + 128) << 8;
break;
// TODO right analog stick
// case 2:
// axis_value = (joyrx[first_player] + 128) << 8;
// break;
// case 3:
// axis_value = (joyry[first_player] + 128) << 8;
// break;
default:
axis_value = 128;
}
full_axis_count++;
}
LOGJVS("%d:%4x ", axis, axis_value);
JVS_OUT(axis_value >> 8);
@ -2493,8 +2576,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
break;
case 0x30: // substract coin
if (buffer_in[cmdi + 1] == 1)
coin_count -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
if (buffer_in[cmdi + 1] > 0 && first_player + buffer_in[cmdi + 1] - 1 < ARRAY_SIZE(coin_count))
coin_count[first_player + buffer_in[cmdi + 1] - 1] -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
JVS_STATUS1(); // report byte
cmdi += 4;
break;
@ -2542,7 +2625,11 @@ maple_device* maple_Create(MapleDeviceType type)
switch(type)
{
case MDT_SegaController:
rv=new maple_sega_controller();
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_sega_controller();
#else
rv = new maple_atomiswave_controller();
#endif
break;
case MDT_Microphone:
@ -2566,7 +2653,11 @@ maple_device* maple_Create(MapleDeviceType type)
break;
case MDT_LightGun:
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_lightgun();
#else
rv = new atomiswave_lightgun();
#endif
break;
case MDT_NaomiJamma:

View File

@ -21,7 +21,6 @@ _vmem_WriteMem32FP* _vmem_WF32[HANDLER_COUNT];
//upper 8b of the address
void* _vmem_MemInfo_ptr[0x100];
void _vmem_get_ptrs(u32 sz,bool write,void*** vmap,void*** func)
{
*vmap=_vmem_MemInfo_ptr;
@ -385,10 +384,7 @@ void _vmem_reset()
verify(_vmem_register_handler(0,0,0,0,0,0)==0);
}
void _vmem_term()
{
}
void _vmem_term() {}
#include "hw/pvr/pvr_mem.h"
#include "hw/sh4/sh4_mem.h"
@ -409,414 +405,119 @@ void* malloc_pages(size_t size) {
#endif
}
bool _vmem_reserve_nonvmem()
{
virt_ram_base = 0;
p_sh4rcb=(Sh4RCB*)malloc_pages(sizeof(Sh4RCB));
mem_b.size=RAM_SIZE;
mem_b.data=(u8*)malloc_pages(RAM_SIZE);
vram.size=VRAM_SIZE;
vram.data=(u8*)malloc_pages(VRAM_SIZE);
aica_ram.size=ARAM_SIZE;
aica_ram.data=(u8*)malloc_pages(ARAM_SIZE);
return true;
}
void _vmem_bm_reset_nvmem();
// Resets the FPCB table (by either clearing it to the default val
// or by flushing it and making it fault on access again.
void _vmem_bm_reset() {
if (virt_ram_base) {
#if !defined(TARGET_NO_NVMEM)
_vmem_bm_reset_nvmem();
#endif
}
#ifndef TARGET_IPHONE
if (!virt_ram_base)
#endif
{
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, FPCB_SIZE);
}
// If we allocated it via vmem:
if (virt_ram_base)
vmem_platform_reset_mem(p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
else
// We allocated it via a regular malloc/new/whatever on the heap
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
}
static void _vmem_release_nonvmem()
{
free(p_sh4rcb);
free(vram.data);
free(aica_ram.data);
free(mem_b.data);
}
// This gets called whenever there is a pagefault, it is possible that it lands
// on the fpcb memory range, which is allocated on miss. Returning true tells the
// fault handler this was us, and that the page is resolved and can continue the execution.
bool BM_LockedWrite(u8* address) {
if (!virt_ram_base)
return false; // No vmem, therefore not us who caused this.
#if !defined(TARGET_NO_NVMEM)
uintptr_t ptrint = (uintptr_t)address;
uintptr_t start = (uintptr_t)p_sh4rcb->fpcb;
uintptr_t end = start + sizeof(p_sh4rcb->fpcb);
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
#if HOST_OS==OS_WINDOWS
#include <Windows.h>
HANDLE mem_handle;
void* _nvmem_map_buffer(u32 dst,u32 addrsz,u32 offset,u32 size, bool w)
{
void* ptr;
void* rv;
u32 map_times=addrsz/size;
verify((addrsz%size)==0);
verify(map_times>=1);
rv= MapViewOfFileEx(mem_handle,FILE_MAP_READ | (w?FILE_MAP_WRITE:0),0,offset,size,&virt_ram_base[dst]);
if (!rv)
return 0;
for (u32 i=1;i<map_times;i++)
{
dst+=size;
ptr=MapViewOfFileEx(mem_handle,FILE_MAP_READ | (w?FILE_MAP_WRITE:0),0,offset,size,&virt_ram_base[dst]);
if (!ptr) return 0;
}
return rv;
}
void* _nvmem_unused_buffer(u32 start,u32 end)
{
void* ptr=VirtualAlloc(&virt_ram_base[start],end-start,MEM_RESERVE,PAGE_NOACCESS);
if (ptr == 0)
return 0;
return ptr;
}
void* _nvmem_alloc_mem()
{
mem_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX, 0);
void* rv= (u8*)VirtualAlloc(0, 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX, MEM_RESERVE, PAGE_NOACCESS);
if (rv) VirtualFree(rv,0,MEM_RELEASE);
return rv;
}
#else
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0 //missing from linux :/ -- could be the cause of android slowness ?
#endif
#ifdef _ANDROID
#include <linux/ashmem.h>
#ifndef ASHMEM_DEVICE
#define ASHMEM_DEVICE "/dev/ashmem"
#endif
int ashmem_create_region(const char *name, size_t size)
{
int fd, ret;
fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
if (name) {
char buf[ASHMEM_NAME_LEN];
strlcpy(buf, name, sizeof(buf));
ret = ioctl(fd, ASHMEM_SET_NAME, buf);
if (ret < 0)
goto error;
}
ret = ioctl(fd, ASHMEM_SET_SIZE, size);
if (ret < 0)
goto error;
return fd;
error:
close(fd);
return ret;
}
#endif
int fd;
void* _nvmem_unused_buffer(u32 start,u32 end)
{
void* ptr=mmap(&virt_ram_base[start], end-start, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
if (MAP_FAILED==ptr)
return 0;
return ptr;
}
void* _nvmem_map_buffer(u32 dst,u32 addrsz,u32 offset,u32 size, bool w)
{
void* ptr;
void* rv;
printf("MAP %08X w/ %d\n",dst,offset);
u32 map_times=addrsz/size;
verify((addrsz%size)==0);
verify(map_times>=1);
u32 prot=PROT_READ|(w?PROT_WRITE:0);
rv= mmap(&virt_ram_base[dst], size, prot, MAP_SHARED | MAP_NOSYNC | MAP_FIXED, fd, offset);
if (MAP_FAILED==rv || rv!=(void*)&virt_ram_base[dst] || (mprotect(rv,size,prot)!=0))
{
printf("MAP1 failed %d\n",errno);
return 0;
}
for (u32 i=1;i<map_times;i++)
{
dst+=size;
ptr=mmap(&virt_ram_base[dst], size, prot , MAP_SHARED | MAP_NOSYNC | MAP_FIXED, fd, offset);
if (MAP_FAILED==ptr || ptr!=(void*)&virt_ram_base[dst] || (mprotect(rv,size,prot)!=0))
{
printf("MAP2 failed %d\n",errno);
return 0;
}
}
return rv;
}
void* _nvmem_alloc_mem()
{
#if HOST_OS == OS_DARWIN
string path = get_writable_data_path("/dcnzorz_mem");
fd = open(path.c_str(),O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink(path.c_str());
verify(ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
#elif !defined(_ANDROID)
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR,S_IREAD | S_IWRITE);
shm_unlink("/dcnzorz_mem");
if (fd==-1)
{
fd = open("dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink("dcnzorz_mem");
}
verify(ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX) == 0);
#else
fd = ashmem_create_region(0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
if (false)//this causes writebacks to flash -> slow and stuttery
{
fd = open("/data/data/com.reicast.emulator/files/dcnzorz_mem",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
unlink("/data/data/com.reicast.emulator/files/dcnzorz_mem");
}
#endif
u32 sz = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX + 0x10000;
void* rv=mmap(0, sz, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
verify(rv != NULL);
munmap(rv,sz);
return (u8*)rv + 0x10000 - unat(rv)%0x10000;//align to 64 KB (Needed for linaro mmap not to extend to next region)
}
#endif
#define map_buffer(dsts,dste,offset,sz,w) {ptr=_nvmem_map_buffer(dsts,dste-dsts,offset,sz,w);if (!ptr) return false;}
#define unused_buffer(start,end) {ptr=_nvmem_unused_buffer(start,end);if (!ptr) return false;}
u32 pagecnt;
void _vmem_bm_reset_nvmem()
{
#if defined(TARGET_NO_NVMEM)
return;
#endif
#ifdef TARGET_IPHONE
//On iOS & nacl we allways allocate all of the mapping table
mprotect(p_sh4rcb, sizeof(p_sh4rcb->fpcb), PROT_READ | PROT_WRITE);
return;
#endif
pagecnt=0;
#if HOST_OS==OS_WINDOWS
VirtualFree(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MEM_DECOMMIT);
#else
mprotect(p_sh4rcb, sizeof(p_sh4rcb->fpcb), PROT_NONE);
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_DONTNEED);
#ifdef MADV_REMOVE
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_REMOVE);
#else
//OSX, IOS
madvise(p_sh4rcb,sizeof(p_sh4rcb->fpcb),MADV_FREE);
#endif
#endif
printf("Freeing fpcb\n");
}
bool BM_LockedWrite(u8* address)
{
if (!_nvmem_enabled())
return false;
#if FEAT_SHREC != DYNAREC_NONE
u32 addr=address-(u8*)p_sh4rcb->fpcb;
address=(u8*)p_sh4rcb->fpcb+ (addr&~PAGE_MASK);
if (addr<sizeof(p_sh4rcb->fpcb))
{
//printf("Allocated %d PAGES [%08X]\n",++pagecnt,addr);
#if HOST_OS==OS_WINDOWS
verify(VirtualAlloc(address,PAGE_SIZE,MEM_COMMIT,PAGE_READWRITE));
#else
mprotect (address, PAGE_SIZE, PROT_READ | PROT_WRITE);
#endif
bm_vmem_pagefill((void**)address,PAGE_SIZE);
if (ptrint >= start && ptrint < end) {
// Alloc the page then and initialize it to default values
void *aligned_addr = (void*)(ptrint & (~PAGE_MASK));
vmem_platform_ondemand_page(aligned_addr, PAGE_SIZE);
bm_vmem_pagefill((void**)aligned_addr, PAGE_SIZE);
return true;
}
#else
die("BM_LockedWrite and NO REC");
#endif
return false;
}
bool _vmem_reserve()
{
void* ptr=0;
bool _vmem_reserve() {
// TODO: Static assert?
verify((sizeof(Sh4RCB)%PAGE_SIZE)==0);
if (settings.dynarec.disable_nvmem)
return _vmem_reserve_nonvmem();
VMemType vmemstatus = MemTypeError;
virt_ram_base=(u8*)_nvmem_alloc_mem();
// Use vmem only if settings mandate so, and if we have proper exception handlers.
#ifndef TARGET_NO_EXCEPTIONS
if (!settings.dynarec.disable_nvmem)
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb);
#endif
if (virt_ram_base==0)
return _vmem_reserve_nonvmem();
p_sh4rcb=(Sh4RCB*)virt_ram_base;
// Fallback to statically allocated buffers, this results in slow-ops being generated.
if (vmemstatus == MemTypeError) {
printf("Warning! nvmem is DISABLED (due to failure or not being built-in\n");
virt_ram_base = 0;
// Map the sh4 context but protect access to Sh4RCB.fpcb[]
#if HOST_OS==OS_WINDOWS
//verify(p_sh4rcb==VirtualAlloc(p_sh4rcb,sizeof(Sh4RCB),MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE));
verify(p_sh4rcb==VirtualAlloc(p_sh4rcb,sizeof(Sh4RCB),MEM_RESERVE,PAGE_NOACCESS));
// Allocate it all and initialize it.
p_sh4rcb = (Sh4RCB*)malloc_pages(sizeof(Sh4RCB));
bm_vmem_pagefill((void**)p_sh4rcb->fpcb, sizeof(p_sh4rcb->fpcb));
verify(VirtualAlloc((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb),sizeof(Sh4RCB)-sizeof(p_sh4rcb->fpcb),MEM_COMMIT,PAGE_READWRITE));
#else
verify(p_sh4rcb==mmap(p_sh4rcb,sizeof(Sh4RCB),PROT_NONE,MAP_PRIVATE | MAP_ANON, -1, 0));
mprotect((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb),sizeof(Sh4RCB)-sizeof(p_sh4rcb->fpcb),PROT_READ|PROT_WRITE);
#endif
virt_ram_base+=sizeof(Sh4RCB);
mem_b.size = RAM_SIZE;
mem_b.data = (u8*)malloc_pages(RAM_SIZE);
//Area 0
//[0x00000000 ,0x00800000) -> unused
unused_buffer(0x00000000,0x00800000);
vram.size = VRAM_SIZE;
vram.data = (u8*)malloc_pages(VRAM_SIZE);
//I wonder, aica ram warps here ?.?
//I really should check teh docs before codin ;p
//[0x00800000,0x00A00000);
map_buffer(0x00800000,0x01000000,MAP_ARAM_START_OFFSET,ARAM_SIZE,false);
map_buffer(0x20000000,0x20000000+ARAM_SIZE,MAP_ARAM_START_OFFSET,ARAM_SIZE,true);
aica_ram.size = ARAM_SIZE;
aica_ram.data = (u8*)malloc_pages(ARAM_SIZE);
}
else {
printf("Info: nvmem is enabled, with addr space of size %s\n", vmemstatus == MemType4GB ? "4GB" : "512MB");
// Map the different parts of the memory file into the new memory range we got.
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
const vmem_mapping mem_mappings[] = {
{0x00000000, 0x00800000, 0, 0, false}, // Area 0 -> unused
{0x00800000, 0x01000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, false}, // Aica, wraps too
{0x20000000, 0x20000000+ARAM_SIZE, MAP_ARAM_START_OFFSET, ARAM_SIZE, true},
{0x01000000, 0x04000000, 0, 0, false}, // More unused
{0x04000000, 0x05000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x10000000, 0x20000000, 0, 0, false}, // Area 4-7 (unused)
};
vmem_platform_create_mappings(&mem_mappings[0], sizeof(mem_mappings) / sizeof(mem_mappings[0]));
aica_ram.size=ARAM_SIZE;
aica_ram.data=(u8*)ptr;
//[0x01000000 ,0x04000000) -> unused
unused_buffer(0x01000000,0x04000000);
// Point buffers to actual data pointers
aica_ram.size = ARAM_SIZE;
aica_ram.data = &virt_ram_base[0x20000000]; // Points to the writtable AICA addrspace
//Area 1
//[0x04000000,0x05000000) -> vram (16mb, warped on dc)
map_buffer(0x04000000,0x05000000,MAP_VRAM_START_OFFSET,VRAM_SIZE,true);
vram.size=VRAM_SIZE;
vram.data=(u8*)ptr;
vram.size = VRAM_SIZE;
vram.data = &virt_ram_base[0x04000000]; // Points to first vram mirror (writtable and lockable)
//[0x05000000,0x06000000) -> unused (32b path)
unused_buffer(0x05000000,0x06000000);
//[0x06000000,0x07000000) -> vram mirror
map_buffer(0x06000000,0x07000000,MAP_VRAM_START_OFFSET,VRAM_SIZE,true);
//[0x07000000,0x08000000) -> unused (32b path) mirror
unused_buffer(0x07000000,0x08000000);
//Area 2
//[0x08000000,0x0C000000) -> unused
unused_buffer(0x08000000,0x0C000000);
//Area 3
//[0x0C000000,0x0D000000) -> main ram
//[0x0D000000,0x0E000000) -> main ram mirror
//[0x0E000000,0x0F000000) -> main ram mirror
//[0x0F000000,0x10000000) -> main ram mirror
map_buffer(0x0C000000,0x10000000,MAP_RAM_START_OFFSET,RAM_SIZE,true);
mem_b.size=RAM_SIZE;
mem_b.data=(u8*)ptr;
//Area 4
//Area 5
//Area 6
//Area 7
//all -> Unused
//[0x10000000,0x20000000) -> unused
unused_buffer(0x10000000,0x20000000);
printf("vmem reserve: base: %08X, aram: %08x, vram: %08X, ram: %08X\n",virt_ram_base,aica_ram.data,vram.data,mem_b.data);
mem_b.size = RAM_SIZE;
mem_b.data = &virt_ram_base[0x0C000000]; // Main memory, first mirror
}
// Clear out memory
aica_ram.Zero();
vram.Zero();
mem_b.Zero();
printf("Mem alloc successful!\n");
return virt_ram_base!=0;
return true;
}
void _vmem_release()
{
if (!_nvmem_enabled())
_vmem_release_nonvmem();
else
{
if (virt_ram_base != NULL)
{
#if HOST_OS == OS_WINDOWS
VirtualFree(virt_ram_base, 0, MEM_RELEASE);
#else
munmap(virt_ram_base, 0x20000000);
#endif
virt_ram_base = NULL;
}
#if HOST_OS != OS_WINDOWS
close(fd);
#endif
#define freedefptr(x) \
if (x) { free(x); x = NULL; }
void _vmem_release() {
if (virt_ram_base)
vmem_platform_destroy();
else {
freedefptr(p_sh4rcb);
freedefptr(vram.data);
freedefptr(aica_ram.data);
freedefptr(mem_b.data);
}
}
#else
bool _vmem_reserve()
{
return _vmem_reserve_nonvmem();
}
void _vmem_release()
{
_vmem_release_nonvmem();
}
#endif

View File

@ -1,6 +1,33 @@
#pragma once
#include "types.h"
enum VMemType {
MemType4GB,
MemType512MB,
MemTypeError
};
struct vmem_mapping {
u32 start_address, end_address;
unsigned memoffset, memsize;
bool allow_writes;
};
// Platform specific vmemory API
// To initialize (maybe) the vmem subsystem
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr);
// To reset the on-demand allocated pages.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes);
// To handle a fault&allocate an ondemand page.
void vmem_platform_ondemand_page(void *address, unsigned size_bytes);
// To create the mappings in the address space.
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps);
// Just tries to wipe as much as possible in the relevant area.
void vmem_platform_destroy();
// Note: if you want to disable vmem magic in any given platform, implement the
// above functions as empty functions and make vmem_platform_init return MemTypeError.
//Typedef's
//ReadMem
typedef u8 DYNACALL _vmem_ReadMem8FP(u32 Address);
@ -70,4 +97,4 @@ static inline bool _nvmem_enabled() {
return virt_ram_base != 0;
}
void _vmem_bm_reset();
void _vmem_bm_reset();

View File

@ -18,6 +18,9 @@
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "types.h"
#if BUILD_COMPILER!=COMPILER_VC && (BUILD_COMPILER!=COMPILER_CLANG || !defined(WIN32))
#include <stdio.h>
#include <errno.h>
@ -145,3 +148,5 @@ char *read_name(char *reader, char *buffer, int *count)
return name;
}
#endif // !COMPILER_VC_OR_CLANG_WIN32

View File

@ -162,6 +162,11 @@ ROM board internal layouts:
*/
#include "awcartridge.h"
#include "awave_regs.h"
#ifdef _MSC_VER
#undef min
#undef max
#include <algorithm>
#endif
u32 AWCartridge::ReadMem(u32 address, u32 size) {
verify(size != 1);

View File

@ -6,6 +6,7 @@
#include "hw/holly/sb.h"
#include "hw/sh4/sh4_mem.h"
#include "hw/holly/holly_intc.h"
#include "hw/maple/maple_cfg.h"
#include "naomi.h"
#include "naomi_cart.h"
@ -634,7 +635,6 @@ void Update_naomi()
}
static u8 aw_maple_devs;
extern bool coin_chute;
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
addr &= 0x7ff;
@ -653,12 +653,13 @@ u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
aw_ram_test_skipped = true;
return 0;
}
if (coin_chute)
{
// FIXME Coin Error if coin_chute is set for too long
return 0xE;
u8 coin_input = 0xF;
for (int slot = 0; slot < 4; slot++)
if (maple_atomiswave_coin_chute(slot))
coin_input &= ~(1 << slot);
return coin_input;
}
return 0xF;
case 0x284: // Atomiswave maple devices
// ddcc0000 where cc/dd are the types of devices on maple bus 2 and 3:

View File

@ -32,7 +32,7 @@ fd_t* RomCacheMap = NULL;
u32 RomCacheMapCount;
char naomi_game_id[33];
InputDescriptors *naomi_game_inputs;
InputDescriptors *NaomiGameInputs;
u8 *naomi_default_eeprom;
extern RomChip sys_rom;
@ -246,7 +246,7 @@ static bool naomi_cart_LoadZip(char *filename)
break;
}
CurrentCartridge->SetKey(game->key);
naomi_game_inputs = game->inputs;
NaomiGameInputs = game->inputs;
for (int romid = 0; game->blobs[romid].filename != NULL; romid++)
{

View File

@ -110,6 +110,6 @@ struct InputDescriptors
AxisDescriptor axes[8];
};
extern InputDescriptors *naomi_game_inputs;
extern InputDescriptors *NaomiGameInputs;
#endif //NAOMI_CART_H

View File

@ -82,8 +82,7 @@ bool renderer_enabled = true; // Signals the renderer thread to exit
bool renderer_changed = false; // Signals the renderer thread to switch renderer
#if !defined(TARGET_NO_THREADS)
cResetEvent rs(false,true);
cResetEvent re(false,true);
cResetEvent rs, re;
#endif
int max_idx,max_mvo,max_op,max_pt,max_tr,max_vtx,max_modt, ovrn;
@ -99,6 +98,7 @@ TA_context* _pvrrc;
void SetREP(TA_context* cntx);
void killtex();
bool render_output_framebuffer();
static void rend_create_renderer();
void dump_frame(const char* file, TA_context* ctx, u8* vram, u8* vram_ref = NULL) {
FILE* fw = fopen(file, "wb");
@ -267,6 +267,13 @@ bool rend_frame(TA_context* ctx, bool draw_osd) {
bool rend_single_frame()
{
if (renderer_changed)
{
renderer_changed = false;
rend_term_renderer();
rend_create_renderer();
rend_init_renderer();
}
//wait render start only if no frame pending
do
{
@ -363,6 +370,7 @@ void rend_init_renderer()
}
printf("Selected renderer initialization failed. Falling back to default renderer.\n");
renderer = fallback_renderer;
fallback_renderer = NULL; // avoid double-free
}
}
@ -378,7 +386,6 @@ void rend_term_renderer()
delete fallback_renderer;
fallback_renderer = NULL;
}
tactx_Term();
}
void* rend_thread(void* p)
@ -392,13 +399,6 @@ void* rend_thread(void* p)
{
if (rend_single_frame())
renderer->Present();
if (renderer_changed)
{
renderer_changed = false;
rend_term_renderer();
rend_create_renderer();
rend_init_renderer();
}
}
rend_term_renderer();
@ -539,6 +539,7 @@ void rend_end_render()
void rend_stop_renderer()
{
renderer_enabled = false;
tactx_Term();
}
void rend_vblank()

View File

@ -9,7 +9,7 @@ f32 vrf(u32 addr);
u32 vri(u32 addr);
//vram 32-64b
extern VArray2 vram;
extern VLockedMemory vram;
//read
u8 DYNACALL pvr_read_area1_8(u32 addr);
u16 DYNACALL pvr_read_area1_16(u32 addr);
@ -36,4 +36,4 @@ extern "C" void DYNACALL TAWriteSQ(u32 address,u8* sqb);
void YUV_init();
//registers
#define PVR_BASE 0x005F8000
#define PVR_BASE 0x005F8000

View File

@ -88,6 +88,8 @@ double full_rps;
static u32 lightgun_line = 0xffff;
static u32 lightgun_hpos;
double mspdf;
u32 fskip=0;
//called from sh4 context , should update pvr/ta state and everything else
int spg_line_sched(int tag, int cycl, int jit)
@ -174,7 +176,7 @@ int spg_line_sched(int tag, int cycl, int jit)
}
double frames_done=spd_cpu/2;
double mspdf=1/frames_done*1000;
mspdf=1/frames_done*1000;
full_rps=(spd_fps+fskip/ts);

View File

@ -124,7 +124,7 @@ void VDecEnd()
cMutex mtx_rqueue;
TA_context* rqueue;
cResetEvent frame_finished(false, true);
cResetEvent frame_finished;
double last_frame = 0;
u64 last_cyces = 0;

View File

@ -339,9 +339,9 @@ void bm_Rebuild()
rebuild_counter=30;
}
void bm_vmem_pagefill(void** ptr,u32 PAGE_SZ)
void bm_vmem_pagefill(void** ptr, u32 size_bytes)
{
for (size_t i=0; i<PAGE_SZ/sizeof(ptr[0]); i++)
for (size_t i=0; i < size_bytes / sizeof(ptr[0]); i++)
{
ptr[i]=(void*)ngen_FailedToFindBlock;
}

View File

@ -86,7 +86,7 @@ void bm_WriteBlockMap(const string& file);
DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr);
extern "C" {
__attribute__((used)) DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr);
ATTR_USED DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr);
}
RuntimeBlockInfo* bm_GetBlock(void* dynarec_code);

View File

@ -232,7 +232,7 @@ int AicaUpdate(int tag, int c, int j)
int DreamcastSecond(int tag, int c, int j)
{
settings.dreamcast.RTC++;
RealTimeClock++;
#if 1 //HOST_OS==OS_WINDOWS
prof_periodical();

View File

@ -314,7 +314,7 @@ struct Sh4RCB
Sh4Context cntx;
};
extern Sh4RCB* p_sh4rcb;
extern "C" Sh4RCB* p_sh4rcb;
extern u8* sh4_dyna_rcb;
INLINE u32 sh4_sr_GetFull()

View File

@ -61,6 +61,7 @@ void ExecuteDelayslot_RTE();
extern "C" {
int UpdateSystem();
__attribute__((used)) int UpdateSystem_INTC();
ATTR_USED int UpdateSystem_INTC();
}

View File

@ -17,7 +17,7 @@
//main system mem
VArray2 mem_b;
VLockedMemory mem_b;
void _vmem_init();
void _vmem_reset();

View File

@ -2,7 +2,7 @@
#include "types.h"
//main system mem
extern VArray2 mem_b;
extern VLockedMemory mem_b;
#include "hw/mem/_vmem.h"
#include "modules/mmu.h"

View File

@ -25,15 +25,15 @@ u64 sh4_sched_ffb;
u32 sh4_sched_intr;
vector<sched_list> list;
vector<sched_list> sch_list; // using list as external inside a macro confuses clang and msc
int sh4_sched_next_id=-1;
u32 sh4_sched_remaining(int id, u32 reference)
{
if (list[id].end != -1)
if (sch_list[id].end != -1)
{
return list[id].end - reference;
return sch_list[id].end - reference;
}
else
{
@ -51,7 +51,7 @@ void sh4_sched_ffts()
u32 diff=-1;
int slot=-1;
for (size_t i=0;i<list.size();i++)
for (size_t i=0;i<sch_list.size();i++)
{
if (sh4_sched_remaining(i)<diff)
{
@ -79,9 +79,9 @@ int sh4_sched_register(int tag, sh4_sched_callback* ssc)
{
sched_list t={ssc,tag,-1,-1};
list.push_back(t);
sch_list.push_back(t);
return list.size()-1;
return sch_list.size()-1;
}
/*
@ -103,16 +103,16 @@ void sh4_sched_request(int id, int cycles)
{
verify(cycles== -1 || (cycles >= 0 && cycles <= SH4_MAIN_CLOCK));
list[id].start=sh4_sched_now();
sch_list[id].start=sh4_sched_now();
if (cycles == -1) {
list[id].end = -1;
sch_list[id].end = -1;
}
else
{
list[id].end = list[id].start + cycles;
if (list[id].end == -1)
list[id].end++;
sch_list[id].end = sch_list[id].start + cycles;
if (sch_list[id].end == -1)
sch_list[id].end++;
}
sh4_sched_ffts();
@ -120,10 +120,10 @@ void sh4_sched_request(int id, int cycles)
int sh4_sched_elapsed(int id)
{
if (list[id].end!=-1)
if (sch_list[id].end!=-1)
{
int rv=sh4_sched_now()-list[id].start;
list[id].start=sh4_sched_now();
int rv=sh4_sched_now()-sch_list[id].start;
sch_list[id].start=sh4_sched_now();
return rv;
}
else
@ -132,12 +132,12 @@ int sh4_sched_elapsed(int id)
void handle_cb(int id)
{
int remain=list[id].end-list[id].start;
int remain=sch_list[id].end-sch_list[id].start;
int elapsd=sh4_sched_elapsed(id);
int jitter=elapsd-remain;
list[id].end=-1;
int re_sch=list[id].cb(list[id].tag,remain,jitter);
sch_list[id].end=-1;
int re_sch=sch_list[id].cb(sch_list[id].tag,remain,jitter);
if (re_sch > 0)
sh4_sched_request(id, max(0, re_sch - jitter));
@ -156,7 +156,7 @@ void sh4_sched_tick(int cycles)
sh4_sched_intr++;
if (sh4_sched_next_id!=-1)
{
for (int i=0;i<list.size();i++)
for (int i=0;i<sch_list.size();i++)
{
int remaining = sh4_sched_remaining(i, fztime);
verify(remaining >= 0 || remaining == -1);

View File

@ -4,7 +4,7 @@
#include "common.h"
#include <stddef.h>
#include <Windows.h>
#include <windows.h>
#include <ntddscsi.h>
#include "SCSIDEFS.H"
@ -388,4 +388,4 @@ Disc* ioctl_parse(const wchar* file)
}
}
#endif
#endif

View File

@ -51,7 +51,39 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
if (key < 0x10000)
{
if (pressed)
{
kcode[_maple_port] &= ~(u16)key;
// Avoid two opposite dpad keys being pressed simultaneously
switch (key)
{
case DC_DPAD_UP:
kcode[_maple_port] |= (u16)DC_DPAD_DOWN;
break;
case DC_DPAD_DOWN:
kcode[_maple_port] |= (u16)DC_DPAD_UP;
break;
case DC_DPAD_LEFT:
kcode[_maple_port] |= (u16)DC_DPAD_RIGHT;
break;
case DC_DPAD_RIGHT:
kcode[_maple_port] |= (u16)DC_DPAD_LEFT;
break;
case DC_DPAD2_UP:
kcode[_maple_port] |= (u16)DC_DPAD2_DOWN;
break;
case DC_DPAD2_DOWN:
kcode[_maple_port] |= (u16)DC_DPAD2_UP;
break;
case DC_DPAD2_LEFT:
kcode[_maple_port] |= (u16)DC_DPAD2_RIGHT;
break;
case DC_DPAD2_RIGHT:
kcode[_maple_port] |= (u16)DC_DPAD2_LEFT;
break;
default:
break;
}
}
else
kcode[_maple_port] |= (u16)key;
}

View File

@ -84,8 +84,6 @@ Atom wmDeleteMessage;
void* x11_vis;
extern bool dump_frame_switch;
extern bool naomi_test_button;
extern bool coin_chute;
void dc_exit(void);
@ -275,16 +273,6 @@ void input_x11_handle()
x11_fullscreen = !x11_fullscreen;
x11_window_set_fullscreen(x11_fullscreen);
}
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
else if (e.xkey.keycode == KEY_F8)
{
coin_chute = e.type == KeyPress;
}
else if (e.xkey.keycode == KEY_F7)
{
naomi_test_button = e.type == KeyPress;
}
#endif
}
}
break;
@ -373,6 +361,11 @@ void input_x11_init()
printf("X11 Keyboard input disabled by config.\n");
}
static int x11_error_handler(Display *, XErrorEvent *)
{
return 0;
}
void x11_window_create()
{
if (cfgLoadInt("pvr", "nox11", 0) == 0)
@ -531,20 +524,22 @@ void x11_window_create()
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
None
};
int (*old_handler)(Display *, XErrorEvent *) = XSetErrorHandler(&x11_error_handler);
x11_glc = glXCreateContextAttribsARB(x11Display, bestFbc, 0, True, context_attribs);
if (!x11_glc)
{
printf("Open GL 4.3 not supported\n");
// Try GL 3.1
// Try GL 3.0
context_attribs[1] = 3;
context_attribs[3] = 1;
context_attribs[3] = 0;
x11_glc = glXCreateContextAttribsARB(x11Display, bestFbc, 0, True, context_attribs);
if (!x11_glc)
{
die("Open GL 3.1 not supported\n");
die("Open GL 3.0 not supported\n");
}
}
XSetErrorHandler(old_handler);
XSync(x11Display, False);
#endif

View File

@ -23,10 +23,6 @@
#include <sys/personality.h>
#include <dlfcn.h>
#endif
#if HOST_OS == OS_DARWIN
#include <mach/clock.h>
#include <mach/mach.h>
#endif
#include <unistd.h>
#include "hw/sh4/dyna/blockmanager.h"
@ -57,7 +53,6 @@ void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx) {
}
#endif
#if !defined(TARGET_NO_EXCEPTIONS)
void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
{
rei_host_context_t ctx;
@ -108,12 +103,9 @@ void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
signal(SIGSEGV, SIG_DFL);
}
}
#endif
#endif
void install_fault_handler (void)
void install_fault_handler(void)
{
#if !defined(TARGET_NO_EXCEPTIONS)
struct sigaction act, segv_oact;
memset(&act, 0, sizeof(act));
act.sa_sigaction = fault_handler;
@ -127,180 +119,14 @@ void install_fault_handler (void)
act.sa_sigaction = sigill_handler;
sigaction(SIGILL, &act, &segv_oact);
#endif
#endif
}
#if !defined(TARGET_NO_THREADS)
//Thread class
cThread::cThread(ThreadEntryFP* function,void* prm)
{
Entry=function;
param=prm;
}
void cThread::Start()
{
verify(hThread == NULL);
if (pthread_create( (pthread_t*)&hThread, NULL, Entry, param))
{
die("Thread creation failed");
}
}
void cThread::WaitToEnd()
{
if (hThread != NULL)
{
pthread_join((pthread_t)hThread,0);
hThread = NULL;
}
}
//End thread class
#endif
//cResetEvent Calss
cResetEvent::cResetEvent(bool State,bool Auto)
{
//sem_init((sem_t*)hEvent, 0, State?1:0);
verify(State==false&&Auto==true);
pthread_mutex_init(&mutx, NULL);
pthread_cond_init(&cond, NULL);
}
cResetEvent::~cResetEvent()
{
//Destroy the event object ?
}
void cResetEvent::Set()//Signal
{
pthread_mutex_lock( &mutx );
state=true;
pthread_cond_signal( &cond);
pthread_mutex_unlock( &mutx );
}
void cResetEvent::Reset()//reset
{
pthread_mutex_lock( &mutx );
state=false;
pthread_mutex_unlock( &mutx );
}
bool cResetEvent::Wait(u32 msec)//Wait for signal , then reset
{
pthread_mutex_lock( &mutx );
if (!state)
{
struct timespec ts;
#if HOST_OS == OS_DARWIN
// OSX doesn't have clock_gettime.
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
#else
clock_gettime(CLOCK_REALTIME, &ts);
#endif
ts.tv_sec += msec / 1000;
ts.tv_nsec += (msec % 1000) * 1000000;
while (ts.tv_nsec > 1000000000)
{
ts.tv_nsec -= 1000000000;
ts.tv_sec++;
}
pthread_cond_timedwait( &cond, &mutx, &ts );
}
bool rc = state;
state=false;
pthread_mutex_unlock( &mutx );
return rc;
}
void cResetEvent::Wait()//Wait for signal , then reset
{
pthread_mutex_lock( &mutx );
if (!state)
{
pthread_cond_wait( &cond, &mutx );
}
state=false;
pthread_mutex_unlock( &mutx );
}
//End AutoResetEvent
#else // !defined(TARGET_NO_EXCEPTIONS)
// No exceptions/nvmem dummy handlers.
void install_fault_handler(void) {}
#endif // !defined(TARGET_NO_EXCEPTIONS)
#include <errno.h>
void VArray2::LockRegion(u32 offset,u32 size)
{
#if !defined(TARGET_NO_EXCEPTIONS)
u32 inpage=offset & PAGE_MASK;
u32 rv=mprotect (data+offset-inpage, size+inpage, PROT_READ );
if (rv!=0)
{
printf("mprotect(%8s,%08X,R) failed: %d | %d\n",data+offset-inpage,size+inpage,rv,errno);
die("mprotect failed ..\n");
}
#else
//printf("VA2: LockRegion\n");
#endif
}
void print_mem_addr()
{
FILE *ifp, *ofp;
char outputFilename[] = "/data/data/com.reicast.emulator/files/mem_alloc.txt";
ifp = fopen("/proc/self/maps", "r");
if (ifp == NULL) {
fprintf(stderr, "Can't open input file /proc/self/maps!\n");
exit(1);
}
ofp = fopen(outputFilename, "w");
if (ofp == NULL) {
fprintf(stderr, "Can't open output file %s!\n",
outputFilename);
#if HOST_OS == OS_LINUX
ofp = stderr;
#else
exit(1);
#endif
}
char line [ 512 ];
while (fgets(line, sizeof line, ifp) != NULL) {
fprintf(ofp, "%s", line);
}
fclose(ifp);
if (ofp != stderr)
fclose(ofp);
}
void VArray2::UnLockRegion(u32 offset,u32 size)
{
#if !defined(TARGET_NO_EXCEPTIONS)
u32 inpage=offset & PAGE_MASK;
u32 rv=mprotect (data+offset-inpage, size+inpage, PROT_READ | PROT_WRITE);
if (rv!=0)
{
print_mem_addr();
printf("mprotect(%8p,%08X,RW) failed: %d | %d\n",data+offset-inpage,size+inpage,rv,errno);
die("mprotect failed ..\n");
}
#else
//printf("VA2: UnLockRegion\n");
#endif
}
double os_GetSeconds()
{
timeval a;

178
core/linux/posix_vmem.cpp Normal file
View File

@ -0,0 +1,178 @@
// Implementation of the vmem related function for POSIX-like platforms.
// There's some minimal amount of platform specific hacks to support
// Android and OSX since they are slightly different in some areas.
// This implements the VLockedMemory interface, as defined in _vmem.h
// The implementation allows it to be empty (that is, to not lock memory).
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include "hw/mem/_vmem.h"
#include "stdclass.h"
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0 //missing from linux :/ -- could be the cause of android slowness ?
#endif
#ifdef _ANDROID
#include <linux/ashmem.h>
#ifndef ASHMEM_DEVICE
#define ASHMEM_DEVICE "/dev/ashmem"
#undef PAGE_MASK
#define PAGE_MASK (PAGE_SIZE-1)
#else
#define PAGE_SIZE 4096
#define PAGE_MASK (PAGE_SIZE-1)
#endif
// Android specific ashmem-device stuff for creating shared memory regions
int ashmem_create_region(const char *name, size_t size) {
int fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return -1;
if (ioctl(fd, ASHMEM_SET_SIZE, size) < 0) {
close(fd);
return -1;
}
return fd;
}
#endif // #ifdef _ANDROID
void VLockedMemory::LockRegion(unsigned offset, unsigned size_bytes) {
size_t inpage = offset & PAGE_MASK;
if (mprotect(&data[offset - inpage], size_bytes + inpage, PROT_READ)) {
die("mprotect failed ..\n");
}
}
void VLockedMemory::UnLockRegion(unsigned offset, unsigned size_bytes) {
size_t inpage = offset & PAGE_MASK;
if (mprotect(&data[offset - inpage], size_bytes + inpage, PROT_READ|PROT_WRITE)) {
// Add some way to see why it failed? gdb> info proc mappings
die("mprotect failed ..\n");
}
}
// Allocates memory via a fd on shmem/ahmem or even a file on disk
static int allocate_shared_filemem() {
int fd = -1;
#if defined(_ANDROID)
// Use Android's specific shmem stuff.
fd = ashmem_create_region(0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX);
#else
#if HOST_OS != OS_DARWIN
fd = shm_open("/dcnzorz_mem", O_CREAT | O_EXCL | O_RDWR,S_IREAD | S_IWRITE);
shm_unlink("/dcnzorz_mem");
#endif
// if shmem does not work (or using OSX) fallback to a regular file on disk
if (fd < 0) {
string path = get_writable_data_path("/dcnzorz_mem");
fd = open(path.c_str(), O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO);
unlink(path.c_str());
}
// If we can't open the file, fallback to slow mem.
if (fd < 0)
return -1;
// Finally make the file as big as we need!
if (ftruncate(fd, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX)) {
// Can't get as much memory as needed, fallback.
close(fd);
return -1;
}
#endif
return fd;
}
// Implement vmem initialization for RAM, ARAM, VRAM and SH4 context, fpcb etc.
// The function supports allocating 512MB or 4GB addr spaces.
static int shmem_fd = -1;
// vmem_base_addr points to an address space of 512MB (or 4GB) that can be used for fast memory ops.
// In negative offsets of the pointer (up to FPCB size, usually 65/129MB) the context and jump table
// can be found. If the platform init returns error, the user is responsible for initializing the
// memory using a fallback (that is, regular mallocs and falling back to slow memory JIT).
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr) {
// Firt let's try to allocate the shm-backed memory
shmem_fd = allocate_shared_filemem();
if (shmem_fd < 0)
return MemTypeError;
// Now try to allocate a contiguous piece of memory.
unsigned memsize = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX + 0x10000;
void *first_ptr = mmap(0, memsize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (!first_ptr) {
close(shmem_fd);
return MemTypeError;
}
// Align pointer to 64KB too, some Linaro bug (no idea but let's just be safe I guess).
uintptr_t ptrint = (uintptr_t)first_ptr;
ptrint = (ptrint + 0x10000 - 1) & (~0xffff);
*sh4rcb_addr = (void*)ptrint;
*vmem_base_addr = (void*)(ptrint + sizeof(Sh4RCB));
void *sh4rcb_base_ptr = (void*)(ptrint + FPCB_SIZE);
// Now map the memory for the SH4 context, do not include FPCB on purpose (paged on demand).
mprotect(sh4rcb_base_ptr, sizeof(Sh4RCB) - FPCB_SIZE, PROT_READ | PROT_WRITE);
return MemType512MB;
}
// Just tries to wipe as much as possible in the relevant area.
void vmem_platform_destroy() {
munmap(virt_ram_base, 0x20000000);
}
// Resets a chunk of memory by deleting its data and setting its protection back.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes) {
// Mark them as non accessible.
mprotect(ptr, size_bytes, PROT_NONE);
// Tell the kernel to flush'em all (FIXME: perhaps unmap+mmap 'd be better?)
madvise(ptr, size_bytes, MADV_DONTNEED);
#if defined(MADV_REMOVE)
madvise(ptr, size_bytes, MADV_REMOVE);
#elif defined(MADV_FREE)
madvise(ptr, size_bytes, MADV_FREE);
#endif
}
// Allocates a bunch of memory (page aligned and page-sized)
void vmem_platform_ondemand_page(void *address, unsigned size_bytes) {
verify(!mprotect(address, size_bytes, PROT_READ | PROT_WRITE));
}
// Creates mappings to the underlying file including mirroring sections
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps) {
for (unsigned i = 0; i < nummaps; i++) {
// Ignore unmapped stuff, it is already reserved as PROT_NONE
if (!vmem_maps[i].memsize)
continue;
// Calculate the number of mirrors
unsigned address_range_size = vmem_maps[i].end_address - vmem_maps[i].start_address;
unsigned num_mirrors = (address_range_size) / vmem_maps[i].memsize;
int protection = vmem_maps[i].allow_writes ? (PROT_READ | PROT_WRITE) : PROT_READ;
verify((address_range_size % vmem_maps[i].memsize) == 0 && num_mirrors >= 1);
for (unsigned j = 0; j < num_mirrors; j++) {
unsigned offset = vmem_maps[i].start_address + j * vmem_maps[i].memsize;
verify(!munmap(&virt_ram_base[offset], vmem_maps[i].memsize));
verify(MAP_FAILED != mmap(&virt_ram_base[offset], vmem_maps[i].memsize, protection,
MAP_SHARED | MAP_NOSYNC | MAP_FIXED, shmem_fd, vmem_maps[i].memoffset));
// ??? (mprotect(rv,size,prot)!=0)
}
}
}

View File

@ -134,7 +134,7 @@ void LoadSpecialSettings()
safemode_game = false;
tr_poly_depth_mask_game = false;
extra_depth_game = false;
if (reios_windows_ce)
{
printf("Enabling Extra depth scaling for Windows CE games\n");
@ -190,7 +190,7 @@ void LoadSpecialSettings()
}
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
printf("Game ID is [%s]\n", naomi_game_id);
if (!strcmp("METAL SLUG 6", naomi_game_id) || !strcmp("WAVE RUNNER GP", naomi_game_id))
{
printf("Enabling Dynarec safe mode for game %s\n", naomi_game_id);
@ -213,12 +213,14 @@ void LoadSpecialSettings()
printf("Enabling JVS rotary encoders for game %s\n", naomi_game_id);
settings.input.JammaSetup = 2;
}
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id))
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id) // Naomi
|| !strcmp("GUILTY GEAR isuka", naomi_game_id)) // AW
{
printf("Enabling 4-player setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 1;
}
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id))
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id)
|| !strcmp(naomi_game_id, "BASS FISHING SIMULATOR VER.A")) // AW
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 3;
@ -228,9 +230,11 @@ void LoadSpecialSettings()
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 4;
}
else if (!strcmp("NINJA ASSAULT", naomi_game_id))
else if (!strcmp("NINJA ASSAULT", naomi_game_id)
|| !strcmp(naomi_game_id, "Sports Shooting USA") // AW
|| !strcmp(naomi_game_id, "SEGA CLAY CHALLENGE")) // AW
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
printf("Enabling lightgun setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 5;
}
else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id))
@ -309,11 +313,12 @@ int dc_start_game(const char *path)
{
InitSettings();
LoadSettings(false);
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (!settings.bios.UseReios)
#endif
LoadRomFiles(get_readonly_data_path(DATA_PATH));
if (!LoadRomFiles(get_readonly_data_path(DATA_PATH)))
return -5;
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (path == NULL)
{
@ -345,7 +350,6 @@ int dc_start_game(const char *path)
return 0;
}
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
if (settings.bios.UseReios || !LoadRomFiles(get_readonly_data_path(DATA_PATH)))
{
#ifdef USE_REIOS
@ -485,7 +489,6 @@ void dc_exit()
void InitSettings()
{
settings.dreamcast.RTC = GetRTC_now();
settings.dynarec.Enable = true;
settings.dynarec.idleskip = true;
settings.dynarec.unstable_opt = false;
@ -499,6 +502,7 @@ void InitSettings()
settings.aica.LimitFPS = true;
settings.aica.NoBatch = false; // This also controls the DSP. Disabled by default
settings.aica.NoSound = false;
settings.audio.backend = "auto";
settings.rend.UseMipmaps = true;
settings.rend.WideScreen = false;
settings.rend.ShowFPS = false;
@ -513,6 +517,10 @@ void InitSettings()
settings.rend.CustomTextures = false;
settings.rend.DumpTextures = false;
settings.rend.ScreenScaling = 100;
settings.rend.ScreenStretching = 100;
settings.rend.Fog = true;
settings.rend.FloatVMUs = false;
settings.rend.Rotate90 = false;
settings.pvr.ta_skip = 0;
settings.pvr.rend = 0;
@ -559,6 +567,7 @@ void LoadSettings(bool game_specific)
{
const char *config_section = game_specific ? cfgGetGameId() : "config";
const char *input_section = game_specific ? cfgGetGameId() : "input";
const char *audio_section = game_specific ? cfgGetGameId() : "audio";
settings.dynarec.Enable = cfgLoadBool(config_section, "Dynarec.Enabled", settings.dynarec.Enable);
settings.dynarec.idleskip = cfgLoadBool(config_section, "Dynarec.idleskip", settings.dynarec.idleskip);
@ -574,6 +583,7 @@ void LoadSettings(bool game_specific)
settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS);
settings.aica.NoBatch = cfgLoadBool(config_section, "aica.NoBatch", settings.aica.NoBatch);
settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound);
settings.audio.backend = cfgLoadStr(audio_section, "backend", settings.audio.backend.c_str());
settings.rend.UseMipmaps = cfgLoadBool(config_section, "rend.UseMipmaps", settings.rend.UseMipmaps);
settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen);
settings.rend.ShowFPS = cfgLoadBool(config_section, "rend.ShowFPS", settings.rend.ShowFPS);
@ -595,6 +605,10 @@ void LoadSettings(bool game_specific)
settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures);
settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling);
settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100);
settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching);
settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog);
settings.rend.FloatVMUs = cfgLoadBool(config_section, "rend.FloatVMUs", settings.rend.FloatVMUs);
settings.rend.Rotate90 = cfgLoadBool(config_section, "rend.Rotate90", settings.rend.Rotate90);
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
settings.pvr.rend = cfgLoadInt(config_section, "pvr.rend", settings.pvr.rend);
@ -706,6 +720,27 @@ void SaveSettings()
cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS);
cfgSaveBool("config", "aica.NoBatch", settings.aica.NoBatch);
cfgSaveBool("config", "aica.NoSound", settings.aica.NoSound);
cfgSaveStr("audio", "backend", settings.audio.backend.c_str());
// Write backend specific settings
// std::map<std::string, std::map<std::string, std::string>>
for (std::map<std::string, std::map<std::string, std::string>>::iterator it = settings.audio.options.begin(); it != settings.audio.options.end(); ++it)
{
std::pair<std::string, std::map<std::string, std::string>> p = (std::pair<std::string, std::map<std::string, std::string>>)*it;
std::string section = p.first;
std::map<std::string, std::string> options = p.second;
for (std::map<std::string, std::string>::iterator it2 = options.begin(); it2 != options.end(); ++it2)
{
std::pair<std::string, std::string> p2 = (std::pair<std::string, std::string>)*it2;
std::string key = p2.first;
std::string val = p2.second;
cfgSaveStr(section.c_str(), key.c_str(), val.c_str());
}
}
cfgSaveBool("config", "rend.WideScreen", settings.rend.WideScreen);
cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS);
if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer)
@ -718,6 +753,10 @@ void SaveSettings()
cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures);
cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures);
cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling);
cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching);
cfgSaveBool("config", "rend.Fog", settings.rend.Fog);
cfgSaveBool("config", "rend.FloatVMUs", settings.rend.FloatVMUs);
cfgSaveBool("config", "rend.Rotate90", settings.rend.Rotate90);
cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip);
cfgSaveInt("config", "pvr.rend", settings.pvr.rend);

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_alsa.h"
#include "oslib/audiostream.h"
#if USE_ALSA
#include <alsa/asoundlib.h>
#include "cfg/cfg.h"
@ -18,30 +18,43 @@ static void alsa_init()
string device = cfgLoadStr("alsa", "device", "");
int rc = -1;
if (device == "")
if (device == "" || device == "auto")
{
printf("ALSA: trying to determine audio device\n");
/* Open PCM device for playback. */
// trying default device
device = "default";
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
// "default" didn't work, try first device
if (rc < 0)
{
device = "plughw:0,0,0";
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0)
{
device = "plughw:0,0";
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
}
}
// first didn't work, try second
if (rc < 0)
{
device = "plughw:0,0";
device = "plughw:1,0";
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
}
if (rc >= 0)
// try pulse audio backend
if (rc < 0)
{
// init successfull, write value back to config
cfgSaveStr("alsa", "device", device.c_str());
device = "pulse";
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
}
if (rc < 0)
printf("ALSA: unable to automatically determine audio device.\n");
}
else {
rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
@ -49,7 +62,7 @@ static void alsa_init()
if (rc < 0)
{
fprintf(stderr, "unable to open PCM device %s: %s\n", device.c_str(), snd_strerror(rc));
fprintf(stderr, "ALSA: unable to open PCM device %s: %s\n", device.c_str(), snd_strerror(rc));
return;
}
@ -62,7 +75,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_any(handle, params);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_any %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_any %s\n", snd_strerror(rc));
return;
}
@ -72,7 +85,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_access %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_access %s\n", snd_strerror(rc));
return;
}
@ -80,7 +93,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_format %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_format %s\n", snd_strerror(rc));
return;
}
@ -88,7 +101,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_channels(handle, params, 2);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_channels %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_channels %s\n", snd_strerror(rc));
return;
}
@ -97,7 +110,7 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_rate_near %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_rate_near %s\n", snd_strerror(rc));
return;
}
@ -106,26 +119,31 @@ static void alsa_init()
rc=snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, &dir);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
return;
}
else
{
printf("ALSA: period size set to %ld\n", period_size);
}
buffer_size = (44100 * 100 /* settings.omx.Audio_Latency */ / 1000 / period_size + 1) * period_size;
rc=snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
if (rc < 0)
{
fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
return;
}
else
{
printf("ALSA: buffer size set to %ld\n", buffer_size);
}
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0)
{
fprintf(stderr, "Unable to set hw parameters: %s\n", snd_strerror(rc));
fprintf(stderr, "ALSA: Unable to set hw parameters: %s\n", snd_strerror(rc));
return;
}
}
@ -175,11 +193,84 @@ static void alsa_term()
snd_pcm_close(handle);
}
audiobackend_t audiobackend_alsa = {
std::vector<std::string> alsa_get_devicelist()
{
std::vector<std::string> result;
char **hints;
int err = snd_device_name_hint(-1, "pcm", (void***)&hints);
// Error initializing ALSA
if (err != 0)
return result;
// special value to automatically detect on initialization
result.push_back("auto");
char** n = hints;
while (*n != NULL)
{
// Get the type (NULL/Input/Output)
char *type = snd_device_name_get_hint(*n, "IOID");
char *name = snd_device_name_get_hint(*n, "NAME");
if (name != NULL)
{
// We only want output or special devices (like "default" or "pulse")
// TODO Only those with type == NULL?
if (type == NULL || strcmp(type, "Output") == 0)
{
// TODO Check if device works (however we need to hash the resulting list then)
/*snd_pcm_t *handle;
int rc = snd_pcm_open(&handle, name, SND_PCM_STREAM_PLAYBACK, 0);
if (rc == 0)
{
result.push_back(name);
snd_pcm_close(handle);
}
*/
result.push_back(name);
}
}
if (type != NULL)
free(type);
if (name != NULL)
free(name);
n++;
}
snd_device_name_free_hint((void**)hints);
return result;
}
static audio_option_t* alsa_audio_options(int* option_count)
{
*option_count = 1;
static audio_option_t result[1];
result[0].cfg_name = "device";
result[0].caption = "Device";
result[0].type = list;
result[0].list_callback = alsa_get_devicelist;
return result;
}
static audiobackend_t audiobackend_alsa = {
"alsa", // Slug
"Advanced Linux Sound Architecture", // Name
&alsa_init,
&alsa_push,
&alsa_term
&alsa_term,
&alsa_audio_options
};
static bool alsa = RegisterAudioBackend(&audiobackend_alsa);
#endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_alsa;

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_android;

View File

@ -1,18 +1,18 @@
/*
Simple Core Audio backend for osx (and maybe ios?)
Based off various audio core samples and dolphin's code
This is part of the Reicast project, please consult the
LICENSE file for licensing & related information
This could do with some locking logic to avoid
race conditions, and some variable length buffer
logic to support chunk sizes other than 512 bytes
It does work on my macmini though
*/
#include "oslib/audiobackend_coreaudio.h"
#include "oslib/audiostream.h"
#if HOST_OS == OS_DARWIN
#include <atomic>
@ -28,7 +28,7 @@ static u8 samples_temp[BUFSIZE];
static std::atomic<int> samples_wptr;
static std::atomic<int> samples_rptr;
static cResetEvent bufferEmpty(false, true);
static cResetEvent bufferEmpty;
static OSStatus coreaudio_callback(void* ctx, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* ts,
UInt32 bus, UInt32 frames, AudioBufferList* abl)
@ -49,9 +49,9 @@ static OSStatus coreaudio_callback(void* ctx, AudioUnitRenderActionFlags* flags,
samples_rptr = (samples_rptr + buf_size) % BUFSIZE;
}
}
bufferEmpty.Set();
return noErr;
}
@ -63,7 +63,7 @@ static void coreaudio_init()
AudioStreamBasicDescription format;
AudioComponentDescription desc;
AudioComponent component;
desc.componentType = kAudioUnitType_Output;
#if !defined(TARGET_IPHONE)
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
@ -75,12 +75,12 @@ static void coreaudio_init()
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
component = AudioComponentFindNext(nullptr, &desc);
verify(component != nullptr);
err = AudioComponentInstanceNew(component, &audioUnit);
verify(err == noErr);
FillOutASBDForLPCM(format, 44100,
2, 16, 16, false, false, false);
err = AudioUnitSetProperty(audioUnit,
@ -88,7 +88,7 @@ static void coreaudio_init()
kAudioUnitScope_Input, 0, &format,
sizeof(AudioStreamBasicDescription));
verify(err == noErr);
callback_struct.inputProc = coreaudio_callback;
callback_struct.inputProcRefCon = 0;
err = AudioUnitSetProperty(audioUnit,
@ -96,24 +96,24 @@ static void coreaudio_init()
kAudioUnitScope_Input, 0, &callback_struct,
sizeof callback_struct);
verify(err == noErr);
/*
err = AudioUnitSetParameter(audioUnit,
kHALOutputParam_Volume,
kAudioUnitParameterFlag_Output, 0,
1, 0);
verify(err == noErr);
*/
err = AudioUnitInitialize(audioUnit);
verify(err == noErr);
err = AudioOutputUnitStart(audioUnit);
verify(err == noErr);
bufferEmpty.Set();
}
@ -134,23 +134,23 @@ static u32 coreaudio_push(void* frame, u32 samples, bool wait)
samples_wptr = (samples_wptr + byte_size) % BUFSIZE;
break;
}
return 1;
}
static void coreaudio_term()
{
OSStatus err;
err = AudioOutputUnitStop(audioUnit);
verify(err == noErr);
err = AudioUnitUninitialize(audioUnit);
verify(err == noErr);
err = AudioComponentInstanceDispose(audioUnit);
verify(err == noErr);
bufferEmpty.Set();
}
@ -159,6 +159,10 @@ audiobackend_t audiobackend_coreaudio = {
"Core Audio", // Name
&coreaudio_init,
&coreaudio_push,
&coreaudio_term
&coreaudio_term,
NULL
};
static bool core = RegisterAudioBackend(&audiobackend_coreaudio);
#endif

View File

@ -1,5 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_coreaudio;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_directsound.h"
#include "oslib/audiostream.h"
#if HOST_OS==OS_WINDOWS
#include "oslib.h"
#include <initguid.h>
@ -19,31 +19,31 @@ static void directsound_init()
verifyc(dsound->SetCooperativeLevel((HWND)libPvr_GetRenderTarget(),DSSCL_PRIORITY));
IDirectSoundBuffer* buffer_;
WAVEFORMATEX wfx;
DSBUFFERDESC desc;
WAVEFORMATEX wfx;
DSBUFFERDESC desc;
// Set up WAV format structure.
// Set up WAV format structure.
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 44100;
wfx.nBlockAlign = 4;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.wBitsPerSample = 16;
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 44100;
wfx.nBlockAlign = 4;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.wBitsPerSample = 16;
// Set up DSBUFFERDESC structure.
// Set up DSBUFFERDESC structure.
ds_ring_size=8192*wfx.nBlockAlign;
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
desc.dwBufferBytes = ds_ring_size;
desc.lpwfxFormat = &wfx;
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
desc.dwBufferBytes = ds_ring_size;
desc.lpwfxFormat = &wfx;
if (settings.aica.HW_mixing==0)
{
@ -71,7 +71,7 @@ static void directsound_init()
//Play the buffer !
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
}
@ -159,7 +159,7 @@ static u32 directsound_push(void* frame, u32 samples, bool wait)
wait &= w;
*/
int ffs=1;
/*
while (directsound_IsAudioBufferedLots() && wait)
if (ffs == 0)
@ -175,7 +175,7 @@ static u32 directsound_push(void* frame, u32 samples, bool wait)
static void directsound_term()
{
buffer->Stop();
buffer->Release();
dsound->Release();
}
@ -185,6 +185,9 @@ audiobackend_t audiobackend_directsound = {
"Microsoft DirectSound", // Name
&directsound_init,
&directsound_push,
&directsound_term
&directsound_term,
NULL
};
static bool ds = RegisterAudioBackend(&audiobackend_directsound);
#endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_directsound;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_libao.h"
#include "oslib/audiostream.h"
#ifdef USE_LIBAO
#include <ao/ao.h>
@ -10,12 +10,12 @@ static void libao_init()
{
ao_initialize();
memset(&aoformat, 0, sizeof(aoformat));
aoformat.bits = 16;
aoformat.channels = 2;
aoformat.rate = 44100;
aoformat.byte_format = AO_FMT_LITTLE;
aodevice = ao_open_live(ao_default_driver_id(), &aoformat, NULL); // Live output
if (!aodevice)
aodevice = ao_open_live(ao_driver_id("null"), &aoformat, NULL);
@ -23,13 +23,13 @@ static void libao_init()
static u32 libao_push(void* frame, u32 samples, bool wait)
{
if (aodevice)
if (aodevice)
ao_play(aodevice, (char*)frame, samples * 4);
return 1;
}
static void libao_term()
static void libao_term()
{
if (aodevice)
{
@ -43,7 +43,9 @@ audiobackend_t audiobackend_libao = {
"libao", // Name
&libao_init,
&libao_push,
&libao_term
&libao_term,
NULL
};
static bool ao = RegisterAudioBackend(&audiobackend_libao);
#endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_libao;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_omx.h"
#include "oslib/audiostream.h"
#if USE_OMX
#include <IL/OMX_Broadcom.h>
@ -313,7 +313,9 @@ audiobackend_t audiobackend_omx = {
"OpenMAX IL", // Name
&omx_init,
&omx_push,
&omx_term
&omx_term,
NULL
};
static bool omx = RegisterAudioBackend(&audiobackend_omx);
#endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_omx;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_oss.h"
#include "oslib/audiostream.h"
#ifdef USE_OSS
#include <sys/ioctl.h>
#include <sys/fcntl.h>
@ -48,7 +48,9 @@ audiobackend_t audiobackend_oss = {
"Open Sound System", // Name
&oss_init,
&oss_push,
&oss_term
&oss_term,
NULL
};
static bool oss = RegisterAudioBackend(&audiobackend_oss);
#endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_oss;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_pulseaudio.h"
#include "oslib/audiostream.h"
#ifdef USE_PULSEAUDIO
#include <sys/ioctl.h>
#include <sys/fcntl.h>
@ -43,6 +43,9 @@ audiobackend_t audiobackend_pulseaudio = {
"PulseAudio", // Name
&pulseaudio_init,
&pulseaudio_push,
&pulseaudio_term
&pulseaudio_term,
NULL
};
static bool pulse = RegisterAudioBackend(&audiobackend_pulseaudio);
#endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_pulseaudio;

View File

@ -0,0 +1,136 @@
#if defined(USE_SDL_AUDIO)
#include <SDL2/SDL.h>
#include "oslib/audiostream.h"
#include "stdclass.h"
static SDL_AudioDeviceID audiodev;
static bool needs_resampling;
static cResetEvent read_wait;
static cMutex stream_mutex;
static struct {
uint32_t prevs;
uint32_t sample_buffer[2048];
} audiobuf;
static unsigned sample_count = 0;
// To easily access samples.
union Sample { int16_t s[2]; uint32_t l; };
static float InterpolateCatmull4pt3oX(float x0, float x1, float x2, float x3, float t) {
return 0.45 * ((2 * x1) + t * ((-x0 + x2) + t * ((2 * x0 - 5 * x1 + 4 * x2 - x3) + t * (-x0 + 3 * x1 - 3 * x2 + x3))));
}
static void sdl2_audiocb(void* userdata, Uint8* stream, int len) {
stream_mutex.Lock();
// Wait until there's enough samples to feed the kraken
unsigned oslen = len / sizeof(uint32_t);
unsigned islen = needs_resampling ? oslen * 16 / 17 : oslen;
unsigned minlen = needs_resampling ? islen + 2 : islen; // Resampler looks ahead by 2 samples.
if (sample_count < minlen) {
// No data, just output a bit of silence for the underrun
memset(stream, 0, len);
stream_mutex.Unlock();
read_wait.Set();
return;
}
if (!needs_resampling) {
// Just copy bytes for this case.
memcpy(stream, &audiobuf.sample_buffer[0], len);
}
else {
// 44.1KHz to 48KHz (actually 46.86KHz) resampling
uint32_t *outbuf = (uint32_t*)stream;
const float ra = 1.0f / 17;
Sample *sbuf = (Sample*)&audiobuf.sample_buffer[0]; // [-1] stores the previous iteration last sample output
for (int i = 0; i < islen/16; i++) {
*outbuf++ = sbuf[i*16+ 0].l; // First sample stays at the same location.
for (int k = 1; k < 17; k++) {
Sample r;
// Note we access offset -1 on first iteration, as to access prevs
r.s[0] = InterpolateCatmull4pt3oX(sbuf[i*16+k-2].s[0], sbuf[i*16+k-1].s[0], sbuf[i*16+k].s[0], sbuf[i*16+k+1].s[0], 1 - ra*k);
r.s[1] = InterpolateCatmull4pt3oX(sbuf[i*16+k-2].s[1], sbuf[i*16+k-1].s[1], sbuf[i*16+k].s[1], sbuf[i*16+k+1].s[1], 1 - ra*k);
*outbuf++ = r.l;
}
}
audiobuf.prevs = audiobuf.sample_buffer[islen-1];
}
// Move samples in the buffer and consume them
memmove(&audiobuf.sample_buffer[0], &audiobuf.sample_buffer[islen], (sample_count-islen)*sizeof(uint32_t));
sample_count -= islen;
stream_mutex.Unlock();
read_wait.Set();
}
static void sdl2_audio_init() {
if (!SDL_WasInit(SDL_INIT_AUDIO))
SDL_InitSubSystem(SDL_INIT_AUDIO);
// Support 44.1KHz (native) but also upsampling to 48KHz
SDL_AudioSpec wav_spec, out_spec;
memset(&wav_spec, 0, sizeof(wav_spec));
wav_spec.freq = 44100;
wav_spec.format = AUDIO_S16;
wav_spec.channels = 2;
wav_spec.samples = 1024; // Must be power of two
wav_spec.callback = sdl2_audiocb;
// Try 44.1KHz which should be faster since it's native.
audiodev = SDL_OpenAudioDevice(NULL, 0, &wav_spec, &out_spec, 0);
if (!audiodev) {
needs_resampling = true;
wav_spec.freq = 48000;
audiodev = SDL_OpenAudioDevice(NULL, 0, &wav_spec, &out_spec, 0);
verify(audiodev);
}
}
static u32 sdl2_audio_push(void* frame, u32 samples, bool wait) {
// Unpause the device shall it be paused.
if (SDL_GetAudioDeviceStatus(audiodev) != SDL_AUDIO_PLAYING)
SDL_PauseAudioDevice(audiodev, 0);
// If wait, then wait for the buffer to be smaller than a certain size.
stream_mutex.Lock();
if (wait) {
while (sample_count + samples > sizeof(audiobuf.sample_buffer)/sizeof(audiobuf.sample_buffer[0])) {
stream_mutex.Unlock();
read_wait.Wait();
read_wait.Reset();
stream_mutex.Lock();
}
}
// Copy as many samples as possible, drop any remaining (this should not happen usually)
unsigned free_samples = sizeof(audiobuf.sample_buffer) / sizeof(audiobuf.sample_buffer[0]) - sample_count;
unsigned tocopy = samples < free_samples ? samples : free_samples;
memcpy(&audiobuf.sample_buffer[sample_count], frame, tocopy * sizeof(uint32_t));
sample_count += tocopy;
stream_mutex.Unlock();
return 1;
}
static void sdl2_audio_term() {
// Stop audio playback.
SDL_PauseAudioDevice(audiodev, 1);
read_wait.Set();
}
audiobackend_t audiobackend_sdl2audio = {
"sdl2", // Slug
"Simple DirectMedia Layer 2 Audio", // Name
&sdl2_audio_init,
&sdl2_audio_push,
&sdl2_audio_term
};
static bool sdl2audiobe = RegisterAudioBackend(&audiobackend_sdl2audio);
#endif

View File

@ -2,14 +2,6 @@
#include "cfg/cfg.h"
#include "oslib/oslib.h"
#include "audiostream.h"
#include "oslib/audiobackend_directsound.h"
#include "oslib/audiobackend_android.h"
#include "oslib/audiobackend_alsa.h"
#include "oslib/audiobackend_oss.h"
#include "oslib/audiobackend_pulseaudio.h"
#include "oslib/audiobackend_coreaudio.h"
#include "oslib/audiobackend_omx.h"
#include "oslib/audiobackend_libao.h"
struct SoundFrame { s16 l;s16 r; };
#define SAMPLE_COUNT 512
@ -25,16 +17,27 @@ u32 gen_samples=0;
double time_diff = 128/44100.0;
double time_last;
#ifdef LOG_SOUND
// TODO Only works on Windows!
WaveWriter rawout("d:\\aica_out.wav");
#endif
static bool audiobackends_registered = false;
static unsigned int audiobackends_num_max = 1;
static unsigned int audiobackends_num_registered = 0;
static audiobackend_t **audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
static audiobackend_t **audiobackends = NULL;
static audiobackend_t *audiobackend_current = NULL;
u32 GetAudioBackendCount()
{
return audiobackends_num_registered;
}
audiobackend_t* GetAudioBackend(int num)
{
return audiobackends[num];
}
bool RegisterAudioBackend(audiobackend_t *backend)
{
/* This function announces the availability of an audio backend to reicast. */
@ -44,10 +47,16 @@ bool RegisterAudioBackend(audiobackend_t *backend)
printf("ERROR: Tried to register invalid audio backend (NULL pointer).\n");
return false;
}
if (backend->slug == "auto" || backend->slug == "none") {
printf("ERROR: Tried to register invalid audio backend (slug \"%s\" is a reserved keyword).\n", backend->slug.c_str());
return false;
}
// First call to RegisterAudioBackend(), create the backend structure;
if (audiobackends == NULL)
audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
// Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
if (audiobackends_num_registered == audiobackends_num_max)
{
@ -67,46 +76,19 @@ bool RegisterAudioBackend(audiobackend_t *backend)
}
audiobackends = new_ptr;
}
audiobackends[audiobackends_num_registered] = backend;
audiobackends_num_registered++;
return true;
}
void RegisterAllAudioBackends() {
#if HOST_OS==OS_WINDOWS
RegisterAudioBackend(&audiobackend_directsound);
#endif
#if ANDROID
RegisterAudioBackend(&audiobackend_android);
#endif
#if USE_OMX
RegisterAudioBackend(&audiobackend_omx);
#endif
#if USE_ALSA
RegisterAudioBackend(&audiobackend_alsa);
#endif
#if USE_OSS
RegisterAudioBackend(&audiobackend_oss);
#endif
#if USE_PULSEAUDIO
RegisterAudioBackend(&audiobackend_pulseaudio);
#endif
#if USE_LIBAO
RegisterAudioBackend(&audiobackend_libao);
#endif
#if HOST_OS == OS_DARWIN
RegisterAudioBackend(&audiobackend_coreaudio);
#endif
audiobackends_registered = true;
}
static audiobackend_t* GetAudioBackend(std::string slug)
audiobackend_t* GetAudioBackend(std::string slug)
{
if (slug == "none")
{
printf("WARNING: Audio backend set to \"none\"!\n");
}
else if(audiobackends_num_registered > 0)
else if (audiobackends_num_registered > 0)
{
if (slug == "auto")
{
@ -135,7 +117,8 @@ static audiobackend_t* GetAudioBackend(std::string slug)
return NULL;
}
u32 PushAudio(void* frame, u32 amt, bool wait) {
u32 PushAudio(void* frame, u32 amt, bool wait)
{
if (audiobackend_current != NULL) {
return audiobackend_current->push(frame, amt, wait);
}
@ -151,11 +134,13 @@ u32 asRingUsedCount()
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
//return sz<0?sz+RingBufferSampleCount:sz;
}
u32 asRingFreeCount()
{
return RingBufferSampleCount-asRingUsedCount();
}
extern double mspdf;
void WriteSample(s16 r, s16 l)
{
const u32 ptr=(WritePtr+1)%RingBufferSampleCount;
@ -165,7 +150,30 @@ void WriteSample(s16 r, s16 l)
if (WritePtr==(SAMPLE_COUNT-1))
{
PushAudio(RingBuffer,SAMPLE_COUNT,settings.aica.LimitFPS);
bool do_wait = settings.aica.LimitFPS && (mspdf <= 11);
PushAudio(RingBuffer,SAMPLE_COUNT, do_wait);
}
}
static bool backends_sorted = false;
void SortAudioBackends()
{
if (backends_sorted)
return;
// Sort backends by slug
for (int n = audiobackends_num_registered; n > 0; n--)
{
for (int i = 0; i < n-1; i++)
{
if (audiobackends[i]->slug > audiobackends[i+1]->slug)
{
audiobackend_t* swap = audiobackends[i];
audiobackends[i] = audiobackends[i+1];
audiobackends[i+1] = swap;
}
}
}
}
@ -176,26 +184,24 @@ void InitAudio()
return;
}
cfgSaveInt("audio","disable",0);
if (!audiobackends_registered) {
//FIXME: There might some nicer way to do this.
RegisterAllAudioBackends();
}
cfgSaveInt("audio", "disable", 0);
if (audiobackend_current != NULL) {
printf("ERROR: The audio backend \"%s\" (%s) has already been initialized, you need to terminate it before you can call audio_init() again!\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
return;
}
string audiobackend_slug = cfgLoadStr("audio", "backend", "auto"); // FIXME: This could be made a parameter
SortAudioBackends();
string audiobackend_slug = settings.audio.backend;
audiobackend_current = GetAudioBackend(audiobackend_slug);
if (audiobackend_current == NULL) {
printf("WARNING: Running without audio!\n");
return;
}
printf("Initializing audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
audiobackend_current->init();
audiobackend_current->init();
}
void TermAudio()
@ -204,5 +210,5 @@ void TermAudio()
audiobackend_current->term();
printf("Terminating audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
audiobackend_current = NULL;
}
}
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "types.h"
#include <tuple>
//Get used size in the ring buffer
u32 asRingUsedCount();
@ -10,6 +11,29 @@ u32 asRingFreeCount();
bool asRingRead(u8* dst,u32 count=0);
void UpdateBuff(u8* pos);
typedef std::vector<std::string> (*audio_option_callback_t)();
enum audio_option_type
{
integer = 0
, checkbox = 1
, list = 2
};
typedef struct {
std::string cfg_name;
std::string caption;
audio_option_type type;
// type int_value (spin edit)
int min_value;
int max_value;
// type list edit (string/char*)
audio_option_callback_t list_callback;
} audio_option_t;
typedef audio_option_t* (*audio_options_func_t)(int* option_count);
typedef void (*audio_backend_init_func_t)();
typedef u32 (*audio_backend_push_func_t)(void*, u32, bool);
typedef void (*audio_backend_term_func_t)();
@ -19,8 +43,14 @@ typedef struct {
audio_backend_init_func_t init;
audio_backend_push_func_t push;
audio_backend_term_func_t term;
audio_options_func_t get_options;
} audiobackend_t;
extern bool RegisterAudioBackend(audiobackend_t* backend);
extern void InitAudio();
extern u32 PushAudio(void* frame, u32 amt, bool wait);
extern void TermAudio();
u32 GetAudioBackendCount();
void SortAudioBackends();
audiobackend_t* GetAudioBackend(int num);
audiobackend_t* GetAudioBackend(std::string slug);

View File

@ -1420,9 +1420,12 @@ private:
std::vector<const VRegister*> call_fregs;
Arm64RegAlloc regalloc;
RuntimeBlockInfo* block;
const int write_memory_rewrite_size = 3; // same size (fast write) for any size: add, bfc, str
#ifdef EXPLODE_SPANS
const int read_memory_rewrite_size = 6; // worst case for u64: add, bfc, ldr, fmov, lsr, fmov
// FIXME rewrite size per read/write size?
const int write_memory_rewrite_size = 3;
#else
const int read_memory_rewrite_size = 4; // worst case for u64: add, bfc, ldr, str
#endif
};
static Arm64Assembler* compiler;

61
core/rec-x64/msvc.asm Normal file
View File

@ -0,0 +1,61 @@
_TEXT SEGMENT
SH4_TIMESLICE = 448
CPU_RUNNING = 135266148
PC = 135266120
EXTERN bm_GetCode2: PROC
EXTERN UpdateSystem_INTC: PROC
EXTERN cycle_counter: dword
EXTERN p_sh4rcb: qword
PUBLIC ngen_mainloop
ngen_mainloop PROC
push rbx
push rbp
push rdi
push rsi
push r12
push r13
push r14
push r15
sub rsp, 40 ; 32-byte shadow space + 8 for stack 16-byte alignment
mov dword ptr [cycle_counter], SH4_TIMESLICE
run_loop:
mov rax, qword ptr [p_sh4rcb]
mov edx, dword ptr[CPU_RUNNING + rax]
test edx, edx
je end_run_loop
slice_loop:
mov rax, qword ptr [p_sh4rcb]
mov ecx, dword ptr[PC + rax]
call bm_GetCode2
call rax
mov ecx, dword ptr [cycle_counter]
test ecx, ecx
jg slice_loop
add ecx, SH4_TIMESLICE
mov dword ptr [cycle_counter], ecx
call UpdateSystem_INTC
jmp run_loop
end_run_loop:
add rsp, 40
pop r15
pop r14
pop r13
pop r12
pop rsi
pop rdi
pop rbp
pop rbx
ret
ngen_mainloop ENDP
_TEXT ENDS
END

View File

@ -32,7 +32,9 @@ struct DynaRBI : RuntimeBlockInfo
}
};
int cycle_counter;
extern "C" {
int cycle_counter;
}
double host_cpu_time;
u64 guest_cpu_cycles;
@ -76,6 +78,8 @@ static __attribute((used)) void end_slice()
#error RAM_SIZE_MAX unknown
#endif
#ifndef _MSC_VER
#ifdef _WIN32
// Fully naked function in win32 for proper SEH prologue
__asm__ (
@ -177,6 +181,7 @@ WIN32_ONLY( ".seh_pushreg %r14 \n\t")
}
#endif
#endif // !_MSC_VER
#undef _U
#undef _S

View File

@ -326,8 +326,8 @@ void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset,
if (prof.enable)
{
if (force_checks)
x86e->Emit(op_add32,&prof.counters.blkrun.force_check,1);
//if (force_checks)
// x86e->Emit(op_add32,&prof.counters.blkrun.force_check,1);
x86e->Emit(op_add32,&prof.counters.blkrun.cycles[block->guest_cycles],1);
}

View File

@ -124,8 +124,7 @@ void palette_update()
using namespace std;
vector<vram_block*> VramLocks[VRAM_SIZE/PAGE_SIZE];
//vram 32-64b
VArray2 vram;
VLockedMemory vram; // vram 32-64b
//List functions
//
@ -207,7 +206,7 @@ vram_block* libCore_vramlock_Lock(u32 start_offset64,u32 end_offset64,void* user
{
vramlist_lock.Lock();
vram.LockRegion(block->start,block->len);
vram.LockRegion(block->start, block->len);
//TODO: Fix this for 32M wrap as well
if (_nvmem_enabled() && VRAM_SIZE == 0x800000) {

View File

@ -1,6 +1,6 @@
#include <d3d11.h>
#include "hw\pvr\Renderer_if.h"
#include "oslib\oslib.h"
#include "hw/pvr/Renderer_if.h"
#include "oslib/oslib.h"
#pragma comment(lib,"d3d11.lib")
@ -102,4 +102,4 @@ struct d3d11 : Renderer
Renderer* rend_D3D11()
{
return new d3d11();
}
}

View File

@ -331,23 +331,23 @@ void initABuffer()
{
char source[16384];
sprintf(source, final_shader_source, 1);
gl4CompilePipelineShader(&g_abuffer_final_shader, source);
gl4CompilePipelineShader(&g_abuffer_final_shader, false, source);
}
if (g_abuffer_final_nosort_shader.program == 0)
{
char source[16384];
sprintf(source, final_shader_source, 0);
gl4CompilePipelineShader(&g_abuffer_final_nosort_shader, source);
gl4CompilePipelineShader(&g_abuffer_final_nosort_shader, false, source);
}
if (g_abuffer_clear_shader.program == 0)
gl4CompilePipelineShader(&g_abuffer_clear_shader, clear_shader_source);
gl4CompilePipelineShader(&g_abuffer_clear_shader, false, clear_shader_source);
if (g_abuffer_tr_modvol_shaders[0].program == 0)
{
char source[16384];
for (int mode = 0; mode < ModeCount; mode++)
{
sprintf(source, tr_modvol_shader_source, mode);
gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], source);
gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], false, source);
}
}
@ -417,6 +417,17 @@ void termABuffer()
glDeleteBuffers(1, &g_quadBuffer);
g_quadBuffer = 0;
}
glcache.DeleteProgram(g_abuffer_final_shader.program);
g_abuffer_final_shader.program = 0;
glcache.DeleteProgram(g_abuffer_final_nosort_shader.program);
g_abuffer_final_nosort_shader.program = 0;
glcache.DeleteProgram(g_abuffer_clear_shader.program);
g_abuffer_clear_shader.program = 0;
for (int mode = 0; mode < ModeCount; mode++)
{
glcache.DeleteProgram(g_abuffer_tr_modvol_shaders[mode].program);
g_abuffer_tr_modvol_shaders[mode].program = 0;
}
}
void reshapeABuffer(int w, int h)

View File

@ -1,6 +1,6 @@
#pragma once
#include "rend/gles/gles.h"
#include <map>
#include <unordered_map>
void gl4DrawStrips(GLuint output_fbo);
@ -44,7 +44,8 @@ struct gl4_ctx
GLuint extra_depth_scale;
} modvol_shader;
std::map<int, gl4PipelineShader *> shaders;
std::unordered_map<u32, gl4PipelineShader> shaders;
bool rotate90;
struct
{
@ -53,16 +54,6 @@ struct gl4_ctx
GLuint modvol_vao;
GLuint tr_poly_params;
} vbo;
gl4PipelineShader *getShader(int programId) {
gl4PipelineShader *shader = shaders[programId];
if (shader == NULL) {
shader = new gl4PipelineShader();
shaders[programId] = shader;
shader->program = -1;
}
return shader;
}
};
extern gl4_ctx gl4;
@ -76,7 +67,8 @@ bool gl4_render_output_framebuffer();
void abufferDrawQuad(bool upsideDown = false, float x = 0.f, float y = 0.f, float w = 0.f, float h = 0.f);
extern const char *gl4PixelPipelineShader;
bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *source = gl4PixelPipelineShader);
bool gl4CompilePipelineShader(gl4PipelineShader* s, bool rotate_90, const char *source = gl4PixelPipelineShader);
void gl4_delete_shaders();
extern GLuint stencilTexId;
extern GLuint depthTexId;

View File

@ -45,10 +45,15 @@ static GLuint texSamplers[2];
static GLuint depth_fbo;
GLuint depthSaveTexId;
static int gl4GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
static gl4PipelineShader *gl4GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass)
{
if (settings.rend.Rotate90 != gl4.rotate90)
{
gl4_delete_shaders();
gl4.rotate90 = settings.rend.Rotate90;
}
u32 rv=0;
rv|=pp_ClipTestMode;
@ -66,45 +71,27 @@ static int gl4GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
rv <<= 1; rv |= fog_clamping;
rv <<= 2; rv |= pass;
return rv;
}
static void setCurrentShader(u32 cp_AlphaTest, u32 pp_ClipTestMode,
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass)
{
int shaderId = gl4GetProgramID(cp_AlphaTest,
pp_ClipTestMode + 1,
pp_Texture,
pp_UseAlpha,
pp_IgnoreTexA,
pp_ShadInstr,
pp_Offset,
pp_FogCtrl,
pp_TwoVolumes,
pp_DepthFunc,
pp_Gouraud,
pp_BumpMap,
fog_clamping,
pass);
CurrentShader = gl4.getShader(shaderId);
if (CurrentShader->program == -1) {
CurrentShader->cp_AlphaTest = cp_AlphaTest;
CurrentShader->pp_ClipTestMode = pp_ClipTestMode;
CurrentShader->pp_Texture = pp_Texture;
CurrentShader->pp_UseAlpha = pp_UseAlpha;
CurrentShader->pp_IgnoreTexA = pp_IgnoreTexA;
CurrentShader->pp_ShadInstr = pp_ShadInstr;
CurrentShader->pp_Offset = pp_Offset;
CurrentShader->pp_FogCtrl = pp_FogCtrl;
CurrentShader->pp_TwoVolumes = pp_TwoVolumes;
CurrentShader->pp_DepthFunc = pp_DepthFunc;
CurrentShader->pp_Gouraud = pp_Gouraud;
CurrentShader->pp_BumpMap = pp_BumpMap;
CurrentShader->fog_clamping = fog_clamping;
CurrentShader->pass = pass;
gl4CompilePipelineShader(CurrentShader);
gl4PipelineShader *shader = &gl4.shaders[rv];
if (shader->program == 0)
{
shader->cp_AlphaTest = cp_AlphaTest;
shader->pp_ClipTestMode = pp_ClipTestMode;
shader->pp_Texture = pp_Texture;
shader->pp_UseAlpha = pp_UseAlpha;
shader->pp_IgnoreTexA = pp_IgnoreTexA;
shader->pp_ShadInstr = pp_ShadInstr;
shader->pp_Offset = pp_Offset;
shader->pp_FogCtrl = pp_FogCtrl;
shader->pp_TwoVolumes = pp_TwoVolumes;
shader->pp_DepthFunc = pp_DepthFunc;
shader->pp_Gouraud = pp_Gouraud;
shader->pp_BumpMap = pp_BumpMap;
shader->fog_clamping = fog_clamping;
shader->pass = pass;
gl4CompilePipelineShader(shader, settings.rend.Rotate90);
}
return shader;
}
static void SetTextureRepeatMode(int index, GLuint dir, u32 clamp, u32 mirror)
@ -132,7 +119,7 @@ template <u32 Type, bool SortingEnabled>
if (pass == 0)
{
setCurrentShader(Type == ListType_Punch_Through ? 1 : 0,
CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
clipping,
Type == ListType_Punch_Through ? gp->pcw.Texture : 0,
1,
@ -153,6 +140,8 @@ template <u32 Type, bool SortingEnabled>
bool two_volumes_mode = (gp->tsp1.full != -1) && Type != ListType_Translucent;
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
int fog_ctrl = settings.rend.Fog ? gp->tsp.FogCtrl : 2;
int depth_func = 0;
if (Type == ListType_Translucent)
{
@ -162,14 +151,14 @@ template <u32 Type, bool SortingEnabled>
depth_func = gp->isp.DepthMode;
}
setCurrentShader(Type == ListType_Punch_Through ? 1 : 0,
CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
clipping,
gp->pcw.Texture,
gp->tsp.UseAlpha,
gp->tsp.IgnoreTexA,
gp->tsp.ShadInstr,
gp->pcw.Offset,
gp->tsp.FogCtrl,
fog_ctrl,
two_volumes_mode,
depth_func,
gp->pcw.Gouraud,
@ -681,7 +670,7 @@ static void gl4_draw_quad_texture(GLuint texture, bool upsideDown, float x = 0.f
ShaderUniforms.trilinear_alpha = 1.0;
setCurrentShader(0,
CurrentShader = gl4GetProgram(0,
0,
1,
0,
@ -713,11 +702,15 @@ void gl4DrawFramebuffer(float w, float h)
bool gl4_render_output_framebuffer()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0)
glcache.Disable(GL_SCISSOR_TEST);
if (gl.ofbo.fbo == 0)
return false;
gl4_draw_quad_texture(gl.ofbo.tex, true);
glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height,
0, 0, screen_width, screen_height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return true;
}

View File

@ -14,6 +14,7 @@ static const char* VertexShaderSource =
"\
#version 140 \n\
#define pp_Gouraud %d \n\
#define ROTATE_90 %d \n\
\n\
#if pp_Gouraud == 0 \n\
#define INTERPOLATION flat \n\
@ -56,6 +57,9 @@ void main() \n\
\n\
vpos.w = extra_depth_scale / vpos.z; \n\
vpos.z = vpos.w; \n\
#if ROTATE_90 == 1 \n\
vpos.xy = vec2(vpos.y, -vpos.x); \n\
#endif \n\
vpos.xy=vpos.xy*scale.xy-scale.zw; \n\
vpos.xy*=vpos.w; \n\
gl_Position = vpos; \n\
@ -393,11 +397,11 @@ gl4_ctx gl4;
struct gl4ShaderUniforms_t gl4ShaderUniforms;
bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *source /* = PixelPipelineShader */)
bool gl4CompilePipelineShader( gl4PipelineShader* s, bool rotate_90, const char *source /* = PixelPipelineShader */)
{
char vshader[16384];
sprintf(vshader, VertexShaderSource, s->pp_Gouraud);
sprintf(vshader, VertexShaderSource, s->pp_Gouraud, rotate_90);
char pshader[16384];
@ -478,28 +482,45 @@ bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *source /* = Pix
void gl_term();
void gl4_delete_shaders()
{
for (auto it : gl4.shaders)
{
if (it.second.program != 0)
glcache.DeleteProgram(it.second.program);
}
gl4.shaders.clear();
glcache.DeleteProgram(gl4.modvol_shader.program);
gl4.modvol_shader.program = 0;
}
static void gles_term(void)
{
glDeleteProgram(gl4.modvol_shader.program);
glDeleteBuffers(1, &gl4.vbo.geometry);
gl4.vbo.geometry = 0;
glDeleteBuffers(1, &gl4.vbo.modvols);
glDeleteBuffers(1, &gl4.vbo.idxs);
glDeleteBuffers(1, &gl4.vbo.idxs2);
glDeleteBuffers(1, &gl4.vbo.tr_poly_params);
for (auto it = gl4.shaders.begin(); it != gl4.shaders.end(); it++)
{
if (it->second->program != -1)
glDeleteProgram(it->second->program);
delete it->second;
}
gl4.shaders.clear();
gl4_delete_shaders();
glDeleteVertexArrays(1, &gl4.vbo.main_vao);
glDeleteVertexArrays(1, &gl4.vbo.modvol_vao);
gl_term();
}
static void create_modvol_shader()
{
if (gl4.modvol_shader.program != 0)
return;
char vshader[16384];
sprintf(vshader, VertexShaderSource, 1, settings.rend.Rotate90);
gl4.modvol_shader.program=gl_CompileAndLink(vshader, ModifierVolumeShader);
gl4.modvol_shader.scale = glGetUniformLocation(gl4.modvol_shader.program, "scale");
gl4.modvol_shader.extra_depth_scale = glGetUniformLocation(gl4.modvol_shader.program, "extra_depth_scale");
}
static bool gl_create_resources()
{
if (gl4.vbo.geometry != 0)
@ -521,12 +542,7 @@ static bool gl_create_resources()
gl4SetupMainVBO();
gl4SetupModvolVBO();
char vshader[16384];
sprintf(vshader, VertexShaderSource, 1);
gl4.modvol_shader.program=gl_CompileAndLink(vshader, ModifierVolumeShader);
gl4.modvol_shader.scale = glGetUniformLocation(gl4.modvol_shader.program, "scale");
gl4.modvol_shader.extra_depth_scale = glGetUniformLocation(gl4.modvol_shader.program, "extra_depth_scale");
create_modvol_shader();
gl_load_osd_resources();
@ -604,6 +620,7 @@ static bool RenderFrame()
old_screen_scaling = settings.rend.ScreenScaling;
}
DoCleanup();
create_modvol_shader();
bool is_rtt=pvrrc.isRTT;
@ -639,6 +656,8 @@ static bool RenderFrame()
{
scale_x=fb_scale_x;
scale_y=fb_scale_y;
if (SCALER_CTL.interlace == 0 && SCALER_CTL.vscalefactor >= 0x400)
scale_y *= SCALER_CTL.vscalefactor / 0x400;
//work out scaling parameters !
//Pixel doubling is on VO, so it does not affect any pixel operations
@ -662,16 +681,41 @@ static bool RenderFrame()
/*
Handle Dc to screen scaling
*/
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f;
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0);
dc2s_scale_h *= screen_scaling;
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
float screen_scaling = settings.rend.ScreenScaling / 100.f;
float screen_stretching = settings.rend.ScreenStretching / 100.f;
//-1 -> too much to left
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x);
gl4ShaderUniforms.scale_coefs[1] = (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling);
gl4ShaderUniforms.scale_coefs[3] = (is_rtt ? 1 : -1);
float dc2s_scale_h;
float ds2s_offs_x;
if (is_rtt)
{
gl4ShaderUniforms.scale_coefs[0] = 2.0f / dc_width;
gl4ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
gl4ShaderUniforms.scale_coefs[2] = 1;
gl4ShaderUniforms.scale_coefs[3] = 1;
}
else
{
if (settings.rend.Rotate90)
{
dc2s_scale_h = screen_height / 640.0;
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2;
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
gl4ShaderUniforms.scale_coefs[1] = -2.0f / dc_width;
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
gl4ShaderUniforms.scale_coefs[3] = 1;
}
else
{
dc2s_scale_h = screen_height / 480.0;
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2;
//-1 -> too much to left
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
gl4ShaderUniforms.scale_coefs[1] = -2.0f / dc_height;
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
gl4ShaderUniforms.scale_coefs[3] = -1;
}
}
gl4ShaderUniforms.extra_depth_scale = settings.rend.ExtraDepthScale;
@ -704,7 +748,7 @@ static bool RenderFrame()
gl4ShaderUniforms.fog_clamp_max[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f;
gl4ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 0xFF) / 255.0f;
if (fog_needs_update)
if (fog_needs_update && settings.rend.Fog)
{
fog_needs_update = false;
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE5, GL_RED);
@ -764,7 +808,7 @@ static bool RenderFrame()
{
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
{
output_fbo = init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
output_fbo = init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f);
}
else
{
@ -826,22 +870,37 @@ static bool RenderFrame()
float min_y = pvrrc.fb_Y_CLIP.min / scale_y;
if (!is_rtt)
{
if (SCALER_CTL.interlace && SCALER_CTL.vscalefactor >= 0x400)
{
// Clipping is done after scaling/filtering so account for that if enabled
height *= SCALER_CTL.vscalefactor / 0x400;
min_y *= SCALER_CTL.vscalefactor / 0x400;
}
if (settings.rend.Rotate90)
{
float t = width;
width = height;
height = t;
t = min_x;
min_x = min_y;
min_y = 640 - t - height;
}
// Add x offset for aspect ratio > 4/3
min_x = min_x * dc2s_scale_h + ds2s_offs_x;
min_x = (min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x) * screen_scaling;
// Invert y coordinates when rendering to screen
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h;
width *= dc2s_scale_h;
height *= dc2s_scale_h;
min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
width *= dc2s_scale_h * screen_stretching * screen_scaling;
height *= dc2s_scale_h * screen_scaling;
if (ds2s_offs_x > 0)
{
float rounded_offs_x = ds2s_offs_x + 0.5f;
float scaled_offs_x = ds2s_offs_x * screen_scaling;
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
glcache.Enable(GL_SCISSOR_TEST);
glScissor(0, 0, rounded_offs_x, screen_height);
glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height);
glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
}
}

View File

@ -1,5 +1,5 @@
#include "gl4.h"
#include "glcache.h"
#include "../gles/glcache.h"
GLuint gl4BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt)
{

View File

@ -22,7 +22,11 @@
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _MSC_VER
#include "dirent/dirent.h"
#else
#include <dirent.h>
#endif
#include "deps/libpng/png.h"
#include "reios/reios.h"
@ -46,23 +50,28 @@ void CustomTexture::LoaderThread()
if (texture != NULL)
{
// FIXME texture may have been deleted. Need to detect this.
texture->ComputeHash();
int width, height;
u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height);
if (image_data == NULL)
if (texture->custom_image_data != NULL)
{
image_data = LoadCustomTexture(texture->old_texture_hash, width, height);
delete [] texture->custom_image_data;
texture->custom_image_data = NULL;
}
if (image_data != NULL)
if (!texture->dirty)
{
if (texture->custom_image_data != NULL)
delete [] texture->custom_image_data;
texture->custom_width = width;
texture->custom_height = height;
texture->custom_image_data = image_data;
int width, height;
u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height);
if (image_data == NULL)
{
image_data = LoadCustomTexture(texture->old_texture_hash, width, height);
}
if (image_data != NULL)
{
texture->custom_width = width;
texture->custom_height = height;
texture->custom_image_data = image_data;
}
}
texture->custom_load_in_progress = false;
texture->custom_load_in_progress--;
}
} while (texture != NULL);
@ -140,10 +149,9 @@ u8* CustomTexture::LoadCustomTexture(u32 hash, int& width, int& height)
void CustomTexture::LoadCustomTextureAsync(TextureCacheData *texture_data)
{
if (!Init())
{
texture_data->custom_load_in_progress = false;
return;
}
texture_data->custom_load_in_progress++;
work_queue_mutex.Lock();
work_queue.insert(work_queue.begin(), texture_data);
work_queue_mutex.Unlock();

View File

@ -29,9 +29,9 @@ public:
CustomTexture()
:
#ifndef TARGET_NO_THREADS
loader_thread(loader_thread_func, this),
loader_thread(loader_thread_func, this)
#endif
wakeup_thread(false, true) {}
{}
~CustomTexture() { Terminate(); }
u8* LoadCustomTexture(u32 hash, int& width, int& height);
void LoadCustomTextureAsync(TextureCacheData *texture_data);
@ -53,7 +53,7 @@ private:
cThread loader_thread;
#endif
cResetEvent wakeup_thread;
std::vector<struct TextureCacheData *> work_queue;
std::vector<TextureCacheData *> work_queue;
cMutex work_queue_mutex;
};

View File

@ -149,6 +149,19 @@ public:
return _texture_ids[--_texture_cache_size];
}
void DeleteProgram(GLuint program)
{
GLsizei shader_count;
GLuint shaders[2];
glGetAttachedShaders(program, ARRAY_SIZE(shaders), &shader_count, shaders);
for (int i = 0; i < shader_count; i++)
glDeleteShader(shaders[i]);
glDeleteProgram(program);
if (_program == program)
_program = 0;
}
void Reset() {
_texture = 0xFFFFFFFFu;
_src_blend_factor = 0xFFFFFFFFu;
@ -179,7 +192,7 @@ public:
void DisableCache() { _disable_cache = true; }
void EnableCache()
{
_disable_cache = true;
_disable_cache = false;
Reset();
}

View File

@ -114,13 +114,30 @@ s32 SetTileClip(u32 val, GLint uniform)
csy /= scale_y;
cex /= scale_x;
cey /= scale_y;
float t = cey;
cey = 480 - csy;
csy = 480 - t;
float dc2s_scale_h = screen_height / 480.0f;
float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2;
csx = csx * dc2s_scale_h + ds2s_offs_x;
cex = cex * dc2s_scale_h + ds2s_offs_x;
float dc2s_scale_h;
float ds2s_offs_x;
float screen_stretching = settings.rend.ScreenStretching / 100.f;
if (settings.rend.Rotate90)
{
float t = cex;
cex = cey;
cey = 640 - csx;
csx = csy;
csy = 640 - t;
dc2s_scale_h = screen_height / 640.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2;
}
else
{
float t = cey;
cey = 480 - csy;
csy = 480 - t;
dc2s_scale_h = screen_height / 480.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2;
}
csx = csx * dc2s_scale_h * screen_stretching + ds2s_offs_x;
cex = cex * dc2s_scale_h * screen_stretching + ds2s_offs_x;
csy = csy * dc2s_scale_h;
cey = cey * dc2s_scale_h;
}
@ -173,28 +190,25 @@ __forceinline
ShaderUniforms.trilinear_alpha = 1.f;
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
int fog_ctrl = settings.rend.Fog ? gp->tsp.FogCtrl : 2;
CurrentShader = &gl.pogram_table[
GetProgramID(Type == ListType_Punch_Through ? 1 : 0,
SetTileClip(gp->tileclip, -1) + 1,
gp->pcw.Texture,
gp->tsp.UseAlpha,
gp->tsp.IgnoreTexA,
gp->tsp.ShadInstr,
gp->pcw.Offset,
gp->tsp.FogCtrl,
gp->pcw.Gouraud,
gp->tcw.PixelFmt == PixelBumpMap,
color_clamp,
ShaderUniforms.trilinear_alpha != 1.f)];
CurrentShader = GetProgram(Type == ListType_Punch_Through ? 1 : 0,
SetTileClip(gp->tileclip, -1) + 1,
gp->pcw.Texture,
gp->tsp.UseAlpha,
gp->tsp.IgnoreTexA,
gp->tsp.ShadInstr,
gp->pcw.Offset,
fog_ctrl,
gp->pcw.Gouraud,
gp->tcw.PixelFmt == PixelBumpMap,
color_clamp,
ShaderUniforms.trilinear_alpha != 1.f);
if (CurrentShader->program == -1)
CompilePipelineShader(CurrentShader);
else
{
glcache.UseProgram(CurrentShader->program);
ShaderUniforms.Set(CurrentShader);
}
glcache.UseProgram(CurrentShader->program);
if (CurrentShader->trilinear_alpha != -1)
glUniform1f(CurrentShader->trilinear_alpha, ShaderUniforms.trilinear_alpha);
SetTileClip(gp->tileclip, CurrentShader->pp_ClipTest);
//This bit control which pixels are affected
@ -1124,14 +1138,8 @@ static void DrawQuad(GLuint texId, float x, float y, float w, float h, float u0,
ShaderUniforms.trilinear_alpha = 1.0;
PipelineShader *shader = &gl.pogram_table[GetProgramID(0, 1, 1, 0, 1, 0, 0, 2, false, false, false, false)];
if (shader->program == -1)
CompilePipelineShader(shader);
else
{
glcache.UseProgram(shader->program);
ShaderUniforms.Set(shader);
}
PipelineShader *shader = GetProgram(0, 1, 1, 0, 1, 0, 0, 2, false, false, false, false);
glcache.UseProgram(shader->program);
glActiveTexture(GL_TEXTURE0);
glcache.BindTexture(GL_TEXTURE_2D, texId);
@ -1152,17 +1160,27 @@ void DrawFramebuffer(float w, float h)
bool render_output_framebuffer()
{
#if HOST_OS != OS_DARWIN
//Fix this in a proper way
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif
glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0)
return false;
float scl = 480.f / screen_height;
float tx = (screen_width * scl - 640.f) / 2;
DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0);
glcache.Disable(GL_SCISSOR_TEST);
if (gl.gl_major < 3)
{
glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0)
return false;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
float scl = 480.f / screen_height;
float tx = (screen_width * scl - 640.f) / 2;
DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0);
}
else
{
if (gl.ofbo.fbo == 0)
return false;
glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height,
0, 0, screen_width, screen_height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
return true;
}

View File

@ -79,6 +79,7 @@ const char* VertexShaderSource =
%s \n\
#define TARGET_GL %s \n\
#define pp_Gouraud %d \n\
#define ROTATE_90 %d \n\
\n\
#define GLES2 0 \n\
#define GLES3 1 \n\
@ -136,6 +137,9 @@ void main() \n\
vpos.z = vpos.w; \n\
#else \n\
vpos.z=depth_scale.x+depth_scale.y*vpos.w; \n\
#endif \n\
#if ROTATE_90 == 1 \n\
vpos.xy = vec2(vpos.y, -vpos.x); \n\
#endif \n\
vpos.xy=vpos.xy*scale.xy-scale.zw; \n\
vpos.xy*=vpos.w; \n\
@ -782,7 +786,7 @@ GLuint fogTextureId;
return rv;
}
#include <Wingdi.h>
#include <wingdi.h>
void gl_swap()
{
wglSwapLayerBuffers(ourWindowHandleToDeviceContext,WGL_SWAP_MAIN_PLANE);
@ -853,9 +857,20 @@ GLuint fogTextureId;
extern void gl_term();
#endif
static void gl_delete_shaders()
{
for (auto it : gl.shaders)
{
if (it.second.program != 0)
glcache.DeleteProgram(it.second.program);
}
gl.shaders.clear();
glcache.DeleteProgram(gl.modvol_shader.program);
gl.modvol_shader.program = 0;
}
static void gles_term()
{
glDeleteProgram(gl.modvol_shader.program);
glDeleteBuffers(1, &gl.vbo.geometry);
gl.vbo.geometry = 0;
glDeleteBuffers(1, &gl.vbo.modvols);
@ -868,7 +883,7 @@ static void gles_term()
gl_free_osd_resources();
free_output_framebuffer();
memset(gl.pogram_table, 0, sizeof(gl.pogram_table));
gl_delete_shaders();
gl_term();
}
@ -1017,10 +1032,15 @@ GLuint gl_CompileAndLink(const char* VertexShader, const char* FragmentShader)
return program;
}
int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
PipelineShader *GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear)
{
if (settings.rend.Rotate90 != gl.rotate90)
{
gl_delete_shaders();
gl.rotate90 = settings.rend.Rotate90;
}
u32 rv=0;
rv|=pp_ClipTestMode;
@ -1036,14 +1056,32 @@ int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
rv<<=1; rv|=fog_clamping;
rv<<=1; rv|=trilinear;
return rv;
PipelineShader *shader = &gl.shaders[rv];
if (shader->program == 0)
{
shader->cp_AlphaTest = cp_AlphaTest;
shader->pp_ClipTestMode = pp_ClipTestMode-1;
shader->pp_Texture = pp_Texture;
shader->pp_UseAlpha = pp_UseAlpha;
shader->pp_IgnoreTexA = pp_IgnoreTexA;
shader->pp_ShadInstr = pp_ShadInstr;
shader->pp_Offset = pp_Offset;
shader->pp_FogCtrl = pp_FogCtrl;
shader->pp_Gouraud = pp_Gouraud;
shader->pp_BumpMap = pp_BumpMap;
shader->fog_clamping = fog_clamping;
shader->trilinear = trilinear;
CompilePipelineShader(shader);
}
return shader;
}
bool CompilePipelineShader( PipelineShader* s)
{
char vshader[8192];
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud);
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud, settings.rend.Rotate90);
char pshader[8192];
@ -1129,13 +1167,30 @@ void gl_load_osd_resources()
void gl_free_osd_resources()
{
glDeleteProgram(gl.OSD_SHADER.program);
glcache.DeleteProgram(gl.OSD_SHADER.program);
if (osd_tex != 0) {
glcache.DeleteTextures(1, &osd_tex);
osd_tex = 0;
}
}
static void create_modvol_shader()
{
if (gl.modvol_shader.program != 0)
return;
char vshader[8192];
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1, settings.rend.Rotate90);
char fshader[8192];
sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version);
gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader);
gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale");
gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor");
gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale");
gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale");
}
bool gl_create_resources()
{
if (gl.vbo.geometry != 0)
@ -1161,84 +1216,7 @@ bool gl_create_resources()
glGenBuffers(1, &gl.vbo.idxs);
glGenBuffers(1, &gl.vbo.idxs2);
memset(gl.pogram_table,0,sizeof(gl.pogram_table));
PipelineShader* dshader=0;
u32 compile=0;
#define forl(name,max) for(u32 name=0;name<=max;name++)
forl(cp_AlphaTest,1)
{
forl(pp_ClipTestMode,2)
{
forl(pp_UseAlpha,1)
{
forl(pp_Texture,1)
{
forl(pp_FogCtrl,3)
{
forl(pp_IgnoreTexA,1)
{
forl(pp_ShadInstr,3)
{
forl(pp_Offset,1)
{
forl(pp_Gouraud,1)
{
forl(pp_BumpMap,1)
{
forl(fog_clamping,1)
{
forl(trilinear,1)
{
dshader=&gl.pogram_table[GetProgramID(cp_AlphaTest,pp_ClipTestMode,pp_Texture,pp_UseAlpha,pp_IgnoreTexA,
pp_ShadInstr,pp_Offset,pp_FogCtrl, (bool)pp_Gouraud, (bool)pp_BumpMap, (bool)fog_clamping,
(bool)trilinear)];
dshader->cp_AlphaTest = cp_AlphaTest;
dshader->pp_ClipTestMode = pp_ClipTestMode-1;
dshader->pp_Texture = pp_Texture;
dshader->pp_UseAlpha = pp_UseAlpha;
dshader->pp_IgnoreTexA = pp_IgnoreTexA;
dshader->pp_ShadInstr = pp_ShadInstr;
dshader->pp_Offset = pp_Offset;
dshader->pp_FogCtrl = pp_FogCtrl;
dshader->pp_Gouraud = pp_Gouraud;
dshader->pp_BumpMap = pp_BumpMap;
dshader->fog_clamping = fog_clamping;
dshader->trilinear = trilinear;
dshader->program = -1;
}
}
}
}
}
}
}
}
}
}
}
}
char vshader[8192];
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1);
char fshader[8192];
sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version);
gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader);
gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale");
gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor");
gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale");
gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale");
//#define PRECOMPILE_SHADERS
#ifdef PRECOMPILE_SHADERS
for (u32 i=0;i<sizeof(gl.pogram_table)/sizeof(gl.pogram_table[0]);i++)
{
if (!CompilePipelineShader( &gl.pogram_table[i] ))
return false;
}
#endif
create_modvol_shader();
gl_load_osd_resources();
@ -1558,6 +1536,7 @@ static void upload_vertex_indices()
bool RenderFrame()
{
DoCleanup();
create_modvol_shader();
bool is_rtt=pvrrc.isRTT;
@ -1677,6 +1656,8 @@ bool RenderFrame()
{
scale_x=fb_scale_x;
scale_y=fb_scale_y;
if (SCALER_CTL.interlace == 0 && SCALER_CTL.vscalefactor >= 0x400)
scale_y *= SCALER_CTL.vscalefactor / 0x400;
//work out scaling parameters !
//Pixel doubling is on VO, so it does not affect any pixel operations
@ -1724,17 +1705,41 @@ bool RenderFrame()
/*
Handle Dc to screen scaling
*/
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f;
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0);
dc2s_scale_h *= screen_scaling;
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
float screen_stretching = settings.rend.ScreenStretching / 100.f;
float screen_scaling = settings.rend.ScreenScaling / 100.f;
//-1 -> too much to left
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x);
ShaderUniforms.scale_coefs[1]= (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling);
ShaderUniforms.scale_coefs[3]= (is_rtt ? 1 : -1);
float dc2s_scale_h;
float ds2s_offs_x;
if (is_rtt)
{
ShaderUniforms.scale_coefs[0] = 2.0f / dc_width;
ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
ShaderUniforms.scale_coefs[2] = 1;
ShaderUniforms.scale_coefs[3] = 1;
}
else
{
if (settings.rend.Rotate90)
{
dc2s_scale_h = screen_height / 640.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2;
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
ShaderUniforms.scale_coefs[1] = -2.0f / dc_width;
ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
ShaderUniforms.scale_coefs[3] = 1;
}
else
{
dc2s_scale_h = screen_height / 480.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2;
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
ShaderUniforms.scale_coefs[1] = -2.0f / dc_height;
ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
ShaderUniforms.scale_coefs[3] = -1;
}
//-1 -> too much to left
}
ShaderUniforms.depth_coefs[0]=2/(vtx_max_fZ-vtx_min_fZ);
ShaderUniforms.depth_coefs[1]=-vtx_min_fZ-1;
@ -1773,7 +1778,7 @@ bool RenderFrame()
ShaderUniforms.fog_clamp_max[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f;
ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 0xFF) / 255.0f;
if (fog_needs_update)
if (fog_needs_update && settings.rend.Fog)
{
fog_needs_update = false;
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE1, gl.fog_image_format);
@ -1787,16 +1792,12 @@ bool RenderFrame()
ShaderUniforms.PT_ALPHA=(PT_ALPHA_REF&0xFF)/255.0f;
// for (u32 i=0;i<sizeof(gl.pogram_table)/sizeof(gl.pogram_table[0]);i++)
// {
// PipelineShader* s=&gl.pogram_table[i];
// if (s->program == -1)
// continue;
//
// glcache.UseProgram(s->program);
//
// ShaderUniforms.Set(s);
// }
for (auto it : gl.shaders)
{
glcache.UseProgram(it.second.program);
ShaderUniforms.Set(&it.second);
}
//setup render target first
if (is_rtt)
{
@ -1841,7 +1842,7 @@ bool RenderFrame()
{
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
{
init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f);
}
else
{
@ -1888,9 +1889,6 @@ bool RenderFrame()
glBufferData(GL_ARRAY_BUFFER,pvrrc.modtrig.bytes(),pvrrc.modtrig.head(),GL_STREAM_DRAW); glCheck();
}
int offs_x=ds2s_offs_x+0.5f;
//this needs to be scaled
//not all scaling affects pixel operations, scale to adjust for that
scale_x *= scissoring_scale_x;
@ -1909,22 +1907,37 @@ bool RenderFrame()
float min_y = pvrrc.fb_Y_CLIP.min / scale_y;
if (!is_rtt)
{
if (SCALER_CTL.interlace && SCALER_CTL.vscalefactor >= 0x400)
{
// Clipping is done after scaling/filtering so account for that if enabled
height *= SCALER_CTL.vscalefactor / 0x400;
min_y *= SCALER_CTL.vscalefactor / 0x400;
}
if (settings.rend.Rotate90)
{
float t = width;
width = height;
height = t;
t = min_x;
min_x = min_y;
min_y = 640 - t - height;
}
// Add x offset for aspect ratio > 4/3
min_x = min_x * dc2s_scale_h + ds2s_offs_x;
min_x = (min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x) * screen_scaling;
// Invert y coordinates when rendering to screen
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h;
width *= dc2s_scale_h;
height *= dc2s_scale_h;
min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
width *= dc2s_scale_h * screen_stretching * screen_scaling;
height *= dc2s_scale_h * screen_scaling;
if (ds2s_offs_x > 0)
{
float rounded_offs_x = ds2s_offs_x + 0.5f;
float scaled_offs_x = ds2s_offs_x * screen_scaling;
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
glcache.Enable(GL_SCISSOR_TEST);
glScissor(0, 0, rounded_offs_x, screen_height);
glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height);
glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
}
}

View File

@ -1,4 +1,6 @@
#pragma once
#include <unordered_map>
#include <atomic>
#include "rend/rend.h"
#if (defined(GLES) && !defined(TARGET_NACL32) && HOST_OS != OS_DARWIN && !defined(USE_SDL)) || defined(_ANDROID)
@ -95,7 +97,9 @@ struct gl_ctx
} modvol_shader;
PipelineShader pogram_table[24576];
std::unordered_map<u32, PipelineShader> shaders;
bool rotate90;
struct
{
GLuint program;
@ -119,6 +123,7 @@ struct gl_ctx
struct
{
GLuint depthb;
GLuint colorb;
GLuint tex;
GLuint fbo;
int width;
@ -178,7 +183,7 @@ void free_output_framebuffer();
void HideOSD();
void OSD_DRAW(bool clear_screen);
int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
PipelineShader *GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear);
@ -225,9 +230,6 @@ extern struct ShaderUniforms_t
if (s->sp_FOG_COL_VERT!=-1)
glUniform3fv( s->sp_FOG_COL_VERT, 1, ps_FOG_COL_VERT);
if (s->trilinear_alpha != -1)
glUniform1f(s->trilinear_alpha, trilinear_alpha);
if (s->fog_clamp_min != -1)
glUniform4fv(s->fog_clamp_min, 1, fog_clamp_min);
if (s->fog_clamp_max != -1)
@ -274,10 +276,10 @@ struct TextureCacheData
//a texture can't be both VQ and PAL at the same time
u32 texture_hash; // xxhash of texture data, used for custom textures
u32 old_texture_hash; // legacy hash
u8* custom_image_data; // loaded custom image data
u32 custom_width;
u32 custom_height;
bool custom_load_in_progress;
u8* volatile custom_image_data; // loaded custom image data
volatile u32 custom_width;
volatile u32 custom_height;
std::atomic_int custom_load_in_progress;
void PrintTextureName();

View File

@ -296,10 +296,7 @@ void TextureCacheData::Update()
}
}
if (settings.rend.CustomTextures)
{
custom_load_in_progress = true;
custom_texture.LoadCustomTextureAsync(this);
}
void *temp_tex_buffer = NULL;
u32 upscaled_w = w;
@ -428,7 +425,7 @@ void TextureCacheData::UploadToGPU(GLuint textype, int width, int height, u8 *te
void TextureCacheData::CheckCustomTexture()
{
if (custom_image_data != NULL)
if (custom_load_in_progress == 0 && custom_image_data != NULL)
{
UploadToGPU(GL_UNSIGNED_BYTE, custom_width, custom_height, custom_image_data);
delete [] custom_image_data;
@ -446,7 +443,7 @@ bool TextureCacheData::NeedsUpdate() {
bool TextureCacheData::Delete()
{
if (custom_load_in_progress)
if (custom_load_in_progress > 0)
return false;
if (pData) {
@ -736,11 +733,7 @@ TextureCacheData *getTextureCacheData(TSP tsp, TCW tcw) {
}
else //create if not existing
{
TextureCacheData tfc={0};
TexCache[key] = tfc;
tx=TexCache.find(key);
tf=&tx->second;
tf=&TexCache[key];
tf->tsp = tsp;
tf->tcw = tcw;
@ -800,11 +793,7 @@ text_info raw_GetTexture(TSP tsp, TCW tcw)
}
else //create if not existing
{
TextureCacheData tfc = { 0 };
TexCache[key] = tfc;
tx = TexCache.find(key);
tf = &tx->second;
tf = &TexCache[key];
tf->tsp = tsp;
tf->tcw = tcw;
@ -1007,13 +996,7 @@ GLuint init_output_framebuffer(int width, int height)
{
if (width != gl.ofbo.width || height != gl.ofbo.height)
{
if (gl.ofbo.fbo != 0)
{
glDeleteFramebuffers(1, &gl.ofbo.fbo);
gl.ofbo.fbo = 0;
glDeleteRenderbuffers(1, &gl.ofbo.depthb);
glcache.DeleteTextures(1, &gl.ofbo.tex);
}
free_output_framebuffer();
gl.ofbo.width = width;
gl.ofbo.height = height;
}
@ -1037,15 +1020,25 @@ GLuint init_output_framebuffer(int width, int height)
else
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
// Create a texture for rendering to
gl.ofbo.tex = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex);
if (gl.gl_major < 3)
{
// Create a texture for rendering to
gl.ofbo.tex = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
else
{
// Use a renderbuffer and glBlitFramebuffer
glGenRenderbuffers(1, &gl.ofbo.colorb);
glBindRenderbuffer(GL_RENDERBUFFER, gl.ofbo.colorb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
}
// Create the framebuffer
glGenFramebuffers(1, &gl.ofbo.fbo);
@ -1057,13 +1050,20 @@ GLuint init_output_framebuffer(int width, int height)
if (!gl.is_gles || gl.GL_OES_packed_depth_stencil_supported)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl.ofbo.depthb);
// Attach the texture to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0);
// Attach the texture/renderbuffer to the FBO
if (gl.gl_major < 3)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0);
else
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, gl.ofbo.colorb);
// Check that our FBO creation was successful
GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
verify(uStatus == GL_FRAMEBUFFER_COMPLETE);
glcache.Disable(GL_SCISSOR_TEST);
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
}
else
glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.fbo);
@ -1082,7 +1082,15 @@ void free_output_framebuffer()
gl.ofbo.fbo = 0;
glDeleteRenderbuffers(1, &gl.ofbo.depthb);
gl.ofbo.depthb = 0;
glcache.DeleteTextures(1, &gl.ofbo.tex);
gl.ofbo.tex = 0;
if (gl.ofbo.tex != 0)
{
glcache.DeleteTextures(1, &gl.ofbo.tex);
gl.ofbo.tex = 0;
}
if (gl.ofbo.colorb != 0)
{
glDeleteRenderbuffers(1, &gl.ofbo.colorb);
gl.ofbo.colorb = 0;
}
}
}

View File

@ -67,6 +67,7 @@
#endif
#include "gles.h"
#include "glcache.h"
// OpenGL Data
static char g_GlslVersionString[32] = "";
@ -127,28 +128,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
// Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
#ifdef GL_POLYGON_MODE
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
#endif
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
bool clip_origin_lower_left = true;
#ifdef GL_CLIP_ORIGIN
if (gl.gl_major >= 4 && glClipControl != NULL)
@ -167,13 +147,13 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
// (Re-)create the background texture and reserve space for it
if (g_BackgroundTexture != 0)
glDeleteTextures(1, &g_BackgroundTexture);
glGenTextures(1, &g_BackgroundTexture);
glBindTexture(GL_TEXTURE_2D, g_BackgroundTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glcache.DeleteTextures(1, &g_BackgroundTexture);
g_BackgroundTexture = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, g_BackgroundTexture);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_width, fb_height, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)NULL);
// Copy the current framebuffer into it
@ -182,12 +162,12 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
}
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
glcache.Enable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glcache.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glcache.Disable(GL_CULL_FACE);
glcache.Disable(GL_DEPTH_TEST);
glcache.Enable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE
if (glPolygonMode != NULL)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@ -207,7 +187,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
};
glUseProgram(g_ShaderHandle);
glcache.UseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
#if !defined(GLES) || defined(_ANDROID)
@ -265,7 +245,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glcache.BindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
}
}
@ -276,31 +256,6 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
if (vao_handle != 0)
glDeleteVertexArrays(1, &vao_handle);
#endif
// Restore modified GL state
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
#if !defined(GLES) || defined(_ANDROID)
if (gl.gl_major >= 3 && glBindSampler != NULL)
glBindSampler(0, last_sampler);
#endif
glActiveTexture(last_active_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
#if !defined(GLES) || defined(_ANDROID)
if (gl.gl_major >= 3)
glBindVertexArray(last_vertex_array);
#endif
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE
if (glPolygonMode != NULL)
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
#endif
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
@ -312,21 +267,16 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
g_FontTexture = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, g_FontTexture);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
@ -335,7 +285,7 @@ void ImGui_ImplOpenGL3_DestroyFontsTexture()
if (g_FontTexture)
{
ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
glcache.DeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0;
g_FontTexture = 0;
}
@ -377,14 +327,8 @@ static bool CheckProgram(GLuint handle, const char* desc)
return (GLboolean)status == GL_TRUE;
}
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
{
// Backup GL state
GLint last_texture, last_array_buffer, last_vertex_array;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
// Parse GLSL version string
int glsl_version = 130;
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
@ -544,14 +488,6 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
#if !defined(GLES) || defined(_ANDROID)
if (gl.gl_major >= 3)
glBindVertexArray(last_vertex_array);
#endif
return true;
}
@ -561,26 +497,23 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects()
if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle);
g_VboHandle = g_ElementsHandle = 0;
if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle);
if (g_VertHandle) glDeleteShader(g_VertHandle);
glcache.DeleteProgram(g_ShaderHandle);
g_VertHandle = 0;
if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle);
if (g_FragHandle) glDeleteShader(g_FragHandle);
g_FragHandle = 0;
if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle);
g_ShaderHandle = 0;
ImGui_ImplOpenGL3_DestroyFontsTexture();
if (g_BackgroundTexture != 0)
glDeleteTextures(1, &g_BackgroundTexture);
glcache.DeleteTextures(1, &g_BackgroundTexture);
g_BackgroundTexture = 0;
}
void ImGui_ImplOpenGL3_DrawBackground()
{
glcache.Disable(GL_SCISSOR_TEST);
glcache.ClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
if (g_BackgroundTexture != 0)
{
ImGuiIO& io = ImGui::GetIO();
@ -591,20 +524,14 @@ void ImGui_ImplOpenGL3_DrawBackground()
ImGui::GetWindowDrawList()->AddImage((ImTextureID)(uintptr_t)g_BackgroundTexture, ImVec2(0, 0), io.DisplaySize, ImVec2(0, 1), ImVec2(1, 0), 0xffffffff);
ImGui::End();
}
else
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
}
}
ImTextureID ImGui_ImplOpenGL3_CreateVmuTexture(const unsigned int *data)
{
GLuint tex_id;
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLuint tex_id = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, tex_id);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 48, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
return reinterpret_cast<ImTextureID>(tex_id);
@ -612,5 +539,5 @@ ImTextureID ImGui_ImplOpenGL3_CreateVmuTexture(const unsigned int *data)
void ImGui_ImplOpenGL3_DeleteVmuTexture(ImTextureID tex_id)
{
glDeleteTextures(1, &(GLuint &)tex_id);
glcache.DeleteTextures(1, &(GLuint &)tex_id);
}

View File

@ -18,7 +18,12 @@
*/
#include <algorithm>
#include <math.h>
#ifdef _MSC_VER
#include "dirent/dirent.h"
#define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
#else
#include <dirent.h>
#endif
#include <sys/stat.h>
#include "gui.h"
@ -34,7 +39,10 @@
#include "linux-dist/main.h" // FIXME for kcode[]
#include "gui_util.h"
#include "gui_android.h"
#include "version/version.h"
#include "version.h"
#include "oslib/audiostream.h"
extern void dc_loadstate();
extern void dc_savestate();
@ -294,7 +302,9 @@ static void gui_display_commands()
if (!settings_opening)
ImGui_ImplOpenGL3_DrawBackground();
display_vmus();
if (!settings.rend.FloatVMUs)
// If floating VMUs, they are already visible on the background
display_vmus();
ImGui::SetNextWindowPos(ImVec2(screen_width / 2.f, screen_height / 2.f), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(ImVec2(330 * scaling, 0));
@ -617,6 +627,8 @@ void directory_selected_callback(bool cancelled, std::string selection)
static void gui_display_settings()
{
static bool maple_devices_changed;
ImGui_Impl_NewFrame();
ImGui::NewFrame();
@ -639,10 +651,14 @@ static void gui_display_settings()
gui_state = Commands;
else
gui_state = Main;
if (maple_devices_changed)
{
maple_devices_changed = false;
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
maple_ReconnectDevices();
reset_vmus();
maple_ReconnectDevices();
reset_vmus();
#endif
}
SaveSettings();
}
if (game_started)
@ -796,13 +812,14 @@ static void gui_display_settings()
if (ImGui::BeginTabItem("Controls"))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding);
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
if (ImGui::CollapsingHeader("Dreamcast Devices", ImGuiTreeNodeFlags_DefaultOpen))
{
for (int bus = 0; bus < MAPLE_PORTS; bus++)
{
ImGui::Text("Device %c", bus + 'A');
ImGui::SameLine();
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
char device_name[32];
sprintf(device_name, "##device%d", bus);
float w = ImGui::CalcItemWidth() / 3;
@ -813,7 +830,10 @@ static void gui_display_settings()
{
bool is_selected = settings.input.maple_devices[bus] == maple_device_type_from_index(i);
if (ImGui::Selectable(maple_device_types[i], &is_selected))
{
settings.input.maple_devices[bus] = maple_device_type_from_index(i);
maple_devices_changed = true;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
@ -831,7 +851,10 @@ static void gui_display_settings()
{
bool is_selected = settings.input.maple_expansion_devices[bus][port] == maple_expansion_device_type_from_index(i);
if (ImGui::Selectable(maple_expansion_device_types[i], &is_selected))
{
settings.input.maple_expansion_devices[bus][port] = maple_expansion_device_type_from_index(i);
maple_devices_changed = true;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
@ -840,6 +863,10 @@ static void gui_display_settings()
ImGui::PopID();
}
ImGui::PopItemWidth();
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
if (MapleDevices[bus][5] != NULL)
ImGui::Text("%s", maple_device_name(MapleDevices[bus][5]->get_device_type()));
#endif
}
ImGui::Spacing();
}
@ -940,15 +967,27 @@ static void gui_display_settings()
ImGui::Checkbox("Shadows", &settings.rend.ModifierVolumes);
ImGui::SameLine();
ShowHelpMarker("Enable modifier volumes, usually used for shadows");
ImGui::Checkbox("Fog", &settings.rend.Fog);
ImGui::SameLine();
ShowHelpMarker("Enable fog effects");
ImGui::Checkbox("Widescreen", &settings.rend.WideScreen);
ImGui::SameLine();
ShowHelpMarker("Draw geometry outside of the normal 4:3 aspect ratio. May produce graphical glitches in the revealed areas");
ImGui::Checkbox("Show FPS Counter", &settings.rend.ShowFPS);
ImGui::SameLine();
ShowHelpMarker("Show on-screen frame/sec counter");
ImGui::Checkbox("Show VMU in game", &settings.rend.FloatVMUs);
ImGui::SameLine();
ShowHelpMarker("Show the VMU LCD screens while in game");
ImGui::Checkbox("Rotate screen 90°", &settings.rend.Rotate90);
ImGui::SameLine();
ShowHelpMarker("Rotate the screen 90° counterclockwise");
ImGui::SliderInt("Scaling", (int *)&settings.rend.ScreenScaling, 1, 100);
ImGui::SameLine();
ShowHelpMarker("Downscaling factor relative to native screen resolution. Higher is better");
ImGui::SliderInt("Horizontal Stretching", (int *)&settings.rend.ScreenStretching, 100, 150);
ImGui::SameLine();
ShowHelpMarker("Stretch the screen horizontally");
ImGui::SliderInt("Frame Skipping", (int *)&settings.pvr.ta_skip, 0, 6);
ImGui::SameLine();
ShowHelpMarker("Number of frames to skip between two actually rendered frames");
@ -986,12 +1025,122 @@ static void gui_display_settings()
ImGui::Checkbox("Disable Sound", &settings.aica.NoSound);
ImGui::SameLine();
ShowHelpMarker("Disable the emulator sound output");
ImGui::Checkbox("Enable DSP", &settings.aica.NoBatch);
ImGui::SameLine();
ShowHelpMarker("Enable the Dreamcast Digital Sound Processor. Only recommended on fast and arm64 platforms");
ImGui::Checkbox("Limit FPS", &settings.aica.LimitFPS);
ImGui::SameLine();
ShowHelpMarker("Use the sound output to limit the speed of the emulator. Recommended in most cases");
audiobackend_t* backend = NULL;;
std::string backend_name = settings.audio.backend;
if (backend_name != "auto" && backend_name != "none")
{
backend = GetAudioBackend(settings.audio.backend);
if (backend != NULL)
backend_name = backend->slug;
}
SortAudioBackends();
audiobackend_t* current_backend = backend;
if (ImGui::BeginCombo("Audio Backend", backend_name.c_str(), ImGuiComboFlags_None))
{
bool is_selected = (settings.audio.backend == "auto");
if (ImGui::Selectable("auto", &is_selected))
settings.audio.backend = "auto";
ImGui::SameLine(); ImGui::Text("-");
ImGui::SameLine(); ImGui::Text("Autoselect audio backend");
is_selected = (settings.audio.backend == "none");
if (ImGui::Selectable("none", &is_selected))
settings.audio.backend = "none";
ImGui::SameLine(); ImGui::Text("-");
ImGui::SameLine(); ImGui::Text("No audio backend");
for (int i = 0; i < GetAudioBackendCount(); i++)
{
backend = GetAudioBackend(i);
is_selected = (settings.audio.backend == backend->slug);
if (is_selected)
current_backend = backend;
if (ImGui::Selectable(backend->slug.c_str(), &is_selected))
settings.audio.backend = backend->slug;
ImGui::SameLine(); ImGui::Text("-");
ImGui::SameLine(); ImGui::Text(backend->name.c_str());
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::SameLine();
ShowHelpMarker("The audio backend to use");
if (current_backend != NULL && current_backend->get_options != NULL)
{
// get backend specific options
int option_count;
audio_option_t* options = current_backend->get_options(&option_count);
// initialize options if not already done
std::map<std::string, std::string>* cfg_entries = &settings.audio.options[current_backend->slug];
bool populate_entries = (cfg_entries->size() == 0);
for (int o = 0; o < option_count; o++)
{
std::string value;
if (populate_entries)
{
value = cfgLoadStr(current_backend->slug.c_str(), options->cfg_name.c_str(), "");
(*cfg_entries)[options->cfg_name] = value;
}
value = (*cfg_entries)[options->cfg_name];
if (options->type == integer)
{
int val = stoi(value);
ImGui::SliderInt(options->caption.c_str(), &val, options->min_value, options->max_value);
(*cfg_entries)[options->cfg_name] = to_string(val);
}
else if (options->type == checkbox)
{
bool check = (value == "1");
ImGui::Checkbox(options->caption.c_str(), &check);
std::string cur = check ? "1" : "0";
(*cfg_entries)[options->cfg_name] = cur;
}
else if (options->type == list)
{
if (ImGui::BeginCombo(options->caption.c_str(), value.c_str(), ImGuiComboFlags_None))
{
bool is_selected = false;
std::vector<std::string> list_items = options->list_callback();
for (std::vector<std::string>::iterator it = list_items.begin() ; it != list_items.end(); ++it)
{
std::string cur = (std::string)*it;
is_selected = (value == cur);
if (ImGui::Selectable(cur.c_str(), &is_selected))
{
(*cfg_entries)[options->cfg_name] = cur;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
else {
printf("Unknown option\n");
}
options++;
}
}
ImGui::PopStyleVar();
ImGui::EndTabItem();
}
@ -1064,9 +1213,9 @@ static void gui_display_settings()
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding);
if (ImGui::CollapsingHeader("Reicast", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Text("Version: %s", version);
ImGui::Text("Git Hash: %s", git_hash);
ImGui::Text("Build Date: %s", build_date);
ImGui::Text("Version: %s", REICAST_VERSION);
ImGui::Text("Git Hash: %s", GIT_HASH);
ImGui::Text("Build Date: %s", BUILD_DATE);
ImGui::Text("Target: %s",
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
"Dreamcast"
@ -1248,6 +1397,7 @@ static void gui_start_game(const std::string& path)
{
gui_state = Main;
game_started = false;
cfgSetVirtual("config", "image", "");
switch (rc) {
case -3:
error_msg = "Audio/video initialization failed";
@ -1405,24 +1555,6 @@ void gui_display_ui()
gui_state = Closed;
}
void gui_display_fps(const char *string)
{
ImGui_Impl_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
ImGui::Begin("##fps", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(2);
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", string);
ImGui::End();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
static float LastFPSTime;
static int lastFrameCount = 0;
static float fps = -1;
@ -1470,26 +1602,32 @@ void gui_display_osd()
if (osd_message.empty())
{
message = getFPSNotification();
if (message.empty())
return;
}
else
message = osd_message;
ImGui_Impl_NewFrame();
ImGui::NewFrame();
if (!message.empty() || settings.rend.FloatVMUs)
{
ImGui_Impl_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
if (!message.empty())
{
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(1.5);
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str());
ImGui::End();
ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(1.5);
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str());
ImGui::End();
}
if (settings.rend.FloatVMUs)
display_vmus();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
}
void gui_open_onboarding()

View File

@ -21,8 +21,16 @@
#include <vector>
#include <algorithm>
#include <stdlib.h>
#ifdef _MSC_VER
#include <io.h>
#include "dirent/dirent.h"
#define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
#define access _access
#define R_OK 4
#else
#include <dirent.h>
#include <unistd.h>
#endif
#include <sys/stat.h>
#include "types.h"

View File

@ -101,7 +101,7 @@ extern AicaTimer timers[3];
//./core/hw/aica/aica_if.o
extern VArray2 aica_ram;
extern VLockedMemory aica_ram;
extern u32 VREG;//video reg =P
extern u32 ARMRST;//arm reset reg
extern u32 rtc_EN;
@ -381,7 +381,7 @@ extern DECL_ALIGN(4) u32 SFaceOffsColor;
//extern vector<vram_block*> VramLocks[/*VRAM_SIZE*/(16*1024*1024)/PAGE_SIZE];
//maybe - probably not - just a locking mechanism
//extern cMutex vramlist_lock;
extern VArray2 vram;
extern VLockedMemory vram;
@ -403,7 +403,7 @@ extern Array<RegisterStruct> SCIF; //SCIF : 10 registers
//./core/hw/sh4/sh4_mem.o
extern VArray2 mem_b;
extern VLockedMemory mem_b;
//one-time init
//extern _vmem_handler area1_32b;
//one-time init
@ -441,7 +441,7 @@ extern u32 old_dn;
//./core/hw/sh4/sh4_sched.o
extern u64 sh4_sched_ffb;
extern u32 sh4_sched_intr;
extern vector<sched_list> list;
extern vector<sched_list> sch_list;
//extern int sh4_sched_next_id;
@ -975,8 +975,6 @@ bool dc_serialize(void **data, unsigned int *total_size)
REICAST_S(decoded_srimask);
//default to nommu_full
i = 3 ;
if ( do_sqw_nommu == &do_sqw_nommu_area_3)
@ -1008,61 +1006,63 @@ bool dc_serialize(void **data, unsigned int *total_size)
//extern vector<sched_list> list;
REICAST_S(list[aica_schid].tag) ;
REICAST_S(list[aica_schid].start) ;
REICAST_S(list[aica_schid].end) ;
REICAST_S(list[rtc_schid].tag) ;
REICAST_S(list[rtc_schid].start) ;
REICAST_S(list[rtc_schid].end) ;
REICAST_S(sch_list[aica_schid].tag) ;
REICAST_S(sch_list[aica_schid].start) ;
REICAST_S(sch_list[aica_schid].end) ;
REICAST_S(list[gdrom_schid].tag) ;
REICAST_S(list[gdrom_schid].start) ;
REICAST_S(list[gdrom_schid].end) ;
REICAST_S(sch_list[rtc_schid].tag) ;
REICAST_S(sch_list[rtc_schid].start) ;
REICAST_S(sch_list[rtc_schid].end) ;
REICAST_S(list[maple_schid].tag) ;
REICAST_S(list[maple_schid].start) ;
REICAST_S(list[maple_schid].end) ;
REICAST_S(sch_list[gdrom_schid].tag) ;
REICAST_S(sch_list[gdrom_schid].start) ;
REICAST_S(sch_list[gdrom_schid].end) ;
REICAST_S(list[dma_sched_id].tag) ;
REICAST_S(list[dma_sched_id].start) ;
REICAST_S(list[dma_sched_id].end) ;
REICAST_S(sch_list[maple_schid].tag) ;
REICAST_S(sch_list[maple_schid].start) ;
REICAST_S(sch_list[maple_schid].end) ;
REICAST_S(sch_list[dma_sched_id].tag) ;
REICAST_S(sch_list[dma_sched_id].start) ;
REICAST_S(sch_list[dma_sched_id].end) ;
for (int i = 0; i < 3; i++)
{
REICAST_S(list[tmu_sched[i]].tag) ;
REICAST_S(list[tmu_sched[i]].start) ;
REICAST_S(list[tmu_sched[i]].end) ;
REICAST_S(sch_list[tmu_sched[i]].tag) ;
REICAST_S(sch_list[tmu_sched[i]].start) ;
REICAST_S(sch_list[tmu_sched[i]].end) ;
}
REICAST_S(list[render_end_schid].tag) ;
REICAST_S(list[render_end_schid].start) ;
REICAST_S(list[render_end_schid].end) ;
REICAST_S(sch_list[render_end_schid].tag) ;
REICAST_S(sch_list[render_end_schid].start) ;
REICAST_S(sch_list[render_end_schid].end) ;
REICAST_S(list[vblank_schid].tag) ;
REICAST_S(list[vblank_schid].start) ;
REICAST_S(list[vblank_schid].end) ;
REICAST_S(list[time_sync].tag) ;
REICAST_S(list[time_sync].start) ;
REICAST_S(list[time_sync].end) ;
REICAST_S(list[modem_sched].tag) ;
REICAST_S(list[modem_sched].start) ;
REICAST_S(list[modem_sched].end) ;
REICAST_S(sch_list[vblank_schid].tag) ;
REICAST_S(sch_list[vblank_schid].start) ;
REICAST_S(sch_list[vblank_schid].end) ;
REICAST_S(sch_list[time_sync].tag) ;
REICAST_S(sch_list[time_sync].start) ;
REICAST_S(sch_list[time_sync].end) ;
#ifdef ENABLE_MODEM
REICAST_S(sch_list[modem_sched].tag) ;
REICAST_S(sch_list[modem_sched].start) ;
REICAST_S(sch_list[modem_sched].end) ;
#else
int modem_dummy = 0;
REICAST_S(modem_dummy);
REICAST_S(modem_dummy);
REICAST_S(modem_dummy);
#endif
REICAST_S(SCIF_SCFSR2);
REICAST_S(SCIF_SCFRDR2);
REICAST_S(SCIF_SCFDR2);
REICAST_S(BSC_PDTRA);
REICAST_SA(tmu_shift,3);
REICAST_SA(tmu_mask,3);
REICAST_SA(tmu_mask64,3);
@ -1070,14 +1070,8 @@ bool dc_serialize(void **data, unsigned int *total_size)
REICAST_SA(tmu_ch_base,3);
REICAST_SA(tmu_ch_base64,3);
REICAST_SA(CCN_QACR_TR,2);
REICAST_SA(UTLB,64);
REICAST_SA(ITLB,4);
#if defined(NO_MMU)
@ -1087,8 +1081,6 @@ bool dc_serialize(void **data, unsigned int *total_size)
REICAST_S(mmu_error_TT);
#endif
REICAST_S(NullDriveDiscType);
REICAST_SA(q_subchannel,96);
@ -1130,22 +1122,16 @@ bool dc_serialize(void **data, unsigned int *total_size)
REICAST_S(div_som_reg2);
REICAST_S(div_som_reg3);
REICAST_S(LastAddr);
REICAST_S(LastAddr_min);
REICAST_SA(block_hash,1024);
REICAST_SA(RegisterWrite,sh4_reg_count);
REICAST_SA(RegisterRead,sh4_reg_count);
REICAST_S(fallback_blocks);
REICAST_S(total_blocks);
REICAST_S(REMOVED_OPS);
REICAST_SA(kcode,4);
REICAST_SA(rt,4);
REICAST_SA(lt,4);
@ -1246,12 +1232,7 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size)
//this is one-time init, no updates - don't need to serialize
//extern _vmem_handler area0_handler;
REICAST_USA(reply_11,16) ;
REICAST_USA(reply_11,16);
REICAST_US(sns_asc);
REICAST_US(sns_ascq);
@ -1365,8 +1346,6 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size)
REICAST_USA(mem_b.data, mem_b.size);
REICAST_US(IRLPriority);
REICAST_USA(InterruptEnvId,32);
REICAST_USA(InterruptBit,32);
@ -1375,9 +1354,6 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size)
REICAST_US(interrupt_vmask);
REICAST_US(decoded_srimask);
REICAST_US(i) ;
if ( i == 0 )
do_sqw_nommu = &do_sqw_nommu_area_3 ;
@ -1402,69 +1378,67 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size)
REICAST_US(old_rm);
REICAST_US(old_dn);
REICAST_US(sh4_sched_ffb);
REICAST_US(sh4_sched_intr);
//extern vector<sched_list> list;
//extern vector<sched_list> sch_list;
REICAST_US(list[aica_schid].tag) ;
REICAST_US(list[aica_schid].start) ;
REICAST_US(list[aica_schid].end) ;
REICAST_US(sch_list[aica_schid].tag) ;
REICAST_US(sch_list[aica_schid].start) ;
REICAST_US(sch_list[aica_schid].end) ;
REICAST_US(list[rtc_schid].tag) ;
REICAST_US(list[rtc_schid].start) ;
REICAST_US(list[rtc_schid].end) ;
REICAST_US(sch_list[rtc_schid].tag) ;
REICAST_US(sch_list[rtc_schid].start) ;
REICAST_US(sch_list[rtc_schid].end) ;
REICAST_US(list[gdrom_schid].tag) ;
REICAST_US(list[gdrom_schid].start) ;
REICAST_US(list[gdrom_schid].end) ;
REICAST_US(sch_list[gdrom_schid].tag) ;
REICAST_US(sch_list[gdrom_schid].start) ;
REICAST_US(sch_list[gdrom_schid].end) ;
REICAST_US(list[maple_schid].tag) ;
REICAST_US(list[maple_schid].start) ;
REICAST_US(list[maple_schid].end) ;
REICAST_US(sch_list[maple_schid].tag) ;
REICAST_US(sch_list[maple_schid].start) ;
REICAST_US(sch_list[maple_schid].end) ;
REICAST_US(list[dma_sched_id].tag) ;
REICAST_US(list[dma_sched_id].start) ;
REICAST_US(list[dma_sched_id].end) ;
REICAST_US(sch_list[dma_sched_id].tag) ;
REICAST_US(sch_list[dma_sched_id].start) ;
REICAST_US(sch_list[dma_sched_id].end) ;
for (int i = 0; i < 3; i++)
{
REICAST_US(list[tmu_sched[i]].tag) ;
REICAST_US(list[tmu_sched[i]].start) ;
REICAST_US(list[tmu_sched[i]].end) ;
REICAST_US(sch_list[tmu_sched[i]].tag) ;
REICAST_US(sch_list[tmu_sched[i]].start) ;
REICAST_US(sch_list[tmu_sched[i]].end) ;
}
REICAST_US(list[render_end_schid].tag) ;
REICAST_US(list[render_end_schid].start) ;
REICAST_US(list[render_end_schid].end) ;
REICAST_US(sch_list[render_end_schid].tag) ;
REICAST_US(sch_list[render_end_schid].start) ;
REICAST_US(sch_list[render_end_schid].end) ;
REICAST_US(list[vblank_schid].tag) ;
REICAST_US(list[vblank_schid].start) ;
REICAST_US(list[vblank_schid].end) ;
REICAST_US(list[time_sync].tag) ;
REICAST_US(list[time_sync].start) ;
REICAST_US(list[time_sync].end) ;
REICAST_US(list[modem_sched].tag) ;
REICAST_US(list[modem_sched].start) ;
REICAST_US(list[modem_sched].end) ;
REICAST_US(sch_list[vblank_schid].tag) ;
REICAST_US(sch_list[vblank_schid].start) ;
REICAST_US(sch_list[vblank_schid].end) ;
REICAST_US(sch_list[time_sync].tag) ;
REICAST_US(sch_list[time_sync].start) ;
REICAST_US(sch_list[time_sync].end) ;
#ifdef ENABLE_MODEM
REICAST_US(sch_list[modem_sched].tag) ;
REICAST_US(sch_list[modem_sched].start) ;
REICAST_US(sch_list[modem_sched].end) ;
#else
int modem_dummy;
REICAST_US(modem_dummy);
REICAST_US(modem_dummy);
REICAST_US(modem_dummy);
#endif
REICAST_US(SCIF_SCFSR2);
REICAST_US(SCIF_SCFRDR2);
REICAST_US(SCIF_SCFDR2);
REICAST_US(BSC_PDTRA);
REICAST_USA(tmu_shift,3);
REICAST_USA(tmu_mask,3);
REICAST_USA(tmu_mask64,3);
@ -1472,14 +1446,8 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size)
REICAST_USA(tmu_ch_base,3);
REICAST_USA(tmu_ch_base64,3);
REICAST_USA(CCN_QACR_TR,2);
REICAST_USA(UTLB,64);
REICAST_USA(ITLB,4);
#if defined(NO_MMU)
@ -1489,9 +1457,6 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size)
REICAST_US(mmu_error_TT);
#endif
REICAST_US(NullDriveDiscType);
REICAST_USA(q_subchannel,96);
@ -1546,9 +1511,6 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size)
REICAST_US(div_som_reg2);
REICAST_US(div_som_reg3);
//REICAST_USA(CodeCache,CODE_SIZE) ;
//REICAST_USA(SH4_TCB,CODE_SIZE+4096);
REICAST_US(LastAddr);
@ -1612,7 +1574,6 @@ bool dc_unserialize(void **data, unsigned int *total_size)
REICAST_US(timers[i].m_step);
}
REICAST_USA(aica_ram.data,aica_ram.size) ;
REICAST_US(VREG);
REICAST_US(ARMRST);
@ -1620,8 +1581,6 @@ bool dc_unserialize(void **data, unsigned int *total_size)
REICAST_USA(aica_reg,0x8000);
REICAST_USA(volume_lut,16);
REICAST_USA(tl_lut,256 + 768);
REICAST_USA(AEG_ATT_SPS,64);
@ -1636,14 +1595,11 @@ bool dc_unserialize(void **data, unsigned int *total_size)
REICAST_USA(mxlr,64);
REICAST_US(samples_gen);
register_unserialize(sb_regs, data, total_size) ;
REICAST_US(SB_ISTNRM);
REICAST_US(SB_FFST_rc);
REICAST_US(SB_FFST);
//this is one-time init, no updates - don't need to serialize
//extern RomChip sys_rom;
REICAST_US(sys_nvmem.size);
@ -1755,8 +1711,6 @@ bool dc_unserialize(void **data, unsigned int *total_size)
REICAST_USA(mem_b.data, mem_b.size);
REICAST_US(IRLPriority);
REICAST_USA(InterruptEnvId,32);
REICAST_USA(InterruptBit,32);
@ -1765,9 +1719,6 @@ bool dc_unserialize(void **data, unsigned int *total_size)
REICAST_US(interrupt_vmask);
REICAST_US(decoded_srimask);
REICAST_US(i) ;
if ( i == 0 )
do_sqw_nommu = &do_sqw_nommu_area_3 ;
@ -1800,50 +1751,55 @@ bool dc_unserialize(void **data, unsigned int *total_size)
//extern vector<sched_list> list;
REICAST_US(list[aica_schid].tag) ;
REICAST_US(list[aica_schid].start) ;
REICAST_US(list[aica_schid].end) ;
REICAST_US(sch_list[aica_schid].tag) ;
REICAST_US(sch_list[aica_schid].start) ;
REICAST_US(sch_list[aica_schid].end) ;
REICAST_US(list[rtc_schid].tag) ;
REICAST_US(list[rtc_schid].start) ;
REICAST_US(list[rtc_schid].end) ;
REICAST_US(sch_list[rtc_schid].tag) ;
REICAST_US(sch_list[rtc_schid].start) ;
REICAST_US(sch_list[rtc_schid].end) ;
REICAST_US(list[gdrom_schid].tag) ;
REICAST_US(list[gdrom_schid].start) ;
REICAST_US(list[gdrom_schid].end) ;
REICAST_US(sch_list[gdrom_schid].tag) ;
REICAST_US(sch_list[gdrom_schid].start) ;
REICAST_US(sch_list[gdrom_schid].end) ;
REICAST_US(list[maple_schid].tag) ;
REICAST_US(list[maple_schid].start) ;
REICAST_US(list[maple_schid].end) ;
REICAST_US(sch_list[maple_schid].tag) ;
REICAST_US(sch_list[maple_schid].start) ;
REICAST_US(sch_list[maple_schid].end) ;
REICAST_US(list[dma_sched_id].tag) ;
REICAST_US(list[dma_sched_id].start) ;
REICAST_US(list[dma_sched_id].end) ;
REICAST_US(sch_list[dma_sched_id].tag) ;
REICAST_US(sch_list[dma_sched_id].start) ;
REICAST_US(sch_list[dma_sched_id].end) ;
for (int i = 0; i < 3; i++)
{
REICAST_US(list[tmu_sched[i]].tag) ;
REICAST_US(list[tmu_sched[i]].start) ;
REICAST_US(list[tmu_sched[i]].end) ;
REICAST_US(sch_list[tmu_sched[i]].tag) ;
REICAST_US(sch_list[tmu_sched[i]].start) ;
REICAST_US(sch_list[tmu_sched[i]].end) ;
}
REICAST_US(list[render_end_schid].tag) ;
REICAST_US(list[render_end_schid].start) ;
REICAST_US(list[render_end_schid].end) ;
REICAST_US(sch_list[render_end_schid].tag) ;
REICAST_US(sch_list[render_end_schid].start) ;
REICAST_US(sch_list[render_end_schid].end) ;
REICAST_US(list[vblank_schid].tag) ;
REICAST_US(list[vblank_schid].start) ;
REICAST_US(list[vblank_schid].end) ;
REICAST_US(list[time_sync].tag) ;
REICAST_US(list[time_sync].start) ;
REICAST_US(list[time_sync].end) ;
REICAST_US(list[modem_sched].tag) ;
REICAST_US(list[modem_sched].start) ;
REICAST_US(list[modem_sched].end) ;
REICAST_US(sch_list[vblank_schid].tag) ;
REICAST_US(sch_list[vblank_schid].start) ;
REICAST_US(sch_list[vblank_schid].end) ;
REICAST_US(sch_list[time_sync].tag) ;
REICAST_US(sch_list[time_sync].start) ;
REICAST_US(sch_list[time_sync].end) ;
#ifdef ENABLE_MODEM
REICAST_US(sch_list[modem_sched].tag) ;
REICAST_US(sch_list[modem_sched].start) ;
REICAST_US(sch_list[modem_sched].end) ;
#else
int modem_dummy;
REICAST_US(modem_dummy);
REICAST_US(modem_dummy);
REICAST_US(modem_dummy);
#endif
REICAST_US(SCIF_SCFSR2);
REICAST_US(SCIF_SCFRDR2);
@ -1880,8 +1836,6 @@ bool dc_unserialize(void **data, unsigned int *total_size)
#endif
REICAST_US(NullDriveDiscType);
REICAST_USA(q_subchannel,96);
@ -1897,7 +1851,6 @@ bool dc_unserialize(void **data, unsigned int *total_size)
// REICAST_US(i); // VRAM_MASK
REICAST_US(naomi_updates);
REICAST_US(i); // BoardID
REICAST_US(GSerialBuffer);
@ -1936,25 +1889,18 @@ bool dc_unserialize(void **data, unsigned int *total_size)
REICAST_US(div_som_reg2);
REICAST_US(div_som_reg3);
//REICAST_USA(CodeCache,CODE_SIZE) ;
//REICAST_USA(SH4_TCB,CODE_SIZE+4096);
REICAST_US(LastAddr);
REICAST_US(LastAddr_min);
REICAST_USA(block_hash,1024);
REICAST_USA(RegisterWrite,sh4_reg_count);
REICAST_USA(RegisterRead,sh4_reg_count);
REICAST_US(fallback_blocks);
REICAST_US(total_blocks);
REICAST_US(REMOVED_OPS);
REICAST_USA(kcode,4);
REICAST_USA(rt,4);
REICAST_USA(lt,4);

View File

@ -4,9 +4,16 @@
#include <sys/stat.h>
#include "types.h"
#include "cfg/cfg.h"
#include "stdclass.h"
#if HOST_OS == OS_DARWIN
#include <mach/clock.h>
#include <mach/mach.h>
#endif
#if BUILD_COMPILER==COMPILER_VC
#if COMPILER_VC_OR_CLANG_WIN32
#include <io.h>
#include <direct.h>
#define access _access
#define R_OK 4
#else
@ -140,62 +147,156 @@ string get_game_dir()
bool make_directory(const string& path)
{
return mkdir(path.c_str()
#ifndef _WIN32
, 0755
#if COMPILER_VC_OR_CLANG_WIN32
#define mkdir _mkdir
#endif
#ifdef _WIN32
return mkdir(path.c_str()) == 0;
#else
return mkdir(path.c_str(), 0755) == 0;
#endif
) == 0;
}
#if 0
//File Enumeration
void FindAllFiles(FileFoundCB* callback,wchar* dir,void* param)
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
wchar DirSpec[MAX_PATH + 1]; // directory specification
DWORD dwError;
// Thread & related platform dependant code
#if !defined(HOST_NO_THREADS)
strncpy (DirSpec, dir, strlen(dir)+1);
//strncat (DirSpec, "\\*", 3);
hFind = FindFirstFile( DirSpec, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
return;
}
else
{
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0)
{
callback(FindFileData.cFileName,param);
}
u32 rv;
while ( (rv=FindNextFile(hFind, &FindFileData)) != 0)
{
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0)
{
callback(FindFileData.cFileName,param);
}
}
dwError = GetLastError();
FindClose(hFind);
if (dwError != ERROR_NO_MORE_FILES)
{
return ;
}
#if HOST_OS==OS_WINDOWS
void cThread::Start() {
verify(hThread == NULL);
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)entry, param, 0, NULL);
ResumeThread(hThread);
}
void cThread::WaitToEnd() {
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
hThread = NULL;
}
#else
void cThread::Start() {
verify(hThread == NULL);
hThread = new pthread_t;
if (pthread_create( hThread, NULL, entry, param))
die("Thread creation failed");
}
void cThread::WaitToEnd() {
if (hThread) {
pthread_join(*hThread,0);
delete hThread;
hThread = NULL;
}
return ;
}
#endif
/*
#include "dc\sh4\rec_v1\compiledblock.h"
#include "dc\sh4\rec_v1\blockmanager.h"
#endif
#if HOST_OS==OS_WINDOWS
cResetEvent::cResetEvent() {
hEvent = CreateEvent(
NULL, // default security attributes
FALSE, // auto-reset event?
FALSE, // initial state is State
NULL // unnamed object
);
}
cResetEvent::~cResetEvent()
{
//Destroy the event object ?
CloseHandle(hEvent);
}
void cResetEvent::Set()//Signal
{
#if defined(DEBUG_THREADS)
Sleep(rand() % 10);
#endif
SetEvent(hEvent);
}
void cResetEvent::Reset()//reset
{
#if defined(DEBUG_THREADS)
Sleep(rand() % 10);
#endif
ResetEvent(hEvent);
}
bool cResetEvent::Wait(u32 msec)//Wait for signal , then reset
{
#if defined(DEBUG_THREADS)
Sleep(rand() % 10);
#endif
return WaitForSingleObject(hEvent,msec) == WAIT_OBJECT_0;
}
void cResetEvent::Wait()//Wait for signal , then reset
{
#if defined(DEBUG_THREADS)
Sleep(rand() % 10);
#endif
WaitForSingleObject(hEvent,(u32)-1);
}
#else
cResetEvent::cResetEvent() {
pthread_mutex_init(&mutx, NULL);
pthread_cond_init(&cond, NULL);
}
cResetEvent::~cResetEvent() {
}
void cResetEvent::Set()//Signal
{
pthread_mutex_lock( &mutx );
state=true;
pthread_cond_signal( &cond);
pthread_mutex_unlock( &mutx );
}
void cResetEvent::Reset()//reset
{
pthread_mutex_lock( &mutx );
state=false;
pthread_mutex_unlock( &mutx );
}
bool cResetEvent::Wait(u32 msec)//Wait for signal , then reset
{
pthread_mutex_lock( &mutx );
if (!state)
{
struct timespec ts;
#if HOST_OS == OS_DARWIN
// OSX doesn't have clock_gettime.
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
#else
clock_gettime(CLOCK_REALTIME, &ts);
#endif
ts.tv_sec += msec / 1000;
ts.tv_nsec += (msec % 1000) * 1000000;
while (ts.tv_nsec > 1000000000)
{
ts.tv_nsec -= 1000000000;
ts.tv_sec++;
}
pthread_cond_timedwait( &cond, &mutx, &ts );
}
bool rc = state;
state=false;
pthread_mutex_unlock( &mutx );
return rc;
}
void cResetEvent::Wait()//Wait for signal , then reset
{
pthread_mutex_lock( &mutx );
if (!state)
{
pthread_cond_wait( &cond, &mutx );
}
state=false;
pthread_mutex_unlock( &mutx );
}
#endif
bool VramLockedWrite(u8* address);
bool RamLockedWrite(u8* address,u32* sp);
*/

View File

@ -7,7 +7,7 @@
#if HOST_OS!=OS_WINDOWS
#include <pthread.h>
#else
#include <Windows.h>
#include <windows.h>
#endif
@ -166,38 +166,41 @@ public:
#if !defined(HOST_NO_THREADS)
typedef void* ThreadEntryFP(void* param);
typedef void* THREADHANDLE;
class cThread
{
class cThread {
private:
ThreadEntryFP* Entry;
ThreadEntryFP* entry;
void* param;
public :
THREADHANDLE hThread;
cThread(ThreadEntryFP* function,void* param);
#if HOST_OS==OS_WINDOWS
HANDLE hThread;
#else
pthread_t *hThread;
#endif
cThread(ThreadEntryFP* function, void* param)
:entry(function), param(param), hThread(NULL) {}
~cThread() { WaitToEnd(); }
void Start();
void WaitToEnd();
};
#endif
//Wait Events
typedef void* EVENTHANDLE;
class cResetEvent
{
private:
#if HOST_OS==OS_WINDOWS
EVENTHANDLE hEvent;
#else
pthread_mutex_t mutx;
pthread_cond_t cond;
bool state;
#endif
public :
bool state;
cResetEvent(bool State,bool Auto);
cResetEvent();
~cResetEvent();
void Set(); //Set state to signaled
void Reset(); //Set state to non signaled
@ -276,29 +279,38 @@ string get_game_save_prefix();
string get_game_basename();
string get_game_dir();
class VArray2
{
// Locked memory class, used for texture invalidation purposes.
class VLockedMemory {
public:
u8* data;
u32 size;
//void Init(void* data,u32 sz);
//void Term();
void LockRegion(u32 offset,u32 size);
void UnLockRegion(u32 offset,u32 size);
unsigned size;
void Zero()
{
UnLockRegion(0,size);
memset(data,0,size);
void SetRegion(void* ptr, unsigned size) {
this->data = (u8*)ptr;
this->size = size;
}
void *getPtr() const { return data; }
unsigned getSize() const { return size; }
#ifdef TARGET_NO_EXCEPTIONS
void LockRegion(unsigned offset, unsigned size_bytes) {}
void UnLockRegion(unsigned offset, unsigned size_bytes) {}
#else
void LockRegion(unsigned offset, unsigned size_bytes);
void UnLockRegion(unsigned offset, unsigned size_bytes);
#endif
void Zero() {
UnLockRegion(0, size);
memset(data, 0, size);
}
INLINE u8& operator [](const u32 i)
{
INLINE u8& operator [](unsigned i) {
#ifdef MEM_BOUND_CHECK
if (i>=size)
if (i >= size)
{
printf("Error: VArray2 , index out of range (%d>%d)\n",i,size-1);
printf("Error: VLockedMemory , index out of range (%d > %d)\n", i, size-1);
MEM_DO_BREAK;
}
#endif
@ -306,6 +318,7 @@ public:
}
};
int msgboxf(const wchar* text,unsigned int type,...);

View File

@ -39,7 +39,7 @@
#undef _CRT_SECURE_NO_DEPRECATE
#endif
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
//unnamed struncts/unions
#pragma warning( disable : 4201)
@ -123,7 +123,7 @@ enum HollyInterruptType
};
enum HollyInterruptID
{
{
// asic9a /sh4 external holly normal [internal]
holly_RENDER_DONE_vd = holly_nrm | 0, //bit 0 = End of Render interrupt : Video
holly_RENDER_DONE_isp = holly_nrm | 1, //bit 1 = End of Render interrupt : ISP
@ -132,11 +132,11 @@ enum HollyInterruptID
holly_SCANINT1 = holly_nrm | 3, //bit 3 = V Blank-in interrupt
holly_SCANINT2 = holly_nrm | 4, //bit 4 = V Blank-out interrupt
holly_HBLank = holly_nrm | 5, //bit 5 = H Blank-in interrupt
holly_YUV_DMA = holly_nrm | 6, //bit 6 = End of Transferring interrupt : YUV
holly_OPAQUE = holly_nrm | 7, //bit 7 = End of Transferring interrupt : Opaque List
holly_OPAQUEMOD = holly_nrm | 8, //bit 8 = End of Transferring interrupt : Opaque Modifier Volume List
holly_TRANS = holly_nrm | 9, //bit 9 = End of Transferring interrupt : Translucent List
holly_TRANSMOD = holly_nrm | 10, //bit 10 = End of Transferring interrupt : Translucent Modifier Volume List
holly_PVR_DMA = holly_nrm | 11, //bit 11 = End of DMA interrupt : PVR-DMA
@ -145,12 +145,12 @@ enum HollyInterruptID
holly_MAPLE_VBOI = holly_nrm | 13, //bit 13 = Maple V blank over interrupt
holly_GDROM_DMA = holly_nrm | 14, //bit 14 = End of DMA interrupt : GD-DMA
holly_SPU_DMA = holly_nrm | 15, //bit 15 = End of DMA interrupt : AICA-DMA
holly_EXT_DMA1 = holly_nrm | 16, //bit 16 = End of DMA interrupt : Ext-DMA1(External 1)
holly_EXT_DMA2 = holly_nrm | 17, //bit 17 = End of DMA interrupt : Ext-DMA2(External 2)
holly_DEV_DMA = holly_nrm | 18, //bit 18 = End of DMA interrupt : Dev-DMA(Development tool DMA)
holly_CH2_DMA = holly_nrm | 19, //bit 19 = End of DMA interrupt : ch2-DMA
holly_CH2_DMA = holly_nrm | 19, //bit 19 = End of DMA interrupt : ch2-DMA
holly_PVR_SortDMA = holly_nrm | 20, //bit 20 = End of DMA interrupt : Sort-DMA (Transferring for alpha sorting)
holly_PUNCHTHRU = holly_nrm | 21, //bit 21 = End of Transferring interrupt : Punch Through List
@ -188,8 +188,8 @@ enum HollyInterruptID
//bit 23 = G2 : AICA-DMA Time out
//bit 24 = G2 : Ext-DMA1 Time out
//bit 25 = G2 : Ext-DMA2 Time out
//bit 26 = G2 : Dev-DMA Time out
//bit 27 = G2 : Time out in CPU accessing
//bit 26 = G2 : Dev-DMA Time out
//bit 27 = G2 : Time out in CPU accessing
};
@ -200,7 +200,7 @@ struct vram_block
u32 end;
u32 len;
u32 type;
void* userdata;
};
@ -229,7 +229,7 @@ struct NDC_WINDOW_RECT
//******************************************************
//*********************** PowerVR **********************
//******************************************************
void libCore_vramlock_Unlock_block (vram_block* block);
void libCore_vramlock_Unlock_block_wb (vram_block* block);
vram_block* libCore_vramlock_Lock(u32 start_offset,u32 end_offset,void* userdata);
@ -246,7 +246,7 @@ enum DiscType
CdRom_XA=0x20,
CdRom_Extra=0x30,
CdRom_CDI=0x40,
GdRom=0x80,
GdRom=0x80,
NoDisk=0x1, //These are a bit hacky .. but work for now ...
Open=0x2, //tray is open :)
@ -344,6 +344,7 @@ int darw_printf(const wchar* Text,...);
//includes from c++rt
#include <vector>
#include <string>
#include <map>
using namespace std;
//used for asm-olny functions
@ -385,9 +386,9 @@ using namespace std;
#include "stdclass.h"
#ifndef RELEASE
#define EMUERROR(format, ...) printf("Error in %s:%s:%d: " format "\n", \
strlen(__FILE__) <= 20 ? __FILE__ : __FILE__ + strlen(__FILE__) - 20, \
__FUNCTION__, __LINE__, ##__VA_ARGS__)
#define EMUERROR(format, ...) printf("Error in %20s:%s:%d: " format "\n", \
__FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
//strlen(__FILE__) <= 20 ? __FILE__ : __FILE__ + strlen(__FILE__) - 20,
#else
#define EMUERROR(format, ...)
#endif
@ -518,7 +519,7 @@ typedef union
#if COMPILER_VC==BUILD_COMPILER
#if COMPILER_VC_OR_CLANG_WIN32
#pragma warning( disable : 4127 4996 /*4244*/)
#else
#define stricmp strcasecmp
@ -576,7 +577,7 @@ enum RegIO
RIO_RO = REG_RO | REG_WF,
RIO_RO_FUNC = REG_RO | REG_RF | REG_WF,
RIO_CONST = REG_RO | REG_WF,
RIO_WO_FUNC = REG_WF | REG_RF | REG_WO,
RIO_WO_FUNC = REG_WF | REG_RF | REG_WO,
RIO_NO_ACCESS = REG_WF | REG_RF | REG_NO_ACCESS
};
@ -632,7 +633,11 @@ struct settings_t
f32 ExtraDepthScale;
bool CustomTextures;
bool DumpTextures;
int ScreenScaling; // in percent. 50 means half the native resolution
int ScreenScaling; // in percent. 50 means half the native resolution
int ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3
bool Fog;
bool FloatVMUs;
bool Rotate90; // Rotate the screen 90 deg CC
} rend;
struct
@ -644,7 +649,7 @@ struct settings_t
bool disable_nvmem;
SmcCheckEnum SmcCheckLevel;
} dynarec;
struct
{
u32 run_counts;
@ -653,7 +658,6 @@ struct settings_t
struct
{
u32 cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV
u32 RTC;
u32 region; // 0 -> JP, 1 -> USA, 2 -> EU, 3 -> default
u32 broadcast; // 0 -> NTSC, 1 -> PAL, 2 -> PAL/M, 3 -> PAL/N, 4 -> default
u32 language; // 0 -> JP, 1 -> EN, 2 -> DE, 3 -> FR, 4 -> SP, 5 -> IT, 6 -> default
@ -676,6 +680,14 @@ struct settings_t
bool NoSound;
} aica;
struct{
std::string backend;
// slug<<key, value>>
std::map<std::string, std::map<std::string, std::string>> options;
} audio;
#if USE_OMX
struct
{
@ -705,7 +717,7 @@ struct settings_t
{
u32 ta_skip;
u32 rend;
u32 MaxThreads;
bool SynchronousRender;
} pvr;
@ -748,7 +760,7 @@ static inline void do_nada(...) { }
#ifdef _ANDROID
#include <android/log.h>
#ifdef printf
#ifdef printf
#undef printf
#endif
@ -855,7 +867,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \
return *(u16*)&arr[addr]; \
else if (sz==4) \
return *(u32*)&arr[addr];}
return *(u32*)&arr[addr];}
#define WriteMemArr(arr,addr,data,sz) \
{if(sz==1) \
@ -863,7 +875,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \
{*(u16*)&arr[addr]=(u16)data;} \
else if (sz==4) \
{*(u32*)&arr[addr]=data;}}
{*(u32*)&arr[addr]=data;}}
#define WriteMemArrRet(arr,addr,data,sz) \
{if(sz==1) \
@ -871,7 +883,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \
{*(u16*)&arr[addr]=(u16)data;return;} \
else if (sz==4) \
{*(u32*)&arr[addr]=data;return;}}
{*(u32*)&arr[addr]=data;return;}}
struct OnLoad
{

8
core/version.h.in Normal file
View File

@ -0,0 +1,8 @@
/*
* reicast: version.h
*/
#pragma once
#define REICAST_VERSION "@GIT_VERSION@"
#define GIT_HASH "@GIT_HASH@"
#define BUILD_DATE __DATE__

View File

@ -1 +0,0 @@
/version.cpp

View File

@ -1,3 +0,0 @@
extern const char *version;
extern const char *git_hash;
extern const char *build_date;

104
core/windows/win_vmem.cpp Normal file
View File

@ -0,0 +1,104 @@
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <windowsx.h>
#include "hw/mem/_vmem.h"
// Implementation of the vmem related function for Windows platforms.
// For now this probably does some assumptions on the CPU/platform.
// This implements the VLockedMemory interface, as defined in _vmem.h
// The implementation allows it to be empty (that is, to not lock memory).
void VLockedMemory::LockRegion(unsigned offset, unsigned size) {
//verify(offset + size < this->size && size != 0);
DWORD old;
VirtualProtect(&data[offset], size, PAGE_READONLY, &old);
}
void VLockedMemory::UnLockRegion(unsigned offset, unsigned size) {
//verify(offset + size <= this->size && size != 0);
DWORD old;
VirtualProtect(&data[offset], size, PAGE_READWRITE, &old);
}
static HANDLE mem_handle = INVALID_HANDLE_VALUE;
static char * base_alloc = NULL;
// Implement vmem initialization for RAM, ARAM, VRAM and SH4 context, fpcb etc.
// The function supports allocating 512MB or 4GB addr spaces.
// Plase read the POSIX implementation for more information. On Windows this is
// rather straightforward.
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr) {
// Firt let's try to allocate the in-memory file
mem_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX, 0);
// Now allocate the actual address space (it will be 64KB aligned on windows).
unsigned memsize = 512*1024*1024 + sizeof(Sh4RCB) + ARAM_SIZE_MAX;
base_alloc = (char*)VirtualAlloc(0, memsize, MEM_RESERVE, PAGE_NOACCESS);
// Calculate pointers now
*sh4rcb_addr = &base_alloc[0];
*vmem_base_addr = &base_alloc[sizeof(Sh4RCB)];
return MemType512MB;
}
// Just tries to wipe as much as possible in the relevant area.
void vmem_platform_destroy() {
VirtualFree(base_alloc, 0, MEM_RELEASE);
CloseHandle(mem_handle);
}
// Resets a chunk of memory by deleting its data and setting its protection back.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes) {
VirtualFree(ptr, size_bytes, MEM_DECOMMIT);
}
// Allocates a bunch of memory (page aligned and page-sized)
void vmem_platform_ondemand_page(void *address, unsigned size_bytes) {
verify(VirtualAlloc(address, size_bytes, MEM_COMMIT, PAGE_READWRITE));
}
/// Creates mappings to the underlying file including mirroring sections
void vmem_platform_create_mappings(const vmem_mapping *vmem_maps, unsigned nummaps) {
// Since this is tricky to get right in Windows (in posix one can just unmap sections and remap later)
// we unmap the whole thing only to remap it later.
// Unmap the whole section
VirtualFree(base_alloc, 0, MEM_RELEASE);
// Map the SH4CB block too
void *base_ptr = VirtualAlloc(base_alloc, sizeof(Sh4RCB), MEM_RESERVE, PAGE_NOACCESS);
verify(base_ptr == base_alloc);
void *cntx_ptr = VirtualAlloc((u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb), sizeof(Sh4RCB) - sizeof(p_sh4rcb->fpcb), MEM_COMMIT, PAGE_READWRITE);
verify(cntx_ptr == (u8*)p_sh4rcb + sizeof(p_sh4rcb->fpcb));
for (unsigned i = 0; i < nummaps; i++) {
unsigned address_range_size = vmem_maps[i].end_address - vmem_maps[i].start_address;
DWORD protection = vmem_maps[i].allow_writes ? (FILE_MAP_READ | FILE_MAP_WRITE) : FILE_MAP_READ;
if (!vmem_maps[i].memsize) {
// Unmapped stuff goes with a protected area or memory. Prevent anything from allocating here
void *ptr = VirtualAlloc(&virt_ram_base[vmem_maps[i].start_address], address_range_size, MEM_RESERVE, PAGE_NOACCESS);
verify(ptr == &virt_ram_base[vmem_maps[i].start_address]);
}
else {
// Calculate the number of mirrors
unsigned num_mirrors = (address_range_size) / vmem_maps[i].memsize;
verify((address_range_size % vmem_maps[i].memsize) == 0 && num_mirrors >= 1);
// Remap the views one by one
for (unsigned j = 0; j < num_mirrors; j++) {
unsigned offset = vmem_maps[i].start_address + j * vmem_maps[i].memsize;
void *ptr = MapViewOfFileEx(mem_handle, protection, 0, vmem_maps[i].memoffset,
vmem_maps[i].memsize, &virt_ram_base[offset]);
verify(ptr == &virt_ram_base[offset]);
}
}
}
}

View File

@ -1,6 +1,6 @@
#include "oslib\oslib.h"
#include "oslib\audiostream.h"
#include "imgread\common.h"
#include "oslib/oslib.h"
#include "oslib/audiostream.h"
#include "imgread/common.h"
#include "stdclass.h"
#include "cfg/cfg.h"
#include "xinput_gamepad.h"
@ -10,8 +10,8 @@
#include <windows.h>
#include <windowsx.h>
#include <Xinput.h>
#include "hw\maple\maple_cfg.h"
#include <xinput.h>
#include "hw/maple/maple_cfg.h"
#pragma comment(lib, "XInput9_1_0.lib")
PCHAR*
@ -148,12 +148,10 @@ LONG ExeptionHandler(EXCEPTION_POINTERS *ExceptionInfo)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
#ifndef TARGET_NO_NVMEM
else if (BM_LockedWrite(address))
{
return EXCEPTION_CONTINUE_EXECUTION;
}
#endif
#if FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X86
else if ( ngen_Rewrite((unat&)ep->ContextRecord->Eip,*(unat*)ep->ContextRecord->Esp,ep->ContextRecord->Eax) )
{
@ -188,8 +186,6 @@ u16 kcode[4] = { 0xffff, 0xffff, 0xffff, 0xffff };
u32 vks[4];
s8 joyx[4],joyy[4];
u8 rt[4],lt[4];
extern bool coin_chute;
extern bool naomi_test_button;
// Mouse
extern s32 mo_x_abs;
extern s32 mo_y_abs;
@ -200,6 +196,10 @@ extern f32 mo_wheel_delta;
// Keyboard
static Win32KeyboardDevice keyboard(0);
void ToggleFullscreen();
void UpdateInputState(u32 port)
{
/*
@ -220,12 +220,6 @@ void UpdateInputState(u32 port)
std::shared_ptr<XInputGamepadDevice> gamepad = XInputGamepadDevice::GetXInputDevice(port);
if (gamepad != NULL)
gamepad->ReadInput();
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
// FIXME
coin_chute = GetAsyncKeyState(VK_F8);
naomi_test_button = GetAsyncKeyState(VK_F7);
#endif
}
// Windows class name to register
@ -339,6 +333,14 @@ LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
keyboard.keyboard_input(keycode, message == WM_KEYDOWN);
}
break;
case WM_SYSKEYDOWN:
if (wParam == VK_RETURN)
if ((HIWORD(lParam) & KF_ALTDOWN))
ToggleFullscreen();
break;
case WM_CHAR:
keyboard.keyboard_character((char)wParam);
return 0;
@ -396,6 +398,45 @@ void* libPvr_GetRenderSurface()
return GetDC((HWND)window_win);
}
void ToggleFullscreen()
{
static RECT rSaved;
static bool fullscreen=false;
HWND hWnd = (HWND)window_win;
fullscreen = !fullscreen;
if (fullscreen)
{
GetWindowRect(hWnd, &rSaved);
MONITORINFO mi = { sizeof(mi) };
HMONITOR hmon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
if (GetMonitorInfo(hmon, &mi)) {
SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST);
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowPos(hWnd, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top,
SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_ASYNCWINDOWPOS);
}
}
else {
SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST);
SetWindowLongPtr(hWnd, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW | (window_maximized ? WS_MAXIMIZE : 0));
SetWindowPos(hWnd, NULL, rSaved.left, rSaved.top,
rSaved.right - rSaved.left, rSaved.bottom - rSaved.top,
SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_ASYNCWINDOWPOS|SWP_NOZORDER);
}
}
BOOL CtrlHandler( DWORD fdwCtrlType )
{
switch( fdwCtrlType )
@ -646,15 +687,31 @@ int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine
int argc=0;
wchar* cmd_line=GetCommandLineA();
wchar** argv=CommandLineToArgvA(cmd_line,&argc);
if(strstr(cmd_line,"NoConsole")==0)
for (int i = 0; i < argc; i++)
{
if (AllocConsole())
if (!stricmp(argv[i], "-console"))
{
freopen("CON","w",stdout);
freopen("CON","w",stderr);
freopen("CON","r",stdin);
if (AllocConsole())
{
freopen("CON", "w", stdout);
freopen("CON", "w", stderr);
freopen("CON", "r", stdin);
}
SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
}
else if (!stricmp(argv[i], "-log"))
{
const char *logfile;
if (i < argc - 1)
{
logfile = argv[i + 1];
i++;
}
else
logfile = "reicast-log.txt";
freopen(logfile, "w", stdout);
freopen(logfile, "w", stderr);
}
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE );
}
#endif
@ -662,14 +719,13 @@ int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine
ReserveBottomMemory();
SetupPath();
#ifndef __GNUC__
__try
#else
#ifdef _WIN64
AddVectoredExceptionHandler(1, ExeptionHandler);
#else
SetUnhandledExceptionFilter(&ExeptionHandler);
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&ExeptionHandler);
#endif
#ifndef __GNUC__
__try
#endif
{
int reicast_init(int argc, char* argv[]);
@ -742,90 +798,5 @@ void os_DoEvents()
}
}
//Windoze Code implementation of commong classes from here and after ..
//Thread class
cThread::cThread(ThreadEntryFP* function,void* prm)
{
Entry=function;
param=prm;
}
void cThread::Start()
{
hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Entry,param,0,NULL);
ResumeThread(hThread);
}
void cThread::WaitToEnd()
{
WaitForSingleObject(hThread,INFINITE);
}
//End thread class
//cResetEvent Calss
cResetEvent::cResetEvent(bool State,bool Auto)
{
hEvent = CreateEvent(
NULL, // default security attributes
Auto?FALSE:TRUE, // auto-reset event?
State?TRUE:FALSE, // initial state is State
NULL // unnamed object
);
}
cResetEvent::~cResetEvent()
{
//Destroy the event object ?
CloseHandle(hEvent);
}
void cResetEvent::Set()//Signal
{
#if defined(DEBUG_THREADS)
Sleep(rand() % 10);
#endif
SetEvent(hEvent);
}
void cResetEvent::Reset()//reset
{
#if defined(DEBUG_THREADS)
Sleep(rand() % 10);
#endif
ResetEvent(hEvent);
}
bool cResetEvent::Wait(u32 msec)//Wait for signal , then reset
{
#if defined(DEBUG_THREADS)
Sleep(rand() % 10);
#endif
return WaitForSingleObject(hEvent,msec) == WAIT_OBJECT_0;
}
void cResetEvent::Wait()//Wait for signal , then reset
{
#if defined(DEBUG_THREADS)
Sleep(rand() % 10);
#endif
WaitForSingleObject(hEvent,(u32)-1);
}
//End AutoResetEvent
void VArray2::LockRegion(u32 offset,u32 size)
{
//verify(offset+size<this->size);
verify(size!=0);
DWORD old;
VirtualProtect(((u8*)data)+offset , size, PAGE_READONLY,&old);
}
void VArray2::UnLockRegion(u32 offset,u32 size)
{
//verify(offset+size<=this->size);
verify(size!=0);
DWORD old;
VirtualProtect(((u8*)data)+offset , size, PAGE_READWRITE,&old);
}
int get_mic_data(u8* buffer) { return 0; }
int push_vmu_screen(u8* buffer) { return 0; }

View File

@ -1,4 +1,4 @@
#include <Xinput.h>
#include <xinput.h>
#include "input/gamepad_device.h"
#include "rend/gui.h"
@ -181,7 +181,6 @@ protected:
private:
void do_rumble(float power)
{
printf("do_rumble %f\n", power);
XINPUT_VIBRATION vib;
vib.wLeftMotorSpeed = (u16)(65535 * power);

View File

@ -3,54 +3,57 @@
xmlns:tools="http://schemas.android.com/tools">
<application android:name="com.reicast.emulator.Emulator">
<activity
android:name="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.GDI"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.gdi"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CHD"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.chd"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CDI"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.cdi"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CUE"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.cue"
android:scheme="file" />
</intent-filter>
</activity>
android:name="com.reicast.emulator.NativeGLActivity"/>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.GDI"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.gdi"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CHD"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.chd"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CDI"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.cdi"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CUE"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.cue"
android:scheme="file" />
</intent-filter>
</activity-alias>
</application>
</manifest>
</manifest>

View File

@ -53,14 +53,18 @@
<activity
android:name="com.reicast.emulator.NativeGLActivity"
android:configChanges="orientation|navigation|screenSize|screenLayout|uiMode|keyboard|keyboardHidden"
android:screenOrientation="sensorLandscape">
android:screenOrientation="sensorLandscape"
android:exported="true"/>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="tv.ouya.intent.category.GAME" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
</activity-alias>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"

View File

@ -228,22 +228,24 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (!JNIdc.guiIsOpen()) {
showMenu();
return true;
if (event.getRepeatCount() == 0) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (!JNIdc.guiIsOpen()) {
showMenu();
return true;
}
else if (JNIdc.guiIsContentBrowser()) {
finish();
return true;
}
}
else if (JNIdc.guiIsContentBrowser()) {
finish();
if (InputDeviceManager.getInstance().joystickButtonEvent(event.getDeviceId(), keyCode, true))
return true;
}
}
if (InputDeviceManager.getInstance().joystickButtonEvent(event.getDeviceId(), keyCode, true))
return true;
if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
return showMenu();
if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
return showMenu();
}
}
}
return super.onKeyDown(keyCode, event);
@ -296,7 +298,7 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat.
}
// Called from native code
private void generateErrorLog() {
protected void generateErrorLog() {
try {
new GenerateLogs(this).execute(getFilesDir().getAbsolutePath());
} catch (RuntimeException e) {

View File

@ -21,8 +21,7 @@ public final class JNIdc
public static native int send(int cmd, int opt);
public static native int data(int cmd, byte[] data);
public static native void rendinitNative(Surface surface, int w, int h);
public static native boolean rendframeNative();
public static native void rendinitNative(Surface surface);
public static native void rendinitJava(int w, int h);
public static native boolean rendframeJava();
public static native void rendtermJava();

View File

@ -19,8 +19,6 @@ import com.reicast.emulator.NativeGLActivity;
import com.reicast.emulator.config.Config;
public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback {
private Handler handler = new Handler();
private boolean surfaceReady = false;
private boolean paused = false;
VirtualJoystickDelegate vjoyDelegate;
@ -66,23 +64,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
if (NativeGLActivity.syms != null)
JNIdc.data(1, NativeGLActivity.syms);
startRendering();
}
private void startRendering() {
// Continuously render frames
handler.removeCallbacksAndMessages(null);
handler.postAtTime(new Runnable() {
@Override
public void run() {
if (!paused)
{
JNIdc.rendframeNative();
handler.post(this);
}
}
}, SystemClock.uptimeMillis() + 500);
}
@Override
@ -111,7 +92,7 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
//Log.i("reicast", "NativeGLView.surfaceChanged: " + w + "x" + h);
surfaceReady = true;
JNIdc.rendinitNative(surfaceHolder.getSurface(), w, h);
JNIdc.rendinitNative(surfaceHolder.getSurface());
Emulator.getCurrentActivity().handleStateChange(false);
}
@ -119,7 +100,7 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//Log.i("reicast", "NativeGLView.surfaceDestroyed");
surfaceReady = false;
JNIdc.rendinitNative(null, 0, 0);
JNIdc.rendinitNative(null);
Emulator.getCurrentActivity().handleStateChange(true);
}
@ -142,7 +123,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
requestFocus();
JNIdc.resume();
}
startRendering();
}
@TargetApi(19)

View File

@ -15,7 +15,7 @@ import com.reicast.emulator.periph.InputDeviceManager;
import com.reicast.emulator.periph.VJoy;
public class VirtualJoystickDelegate {
private Vibrator vib;
private VibratorThread vibratorThread;
private boolean editVjoyMode = false;
private int selectedVjoyElement = -1;
@ -39,7 +39,10 @@ public class VirtualJoystickDelegate {
public VirtualJoystickDelegate(View view) {
this.view = view;
this.context = view.getContext();
vib = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
vibratorThread = new VibratorThread(context);
vibratorThread.start();
readCustomVjoyValues();
scaleGestureDetector = new ScaleGestureDetector(context, new OscOnScaleGestureListener());
}
@ -224,8 +227,9 @@ public class VirtualJoystickDelegate {
if (y > vjoy[j][1] && y <= (vjoy[j][1] + vjoy[j][3])) {
if (vjoy[j][4] >= -2) {
if (vjoy[j][5] == 0)
if (!editVjoyMode && Emulator.vibrationDuration > 0)
vib.vibrate(Emulator.vibrationDuration);
if (!editVjoyMode) {
vibratorThread.vibrate();
}
vjoy[j][5] = 2;
}
@ -397,4 +401,51 @@ public class VirtualJoystickDelegate {
selectedVjoyElement = -1;
}
}
private class VibratorThread extends Thread
{
private Vibrator vibrator;
private boolean vibrate = false;
private boolean stopping = false;
VibratorThread(Context context) {
vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
}
@Override
public void run() {
while (!stopping) {
boolean doVibrate;
synchronized (this) {
doVibrate = false;
try {
this.wait();
} catch (InterruptedException e) {
}
if (vibrate) {
doVibrate = true;
vibrate = false;
}
}
if (doVibrate)
vibrator.vibrate(Emulator.vibrationDuration);
}
}
public void stopVibrator() {
synchronized (this) {
stopping = true;
notify();
}
}
public void vibrate() {
if (Emulator.vibrationDuration > 0) {
synchronized (this) {
vibrate = true;
notify();
}
}
}
}
}

View File

@ -22,6 +22,7 @@ WEBUI := 1
USE_GLES := 1
CHD5_LZMA := 1
CHD5_FLAC := 1
USE_MODEM := 1
ifneq ($(TARGET_ARCH_ABI),armeabi-v7a)
NOT_ARM := 1
@ -112,6 +113,8 @@ else
endif
endif
$(LOCAL_SRC_FILES): $(VERSION_HEADER)
#
# android has poor support for hardfp calling.
# r9b+ is required, and it only works for internal calls

View File

@ -20,7 +20,7 @@
#include "hw/maple/maple_devs.h"
#include "hw/maple/maple_if.h"
#include "hw/naomi/naomi_cart.h"
#include "oslib/audiobackend_android.h"
#include "oslib/audiostream.h"
#include "imgread/common.h"
#include "rend/gui.h"
#include "cfg/cfg.h"
@ -91,8 +91,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,j
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_send(JNIEnv *env,jobject obj,jint id, jint v) __attribute__((visibility("default")));
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env,jobject obj,jint id, jbyteArray d) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface, jint w, jint h) __attribute__((visibility("default")));
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeNative(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv *env, jobject obj, jint w, jint h) __attribute__((visibility("default")));
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeJava(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendtermJava(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
@ -404,35 +403,57 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env, job
extern void gl_swap();
extern void egl_stealcntx();
volatile static bool render_running;
volatile static bool render_reinit;
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeNative(JNIEnv *env,jobject obj)
void *render_thread_func(void *)
{
if (g_window == NULL)
return false;
if (!egl_makecurrent())
return false;
jboolean ret = (jboolean)rend_single_frame();
if (ret)
gl_swap();
return ret;
render_running = true;
rend_init_renderer();
while (render_running) {
if (render_reinit)
{
render_reinit = false;
rend_init_renderer();
}
else
if (!egl_makecurrent())
break;;
bool ret = rend_single_frame();
if (ret)
gl_swap();
}
egl_makecurrent();
rend_term_renderer();
ANativeWindow_release(g_window);
g_window = NULL;
render_running = false;
return NULL;
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface, jint width, jint height)
static cThread render_thread(render_thread_func, NULL);
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface)
{
if (g_window != NULL)
{
egl_makecurrent();
rend_term_renderer();
ANativeWindow_release(g_window);
g_window = NULL;
}
if (surface != NULL)
{
if (render_thread.hThread != NULL)
{
if (surface == NULL)
{
render_running = false;
render_thread.WaitToEnd();
}
else
render_reinit = true;
}
else if (surface != NULL)
{
g_window = ANativeWindow_fromSurface(env, surface);
rend_init_renderer();
screen_width = width;
screen_height = height;
}
render_thread.Start();
}
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv * env, jobject obj, jint width, jint height)
@ -526,9 +547,13 @@ audiobackend_t audiobackend_android = {
"Android Audio", // Name
&androidaudio_init,
&androidaudio_push,
&androidaudio_term
&androidaudio_term,
NULL
};
static bool android = RegisterAudioBackend(&audiobackend_android);
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_AudioBackend_setInstance(JNIEnv *env, jobject obj, jobject instance)
{
if (g_audioBackend != NULL)
@ -568,7 +593,7 @@ void os_DebugBreak()
raise(SIGABRT);
//pthread_exit(NULL);
// Attach debugger here to figure out what went wrong
for(;;) ;
}

View File

@ -3,7 +3,10 @@
android:name="com.reicast.emulator.Emulator">
<activity
android:name="com.reicast.emulator.MainActivity">
android:name="com.reicast.emulator.NativeGLActivity"/>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -61,6 +64,6 @@
android:pathPattern=".*\\.7z"
android:scheme="file" />
</intent-filter>
</activity>
</activity-alias>
</application>
</manifest>

View File

@ -266,6 +266,7 @@
AEE6278E2224762000EC7E89 /* imgui_impl_opengl3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6278B2224762000EC7E89 /* imgui_impl_opengl3.cpp */; };
AEE6279422247C0A00EC7E89 /* gui_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6279222247C0A00EC7E89 /* gui_util.cpp */; };
AEE6279622247C2B00EC7E89 /* keyboard_device.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEE6279522247C2B00EC7E89 /* keyboard_device.cpp */; };
AEF2564822886A2E00348550 /* posix_vmem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEF2564722886A2E00348550 /* posix_vmem.cpp */; };
AEFF7ECC214AEC810068CE11 /* modem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEFF7EC7214AEC800068CE11 /* modem.cpp */; };
AEFF7F4D214D9D590068CE11 /* pico_arp.c in Sources */ = {isa = PBXBuildFile; fileRef = AEFF7EFA214D9D590068CE11 /* pico_arp.c */; };
AEFF7F4E214D9D590068CE11 /* pico_dev_ppp.c in Sources */ = {isa = PBXBuildFile; fileRef = AEFF7EFE214D9D590068CE11 /* pico_dev_ppp.c */; };
@ -803,6 +804,7 @@
AEE6279222247C0A00EC7E89 /* gui_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gui_util.cpp; sourceTree = "<group>"; };
AEE6279322247C0A00EC7E89 /* gui_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gui_util.h; sourceTree = "<group>"; };
AEE6279522247C2B00EC7E89 /* keyboard_device.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = keyboard_device.cpp; sourceTree = "<group>"; };
AEF2564722886A2E00348550 /* posix_vmem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = posix_vmem.cpp; sourceTree = "<group>"; };
AEFF7EC7214AEC800068CE11 /* modem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = modem.cpp; sourceTree = "<group>"; };
AEFF7EC8214AEC800068CE11 /* modem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modem.h; sourceTree = "<group>"; };
AEFF7EC9214AEC800068CE11 /* modem_regs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modem_regs.h; sourceTree = "<group>"; };
@ -1556,6 +1558,7 @@
84B7BE661B72720100F9733F /* context.cpp */,
84B7BE671B72720100F9733F /* context.h */,
84B7BE681B72720100F9733F /* nixprof */,
AEF2564722886A2E00348550 /* posix_vmem.cpp */,
84B7BE6A1B72720100F9733F /* typedefs.h */,
);
name = linux;
@ -2199,7 +2202,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"const char *version = \\\"`git describe --tags --always`\\\";\" > $SRCROOT/../../../core/version/version.cpp\necho \"const char *git_hash = \\\"`git rev-parse --short HEAD`\\\";\" >> $SRCROOT/../../../core/version/version.cpp\necho \"const char *build_date = \\\"`date '+%Y-%m-%d %H:%M:%S %Z'`\\\";\" >> $SRCROOT/../../../core/version/version.cpp\n";
shellScript = "echo \"#define REICAST_VERSION \\\"`git describe --tags --always`\\\"\" > $SRCROOT/../../../core/version.h\necho \"#define GIT_HASH \\\"`git rev-parse --short HEAD`\\\"\" >> $SRCROOT/../../../core/version.h\necho \"#define BUILD_DATE \\\"`date '+%Y-%m-%d %H:%M:%S %Z'`\\\"\" >> $SRCROOT/../../../core/version.h\n";
};
/* End PBXShellScriptBuildPhase section */
@ -2310,6 +2313,7 @@
84B7BF131B72720200F9733F /* zip_unchange_all.c in Sources */,
84B7BF541B72720200F9733F /* sh4_interrupts.cpp in Sources */,
AE2A2D7F21D6851E004B308D /* 7zFile.c in Sources */,
AEF2564822886A2E00348550 /* posix_vmem.cpp in Sources */,
84B7BF6B1B72720200F9733F /* audiostream.cpp in Sources */,
84B7BEFB1B72720200F9733F /* zip_get_file_comment.c in Sources */,
84B7BF301B72720200F9733F /* holly_intc.cpp in Sources */,
@ -2546,6 +2550,7 @@
TARGET_NO_AREC,
XBYAK_NO_OP_NAMES,
TARGET_NO_OPENMP,
ENABLE_MODEM,
CHD5_LZMA,
_7ZIP_ST,
CHD5_FLAC,
@ -2602,6 +2607,7 @@
TARGET_NO_AREC,
XBYAK_NO_OP_NAMES,
TARGET_NO_OPENMP,
ENABLE_MODEM,
CHD5_LZMA,
_7ZIP_ST,
CHD5_FLAC,

Some files were not shown because too many files have changed in this diff Show More