From 79c4d4343ef401c5d5489972c7a7e434f441578a Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 27 Oct 2024 21:52:25 +0200 Subject: [PATCH] merge from libretro got tired of all the conflicts --- .gitmodules | 3 + Makefile | 36 +- Makefile.libretro | 691 +++++++++++++++++++++++++++++- deps/mman | 1 + include/mman/sys/mman.h | 1 + jni/Android.mk | 265 +++++++++++- plugins/dfsound/out.c | 2 +- plugins/dfxvideo/gpulib_if.c | 24 ++ plugins/gpu-gles/gpulib_if.c | 8 + plugins/gpu_neon/psx_gpu_if.c | 8 + plugins/gpulib/gpu.c | 18 +- plugins/gpulib/gpu.h | 5 + plugins/gpulib/gpulib_thread_if.c | 563 ++++++++++++++++++++++++ plugins/gpulib/gpulib_thread_if.h | 42 ++ 14 files changed, 1660 insertions(+), 7 deletions(-) create mode 160000 deps/mman create mode 100644 include/mman/sys/mman.h create mode 100644 plugins/gpulib/gpulib_thread_if.c create mode 100644 plugins/gpulib/gpulib_thread_if.h diff --git a/.gitmodules b/.gitmodules index d4665d30..e96248d9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "deps/libretro-common"] path = deps/libretro-common url = https://github.com/libretro/libretro-common.git +[submodule "deps/mman"] + path = deps/mman + url = https://github.com/witwall/mman-win32 diff --git a/Makefile b/Makefile index d2977913..39b5fbaf 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ CFLAGS += -ggdb endif ifneq ($(DEBUG), 1) CFLAGS += -O2 -ifndef ASSERTS +ifneq ($(ASSERTS), 1) CFLAGS += -DNDEBUG endif endif @@ -77,6 +77,28 @@ OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cdrom-async.o \ libpcsxcore/sio.o libpcsxcore/spu.o libpcsxcore/gpu.o OBJS += libpcsxcore/gte.o libpcsxcore/gte_nf.o libpcsxcore/gte_divider.o #OBJS += libpcsxcore/debug.o libpcsxcore/socket.o libpcsxcore/disr3000a.o + +ifeq ($(WANT_ZLIB),1) +ZLIB_DIR = deps/libchdr/deps/zlib-1.3.1 +CFLAGS += -I$(ZLIB_DIR) +OBJS += $(ZLIB_DIR)/adler32.o \ + $(ZLIB_DIR)/compress.o \ + $(ZLIB_DIR)/crc32.o \ + $(ZLIB_DIR)/deflate.o \ + $(ZLIB_DIR)/gzclose.o \ + $(ZLIB_DIR)/gzlib.o \ + $(ZLIB_DIR)/gzread.o \ + $(ZLIB_DIR)/gzwrite.o \ + $(ZLIB_DIR)/infback.o \ + $(ZLIB_DIR)/inffast.o \ + $(ZLIB_DIR)/inflate.o \ + $(ZLIB_DIR)/inftrees.o \ + $(ZLIB_DIR)/trees.o \ + $(ZLIB_DIR)/uncompr.o \ + $(ZLIB_DIR)/zutil.o +$(ZLIB_DIR)/%.o: CFLAGS += -DHAVE_UNISTD_H +endif + ifeq "$(ARCH)" "arm" OBJS += libpcsxcore/gte_arm.o endif @@ -209,6 +231,7 @@ endif # builtin gpu OBJS += plugins/gpulib/gpu.o plugins/gpulib/vout_pl.o ifeq "$(BUILTIN_GPU)" "neon" +CFLAGS += -DGPU_NEON OBJS += plugins/gpu_neon/psx_gpu_if.o plugins/gpu_neon/psx_gpu_if.o: CFLAGS += -DNEON_BUILD -DTEXTURE_CACHE_4BPP -DTEXTURE_CACHE_8BPP plugins/gpu_neon/psx_gpu_if.o: plugins/gpu_neon/psx_gpu/*.c @@ -222,13 +245,20 @@ frontend/menu.o frontend/plugin_lib.o: CFLAGS += -DBUILTIN_GPU_NEON endif endif ifeq "$(BUILTIN_GPU)" "peops" +CFLAGS += -DGPU_PEOPS # note: code is not safe for strict-aliasing? (Castlevania problems) plugins/dfxvideo/gpulib_if.o: CFLAGS += -fno-strict-aliasing plugins/dfxvideo/gpulib_if.o: plugins/dfxvideo/prim.c plugins/dfxvideo/soft.c OBJS += plugins/dfxvideo/gpulib_if.o +ifeq "$(THREAD_RENDERING)" "1" +CFLAGS += -DTHREAD_RENDERING +OBJS += plugins/gpulib/gpulib_thread_if.o +endif endif ifeq "$(BUILTIN_GPU)" "unai" +CFLAGS += -DGPU_UNAI +CFLAGS += -DUSE_GPULIB=1 OBJS += plugins/gpu_unai/gpulib_if.o ifeq "$(ARCH)" "arm" OBJS += plugins/gpu_unai/gpu_arm.o @@ -249,7 +279,7 @@ CC_LINK = $(CXX) endif # libchdr -#ifeq "$(HAVE_CHD)" "1" +ifeq "$(HAVE_CHD)" "1" LCHDR = deps/libchdr LCHDR_LZMA = $(LCHDR)/deps/lzma-24.05 LCHDR_ZSTD = $(LCHDR)/deps/zstd-1.5.6/lib @@ -283,7 +313,7 @@ $(LCHDR_ZSTD)/decompress/%.o: CFLAGS += -I$(LCHDR_ZSTD) $(LCHDR)/src/%.o: CFLAGS += -I$(LCHDR_ZSTD) libpcsxcore/cdriso.o: CFLAGS += -Wno-unused-function CFLAGS += -DHAVE_CHD -I$(LCHDR)/include -#endif +endif # frontend/gui OBJS += frontend/cspace.o diff --git a/Makefile.libretro b/Makefile.libretro index 03ccff7e..6bacb3f4 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -1 +1,690 @@ -$(error This file is unmaintained. Please use the libretro fork: https://github.com/libretro/pcsx_rearmed) +# Makefile for PCSX ReARMed (libretro) + +DEBUG ?= 0 +WANT_ZLIB ?= 1 +HAVE_CHD ?= 1 +HAVE_PHYSICAL_CDROM ?= 1 +USE_ASYNC_CDROM ?= 1 +USE_LIBRETRO_VFS ?= 0 +NDRC_THREAD ?= 1 + +# Dynarec options: lightrec, ari64 +DYNAREC ?= lightrec + +ifeq ($(platform),) + platform = unix + ifeq ($(shell uname -a),) + platform = win + else ifneq ($(findstring MINGW,$(shell uname -a)),) + platform = win + else ifneq ($(findstring Darwin,$(shell uname -a)),) + platform = osx + else ifneq ($(findstring win,$(shell uname -a)),) + platform = win + endif +endif + +CC ?= gcc +CXX ?= g++ +AS ?= as +LD ?= ld +CFLAGS ?= + +# early compiler overrides +ifeq ($(platform),ios-arm64) + CC = cc -arch arm64 -isysroot $(IOSSDK) + CXX = c++ -arch arm64 -isysroot $(IOSSDK) +else ifneq (,$(findstring ios,$(platform))) + CC = cc -arch armv7 -isysroot $(IOSSDK) + CXX = c++ -arch armv7 -isysroot $(IOSSDK) +else ifeq ($(platform), tvos-arm64) + ifeq ($(IOSSDK),) + IOSSDK := $(shell xcodebuild -version -sdk appletvos Path) + endif + CC = cc -arch arm64 -isysroot $(IOSSDK) + CXX = c++ -arch arm64 -isysroot $(IOSSDK) +else ifeq ($(platform), osx) + ifeq ($(CROSS_COMPILE),1) + TARGET_RULE = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT) + CFLAGS += $(TARGET_RULE) + CXXFLAGS += $(TARGET_RULE) + LDFLAGS += $(TARGET_RULE) + endif +else ifeq ($(platform), psl1ght) + ifeq ($(strip $(PS3DEV)),) + $(error "PS3DEV env var is not set") + endif + CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT) + AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT) +else ifeq ($(platform), psp1) + CC = psp-gcc$(EXE_EXT) + AR = psp-ar$(EXE_EXT) + LD = psp-ld$(EXE_EXT) +else ifeq ($(platform), vita) + CC = arm-vita-eabi-gcc$(EXE_EXT) + AR = arm-vita-eabi-ar$(EXE_EXT) + LD = arm-vita-eabi-ld$(EXE_EXT) + OBJCOPY = arm-vita-eabi-objcopy$(EXE_EXT) +else ifeq ($(platform), ctr) + ifeq ($(strip $(DEVKITARM)),) + $(error "DEVKITARM env var is not set") + endif + CC = $(DEVKITARM)/bin/arm-none-eabi-gcc$(EXE_EXT) + CXX = $(DEVKITARM)/bin/arm-none-eabi-g++$(EXE_EXT) + AR = $(DEVKITARM)/bin/arm-none-eabi-ar$(EXE_EXT) + LD = $(DEVKITARM)/bin/arm-none-eabi-ld$(EXE_EXT) + OBJCOPY = $(DEVKITARM)/bin/arm-none-eabi-objcopy$(EXE_EXT) +else ifeq ($(platform), libnx) + export DEPSDIR := $(CURDIR)/ + ifeq ($(strip $(DEVKITPRO)),) + $(error "DEVKITPRO env var is not set") + endif + include $(DEVKITPRO)/libnx/switch_rules + SHELL := PATH=$(PATH) $(SHELL) + LD = $(PREFIX)ld +else ifeq ($(platform), xenon) + CC = xenon-gcc$(EXE_EXT) + AR = xenon-ar$(EXE_EXT) + LD = xenon-ld$(EXE_EXT) +else ifneq (,$(filter $(platform),ngc wii wiiu)) + ifeq ($(strip $(DEVKITPPC)),) + $(error "DEVKITPPC env var is not set") + endif + CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) + CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT) + AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) + LD = $(DEVKITPPC)/bin/powerpc-eabi-ld$(EXE_EXT) +else ifeq ($(platform), qnx) + CC = qcc -Vgcc_ntoarmv7le +else ifeq ($(platform), miyoo) + CC = /opt/miyoo/usr/bin/arm-linux-gcc + CXX = /opt/miyoo/usr/bin/arm-linux-g++ +endif +CC_AS ?= $(CC) + +# workaround wrong owner in libretro infra +GIT_VERSION1 := $(shell test -d /builds/libretro/pcsx_rearmed && git rev-parse --short HEAD 2>&1) +ifneq ($(findstring dubious ownership,$(GIT_VERSION1)),) +DUMMY := $(shell git config --global --add safe.directory /builds/libretro/pcsx_rearmed) +endif + +TARGET_NAME := pcsx_rearmed +ARCH_DETECTED := $(shell $(CC) $(CFLAGS) -dumpmachine | awk -F- '{print $$1}') +GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)" +ifneq ($(GIT_VERSION)," unknown") + CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" +endif +ifneq ($(WANT_ZLIB),1) +LIBZ := -lz +endif +LIBPTHREAD := -lpthread +ifneq ($(findstring Haiku,$(shell uname -s)),) +LIBDL := -lroot -lnetwork +else +LIBDL := -ldl +endif +LIBM := -lm +MMAP_WIN32 = 0 +EXTRA_LDFLAGS = + +# select some defaults +ifneq (,$(findstring $(ARCH_DETECTED),arm aarch64)) + DYNAREC = ari64 +ifneq (,$(shell $(CC) -E -dD $(CFLAGS) include/arm_features.h | grep 'define __thumb__')) + # must disable thumb as ari64 can't handle it + CFLAGS += -marm +endif +ifneq (,$(shell $(CC) -E -dD $(CFLAGS) include/arm_features.h | grep 'HAVE_NEON32')) + BUILTIN_GPU = neon +endif +endif +ifneq (,$(filter $(ARCH_DETECTED),i686 x86_64 arm64 aarch64)) + BUILTIN_GPU = neon +endif + +# platform specific options + +# Unix +ifeq ($(platform), unix) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + THREAD_RENDERING = 1 +ifeq ($(shell uname),Linux) + LIGHTREC_CUSTOM_MAP := 1 +endif + +# ODROIDN2 +else ifneq (,$(findstring CortexA73_G12B,$(platform))) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + ARCH = arm64 + BUILTIN_GPU = neon + HAVE_NEON = 1 + DYNAREC = ari64 + CFLAGS += -fomit-frame-pointer -ffast-math -DARM + CFLAGS += -march=armv8-a+crc -mcpu=cortex-a73 -mtune=cortex-a73.cortex-a53 + +# ALLWINNER H5 +else ifneq (,$(findstring h5,$(platform))) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + ARCH = arm64 + BUILTIN_GPU = neon + HAVE_NEON = 1 + DYNAREC = ari64 + CFLAGS += -fomit-frame-pointer -ffast-math -DARM + CFLAGS += -march=armv8-a+crc -mcpu=cortex-a53 -mtune=cortex-a53 + +else ifeq ($(platform), linux-portable) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC -nostdlib + EXTRA_LDFLAGS += -fPIC -nostdlib + LIBZ := + LIBPTHREAD := + LIBDL := + LIBM := + NO_UNDEF_CHECK = 1 + LIGHTREC_CUSTOM_MAP := 1 + +# OS X +else ifeq ($(platform), osx) + DYNAREC := 0 + TARGET := $(TARGET_NAME)_libretro.dylib + fpic := -fPIC + MACSOSVER = `sw_vers -productVersion | cut -d. -f 1` + OSXVER = `sw_vers -productVersion | cut -d. -f 2` + OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"` + ifeq ($(OSX_LT_MAVERICKS),YES) + fpic += -mmacosx-version-min=10.1 + endif + CFLAGS += $(ARCHFLAGS) + CXXFLAGS += $(ARCHFLAGS) + LDFLAGS += $(ARCHFLAGS) + HAVE_PHYSICAL_CDROM = 0 + FSECTIONS_LDFLAGS = -Wl,-dead_strip + +# iOS +else ifneq (,$(findstring ios,$(platform))) + TARGET := $(TARGET_NAME)_libretro_ios.dylib + MINVERSION := +ifeq ($(DYNAREC),lightrec) + # Override + DYNAREC := 0 +endif + fpic := -fPIC + + ifeq ($(IOSSDK),) + IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path) + endif + + CFLAGS += -DIOS +ifeq ($(platform),ios-arm64) + ARCH := arm64 + BUILTIN_GPU = neon + HAVE_NEON = 1 + DYNAREC = 0 +else + ARCH := arm + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + BUILTIN_GPU = neon + CFLAGS += -marm -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon + ASFLAGS += -marm -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon +endif + HAVE_PHYSICAL_CDROM = 0 + CC_AS = perl ./tools/gas-preprocessor.pl $(CC) +ifeq ($(platform),$(filter $(platform),ios9 ios-arm64)) + MINVERSION = -miphoneos-version-min=8.0 +else + MINVERSION = -miphoneos-version-min=5.0 +endif + CFLAGS += $(MINVERSION) + FSECTIONS_LDFLAGS = -Wl,-dead_strip + +else ifeq ($(platform), tvos-arm64) + TARGET := $(TARGET_NAME)_libretro_tvos.dylib + MINVERSION := +ifeq ($(DYNAREC),lightrec) + # Override + DYNAREC := 0 +endif + fpic := -fPIC + + ifeq ($(IOSSDK),) + IOSSDK := $(shell xcodebuild -version -sdk appletvos Path) + endif + + CFLAGS += -DIOS -DTVOS + ARCH := arm64 + BUILTIN_GPU = neon + HAVE_NEON = 1 + DYNAREC = 0 + HAVE_PHYSICAL_CDROM = 0 + CC_AS = perl ./tools/gas-preprocessor.pl $(CC) + MINVERSION = -mappletvos-version-min=11.0 + CFLAGS += $(MINVERSION) + FSECTIONS_LDFLAGS = -Wl,-dead_strip + +# Nintendo Switch (libnx) +else ifeq ($(platform), libnx) + TARGET := $(TARGET_NAME)_libretro_$(platform).a + ARCH := arm64 + HAVE_VFS_FD = 0 + CFLAGS += -O3 -fomit-frame-pointer -ffast-math -I$(DEVKITPRO)/libnx/include/ -fPIE + CFLAGS += -specs=$(DEVKITPRO)/libnx/switch.specs -DNO_DYLIB -D__arm64__ -D__ARM_NEON__ + CFLAGS += -D__SWITCH__ -DSWITCH -DHAVE_LIBNX + CFLAGS += -DARM -D__aarch64__=1 -march=armv8-a -mtune=cortex-a57 -mtp=soft -DHAVE_INTTYPES -DLSB_FIRST -ffast-math -mcpu=cortex-a57+crc+fp+simd + CFLAGS += -ftree-vectorize + CFLAGS += -Ifrontend/switch + NO_POSIX_MEMALIGN := 1 + NO_PTHREAD=1 + NO_MMAP := 1 # for psxmem + LIBPTHREAD := + WANT_ZLIB = 0 + PARTIAL_LINKING = 1 + BUILTIN_GPU = neon + HAVE_NEON = 1 + DYNAREC = ari64 + HAVE_PHYSICAL_CDROM = 0 + +# Lakka Switch (arm64) +else ifeq ($(platform), arm64) + TARGET := $(TARGET_NAME)_libretro.so + ARCH := arm64 + BUILTIN_GPU = neon + HAVE_NEON = 1 + DYNAREC = ari64 + HAVE_PHYSICAL_CDROM = 0 + fpic := -fPIC + CFLAGS := $(filter-out -O2, $(CFLAGS)) + CFLAGS += -O3 -ftree-vectorize + +# Lightweight PS3 Homebrew SDK +else ifeq ($(platform), psl1ght) + TARGET := $(TARGET_NAME)_libretro_psl1ght.a + CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ + CFLAGS += -DNO_DYLIB + NO_UNDEF_CHECK := 1 + STATIC_LINKING := 1 + NO_MMAP := 1 + NO_PTHREAD := 1 + LIBPTHREAD := + LIBDL := + NEED_SYSCONF := 1 + HAVE_PHYSICAL_CDROM = 0 + USE_ASYNC_CDROM = 0 + +# PSP +else ifeq ($(platform), psp1) + TARGET := $(TARGET_NAME)_libretro_psp1.a + CFLAGS += -DPSP -G0 + HAVE_PHYSICAL_CDROM = 0 + +# Vita +else ifeq ($(platform), vita) + TARGET := $(TARGET_NAME)_libretro_vita.a + CFLAGS += -DVITA + CFLAGS += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon -marm + CFLAGS += -fsingle-precision-constant -mword-relocations -fno-unwind-tables + CFLAGS += -fno-asynchronous-unwind-tables -ftree-vectorize -funroll-loops + CFLAGS += -fno-optimize-sibling-calls + CFLAGS += -I$(VITASDK)/include -Ifrontend/vita + CFLAGS += -DNO_DYLIB + CFLAGS_LAST += -O3 + ASFLAGS += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon + + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + BUILTIN_GPU = neon + + DYNAREC = ari64 + ARCH = arm + PARTIAL_LINKING = 1 + NO_PTHREAD=1 + NO_POSIX_MEMALIGN := 1 + HAVE_PHYSICAL_CDROM = 0 + +# CTR(3DS) +else ifeq ($(platform), ctr) + ifeq ($(strip $(CTRULIB)),) + $(error "CTRULIB env var is not set") + endif + TARGET := $(TARGET_NAME)_libretro_ctr.a + CFLAGS += -DARM11 -D_3DS -D__3DS__ + CFLAGS += -DNO_DYLIB -DGPU_UNAI_USE_FLOATMATH -DGPU_UNAI_USE_FLOAT_DIV_MULTINV + CFLAGS += -march=armv6k -mtune=mpcore -mfloat-abi=hard -marm -mfpu=vfp -mtp=soft + CFLAGS += -Wall -mword-relocations + CFLAGS += -fomit-frame-pointer + CFLAGS_LAST += -O3 + # CFLAGS += -funroll-loops # ~500K of bloat + CFLAGS += -Ifrontend/3ds -I$(CTRULIB)/include + CFLAGS += -Werror=implicit-function-declaration + CFLAGS += -DHAVE_UNISTD_H + CFLAGS += -DZ7_DECL_Int32_AS_long + CFLAGS += -DUSE_CTRULIB_2 + + OBJS += deps/arm-mem/memcpymove-v6l.o + OBJS += deps/arm-mem/memset-v6l.o + OBJS += frontend/3ds/utils.o + + BUILTIN_GPU = unai + THREAD_RENDERING = 1 + DYNAREC = ari64 + ARCH = arm + HAVE_NEON = 0 + PARTIAL_LINKING = 1 + WANT_ZLIB = 0 + NO_POSIX_MEMALIGN := 1 + NO_MMAP := 1 # for psxmem + HAVE_PHYSICAL_CDROM = 0 + +# Xbox 360 +else ifeq ($(platform), xenon) + TARGET := $(TARGET_NAME)_libretro_xenon360.a + CFLAGS += -D__LIBXENON__ -m32 -D__ppc__ + HAVE_PHYSICAL_CDROM = 0 + +# Nintendo GC/Wii/WiiU +else ifneq (,$(filter $(platform),ngc wii wiiu)) + TARGET := $(TARGET_NAME)_libretro_$(platform).a + ifeq ($(platform), ngc) + CFLAGS += -DHW_DOL -mogc + NEED_SYSCONF := 1 + else ifeq ($(platform), wii) + CFLAGS += -DHW_RVL -mrvl + NEED_SYSCONF := 1 + else ifeq ($(platform), wiiu) + # -mwup was removed in newer devkitPPC versions + CFLAGS += -DHW_WUP + CFLAGS += -I frontend/wiiu + CFLAGS += -DZ7_DECL_Int32_AS_long + LIGHTREC_CUSTOM_MAP := 1 + LIGHTREC_CUSTOM_MAP_OBJ := libpcsxcore/lightrec/mem_wiiu.o + LIGHTREC_CODE_INV := 1 + endif + ARCH = powerpc + BUILTIN_GPU = peops + CFLAGS += -D__ppc__ -D__powerpc__ + CFLAGS += -DGEKKO -mcpu=750 -meabi -mhard-float + CFLAGS += -DNO_DYLIB + STATIC_LINKING := 1 + THREAD_RENDERING := 0 + NO_PTHREAD := 1 + NO_MMAP := 1 + NO_POSIX_MEMALIGN := 1 + LIBDL := + LIBPTHREAD := + LIBRT := + HAVE_PHYSICAL_CDROM = 0 + USE_ASYNC_CDROM = 0 + +# QNX +else ifeq ($(platform), qnx) + TARGET := $(TARGET_NAME)_libretro_qnx.so + fpic := -fPIC + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + DYNAREC = ari64 + BUILTIN_GPU = neon + ARCH = arm + CFLAGS += -D__BLACKBERRY_QNX__ -marm -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp + ASFLAGS += -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp + MAIN_LDLIBS += -lsocket + LIBPTHREAD := + LIBDL := + LIBM := + HAVE_PHYSICAL_CDROM = 0 + +#Raspberry Pi 1 +else ifeq ($(platform), rpi1) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + CFLAGS += -marm -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard + ASFLAGS += -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard + HAVE_NEON = 0 + ARCH = arm + BUILTIN_GPU = unai + DYNAREC = ari64 + +#Raspberry Pi 2 +else ifeq ($(platform), rpi2) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + CFLAGS += -marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard + ASFLAGS += -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + ARCH = arm + BUILTIN_GPU = neon + DYNAREC = ari64 + +#Raspberry Pi 3 +else ifeq ($(platform), rpi3) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + CFLAGS += -marm -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard + ASFLAGS += -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + ARCH = arm + BUILTIN_GPU = neon + DYNAREC = ari64 + +#Raspberry Pi 3 with a 64bit GNU/Linux OS +else ifeq ($(platform), rpi3_64) + TARGET := $(TARGET_NAME)_libretro.so + ARCH := arm64 + BUILTIN_GPU = neon + HAVE_NEON = 1 + DYNAREC = ari64 + fpic := -fPIC + CFLAGS += -march=armv8-a+crc+simd -mtune=cortex-a53 -ftree-vectorize + +#Raspberry Pi 4 with a 32bit GNU/Linux OS +else ifeq ($(platform), rpi4) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + CFLAGS += -marm -mcpu=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard + ASFLAGS += -mcpu=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + ARCH = arm + BUILTIN_GPU = neon + DYNAREC = ari64 + +#Raspberry Pi 4 with a 64bit GNU/Linux OS +else ifeq ($(platform), rpi4_64) + TARGET := $(TARGET_NAME)_libretro.so + ARCH := arm64 + BUILTIN_GPU = neon + HAVE_NEON = 1 + DYNAREC = ari64 + fpic := -fPIC + CFLAGS += -march=armv8-a+crc+simd -mtune=cortex-a72 -ftree-vectorize + +# Classic Platforms #################### +# Platform affix = classic__<µARCH> +# Help at https://modmyclassic.com/comp + +# (armv7 a7, hard point, neon based) ### +# NESC, SNESC, C64 mini +else ifeq ($(platform), classic_armv7_a7) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + CFLAGS += -Ofast \ + -flto=auto -fuse-linker-plugin \ + -fno-stack-protector -fno-ident -fomit-frame-pointer \ + -falign-functions=1 -falign-jumps=1 -falign-loops=1 \ + -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \ + -fmerge-all-constants -fno-math-errno \ + -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard + CXXFLAGS += $(CFLAGS) + CPPFLAGS += $(CFLAGS) + ASFLAGS += $(CFLAGS) + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + ARCH = arm + BUILTIN_GPU = neon + DYNAREC = ari64 + ifeq ($(shell echo `$(CC) -dumpversion` "< 4.9" | bc -l), 1) + CFLAGS += -march=armv7-a + else + CFLAGS += -march=armv7ve + # If gcc is 5.0 or later + ifeq ($(shell echo `$(CC) -dumpversion` ">= 5" | bc -l), 1) + LDFLAGS += -static-libgcc -static-libstdc++ + endif + endif + +# (armv8 a35, hard point, neon based) ### +# PlayStation Classic +else ifeq ($(platform), classic_armv8_a35) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + CFLAGS += -Ofast \ + -fmerge-all-constants -fno-math-errno \ + -fno-stack-protector -fomit-frame-pointer \ + -marm -mcpu=cortex-a35 -mtune=cortex-a35 -mfpu=neon-fp-armv8 -mfloat-abi=hard + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + ARCH = arm + BUILTIN_GPU = neon + DYNAREC = ari64 + LDFLAGS += -static-libgcc -static-libstdc++ -fPIC + +####################################### + +# ARM +else ifneq (,$(findstring armv,$(platform))) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + HAVE_NEON = 0 + BUILTIN_GPU = peops + ifneq (,$(findstring cortexa8,$(platform))) + CFLAGS += -mcpu=cortex-a8 + ASFLAGS += -mcpu=cortex-a8 + else ifneq (,$(findstring cortexa7,$(platform))) + CFLAGS += -mcpu=cortex-a7 + ASFLAGS += -mcpu=cortex-a7 + LIBZ := + else ifneq (,$(findstring cortexa9,$(platform))) + CFLAGS += -mcpu=cortex-a9 + ASFLAGS += -mcpu=cortex-a9 + endif + CFLAGS += -marm + ifneq (,$(findstring neon,$(platform))) + CFLAGS += -mfpu=neon + ASFLAGS += -mfpu=neon + HAVE_NEON = 1 + HAVE_NEON_ASM = 1 + BUILTIN_GPU = neon + endif + ifneq (,$(findstring softfloat,$(platform))) + CFLAGS += -mfloat-abi=softfp + ASFLAGS += -mfloat-abi=softfp + else ifneq (,$(findstring hardfloat,$(platform))) + CFLAGS += -mfloat-abi=hard + ASFLAGS += -mfloat-abi=hard + endif + ARCH = arm + DYNAREC = ari64 + +else ifeq ($(platform), miyoo) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + CFLAGS += -mcpu=arm926ej-s -fsingle-precision-constant + CFLAGS += -DGPU_UNAI_USE_INT_DIV_MULTINV -D_MIYOO + ARCH = arm + BUILTIN_GPU = unai + DYNAREC = ari64 + HAVE_NEON = 0 + +# Emscripten +else ifeq ($(platform), emscripten) + TARGET := $(TARGET_NAME)_libretro_$(platform).bc + fpic := -fPIC + NO_MMAP = 1 + CFLAGS += -DNO_DYLIB -DNO_SOCKET + CFLAGS += -msimd128 -ftree-vectorize + LIBPTHREAD := + NO_PTHREAD=1 + DYNAREC = + STATIC_LINKING = 1 + HAVE_PHYSICAL_CDROM = 0 + +# Windows +else + TARGET := $(TARGET_NAME)_libretro.dll + PLATFORM = libretro + MAIN_LDFLAGS += -static-libgcc -static-libstdc++ +ifneq ($(DEBUG),1) + MAIN_LDFLAGS += -s +endif + CFLAGS += -D__WIN32__ -DNO_DYLIB + MMAP_WIN32=1 + NO_PTHREAD=1 + MAIN_LDLIBS += -lws2_32 + LIBPTHREAD := + LIBDL := + LIBM := + USE_LIBRETRO_VFS = 1 +endif + +CFLAGS += $(fpic) +MAIN_LDFLAGS += -shared +MAIN_LDLIBS += $(LIBPTHREAD) $(LIBM) $(LIBDL) $(LIBZ) + +# enable large file support if available +ifeq ($(shell $(CC) -E -dD $(CFLAGS) include/arm_features.h | grep __SIZEOF_LONG__ | awk '{print $$3}'),4) +CFLAGS += -D_FILE_OFFSET_BITS=64 +endif + +# try to autodetect stuff for the lazy +ifndef ARCH +ARCH = $(ARCH_DETECTED) +endif +ifndef HAVE_NEON_ASM +# asm for 32bit only +HAVE_NEON_ASM = $(shell $(CC) -E -dD $(CFLAGS) include/arm_features.h | grep -q HAVE_NEON32 && echo 1 || echo 0) +endif +ifeq ($(NO_UNDEF_CHECK)$(shell $(LD) -v 2> /dev/null | awk '{print $$1}'),GNU) + ifeq (,$(findstring $(platform),win32)) + MAIN_LDFLAGS += -Wl,-version-script=frontend/libretro-version-script + endif +MAIN_LDFLAGS += -Wl,--no-undefined +endif +ifdef ALLOW_LIGHTREC_ON_ARM +CFLAGS += -DALLOW_LIGHTREC_ON_ARM +endif +ifeq ($(BUILTIN_GPU),neon) +ifneq (,$(findstring $(ARCH),x86 i686)) + CFLAGS_GPU_NEON ?= -msse2 # required +endif +ifeq ($(ARCH),x86_64) + CFLAGS_GPU_NEON ?= -mssse3 # optional, for more perf +endif +CFLAGS += $(CFLAGS_GPU_NEON) +endif + +TARGET ?= libretro.so +PLATFORM = libretro +BUILTIN_GPU ?= peops +SOUND_DRIVERS = libretro +PLUGINS = +NO_CONFIG_MAK = yes + +$(info TARGET: $(TARGET)) +$(info platform: $(platform)) +$(info ARCH: $(ARCH)) +$(info DYNAREC: $(DYNAREC)) +$(info BUILTIN_GPU: $(BUILTIN_GPU)) +$(info CC: $(CC) : $(shell $(CC) --version | head -1)) +$(info CFLAGS: $(CFLAGS)) +$(info MAIN_LDLIBS: $(MAIN_LDLIBS)) +$(info ) + +include Makefile + +# no special AS needed for gpu_neon +plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.o: plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.S + $(CC) $(CFLAGS) -c $^ -o $@ diff --git a/deps/mman b/deps/mman new file mode 160000 index 00000000..2d1c576e --- /dev/null +++ b/deps/mman @@ -0,0 +1 @@ +Subproject commit 2d1c576e62b99e85d99407e1a88794c6e44c3310 diff --git a/include/mman/sys/mman.h b/include/mman/sys/mman.h new file mode 100644 index 00000000..55f7ea8a --- /dev/null +++ b/include/mman/sys/mman.h @@ -0,0 +1 @@ +#include diff --git a/jni/Android.mk b/jni/Android.mk index 03ccff7e..aacf89f5 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -1 +1,264 @@ -$(error This file is unmaintained. Please use the libretro fork: https://github.com/libretro/pcsx_rearmed) +LOCAL_PATH := $(call my-dir) + +$(shell cd "$(LOCAL_PATH)" && ((git describe --always || echo) | sed -e 's/.*/#define REV "\0"/' > ../frontend/revision.h_)) +$(shell cd "$(LOCAL_PATH)" && (diff -q ../frontend/revision.h_ ../frontend/revision.h > /dev/null 2>&1 || cp ../frontend/revision.h_ ../frontend/revision.h)) +$(shell cd "$(LOCAL_PATH)" && (rm ../frontend/revision.h_)) + +USE_LIBRETRO_VFS ?= 0 +USE_ASYNC_CDROM ?= 1 +USE_RTHREADS ?= 0 +NDRC_THREAD ?= 1 + +ROOT_DIR := $(LOCAL_PATH)/.. +CORE_DIR := $(ROOT_DIR)/libpcsxcore +SPU_DIR := $(ROOT_DIR)/plugins/dfsound +GPU_DIR := $(ROOT_DIR)/plugins/gpulib +CDR_DIR := $(ROOT_DIR)/plugins/cdrcimg +FRONTEND_DIR := $(ROOT_DIR)/frontend +NEON_DIR := $(ROOT_DIR)/plugins/gpu_neon +UNAI_DIR := $(ROOT_DIR)/plugins/gpu_unai +PEOPS_DIR := $(ROOT_DIR)/plugins/dfxvideo +DYNAREC_DIR := $(ROOT_DIR)/libpcsxcore/new_dynarec +DEPS_DIR := $(ROOT_DIR)/deps +LIBRETRO_COMMON := $(DEPS_DIR)/libretro-common +EXTRA_INCLUDES := + +# core +SOURCES_C := $(CORE_DIR)/cdriso.c \ + $(CORE_DIR)/cdrom.c \ + $(CORE_DIR)/cdrom-async.c \ + $(CORE_DIR)/cheat.c \ + $(CORE_DIR)/database.c \ + $(CORE_DIR)/decode_xa.c \ + $(CORE_DIR)/mdec.c \ + $(CORE_DIR)/misc.c \ + $(CORE_DIR)/plugins.c \ + $(CORE_DIR)/ppf.c \ + $(CORE_DIR)/psxbios.c \ + $(CORE_DIR)/psxcommon.c \ + $(CORE_DIR)/psxcounters.c \ + $(CORE_DIR)/psxdma.c \ + $(CORE_DIR)/psxevents.c \ + $(CORE_DIR)/psxhw.c \ + $(CORE_DIR)/psxinterpreter.c \ + $(CORE_DIR)/psxmem.c \ + $(CORE_DIR)/r3000a.c \ + $(CORE_DIR)/sio.c \ + $(CORE_DIR)/spu.c \ + $(CORE_DIR)/gpu.c \ + $(CORE_DIR)/gte.c \ + $(CORE_DIR)/gte_nf.c \ + $(CORE_DIR)/gte_divider.c + +# spu +SOURCES_C += $(SPU_DIR)/dma.c \ + $(SPU_DIR)/freeze.c \ + $(SPU_DIR)/registers.c \ + $(SPU_DIR)/spu.c \ + $(SPU_DIR)/out.c \ + $(SPU_DIR)/nullsnd.c + +# gpu +SOURCES_C += $(GPU_DIR)/gpu.c \ + $(GPU_DIR)/vout_pl.c + +# cdrcimg +SOURCES_C += $(CDR_DIR)/cdrcimg.c + +# frontend +SOURCES_C += $(FRONTEND_DIR)/main.c \ + $(FRONTEND_DIR)/plugin.c \ + $(FRONTEND_DIR)/cspace.c \ + $(FRONTEND_DIR)/libretro.c + +# libchdr +LCHDR = $(DEPS_DIR)/libchdr +LCHDR_LZMA = $(LCHDR)/deps/lzma-24.05 +LCHDR_ZSTD = $(LCHDR)/deps/zstd-1.5.6/lib +SOURCES_C += \ + $(LCHDR)/src/libchdr_bitstream.c \ + $(LCHDR)/src/libchdr_cdrom.c \ + $(LCHDR)/src/libchdr_chd.c \ + $(LCHDR)/src/libchdr_flac.c \ + $(LCHDR)/src/libchdr_huffman.c \ + $(LCHDR_LZMA)/src/Alloc.c \ + $(LCHDR_LZMA)/src/CpuArch.c \ + $(LCHDR_LZMA)/src/Delta.c \ + $(LCHDR_LZMA)/src/LzFind.c \ + $(LCHDR_LZMA)/src/LzmaDec.c \ + $(LCHDR_LZMA)/src/LzmaEnc.c \ + $(LCHDR_LZMA)/src/Sort.c \ + $(LCHDR_ZSTD)/common/entropy_common.c \ + $(LCHDR_ZSTD)/common/error_private.c \ + $(LCHDR_ZSTD)/common/fse_decompress.c \ + $(LCHDR_ZSTD)/common/xxhash.c \ + $(LCHDR_ZSTD)/common/zstd_common.c \ + $(LCHDR_ZSTD)/decompress/huf_decompress.c \ + $(LCHDR_ZSTD)/decompress/zstd_ddict.c \ + $(LCHDR_ZSTD)/decompress/zstd_decompress_block.c \ + $(LCHDR_ZSTD)/decompress/zstd_decompress.c +SOURCES_ASM := +EXTRA_INCLUDES += $(LCHDR)/include $(LCHDR_LZMA)/include $(LCHDR_ZSTD) +COREFLAGS += -DHAVE_CHD -DZ7_ST -DZSTD_DISABLE_ASM +ifeq (,$(call gte,$(APP_PLATFORM_LEVEL),18)) +ifneq ($(TARGET_ARCH_ABI),arm64-v8a) +# HACK +COREFLAGS += -Dgetauxval=0* +endif +endif + +COREFLAGS += -ffast-math -funroll-loops -DHAVE_LIBRETRO -DNO_FRONTEND -DFRONTEND_SUPPORTS_RGB565 -DANDROID -DREARMED +COREFLAGS += -DP_HAVE_MMAP=1 -DP_HAVE_PTHREAD=1 -DP_HAVE_POSIX_MEMALIGN=1 + +ifeq ($(USE_LIBRETRO_VFS),1) +SOURCES_C += \ + $(LIBRETRO_COMMON)/compat/compat_posix_string.c \ + $(LIBRETRO_COMMON)/compat/fopen_utf8.c \ + $(LIBRETRO_COMMON)/encodings/compat_strl.c \ + $(LIBRETRO_COMMON)/encodings/encoding_utf.c \ + $(LIBRETRO_COMMON)/file/file_path.c \ + $(LIBRETRO_COMMON)/streams/file_stream.c \ + $(LIBRETRO_COMMON)/streams/file_stream_transforms.c \ + $(LIBRETRO_COMMON)/string/stdstring.c \ + $(LIBRETRO_COMMON)/time/rtime.c \ + $(LIBRETRO_COMMON)/vfs/vfs_implementation.c +COREFLAGS += -DUSE_LIBRETRO_VFS +endif +EXTRA_INCLUDES += $(LIBRETRO_COMMON)/include + +USE_RTHREADS=0 +HAVE_ARI64=0 +HAVE_LIGHTREC=0 +LIGHTREC_CUSTOM_MAP=0 +LIGHTREC_THREADED_COMPILER=0 +HAVE_GPU_NEON=0 +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + HAVE_ARI64=1 + HAVE_GPU_NEON=1 +else ifeq ($(TARGET_ARCH_ABI),armeabi) + HAVE_ARI64=1 +else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) + HAVE_ARI64=1 + HAVE_GPU_NEON=1 +else ifeq ($(TARGET_ARCH_ABI),x86_64) + HAVE_LIGHTREC=1 + HAVE_GPU_NEON=1 +else ifeq ($(TARGET_ARCH_ABI),x86) + HAVE_LIGHTREC=1 + HAVE_GPU_NEON=1 +else + COREFLAGS += -DDRC_DISABLE +endif + COREFLAGS += -DLIGHTREC_CUSTOM_MAP=$(LIGHTREC_CUSTOM_MAP) + COREFLAGS += -DLIGHTREC_ENABLE_THREADED_COMPILER=$(LIGHTREC_THREADED_COMPILER) + +ifeq ($(HAVE_ARI64),1) + SOURCES_C += $(DYNAREC_DIR)/new_dynarec.c \ + $(DYNAREC_DIR)/pcsxmem.c + ifeq ($(TARGET_ARCH_ABI),arm64-v8a) + SOURCES_ASM += $(DYNAREC_DIR)/linkage_arm64.S + else + SOURCES_ASM += $(CORE_DIR)/gte_arm.S \ + $(SPU_DIR)/arm_utils.S \ + $(DYNAREC_DIR)/linkage_arm.S + endif + ifeq ($(NDRC_THREAD),1) + COREFLAGS += -DNDRC_THREAD + USE_RTHREADS := 1 + endif +endif + SOURCES_C += $(DYNAREC_DIR)/emu_if.c + +ifeq ($(HAVE_LIGHTREC),1) + COREFLAGS += -DLIGHTREC -DLIGHTREC_STATIC -DLIGHTREC_CODE_INV=0 + EXTRA_INCLUDES += $(DEPS_DIR)/lightning/include \ + $(DEPS_DIR)/lightrec \ + $(DEPS_DIR)/lightrec/tlsf \ + $(ROOT_DIR)/include/lightning \ + $(ROOT_DIR)/include/lightrec + SOURCES_C += $(DEPS_DIR)/lightrec/blockcache.c \ + $(DEPS_DIR)/lightrec/constprop.c \ + $(DEPS_DIR)/lightrec/disassembler.c \ + $(DEPS_DIR)/lightrec/emitter.c \ + $(DEPS_DIR)/lightrec/interpreter.c \ + $(DEPS_DIR)/lightrec/lightrec.c \ + $(DEPS_DIR)/lightrec/memmanager.c \ + $(DEPS_DIR)/lightrec/optimizer.c \ + $(DEPS_DIR)/lightrec/regcache.c \ + $(DEPS_DIR)/lightrec/recompiler.c \ + $(DEPS_DIR)/lightrec/reaper.c \ + $(DEPS_DIR)/lightrec/tlsf/tlsf.c + SOURCES_C += $(DEPS_DIR)/lightning/lib/jit_disasm.c \ + $(DEPS_DIR)/lightning/lib/jit_memory.c \ + $(DEPS_DIR)/lightning/lib/jit_names.c \ + $(DEPS_DIR)/lightning/lib/jit_note.c \ + $(DEPS_DIR)/lightning/lib/jit_print.c \ + $(DEPS_DIR)/lightning/lib/jit_size.c \ + $(DEPS_DIR)/lightning/lib/lightning.c + SOURCES_C += $(CORE_DIR)/lightrec/plugin.c +ifeq ($(LIGHTREC_CUSTOM_MAP),1) + SOURCES_C += $(CORE_DIR)/lightrec/mem.c +endif +endif + + +ifeq ($(HAVE_GPU_NEON),1) + COREFLAGS += -DNEON_BUILD -DTEXTURE_CACHE_4BPP -DTEXTURE_CACHE_8BPP -DGPU_NEON + ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + SOURCES_ASM += $(NEON_DIR)/psx_gpu/psx_gpu_arm_neon.S + else + COREFLAGS += -DSIMD_BUILD + SOURCES_C += $(NEON_DIR)/psx_gpu/psx_gpu_simd.c + endif + SOURCES_C += $(NEON_DIR)/psx_gpu_if.c +else ifeq ($(TARGET_ARCH_ABI),armeabi) + COREFLAGS += -DUSE_GPULIB=1 -DGPU_UNAI + COREFLAGS += -DHAVE_bgr555_to_rgb565 + SOURCES_ASM += $(UNAI_DIR)/gpu_arm.S \ + $(FRONTEND_DIR)/cspace_arm.S + SOURCES_C += $(UNAI_DIR)/gpulib_if.cpp +else + COREFLAGS += -fno-strict-aliasing -DGPU_PEOPS + SOURCES_C += $(PEOPS_DIR)/gpulib_if.c +endif + +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + COREFLAGS += -DHAVE_bgr555_to_rgb565 -DHAVE_bgr888_to_x + SOURCES_ASM += $(CORE_DIR)/gte_neon.S \ + $(FRONTEND_DIR)/cspace_neon.S +endif + +ifeq ($(USE_ASYNC_CDROM),1) +COREFLAGS += -DUSE_ASYNC_CDROM +USE_RTHREADS := 1 +endif +ifeq ($(USE_RTHREADS),1) +SOURCES_C += \ + $(FRONTEND_DIR)/libretro-rthreads.c \ + $(LIBRETRO_COMMON)/features/features_cpu.c +COREFLAGS += -DHAVE_RTHREADS +endif + +GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)" +ifneq ($(GIT_VERSION)," unknown") + COREFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" +endif + +include $(CLEAR_VARS) +LOCAL_MODULE := retro +LOCAL_SRC_FILES := $(SOURCES_C) $(SOURCES_ASM) +LOCAL_CFLAGS := $(COREFLAGS) +LOCAL_C_INCLUDES := $(ROOT_DIR)/include +LOCAL_C_INCLUDES += $(DEPS_DIR)/crypto +LOCAL_C_INCLUDES += $(EXTRA_INCLUDES) +LOCAL_LDFLAGS += -Wl,-version-script=$(FRONTEND_DIR)/libretro-version-script +LOCAL_LDFLAGS += -Wl,--script=$(FRONTEND_DIR)/libretro-extern.T +LOCAL_LDFLAGS += -Wl,--gc-sections +LOCAL_LDLIBS := -lz -llog +LOCAL_ARM_MODE := arm + +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + LOCAL_ARM_NEON := true +endif + +include $(BUILD_SHARED_LIBRARY) diff --git a/plugins/dfsound/out.c b/plugins/dfsound/out.c index 5ddd3f40..4443dae3 100644 --- a/plugins/dfsound/out.c +++ b/plugins/dfsound/out.c @@ -47,6 +47,6 @@ void SetupSound(void) } out_current = &out_drivers[i]; - printf("selected sound output driver: %s\n", out_current->name); + // printf("selected sound output driver: %s\n", out_current->name); } diff --git a/plugins/dfxvideo/gpulib_if.c b/plugins/dfxvideo/gpulib_if.c index af35f3cb..8a3f2f9a 100644 --- a/plugins/dfxvideo/gpulib_if.c +++ b/plugins/dfxvideo/gpulib_if.c @@ -22,6 +22,22 @@ #pragma GCC diagnostic ignored "-Wmisleading-indentation" #endif +#ifdef THREAD_RENDERING +#include "../gpulib/gpulib_thread_if.h" +#define do_cmd_list real_do_cmd_list +#define renderer_init real_renderer_init +#define renderer_finish real_renderer_finish +#define renderer_sync_ecmds real_renderer_sync_ecmds +#define renderer_update_caches real_renderer_update_caches +#define renderer_flush_queues real_renderer_flush_queues +#define renderer_set_interlace real_renderer_set_interlace +#define renderer_set_config real_renderer_set_config +#define renderer_notify_res_change real_renderer_notify_res_change +#define renderer_notify_update_lace real_renderer_notify_update_lace +#define renderer_sync real_renderer_sync +#define ex_regs scratch_ex_regs +#endif + #define u32 uint32_t #define INFO_TW 0 @@ -468,6 +484,14 @@ void renderer_set_interlace(int enable, int is_odd) { } +void renderer_sync(void) +{ +} + +void renderer_notify_update_lace(int updated) +{ +} + #include "../../frontend/plugin_lib.h" void renderer_set_config(const struct rearmed_cbs *cbs) diff --git a/plugins/gpu-gles/gpulib_if.c b/plugins/gpu-gles/gpulib_if.c index f00c4592..ab95c641 100644 --- a/plugins/gpu-gles/gpulib_if.c +++ b/plugins/gpu-gles/gpulib_if.c @@ -775,3 +775,11 @@ static void fps_update(void) DisplayText(buf, 1); } } + +void renderer_sync(void) +{ +} + +void renderer_notify_update_lace(int updated) +{ +} diff --git a/plugins/gpu_neon/psx_gpu_if.c b/plugins/gpu_neon/psx_gpu_if.c index 3f43e431..02104586 100644 --- a/plugins/gpu_neon/psx_gpu_if.c +++ b/plugins/gpu_neon/psx_gpu_if.c @@ -244,4 +244,12 @@ void renderer_set_config(const struct rearmed_cbs *cbs) } } +void renderer_sync(void) +{ +} + +void renderer_notify_update_lace(int updated) +{ +} + // vim:ts=2:sw=2:expandtab diff --git a/plugins/gpulib/gpu.c b/plugins/gpulib/gpu.c index d1be12a6..03be13d0 100644 --- a/plugins/gpulib/gpu.c +++ b/plugins/gpulib/gpu.c @@ -43,6 +43,7 @@ static void finish_vram_transfer(int is_read); static noinline void do_cmd_reset(void) { int dummy = 0; + renderer_sync(); if (unlikely(gpu.cmd_len > 0)) do_cmd_buffer(gpu.cmd_buffer, gpu.cmd_len, &dummy, &dummy); gpu.cmd_len = 0; @@ -167,6 +168,8 @@ static noinline void update_height(void) static noinline void decide_frameskip(void) { + *gpu.frameskip.dirty = 1; + if (gpu.frameskip.active) gpu.frameskip.cnt++; else { @@ -174,7 +177,9 @@ static noinline void decide_frameskip(void) gpu.frameskip.frame_ready = 1; } - if (!gpu.frameskip.active && *gpu.frameskip.advice) + if (*gpu.frameskip.force) + gpu.frameskip.active = 1; + else if (!gpu.frameskip.active && *gpu.frameskip.advice) gpu.frameskip.active = 1; else if (gpu.frameskip.set > 0 && gpu.frameskip.cnt < gpu.frameskip.set) gpu.frameskip.active = 1; @@ -448,6 +453,8 @@ static int do_vram_io(uint32_t *data, int count, int is_read) int l; count *= 2; // operate in 16bpp pixels + renderer_sync(); + if (gpu.dma.offset) { l = w - gpu.dma.offset; if (count < l) @@ -687,6 +694,7 @@ static noinline int do_cmd_buffer(uint32_t *data, int count, cmd = -1; // incomplete cmd, can't consume yet break; } + renderer_sync(); *cycles_sum += *cycles_last; *cycles_last = 0; do_vram_copy(data + pos + 1, cycles_last); @@ -890,12 +898,15 @@ long GPUfreeze(uint32_t type, struct GPUFreeze *freeze) case 1: // save if (gpu.cmd_len > 0) flush_cmd_buffer(); + + renderer_sync(); memcpy(freeze->psxVRam, gpu.vram, 1024 * 512 * 2); memcpy(freeze->ulControl, gpu.regs, sizeof(gpu.regs)); memcpy(freeze->ulControl + 0xe0, gpu.ex_regs, sizeof(gpu.ex_regs)); freeze->ulStatus = gpu.status; break; case 0: // load + renderer_sync(); memcpy(gpu.vram, freeze->psxVRam, 1024 * 512 * 2); memcpy(gpu.regs, freeze->ulControl, sizeof(gpu.regs)); memcpy(gpu.ex_regs, freeze->ulControl + 0xe0, sizeof(gpu.ex_regs)); @@ -929,6 +940,8 @@ void GPUupdateLace(void) return; } + renderer_notify_update_lace(0); + if (!gpu.state.fb_dirty) return; #endif @@ -948,6 +961,7 @@ void GPUupdateLace(void) gpu.state.enhancement_was_active = gpu.state.enhancement_active; gpu.state.fb_dirty = 0; gpu.state.blanked = 0; + renderer_notify_update_lace(1); } void GPUvBlank(int is_vblank, int lcf) @@ -984,6 +998,8 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs) { gpu.frameskip.set = cbs->frameskip; gpu.frameskip.advice = &cbs->fskip_advice; + gpu.frameskip.force = &cbs->fskip_force; + gpu.frameskip.dirty = (void *)&cbs->fskip_dirty; gpu.frameskip.active = 0; gpu.frameskip.frame_ready = 1; gpu.state.hcnt = (uint32_t *)cbs->gpu_hcnt; diff --git a/plugins/gpulib/gpu.h b/plugins/gpulib/gpu.h index ec7e0575..2083224e 100644 --- a/plugins/gpulib/gpu.h +++ b/plugins/gpulib/gpu.h @@ -105,9 +105,12 @@ struct psx_gpu { uint32_t allow:1; uint32_t frame_ready:1; const int *advice; + const int *force; + int *dirty; uint32_t last_flip_frame; uint32_t pending_fill[3]; } frameskip; + uint32_t scratch_ex_regs[8]; // for threaded rendering void *(*get_enhancement_bufer) (int *x, int *y, int *w, int *h, int *vram_h); uint16_t *(*get_downscale_buffer) @@ -134,6 +137,8 @@ void renderer_flush_queues(void); void renderer_set_interlace(int enable, int is_odd); void renderer_set_config(const struct rearmed_cbs *config); void renderer_notify_res_change(void); +void renderer_notify_update_lace(int updated); +void renderer_sync(void); void renderer_notify_scanout_change(int x, int y); int vout_init(void); diff --git a/plugins/gpulib/gpulib_thread_if.c b/plugins/gpulib/gpulib_thread_if.c new file mode 100644 index 00000000..0b28fe33 --- /dev/null +++ b/plugins/gpulib/gpulib_thread_if.c @@ -0,0 +1,563 @@ +/************************************************************************** +* Copyright (C) 2020 The RetroArch Team * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. * +***************************************************************************/ + +#include +#include +#include +#include +#include "../gpulib/gpu.h" +#include "../../frontend/plugin_lib.h" +#include "gpu.h" +#include "gpu_timing.h" +#include "gpulib_thread_if.h" + +extern void SysPrintf(const char *fmt, ...); + +#define FALSE 0 +#define TRUE 1 +#define BOOL unsigned short + +typedef struct { + uint32_t *cmd_list; + int count; + int last_cmd; +} video_thread_cmd; + +#define QUEUE_SIZE 0x2000 + +typedef struct { + size_t start; + size_t end; + size_t used; + video_thread_cmd queue[QUEUE_SIZE]; +} video_thread_queue; + +typedef struct { + pthread_t thread; + pthread_mutex_t queue_lock; + pthread_cond_t cond_msg_avail; + pthread_cond_t cond_msg_done; + pthread_cond_t cond_queue_empty; + video_thread_queue *queue; + video_thread_queue *bg_queue; + BOOL running; +} video_thread_state; + +static video_thread_state thread; +static video_thread_queue queues[2]; +static int thread_rendering; +static BOOL hold_cmds; +static BOOL needs_display; +static BOOL flushed; + +extern const unsigned char cmd_lengths[]; + +static void *video_thread_main(void *arg) { + video_thread_cmd *cmd; + int i; + +#ifdef _3DS + static int processed = 0; +#endif /* _3DS */ + + while(1) { + int result, cycles_dummy = 0, last_cmd, start, end; + video_thread_queue *queue; + pthread_mutex_lock(&thread.queue_lock); + + while (!thread.queue->used && thread.running) { + pthread_cond_wait(&thread.cond_msg_avail, &thread.queue_lock); + } + + if (!thread.running) { + pthread_mutex_unlock(&thread.queue_lock); + break; + } + + queue = thread.queue; + start = queue->start; + end = queue->end > queue->start ? queue->end : QUEUE_SIZE; + queue->start = end % QUEUE_SIZE; + pthread_mutex_unlock(&thread.queue_lock); + + for (i = start; i < end; i++) { + cmd = &queue->queue[i]; + result = real_do_cmd_list(cmd->cmd_list, cmd->count, + &cycles_dummy, &cycles_dummy, &last_cmd); + if (result != cmd->count) { + fprintf(stderr, "Processed wrong cmd count: expected %d, got %d\n", cmd->count, result); + } + +#ifdef _3DS + /* Periodically yield so as not to starve other threads */ + processed += cmd->count; + if (processed >= 512) { + svcSleepThread(1); + processed %= 512; + } +#endif /* _3DS */ + } + + pthread_mutex_lock(&thread.queue_lock); + queue->used -= (end - start); + + if (!queue->used) + pthread_cond_signal(&thread.cond_queue_empty); + + pthread_cond_signal(&thread.cond_msg_done); + pthread_mutex_unlock(&thread.queue_lock); + } + + return 0; +} + +static void cmd_queue_swap() { + video_thread_queue *tmp; + if (!thread.bg_queue->used) return; + + pthread_mutex_lock(&thread.queue_lock); + if (!thread.queue->used) { + tmp = thread.queue; + thread.queue = thread.bg_queue; + thread.bg_queue = tmp; + pthread_cond_signal(&thread.cond_msg_avail); + } + pthread_mutex_unlock(&thread.queue_lock); +} + +/* Waits for the main queue to completely finish. */ +void renderer_wait() { + if (!thread.running) return; + + /* Not completely safe, but should be fine since the render thread + * only decreases used, and we check again inside the lock. */ + if (!thread.queue->used) { + return; + } + + pthread_mutex_lock(&thread.queue_lock); + + while (thread.queue->used) { + pthread_cond_wait(&thread.cond_queue_empty, &thread.queue_lock); + } + + pthread_mutex_unlock(&thread.queue_lock); +} + +/* Waits for all GPU commands in both queues to finish, bringing VRAM + * completely up-to-date. */ +void renderer_sync(void) { + if (!thread.running) return; + + /* Not completely safe, but should be fine since the render thread + * only decreases used, and we check again inside the lock. */ + if (!thread.queue->used && !thread.bg_queue->used) { + return; + } + + if (thread.bg_queue->used) { + /* When we flush the background queue, the vblank handler can't + * know that we had a frame pending, and we delay rendering too + * long. Force it. */ + flushed = TRUE; + } + + /* Flush both queues. This is necessary because gpulib could be + * trying to process a DMA write that a command in the queue should + * run beforehand. For example, Xenogears sprites write a black + * rectangle over the to-be-DMA'd spot in VRAM -- if this write + * happens after the DMA, it will clear the DMA, resulting in + * flickering sprites. We need to be totally up-to-date. This may + * drop a frame. */ + renderer_wait(); + cmd_queue_swap(); + hold_cmds = FALSE; + renderer_wait(); +} + +static void video_thread_stop() { + int i; + renderer_sync(); + + if (thread.running) { + thread.running = FALSE; + pthread_cond_signal(&thread.cond_msg_avail); + pthread_join(thread.thread, NULL); + } + + pthread_mutex_destroy(&thread.queue_lock); + pthread_cond_destroy(&thread.cond_msg_avail); + pthread_cond_destroy(&thread.cond_msg_done); + pthread_cond_destroy(&thread.cond_queue_empty); + + for (i = 0; i < QUEUE_SIZE; i++) { + video_thread_cmd *cmd = &thread.queue->queue[i]; + free(cmd->cmd_list); + cmd->cmd_list = NULL; + } + + for (i = 0; i < QUEUE_SIZE; i++) { + video_thread_cmd *cmd = &thread.bg_queue->queue[i]; + free(cmd->cmd_list); + cmd->cmd_list = NULL; + } +} + +static void video_thread_start() { + SysPrintf("Starting render thread\n"); + + thread.queue = &queues[0]; + thread.bg_queue = &queues[1]; + thread.running = TRUE; + + if (pthread_cond_init(&thread.cond_msg_avail, NULL) || + pthread_cond_init(&thread.cond_msg_done, NULL) || + pthread_cond_init(&thread.cond_queue_empty, NULL) || + pthread_mutex_init(&thread.queue_lock, NULL) || + pthread_create(&thread.thread, NULL, video_thread_main, &thread)) { + goto error; + } + + return; + + error: + SysPrintf("Failed to start rendering thread\n"); + thread.running = FALSE; + video_thread_stop(); +} + +static void video_thread_queue_cmd(uint32_t *list, int count, int last_cmd) { + video_thread_cmd *cmd; + uint32_t *cmd_list; + video_thread_queue *queue; + BOOL lock; + + cmd_list = (uint32_t *)calloc(count, sizeof(uint32_t)); + + if (!cmd_list) { + /* Out of memory, disable the thread and run sync from now on */ + SysPrintf("Failed to allocate render thread command list, stopping thread\n"); + video_thread_stop(); + } + + memcpy(cmd_list, list, count * sizeof(uint32_t)); + + if (hold_cmds && thread.bg_queue->used >= QUEUE_SIZE) { + /* If the bg queue is full, do a full sync to empty both queues + * and clear space. This should be very rare, I've only seen it in + * Tekken 3 post-battle-replay. */ + renderer_sync(); + } + + if (hold_cmds) { + queue = thread.bg_queue; + lock = FALSE; + } else { + queue = thread.queue; + lock = TRUE; + } + + if (lock) { + pthread_mutex_lock(&thread.queue_lock); + + while (queue->used >= QUEUE_SIZE) { + pthread_cond_wait(&thread.cond_msg_done, &thread.queue_lock); + } + } + + cmd = &queue->queue[queue->end]; + free(cmd->cmd_list); + cmd->cmd_list = cmd_list; + cmd->count = count; + cmd->last_cmd = last_cmd; + queue->end = (queue->end + 1) % QUEUE_SIZE; + queue->used++; + + if (lock) { + pthread_cond_signal(&thread.cond_msg_avail); + pthread_mutex_unlock(&thread.queue_lock); + } +} + +/* Slice off just the part of the list that can be handled async, and + * update ex_regs. */ +static int scan_cmd_list(uint32_t *data, int count, + int *cycles_sum_out, int *cycles_last, int *last_cmd) +{ + int cpu_cycles_sum = 0, cpu_cycles = *cycles_last; + int cmd = 0, pos = 0, len, v; + + while (pos < count) { + uint32_t *list = data + pos; + short *slist = (void *)list; + cmd = LE32TOH(list[0]) >> 24; + len = 1 + cmd_lengths[cmd]; + + switch (cmd) { + case 0x02: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_fill(LE16TOH(slist[4]) & 0x3ff, + LE16TOH(slist[5]) & 0x1ff)); + break; + case 0x20 ... 0x23: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base()); + break; + case 0x24 ... 0x27: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t()); + gpu.ex_regs[1] &= ~0x1ff; + gpu.ex_regs[1] |= LE32TOH(list[4]) & 0x1ff; + break; + case 0x28 ... 0x2b: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base()); + break; + case 0x2c ... 0x2f: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t()); + gpu.ex_regs[1] &= ~0x1ff; + gpu.ex_regs[1] |= LE32TOH(list[4]) & 0x1ff; + break; + case 0x30 ... 0x33: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g()); + break; + case 0x34 ... 0x37: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt()); + gpu.ex_regs[1] &= ~0x1ff; + gpu.ex_regs[1] |= LE32TOH(list[5]) & 0x1ff; + break; + case 0x38 ... 0x3b: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g()); + break; + case 0x3c ... 0x3f: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt()); + gpu.ex_regs[1] &= ~0x1ff; + gpu.ex_regs[1] |= LE32TOH(list[5]) & 0x1ff; + break; + case 0x40 ... 0x47: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + break; + case 0x48 ... 0x4F: + for (v = 3; pos + v < count; v++) + { + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + if ((list[v] & 0xf000f000) == 0x50005000) + break; + } + len += v - 3; + break; + case 0x50 ... 0x57: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + break; + case 0x58 ... 0x5F: + for (v = 4; pos + v < count; v += 2) + { + gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0)); + if ((list[v] & 0xf000f000) == 0x50005000) + break; + } + len += v - 4; + break; + case 0x60 ... 0x63: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_sprite(LE16TOH(slist[4]) & 0x3ff, + LE16TOH(slist[5]) & 0x1ff)); + break; + case 0x64 ... 0x67: + gput_sum(cpu_cycles_sum, cpu_cycles, + gput_sprite(LE16TOH(slist[6]) & 0x3ff, + LE16TOH(slist[7]) & 0x1ff)); + break; + case 0x68 ... 0x6b: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1)); + break; + case 0x70 ... 0x77: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(8, 8)); + break; + case 0x78 ... 0x7f: + gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(16, 16)); + break; + default: + if ((cmd & 0xf8) == 0xe0) + gpu.ex_regs[cmd & 7] = list[0]; + break; + } + + if (pos + len > count) { + cmd = -1; + break; /* incomplete cmd */ + } + if (0x80 <= cmd && cmd <= 0xdf) + break; /* image i/o */ + + pos += len; + } + + *cycles_sum_out += cpu_cycles_sum; + *cycles_last = cpu_cycles; + *last_cmd = cmd; + return pos; +} + +int do_cmd_list(uint32_t *list, int count, + int *cycles_sum, int *cycles_last, int *last_cmd) +{ + int pos = 0; + + if (thread.running) { + pos = scan_cmd_list(list, count, cycles_sum, cycles_last, last_cmd); + video_thread_queue_cmd(list, pos, *last_cmd); + } else { + pos = real_do_cmd_list(list, count, cycles_sum, cycles_last, last_cmd); + memcpy(gpu.ex_regs, gpu.scratch_ex_regs, sizeof(gpu.ex_regs)); + } + return pos; +} + +int renderer_init(void) { + if (thread_rendering) { + video_thread_start(); + } + return real_renderer_init(); +} + +void renderer_finish(void) { + real_renderer_finish(); + + if (thread_rendering && thread.running) { + video_thread_stop(); + } +} + +void renderer_sync_ecmds(uint32_t * ecmds) { + if (thread.running) { + int dummy = 0; + do_cmd_list(&ecmds[1], 6, &dummy, &dummy, &dummy); + } else { + real_renderer_sync_ecmds(ecmds); + } +} + +void renderer_update_caches(int x, int y, int w, int h, int state_changed) { + renderer_sync(); + real_renderer_update_caches(x, y, w, h, state_changed); +} + +void renderer_flush_queues(void) { + /* Called during DMA and updateLace. We want to sync if it's DMA, + * but not if it's updateLace. Instead of syncing here, there's a + * renderer_sync call during DMA. */ + real_renderer_flush_queues(); +} + +/* + * Normally all GPU commands are processed before rendering the + * frame. For games that naturally run < 50/60fps, this is unnecessary + * -- it forces the game to render as if it was 60fps and leaves the + * GPU idle half the time on a 30fps game, for example. + * + * Allowing the renderer to wait until a frame is done before + * rendering it would give it double, triple, or quadruple the amount + * of time to finish before we have to wait for it. + * + * We can use a heuristic to figure out when to force a render. + * + * - If a frame isn't done when we're asked to render, wait for it and + * put future GPU commands in a separate buffer (for the next frame) + * + * - If the frame is done, and had no future GPU commands, render it. + * + * - If we do have future GPU commands, it meant the frame took too + * long to render and there's another frame waiting. Stop until the + * first frame finishes, render it, and start processing the next + * one. + * + * This may possibly add a frame or two of latency that shouldn't be + * different than the real device. It may skip rendering a frame + * entirely if a VRAM transfer happens while a frame is waiting, or in + * games that natively run at 60fps if frames are coming in too + * quickly to process. Depending on how the game treats "60fps," this + * may not be noticeable. + */ +void renderer_notify_update_lace(int updated) { + if (!thread.running) return; + + if (thread_rendering == THREAD_RENDERING_SYNC) { + renderer_sync(); + return; + } + + if (updated) { + cmd_queue_swap(); + return; + } + + pthread_mutex_lock(&thread.queue_lock); + if (thread.bg_queue->used || flushed) { + /* We have commands for a future frame to run. Force a wait until + * the current frame is finished, and start processing the next + * frame after it's drawn (see the `updated` clause above). */ + pthread_mutex_unlock(&thread.queue_lock); + renderer_wait(); + pthread_mutex_lock(&thread.queue_lock); + + /* We are no longer holding commands back, so the next frame may + * get mixed into the following frame. This is usually fine, but can + * result in frameskip-like effects for 60fps games. */ + flushed = FALSE; + hold_cmds = FALSE; + needs_display = TRUE; + gpu.state.fb_dirty = TRUE; + } else if (thread.queue->used) { + /* We are still drawing during a vblank. Cut off the current frame + * by sending new commands to the background queue and skip + * drawing our partly rendered frame to the display. */ + hold_cmds = TRUE; + needs_display = TRUE; + gpu.state.fb_dirty = FALSE; + } else if (needs_display && !thread.queue->used) { + /* We have processed all commands in the queue, render the + * buffer. We know we have something to render, because + * needs_display is TRUE. */ + hold_cmds = FALSE; + needs_display = FALSE; + gpu.state.fb_dirty = TRUE; + } else { + /* Everything went normally, so do the normal thing. */ + } + + pthread_mutex_unlock(&thread.queue_lock); +} + +void renderer_set_interlace(int enable, int is_odd) { + real_renderer_set_interlace(enable, is_odd); +} + +void renderer_set_config(const struct rearmed_cbs *cbs) { + renderer_sync(); + thread_rendering = cbs->thread_rendering; + if (!thread.running && thread_rendering != THREAD_RENDERING_OFF) { + video_thread_start(); + } else if (thread.running && thread_rendering == THREAD_RENDERING_OFF) { + video_thread_stop(); + } + real_renderer_set_config(cbs); +} + +void renderer_notify_res_change(void) { + renderer_sync(); + real_renderer_notify_res_change(); +} diff --git a/plugins/gpulib/gpulib_thread_if.h b/plugins/gpulib/gpulib_thread_if.h new file mode 100644 index 00000000..45fdfe01 --- /dev/null +++ b/plugins/gpulib/gpulib_thread_if.h @@ -0,0 +1,42 @@ +/************************************************************************** +* Copyright (C) 2020 The RetroArch Team * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. * +***************************************************************************/ + +#ifndef __GPULIB_THREAD_H__ +#define __GPULIB_THREAD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int real_do_cmd_list(uint32_t *list, int count, + int *cycles_sum_out, int *cycles_last, int *last_cmd); +int real_renderer_init(void); +void real_renderer_finish(void); +void real_renderer_sync_ecmds(uint32_t * ecmds); +void real_renderer_update_caches(int x, int y, int w, int h, int state_changed); +void real_renderer_flush_queues(void); +void real_renderer_set_interlace(int enable, int is_odd); +void real_renderer_set_config(const struct rearmed_cbs *config); +void real_renderer_notify_res_change(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPULIB_THREAD_H__ */ -- 2.39.5