Merge branch 'master' into integrate_rcheevos
This commit is contained in:
commit
d67aa83f48
|
@ -120,6 +120,9 @@ wiiu/wut/elf2rpl/elf2rpl
|
||||||
|
|
||||||
pkg/apple/iOS/build/
|
pkg/apple/iOS/build/
|
||||||
pkg/apple/iOS/modules/
|
pkg/apple/iOS/modules/
|
||||||
|
pkg/apple/build/
|
||||||
|
ui/drivers/qt/moc_*
|
||||||
|
ui/drivers/moc_*
|
||||||
|
|
||||||
obj-unix/
|
obj-unix/
|
||||||
.vagrant/
|
.vagrant/
|
||||||
|
@ -151,3 +154,12 @@ retroarch.js.mem
|
||||||
|
|
||||||
# only ignore .js files in the repo root
|
# only ignore .js files in the repo root
|
||||||
/*.js
|
/*.js
|
||||||
|
|
||||||
|
# Switch
|
||||||
|
*.d
|
||||||
|
exefs/*
|
||||||
|
retroarch_switch.pfs0
|
||||||
|
retroarch_switch.lst
|
||||||
|
retroarch_switch.nacp
|
||||||
|
retroarch_switch.nro
|
||||||
|
retroarch_switch.nso
|
||||||
|
|
22
.travis.yml
22
.travis.yml
|
@ -20,6 +20,13 @@ matrix:
|
||||||
script:
|
script:
|
||||||
- CROSS_COMPILE=x86_64-w64-mingw32- CFLAGS="-D_WIN32_WINNT=0x0501" ./configure --disable-d3d8 --disable-d3d9 --disable-d3d10 --disable-d3d11 --disable-d3d12 && make HAVE_ZLIB=1 HAVE_BUILTINZLIB=1 HAVE_RPNG=1
|
- CROSS_COMPILE=x86_64-w64-mingw32- CFLAGS="-D_WIN32_WINNT=0x0501" ./configure --disable-d3d8 --disable-d3d9 --disable-d3d10 --disable-d3d11 --disable-d3d12 && make HAVE_ZLIB=1 HAVE_BUILTINZLIB=1 HAVE_RPNG=1
|
||||||
- compiler: gcc
|
- compiler: gcc
|
||||||
|
addons:
|
||||||
|
# Install a more recent gcc than the default
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- g++-7
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
- compiler: clang
|
- compiler: clang
|
||||||
addons:
|
addons:
|
||||||
# Install a more recent clang than the default
|
# Install a more recent clang than the default
|
||||||
|
@ -37,7 +44,17 @@ matrix:
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode9.3
|
osx_image: xcode9.3
|
||||||
script:
|
script:
|
||||||
- xcodebuild -target RetroArch -configuration Release -project pkg/apple/RetroArch_Metal.xcodeproj
|
- cd ~/
|
||||||
|
- brew install --force-bottle qt5
|
||||||
|
- git clone --depth=50 https://github.com/libretro/libretro-super
|
||||||
|
- cd libretro-super/travis
|
||||||
|
- ./build-retroarch-metal.sh
|
||||||
|
deploy:
|
||||||
|
skip_cleanup: true
|
||||||
|
provider: script
|
||||||
|
script: cd ../retroarch; bash travis_metal_deploy.sh
|
||||||
|
on:
|
||||||
|
branch: master
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./configure
|
- ./configure
|
||||||
|
@ -60,6 +77,9 @@ addons:
|
||||||
- libsdl-mixer1.2-dev
|
- libsdl-mixer1.2-dev
|
||||||
- libsdl-ttf2.0-dev
|
- libsdl-ttf2.0-dev
|
||||||
- libusb-1.0-0-dev
|
- libusb-1.0-0-dev
|
||||||
|
- qt5-default
|
||||||
|
- qt5-qmake
|
||||||
|
- qtbase5-dev-tools
|
||||||
coverity_scan:
|
coverity_scan:
|
||||||
project:
|
project:
|
||||||
name: "RetroArch"
|
name: "RetroArch"
|
||||||
|
|
|
@ -14,6 +14,13 @@
|
||||||
"*.in": "c",
|
"*.in": "c",
|
||||||
"*.rh": "c",
|
"*.rh": "c",
|
||||||
"array": "c",
|
"array": "c",
|
||||||
|
"file_stream.h": "c",
|
||||||
|
"driver.h": "c",
|
||||||
|
"iosfwd": "c",
|
||||||
|
"xlocbuf": "c",
|
||||||
|
"xmemory0": "c",
|
||||||
|
"ios": "c",
|
||||||
|
"list": "c"
|
||||||
},
|
},
|
||||||
"C_Cpp.dimInactiveRegions": false,
|
"C_Cpp.dimInactiveRegions": false,
|
||||||
}
|
}
|
28
CHANGES.md
28
CHANGES.md
|
@ -1,4 +1,32 @@
|
||||||
# 1.7.5 (future)
|
# 1.7.5 (future)
|
||||||
|
- CAMERA: Fix Video4Linux2 driver that broke years ago.
|
||||||
|
- CHEATS: Add support for Rumble when increase or decrease by the rumble value.
|
||||||
|
- CHEEVOS: Support headerless NES hashing.
|
||||||
|
- CHEEVOS: Prevent loading states before achievements are fully loaded.
|
||||||
|
- CRT: New porches and interlaced bug fix.
|
||||||
|
- CRT: New functionality, ability to switch between 15KHz and 31KHz, etc.
|
||||||
|
- COMMON: Support for "OEM-102" key (usually '\' on Euro keyboards).
|
||||||
|
- DISCORD: Add 'Ask To Join' Feature.
|
||||||
|
- IOS: Use safe area to account for notch for iPhone X and adjust main view.
|
||||||
|
- LOCALIZATION: Update Portuguese / Brazilian translation.
|
||||||
|
- LOCALIZATION: Update Japanese translation.
|
||||||
|
- LOCALIZATION: Update Polish translation.
|
||||||
|
- LOCALIZATION: Update Spanish translation.
|
||||||
|
- MENU: Add dropdown lists for many settings.
|
||||||
|
- MENU: Fix crash that could happen when changing core's options on Android.
|
||||||
|
- MENU/QT/WIMP: Add option to rename playlists.
|
||||||
|
- MENU/QT/WIMP: Add option to filter extensions inside archives when adding to a playlist.
|
||||||
|
- MENU/QT/WIMP: Rename playlist entries with 2 single clicks.
|
||||||
|
- MENU/QT/WIMP: Fix shader parameter checkboxes not working
|
||||||
|
- METAL: Add screenshot support.
|
||||||
|
- NETPLAY: Save lobby details received back from server after first announcement.
|
||||||
|
- OPENGL/GLX: Implement Adaptive VSync - GLX_EXT_swap_control_tear.
|
||||||
|
- OPENGL/WGL: Implement Adaptive VSync - WGL_EXT_swap_control_tear.
|
||||||
|
- RUNAHEAD: Fix performance degradation that could happen over time (after approx. 30 mins). Fixed input IDs outside of range 0-35 causing slow performance in runahead.
|
||||||
|
- SWITCH: Merging of RetroNX Nintendo Switch port, based on libnx SDK.
|
||||||
|
- VULKAN: Fix race condition in threaded mailbox emulation.
|
||||||
|
- VULKAN: Maintenance fixes.
|
||||||
|
- WIIU: Fix menu lag when built with DevKitPro r32.
|
||||||
|
|
||||||
# 1.7.4
|
# 1.7.4
|
||||||
- ANDROID: Add sustained performance mode, can be turned on/off in Power Management settings menu.
|
- ANDROID: Add sustained performance mode, can be turned on/off in Power Management settings menu.
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
include Makefile.common
|
||||||
|
|
||||||
|
# Qt MOC generation, required for QObject-derived classes
|
||||||
|
ifneq ($(MOC_HEADERS),)
|
||||||
|
# prefix moc_ to base filename of paths and change extension from h to cpp, so a/b/foo.h becomes a/b/moc_foo.cpp
|
||||||
|
MOC_SRC := $(join $(addsuffix moc_,$(dir $(MOC_HEADERS))), $(notdir $(MOC_HEADERS:.h=.cpp)))
|
||||||
|
endif
|
||||||
|
|
||||||
|
MOC ?= $(error missing moc path)
|
||||||
|
|
||||||
|
.PHONY: generate
|
||||||
|
|
||||||
|
$(MOC_SRC):
|
||||||
|
@$(if $(Q), $(shell echo echo MOC $<),)
|
||||||
|
$(eval MOC_TMP := $(patsubst %.h,%_moc.cpp,$@))
|
||||||
|
$(MOC) -o $(MOC_TMP) $<
|
||||||
|
|
||||||
|
$(foreach x,$(join $(addsuffix :,$(MOC_SRC)),$(MOC_HEADERS)),$(eval $x))
|
||||||
|
|
||||||
|
generate: $(MOC_SRC)
|
||||||
|
@echo $(MOC_SRC)
|
||||||
|
|
||||||
|
print-%:
|
||||||
|
@echo '$*=$($*)'
|
|
@ -399,6 +399,7 @@ ifneq ($(C89_BUILD), 1)
|
||||||
HAVE_GTKPLUS = 0
|
HAVE_GTKPLUS = 0
|
||||||
|
|
||||||
ifeq ($(HAVE_SSL), 1)
|
ifeq ($(HAVE_SSL), 1)
|
||||||
|
ifeq ($(HAVE_NETWORKING), 1)
|
||||||
DEFINES += -DHAVE_SSL
|
DEFINES += -DHAVE_SSL
|
||||||
|
|
||||||
ifeq ($(DEBUG), 1)
|
ifeq ($(DEBUG), 1)
|
||||||
|
@ -485,6 +486,7 @@ OBJS_TLS = deps/mbedtls/debug.o \
|
||||||
OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS)
|
OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
|
|
||||||
|
@ -525,6 +527,10 @@ ifeq ($(TARGET), retroarch_3ds)
|
||||||
OBJ += gfx/drivers_font/ctr_font.o
|
OBJ += gfx/drivers_font/ctr_font.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_LIBNX), 1)
|
||||||
|
OBJ += gfx/drivers_font/switch_font.o
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_OSS), 1)
|
ifeq ($(HAVE_OSS), 1)
|
||||||
OBJ += audio/drivers/oss.o
|
OBJ += audio/drivers/oss.o
|
||||||
else ifeq ($(HAVE_OSS_BSD), 1)
|
else ifeq ($(HAVE_OSS_BSD), 1)
|
||||||
|
@ -708,7 +714,6 @@ endif
|
||||||
ifeq ($(HAVE_STRIPES), 1)
|
ifeq ($(HAVE_STRIPES), 1)
|
||||||
OBJ += menu/drivers/stripes.o
|
OBJ += menu/drivers/stripes.o
|
||||||
DEFINES += -DHAVE_STRIPES
|
DEFINES += -DHAVE_STRIPES
|
||||||
HAVE_MENU_COMMON = 1
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_LAKKA), 1)
|
ifeq ($(HAVE_LAKKA), 1)
|
||||||
|
@ -719,7 +724,6 @@ ifeq ($(HAVE_MENU_COMMON), 1)
|
||||||
OBJ += menu/menu_driver.o \
|
OBJ += menu/menu_driver.o \
|
||||||
menu/menu_content.o \
|
menu/menu_content.o \
|
||||||
menu/menu_input.o \
|
menu/menu_input.o \
|
||||||
menu/menu_event.o \
|
|
||||||
menu/menu_entries.o \
|
menu/menu_entries.o \
|
||||||
menu/menu_setting.o \
|
menu/menu_setting.o \
|
||||||
menu/menu_networking.o \
|
menu/menu_networking.o \
|
||||||
|
@ -821,10 +825,20 @@ ifeq ($(TARGET), retroarch_3ds)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(TARGET), retroarch_switch)
|
ifeq ($(TARGET), retroarch_switch)
|
||||||
OBJ += gfx/drivers/switch_gfx.o \
|
ifeq ($(HAVE_LIBNX), 1)
|
||||||
input/drivers/switch_input.o \
|
OBJ += menu/drivers_display/menu_display_switch.o \
|
||||||
input/drivers_joypad/switch_joypad.o \
|
gfx/drivers/switch_nx_gfx.o
|
||||||
audio/drivers/switch_audio.o
|
ifeq ($(HAVE_OPENGL), 1)
|
||||||
|
OBJ += gfx/drivers_context/switch_ctx.o
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
OBJ += gfx/drivers/switch_gfx.o
|
||||||
|
endif
|
||||||
|
OBJ += audio/drivers/switch_audio.o \
|
||||||
|
audio/drivers/switch_thread_audio.o \
|
||||||
|
input/drivers/switch_input.o \
|
||||||
|
input/drivers_joypad/switch_joypad.o \
|
||||||
|
frontend/drivers/platform_switch.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_WAYLAND), 1)
|
ifeq ($(HAVE_WAYLAND), 1)
|
||||||
|
|
|
@ -193,7 +193,7 @@ else ifeq ($(libogc_platform), 1)
|
||||||
RARCH_CONSOLE = 1
|
RARCH_CONSOLE = 1
|
||||||
|
|
||||||
ifeq ($(platform), wii)
|
ifeq ($(platform), wii)
|
||||||
HAVE_LANGEXTRA := 1
|
#HAVE_LANGEXTRA := 1
|
||||||
HAVE_WIIUSB_HID := 1
|
HAVE_WIIUSB_HID := 1
|
||||||
HAVE_RARCH_EXEC := 1
|
HAVE_RARCH_EXEC := 1
|
||||||
HAVE_RSOUND := 1
|
HAVE_RSOUND := 1
|
||||||
|
@ -250,7 +250,7 @@ else ifeq ($(platform), psp1)
|
||||||
HAVE_RBMP := 1
|
HAVE_RBMP := 1
|
||||||
HAVE_RTGA := 1
|
HAVE_RTGA := 1
|
||||||
HAVE_KERNEL_PRX := 1
|
HAVE_KERNEL_PRX := 1
|
||||||
HAVE_LANGEXTRA := 1
|
#HAVE_LANGEXTRA := 1
|
||||||
RARCH_CONSOLE = 1
|
RARCH_CONSOLE = 1
|
||||||
|
|
||||||
ifeq ($(BUILD_PRX), 1)
|
ifeq ($(BUILD_PRX), 1)
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOPDIR ?= $(CURDIR)
|
||||||
|
include $(DEVKITPRO)/libnx/switch_rules
|
||||||
|
|
||||||
|
TARGET := retroarch_switch
|
||||||
|
|
||||||
|
DEBUG ?= 0
|
||||||
|
WHOLE_ARCHIVE_LINK = 0
|
||||||
|
GRIFFIN_BUILD = 0
|
||||||
|
|
||||||
|
OBJ :=
|
||||||
|
|
||||||
|
# For threading we need to overwrite some vars with global defines because devkitPro's includes
|
||||||
|
# make it hard for us. This works for the pthread wrapper
|
||||||
|
DEFINES_THREAD := -Dpthread_t=Thread -Dpthread_mutex_t=Mutex -Dpthread_mutexattr_t='void*' -Dpthread_attr_t=int -Dpthread_cond_t=CondVar -Dpthread_condattr_t='int' -D_SYS__PTHREADTYPES_H_
|
||||||
|
DEFINES := -D__SWITCH__=1 -U__linux__ -U__linux -DGLM_FORCE_PURE=1 -DRARCH_CONSOLE -DRARCH_INTERNAL -DGLOBAL_CONFIG_DIR='"/switch"' $(DEFINES_THREAD)
|
||||||
|
|
||||||
|
HAVE_CC_RESAMPLER = 1
|
||||||
|
HAVE_MENU_COMMON = 1
|
||||||
|
HAVE_RTGA = 1
|
||||||
|
HAVE_RPNG = 1
|
||||||
|
HAVE_RJPEG = 1
|
||||||
|
HAVE_RBMP = 1
|
||||||
|
HAVE_ZLIB = 1
|
||||||
|
HAVE_BUILTINZLIB = 1
|
||||||
|
HAVE_LIBRETRODB = 1
|
||||||
|
HAVE_STATIC_VIDEO_FILTERS = 1
|
||||||
|
HAVE_STATIC_AUDIO_FILTERS = 1
|
||||||
|
HAVE_MENU = 1
|
||||||
|
HAVE_RUNAHEAD = 1
|
||||||
|
|
||||||
|
# RetroArch libnx useful flags
|
||||||
|
HAVE_OVERLAY = 0
|
||||||
|
HAVE_THREADS = 1
|
||||||
|
HAVE_PTHREADS = 1
|
||||||
|
HAVE_FREETYPE = 0
|
||||||
|
HAVE_SWITCH = 1
|
||||||
|
HAVE_LIBNX = 1
|
||||||
|
HAVE_OPENGL = 0
|
||||||
|
|
||||||
|
ifeq ($(HAVE_OPENGL), 1)
|
||||||
|
HAVE_EGL = 1
|
||||||
|
HAVE_SHADERPIPELINE = 1
|
||||||
|
|
||||||
|
HAVE_RGUI = 1
|
||||||
|
HAVE_MATERIALUI = 1
|
||||||
|
|
||||||
|
HAVE_ZARCH = 0
|
||||||
|
HAVE_XMB = 0
|
||||||
|
HAVE_STRIPES = 0
|
||||||
|
else
|
||||||
|
HAVE_RGUI = 1
|
||||||
|
|
||||||
|
HAVE_ZARCH = 0
|
||||||
|
HAVE_MATERIALUI = 0
|
||||||
|
HAVE_XMB = 0
|
||||||
|
HAVE_STRIPES = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
include Makefile.common
|
||||||
|
BLACKLIST :=
|
||||||
|
#BLACKLIST += input/input_overlay.o
|
||||||
|
#BLACKLIST += tasks/task_overlay.o
|
||||||
|
|
||||||
|
OBJ := $(filter-out $(BLACKLIST),$(OBJ))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# TARGET is the name of the output
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# DATA is a list of directories containing data files
|
||||||
|
# INCLUDES is a list of directories containing header files
|
||||||
|
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
|
||||||
|
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
||||||
|
#
|
||||||
|
# NO_ICON: if set to anything, do not use icon.
|
||||||
|
# NO_NACP: if set to anything, no .nacp file is generated.
|
||||||
|
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
||||||
|
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
||||||
|
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
||||||
|
# If not set, it attempts to use one of the following (in this order):
|
||||||
|
# - <Project name>.jpg
|
||||||
|
# - icon.jpg
|
||||||
|
# - <libnx folder>/default_icon.jpg
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := $(CURDIR)/source
|
||||||
|
DATA := data
|
||||||
|
INCLUDES := include
|
||||||
|
EXEFS_SRC := exefs_src
|
||||||
|
#ROMFS := switch/romfs
|
||||||
|
|
||||||
|
APP_TITLE := RetroArch
|
||||||
|
APP_VERSION := 1.0.0
|
||||||
|
APP_AUTHOR := libretro Team
|
||||||
|
NO_ICON := 1
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -mcpu=cortex-a57+crc+fp+simd
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O3 -ffast-math -ffunction-sections \
|
||||||
|
$(ARCH) $(DEFINES) -Ideps -Ideps/libz -Ilibretro-common/include -Ideps/stb -I$(LIBNX)/include -I$(PORTLIBS)/include/ -include $(LIBNX)/include/switch.h #$(shell $(DEVKITPRO)/portlibs/switch/bin/freetype-config --cflags)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -DSWITCH=1 -DHAVE_LIBNX=1 -DNXLINK=1
|
||||||
|
|
||||||
|
# The following line works around an issue in newlib that produces a compilation
|
||||||
|
# error in glm. It will be removed as soon as this issue is resolved.
|
||||||
|
CFLAGS += -D_GLIBCXX_USE_C99_MATH_TR1 -D_LDBL_EQ_DBL
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs $(ARCH) -Wl,--allow-multiple-definition -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
LIBS := -lstdc++ -lbz2 -lpng -lz -lnx -lm
|
||||||
|
|
||||||
|
ifeq ($(HAVE_OPENGL), 1)
|
||||||
|
LIBS := -lEGL -lglapi -ldrm_nouveau $(LIBS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(TARGET)
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES := $(OBJ) libretro_switch.a
|
||||||
|
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
|
||||||
|
|
||||||
|
ifeq ($(strip $(ICON)),)
|
||||||
|
icons := $(wildcard *.jpg)
|
||||||
|
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||||
|
else
|
||||||
|
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||||
|
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_ICON)),)
|
||||||
|
export NROFLAGS += --icon=$(APP_ICON)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_NACP)),)
|
||||||
|
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(APP_TITLEID),)
|
||||||
|
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(ROMFS),)
|
||||||
|
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
.PHONY: clean all
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all : $(OUTPUT).pfs0 $(OUTPUT).nro
|
||||||
|
|
||||||
|
$(OUTPUT).pfs0 : $(OUTPUT).nso
|
||||||
|
|
||||||
|
$(OUTPUT).nso : $(OUTPUT).elf
|
||||||
|
|
||||||
|
ifeq ($(strip $(NO_NACP)),)
|
||||||
|
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||||
|
else
|
||||||
|
$(OUTPUT).nro : $(OUTPUT).elf
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OBJ)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ) $(OUTPUT).pfs0 $(OUTPUT).nro $(OUTPUT).elf
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
|
@ -42,7 +42,7 @@ endif
|
||||||
|
|
||||||
|
|
||||||
ifeq ($(strip $(LIBTRANSISTOR_HOME)),)
|
ifeq ($(strip $(LIBTRANSISTOR_HOME)),)
|
||||||
$(error "Please set LIBTRANSISTOR_HOME in your environment. export LIBTRANSISTOR_HOME=<path t>o libtransistor")
|
$(error "Please set LIBTRANSISTOR_HOME in your environment. export LIBTRANSISTOR_HOME=<path/to/libtransistor/dist/>")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(LIBTRANSISTOR_HOME)/libtransistor.mk
|
include $(LIBTRANSISTOR_HOME)/libtransistor.mk
|
||||||
|
@ -52,7 +52,7 @@ LIBDIRS := -L.
|
||||||
|
|
||||||
TARGETS := $(TARGET).nro
|
TARGETS := $(TARGET).nro
|
||||||
|
|
||||||
CFLAGS += $(INCDIRS) $(DEFINES) -Wunused-command-line-argument
|
CFLAGS += $(INCDIRS) $(DEFINES) -Wno-unused-command-line-argument -Werror-implicit-function-declaration
|
||||||
|
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,7 @@ static const audio_driver_t *audio_drivers[] = {
|
||||||
#endif
|
#endif
|
||||||
#ifdef SWITCH
|
#ifdef SWITCH
|
||||||
&audio_switch,
|
&audio_switch,
|
||||||
|
&audio_switch_thread,
|
||||||
#endif
|
#endif
|
||||||
&audio_null,
|
&audio_null,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
|
@ -338,6 +338,7 @@ extern audio_driver_t audio_psp;
|
||||||
extern audio_driver_t audio_ctr_csnd;
|
extern audio_driver_t audio_ctr_csnd;
|
||||||
extern audio_driver_t audio_ctr_dsp;
|
extern audio_driver_t audio_ctr_dsp;
|
||||||
extern audio_driver_t audio_switch;
|
extern audio_driver_t audio_switch;
|
||||||
|
extern audio_driver_t audio_switch_thread;
|
||||||
extern audio_driver_t audio_rwebaudio;
|
extern audio_driver_t audio_rwebaudio;
|
||||||
extern audio_driver_t audio_null;
|
extern audio_driver_t audio_null;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
/* RetroArch - A frontend for libretro.
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2018 - misson20000
|
||||||
|
* Copyright (C) 2018 - m4xw
|
||||||
*
|
*
|
||||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
* RetroArch 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 Found-
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
@ -17,12 +19,16 @@
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include<libtransistor/nx.h>
|
#include "switch_audio_compat.h"
|
||||||
#include<libtransistor/alloc_pages.h>
|
|
||||||
|
|
||||||
#include "../audio_driver.h"
|
#include "../audio_driver.h"
|
||||||
#include "../../verbosity.h"
|
#include "../../verbosity.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
#define BUFFER_COUNT 5
|
||||||
|
#else
|
||||||
|
#define BUFFER_COUNT 3
|
||||||
|
#endif
|
||||||
|
|
||||||
static const int sample_rate = 48000;
|
static const int sample_rate = 48000;
|
||||||
static const int max_num_samples = sample_rate;
|
static const int max_num_samples = sample_rate;
|
||||||
static const int num_channels = 2;
|
static const int num_channels = 2;
|
||||||
|
@ -30,38 +36,57 @@ static const size_t sample_buffer_size = ((max_num_samples * num_channels * size
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
audio_output_t output;
|
|
||||||
handle_t event;
|
|
||||||
audio_output_buffer_t buffers[3];
|
|
||||||
audio_output_buffer_t *current_buffer;
|
|
||||||
bool blocking;
|
bool blocking;
|
||||||
bool is_paused;
|
bool is_paused;
|
||||||
uint64_t last_append;
|
uint64_t last_append;
|
||||||
unsigned latency;
|
unsigned latency;
|
||||||
|
compat_audio_out_buffer buffers[BUFFER_COUNT];
|
||||||
|
compat_audio_out_buffer *current_buffer;
|
||||||
|
|
||||||
|
#ifndef HAVE_LIBNX
|
||||||
|
audio_output_t output;
|
||||||
|
handle_t event;
|
||||||
|
#endif
|
||||||
} switch_audio_t;
|
} switch_audio_t;
|
||||||
|
|
||||||
|
static uint32_t switch_audio_data_size(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
static const int framerate = 1000 / 30;
|
||||||
|
static const int samplecount = (sample_rate / framerate);
|
||||||
|
return (samplecount * num_channels * sizeof(uint16_t));
|
||||||
|
#else
|
||||||
|
return sample_buffer_size;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t switch_audio_buffer_size(void *data)
|
||||||
|
{
|
||||||
|
(void) data;
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
return (switch_audio_data_size() + 0xfff) & ~0xfff;
|
||||||
|
#else
|
||||||
|
return sample_buffer_size;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t switch_audio_write(void *data, const void *buf, size_t size)
|
static ssize_t switch_audio_write(void *data, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
size_t to_write = size;
|
size_t to_write = size;
|
||||||
switch_audio_t *swa = (switch_audio_t*) data;
|
switch_audio_t *swa = (switch_audio_t*) data;
|
||||||
|
|
||||||
#if 0
|
if (!swa)
|
||||||
RARCH_LOG("write %ld samples\n", size/sizeof(uint16_t));
|
return -1;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!swa->current_buffer)
|
if (!swa->current_buffer)
|
||||||
{
|
{
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
if (audio_ipc_output_get_released_buffer(&swa->output, &num, &swa->current_buffer) != RESULT_OK)
|
if (switch_audio_ipc_output_get_released_buffer(swa, num) != 0)
|
||||||
{
|
{
|
||||||
RARCH_LOG("Failed to get released buffer?\n");
|
RARCH_LOG("Failed to get released buffer?\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
RARCH_LOG("got buffer, num %d, ptr %p\n", num, swa->current_buffer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (num < 1)
|
if (num < 1)
|
||||||
swa->current_buffer = NULL;
|
swa->current_buffer = NULL;
|
||||||
|
|
||||||
|
@ -73,47 +98,46 @@ static ssize_t switch_audio_write(void *data, const void *buf, size_t size)
|
||||||
|
|
||||||
while(swa->current_buffer == NULL)
|
while(swa->current_buffer == NULL)
|
||||||
{
|
{
|
||||||
uint32_t num;
|
uint32_t handle_idx = 0;
|
||||||
uint32_t handle_idx;
|
num = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
if (audoutWaitPlayFinish(&swa->current_buffer, &num, U64_MAX) != 0) { }
|
||||||
|
#else
|
||||||
svcWaitSynchronization(&handle_idx, &swa->event, 1, 33333333);
|
svcWaitSynchronization(&handle_idx, &swa->event, 1, 33333333);
|
||||||
svcResetSignal(swa->event);
|
svcResetSignal(swa->event);
|
||||||
|
|
||||||
if (audio_ipc_output_get_released_buffer(&swa->output, &num, &swa->current_buffer) != RESULT_OK)
|
if (switch_audio_ipc_output_get_released_buffer(swa, num) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
/* no buffer, nonblocking... */
|
/* no buffer, nonblocking... */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
swa->current_buffer->data_size = 0;
|
swa->current_buffer->data_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to_write > sample_buffer_size - swa->current_buffer->data_size)
|
if (to_write > switch_audio_buffer_size(NULL) - swa->current_buffer->data_size)
|
||||||
to_write = sample_buffer_size - swa->current_buffer->data_size;
|
to_write = switch_audio_buffer_size(NULL) - swa->current_buffer->data_size;
|
||||||
|
|
||||||
|
#ifndef HAVE_LIBNX
|
||||||
memcpy(((uint8_t*) swa->current_buffer->sample_data) + swa->current_buffer->data_size, buf, to_write);
|
memcpy(((uint8_t*) swa->current_buffer->sample_data) + swa->current_buffer->data_size, buf, to_write);
|
||||||
|
#else
|
||||||
|
memcpy(((uint8_t*) swa->current_buffer->buffer) + swa->current_buffer->data_size, buf, to_write);
|
||||||
|
#endif
|
||||||
swa->current_buffer->data_size += to_write;
|
swa->current_buffer->data_size += to_write;
|
||||||
swa->current_buffer->buffer_size = sample_buffer_size;
|
swa->current_buffer->buffer_size = switch_audio_buffer_size(NULL);
|
||||||
|
|
||||||
if (swa->current_buffer->data_size > (48000*swa->latency)/1000)
|
if (swa->current_buffer->data_size > (48000 * swa->latency) / 1000)
|
||||||
{
|
{
|
||||||
result_t r = audio_ipc_output_append_buffer(&swa->output, swa->current_buffer);
|
if (switch_audio_ipc_output_append_buffer(swa, swa->current_buffer) != 0)
|
||||||
if (r != RESULT_OK)
|
return -1;
|
||||||
{
|
|
||||||
RARCH_ERR("failed to append buffer: 0x%x\n", r);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
swa->current_buffer = NULL;
|
swa->current_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
RARCH_LOG("submitted %ld samples, %ld samples since last submit\n",
|
|
||||||
to_write/num_channels/sizeof(uint16_t),
|
|
||||||
(svcGetSystemTick() - swa->last_append) * sample_rate / 19200000);
|
|
||||||
#endif
|
|
||||||
swa->last_append = svcGetSystemTick();
|
swa->last_append = svcGetSystemTick();
|
||||||
|
|
||||||
return to_write;
|
return to_write;
|
||||||
|
@ -125,25 +149,32 @@ static bool switch_audio_stop(void *data)
|
||||||
if (!swa)
|
if (!swa)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!swa->is_paused) {
|
/* TODO/FIXME - fix libnx codepath */
|
||||||
if(audio_ipc_output_stop(&swa->output) != RESULT_OK)
|
#ifndef HAVE_LIBNX
|
||||||
|
|
||||||
|
if (!swa->is_paused)
|
||||||
|
if (switch_audio_ipc_output_stop(swa) != 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
swa->is_paused = true;
|
swa->is_paused = true;
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool switch_audio_start(void *data, bool is_shutdown)
|
static bool switch_audio_start(void *data, bool is_shutdown)
|
||||||
{
|
{
|
||||||
switch_audio_t *swa = (switch_audio_t*) data;
|
switch_audio_t *swa = (switch_audio_t*) data;
|
||||||
|
if (!swa)
|
||||||
|
return false;
|
||||||
|
|
||||||
if(swa->is_paused) {
|
/* TODO/FIXME - fix libnx codepath */
|
||||||
if (audio_ipc_output_start(&swa->output) != RESULT_OK)
|
#ifndef HAVE_LIBNX
|
||||||
|
if (swa->is_paused)
|
||||||
|
if (switch_audio_ipc_output_start(swa) != 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
swa->is_paused = false;
|
swa->is_paused = false;
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +190,22 @@ static void switch_audio_free(void *data)
|
||||||
{
|
{
|
||||||
switch_audio_t *swa = (switch_audio_t*) data;
|
switch_audio_t *swa = (switch_audio_t*) data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
if (!swa->is_paused)
|
||||||
|
audoutStopAudioOut();
|
||||||
|
|
||||||
|
audoutExit();
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < BUFFER_COUNT; i++)
|
||||||
|
free(swa->buffers[i].buffer);
|
||||||
|
#else
|
||||||
audio_ipc_output_close(&swa->output);
|
audio_ipc_output_close(&swa->output);
|
||||||
audio_ipc_finalize();
|
audio_ipc_finalize();
|
||||||
|
#endif
|
||||||
free(swa);
|
free(swa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,11 +234,10 @@ static void switch_audio_set_nonblock_state(void *data, bool state)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *switch_audio_init(const char *device,
|
static void *switch_audio_init(const char *device,
|
||||||
unsigned rate, unsigned latency,
|
unsigned rate, unsigned latency,
|
||||||
unsigned block_frames,
|
unsigned block_frames,
|
||||||
unsigned *new_rate)
|
unsigned *new_rate)
|
||||||
{
|
{
|
||||||
result_t r;
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
char names[8][0x20];
|
char names[8][0x20];
|
||||||
uint32_t num_names = 0;
|
uint32_t num_names = 0;
|
||||||
|
@ -202,12 +246,14 @@ static void *switch_audio_init(const char *device,
|
||||||
if (!swa)
|
if (!swa)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
r = audio_ipc_init();
|
if (switch_audio_ipc_init() != 0)
|
||||||
|
|
||||||
if (r != RESULT_OK)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (audio_ipc_list_outputs(&names[0], 8, &num_names) != RESULT_OK)
|
#ifdef HAVE_LIBNX
|
||||||
|
if (audoutStartAudioOut() != 0)
|
||||||
|
goto fail;
|
||||||
|
#else
|
||||||
|
if (audio_ipc_list_outputs(&names[0], 8, &num_names) != 0)
|
||||||
goto fail_audio_ipc;
|
goto fail_audio_ipc;
|
||||||
|
|
||||||
if (num_names != 1)
|
if (num_names != 1)
|
||||||
|
@ -216,7 +262,7 @@ static void *switch_audio_init(const char *device,
|
||||||
goto fail_audio_ipc;
|
goto fail_audio_ipc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_ipc_open_output(names[0], &swa->output) != RESULT_OK)
|
if (audio_ipc_open_output(names[0], &swa->output) != 0)
|
||||||
goto fail_audio_ipc;
|
goto fail_audio_ipc;
|
||||||
|
|
||||||
if (swa->output.sample_rate != sample_rate)
|
if (swa->output.sample_rate != sample_rate)
|
||||||
|
@ -239,51 +285,70 @@ static void *switch_audio_init(const char *device,
|
||||||
goto fail_audio_output;
|
goto fail_audio_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_ipc_output_register_buffer_event(&swa->output, &swa->event) != RESULT_OK)
|
if (audio_ipc_output_register_buffer_event(&swa->output, &swa->event) != 0)
|
||||||
goto fail_audio_output;
|
goto fail_audio_output;
|
||||||
|
#endif
|
||||||
|
|
||||||
swa->blocking = block_frames;
|
for (i = 0; i < BUFFER_COUNT; i++)
|
||||||
|
|
||||||
*new_rate = swa->output.sample_rate;
|
|
||||||
|
|
||||||
for(i = 0; i < 3; i++)
|
|
||||||
{
|
{
|
||||||
|
swa->buffers[i].buffer_size = switch_audio_buffer_size(NULL);
|
||||||
|
swa->buffers[i].data_size = switch_audio_data_size();
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
swa->buffers[i].next = NULL; /* Unused */
|
||||||
|
swa->buffers[i].data_offset = 0;
|
||||||
|
swa->buffers[i].buffer = memalign(0x1000, switch_audio_buffer_size(NULL));
|
||||||
|
|
||||||
|
if (swa->buffers[i].buffer == NULL)
|
||||||
|
goto fail_audio_output;
|
||||||
|
|
||||||
|
memset(swa->buffers[i].buffer, 0, switch_audio_buffer_size(NULL));
|
||||||
|
#else
|
||||||
swa->buffers[i].ptr = &swa->buffers[i].sample_data;
|
swa->buffers[i].ptr = &swa->buffers[i].sample_data;
|
||||||
swa->buffers[i].sample_data = alloc_pages(sample_buffer_size, sample_buffer_size, NULL);
|
|
||||||
swa->buffers[i].buffer_size = sample_buffer_size;
|
|
||||||
swa->buffers[i].data_size = sample_buffer_size;
|
|
||||||
swa->buffers[i].unknown = 0;
|
swa->buffers[i].unknown = 0;
|
||||||
|
swa->buffers[i].sample_data = alloc_pages(sample_buffer_size, switch_audio_buffer_size(NULL), NULL);
|
||||||
|
|
||||||
if(swa->buffers[i].sample_data == NULL)
|
if (swa->buffers[i].sample_data == NULL)
|
||||||
goto fail_audio_output;
|
goto fail_audio_output;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (audio_ipc_output_append_buffer(&swa->output, &swa->buffers[i]) != RESULT_OK)
|
if (switch_audio_ipc_output_append_buffer(swa, &swa->buffers[i]) != 0)
|
||||||
goto fail_audio_output;
|
goto fail_audio_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
*new_rate = audoutGetSampleRate();
|
||||||
|
#else
|
||||||
|
*new_rate = swa->output.sample_rate;
|
||||||
|
#endif
|
||||||
|
|
||||||
swa->current_buffer = NULL;
|
swa->current_buffer = NULL;
|
||||||
swa->latency = latency;
|
swa->latency = latency;
|
||||||
swa->last_append = svcGetSystemTick();
|
swa->last_append = svcGetSystemTick();
|
||||||
|
|
||||||
|
swa->blocking = block_frames;
|
||||||
swa->is_paused = true;
|
swa->is_paused = true;
|
||||||
|
|
||||||
|
RARCH_LOG("[Audio]: Audio initialized\n");
|
||||||
|
|
||||||
return swa;
|
return swa;
|
||||||
|
|
||||||
fail_audio_output:
|
fail_audio_output:
|
||||||
|
/* TODO/FIXME - fix libnx codepath */
|
||||||
|
#ifndef HAVE_LIBNX
|
||||||
audio_ipc_output_close(&swa->output);
|
audio_ipc_output_close(&swa->output);
|
||||||
|
#endif
|
||||||
fail_audio_ipc:
|
fail_audio_ipc:
|
||||||
|
/* TODO/FIXME - fix libnx codepath */
|
||||||
|
#ifndef HAVE_LIBNX
|
||||||
audio_ipc_finalize();
|
audio_ipc_finalize();
|
||||||
|
#endif
|
||||||
fail:
|
fail:
|
||||||
free(swa);
|
if (swa)
|
||||||
|
free(swa);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t switch_audio_buffer_size(void *data)
|
|
||||||
{
|
|
||||||
(void) data;
|
|
||||||
return sample_buffer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
audio_driver_t audio_switch = {
|
audio_driver_t audio_switch = {
|
||||||
switch_audio_init,
|
switch_audio_init,
|
||||||
switch_audio_write,
|
switch_audio_write,
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
#ifndef _SWITCH_AUDIO_COMPAT_H
|
||||||
|
#define _SWITCH_AUDIO_COMPAT_H
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
#include <switch.h>
|
||||||
|
#else
|
||||||
|
#include <libtransistor/nx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
|
||||||
|
/* libnx definitions */
|
||||||
|
|
||||||
|
/* threading */
|
||||||
|
typedef Mutex compat_mutex;
|
||||||
|
typedef Thread compat_thread;
|
||||||
|
typedef CondVar compat_condvar;
|
||||||
|
|
||||||
|
#define compat_thread_create(thread, func, data, stack_size, prio, cpu) \
|
||||||
|
threadCreate(thread, func, data, stack_size, prio, cpu)
|
||||||
|
#define compat_thread_start(thread) \
|
||||||
|
threadStart(thread)
|
||||||
|
#define compat_thread_join(thread) \
|
||||||
|
threadWaitForExit(thread)
|
||||||
|
#define compat_thread_close(thread) \
|
||||||
|
threadClose(thread)
|
||||||
|
#define compat_mutex_create(mutex) \
|
||||||
|
mutexInit(mutex)
|
||||||
|
#define compat_mutex_lock(mutex) \
|
||||||
|
mutexLock(mutex)
|
||||||
|
#define compat_mutex_unlock(mutex) \
|
||||||
|
mutexUnlock(mutex)
|
||||||
|
#define compat_condvar_create(condvar) \
|
||||||
|
condvarInit(condvar)
|
||||||
|
#define compat_condvar_wait(condvar, mutex) \
|
||||||
|
condvarWait(condvar, mutex)
|
||||||
|
#define compat_condvar_wake_all(condvar) \
|
||||||
|
condvarWakeAll(condvar)
|
||||||
|
|
||||||
|
/* audio */
|
||||||
|
typedef AudioOutBuffer compat_audio_out_buffer;
|
||||||
|
#define switch_audio_ipc_init audoutInitialize
|
||||||
|
#define switch_audio_ipc_finalize audoutExit
|
||||||
|
#define switch_audio_ipc_output_get_released_buffer(a, b) audoutGetReleasedAudioOutBuffer(&a->current_buffer, &b)
|
||||||
|
#define switch_audio_ipc_output_append_buffer(a, b) audoutAppendAudioOutBuffer(b)
|
||||||
|
#define switch_audio_ipc_output_stop(a) audoutStopAudioOut()
|
||||||
|
#define switch_audio_ipc_output_start(a) audoutStartAudioOut()
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* libtransistor definitions */
|
||||||
|
|
||||||
|
typedef result_t Result;
|
||||||
|
#define R_FAILED(r) ((r) != RESULT_OK)
|
||||||
|
|
||||||
|
/* threading */
|
||||||
|
typedef trn_mutex_t compat_mutex;
|
||||||
|
typedef trn_thread_t compat_thread;
|
||||||
|
typedef trn_condvar_t compat_condvar;
|
||||||
|
|
||||||
|
#define compat_thread_create(thread, func, data, stack_size, prio, cpu) \
|
||||||
|
trn_thread_create(thread, func, data, prio, cpu, stack_size, NULL)
|
||||||
|
#define compat_thread_start(thread) \
|
||||||
|
trn_thread_start(thread)
|
||||||
|
#define compat_thread_join(thread) \
|
||||||
|
trn_thread_join(thread, -1)
|
||||||
|
#define compat_thread_close(thread) \
|
||||||
|
trn_thread_destroy(thread)
|
||||||
|
#define compat_mutex_create(mutex) \
|
||||||
|
trn_mutex_create(mutex)
|
||||||
|
#define compat_mutex_lock(mutex) \
|
||||||
|
trn_mutex_lock(mutex)
|
||||||
|
#define compat_mutex_unlock(mutex) \
|
||||||
|
trn_mutex_unlock(mutex)
|
||||||
|
#define compat_condvar_create(condvar) \
|
||||||
|
trn_condvar_create(condvar)
|
||||||
|
#define compat_condvar_wait(condvar, mutex) \
|
||||||
|
trn_condvar_wait(condvar, mutex, -1)
|
||||||
|
#define compat_condvar_wake_all(condvar) \
|
||||||
|
trn_condvar_signal(condvar, -1)
|
||||||
|
|
||||||
|
/* audio */
|
||||||
|
typedef audio_output_buffer_t compat_audio_out_buffer;
|
||||||
|
#define switch_audio_ipc_init audio_ipc_init
|
||||||
|
#define switch_audio_ipc_finalize audio_ipc_finalize
|
||||||
|
#define switch_audio_ipc_output_get_released_buffer(a, b) audio_ipc_output_get_released_buffer(&a->output, &b, &a->current_buffer)
|
||||||
|
#define switch_audio_ipc_output_append_buffer(a, b) audio_ipc_output_append_buffer(&a->output, b)
|
||||||
|
#define switch_audio_ipc_output_stop(a) audio_ipc_output_stop(&a->output)
|
||||||
|
#define switch_audio_ipc_output_start(a) audio_ipc_output_start(&a->output)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,448 @@
|
||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2018 - misson20000
|
||||||
|
* Copyright (C) 2018 - m4xw
|
||||||
|
* Copyright (C) 2018 - lifajucejo
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/unistd.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
#include <switch.h>
|
||||||
|
#else
|
||||||
|
#include <libtransistor/nx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <queues/fifo_queue.h>
|
||||||
|
#include "../audio_driver.h"
|
||||||
|
#include "../../verbosity.h"
|
||||||
|
|
||||||
|
#include "../../tasks/tasks_internal.h"
|
||||||
|
|
||||||
|
#include "switch_audio_compat.h"
|
||||||
|
|
||||||
|
static const size_t thread_stack_size = 1024 * 8;
|
||||||
|
static const int thread_preferred_cpu = 2;
|
||||||
|
static const int channel_count = 2;
|
||||||
|
static const size_t sample_size = sizeof(uint16_t);
|
||||||
|
static const size_t frame_size = channel_count * sample_size;
|
||||||
|
|
||||||
|
#define AUDIO_BUFFER_COUNT 2
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
fifo_buffer_t* fifo;
|
||||||
|
compat_mutex fifoLock;
|
||||||
|
compat_condvar cond;
|
||||||
|
compat_mutex condLock;
|
||||||
|
|
||||||
|
size_t fifoSize;
|
||||||
|
|
||||||
|
volatile bool running;
|
||||||
|
bool nonblocking;
|
||||||
|
bool is_paused;
|
||||||
|
|
||||||
|
compat_audio_out_buffer buffers[AUDIO_BUFFER_COUNT];
|
||||||
|
compat_thread thread;
|
||||||
|
|
||||||
|
unsigned latency;
|
||||||
|
uint32_t sampleRate;
|
||||||
|
|
||||||
|
#ifndef HAVE_LIBNX
|
||||||
|
audio_output_t output;
|
||||||
|
handle_t event;
|
||||||
|
#endif
|
||||||
|
} switch_thread_audio_t;
|
||||||
|
|
||||||
|
static void mainLoop(void* data)
|
||||||
|
{
|
||||||
|
Result rc;
|
||||||
|
uint32_t released_out_count = 0;
|
||||||
|
compat_audio_out_buffer *released_out_buffer = NULL;
|
||||||
|
switch_thread_audio_t *swa = (switch_thread_audio_t*)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RARCH_LOG("[Audio]: start mainLoop cpu %u tid %u\n", svcGetCurrentProcessorNumber(), swa->thread.handle);
|
||||||
|
|
||||||
|
|
||||||
|
while (swa->running)
|
||||||
|
{
|
||||||
|
size_t buf_avail, avail, to_write;
|
||||||
|
|
||||||
|
if (!released_out_buffer)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
rc = audoutWaitPlayFinish(&released_out_buffer, &released_out_count, U64_MAX);
|
||||||
|
#else
|
||||||
|
uint32_t handle_idx = 0;
|
||||||
|
svcWaitSynchronization(&handle_idx, &swa->event, 1, 33333333);
|
||||||
|
svcResetSignal(swa->event);
|
||||||
|
|
||||||
|
rc = audio_ipc_output_get_released_buffer(&swa->output, &released_out_count, &released_out_buffer);
|
||||||
|
#endif
|
||||||
|
if (R_FAILED(rc))
|
||||||
|
{
|
||||||
|
swa->running = false;
|
||||||
|
RARCH_LOG("[Audio]: audoutGetReleasedAudioOutBuffer failed: %d\n", (int)rc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
released_out_buffer->data_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_avail = released_out_buffer->buffer_size - released_out_buffer->data_size;
|
||||||
|
|
||||||
|
compat_mutex_lock(&swa->fifoLock);
|
||||||
|
|
||||||
|
avail = fifo_read_avail(swa->fifo);
|
||||||
|
to_write = MIN(avail, buf_avail);
|
||||||
|
if (to_write > 0)
|
||||||
|
{
|
||||||
|
uint8_t *base;
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
base = (uint8_t*) released_out_buffer->buffer;
|
||||||
|
#else
|
||||||
|
base = (uint8_t*) released_out_buffer->sample_data;
|
||||||
|
#endif
|
||||||
|
fifo_read(swa->fifo, base + released_out_buffer->data_size, to_write);
|
||||||
|
}
|
||||||
|
|
||||||
|
compat_mutex_unlock(&swa->fifoLock);
|
||||||
|
compat_condvar_wake_all(&swa->cond);
|
||||||
|
|
||||||
|
released_out_buffer->data_size += to_write;
|
||||||
|
if (released_out_buffer->data_size >= released_out_buffer->buffer_size / 2)
|
||||||
|
{
|
||||||
|
rc = switch_audio_ipc_output_append_buffer(swa, released_out_buffer);
|
||||||
|
if (R_FAILED(rc))
|
||||||
|
{
|
||||||
|
RARCH_LOG("[Audio]: audoutAppendAudioOutBuffer failed: %d\n", (int)rc);
|
||||||
|
}
|
||||||
|
released_out_buffer = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
svcSleepThread(16000000); /* 16ms */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *switch_thread_audio_init(const char *device, unsigned rate, unsigned latency, unsigned block_frames, unsigned *new_rate)
|
||||||
|
{
|
||||||
|
Result rc;
|
||||||
|
unsigned i;
|
||||||
|
uint32_t prio;
|
||||||
|
char names[8][0x20];
|
||||||
|
uint32_t num_names = 0;
|
||||||
|
switch_thread_audio_t *swa = (switch_thread_audio_t *)calloc(1, sizeof(*swa));
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
swa->running = true;
|
||||||
|
swa->nonblocking = true;
|
||||||
|
swa->is_paused = true;
|
||||||
|
swa->latency = MAX(latency, 8);
|
||||||
|
|
||||||
|
rc = switch_audio_ipc_init();
|
||||||
|
if (R_FAILED(rc))
|
||||||
|
{
|
||||||
|
RARCH_LOG("[Audio]: audio init failed %d\n", (int)rc);
|
||||||
|
free(swa);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
rc = audoutStartAudioOut();
|
||||||
|
if (R_FAILED(rc))
|
||||||
|
{
|
||||||
|
RARCH_LOG("[Audio]: audio start init failed: %d\n", (int)rc);
|
||||||
|
goto fail_audio_ipc;
|
||||||
|
}
|
||||||
|
|
||||||
|
swa->sampleRate = audoutGetSampleRate();
|
||||||
|
#else
|
||||||
|
if (audio_ipc_list_outputs(&names[0], 8, &num_names) != RESULT_OK)
|
||||||
|
goto fail_audio_ipc;
|
||||||
|
|
||||||
|
if (num_names != 1)
|
||||||
|
{
|
||||||
|
RARCH_ERR("[Audio]: got back more than one AudioOut\n");
|
||||||
|
goto fail_audio_ipc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_ipc_open_output(names[0], &swa->output) != RESULT_OK)
|
||||||
|
goto fail_audio_ipc;
|
||||||
|
|
||||||
|
swa->sampleRate = swa->output.sample_rate;
|
||||||
|
|
||||||
|
if (swa->output.num_channels != 2)
|
||||||
|
{
|
||||||
|
RARCH_ERR("expected %d channels, got %d\n", 2,
|
||||||
|
swa->output.num_channels);
|
||||||
|
goto fail_audio_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swa->output.sample_format != PCM_INT16)
|
||||||
|
{
|
||||||
|
RARCH_ERR("expected PCM_INT16, got %d\n", swa->output.sample_format);
|
||||||
|
goto fail_audio_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_ipc_output_register_buffer_event(&swa->output, &swa->event) != 0)
|
||||||
|
goto fail_audio_output;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*new_rate = swa->sampleRate;
|
||||||
|
swa->fifoSize = (swa->sampleRate * sample_size * swa->latency) / 1000;
|
||||||
|
|
||||||
|
for (i = 0; i < AUDIO_BUFFER_COUNT; i++)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
swa->buffers[i].next = NULL; /* Unused */
|
||||||
|
swa->buffers[i].data_offset = 0;
|
||||||
|
swa->buffers[i].buffer_size = swa->fifoSize;
|
||||||
|
swa->buffers[i].data_size = swa->buffers[i].buffer_size;
|
||||||
|
swa->buffers[i].buffer = memalign(0x1000, swa->buffers[i].buffer_size);
|
||||||
|
|
||||||
|
if (swa->buffers[i].buffer == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
memset(swa->buffers[i].buffer, 0, swa->buffers[i].buffer_size);
|
||||||
|
#else
|
||||||
|
swa->buffers[i].ptr = &swa->buffers[i].sample_data;
|
||||||
|
swa->buffers[i].unknown = 0;
|
||||||
|
swa->buffers[i].buffer_size = swa->fifoSize;
|
||||||
|
swa->buffers[i].data_size = swa->buffers[i].buffer_size;
|
||||||
|
swa->buffers[i].sample_data = alloc_pages(swa->buffers[i].buffer_size, swa->buffers[i].buffer_size, NULL);
|
||||||
|
|
||||||
|
if (swa->buffers[i].sample_data == NULL)
|
||||||
|
goto fail_audio_output;
|
||||||
|
|
||||||
|
memset(swa->buffers[i].sample_data, 0, swa->buffers[i].buffer_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (switch_audio_ipc_output_append_buffer(swa, &swa->buffers[i]) != 0)
|
||||||
|
goto fail_audio_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
compat_mutex_create(&swa->fifoLock);
|
||||||
|
swa->fifo = fifo_new(swa->fifoSize);
|
||||||
|
|
||||||
|
compat_condvar_create(&swa->cond);
|
||||||
|
|
||||||
|
RARCH_LOG("[Audio]: switch_thread_audio_init device %s requested rate %hu rate %hu latency %hu block_frames %hu fifoSize %lu\n",
|
||||||
|
device, rate, swa->sampleRate, swa->latency, block_frames, swa->fifoSize);
|
||||||
|
|
||||||
|
svcGetThreadPriority(&prio, 0xffff8000);
|
||||||
|
rc = compat_thread_create(&swa->thread, &mainLoop, (void*)swa, thread_stack_size, prio - 1, thread_preferred_cpu);
|
||||||
|
|
||||||
|
if (R_FAILED(rc))
|
||||||
|
{
|
||||||
|
RARCH_LOG("[Audio]: thread creation failed create %u\n", swa->thread.handle);
|
||||||
|
swa->running = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_FAILED(compat_thread_start(&swa->thread)))
|
||||||
|
{
|
||||||
|
RARCH_LOG("[Audio]: thread creation failed start %u\n", swa->thread.handle);
|
||||||
|
compat_thread_close(&swa->thread);
|
||||||
|
swa->running = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return swa;
|
||||||
|
|
||||||
|
fail_audio_output:
|
||||||
|
#ifndef HAVE_LIBNX
|
||||||
|
audio_ipc_output_close(&swa->output);
|
||||||
|
#endif
|
||||||
|
fail_audio_ipc:
|
||||||
|
switch_audio_ipc_finalize();
|
||||||
|
fail:
|
||||||
|
free(swa); // freeing a null ptr is valid
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_thread_audio_start(void *data, bool is_shutdown)
|
||||||
|
{
|
||||||
|
/* RARCH_LOG("[Audio]: switch_thread_audio_start\n"); */
|
||||||
|
switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
swa->is_paused = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_thread_audio_stop(void *data)
|
||||||
|
{
|
||||||
|
switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
swa->is_paused = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_thread_audio_free(void *data)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (swa->running)
|
||||||
|
{
|
||||||
|
swa->running = false;
|
||||||
|
compat_thread_join(&swa->thread);
|
||||||
|
compat_thread_close(&swa->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_audio_ipc_output_stop(swa);
|
||||||
|
switch_audio_ipc_finalize();
|
||||||
|
|
||||||
|
if (swa->fifo)
|
||||||
|
{
|
||||||
|
fifo_free(swa->fifo);
|
||||||
|
swa->fifo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(swa->buffers); i++)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
free(swa->buffers[i].buffer);
|
||||||
|
#else
|
||||||
|
free_pages(swa->buffers[i].sample_data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
free(swa);
|
||||||
|
swa = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t switch_thread_audio_write(void *data, const void *buf, size_t size)
|
||||||
|
{
|
||||||
|
size_t avail, written;
|
||||||
|
switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
|
||||||
|
|
||||||
|
if (!swa || !swa->running)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (swa->nonblocking)
|
||||||
|
{
|
||||||
|
compat_mutex_lock(&swa->fifoLock);
|
||||||
|
avail = fifo_write_avail(swa->fifo);
|
||||||
|
written = MIN(avail, size);
|
||||||
|
if (written > 0)
|
||||||
|
fifo_write(swa->fifo, buf, written);
|
||||||
|
compat_mutex_unlock(&swa->fifoLock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
written = 0;
|
||||||
|
while (written < size && swa->running)
|
||||||
|
{
|
||||||
|
compat_mutex_lock(&swa->fifoLock);
|
||||||
|
avail = fifo_write_avail(swa->fifo);
|
||||||
|
if (avail == 0)
|
||||||
|
{
|
||||||
|
compat_mutex_unlock(&swa->fifoLock);
|
||||||
|
compat_mutex_lock(&swa->condLock);
|
||||||
|
if (swa->running)
|
||||||
|
compat_condvar_wait(&swa->cond, &swa->condLock);
|
||||||
|
compat_mutex_unlock(&swa->condLock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t write_amt = MIN(size - written, avail);
|
||||||
|
fifo_write(swa->fifo, (const char*)buf + written, write_amt);
|
||||||
|
compat_mutex_unlock(&swa->fifoLock);
|
||||||
|
written += write_amt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_thread_audio_alive(void *data)
|
||||||
|
{
|
||||||
|
switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !swa->is_paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_thread_audio_set_nonblock_state(void *data, bool state)
|
||||||
|
{
|
||||||
|
switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
|
||||||
|
|
||||||
|
if (swa)
|
||||||
|
swa->nonblocking = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_thread_audio_use_float(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t switch_thread_audio_write_avail(void *data)
|
||||||
|
{
|
||||||
|
size_t val;
|
||||||
|
switch_thread_audio_t* swa = (switch_thread_audio_t*)data;
|
||||||
|
|
||||||
|
compat_mutex_lock(&swa->fifoLock);
|
||||||
|
val = fifo_write_avail(swa->fifo);
|
||||||
|
compat_mutex_unlock(&swa->fifoLock);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t switch_thread_audio_buffer_size(void *data)
|
||||||
|
{
|
||||||
|
switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return swa->fifoSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_driver_t audio_switch_thread = {
|
||||||
|
switch_thread_audio_init,
|
||||||
|
switch_thread_audio_write,
|
||||||
|
switch_thread_audio_stop,
|
||||||
|
switch_thread_audio_start,
|
||||||
|
switch_thread_audio_alive,
|
||||||
|
switch_thread_audio_set_nonblock_state,
|
||||||
|
switch_thread_audio_free,
|
||||||
|
switch_thread_audio_use_float,
|
||||||
|
"switch_thread",
|
||||||
|
NULL, /* device_list_new */
|
||||||
|
NULL, /* device_list_free */
|
||||||
|
switch_thread_audio_write_avail,
|
||||||
|
switch_thread_audio_buffer_size
|
||||||
|
};
|
||||||
|
|
||||||
|
/* vim: set ts=3 sw=3 */
|
|
@ -70,7 +70,7 @@ typedef struct video4linux
|
||||||
char dev_name[255];
|
char dev_name[255];
|
||||||
} video4linux_t;
|
} video4linux_t;
|
||||||
|
|
||||||
static int xioctl(int fd, int request, void *args)
|
static int xioctl(int fd, unsigned long request, void *args)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ static bool init_mmap(void *data)
|
||||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
req.memory = V4L2_MEMORY_MMAP;
|
req.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
if (xioctl(v4l->fd, (uint8_t)VIDIOC_REQBUFS, &req) == -1)
|
if (xioctl(v4l->fd, VIDIOC_REQBUFS, &req) == -1)
|
||||||
{
|
{
|
||||||
if (errno == EINVAL)
|
if (errno == EINVAL)
|
||||||
RARCH_ERR("[V4L2]: %s does not support memory mapping.\n", v4l->dev_name);
|
RARCH_ERR("[V4L2]: %s does not support memory mapping.\n", v4l->dev_name);
|
||||||
|
@ -122,7 +122,7 @@ static bool init_mmap(void *data)
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
buf.index = v4l->n_buffers;
|
buf.index = v4l->n_buffers;
|
||||||
|
|
||||||
if (xioctl(v4l->fd, (uint8_t)VIDIOC_QUERYBUF, &buf) == -1)
|
if (xioctl(v4l->fd, VIDIOC_QUERYBUF, &buf) == -1)
|
||||||
{
|
{
|
||||||
RARCH_ERR("[V4L2]: Error - xioctl VIDIOC_QUERYBUF.\n");
|
RARCH_ERR("[V4L2]: Error - xioctl VIDIOC_QUERYBUF.\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -152,7 +152,7 @@ static bool init_device(void *data)
|
||||||
struct v4l2_cropcap cropcap = {0};
|
struct v4l2_cropcap cropcap = {0};
|
||||||
video4linux_t *v4l = (video4linux_t*)data;
|
video4linux_t *v4l = (video4linux_t*)data;
|
||||||
|
|
||||||
if (xioctl(v4l->fd, (uint8_t)VIDIOC_QUERYCAP, &cap) < 0)
|
if (xioctl(v4l->fd, VIDIOC_QUERYCAP, &cap) < 0)
|
||||||
{
|
{
|
||||||
if (errno == EINVAL)
|
if (errno == EINVAL)
|
||||||
RARCH_ERR("[V4L2]: %s is no V4L2 device.\n", v4l->dev_name);
|
RARCH_ERR("[V4L2]: %s is no V4L2 device.\n", v4l->dev_name);
|
||||||
|
@ -176,7 +176,7 @@ static bool init_device(void *data)
|
||||||
|
|
||||||
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
if (xioctl(v4l->fd, (uint8_t)VIDIOC_CROPCAP, &cropcap) == 0)
|
if (xioctl(v4l->fd, VIDIOC_CROPCAP, &cropcap) == 0)
|
||||||
{
|
{
|
||||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
crop.c = cropcap.defrect;
|
crop.c = cropcap.defrect;
|
||||||
|
@ -190,7 +190,7 @@ static bool init_device(void *data)
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||||
fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
||||||
|
|
||||||
if (xioctl(v4l->fd, (uint8_t)VIDIOC_S_FMT, &fmt) < 0)
|
if (xioctl(v4l->fd, VIDIOC_S_FMT, &fmt) < 0)
|
||||||
{
|
{
|
||||||
RARCH_ERR("[V4L2]: Error - VIDIOC_S_FMT\n");
|
RARCH_ERR("[V4L2]: Error - VIDIOC_S_FMT\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -248,7 +248,7 @@ static bool v4l_start(void *data)
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
buf.index = i;
|
buf.index = i;
|
||||||
|
|
||||||
if (xioctl(v4l->fd, (uint8_t)VIDIOC_QBUF, &buf) == -1)
|
if (xioctl(v4l->fd, VIDIOC_QBUF, &buf) == -1)
|
||||||
{
|
{
|
||||||
RARCH_ERR("[V4L2]: Error - VIDIOC_QBUF.\n");
|
RARCH_ERR("[V4L2]: Error - VIDIOC_QBUF.\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -364,7 +364,7 @@ static bool preprocess_image(void *data)
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
if (xioctl(v4l->fd, (uint8_t)VIDIOC_DQBUF, &buf) == -1)
|
if (xioctl(v4l->fd, VIDIOC_DQBUF, &buf) == -1)
|
||||||
{
|
{
|
||||||
switch (errno)
|
switch (errno)
|
||||||
{
|
{
|
||||||
|
@ -384,7 +384,7 @@ static bool preprocess_image(void *data)
|
||||||
|
|
||||||
scaler_ctx_scale_direct(ctx, v4l->buffer_output, (const uint8_t*)v4l->buffers[buf.index].start);
|
scaler_ctx_scale_direct(ctx, v4l->buffer_output, (const uint8_t*)v4l->buffers[buf.index].start);
|
||||||
|
|
||||||
if (xioctl(v4l->fd, (uint8_t)VIDIOC_QBUF, &buf) == -1)
|
if (xioctl(v4l->fd, VIDIOC_QBUF, &buf) == -1)
|
||||||
RARCH_ERR("[V4L2]: VIDIOC_QBUF\n");
|
RARCH_ERR("[V4L2]: VIDIOC_QBUF\n");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -162,6 +162,7 @@ static cheevos_locals_t cheevos_locals =
|
||||||
bool cheevos_loaded = false;
|
bool cheevos_loaded = false;
|
||||||
bool cheevos_hardcore_active = false;
|
bool cheevos_hardcore_active = false;
|
||||||
bool cheevos_hardcore_paused = false;
|
bool cheevos_hardcore_paused = false;
|
||||||
|
bool cheevos_state_loaded_flag = false;
|
||||||
int cheats_are_enabled = 0;
|
int cheats_are_enabled = 0;
|
||||||
int cheats_were_enabled = 0;
|
int cheats_were_enabled = 0;
|
||||||
|
|
||||||
|
@ -947,6 +948,9 @@ bool cheevos_toggle_hardcore_mode(void)
|
||||||
const char *msg = msg_hash_to_str(
|
const char *msg = msg_hash_to_str(
|
||||||
MSG_CHEEVOS_HARDCORE_MODE_ENABLE);
|
MSG_CHEEVOS_HARDCORE_MODE_ENABLE);
|
||||||
|
|
||||||
|
/* reset the state loaded flag in case it was set */
|
||||||
|
cheevos_state_loaded_flag = false;
|
||||||
|
|
||||||
/* send reset core cmd to avoid any user
|
/* send reset core cmd to avoid any user
|
||||||
* savestate previusly loaded. */
|
* savestate previusly loaded. */
|
||||||
command_event(CMD_EVENT_RESET, NULL);
|
command_event(CMD_EVENT_RESET, NULL);
|
||||||
|
@ -1504,15 +1508,10 @@ found:
|
||||||
memcpy((void*)&coro->header, coro->data,
|
memcpy((void*)&coro->header, coro->data,
|
||||||
sizeof(coro->header));
|
sizeof(coro->header));
|
||||||
|
|
||||||
if ( coro->header.id[0] != 'N'
|
if (coro->header.id[0] == 'N'
|
||||||
|| coro->header.id[1] != 'E'
|
&& coro->header.id[1] == 'E'
|
||||||
|| coro->header.id[2] != 'S'
|
&& coro->header.id[2] == 'S'
|
||||||
|| coro->header.id[3] != 0x1a)
|
&& coro->header.id[3] == 0x1a)
|
||||||
{
|
|
||||||
coro->gameid = 0;
|
|
||||||
CORO_RET();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
size_t romsize = 256;
|
size_t romsize = 256;
|
||||||
/* from FCEU core - compute size using the cart mapper */
|
/* from FCEU core - compute size using the cart mapper */
|
||||||
|
@ -1528,24 +1527,64 @@ found:
|
||||||
* we use FCEU_read. */
|
* we use FCEU_read. */
|
||||||
coro->round = mapper != 53 && mapper != 198 && mapper != 228;
|
coro->round = mapper != 53 && mapper != 198 && mapper != 228;
|
||||||
coro->bytes = coro->round ? romsize : coro->header.rom_size;
|
coro->bytes = coro->round ? romsize : coro->header.rom_size;
|
||||||
}
|
|
||||||
|
|
||||||
/* from FCEU core - check if Trainer included in ROM data */
|
coro->offset = sizeof(coro->header) + (coro->header.rom_type & 4
|
||||||
MD5_Init(&coro->md5);
|
|
||||||
coro->offset = sizeof(coro->header) + (coro->header.rom_type & 4
|
|
||||||
? sizeof(coro->header) : 0);
|
? sizeof(coro->header) : 0);
|
||||||
coro->count = 0x4000 * coro->bytes;
|
|
||||||
CORO_GOSUB(EVAL_MD5);
|
|
||||||
|
|
||||||
if (coro->count < 0x4000 * coro->bytes)
|
/* from FCEU core - check if Trainer included in ROM data */
|
||||||
{
|
MD5_Init(&coro->md5);
|
||||||
coro->offset = 0xff;
|
coro->count = 0x4000 * coro->bytes;
|
||||||
coro->count = 0x4000 * coro->bytes - coro->count;
|
CORO_GOSUB(EVAL_MD5);
|
||||||
CORO_GOSUB(FILL_MD5);
|
|
||||||
|
if (coro->count < 0x4000 * coro->bytes)
|
||||||
|
{
|
||||||
|
coro->offset = 0xff;
|
||||||
|
coro->count = 0x4000 * coro->bytes - coro->count;
|
||||||
|
CORO_GOSUB(FILL_MD5);
|
||||||
|
}
|
||||||
|
|
||||||
|
MD5_Final(coro->hash, &coro->md5);
|
||||||
|
CORO_GOTO(GET_GAMEID);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
size_t chunks = coro->len >> 14;
|
||||||
|
size_t chunk_size = 0x4000;
|
||||||
|
|
||||||
MD5_Final(coro->hash, &coro->md5);
|
/* Fall back to headerless hashing
|
||||||
CORO_GOTO(GET_GAMEID);
|
* PRG ROM size is unknown, so test by 16KB chunks */
|
||||||
|
|
||||||
|
coro->round = 0;
|
||||||
|
coro->offset = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < chunks; i++)
|
||||||
|
{
|
||||||
|
MD5_Init(&coro->md5);
|
||||||
|
|
||||||
|
coro->bytes = i + 1;
|
||||||
|
coro->count = coro->bytes * chunk_size;
|
||||||
|
|
||||||
|
CORO_GOSUB(EVAL_MD5);
|
||||||
|
|
||||||
|
if (coro->count < 0x4000 * coro->bytes)
|
||||||
|
{
|
||||||
|
coro->offset = 0xff;
|
||||||
|
coro->count = 0x4000 * coro->bytes - coro->count;
|
||||||
|
CORO_GOSUB(FILL_MD5);
|
||||||
|
}
|
||||||
|
|
||||||
|
MD5_Final(coro->hash, &coro->md5);
|
||||||
|
CORO_GOSUB(GET_GAMEID);
|
||||||
|
|
||||||
|
if (coro->gameid > 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CORO_RET();
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Info Tries to identify a "generic" game
|
* Info Tries to identify a "generic" game
|
||||||
|
|
|
@ -67,8 +67,10 @@ int cheevos_get_console(void);
|
||||||
extern bool cheevos_loaded;
|
extern bool cheevos_loaded;
|
||||||
extern bool cheevos_hardcore_active;
|
extern bool cheevos_hardcore_active;
|
||||||
extern bool cheevos_hardcore_paused;
|
extern bool cheevos_hardcore_paused;
|
||||||
|
extern bool cheevos_state_loaded_flag;
|
||||||
extern int cheats_are_enabled;
|
extern int cheats_are_enabled;
|
||||||
extern int cheats_were_enabled;
|
extern int cheats_were_enabled;
|
||||||
|
;
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
|
54
command.c
54
command.c
|
@ -98,6 +98,8 @@
|
||||||
#define DEFAULT_NETWORK_CMD_PORT 55355
|
#define DEFAULT_NETWORK_CMD_PORT 55355
|
||||||
#define STDIN_BUF_SIZE 4096
|
#define STDIN_BUF_SIZE 4096
|
||||||
|
|
||||||
|
extern bool discord_is_inited;
|
||||||
|
|
||||||
enum cmd_source_t
|
enum cmd_source_t
|
||||||
{
|
{
|
||||||
CMD_NONE = 0,
|
CMD_NONE = 0,
|
||||||
|
@ -159,7 +161,7 @@ static const struct cmd_map map[] = {
|
||||||
{ "STATE_SLOT_PLUS", RARCH_STATE_SLOT_PLUS },
|
{ "STATE_SLOT_PLUS", RARCH_STATE_SLOT_PLUS },
|
||||||
{ "STATE_SLOT_MINUS", RARCH_STATE_SLOT_MINUS },
|
{ "STATE_SLOT_MINUS", RARCH_STATE_SLOT_MINUS },
|
||||||
{ "REWIND", RARCH_REWIND },
|
{ "REWIND", RARCH_REWIND },
|
||||||
{ "MOVIE_RECORD_TOGGLE", RARCH_MOVIE_RECORD_TOGGLE },
|
{ "BSV_RECORD_TOGGLE", RARCH_BSV_RECORD_TOGGLE },
|
||||||
{ "PAUSE_TOGGLE", RARCH_PAUSE_TOGGLE },
|
{ "PAUSE_TOGGLE", RARCH_PAUSE_TOGGLE },
|
||||||
{ "FRAMEADVANCE", RARCH_FRAMEADVANCE },
|
{ "FRAMEADVANCE", RARCH_FRAMEADVANCE },
|
||||||
{ "RESET", RARCH_RESET },
|
{ "RESET", RARCH_RESET },
|
||||||
|
@ -182,6 +184,8 @@ static const struct cmd_map map[] = {
|
||||||
{ "UI_COMPANION_TOGGLE", RARCH_UI_COMPANION_TOGGLE },
|
{ "UI_COMPANION_TOGGLE", RARCH_UI_COMPANION_TOGGLE },
|
||||||
{ "GAME_FOCUS_TOGGLE", RARCH_GAME_FOCUS_TOGGLE },
|
{ "GAME_FOCUS_TOGGLE", RARCH_GAME_FOCUS_TOGGLE },
|
||||||
{ "MENU_TOGGLE", RARCH_MENU_TOGGLE },
|
{ "MENU_TOGGLE", RARCH_MENU_TOGGLE },
|
||||||
|
{ "RECORDING_TOGGLE", RARCH_RECORDING_TOGGLE },
|
||||||
|
{ "STREAMING_TOGGLE", RARCH_STREAMING_TOGGLE },
|
||||||
{ "MENU_UP", RETRO_DEVICE_ID_JOYPAD_UP },
|
{ "MENU_UP", RETRO_DEVICE_ID_JOYPAD_UP },
|
||||||
{ "MENU_DOWN", RETRO_DEVICE_ID_JOYPAD_DOWN },
|
{ "MENU_DOWN", RETRO_DEVICE_ID_JOYPAD_DOWN },
|
||||||
{ "MENU_LEFT", RETRO_DEVICE_ID_JOYPAD_LEFT },
|
{ "MENU_LEFT", RETRO_DEVICE_ID_JOYPAD_LEFT },
|
||||||
|
@ -1656,6 +1660,9 @@ static bool command_event_main_state(unsigned cmd)
|
||||||
case CMD_EVENT_LOAD_STATE:
|
case CMD_EVENT_LOAD_STATE:
|
||||||
if (content_load_state(state_path, false, false))
|
if (content_load_state(state_path, false, false))
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_CHEEVOS
|
||||||
|
cheevos_state_loaded_flag = true;
|
||||||
|
#endif
|
||||||
ret = true;
|
ret = true;
|
||||||
#ifdef HAVE_NETWORKING
|
#ifdef HAVE_NETWORKING
|
||||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
|
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, NULL);
|
||||||
|
@ -1708,14 +1715,12 @@ static bool command_event_resize_windowed_scale(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_playlist_push_write(
|
void command_playlist_push_write(
|
||||||
void *data,
|
playlist_t *playlist,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *label,
|
const char *label,
|
||||||
const char *core_path,
|
const char *core_path,
|
||||||
const char *core_name)
|
const char *core_name)
|
||||||
{
|
{
|
||||||
playlist_t *playlist = (playlist_t*)data;
|
|
||||||
|
|
||||||
if (!playlist)
|
if (!playlist)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1732,7 +1737,7 @@ void command_playlist_push_write(
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_playlist_update_write(
|
void command_playlist_update_write(
|
||||||
void *data,
|
playlist_t *plist,
|
||||||
size_t idx,
|
size_t idx,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *label,
|
const char *label,
|
||||||
|
@ -1741,7 +1746,6 @@ void command_playlist_update_write(
|
||||||
const char *crc32,
|
const char *crc32,
|
||||||
const char *db_name)
|
const char *db_name)
|
||||||
{
|
{
|
||||||
playlist_t *plist = (playlist_t*)data;
|
|
||||||
playlist_t *playlist = plist ? plist : playlist_get_cached();
|
playlist_t *playlist = plist ? plist : playlist_get_cached();
|
||||||
|
|
||||||
if (!playlist)
|
if (!playlist)
|
||||||
|
@ -1777,11 +1781,6 @@ bool command_event(enum event_command cmd, void *data)
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case CMD_EVENT_MENU_REFRESH:
|
|
||||||
#ifdef HAVE_MENU
|
|
||||||
menu_driver_ctl(RARCH_MENU_CTL_REFRESH, NULL);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case CMD_EVENT_SET_PER_GAME_RESOLUTION:
|
case CMD_EVENT_SET_PER_GAME_RESOLUTION:
|
||||||
#if defined(GEKKO)
|
#if defined(GEKKO)
|
||||||
{
|
{
|
||||||
|
@ -1842,6 +1841,7 @@ bool command_event(enum event_command cmd, void *data)
|
||||||
case CMD_EVENT_LOAD_CORE:
|
case CMD_EVENT_LOAD_CORE:
|
||||||
{
|
{
|
||||||
bool success = command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
|
bool success = command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
|
||||||
|
(void)success;
|
||||||
|
|
||||||
#ifndef HAVE_DYNAMIC
|
#ifndef HAVE_DYNAMIC
|
||||||
command_event(CMD_EVENT_QUIT, NULL);
|
command_event(CMD_EVENT_QUIT, NULL);
|
||||||
|
@ -1888,6 +1888,10 @@ bool command_event(enum event_command cmd, void *data)
|
||||||
command_event_init_controllers();
|
command_event_init_controllers();
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_RESET:
|
case CMD_EVENT_RESET:
|
||||||
|
#ifdef HAVE_CHEEVOS
|
||||||
|
cheevos_state_loaded_flag = false;
|
||||||
|
cheevos_hardcore_paused = false;
|
||||||
|
#endif
|
||||||
RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET));
|
RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET));
|
||||||
runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true);
|
runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true);
|
||||||
|
|
||||||
|
@ -1965,6 +1969,15 @@ bool command_event(enum event_command cmd, void *data)
|
||||||
core_unload_game();
|
core_unload_game();
|
||||||
if (!rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
|
if (!rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
|
||||||
core_unload();
|
core_unload();
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
if (discord_is_inited)
|
||||||
|
{
|
||||||
|
discord_userdata_t userdata;
|
||||||
|
userdata.status = DISCORD_PRESENCE_MENU;
|
||||||
|
|
||||||
|
command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_QUIT:
|
case CMD_EVENT_QUIT:
|
||||||
|
@ -2145,13 +2158,22 @@ TODO: Add a setting for these tweaks */
|
||||||
video_driver_gpu_record_deinit();
|
video_driver_gpu_record_deinit();
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_RECORD_DEINIT:
|
case CMD_EVENT_RECORD_DEINIT:
|
||||||
if (!recording_deinit())
|
{
|
||||||
return false;
|
recording_set_state(false);
|
||||||
|
streaming_set_state(false);
|
||||||
|
if (!recording_deinit())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_RECORD_INIT:
|
case CMD_EVENT_RECORD_INIT:
|
||||||
command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
|
{
|
||||||
if (!recording_init())
|
recording_set_state(true);
|
||||||
return false;
|
if (!recording_init())
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_RECORD_DEINIT, NULL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_HISTORY_DEINIT:
|
case CMD_EVENT_HISTORY_DEINIT:
|
||||||
if (g_defaults.content_history)
|
if (g_defaults.content_history)
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "playlist.h"
|
||||||
|
|
||||||
RETRO_BEGIN_DECLS
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
typedef struct command command_t;
|
typedef struct command command_t;
|
||||||
|
@ -155,7 +157,6 @@ enum event_command
|
||||||
CMD_EVENT_MENU_PAUSE_LIBRETRO,
|
CMD_EVENT_MENU_PAUSE_LIBRETRO,
|
||||||
/* Toggles menu on/off. */
|
/* Toggles menu on/off. */
|
||||||
CMD_EVENT_MENU_TOGGLE,
|
CMD_EVENT_MENU_TOGGLE,
|
||||||
CMD_EVENT_MENU_REFRESH,
|
|
||||||
/* Applies shader changes. */
|
/* Applies shader changes. */
|
||||||
CMD_EVENT_SHADERS_APPLY_CHANGES,
|
CMD_EVENT_SHADERS_APPLY_CHANGES,
|
||||||
/* A new shader preset has been loaded */
|
/* A new shader preset has been loaded */
|
||||||
|
@ -269,14 +270,14 @@ bool command_free(command_t *handle);
|
||||||
bool command_event(enum event_command action, void *data);
|
bool command_event(enum event_command action, void *data);
|
||||||
|
|
||||||
void command_playlist_push_write(
|
void command_playlist_push_write(
|
||||||
void *data,
|
playlist_t *playlist,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *label,
|
const char *label,
|
||||||
const char *core_path,
|
const char *core_path,
|
||||||
const char *core_name);
|
const char *core_name);
|
||||||
|
|
||||||
void command_playlist_update_write(
|
void command_playlist_update_write(
|
||||||
void *data,
|
playlist_t *playlist,
|
||||||
size_t idx,
|
size_t idx,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *label,
|
const char *label,
|
||||||
|
|
47
config.def.h
47
config.def.h
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <audio/audio_resampler.h>
|
#include <audio/audio_resampler.h>
|
||||||
|
#include "configuration.h"
|
||||||
#include "gfx/video_defines.h"
|
#include "gfx/video_defines.h"
|
||||||
#include "input/input_driver.h"
|
#include "input/input_driver.h"
|
||||||
|
|
||||||
|
@ -67,15 +68,15 @@ static bool bundle_assets_extract_enable = false;
|
||||||
static bool materialui_icons_enable = true;
|
static bool materialui_icons_enable = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const bool crt_switch_resolution = false;
|
static const unsigned crt_switch_resolution = CRT_SWITCH_NONE;
|
||||||
static const int crt_switch_resolution_super = 2560;
|
static const int crt_switch_resolution_super = 2560;
|
||||||
|
static const int crt_switch_center_adjust = 0;
|
||||||
|
|
||||||
|
static const bool def_history_list_enable = true;
|
||||||
|
static const bool def_playlist_entry_remove = true;
|
||||||
|
static const bool def_playlist_entry_rename = true;
|
||||||
|
|
||||||
static const bool def_history_list_enable = true;
|
static const unsigned int def_user_language = 0;
|
||||||
static const bool def_playlist_entry_remove = true;
|
|
||||||
static const bool def_playlist_entry_rename = true;
|
|
||||||
|
|
||||||
static const unsigned int def_user_language = 0;
|
|
||||||
|
|
||||||
#if (defined(_WIN32) && !defined(_XBOX)) || (defined(__linux) && !defined(ANDROID) && !defined(HAVE_LAKKA)) || (defined(__MACH__) && !defined(IOS)) || defined(EMSCRIPTEN)
|
#if (defined(_WIN32) && !defined(_XBOX)) || (defined(__linux) && !defined(ANDROID) && !defined(HAVE_LAKKA)) || (defined(__MACH__) && !defined(IOS)) || defined(EMSCRIPTEN)
|
||||||
static const bool def_mouse_enable = true;
|
static const bool def_mouse_enable = true;
|
||||||
|
@ -147,6 +148,8 @@ static const bool vsync = true;
|
||||||
|
|
||||||
static const unsigned max_swapchain_images = 3;
|
static const unsigned max_swapchain_images = 3;
|
||||||
|
|
||||||
|
static const bool adaptive_vsync = false;
|
||||||
|
|
||||||
/* Attempts to hard-synchronize CPU and GPU.
|
/* Attempts to hard-synchronize CPU and GPU.
|
||||||
* Can reduce latency at cost of performance. */
|
* Can reduce latency at cost of performance. */
|
||||||
static const bool hard_sync = false;
|
static const bool hard_sync = false;
|
||||||
|
@ -229,7 +232,7 @@ static const float aspect_ratio = DEFAULT_ASPECT_RATIO;
|
||||||
/* 1:1 PAR */
|
/* 1:1 PAR */
|
||||||
static const bool aspect_ratio_auto = false;
|
static const bool aspect_ratio_auto = false;
|
||||||
|
|
||||||
#if defined(__CELLOS_LV2) || defined(_XBOX360)
|
#if defined(__CELLOS_LV2) || defined(_XBOX360) || defined(ANDROID_AARCH64)
|
||||||
static unsigned aspect_ratio_idx = ASPECT_RATIO_16_9;
|
static unsigned aspect_ratio_idx = ASPECT_RATIO_16_9;
|
||||||
#elif defined(PSP)
|
#elif defined(PSP)
|
||||||
static unsigned aspect_ratio_idx = ASPECT_RATIO_CORE;
|
static unsigned aspect_ratio_idx = ASPECT_RATIO_CORE;
|
||||||
|
@ -259,15 +262,17 @@ static const float default_input_overlay_opacity = 0.7f;
|
||||||
|
|
||||||
static bool default_block_config_read = true;
|
static bool default_block_config_read = true;
|
||||||
|
|
||||||
static bool quick_menu_show_take_screenshot = true;
|
static bool quick_menu_show_take_screenshot = true;
|
||||||
static bool quick_menu_show_save_load_state = true;
|
static bool quick_menu_show_save_load_state = true;
|
||||||
static bool quick_menu_show_undo_save_load_state = true;
|
static bool quick_menu_show_undo_save_load_state = true;
|
||||||
static bool quick_menu_show_add_to_favorites = true;
|
static bool quick_menu_show_add_to_favorites = true;
|
||||||
static bool quick_menu_show_options = true;
|
static bool quick_menu_show_options = true;
|
||||||
static bool quick_menu_show_controls = true;
|
static bool quick_menu_show_controls = true;
|
||||||
static bool quick_menu_show_cheats = true;
|
static bool quick_menu_show_cheats = true;
|
||||||
static bool quick_menu_show_shaders = true;
|
static bool quick_menu_show_shaders = true;
|
||||||
static bool quick_menu_show_information = true;
|
static bool quick_menu_show_information = true;
|
||||||
|
static bool quick_menu_show_recording = true;
|
||||||
|
static bool quick_menu_show_streaming = true;
|
||||||
|
|
||||||
static bool quick_menu_show_save_core_overrides = true;
|
static bool quick_menu_show_save_core_overrides = true;
|
||||||
static bool quick_menu_show_save_game_overrides = true;
|
static bool quick_menu_show_save_game_overrides = true;
|
||||||
|
@ -447,9 +452,11 @@ static const bool font_enable = true;
|
||||||
* If your monitor does not run at 60Hz, or something close to it,
|
* If your monitor does not run at 60Hz, or something close to it,
|
||||||
* disable VSync, and leave this at its default. */
|
* disable VSync, and leave this at its default. */
|
||||||
#ifdef _3DS
|
#ifdef _3DS
|
||||||
static const float refresh_rate = (32730.0 * 8192.0) / 4481134.0 ;
|
static const float refresh_rate = (32730.0 * 8192.0) / 4481134.0 ;
|
||||||
|
static const float crt_refresh_rate = (32730.0 * 8192.0) / 4481134.0 ;
|
||||||
#else
|
#else
|
||||||
static const float refresh_rate = 60/1.001;
|
static const float refresh_rate = 60/1.001;
|
||||||
|
static const float crt_refresh_rate = 60/1.001;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allow games to set rotation. If false, rotation requests are
|
/* Allow games to set rotation. If false, rotation requests are
|
||||||
|
@ -654,6 +661,10 @@ static const unsigned libretro_log_level = 1;
|
||||||
#define RARCH_DEFAULT_PORT 55435
|
#define RARCH_DEFAULT_PORT 55435
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef RARCH_STREAM_DEFAULT_PORT
|
||||||
|
#define RARCH_STREAM_DEFAULT_PORT 56400
|
||||||
|
#endif
|
||||||
|
|
||||||
/* KEYBINDS, JOYPAD */
|
/* KEYBINDS, JOYPAD */
|
||||||
|
|
||||||
/* Axis threshold (between 0.0 and 1.0)
|
/* Axis threshold (between 0.0 and 1.0)
|
||||||
|
|
|
@ -75,7 +75,7 @@ static const struct retro_keybind retro_keybinds_1[] = {
|
||||||
{ true, RARCH_STATE_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_STATE_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_STATE_SLOT_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_STATE_SLOT_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_REWIND, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_REWIND, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_MOVIE_RECORD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_BSV_RECORD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_PAUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_PAUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_FRAMEADVANCE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_FRAMEADVANCE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_RESET, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_RESET, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
|
@ -99,6 +99,8 @@ static const struct retro_keybind retro_keybinds_1[] = {
|
||||||
{ true, RARCH_GAME_FOCUS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_GAME_FOCUS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_UI_COMPANION_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_UI_COMPANION_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_MENU_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, RETROK_SPACE, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_MENU_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, RETROK_SPACE, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
|
{ true, RARCH_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
|
{ true, RARCH_STREAMING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
#else
|
#else
|
||||||
{ true, RETRO_DEVICE_ID_JOYPAD_B, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, RETROK_z, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RETRO_DEVICE_ID_JOYPAD_B, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, RETROK_z, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RETRO_DEVICE_ID_JOYPAD_Y, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, RETROK_a, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RETRO_DEVICE_ID_JOYPAD_Y, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, RETROK_a, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
|
@ -151,7 +153,7 @@ static const struct retro_keybind retro_keybinds_1[] = {
|
||||||
{ true, RARCH_STATE_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, RETROK_F7, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_STATE_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, RETROK_F7, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_STATE_SLOT_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, RETROK_F6, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_STATE_SLOT_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, RETROK_F6, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_REWIND, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, RETROK_r, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_REWIND, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, RETROK_r, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_MOVIE_RECORD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, RETROK_o, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_BSV_RECORD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE, RETROK_o, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_PAUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, RETROK_p, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_PAUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, RETROK_p, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_FRAMEADVANCE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, RETROK_k, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_FRAMEADVANCE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, RETROK_k, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_RESET, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, RETROK_h, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_RESET, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, RETROK_h, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
|
@ -175,6 +177,8 @@ static const struct retro_keybind retro_keybinds_1[] = {
|
||||||
{ true, RARCH_GAME_FOCUS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, RETROK_SCROLLOCK, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_GAME_FOCUS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, RETROK_SCROLLOCK, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_UI_COMPANION_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, RETROK_F5, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_UI_COMPANION_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE, RETROK_F5, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
{ true, RARCH_MENU_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, RETROK_F1, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
{ true, RARCH_MENU_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, RETROK_F1, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
|
{ true, RARCH_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
|
{ true, RARCH_STREAMING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE, RETROK_UNKNOWN, NO_BTN, NO_BTN, 0, AXIS_NONE },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,8 @@
|
||||||
|
|
||||||
#include "../list_special.h"
|
#include "../list_special.h"
|
||||||
|
|
||||||
|
#include "record/record_driver.h"
|
||||||
|
|
||||||
static const char* invalid_filename_chars[] = {
|
static const char* invalid_filename_chars[] = {
|
||||||
/* https://support.microsoft.com/en-us/help/905231/information-about-the-characters-that-you-cannot-use-in-site-names--fo */
|
/* https://support.microsoft.com/en-us/help/905231/information-about-the-characters-that-you-cannot-use-in-site-names--fo */
|
||||||
"~", "#", "%", "&", "*", "{", "}", "\\", ":", "[", "]", "?", "/", "|", "\'", "\"",
|
"~", "#", "%", "&", "*", "{", "}", "\\", ":", "[", "]", "?", "/", "|", "\'", "\"",
|
||||||
|
@ -1103,6 +1105,8 @@ static struct config_array_setting *populate_settings_array(settings_t *settings
|
||||||
SETTING_ARRAY("midi_driver", settings->arrays.midi_driver, false, NULL, true);
|
SETTING_ARRAY("midi_driver", settings->arrays.midi_driver, false, NULL, true);
|
||||||
SETTING_ARRAY("midi_input", settings->arrays.midi_input, true, midi_input, true);
|
SETTING_ARRAY("midi_input", settings->arrays.midi_input, true, midi_input, true);
|
||||||
SETTING_ARRAY("midi_output", settings->arrays.midi_output, true, midi_output, true);
|
SETTING_ARRAY("midi_output", settings->arrays.midi_output, true, midi_output, true);
|
||||||
|
SETTING_ARRAY("youtube_stream_key", settings->arrays.youtube_stream_key, true, NULL, true);
|
||||||
|
SETTING_ARRAY("twitch_stream_key", settings->arrays.twitch_stream_key, true, NULL, true);
|
||||||
*size = count;
|
*size = count;
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
|
@ -1160,6 +1164,12 @@ static struct config_path_setting *populate_settings_path(settings_t *settings,
|
||||||
SETTING_PATH("input_overlay",
|
SETTING_PATH("input_overlay",
|
||||||
settings->paths.path_overlay, false, NULL, true);
|
settings->paths.path_overlay, false, NULL, true);
|
||||||
#endif
|
#endif
|
||||||
|
SETTING_PATH("video_record_config",
|
||||||
|
settings->paths.path_record_config, false, NULL, true);
|
||||||
|
SETTING_PATH("video_stream_config",
|
||||||
|
settings->paths.path_stream_config, false, NULL, true);
|
||||||
|
SETTING_PATH("video_stream_url",
|
||||||
|
settings->paths.path_stream_url, false, NULL, true);
|
||||||
SETTING_PATH("video_font_path",
|
SETTING_PATH("video_font_path",
|
||||||
settings->paths.path_font, false, NULL, true);
|
settings->paths.path_font, false, NULL, true);
|
||||||
SETTING_PATH("cursor_directory",
|
SETTING_PATH("cursor_directory",
|
||||||
|
@ -1234,6 +1244,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||||
struct config_bool_setting *tmp = (struct config_bool_setting*)malloc((*size + 1) * sizeof(struct config_bool_setting));
|
struct config_bool_setting *tmp = (struct config_bool_setting*)malloc((*size + 1) * sizeof(struct config_bool_setting));
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
|
|
||||||
|
SETTING_BOOL("crt_switch_resolution_use_custom_refresh_rate", &settings->bools.crt_switch_custom_refresh_enable, true, false, false);
|
||||||
SETTING_BOOL("automatically_add_content_to_playlist", &settings->bools.automatically_add_content_to_playlist, true, automatically_add_content_to_playlist, false);
|
SETTING_BOOL("automatically_add_content_to_playlist", &settings->bools.automatically_add_content_to_playlist, true, automatically_add_content_to_playlist, false);
|
||||||
SETTING_BOOL("ui_companion_start_on_boot", &settings->bools.ui_companion_start_on_boot, true, ui_companion_start_on_boot, false);
|
SETTING_BOOL("ui_companion_start_on_boot", &settings->bools.ui_companion_start_on_boot, true, ui_companion_start_on_boot, false);
|
||||||
SETTING_BOOL("ui_companion_enable", &settings->bools.ui_companion_enable, true, ui_companion_enable, false);
|
SETTING_BOOL("ui_companion_enable", &settings->bools.ui_companion_enable, true, ui_companion_enable, false);
|
||||||
|
@ -1306,9 +1317,9 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||||
SETTING_BOOL("video_fullscreen", &settings->bools.video_fullscreen, true, fullscreen, false);
|
SETTING_BOOL("video_fullscreen", &settings->bools.video_fullscreen, true, fullscreen, false);
|
||||||
SETTING_BOOL("bundle_assets_extract_enable", &settings->bools.bundle_assets_extract_enable, true, bundle_assets_extract_enable, false);
|
SETTING_BOOL("bundle_assets_extract_enable", &settings->bools.bundle_assets_extract_enable, true, bundle_assets_extract_enable, false);
|
||||||
SETTING_BOOL("video_vsync", &settings->bools.video_vsync, true, vsync, false);
|
SETTING_BOOL("video_vsync", &settings->bools.video_vsync, true, vsync, false);
|
||||||
|
SETTING_BOOL("video_adaptive_vsync", &settings->bools.video_adaptive_vsync, true, adaptive_vsync, false);
|
||||||
SETTING_BOOL("video_hard_sync", &settings->bools.video_hard_sync, true, hard_sync, false);
|
SETTING_BOOL("video_hard_sync", &settings->bools.video_hard_sync, true, hard_sync, false);
|
||||||
SETTING_BOOL("video_black_frame_insertion", &settings->bools.video_black_frame_insertion, true, black_frame_insertion, false);
|
SETTING_BOOL("video_black_frame_insertion", &settings->bools.video_black_frame_insertion, true, black_frame_insertion, false);
|
||||||
SETTING_BOOL("crt_switch_resolution", &settings->bools.crt_switch_resolution, true, crt_switch_resolution, false);
|
|
||||||
SETTING_BOOL("video_disable_composition", &settings->bools.video_disable_composition, true, disable_composition, false);
|
SETTING_BOOL("video_disable_composition", &settings->bools.video_disable_composition, true, disable_composition, false);
|
||||||
SETTING_BOOL("pause_nonactive", &settings->bools.pause_nonactive, true, pause_nonactive, false);
|
SETTING_BOOL("pause_nonactive", &settings->bools.pause_nonactive, true, pause_nonactive, false);
|
||||||
SETTING_BOOL("video_gpu_screenshot", &settings->bools.video_gpu_screenshot, true, gpu_screenshot, false);
|
SETTING_BOOL("video_gpu_screenshot", &settings->bools.video_gpu_screenshot, true, gpu_screenshot, false);
|
||||||
|
@ -1350,6 +1361,9 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||||
SETTING_BOOL("menu_battery_level_enable", &settings->bools.menu_battery_level_enable, true, true, false);
|
SETTING_BOOL("menu_battery_level_enable", &settings->bools.menu_battery_level_enable, true, true, false);
|
||||||
SETTING_BOOL("menu_core_enable", &settings->bools.menu_core_enable, true, true, false);
|
SETTING_BOOL("menu_core_enable", &settings->bools.menu_core_enable, true, true, false);
|
||||||
SETTING_BOOL("menu_dynamic_wallpaper_enable", &settings->bools.menu_dynamic_wallpaper_enable, true, false, false);
|
SETTING_BOOL("menu_dynamic_wallpaper_enable", &settings->bools.menu_dynamic_wallpaper_enable, true, false, false);
|
||||||
|
SETTING_BOOL("quick_menu_show_recording", &settings->bools.quick_menu_show_recording, true, quick_menu_show_recording, false);
|
||||||
|
SETTING_BOOL("quick_menu_show_streaming", &settings->bools.quick_menu_show_streaming, true, quick_menu_show_streaming, false);
|
||||||
|
SETTING_BOOL("quick_menu_show_save_load_state", &settings->bools.quick_menu_show_save_load_state, true, quick_menu_show_save_load_state, false);
|
||||||
SETTING_BOOL("quick_menu_show_take_screenshot", &settings->bools.quick_menu_show_take_screenshot, true, quick_menu_show_take_screenshot, false);
|
SETTING_BOOL("quick_menu_show_take_screenshot", &settings->bools.quick_menu_show_take_screenshot, true, quick_menu_show_take_screenshot, false);
|
||||||
SETTING_BOOL("quick_menu_show_save_load_state", &settings->bools.quick_menu_show_save_load_state, true, quick_menu_show_save_load_state, false);
|
SETTING_BOOL("quick_menu_show_save_load_state", &settings->bools.quick_menu_show_save_load_state, true, quick_menu_show_save_load_state, false);
|
||||||
SETTING_BOOL("quick_menu_show_undo_save_load_state", &settings->bools.quick_menu_show_undo_save_load_state, true, quick_menu_show_undo_save_load_state, false);
|
SETTING_BOOL("quick_menu_show_undo_save_load_state", &settings->bools.quick_menu_show_undo_save_load_state, true, quick_menu_show_undo_save_load_state, false);
|
||||||
|
@ -1484,6 +1498,7 @@ static struct config_float_setting *populate_settings_float(settings_t *settings
|
||||||
|
|
||||||
SETTING_FLOAT("video_aspect_ratio", &settings->floats.video_aspect_ratio, true, aspect_ratio, false);
|
SETTING_FLOAT("video_aspect_ratio", &settings->floats.video_aspect_ratio, true, aspect_ratio, false);
|
||||||
SETTING_FLOAT("video_scale", &settings->floats.video_scale, false, 0.0f, false);
|
SETTING_FLOAT("video_scale", &settings->floats.video_scale, false, 0.0f, false);
|
||||||
|
SETTING_FLOAT("crt_video_refresh_rate", &settings->floats.crt_video_refresh_rate, true, crt_refresh_rate, false);
|
||||||
SETTING_FLOAT("video_refresh_rate", &settings->floats.video_refresh_rate, true, refresh_rate, false);
|
SETTING_FLOAT("video_refresh_rate", &settings->floats.video_refresh_rate, true, refresh_rate, false);
|
||||||
SETTING_FLOAT("audio_rate_control_delta", audio_get_float_ptr(AUDIO_ACTION_RATE_CONTROL_DELTA), true, rate_control_delta, false);
|
SETTING_FLOAT("audio_rate_control_delta", audio_get_float_ptr(AUDIO_ACTION_RATE_CONTROL_DELTA), true, rate_control_delta, false);
|
||||||
SETTING_FLOAT("audio_max_timing_skew", &settings->floats.audio_max_timing_skew, true, max_timing_skew, false);
|
SETTING_FLOAT("audio_max_timing_skew", &settings->floats.audio_max_timing_skew, true, max_timing_skew, false);
|
||||||
|
@ -1517,6 +1532,10 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings,
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
struct config_uint_setting *tmp = (struct config_uint_setting*)malloc((*size + 1) * sizeof(struct config_uint_setting));
|
struct config_uint_setting *tmp = (struct config_uint_setting*)malloc((*size + 1) * sizeof(struct config_uint_setting));
|
||||||
|
|
||||||
|
#ifdef HAVE_NETWORKING
|
||||||
|
SETTING_UINT("streaming_mode", &settings->uints.streaming_mode, true, STREAMING_MODE_TWITCH, false);
|
||||||
|
#endif
|
||||||
|
SETTING_UINT("crt_switch_resolution", &settings->uints.crt_switch_resolution, true, crt_switch_resolution, false);
|
||||||
SETTING_UINT("input_bind_timeout", &settings->uints.input_bind_timeout, true, input_bind_timeout, false);
|
SETTING_UINT("input_bind_timeout", &settings->uints.input_bind_timeout, true, input_bind_timeout, false);
|
||||||
SETTING_UINT("input_bind_hold", &settings->uints.input_bind_hold, true, input_bind_hold, false);
|
SETTING_UINT("input_bind_hold", &settings->uints.input_bind_hold, true, input_bind_hold, false);
|
||||||
SETTING_UINT("input_turbo_period", &settings->uints.input_turbo_period, true, turbo_period, false);
|
SETTING_UINT("input_turbo_period", &settings->uints.input_turbo_period, true, turbo_period, false);
|
||||||
|
@ -1599,6 +1618,12 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings,
|
||||||
|
|
||||||
SETTING_UINT("midi_volume", &settings->uints.midi_volume, true, midi_volume, false);
|
SETTING_UINT("midi_volume", &settings->uints.midi_volume, true, midi_volume, false);
|
||||||
|
|
||||||
|
SETTING_UINT("video_stream_port", &settings->uints.video_stream_port, true, RARCH_STREAM_DEFAULT_PORT, false);
|
||||||
|
SETTING_UINT("video_record_quality", &settings->uints.video_record_quality, true, RECORD_CONFIG_TYPE_RECORDING_LOSSLESS_QUALITY, false);
|
||||||
|
SETTING_UINT("video_stream_quality", &settings->uints.video_stream_quality, true, RECORD_CONFIG_TYPE_STREAMING_LOW_QUALITY, false);
|
||||||
|
SETTING_UINT("video_record_scale_factor", &settings->uints.video_record_scale_factor, true, 1, false);
|
||||||
|
SETTING_UINT("video_stream_scale_factor", &settings->uints.video_stream_scale_factor, true, 1, false);
|
||||||
|
|
||||||
*size = count;
|
*size = count;
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
|
@ -1629,6 +1654,7 @@ static struct config_int_setting *populate_settings_int(settings_t *settings, in
|
||||||
#ifdef HAVE_WASAPI
|
#ifdef HAVE_WASAPI
|
||||||
SETTING_INT("audio_wasapi_sh_buffer_length", &settings->ints.audio_wasapi_sh_buffer_length, true, wasapi_sh_buffer_length, false);
|
SETTING_INT("audio_wasapi_sh_buffer_length", &settings->ints.audio_wasapi_sh_buffer_length, true, wasapi_sh_buffer_length, false);
|
||||||
#endif
|
#endif
|
||||||
|
SETTING_INT("crt_switch_center_adjust", &settings->ints.crt_switch_center_adjust, false, 0 /* TODO */, false);
|
||||||
|
|
||||||
*size = count;
|
*size = count;
|
||||||
|
|
||||||
|
@ -1920,6 +1946,9 @@ static void config_set_defaults(void)
|
||||||
*settings->paths.path_menu_wallpaper = '\0';
|
*settings->paths.path_menu_wallpaper = '\0';
|
||||||
*settings->paths.path_content_database = '\0';
|
*settings->paths.path_content_database = '\0';
|
||||||
*settings->paths.path_overlay = '\0';
|
*settings->paths.path_overlay = '\0';
|
||||||
|
*settings->paths.path_record_config = '\0';
|
||||||
|
*settings->paths.path_stream_config = '\0';
|
||||||
|
*settings->paths.path_stream_url = '\0';
|
||||||
*settings->paths.path_softfilter_plugin = '\0';
|
*settings->paths.path_softfilter_plugin = '\0';
|
||||||
|
|
||||||
*settings->arrays.playlist_names = '\0';
|
*settings->arrays.playlist_names = '\0';
|
||||||
|
@ -3008,6 +3037,7 @@ static bool config_load_file(const char *path, bool set_defaults,
|
||||||
}
|
}
|
||||||
|
|
||||||
frontend_driver_set_sustained_performance_mode(settings->bools.sustained_performance_mode);
|
frontend_driver_set_sustained_performance_mode(settings->bools.sustained_performance_mode);
|
||||||
|
recording_driver_update_streaming_url();
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,13 @@
|
||||||
var = newvar; \
|
var = newvar; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum crt_switch_type
|
||||||
|
{
|
||||||
|
CRT_SWITCH_NONE = 0,
|
||||||
|
CRT_SWITCH_15KHZ,
|
||||||
|
CRT_SWITCH_31KHZ
|
||||||
|
};
|
||||||
|
|
||||||
enum override_type
|
enum override_type
|
||||||
{
|
{
|
||||||
OVERRIDE_NONE = 0,
|
OVERRIDE_NONE = 0,
|
||||||
|
@ -73,6 +80,7 @@ typedef struct settings
|
||||||
bool video_fullscreen;
|
bool video_fullscreen;
|
||||||
bool video_windowed_fullscreen;
|
bool video_windowed_fullscreen;
|
||||||
bool video_vsync;
|
bool video_vsync;
|
||||||
|
bool video_adaptive_vsync;
|
||||||
bool video_hard_sync;
|
bool video_hard_sync;
|
||||||
bool video_black_frame_insertion;
|
bool video_black_frame_insertion;
|
||||||
bool video_vfilter;
|
bool video_vfilter;
|
||||||
|
@ -96,7 +104,6 @@ typedef struct settings
|
||||||
bool video_statistics_show;
|
bool video_statistics_show;
|
||||||
bool video_framecount_show;
|
bool video_framecount_show;
|
||||||
bool video_msg_bgcolor_enable;
|
bool video_msg_bgcolor_enable;
|
||||||
bool crt_switch_resolution;
|
|
||||||
|
|
||||||
/* Audio */
|
/* Audio */
|
||||||
bool audio_enable;
|
bool audio_enable;
|
||||||
|
@ -181,8 +188,12 @@ typedef struct settings
|
||||||
bool quick_menu_show_save_game_overrides;
|
bool quick_menu_show_save_game_overrides;
|
||||||
bool quick_menu_show_save_content_dir_overrides;
|
bool quick_menu_show_save_content_dir_overrides;
|
||||||
bool quick_menu_show_information;
|
bool quick_menu_show_information;
|
||||||
|
bool quick_menu_show_recording;
|
||||||
|
bool quick_menu_show_streaming;
|
||||||
bool kiosk_mode_enable;
|
bool kiosk_mode_enable;
|
||||||
|
|
||||||
|
bool crt_switch_custom_refresh_enable;
|
||||||
|
|
||||||
/* Netplay */
|
/* Netplay */
|
||||||
bool netplay_public_announce;
|
bool netplay_public_announce;
|
||||||
bool netplay_start_as_spectator;
|
bool netplay_start_as_spectator;
|
||||||
|
@ -289,6 +300,7 @@ typedef struct settings
|
||||||
float video_scale;
|
float video_scale;
|
||||||
float video_aspect_ratio;
|
float video_aspect_ratio;
|
||||||
float video_refresh_rate;
|
float video_refresh_rate;
|
||||||
|
float crt_video_refresh_rate;
|
||||||
float video_font_size;
|
float video_font_size;
|
||||||
float video_msg_pos_x;
|
float video_msg_pos_x;
|
||||||
float video_msg_pos_y;
|
float video_msg_pos_y;
|
||||||
|
@ -321,6 +333,7 @@ typedef struct settings
|
||||||
int location_update_interval_distance;
|
int location_update_interval_distance;
|
||||||
int state_slot;
|
int state_slot;
|
||||||
int audio_wasapi_sh_buffer_length;
|
int audio_wasapi_sh_buffer_length;
|
||||||
|
int crt_switch_center_adjust;
|
||||||
} ints;
|
} ints;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
@ -359,6 +372,7 @@ typedef struct settings
|
||||||
unsigned video_window_x;
|
unsigned video_window_x;
|
||||||
unsigned video_window_y;
|
unsigned video_window_y;
|
||||||
unsigned video_window_opacity;
|
unsigned video_window_opacity;
|
||||||
|
unsigned crt_switch_resolution;
|
||||||
unsigned crt_switch_resolution_super;
|
unsigned crt_switch_resolution_super;
|
||||||
unsigned video_monitor_index;
|
unsigned video_monitor_index;
|
||||||
unsigned video_fullscreen_x;
|
unsigned video_fullscreen_x;
|
||||||
|
@ -373,6 +387,11 @@ typedef struct settings
|
||||||
unsigned video_msg_bgcolor_red;
|
unsigned video_msg_bgcolor_red;
|
||||||
unsigned video_msg_bgcolor_green;
|
unsigned video_msg_bgcolor_green;
|
||||||
unsigned video_msg_bgcolor_blue;
|
unsigned video_msg_bgcolor_blue;
|
||||||
|
unsigned video_stream_port;
|
||||||
|
unsigned video_record_quality;
|
||||||
|
unsigned video_stream_quality;
|
||||||
|
unsigned video_record_scale_factor;
|
||||||
|
unsigned video_stream_scale_factor;
|
||||||
|
|
||||||
unsigned menu_thumbnails;
|
unsigned menu_thumbnails;
|
||||||
unsigned menu_left_thumbnails;
|
unsigned menu_left_thumbnails;
|
||||||
|
@ -413,6 +432,7 @@ typedef struct settings
|
||||||
unsigned run_ahead_frames;
|
unsigned run_ahead_frames;
|
||||||
|
|
||||||
unsigned midi_volume;
|
unsigned midi_volume;
|
||||||
|
unsigned streaming_mode;
|
||||||
} uints;
|
} uints;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
@ -457,6 +477,9 @@ typedef struct settings
|
||||||
|
|
||||||
char midi_input[32];
|
char midi_input[32];
|
||||||
char midi_output[32];
|
char midi_output[32];
|
||||||
|
|
||||||
|
char youtube_stream_key[PATH_MAX_LENGTH];
|
||||||
|
char twitch_stream_key[PATH_MAX_LENGTH];
|
||||||
} arrays;
|
} arrays;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
@ -477,6 +500,9 @@ typedef struct settings
|
||||||
char path_cheat_database[PATH_MAX_LENGTH];
|
char path_cheat_database[PATH_MAX_LENGTH];
|
||||||
char path_content_database[PATH_MAX_LENGTH];
|
char path_content_database[PATH_MAX_LENGTH];
|
||||||
char path_overlay[PATH_MAX_LENGTH];
|
char path_overlay[PATH_MAX_LENGTH];
|
||||||
|
char path_record_config[PATH_MAX_LENGTH];
|
||||||
|
char path_stream_config[PATH_MAX_LENGTH];
|
||||||
|
char path_stream_url[PATH_MAX_LENGTH];
|
||||||
char path_menu_wallpaper[PATH_MAX_LENGTH];
|
char path_menu_wallpaper[PATH_MAX_LENGTH];
|
||||||
char path_audio_dsp_plugin[PATH_MAX_LENGTH];
|
char path_audio_dsp_plugin[PATH_MAX_LENGTH];
|
||||||
char path_softfilter_plugin[PATH_MAX_LENGTH];
|
char path_softfilter_plugin[PATH_MAX_LENGTH];
|
||||||
|
@ -491,7 +517,6 @@ typedef struct settings
|
||||||
char path_shader[PATH_MAX_LENGTH];
|
char path_shader[PATH_MAX_LENGTH];
|
||||||
char path_font[PATH_MAX_LENGTH];
|
char path_font[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
|
||||||
char directory_audio_filter[PATH_MAX_LENGTH];
|
char directory_audio_filter[PATH_MAX_LENGTH];
|
||||||
char directory_autoconfig[PATH_MAX_LENGTH];
|
char directory_autoconfig[PATH_MAX_LENGTH];
|
||||||
char directory_video_filter[PATH_MAX_LENGTH];
|
char directory_video_filter[PATH_MAX_LENGTH];
|
||||||
|
@ -513,6 +538,7 @@ typedef struct settings
|
||||||
char directory_thumbnails[PATH_MAX_LENGTH];
|
char directory_thumbnails[PATH_MAX_LENGTH];
|
||||||
char directory_menu_config[PATH_MAX_LENGTH];
|
char directory_menu_config[PATH_MAX_LENGTH];
|
||||||
char directory_menu_content[PATH_MAX_LENGTH];
|
char directory_menu_content[PATH_MAX_LENGTH];
|
||||||
|
char streaming_title[PATH_MAX_LENGTH];
|
||||||
} paths;
|
} paths;
|
||||||
|
|
||||||
bool modified;
|
bool modified;
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "verbosity.h"
|
#include "verbosity.h"
|
||||||
#include "gfx/video_driver.h"
|
#include "gfx/video_driver.h"
|
||||||
#include "audio/audio_driver.h"
|
#include "audio/audio_driver.h"
|
||||||
|
#include "tasks/tasks_internal.h"
|
||||||
|
|
||||||
#ifdef HAVE_RUNAHEAD
|
#ifdef HAVE_RUNAHEAD
|
||||||
#include "runahead/copy_load_info.h"
|
#include "runahead/copy_load_info.h"
|
||||||
|
@ -298,6 +299,7 @@ bool core_load_game(retro_ctx_load_content_info_t *load_info)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
content_get_status(&contentless, &is_inited);
|
content_get_status(&contentless, &is_inited);
|
||||||
|
set_save_state_in_background(false);
|
||||||
|
|
||||||
if (load_info && load_info->special)
|
if (load_info && load_info->special)
|
||||||
current_core.game_loaded = current_core.retro_load_game_special(
|
current_core.game_loaded = current_core.retro_load_game_special(
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#include <sys/dirent.h>
|
#include <sys/dirent.h>
|
||||||
|
#include <sys/iosupport.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
@ -25,21 +25,33 @@
|
||||||
|
|
||||||
#include "../msg_hash.h"
|
#include "../msg_hash.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_NETWORKING
|
||||||
|
#include "../../network/netplay/netplay.h"
|
||||||
|
#include "../../network/netplay/netplay_discovery.h"
|
||||||
|
#include "../../tasks/tasks_internal.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_CHEEVOS
|
||||||
|
#include "../cheevos/cheevos.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char* APPLICATION_ID = "475456035851599874";
|
static const char* APPLICATION_ID = "475456035851599874";
|
||||||
static int FrustrationLevel = 0;
|
static int FrustrationLevel = 0;
|
||||||
|
|
||||||
static int64_t start_time = 0;
|
static int64_t start_time = 0;
|
||||||
static int64_t pause_time = 0;
|
static int64_t pause_time = 0;
|
||||||
|
static int64_t ellapsed_time = 0;
|
||||||
|
|
||||||
static bool discord_ready = false;
|
static bool discord_ready = false;
|
||||||
static bool in_menu = false;
|
|
||||||
static unsigned discord_status = 0;
|
static unsigned discord_status = 0;
|
||||||
|
|
||||||
|
struct netplay_room *room;
|
||||||
|
|
||||||
DiscordRichPresence discord_presence;
|
DiscordRichPresence discord_presence;
|
||||||
|
|
||||||
static void handle_discord_ready(const DiscordUser* connectedUser)
|
static void handle_discord_ready(const DiscordUser* connectedUser)
|
||||||
{
|
{
|
||||||
RARCH_LOG("[Discord] connected to user %s#%s - %s\n",
|
RARCH_LOG("[Discord] connected to user: %s#%s - avatar id: %s\n",
|
||||||
connectedUser->username,
|
connectedUser->username,
|
||||||
connectedUser->discriminator,
|
connectedUser->discriminator,
|
||||||
connectedUser->userId);
|
connectedUser->userId);
|
||||||
|
@ -58,6 +70,21 @@ static void handle_discord_error(int errcode, const char* message)
|
||||||
static void handle_discord_join(const char* secret)
|
static void handle_discord_join(const char* secret)
|
||||||
{
|
{
|
||||||
RARCH_LOG("[Discord] join (%s)\n", secret);
|
RARCH_LOG("[Discord] join (%s)\n", secret);
|
||||||
|
static struct string_list *list = NULL;
|
||||||
|
list = string_split(secret, "|");
|
||||||
|
|
||||||
|
char tmp_hostname[32];
|
||||||
|
snprintf(tmp_hostname,
|
||||||
|
sizeof(tmp_hostname),
|
||||||
|
"%s|%s", list->elems[0].data, list->elems[1].data);
|
||||||
|
|
||||||
|
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
|
||||||
|
deinit_netplay();
|
||||||
|
netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
|
||||||
|
|
||||||
|
task_push_netplay_crc_scan(atoi(list->elems[3].data),
|
||||||
|
list->elems[2].data,
|
||||||
|
tmp_hostname, list->elems[4].data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_discord_spectate(const char* secret)
|
static void handle_discord_spectate(const char* secret)
|
||||||
|
@ -78,19 +105,17 @@ static void handle_discord_join_request(const DiscordUser* request)
|
||||||
void discord_update(enum discord_presence presence)
|
void discord_update(enum discord_presence presence)
|
||||||
{
|
{
|
||||||
core_info_t *core_info = NULL;
|
core_info_t *core_info = NULL;
|
||||||
bool skip = false;
|
|
||||||
|
|
||||||
core_info_get_current_core(&core_info);
|
core_info_get_current_core(&core_info);
|
||||||
|
|
||||||
if (!discord_ready)
|
if (!discord_ready)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (
|
if (presence == discord_status)
|
||||||
(discord_status != DISCORD_PRESENCE_MENU) &&
|
|
||||||
(discord_status == presence))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(&discord_presence, 0, sizeof(discord_presence));
|
if (presence == DISCORD_PRESENCE_NONE || presence == DISCORD_PRESENCE_MENU)
|
||||||
|
memset(&discord_presence, 0, sizeof(discord_presence));
|
||||||
|
|
||||||
switch (presence)
|
switch (presence)
|
||||||
{
|
{
|
||||||
|
@ -99,19 +124,15 @@ void discord_update(enum discord_presence presence)
|
||||||
discord_presence.largeImageKey = "base";
|
discord_presence.largeImageKey = "base";
|
||||||
discord_presence.largeImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE);
|
discord_presence.largeImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE);
|
||||||
discord_presence.instance = 0;
|
discord_presence.instance = 0;
|
||||||
|
|
||||||
in_menu = true;
|
|
||||||
break;
|
break;
|
||||||
case DISCORD_PRESENCE_GAME_PAUSED:
|
case DISCORD_PRESENCE_GAME_PAUSED:
|
||||||
discord_presence.smallImageKey = "paused";
|
discord_presence.smallImageKey = "paused";
|
||||||
discord_presence.smallImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED);
|
discord_presence.smallImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PAUSED);
|
||||||
discord_presence.details = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED);
|
discord_presence.details = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME_PAUSED);
|
||||||
|
|
||||||
pause_time = time(0);
|
pause_time = time(0);
|
||||||
skip = true;
|
ellapsed_time = difftime(time(0), start_time);
|
||||||
|
discord_presence.startTimestamp = pause_time;
|
||||||
if (in_menu)
|
break;
|
||||||
break;
|
|
||||||
case DISCORD_PRESENCE_GAME:
|
case DISCORD_PRESENCE_GAME:
|
||||||
if (core_info)
|
if (core_info)
|
||||||
{
|
{
|
||||||
|
@ -126,7 +147,7 @@ void discord_update(enum discord_presence presence)
|
||||||
|
|
||||||
if (!label)
|
if (!label)
|
||||||
label = (char *)path_basename(path_get(RARCH_PATH_BASENAME));
|
label = (char *)path_basename(path_get(RARCH_PATH_BASENAME));
|
||||||
#if 1
|
#if 0
|
||||||
RARCH_LOG("[Discord] current core: %s\n", system_id);
|
RARCH_LOG("[Discord] current core: %s\n", system_id);
|
||||||
RARCH_LOG("[Discord] current content: %s\n", label);
|
RARCH_LOG("[Discord] current content: %s\n", label);
|
||||||
#endif
|
#endif
|
||||||
|
@ -135,39 +156,57 @@ void discord_update(enum discord_presence presence)
|
||||||
if (core_info->display_name)
|
if (core_info->display_name)
|
||||||
discord_presence.largeImageText = core_info->display_name;
|
discord_presence.largeImageText = core_info->display_name;
|
||||||
|
|
||||||
if (in_menu)
|
start_time = time(0);
|
||||||
start_time = time(0);
|
if (pause_time != 0)
|
||||||
else
|
start_time = time(0) - ellapsed_time;
|
||||||
start_time = start_time + difftime(time(0), pause_time);
|
|
||||||
|
|
||||||
if (!skip)
|
pause_time = 0;
|
||||||
{
|
ellapsed_time = 0;
|
||||||
discord_presence.smallImageKey = "playing";
|
|
||||||
discord_presence.smallImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING);
|
discord_presence.smallImageKey = "playing";
|
||||||
discord_presence.startTimestamp = start_time;
|
discord_presence.smallImageText = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_STATUS_PLAYING);
|
||||||
discord_presence.details = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME);
|
discord_presence.startTimestamp = start_time;
|
||||||
}
|
discord_presence.details = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISCORD_IN_GAME);
|
||||||
|
|
||||||
discord_presence.state = label;
|
discord_presence.state = label;
|
||||||
discord_presence.instance = 0;
|
discord_presence.instance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_menu = false;
|
|
||||||
break;
|
break;
|
||||||
case DISCORD_PRESENCE_NETPLAY_HOSTING:
|
case DISCORD_PRESENCE_NETPLAY_HOSTING:
|
||||||
|
room = netplay_get_host_room();
|
||||||
|
if (room->id == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RARCH_LOG("[Discord] netplay room details: id=%d, nick=%s IP=%s port=%d\n",
|
||||||
|
room->id, room->nickname,
|
||||||
|
room->host_method == NETPLAY_HOST_METHOD_MITM ? room->mitm_address : room->address,
|
||||||
|
room->host_method == NETPLAY_HOST_METHOD_MITM ? room->mitm_port : room->port);
|
||||||
|
|
||||||
|
char party_id[128];
|
||||||
|
snprintf(party_id, sizeof(party_id), "%d|%s", room->id, room->nickname);
|
||||||
|
char join_secret[128];
|
||||||
|
snprintf(join_secret, sizeof(join_secret), "%s|%d|%s|%u|%s",
|
||||||
|
room->host_method == NETPLAY_HOST_METHOD_MITM ? room->mitm_address : room->address,
|
||||||
|
room->host_method == NETPLAY_HOST_METHOD_MITM ? room->mitm_port : room->port,
|
||||||
|
room->gamename, room->gamecrc, room->corename);
|
||||||
|
RARCH_LOG("%s\n", join_secret);
|
||||||
|
discord_presence.joinSecret = strdup(join_secret);
|
||||||
|
discord_presence.spectateSecret = "SPECSPECSPEC";
|
||||||
|
discord_presence.partyId = party_id;
|
||||||
|
discord_presence.partyMax = 0;
|
||||||
|
discord_presence.partySize = 0;
|
||||||
|
break;
|
||||||
|
case DISCORD_PRESENCE_NETPLAY_HOSTING_STOPPED:
|
||||||
case DISCORD_PRESENCE_NETPLAY_CLIENT:
|
case DISCORD_PRESENCE_NETPLAY_CLIENT:
|
||||||
case DISCORD_PRESENCE_CHEEVO_UNLOCKED:
|
default:
|
||||||
/* TODO/FIXME */
|
discord_presence.joinSecret = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_menu && skip)
|
|
||||||
return;
|
|
||||||
|
|
||||||
RARCH_LOG("[Discord] updating (%d)\n", presence);
|
RARCH_LOG("[Discord] updating (%d)\n", presence);
|
||||||
|
|
||||||
Discord_UpdatePresence(&discord_presence);
|
Discord_UpdatePresence(&discord_presence);
|
||||||
discord_status = presence;
|
discord_status = presence;
|
||||||
}
|
}
|
||||||
|
|
||||||
void discord_init(void)
|
void discord_init(void)
|
||||||
|
@ -197,3 +236,8 @@ void discord_shutdown(void)
|
||||||
Discord_Shutdown();
|
Discord_Shutdown();
|
||||||
discord_ready = false;
|
discord_ready = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void discord_run_callbacks()
|
||||||
|
{
|
||||||
|
Discord_RunCallbacks();
|
||||||
|
}
|
|
@ -32,11 +32,13 @@
|
||||||
|
|
||||||
enum discord_presence
|
enum discord_presence
|
||||||
{
|
{
|
||||||
DISCORD_PRESENCE_MENU = 0,
|
DISCORD_PRESENCE_NONE = 0,
|
||||||
|
DISCORD_PRESENCE_MENU,
|
||||||
DISCORD_PRESENCE_GAME,
|
DISCORD_PRESENCE_GAME,
|
||||||
DISCORD_PRESENCE_GAME_PAUSED,
|
DISCORD_PRESENCE_GAME_PAUSED,
|
||||||
DISCORD_PRESENCE_CHEEVO_UNLOCKED,
|
DISCORD_PRESENCE_CHEEVO_UNLOCKED,
|
||||||
DISCORD_PRESENCE_NETPLAY_HOSTING,
|
DISCORD_PRESENCE_NETPLAY_HOSTING,
|
||||||
|
DISCORD_PRESENCE_NETPLAY_HOSTING_STOPPED,
|
||||||
DISCORD_PRESENCE_NETPLAY_CLIENT
|
DISCORD_PRESENCE_NETPLAY_CLIENT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,4 +53,6 @@ void discord_shutdown(void);
|
||||||
|
|
||||||
void discord_update(enum discord_presence presence);
|
void discord_update(enum discord_presence presence);
|
||||||
|
|
||||||
|
void discord_run_callbacks();
|
||||||
|
|
||||||
#endif /* __RARCH_DISCORD_H */
|
#endif /* __RARCH_DISCORD_H */
|
||||||
|
|
38
dynamic.c
38
dynamic.c
|
@ -66,6 +66,7 @@
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "msg_hash.h"
|
#include "msg_hash.h"
|
||||||
#include "verbosity.h"
|
#include "verbosity.h"
|
||||||
|
#include "tasks/tasks_internal.h"
|
||||||
|
|
||||||
#ifdef HAVE_RUNAHEAD
|
#ifdef HAVE_RUNAHEAD
|
||||||
#include "runahead/secondary_core.h"
|
#include "runahead/secondary_core.h"
|
||||||
|
@ -1041,6 +1042,16 @@ static void core_performance_counter_stop(struct retro_perf_counter *perf)
|
||||||
perf->total += cpu_features_get_perf_counter() - perf->start;
|
perf->total += cpu_features_get_perf_counter() - perf->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rarch_clear_all_thread_waits(unsigned clear_threads, void *data)
|
||||||
|
{
|
||||||
|
if ( clear_threads > 0)
|
||||||
|
audio_driver_start(false) ;
|
||||||
|
else
|
||||||
|
audio_driver_stop() ;
|
||||||
|
|
||||||
|
return true ;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rarch_environment_cb:
|
* rarch_environment_cb:
|
||||||
* @cmd : Identifier of command.
|
* @cmd : Identifier of command.
|
||||||
|
@ -1387,6 +1398,16 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case RETRO_ENVIRONMENT_SET_SAVE_STATE_IN_BACKGROUND:
|
||||||
|
{
|
||||||
|
bool state = *(const bool*)data;
|
||||||
|
RARCH_LOG("Environ SET_SAVE_STATE_IN_BACKGROUND: %s.\n", state ? "yes" : "no");
|
||||||
|
|
||||||
|
set_save_state_in_background(state) ;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH:
|
case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH:
|
||||||
{
|
{
|
||||||
const char **path = (const char**)data;
|
const char **path = (const char**)data;
|
||||||
|
@ -1822,8 +1843,8 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||||
int* result_p = (int*)data;
|
int* result_p = (int*)data;
|
||||||
*result_p = result;
|
*result_p = result;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE:
|
case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE:
|
||||||
{
|
{
|
||||||
|
@ -1838,8 +1859,21 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||||
midi_interface->write = midi_driver_write;
|
midi_interface->write = midi_driver_write;
|
||||||
midi_interface->flush = midi_driver_flush;
|
midi_interface->flush = midi_driver_flush;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RETRO_ENVIRONMENT_GET_FASTFORWARDING:
|
||||||
|
{
|
||||||
|
extern bool runloop_fastmotion;
|
||||||
|
*(bool *)data = runloop_fastmotion;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RETRO_ENVIRONMENT_GET_CLEAR_ALL_THREAD_WAITS_CB:
|
||||||
|
{
|
||||||
|
*(retro_environment_t *)data = rarch_clear_all_thread_waits;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd);
|
RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd);
|
||||||
|
|
|
@ -347,9 +347,15 @@ static void frontend_darwin_get_environment_settings(int *argc, char *argv[],
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
strlcat(home_dir_buf, "/RetroArch", sizeof(home_dir_buf));
|
strlcat(home_dir_buf, "/RetroArch", sizeof(home_dir_buf));
|
||||||
|
#ifdef HAVE_METAL
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER],
|
||||||
|
home_dir_buf, "shaders_slang",
|
||||||
|
sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
|
||||||
|
#else
|
||||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER],
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER],
|
||||||
home_dir_buf, "shaders_glsl",
|
home_dir_buf, "shaders_glsl",
|
||||||
sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
|
sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
|
||||||
|
#endif
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
int major, minor;
|
int major, minor;
|
||||||
get_ios_version(&major, &minor);
|
get_ios_version(&major, &minor);
|
||||||
|
|
|
@ -0,0 +1,803 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include <file/nbio.h>
|
||||||
|
#include <formats/rpng.h>
|
||||||
|
#include <formats/image.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
#include <switch.h>
|
||||||
|
#else
|
||||||
|
#include <libtransistor/nx.h>
|
||||||
|
#include <libtransistor/ipc_helpers.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <file/file_path.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "../../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IS_SALAMANDER
|
||||||
|
#include <lists/file_list.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../frontend_driver.h"
|
||||||
|
#include "../../verbosity.h"
|
||||||
|
#include "../../defaults.h"
|
||||||
|
#include "../../paths.h"
|
||||||
|
#include "../../retroarch.h"
|
||||||
|
#include "../../file_path_special.h"
|
||||||
|
#include "../../audio/audio_driver.h"
|
||||||
|
|
||||||
|
#ifndef IS_SALAMANDER
|
||||||
|
#ifdef HAVE_MENU
|
||||||
|
#include "../../menu/menu_driver.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
#define SD_PREFIX
|
||||||
|
#include "../../gfx/common/switch_common.h"
|
||||||
|
#else
|
||||||
|
#define SD_PREFIX "/sd"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static enum frontend_fork switch_fork_mode = FRONTEND_FORK_NONE;
|
||||||
|
static const char *elf_path_cst = "/switch/retroarch_switch.nro";
|
||||||
|
|
||||||
|
static uint64_t frontend_switch_get_mem_used(void);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
|
||||||
|
// Splash
|
||||||
|
static uint32_t *splashData = NULL;
|
||||||
|
|
||||||
|
#endif // HAVE_LIBNX
|
||||||
|
|
||||||
|
static void get_first_valid_core(char *path_return)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
const char *extension = ".nro";
|
||||||
|
|
||||||
|
path_return[0] = '\0';
|
||||||
|
|
||||||
|
dir = opendir(SD_PREFIX "/retroarch/cores");
|
||||||
|
if (dir != NULL)
|
||||||
|
{
|
||||||
|
while ((ent = readdir(dir)) != NULL)
|
||||||
|
{
|
||||||
|
if (ent == NULL)
|
||||||
|
break;
|
||||||
|
if (strlen(ent->d_name) > strlen(extension) && !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension))
|
||||||
|
{
|
||||||
|
strcpy(path_return, SD_PREFIX "/retroarch/cores");
|
||||||
|
strcat(path_return, "/");
|
||||||
|
strcat(path_return, ent->d_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frontend_switch_get_environment_settings(int *argc, char *argv[], void *args, void *params_data)
|
||||||
|
{
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
#ifndef IS_SALAMANDER
|
||||||
|
#if defined(HAVE_LOGGER)
|
||||||
|
logger_init();
|
||||||
|
#elif defined(HAVE_FILE_LOGGER)
|
||||||
|
retro_main_log_file_init(SD_PREFIX "/retroarch-log.txt");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], SD_PREFIX "/retroarch/retroarch_switch.nro", sizeof(g_defaults.dirs[DEFAULT_DIR_PORT]));
|
||||||
|
RARCH_LOG("port dir: [%s]\n", g_defaults.dirs[DEFAULT_DIR_PORT]);
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
"downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
"media", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
"cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||||
|
"info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||||
|
"savestates", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||||
|
"savefiles", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||||
|
"system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||||
|
"playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
"config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
"config/remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
"filters", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
"database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CURSOR], g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
"database/cursors", sizeof(g_defaults.dirs[DEFAULT_DIR_CURSOR]));
|
||||||
|
|
||||||
|
fill_pathname_join(g_defaults.path.config, g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||||
|
file_path_str(FILE_PATH_MAIN_CONFIG), sizeof(g_defaults.path.config));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern switch_ctx_data_t *nx_ctx_ptr;
|
||||||
|
static void frontend_switch_deinit(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
#if defined(SWITCH) && defined(NXLINK)
|
||||||
|
socketExit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Splash
|
||||||
|
if (splashData)
|
||||||
|
{
|
||||||
|
free(splashData);
|
||||||
|
splashData = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_OPENGL
|
||||||
|
gfxExit();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
static void frontend_switch_exec(const char *path, bool should_load_game)
|
||||||
|
{
|
||||||
|
char game_path[PATH_MAX];
|
||||||
|
const char *arg_data[3];
|
||||||
|
char error_string[200 + PATH_MAX];
|
||||||
|
int args = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
game_path[0] = NULL;
|
||||||
|
arg_data[0] = NULL;
|
||||||
|
|
||||||
|
arg_data[args] = elf_path_cst;
|
||||||
|
arg_data[args + 1] = NULL;
|
||||||
|
args++;
|
||||||
|
|
||||||
|
RARCH_LOG("Attempt to load core: [%s].\n", path);
|
||||||
|
#ifndef IS_SALAMANDER
|
||||||
|
if (should_load_game && !path_is_empty(RARCH_PATH_CONTENT))
|
||||||
|
{
|
||||||
|
strcpy(game_path, path_get(RARCH_PATH_CONTENT));
|
||||||
|
arg_data[args] = game_path;
|
||||||
|
arg_data[args + 1] = NULL;
|
||||||
|
args++;
|
||||||
|
RARCH_LOG("content path: [%s].\n", path_get(RARCH_PATH_CONTENT));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (path && path[0])
|
||||||
|
{
|
||||||
|
#ifdef IS_SALAMANDER
|
||||||
|
struct stat sbuff;
|
||||||
|
bool file_exists;
|
||||||
|
|
||||||
|
file_exists = stat(path, &sbuff) == 0;
|
||||||
|
if (!file_exists)
|
||||||
|
{
|
||||||
|
char core_path[PATH_MAX];
|
||||||
|
|
||||||
|
/* find first valid core and load it if the target core doesnt exist */
|
||||||
|
get_first_valid_core(&core_path[0]);
|
||||||
|
|
||||||
|
if (core_path[0] == '\0')
|
||||||
|
{
|
||||||
|
/*errorInit(&error_dialog, ERROR_TEXT, CFG_LANGUAGE_EN);
|
||||||
|
errorText(&error_dialog, "There are no cores installed, install a core to continue.");
|
||||||
|
errorDisp(&error_dialog);*/
|
||||||
|
svcExitProcess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
char *argBuffer = (char *)malloc(PATH_MAX);
|
||||||
|
if (should_load_game)
|
||||||
|
{
|
||||||
|
snprintf(argBuffer, PATH_MAX, "%s \"%s\"", path, game_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(argBuffer, PATH_MAX, "%s", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
envSetNextLoad(path, argBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef IS_SALAMANDER
|
||||||
|
static bool frontend_switch_set_fork(enum frontend_fork fork_mode)
|
||||||
|
{
|
||||||
|
switch (fork_mode)
|
||||||
|
{
|
||||||
|
case FRONTEND_FORK_CORE:
|
||||||
|
RARCH_LOG("FRONTEND_FORK_CORE\n");
|
||||||
|
switch_fork_mode = fork_mode;
|
||||||
|
break;
|
||||||
|
case FRONTEND_FORK_CORE_WITH_ARGS:
|
||||||
|
RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n");
|
||||||
|
switch_fork_mode = fork_mode;
|
||||||
|
break;
|
||||||
|
case FRONTEND_FORK_RESTART:
|
||||||
|
RARCH_LOG("FRONTEND_FORK_RESTART\n");
|
||||||
|
/* NOTE: We don't implement Salamander, so just turn
|
||||||
|
this into FRONTEND_FORK_CORE. */
|
||||||
|
switch_fork_mode = FRONTEND_FORK_CORE;
|
||||||
|
break;
|
||||||
|
case FRONTEND_FORK_NONE:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void frontend_switch_exitspawn(char *s, size_t len)
|
||||||
|
{
|
||||||
|
bool should_load_game = false;
|
||||||
|
#ifndef IS_SALAMANDER
|
||||||
|
if (switch_fork_mode == FRONTEND_FORK_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (switch_fork_mode)
|
||||||
|
{
|
||||||
|
case FRONTEND_FORK_CORE_WITH_ARGS:
|
||||||
|
should_load_game = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
frontend_switch_exec(s, should_load_game);
|
||||||
|
}
|
||||||
|
|
||||||
|
void argb_to_rgba8(uint32_t *buff, uint32_t height, uint32_t width)
|
||||||
|
{
|
||||||
|
// Convert
|
||||||
|
for (uint32_t h = 0; h < height; h++)
|
||||||
|
{
|
||||||
|
for (uint32_t w = 0; w < width; w++)
|
||||||
|
{
|
||||||
|
uint32_t offset = (h * width) + w;
|
||||||
|
uint32_t c = buff[offset];
|
||||||
|
|
||||||
|
uint32_t a = (uint32_t)((c & 0xff000000) >> 24);
|
||||||
|
uint32_t r = (uint32_t)((c & 0x00ff0000) >> 16);
|
||||||
|
uint32_t g = (uint32_t)((c & 0x0000ff00) >> 8);
|
||||||
|
uint32_t b = (uint32_t)(c & 0x000000ff);
|
||||||
|
|
||||||
|
buff[offset] = RGBA8(r, g, b, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void frontend_switch_showsplash()
|
||||||
|
{
|
||||||
|
printf("[Splash] Showing splashScreen\n");
|
||||||
|
|
||||||
|
if (splashData)
|
||||||
|
{
|
||||||
|
uint32_t width, height;
|
||||||
|
width = height = 0;
|
||||||
|
|
||||||
|
uint32_t *frambuffer = (uint32_t *)gfxGetFramebuffer(&width, &height);
|
||||||
|
|
||||||
|
gfx_slow_swizzling_blit(frambuffer, splashData, width, height, 0, 0, false);
|
||||||
|
|
||||||
|
gfxFlushBuffers();
|
||||||
|
gfxSwapBuffers();
|
||||||
|
gfxWaitForVsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From rpng_test.c
|
||||||
|
bool rpng_load_image_argb(const char *path, uint32_t **data, unsigned *width, unsigned *height)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
size_t file_len;
|
||||||
|
bool ret = true;
|
||||||
|
rpng_t *rpng = NULL;
|
||||||
|
void *ptr = NULL;
|
||||||
|
|
||||||
|
struct nbio_t *handle = (struct nbio_t *)nbio_open(path, NBIO_READ);
|
||||||
|
|
||||||
|
if (!handle)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
nbio_begin_read(handle);
|
||||||
|
|
||||||
|
while (!nbio_iterate(handle))
|
||||||
|
svcSleepThread(3);
|
||||||
|
|
||||||
|
ptr = nbio_get_ptr(handle, &file_len);
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpng = rpng_alloc();
|
||||||
|
|
||||||
|
if (!rpng)
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rpng_set_buf_ptr(rpng, (uint8_t *)ptr))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rpng_start(rpng))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (rpng_iterate_image(rpng))
|
||||||
|
svcSleepThread(3);
|
||||||
|
|
||||||
|
if (!rpng_is_valid(rpng))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
retval = rpng_process_image(rpng, (void **)data, file_len, width, height);
|
||||||
|
svcSleepThread(3);
|
||||||
|
} while (retval == IMAGE_PROCESS_NEXT);
|
||||||
|
|
||||||
|
if (retval == IMAGE_PROCESS_ERROR || retval == IMAGE_PROCESS_ERROR_END)
|
||||||
|
ret = false;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (handle)
|
||||||
|
nbio_free(handle);
|
||||||
|
|
||||||
|
if (rpng)
|
||||||
|
rpng_free(rpng);
|
||||||
|
|
||||||
|
rpng = NULL;
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
free(*data);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
|
||||||
|
{
|
||||||
|
svcSleepThread(rqtp->tv_nsec + (rqtp->tv_sec * 1000000000));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long sysconf(int name)
|
||||||
|
{
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
return 0x1000;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taken from glibc
|
||||||
|
char *realpath(const char *name, char *resolved)
|
||||||
|
{
|
||||||
|
char *rpath, *dest, *extra_buf = NULL;
|
||||||
|
const char *start, *end, *rpath_limit;
|
||||||
|
long int path_max;
|
||||||
|
int num_links = 0;
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
{
|
||||||
|
/* As per Single Unix Specification V2 we must return an error if
|
||||||
|
either parameter is a null pointer. We extend this to allow
|
||||||
|
the RESOLVED parameter to be NULL in case the we are expected to
|
||||||
|
allocate the room for the return value. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name[0] == '\0')
|
||||||
|
{
|
||||||
|
/* As per Single Unix Specification V2 we must return an error if
|
||||||
|
the name argument points to an empty string. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PATH_MAX
|
||||||
|
path_max = PATH_MAX;
|
||||||
|
#else
|
||||||
|
path_max = pathconf(name, _PC_PATH_MAX);
|
||||||
|
if (path_max <= 0)
|
||||||
|
path_max = 1024;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (resolved == NULL)
|
||||||
|
{
|
||||||
|
rpath = malloc(path_max);
|
||||||
|
if (rpath == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rpath = resolved;
|
||||||
|
rpath_limit = rpath + path_max;
|
||||||
|
|
||||||
|
if (name[0] != '/')
|
||||||
|
{
|
||||||
|
if (!getcwd(rpath, path_max))
|
||||||
|
{
|
||||||
|
rpath[0] = '\0';
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
dest = memchr(rpath, '\0', path_max);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rpath[0] = '/';
|
||||||
|
dest = rpath + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (start = end = name; *start; start = end)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* Skip sequence of multiple path-separators. */
|
||||||
|
while (*start == '/')
|
||||||
|
++start;
|
||||||
|
|
||||||
|
/* Find end of path component. */
|
||||||
|
for (end = start; *end && *end != '/'; ++end)
|
||||||
|
/* Nothing. */;
|
||||||
|
|
||||||
|
if (end - start == 0)
|
||||||
|
break;
|
||||||
|
else if (end - start == 1 && start[0] == '.')
|
||||||
|
/* nothing */;
|
||||||
|
else if (end - start == 2 && start[0] == '.' && start[1] == '.')
|
||||||
|
{
|
||||||
|
/* Back up to previous component, ignore if at root already. */
|
||||||
|
if (dest > rpath + 1)
|
||||||
|
while ((--dest)[-1] != '/')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t new_size;
|
||||||
|
|
||||||
|
if (dest[-1] != '/')
|
||||||
|
*dest++ = '/';
|
||||||
|
|
||||||
|
if (dest + (end - start) >= rpath_limit)
|
||||||
|
{
|
||||||
|
ptrdiff_t dest_offset = dest - rpath;
|
||||||
|
char *new_rpath;
|
||||||
|
|
||||||
|
if (resolved)
|
||||||
|
{
|
||||||
|
if (dest > rpath + 1)
|
||||||
|
dest--;
|
||||||
|
*dest = '\0';
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
new_size = rpath_limit - rpath;
|
||||||
|
if (end - start + 1 > path_max)
|
||||||
|
new_size += end - start + 1;
|
||||||
|
else
|
||||||
|
new_size += path_max;
|
||||||
|
new_rpath = (char *)realloc(rpath, new_size);
|
||||||
|
if (new_rpath == NULL)
|
||||||
|
goto error;
|
||||||
|
rpath = new_rpath;
|
||||||
|
rpath_limit = rpath + new_size;
|
||||||
|
|
||||||
|
dest = rpath + dest_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest = memcpy(dest, start, end - start);
|
||||||
|
*dest = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dest > rpath + 1 && dest[-1] == '/')
|
||||||
|
--dest;
|
||||||
|
*dest = '\0';
|
||||||
|
|
||||||
|
return rpath;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (resolved == NULL)
|
||||||
|
free(rpath);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HAVE_LIBNX
|
||||||
|
|
||||||
|
static void frontend_switch_shutdown(bool unused)
|
||||||
|
{
|
||||||
|
(void)unused;
|
||||||
|
}
|
||||||
|
|
||||||
|
// runloop_get_system_info isnt initialized that early..
|
||||||
|
extern void retro_get_system_info(struct retro_system_info *info);
|
||||||
|
|
||||||
|
static void frontend_switch_init(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
#ifndef HAVE_OPENGL
|
||||||
|
// Init Resolution before initDefault
|
||||||
|
gfxInitResolution(1280, 720);
|
||||||
|
|
||||||
|
gfxInitDefault();
|
||||||
|
gfxSetMode(GfxMode_TiledDouble);
|
||||||
|
|
||||||
|
gfxConfigureTransform(0);
|
||||||
|
#endif // HAVE_OPENGL
|
||||||
|
#ifdef NXLINK
|
||||||
|
socketInitializeDefault();
|
||||||
|
nxlinkStdio();
|
||||||
|
#ifndef IS_SALAMANDER
|
||||||
|
verbosity_enable();
|
||||||
|
#endif // IS_SALAMANDER
|
||||||
|
#endif // NXLINK
|
||||||
|
|
||||||
|
rarch_system_info_t *sys_info = runloop_get_system_info();
|
||||||
|
retro_get_system_info(sys_info);
|
||||||
|
|
||||||
|
const char *core_name = NULL;
|
||||||
|
uint32_t width, height;
|
||||||
|
width = height = 0;
|
||||||
|
|
||||||
|
// Load splash
|
||||||
|
#ifndef HAVE_OPENGL
|
||||||
|
if (!splashData)
|
||||||
|
{
|
||||||
|
if (sys_info)
|
||||||
|
{
|
||||||
|
core_name = sys_info->info.library_name;
|
||||||
|
char *full_core_splash_path = (char *)malloc(PATH_MAX);
|
||||||
|
snprintf(full_core_splash_path, PATH_MAX, "/retroarch/rgui/splash/%s.png", core_name);
|
||||||
|
|
||||||
|
rpng_load_image_argb((const char *)full_core_splash_path, &splashData, &width, &height);
|
||||||
|
if (splashData)
|
||||||
|
{
|
||||||
|
argb_to_rgba8(splashData, height, width);
|
||||||
|
frontend_switch_showsplash();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rpng_load_image_argb("/retroarch/rgui/splash/RetroArch.png", &splashData, &width, &height);
|
||||||
|
if (splashData)
|
||||||
|
{
|
||||||
|
argb_to_rgba8(splashData, height, width);
|
||||||
|
frontend_switch_showsplash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(full_core_splash_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rpng_load_image_argb("/retroarch/rgui/splash/RetroArch.png", &splashData, &width, &height);
|
||||||
|
if (splashData)
|
||||||
|
{
|
||||||
|
argb_to_rgba8(splashData, height, width);
|
||||||
|
frontend_switch_showsplash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frontend_switch_showsplash();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // HAVE_LIBNX (splash)
|
||||||
|
}
|
||||||
|
|
||||||
|
static int frontend_switch_get_rating(void)
|
||||||
|
{
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum frontend_architecture frontend_switch_get_architecture(void)
|
||||||
|
{
|
||||||
|
return FRONTEND_ARCH_ARMV8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int frontend_switch_parse_drive_list(void *data, bool load_content)
|
||||||
|
{
|
||||||
|
#ifndef IS_SALAMANDER
|
||||||
|
file_list_t *list = (file_list_t *)data;
|
||||||
|
enum msg_hash_enums enum_idx = load_content ? MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR : MSG_UNKNOWN;
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
menu_entries_append_enum(list, "/", msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
|
||||||
|
enum_idx,
|
||||||
|
FILE_TYPE_DIRECTORY, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t frontend_switch_get_mem_total(void)
|
||||||
|
{
|
||||||
|
uint64_t memoryTotal = 0;
|
||||||
|
svcGetInfo(&memoryTotal, 6, 0xffff8001, 0); // avaiable
|
||||||
|
memoryTotal += frontend_switch_get_mem_used();
|
||||||
|
|
||||||
|
return memoryTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t frontend_switch_get_mem_used(void)
|
||||||
|
{
|
||||||
|
uint64_t memoryUsed = 0;
|
||||||
|
svcGetInfo(&memoryUsed, 7, 0xffff8001, 0); // used
|
||||||
|
|
||||||
|
return memoryUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum frontend_powerstate frontend_switch_get_powerstate(int *seconds, int *percent)
|
||||||
|
{
|
||||||
|
// This is fine monkaS
|
||||||
|
return FRONTEND_POWERSTATE_CHARGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frontend_switch_get_os(char *s, size_t len, int *major, int *minor)
|
||||||
|
{
|
||||||
|
strlcpy(s, "Horizon OS", len);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
// There is pretty sure a better way, but this will do just fine
|
||||||
|
if (kernelAbove600())
|
||||||
|
{
|
||||||
|
*major = 6;
|
||||||
|
*minor = 0;
|
||||||
|
}
|
||||||
|
else if(kernelAbove500())
|
||||||
|
{
|
||||||
|
*major = 5;
|
||||||
|
*minor = 0;
|
||||||
|
}else if (kernelAbove400())
|
||||||
|
{
|
||||||
|
*major = 4;
|
||||||
|
*minor = 0;
|
||||||
|
}
|
||||||
|
else if (kernelAbove300())
|
||||||
|
{
|
||||||
|
*major = 3;
|
||||||
|
*minor = 0;
|
||||||
|
}
|
||||||
|
else if (kernelAbove200())
|
||||||
|
{
|
||||||
|
*major = 2;
|
||||||
|
*minor = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// either 1.0 or > 5.x
|
||||||
|
*major = 1;
|
||||||
|
*minor = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// defaults in case we error out
|
||||||
|
*major = 0;
|
||||||
|
*minor = 0;
|
||||||
|
|
||||||
|
char firmware_version[0x100];
|
||||||
|
|
||||||
|
result_t r; // used by LIB_ASSERT_OK macros
|
||||||
|
LIB_ASSERT_OK(fail, sm_init());
|
||||||
|
|
||||||
|
ipc_object_t set_sys;
|
||||||
|
LIB_ASSERT_OK(fail_sm, sm_get_service(&set_sys, "set:sys"));
|
||||||
|
|
||||||
|
ipc_request_t rq = ipc_make_request(3);
|
||||||
|
ipc_buffer_t buffers[] = {
|
||||||
|
ipc_make_buffer(firmware_version, 0x100, 0x1a),
|
||||||
|
};
|
||||||
|
ipc_msg_set_buffers(rq, buffers, buffer_ptrs);
|
||||||
|
|
||||||
|
LIB_ASSERT_OK(fail_object, ipc_send(set_sys, &rq, &ipc_default_response_fmt));
|
||||||
|
|
||||||
|
int patch;
|
||||||
|
sscanf(firmware_version + 0x68, "%d.%d.%d", major, minor, &patch);
|
||||||
|
|
||||||
|
fail_object:
|
||||||
|
ipc_close(set_sys);
|
||||||
|
fail_sm:
|
||||||
|
sm_finalize();
|
||||||
|
fail:
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frontend_switch_get_name(char *s, size_t len)
|
||||||
|
{
|
||||||
|
// TODO: Add Mariko at some point
|
||||||
|
strlcpy(s, "Nintendo Switch", len);
|
||||||
|
}
|
||||||
|
|
||||||
|
frontend_ctx_driver_t frontend_ctx_switch =
|
||||||
|
{
|
||||||
|
frontend_switch_get_environment_settings,
|
||||||
|
frontend_switch_init,
|
||||||
|
frontend_switch_deinit,
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
frontend_switch_exitspawn,
|
||||||
|
NULL, /* process_args */
|
||||||
|
frontend_switch_exec,
|
||||||
|
#ifdef IS_SALAMANDER
|
||||||
|
NULL,
|
||||||
|
#else
|
||||||
|
frontend_switch_set_fork,
|
||||||
|
#endif
|
||||||
|
#else // HAVE_LIBNX
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
#endif // HAVE_LIBNX
|
||||||
|
frontend_switch_shutdown,
|
||||||
|
frontend_switch_get_name,
|
||||||
|
frontend_switch_get_os,
|
||||||
|
frontend_switch_get_rating,
|
||||||
|
NULL, /* load_content */
|
||||||
|
frontend_switch_get_architecture,
|
||||||
|
frontend_switch_get_powerstate,
|
||||||
|
frontend_switch_parse_drive_list,
|
||||||
|
frontend_switch_get_mem_total,
|
||||||
|
frontend_switch_get_mem_used,
|
||||||
|
NULL, /* install_signal_handler */
|
||||||
|
NULL, /* get_signal_handler_state */
|
||||||
|
NULL, /* set_signal_handler_state */
|
||||||
|
NULL, /* destroy_signal_handler_state */
|
||||||
|
NULL, /* attach_console */
|
||||||
|
NULL, /* detach_console */
|
||||||
|
NULL, /* watch_path_for_changes */
|
||||||
|
NULL, /* check_for_path_changes */
|
||||||
|
NULL, /* set_sustained_performance_mode */
|
||||||
|
"switch",
|
||||||
|
};
|
|
@ -59,6 +59,9 @@ static frontend_ctx_driver_t *frontend_ctx_drivers[] = {
|
||||||
#if defined(_3DS)
|
#if defined(_3DS)
|
||||||
&frontend_ctx_ctr,
|
&frontend_ctx_ctr,
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(SWITCH) && defined(HAVE_LIBNX)
|
||||||
|
&frontend_ctx_switch,
|
||||||
|
#endif
|
||||||
#if defined(_WIN32) && !defined(_XBOX)
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
&frontend_ctx_win32,
|
&frontend_ctx_win32,
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,6 +70,9 @@ static frontend_ctx_driver_t *frontend_ctx_drivers[] = {
|
||||||
#endif
|
#endif
|
||||||
#ifdef DJGPP
|
#ifdef DJGPP
|
||||||
&frontend_ctx_dos,
|
&frontend_ctx_dos,
|
||||||
|
#endif
|
||||||
|
#ifdef SWITCH
|
||||||
|
&frontend_ctx_switch,
|
||||||
#endif
|
#endif
|
||||||
&frontend_ctx_null,
|
&frontend_ctx_null,
|
||||||
NULL
|
NULL
|
||||||
|
@ -150,6 +156,9 @@ bool frontend_driver_get_core_extension(char *s, size_t len)
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
strlcpy(s, "elf", len);
|
strlcpy(s, "elf", len);
|
||||||
return true;
|
return true;
|
||||||
|
#elif defined(HAVE_LIBNX)
|
||||||
|
strlcpy(s, "nro", len);
|
||||||
|
return true;
|
||||||
#elif defined(_3DS)
|
#elif defined(_3DS)
|
||||||
if (envIsHomebrew())
|
if (envIsHomebrew())
|
||||||
strlcpy(s, "3dsx", len);
|
strlcpy(s, "3dsx", len);
|
||||||
|
@ -193,6 +202,9 @@ bool frontend_driver_get_salamander_basename(char *s, size_t len)
|
||||||
#elif defined(_3DS)
|
#elif defined(_3DS)
|
||||||
strlcpy(s, "retroarch.core", len);
|
strlcpy(s, "retroarch.core", len);
|
||||||
return true;
|
return true;
|
||||||
|
#elif defined(SWITCH)
|
||||||
|
strlcpy(s, "retroarch_switch.nro", len);
|
||||||
|
return true;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -121,10 +121,12 @@ extern frontend_ctx_driver_t frontend_ctx_darwin;
|
||||||
extern frontend_ctx_driver_t frontend_ctx_unix;
|
extern frontend_ctx_driver_t frontend_ctx_unix;
|
||||||
extern frontend_ctx_driver_t frontend_ctx_psp;
|
extern frontend_ctx_driver_t frontend_ctx_psp;
|
||||||
extern frontend_ctx_driver_t frontend_ctx_ctr;
|
extern frontend_ctx_driver_t frontend_ctx_ctr;
|
||||||
|
extern frontend_ctx_driver_t frontend_ctx_switch;
|
||||||
extern frontend_ctx_driver_t frontend_ctx_win32;
|
extern frontend_ctx_driver_t frontend_ctx_win32;
|
||||||
extern frontend_ctx_driver_t frontend_ctx_xenon;
|
extern frontend_ctx_driver_t frontend_ctx_xenon;
|
||||||
extern frontend_ctx_driver_t frontend_ctx_emscripten;
|
extern frontend_ctx_driver_t frontend_ctx_emscripten;
|
||||||
extern frontend_ctx_driver_t frontend_ctx_dos;
|
extern frontend_ctx_driver_t frontend_ctx_dos;
|
||||||
|
extern frontend_ctx_driver_t frontend_ctx_switch;
|
||||||
extern frontend_ctx_driver_t frontend_ctx_null;
|
extern frontend_ctx_driver_t frontend_ctx_null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -171,7 +171,7 @@ void egl_swap_buffers(void *data)
|
||||||
eglSwapBuffers(egl->dpy, egl->surf);
|
eglSwapBuffers(egl->dpy, egl->surf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void egl_set_swap_interval(egl_ctx_data_t *egl, unsigned interval)
|
void egl_set_swap_interval(egl_ctx_data_t *egl, int interval)
|
||||||
{
|
{
|
||||||
/* Can be called before initialization.
|
/* Can be called before initialization.
|
||||||
* Some contexts require that swap interval
|
* Some contexts require that swap interval
|
||||||
|
|
|
@ -58,7 +58,7 @@ typedef struct
|
||||||
EGLSurface surf;
|
EGLSurface surf;
|
||||||
EGLDisplay dpy;
|
EGLDisplay dpy;
|
||||||
EGLConfig config;
|
EGLConfig config;
|
||||||
unsigned interval;
|
int interval;
|
||||||
|
|
||||||
unsigned major;
|
unsigned major;
|
||||||
unsigned minor;
|
unsigned minor;
|
||||||
|
@ -84,7 +84,7 @@ void egl_bind_hw_render(egl_ctx_data_t *egl, bool enable);
|
||||||
|
|
||||||
void egl_swap_buffers(void *data);
|
void egl_swap_buffers(void *data);
|
||||||
|
|
||||||
void egl_set_swap_interval(egl_ctx_data_t *egl, unsigned interval);
|
void egl_set_swap_interval(egl_ctx_data_t *egl, int interval);
|
||||||
|
|
||||||
void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height);
|
void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,9 @@ typedef struct
|
||||||
/*! @brief Specifies whether rendering is synchronized with the display */
|
/*! @brief Specifies whether rendering is synchronized with the display */
|
||||||
@property (nonatomic, readwrite) bool displaySyncEnabled;
|
@property (nonatomic, readwrite) bool displaySyncEnabled;
|
||||||
|
|
||||||
|
/*! @brief captureEnabled allows previous frames to be read */
|
||||||
|
@property (nonatomic, readwrite) bool captureEnabled;
|
||||||
|
|
||||||
/*! @brief Returns the command buffer used for pre-render work,
|
/*! @brief Returns the command buffer used for pre-render work,
|
||||||
* such as mip maps and shader effects
|
* such as mip maps and shader effects
|
||||||
* */
|
* */
|
||||||
|
@ -52,7 +55,7 @@ typedef struct
|
||||||
|
|
||||||
- (Texture *)newTexture:(struct texture_image)image filter:(enum texture_filter_type)filter;
|
- (Texture *)newTexture:(struct texture_image)image filter:(enum texture_filter_type)filter;
|
||||||
- (id<MTLTexture>)newTexture:(struct texture_image)image mipmapped:(bool)mipmapped;
|
- (id<MTLTexture>)newTexture:(struct texture_image)image mipmapped:(bool)mipmapped;
|
||||||
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLBuffer>)src to:(id<MTLTexture>)dst;
|
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLTexture>)src to:(id<MTLTexture>)dst;
|
||||||
- (id<MTLRenderPipelineState>)getStockShader:(int)index blend:(bool)blend;
|
- (id<MTLRenderPipelineState>)getStockShader:(int)index blend:(bool)blend;
|
||||||
|
|
||||||
/*! @brief resets the viewport for the main render encoder to the drawable size */
|
/*! @brief resets the viewport for the main render encoder to the drawable size */
|
||||||
|
@ -70,4 +73,6 @@ typedef struct
|
||||||
/*! @brief end commits the command buffer */
|
/*! @brief end commits the command buffer */
|
||||||
- (void)end;
|
- (void)end;
|
||||||
|
|
||||||
|
- (bool)readBackBuffer:(uint8_t *)buffer;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -54,6 +54,9 @@
|
||||||
id<MTLRenderPipelineState> _states[GFX_MAX_SHADERS][2];
|
id<MTLRenderPipelineState> _states[GFX_MAX_SHADERS][2];
|
||||||
id<MTLRenderPipelineState> _clearState;
|
id<MTLRenderPipelineState> _clearState;
|
||||||
Uniforms _uniforms;
|
Uniforms _uniforms;
|
||||||
|
|
||||||
|
bool _captureEnabled;
|
||||||
|
id<MTLTexture> _backBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithDevice:(id<MTLDevice>)d
|
- (instancetype)initWithDevice:(id<MTLDevice>)d
|
||||||
|
@ -65,7 +68,9 @@
|
||||||
_inflightSemaphore = dispatch_semaphore_create(MAX_INFLIGHT);
|
_inflightSemaphore = dispatch_semaphore_create(MAX_INFLIGHT);
|
||||||
_device = d;
|
_device = d;
|
||||||
_layer = layer;
|
_layer = layer;
|
||||||
|
#if TARGET_OS_OSX
|
||||||
_layer.displaySyncEnabled = YES;
|
_layer.displaySyncEnabled = YES;
|
||||||
|
#endif
|
||||||
_library = l;
|
_library = l;
|
||||||
_commandQueue = [_device newCommandQueue];
|
_commandQueue = [_device newCommandQueue];
|
||||||
_clearColor = MTLClearColorMake(0, 0, 0, 1);
|
_clearColor = MTLClearColorMake(0, 0, 0, 1);
|
||||||
|
@ -127,7 +132,16 @@
|
||||||
|
|
||||||
- (void)setDisplaySyncEnabled:(bool)displaySyncEnabled
|
- (void)setDisplaySyncEnabled:(bool)displaySyncEnabled
|
||||||
{
|
{
|
||||||
|
#if TARGET_OS_OSX
|
||||||
_layer.displaySyncEnabled = displaySyncEnabled;
|
_layer.displaySyncEnabled = displaySyncEnabled;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (bool)displaySyncEnabled
|
||||||
|
{
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
return _layer.displaySyncEnabled;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - shaders
|
#pragma mark - shaders
|
||||||
|
@ -154,11 +168,6 @@
|
||||||
return _states[index][blend ? 1 : 0];
|
return _states[index][blend ? 1 : 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (bool)displaySyncEnabled
|
|
||||||
{
|
|
||||||
return _layer.displaySyncEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MTLVertexDescriptor *)_spriteVertexDescriptor
|
- (MTLVertexDescriptor *)_spriteVertexDescriptor
|
||||||
{
|
{
|
||||||
MTLVertexDescriptor *vd = [MTLVertexDescriptor new];
|
MTLVertexDescriptor *vd = [MTLVertexDescriptor new];
|
||||||
|
@ -376,7 +385,7 @@
|
||||||
{
|
{
|
||||||
assert(filter >= TEXTURE_FILTER_LINEAR && filter <= TEXTURE_FILTER_MIPMAP_NEAREST);
|
assert(filter >= TEXTURE_FILTER_LINEAR && filter <= TEXTURE_FILTER_MIPMAP_NEAREST);
|
||||||
|
|
||||||
if (!image.pixels && !image.width && !image.height)
|
if (!image.pixels || !image.width || !image.height)
|
||||||
{
|
{
|
||||||
/* Create a dummy texture instead. */
|
/* Create a dummy texture instead. */
|
||||||
#define T0 0xff000000u
|
#define T0 0xff000000u
|
||||||
|
@ -397,6 +406,7 @@
|
||||||
image.pixels = (uint32_t *)checkerboard;
|
image.pixels = (uint32_t *)checkerboard;
|
||||||
image.width = 8;
|
image.width = 8;
|
||||||
image.height = 8;
|
image.height = 8;
|
||||||
|
filter = TEXTURE_FILTER_MIPMAP_NEAREST;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL mipmapped = filter == TEXTURE_FILTER_MIPMAP_LINEAR || filter == TEXTURE_FILTER_MIPMAP_NEAREST;
|
BOOL mipmapped = filter == TEXTURE_FILTER_MIPMAP_LINEAR || filter == TEXTURE_FILTER_MIPMAP_NEAREST;
|
||||||
|
@ -441,13 +451,13 @@
|
||||||
return _drawable;
|
return _drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLBuffer>)src to:(id<MTLTexture>)dst
|
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLTexture>)src to:(id<MTLTexture>)dst
|
||||||
{
|
{
|
||||||
assert(dst.width * dst.height == src.length / RPixelFormatToBPP(fmt));
|
assert(src.width == dst.width && src.height == dst.height);
|
||||||
assert(fmt >= 0 && fmt < RPixelFormatCount);
|
assert(fmt >= 0 && fmt < RPixelFormatCount);
|
||||||
Filter *conv = _filters[fmt];
|
Filter *conv = _filters[fmt];
|
||||||
assert(conv != nil);
|
assert(conv != nil);
|
||||||
[conv apply:self.blitCommandBuffer inBuf:src outTex:dst];
|
[conv apply:self.blitCommandBuffer in:src out:dst];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<MTLCommandBuffer>)blitCommandBuffer
|
- (id<MTLCommandBuffer>)blitCommandBuffer
|
||||||
|
@ -463,11 +473,65 @@
|
||||||
[_chain[_currentChain] discard];
|
[_chain[_currentChain] discard];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setCaptureEnabled:(bool)captureEnabled
|
||||||
|
{
|
||||||
|
if (_captureEnabled == captureEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_captureEnabled = captureEnabled;
|
||||||
|
//_layer.framebufferOnly = !captureEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (bool)captureEnabled
|
||||||
|
{
|
||||||
|
return _captureEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (bool)readBackBuffer:(uint8_t *)buffer
|
||||||
|
{
|
||||||
|
if (!_captureEnabled || _backBuffer == nil)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if (_backBuffer.pixelFormat != MTLPixelFormatBGRA8Unorm)
|
||||||
|
{
|
||||||
|
RARCH_WARN("[Metal]: unexpected pixel format %d\n", _backBuffer.pixelFormat);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *tmp = malloc(_backBuffer.width * _backBuffer.height * 4);
|
||||||
|
|
||||||
|
[_backBuffer getBytes:tmp
|
||||||
|
bytesPerRow:4 * _backBuffer.width
|
||||||
|
fromRegion:MTLRegionMake2D(0, 0, _backBuffer.width, _backBuffer.height)
|
||||||
|
mipmapLevel:0];
|
||||||
|
|
||||||
|
NSUInteger srcStride = _backBuffer.width * 4;
|
||||||
|
uint8_t const *src = tmp + (_viewport.y * srcStride);
|
||||||
|
|
||||||
|
NSUInteger dstStride = _viewport.width * 3;
|
||||||
|
uint8_t *dst = buffer + (_viewport.height - 1) * dstStride;
|
||||||
|
|
||||||
|
for (int y = _viewport.y; y < _viewport.height; y++, src += srcStride, dst -= dstStride)
|
||||||
|
{
|
||||||
|
for (int x = _viewport.x; x < _viewport.width; x++)
|
||||||
|
{
|
||||||
|
dst[3 * x + 0] = src[4 * x + 0];
|
||||||
|
dst[3 * x + 1] = src[4 * x + 1];
|
||||||
|
dst[3 * x + 2] = src[4 * x + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)begin
|
- (void)begin
|
||||||
{
|
{
|
||||||
assert(_commandBuffer == nil);
|
assert(_commandBuffer == nil);
|
||||||
dispatch_semaphore_wait(_inflightSemaphore, DISPATCH_TIME_FOREVER);
|
dispatch_semaphore_wait(_inflightSemaphore, DISPATCH_TIME_FOREVER);
|
||||||
_commandBuffer = [_commandQueue commandBuffer];
|
_commandBuffer = [_commandQueue commandBuffer];
|
||||||
|
_backBuffer = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<MTLRenderCommandEncoder>)rce
|
- (id<MTLRenderCommandEncoder>)rce
|
||||||
|
@ -479,6 +543,10 @@
|
||||||
rpd.colorAttachments[0].clearColor = _clearColor;
|
rpd.colorAttachments[0].clearColor = _clearColor;
|
||||||
rpd.colorAttachments[0].loadAction = MTLLoadActionClear;
|
rpd.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||||
rpd.colorAttachments[0].texture = self.nextDrawable.texture;
|
rpd.colorAttachments[0].texture = self.nextDrawable.texture;
|
||||||
|
if (_captureEnabled)
|
||||||
|
{
|
||||||
|
_backBuffer = self.nextDrawable.texture;
|
||||||
|
}
|
||||||
_rce = [_commandBuffer renderCommandEncoderWithDescriptor:rpd];
|
_rce = [_commandBuffer renderCommandEncoderWithDescriptor:rpd];
|
||||||
}
|
}
|
||||||
return _rce;
|
return _rce;
|
||||||
|
@ -615,6 +683,7 @@ static const NSUInteger kConstantAlignment = 4;
|
||||||
|
|
||||||
- (void)commitRanges
|
- (void)commitRanges
|
||||||
{
|
{
|
||||||
|
#if TARGET_OS_OSX
|
||||||
for (BufferNode *n = _head; n != nil; n = n.next)
|
for (BufferNode *n = _head; n != nil; n = n.next)
|
||||||
{
|
{
|
||||||
if (n.allocated > 0)
|
if (n.allocated > 0)
|
||||||
|
@ -622,6 +691,7 @@ static const NSUInteger kConstantAlignment = 4;
|
||||||
[n.src didModifyRange:NSMakeRange(0, n.allocated)];
|
[n.src didModifyRange:NSMakeRange(0, n.allocated)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)discard
|
- (void)discard
|
||||||
|
@ -635,9 +705,15 @@ static const NSUInteger kConstantAlignment = 4;
|
||||||
{
|
{
|
||||||
bzero(range, sizeof(*range));
|
bzero(range, sizeof(*range));
|
||||||
|
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
MTLResourceOptions opts = MTLResourceStorageModeManaged;
|
||||||
|
#else
|
||||||
|
MTLResourceOptions opts = MTLResourceStorageModeShared;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!_head)
|
if (!_head)
|
||||||
{
|
{
|
||||||
_head = [[BufferNode alloc] initWithBuffer:[_device newBufferWithLength:_blockLen options:MTLResourceStorageModeManaged]];
|
_head = [[BufferNode alloc] initWithBuffer:[_device newBufferWithLength:_blockLen options:opts]];
|
||||||
_length += _blockLen;
|
_length += _blockLen;
|
||||||
_current = _head;
|
_current = _head;
|
||||||
_offset = 0;
|
_offset = 0;
|
||||||
|
@ -659,7 +735,7 @@ static const NSUInteger kConstantAlignment = 4;
|
||||||
blockLen = length;
|
blockLen = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
_current.next = [[BufferNode alloc] initWithBuffer:[_device newBufferWithLength:blockLen options:MTLResourceStorageModeManaged]];
|
_current.next = [[BufferNode alloc] initWithBuffer:[_device newBufferWithLength:blockLen options:opts]];
|
||||||
if (!_current.next)
|
if (!_current.next)
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,12 @@ typedef struct
|
||||||
vector_float2 texCoord METAL_ATTRIBUTE(VertexAttributeTexcoord);
|
vector_float2 texCoord METAL_ATTRIBUTE(VertexAttributeTexcoord);
|
||||||
} Vertex;
|
} Vertex;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
vector_float4 position;
|
||||||
|
vector_float2 texCoord;
|
||||||
|
} VertexSlang;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vector_float4 position METAL_POSITION;
|
vector_float4 position METAL_POSITION;
|
||||||
|
|
|
@ -81,38 +81,32 @@ fragment half4 stock_fragment_color(FontFragmentIn in [[ stage_in ]])
|
||||||
|
|
||||||
#pragma mark - filter kernels
|
#pragma mark - filter kernels
|
||||||
|
|
||||||
kernel void convert_bgra4444_to_bgra8888(device uint16_t * in [[ buffer(0) ]],
|
kernel void convert_bgra4444_to_bgra8888(texture2d<ushort, access::read> in [[ texture(0) ]],
|
||||||
texture2d<half, access::write> out [[ texture(0) ]],
|
texture2d<half, access::write> out [[ texture(1) ]],
|
||||||
uint id [[ thread_position_in_grid ]])
|
uint2 gid [[ thread_position_in_grid ]])
|
||||||
{
|
{
|
||||||
uint16_t pix = in[id];
|
ushort pix = in.read(gid).r;
|
||||||
uchar4 pix2 = uchar4(
|
uchar4 pix2 = uchar4(
|
||||||
extract_bits(pix, 4, 4),
|
extract_bits(pix, 4, 4),
|
||||||
extract_bits(pix, 8, 4),
|
extract_bits(pix, 8, 4),
|
||||||
extract_bits(pix, 12, 4),
|
extract_bits(pix, 12, 4),
|
||||||
extract_bits(pix, 0, 4)
|
extract_bits(pix, 0, 4)
|
||||||
);
|
);
|
||||||
|
|
||||||
uint ypos = id / out.get_width();
|
out.write(half4(pix2) / 15.0, gid);
|
||||||
uint xpos = id % out.get_width();
|
|
||||||
|
|
||||||
out.write(half4(pix2) / 15.0, uint2(xpos, ypos));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel void convert_rgb565_to_bgra8888(device uint16_t * in [[ buffer(0) ]],
|
kernel void convert_rgb565_to_bgra8888(texture2d<ushort, access::read> in [[ texture(0) ]],
|
||||||
texture2d<half, access::write> out [[ texture(0) ]],
|
texture2d<half, access::write> out [[ texture(1) ]],
|
||||||
uint id [[ thread_position_in_grid ]])
|
uint2 gid [[ thread_position_in_grid ]])
|
||||||
{
|
{
|
||||||
uint16_t pix = in[id];
|
ushort pix = in.read(gid).r;
|
||||||
uchar4 pix2 = uchar4(
|
uchar4 pix2 = uchar4(
|
||||||
extract_bits(pix, 11, 5),
|
extract_bits(pix, 11, 5),
|
||||||
extract_bits(pix, 5, 6),
|
extract_bits(pix, 5, 6),
|
||||||
extract_bits(pix, 0, 5),
|
extract_bits(pix, 0, 5),
|
||||||
0xf
|
0xf
|
||||||
);
|
);
|
||||||
|
|
||||||
uint ypos = id / out.get_width();
|
out.write(half4(pix2) / half4(0x1f, 0x3f, 0x1f, 0xf), gid);
|
||||||
uint xpos = id % out.get_width();
|
|
||||||
|
|
||||||
out.write(half4(pix2) / half4(0x1f, 0x3f, 0x1f, 0xf), uint2(xpos, ypos));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
CGRect _frame;
|
CGRect _frame;
|
||||||
NSUInteger _bpp;
|
NSUInteger _bpp;
|
||||||
|
|
||||||
id<MTLBuffer> _pixels; // frame buffer in _srcFmt
|
id<MTLTexture> _src; // source texture
|
||||||
bool _pixelsDirty;
|
bool _srcDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithDescriptor:(ViewDescriptor *)d context:(Context *)c
|
- (instancetype)initWithDescriptor:(ViewDescriptor *)d context:(Context *)c
|
||||||
|
@ -53,7 +53,6 @@
|
||||||
|
|
||||||
_size = size;
|
_size = size;
|
||||||
|
|
||||||
// create new texture
|
|
||||||
{
|
{
|
||||||
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
||||||
width:(NSUInteger)size.width
|
width:(NSUInteger)size.width
|
||||||
|
@ -65,8 +64,11 @@
|
||||||
|
|
||||||
if (_format != RPixelFormatBGRA8Unorm && _format != RPixelFormatBGRX8Unorm)
|
if (_format != RPixelFormatBGRA8Unorm && _format != RPixelFormatBGRX8Unorm)
|
||||||
{
|
{
|
||||||
_pixels = [_context.device newBufferWithLength:(NSUInteger)(size.width * size.height * 2)
|
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR16Uint
|
||||||
options:MTLResourceStorageModeManaged];
|
width:(NSUInteger)size.width
|
||||||
|
height:(NSUInteger)size.height
|
||||||
|
mipmapped:NO];
|
||||||
|
_src = [_context.device newTextureWithDescriptor:td];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,11 +114,11 @@
|
||||||
if (_format == RPixelFormatBGRA8Unorm || _format == RPixelFormatBGRX8Unorm)
|
if (_format == RPixelFormatBGRA8Unorm || _format == RPixelFormatBGRX8Unorm)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_pixelsDirty)
|
if (!_srcDirty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_context convertFormat:_format from:_pixels to:_texture];
|
[_context convertFormat:_format from:_src to:_texture];
|
||||||
_pixelsDirty = NO;
|
_srcDirty = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawWithContext:(Context *)ctx
|
- (void)drawWithContext:(Context *)ctx
|
||||||
|
@ -141,26 +143,10 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
void *dst = _pixels.contents;
|
[_src replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)_size.width, (NSUInteger)_size.height)
|
||||||
size_t len = (size_t)(_bpp * _size.width);
|
mipmapLevel:0 withBytes:src
|
||||||
assert(len <= pitch); // the length can't be larger?
|
bytesPerRow:(NSUInteger)(pitch)];
|
||||||
|
_srcDirty = YES;
|
||||||
if (len < pitch)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _size.height; i++)
|
|
||||||
{
|
|
||||||
memcpy(dst, src, len);
|
|
||||||
dst += len;
|
|
||||||
src += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(dst, src, _pixels.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
[_pixels didModifyRange:NSMakeRange(0, _pixels.length)];
|
|
||||||
_pixelsDirty = YES;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
|
||||||
- (void)setFilteringIndex:(int)index smooth:(bool)smooth;
|
- (void)setFilteringIndex:(int)index smooth:(bool)smooth;
|
||||||
- (BOOL)setShaderFromPath:(NSString *)path;
|
- (BOOL)setShaderFromPath:(NSString *)path;
|
||||||
- (void)updateFrame:(void const *)src pitch:(NSUInteger)pitch;
|
- (void)updateFrame:(void const *)src pitch:(NSUInteger)pitch;
|
||||||
|
- (bool)readViewport:(uint8_t *)buffer isIdle:(bool)isIdle;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -299,30 +299,29 @@
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
if (settings && settings->bools.video_msg_bgcolor_enable)
|
if (settings && settings->bools.video_msg_bgcolor_enable)
|
||||||
{
|
{
|
||||||
int msg_width =
|
int msg_width =
|
||||||
font_driver_get_message_width(NULL, msg, (unsigned)strlen(msg), 1.0f);
|
font_driver_get_message_width(NULL, msg, (unsigned)strlen(msg), 1.0f);
|
||||||
|
|
||||||
float x = video_info->font_msg_pos_x;
|
float x = video_info->font_msg_pos_x;
|
||||||
float y = 1.0f - video_info->font_msg_pos_y;
|
float y = 1.0f - video_info->font_msg_pos_y;
|
||||||
float width = msg_width / (float)_viewport->full_width;
|
float width = msg_width / (float)_viewport->full_width;
|
||||||
float height =
|
float height =
|
||||||
settings->floats.video_font_size / (float)_viewport->full_height;
|
settings->floats.video_font_size / (float)_viewport->full_height;
|
||||||
|
|
||||||
y -= height;
|
y -= height;
|
||||||
|
|
||||||
|
float x2 = 0.005f; /* extend background around text */
|
||||||
|
float y2 = 0.005f;
|
||||||
|
|
||||||
float x2 = 0.005f; /* extend background around text */
|
x -= x2;
|
||||||
float y2 = 0.005f;
|
y -= y2;
|
||||||
|
width += x2;
|
||||||
|
height += y2;
|
||||||
|
|
||||||
x -= x2;
|
float r = settings->uints.video_msg_bgcolor_red / 255.0f;
|
||||||
y -= y2;
|
float g = settings->uints.video_msg_bgcolor_green / 255.0f;
|
||||||
width += x2;
|
float b = settings->uints.video_msg_bgcolor_blue / 255.0f;
|
||||||
height += y2;
|
float a = settings->floats.video_msg_bgcolor_opacity;
|
||||||
|
|
||||||
float r = settings->uints.video_msg_bgcolor_red / 255.0f;
|
|
||||||
float g = settings->uints.video_msg_bgcolor_green / 255.0f;
|
|
||||||
float b = settings->uints.video_msg_bgcolor_blue / 255.0f;
|
|
||||||
float a = settings->floats.video_msg_bgcolor_opacity;
|
|
||||||
[_context resetRenderViewport];
|
[_context resetRenderViewport];
|
||||||
[_context drawQuadX:x y:y w:width h:height r:r g:g b:b a:a];
|
[_context drawQuadX:x y:y w:width h:height r:r g:g b:b a:a];
|
||||||
}
|
}
|
||||||
|
@ -332,7 +331,12 @@
|
||||||
|
|
||||||
- (void)_beginFrame
|
- (void)_beginFrame
|
||||||
{
|
{
|
||||||
|
video_viewport_t vp = *_viewport;
|
||||||
video_driver_update_viewport(_viewport, NO, _keepAspect);
|
video_driver_update_viewport(_viewport, NO, _keepAspect);
|
||||||
|
if (memcmp(&vp, _viewport, sizeof(vp)) != 0)
|
||||||
|
{
|
||||||
|
_context.viewport = _viewport;
|
||||||
|
}
|
||||||
[_context begin];
|
[_context begin];
|
||||||
[self _updateUniforms];
|
[self _updateUniforms];
|
||||||
}
|
}
|
||||||
|
@ -542,12 +546,13 @@ typedef struct MTLALIGN(16)
|
||||||
Context *_context;
|
Context *_context;
|
||||||
id<MTLTexture> _texture; // final render texture
|
id<MTLTexture> _texture; // final render texture
|
||||||
Vertex _v[4];
|
Vertex _v[4];
|
||||||
|
VertexSlang _vertex[4];
|
||||||
CGSize _size; // size of view in pixels
|
CGSize _size; // size of view in pixels
|
||||||
CGRect _frame;
|
CGRect _frame;
|
||||||
NSUInteger _bpp;
|
NSUInteger _bpp;
|
||||||
|
|
||||||
id<MTLBuffer> _pixels; // frame buffer in _srcFmt
|
id<MTLTexture> _src; // src texture
|
||||||
bool _pixelsDirty;
|
bool _srcDirty;
|
||||||
|
|
||||||
id<MTLSamplerState> _samplers[RARCH_FILTER_MAX][RARCH_WRAP_MAX];
|
id<MTLSamplerState> _samplers[RARCH_FILTER_MAX][RARCH_WRAP_MAX];
|
||||||
struct video_shader *_shader;
|
struct video_shader *_shader;
|
||||||
|
@ -583,6 +588,15 @@ typedef struct MTLALIGN(16)
|
||||||
self.size = d.size;
|
self.size = d.size;
|
||||||
self.frame = CGRectMake(0, 0, 1, 1);
|
self.frame = CGRectMake(0, 0, 1, 1);
|
||||||
resize_render_targets = YES;
|
resize_render_targets = YES;
|
||||||
|
|
||||||
|
// init slang vertex buffer
|
||||||
|
VertexSlang v[4] = {
|
||||||
|
{simd_make_float4(0, 1, 0, 1), simd_make_float2(0, 1)},
|
||||||
|
{simd_make_float4(1, 1, 0, 1), simd_make_float2(1, 1)},
|
||||||
|
{simd_make_float4(0, 0, 0, 1), simd_make_float2(0, 0)},
|
||||||
|
{simd_make_float4(1, 0, 0, 1), simd_make_float2(1, 0)},
|
||||||
|
};
|
||||||
|
memcpy(_vertex, v, sizeof(_vertex));
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -655,8 +669,11 @@ typedef struct MTLALIGN(16)
|
||||||
|
|
||||||
if (_format != RPixelFormatBGRA8Unorm && _format != RPixelFormatBGRX8Unorm)
|
if (_format != RPixelFormatBGRA8Unorm && _format != RPixelFormatBGRX8Unorm)
|
||||||
{
|
{
|
||||||
_pixels = [_context.device newBufferWithLength:(NSUInteger)(size.width * size.height * 2)
|
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR16Uint
|
||||||
options:MTLResourceStorageModeManaged];
|
width:(NSUInteger)size.width
|
||||||
|
height:(NSUInteger)size.height
|
||||||
|
mipmapped:NO];
|
||||||
|
_src = [_context.device newTextureWithDescriptor:td];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,11 +719,11 @@ typedef struct MTLALIGN(16)
|
||||||
if (_format == RPixelFormatBGRA8Unorm || _format == RPixelFormatBGRX8Unorm)
|
if (_format == RPixelFormatBGRA8Unorm || _format == RPixelFormatBGRX8Unorm)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_pixelsDirty)
|
if (!_srcDirty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_context convertFormat:_format from:_pixels to:_texture];
|
[_context convertFormat:_format from:_src to:_texture];
|
||||||
_pixelsDirty = NO;
|
_srcDirty = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updateHistory
|
- (void)_updateHistory
|
||||||
|
@ -743,6 +760,24 @@ typedef struct MTLALIGN(16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (bool)readViewport:(uint8_t *)buffer isIdle:(bool)isIdle
|
||||||
|
{
|
||||||
|
RARCH_LOG("[Metal]: readViewport is_idle = %s\n", isIdle ? "YES" : "NO");
|
||||||
|
|
||||||
|
bool enabled = _context.captureEnabled;
|
||||||
|
if (!enabled)
|
||||||
|
_context.captureEnabled = YES;
|
||||||
|
|
||||||
|
video_driver_cached_frame();
|
||||||
|
|
||||||
|
bool res = [_context readBackBuffer:buffer];
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
_context.captureEnabled = NO;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)updateFrame:(void const *)src pitch:(NSUInteger)pitch
|
- (void)updateFrame:(void const *)src pitch:(NSUInteger)pitch
|
||||||
{
|
{
|
||||||
if (_shader && (_engine.frame.output_size.x != _viewport->width ||
|
if (_shader && (_engine.frame.output_size.x != _viewport->width ||
|
||||||
|
@ -778,26 +813,10 @@ typedef struct MTLALIGN(16)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
void *dst = _pixels.contents;
|
[_src replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)_size.width, (NSUInteger)_size.height)
|
||||||
size_t len = (size_t)(_bpp * _size.width);
|
mipmapLevel:0 withBytes:src
|
||||||
assert(len <= pitch); // the length can't be larger?
|
bytesPerRow:(NSUInteger)(pitch)];
|
||||||
|
_srcDirty = YES;
|
||||||
if (len < pitch)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _size.height; i++)
|
|
||||||
{
|
|
||||||
memcpy(dst, src, len);
|
|
||||||
dst += len;
|
|
||||||
src += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(dst, src, _pixels.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
[_pixels didModifyRange:NSMakeRange(0, _pixels.length)];
|
|
||||||
_pixelsDirty = YES;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,19 +844,6 @@ typedef struct MTLALIGN(16)
|
||||||
init_history = NO;
|
init_history = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct vertex
|
|
||||||
{
|
|
||||||
simd_float4 pos;
|
|
||||||
simd_float2 tex;
|
|
||||||
} vertex_t;
|
|
||||||
|
|
||||||
static vertex_t vertex_bytes[] = {
|
|
||||||
{{0, 1, 0, 1}, {0, 1}},
|
|
||||||
{{1, 1, 0, 1}, {1, 1}},
|
|
||||||
{{0, 0, 0, 1}, {0, 0}},
|
|
||||||
{{1, 0, 0, 1}, {1, 0}},
|
|
||||||
};
|
|
||||||
|
|
||||||
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce
|
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce
|
||||||
{
|
{
|
||||||
if (_texture)
|
if (_texture)
|
||||||
|
@ -951,7 +957,7 @@ static vertex_t vertex_bytes[] = {
|
||||||
|
|
||||||
[rce setFragmentTextures:textures withRange:NSMakeRange(0, SLANG_NUM_BINDINGS)];
|
[rce setFragmentTextures:textures withRange:NSMakeRange(0, SLANG_NUM_BINDINGS)];
|
||||||
[rce setFragmentSamplerStates:samplers withRange:NSMakeRange(0, SLANG_NUM_BINDINGS)];
|
[rce setFragmentSamplerStates:samplers withRange:NSMakeRange(0, SLANG_NUM_BINDINGS)];
|
||||||
[rce setVertexBytes:vertex_bytes length:sizeof(vertex_bytes) atIndex:4];
|
[rce setVertexBytes:_vertex length:sizeof(_vertex) atIndex:4];
|
||||||
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||||
|
|
||||||
if (!backBuffer)
|
if (!backBuffer)
|
||||||
|
@ -1171,13 +1177,13 @@ static vertex_t vertex_bytes[] = {
|
||||||
@try
|
@try
|
||||||
{
|
{
|
||||||
MTLVertexDescriptor *vd = [MTLVertexDescriptor new];
|
MTLVertexDescriptor *vd = [MTLVertexDescriptor new];
|
||||||
vd.attributes[0].offset = offsetof(vertex_t, pos);
|
vd.attributes[0].offset = offsetof(VertexSlang, position);
|
||||||
vd.attributes[0].format = MTLVertexFormatFloat4;
|
vd.attributes[0].format = MTLVertexFormatFloat4;
|
||||||
vd.attributes[0].bufferIndex = 4;
|
vd.attributes[0].bufferIndex = 4;
|
||||||
vd.attributes[1].offset = offsetof(vertex_t, tex);
|
vd.attributes[1].offset = offsetof(VertexSlang, texCoord);
|
||||||
vd.attributes[1].format = MTLVertexFormatFloat2;
|
vd.attributes[1].format = MTLVertexFormatFloat2;
|
||||||
vd.attributes[1].bufferIndex = 4;
|
vd.attributes[1].bufferIndex = 4;
|
||||||
vd.layouts[4].stride = sizeof(vertex_t);
|
vd.layouts[4].stride = sizeof(VertexSlang);
|
||||||
vd.layouts[4].stepFunction = MTLVertexStepFunctionPerVertex;
|
vd.layouts[4].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||||
|
|
||||||
MTLRenderPipelineDescriptor *psd = [MTLRenderPipelineDescriptor new];
|
MTLRenderPipelineDescriptor *psd = [MTLRenderPipelineDescriptor new];
|
||||||
|
@ -1204,7 +1210,7 @@ static vertex_t vertex_bytes[] = {
|
||||||
if (lib == nil)
|
if (lib == nil)
|
||||||
{
|
{
|
||||||
save_msl = true;
|
save_msl = true;
|
||||||
RARCH_ERR("Metal]: unable to compile vertex shader: %s\n", err.localizedDescription.UTF8String);
|
RARCH_ERR("[Metal]: unable to compile vertex shader: %s\n", err.localizedDescription.UTF8String);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -1220,7 +1226,7 @@ static vertex_t vertex_bytes[] = {
|
||||||
if (lib == nil)
|
if (lib == nil)
|
||||||
{
|
{
|
||||||
save_msl = true;
|
save_msl = true;
|
||||||
RARCH_ERR("Metal]: unable to compile fragment shader: %s\n", err.localizedDescription.UTF8String);
|
RARCH_ERR("[Metal]: unable to compile fragment shader: %s\n", err.localizedDescription.UTF8String);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -1234,7 +1240,8 @@ static vertex_t vertex_bytes[] = {
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
save_msl = true;
|
save_msl = true;
|
||||||
RARCH_ERR("error creating pipeline state: %s", err.localizedDescription.UTF8String);
|
RARCH_ERR("[Metal]: error creating pipeline state for pass %d: %s\n", i,
|
||||||
|
err.localizedDescription.UTF8String);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,10 +1260,11 @@ static vertex_t vertex_bytes[] = {
|
||||||
{
|
{
|
||||||
if (save_msl)
|
if (save_msl)
|
||||||
{
|
{
|
||||||
RARCH_LOG("[Metal]: saving metal shader files\n");
|
NSString *basePath = [[NSString stringWithUTF8String:shader->pass[i].source.path] stringByDeletingPathExtension];
|
||||||
|
|
||||||
|
RARCH_LOG("[Metal]: saving metal shader files to %s\n", basePath.UTF8String);
|
||||||
|
|
||||||
NSError *err = nil;
|
NSError *err = nil;
|
||||||
NSString *basePath = [[NSString stringWithUTF8String:shader->pass[i].source.path] stringByDeletingPathExtension];
|
|
||||||
[vs_src writeToFile:[basePath stringByAppendingPathExtension:@"vs.metal"]
|
[vs_src writeToFile:[basePath stringByAppendingPathExtension:@"vs.metal"]
|
||||||
atomically:NO
|
atomically:NO
|
||||||
encoding:NSStringEncodingConversionAllowLossy
|
encoding:NSStringEncodingConversionAllowLossy
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
#ifndef SWITCH_COMMON_H__
|
||||||
|
#define SWITCH_COMMON_H__
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include <gfx/scaler/scaler.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
#include "../common/egl_common.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool vsync;
|
||||||
|
bool rgb32;
|
||||||
|
bool smooth; // bilinear
|
||||||
|
unsigned width, height;
|
||||||
|
unsigned rotation;
|
||||||
|
struct video_viewport vp;
|
||||||
|
struct texture_image *overlay;
|
||||||
|
bool overlay_enabled;
|
||||||
|
bool in_menu;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
bool enable;
|
||||||
|
bool fullscreen;
|
||||||
|
|
||||||
|
uint32_t *pixels;
|
||||||
|
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
unsigned tgtw;
|
||||||
|
unsigned tgth;
|
||||||
|
|
||||||
|
struct scaler_ctx scaler;
|
||||||
|
} menu_texture;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint32_t x_offset;
|
||||||
|
} hw_scale;
|
||||||
|
|
||||||
|
uint32_t image[1280 * 720];
|
||||||
|
uint32_t tmp_image[1280 * 720];
|
||||||
|
u32 cnt;
|
||||||
|
struct scaler_ctx scaler;
|
||||||
|
uint32_t last_width;
|
||||||
|
uint32_t last_height;
|
||||||
|
bool keep_aspect;
|
||||||
|
bool should_resize;
|
||||||
|
bool need_clear;
|
||||||
|
bool is_threaded;
|
||||||
|
|
||||||
|
bool o_size;
|
||||||
|
uint32_t o_height;
|
||||||
|
uint32_t o_width;
|
||||||
|
} switch_video_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
egl_ctx_data_t egl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned short width;
|
||||||
|
unsigned short height;
|
||||||
|
} native_window;
|
||||||
|
bool resize;
|
||||||
|
unsigned width, height;
|
||||||
|
float refresh_rate;
|
||||||
|
} switch_ctx_data_t;
|
||||||
|
|
||||||
|
void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend);
|
||||||
|
|
||||||
|
#endif
|
|
@ -38,6 +38,14 @@
|
||||||
#include "../../libretro-common/include/retro_math.h"
|
#include "../../libretro-common/include/retro_math.h"
|
||||||
#include "../../libretro-common/include/string/stdstring.h"
|
#include "../../libretro-common/include/string/stdstring.h"
|
||||||
|
|
||||||
|
#define VENDOR_ID_AMD 0x1002
|
||||||
|
#define VENDOR_ID_NV 0x10DE
|
||||||
|
#define VENDOR_ID_INTEL 0x8086
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define VULKAN_EMULATE_MAILBOX
|
||||||
|
#endif
|
||||||
|
|
||||||
static dylib_t vulkan_library;
|
static dylib_t vulkan_library;
|
||||||
static VkInstance cached_instance_vk;
|
static VkInstance cached_instance_vk;
|
||||||
static VkDevice cached_device_vk;
|
static VkDevice cached_device_vk;
|
||||||
|
@ -88,6 +96,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_cb(
|
||||||
RARCH_ERR("[Vulkan]: Error: %s: %s\n",
|
RARCH_ERR("[Vulkan]: Error: %s: %s\n",
|
||||||
pLayerPrefix, pMessage);
|
pLayerPrefix, pMessage);
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
|
else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
|
||||||
{
|
{
|
||||||
RARCH_WARN("[Vulkan]: Warning: %s: %s\n",
|
RARCH_WARN("[Vulkan]: Warning: %s: %s\n",
|
||||||
|
@ -103,11 +112,157 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_cb(
|
||||||
RARCH_LOG("[Vulkan]: Information: %s: %s\n",
|
RARCH_LOG("[Vulkan]: Information: %s: %s\n",
|
||||||
pLayerPrefix, pMessage);
|
pLayerPrefix, pMessage);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void vulkan_emulated_mailbox_deinit(struct vulkan_emulated_mailbox *mailbox)
|
||||||
|
{
|
||||||
|
if (mailbox->thread)
|
||||||
|
{
|
||||||
|
slock_lock(mailbox->lock);
|
||||||
|
mailbox->dead = true;
|
||||||
|
scond_signal(mailbox->cond);
|
||||||
|
slock_unlock(mailbox->lock);
|
||||||
|
sthread_join(mailbox->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mailbox->lock)
|
||||||
|
slock_free(mailbox->lock);
|
||||||
|
if (mailbox->cond)
|
||||||
|
scond_free(mailbox->cond);
|
||||||
|
|
||||||
|
memset(mailbox, 0, sizeof(*mailbox));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult vulkan_emulated_mailbox_acquire_next_image(struct vulkan_emulated_mailbox *mailbox,
|
||||||
|
unsigned *index)
|
||||||
|
{
|
||||||
|
VkResult res;
|
||||||
|
if (mailbox->swapchain == VK_NULL_HANDLE)
|
||||||
|
return VK_ERROR_OUT_OF_DATE_KHR;
|
||||||
|
|
||||||
|
slock_lock(mailbox->lock);
|
||||||
|
|
||||||
|
if (!mailbox->has_pending_request)
|
||||||
|
{
|
||||||
|
mailbox->request_acquire = true;
|
||||||
|
scond_signal(mailbox->cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
mailbox->has_pending_request = true;
|
||||||
|
|
||||||
|
if (mailbox->acquired)
|
||||||
|
{
|
||||||
|
res = mailbox->result;
|
||||||
|
*index = mailbox->index;
|
||||||
|
mailbox->has_pending_request = false;
|
||||||
|
mailbox->acquired = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
res = VK_TIMEOUT;
|
||||||
|
|
||||||
|
slock_unlock(mailbox->lock);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult vulkan_emulated_mailbox_acquire_next_image_blocking(
|
||||||
|
struct vulkan_emulated_mailbox *mailbox,
|
||||||
|
unsigned *index)
|
||||||
|
{
|
||||||
|
VkResult res;
|
||||||
|
if (mailbox->swapchain == VK_NULL_HANDLE)
|
||||||
|
return VK_ERROR_OUT_OF_DATE_KHR;
|
||||||
|
|
||||||
|
slock_lock(mailbox->lock);
|
||||||
|
|
||||||
|
if (!mailbox->has_pending_request)
|
||||||
|
{
|
||||||
|
mailbox->request_acquire = true;
|
||||||
|
scond_signal(mailbox->cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
mailbox->has_pending_request = true;
|
||||||
|
|
||||||
|
while (!mailbox->acquired)
|
||||||
|
scond_wait(mailbox->cond, mailbox->lock);
|
||||||
|
|
||||||
|
res = mailbox->result;
|
||||||
|
if (res == VK_SUCCESS)
|
||||||
|
*index = mailbox->index;
|
||||||
|
mailbox->has_pending_request = false;
|
||||||
|
mailbox->acquired = false;
|
||||||
|
|
||||||
|
slock_unlock(mailbox->lock);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vulkan_emulated_mailbox_loop(void *userdata)
|
||||||
|
{
|
||||||
|
VkResult res;
|
||||||
|
VkFence fence;
|
||||||
|
VkFenceCreateInfo info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||||
|
struct vulkan_emulated_mailbox *mailbox =
|
||||||
|
(struct vulkan_emulated_mailbox *)userdata;
|
||||||
|
|
||||||
|
vkCreateFence(mailbox->device, &info, NULL, &fence);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
slock_lock(mailbox->lock);
|
||||||
|
while (!mailbox->dead && !mailbox->request_acquire)
|
||||||
|
scond_wait(mailbox->cond, mailbox->lock);
|
||||||
|
|
||||||
|
if (mailbox->dead)
|
||||||
|
{
|
||||||
|
slock_unlock(mailbox->lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mailbox->request_acquire = false;
|
||||||
|
slock_unlock(mailbox->lock);
|
||||||
|
|
||||||
|
mailbox->result = vkAcquireNextImageKHR(mailbox->device, mailbox->swapchain, UINT64_MAX,
|
||||||
|
VK_NULL_HANDLE, fence, &mailbox->index);
|
||||||
|
|
||||||
|
if (mailbox->result == VK_SUCCESS)
|
||||||
|
vkWaitForFences(mailbox->device, 1, &fence, true, UINT64_MAX);
|
||||||
|
vkResetFences(mailbox->device, 1, &fence);
|
||||||
|
|
||||||
|
if (mailbox->result == VK_SUCCESS)
|
||||||
|
{
|
||||||
|
slock_lock(mailbox->lock);
|
||||||
|
mailbox->acquired = true;
|
||||||
|
scond_signal(mailbox->cond);
|
||||||
|
slock_unlock(mailbox->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyFence(mailbox->device, fence, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vulkan_emulated_mailbox_init(struct vulkan_emulated_mailbox *mailbox,
|
||||||
|
VkDevice device,
|
||||||
|
VkSwapchainKHR swapchain)
|
||||||
|
{
|
||||||
|
memset(mailbox, 0, sizeof(*mailbox));
|
||||||
|
mailbox->device = device;
|
||||||
|
mailbox->swapchain = swapchain;
|
||||||
|
|
||||||
|
mailbox->cond = scond_new();
|
||||||
|
if (!mailbox->cond)
|
||||||
|
return false;
|
||||||
|
mailbox->lock = slock_new();
|
||||||
|
if (!mailbox->lock)
|
||||||
|
return false;
|
||||||
|
mailbox->thread = sthread_create(vulkan_emulated_mailbox_loop, mailbox);
|
||||||
|
if (!mailbox->thread)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t vulkan_find_memory_type(
|
uint32_t vulkan_find_memory_type(
|
||||||
const VkPhysicalDeviceMemoryProperties *mem_props,
|
const VkPhysicalDeviceMemoryProperties *mem_props,
|
||||||
uint32_t device_reqs, uint32_t host_reqs)
|
uint32_t device_reqs, uint32_t host_reqs)
|
||||||
|
@ -184,13 +339,12 @@ void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||||
struct vk_texture *dynamic,
|
struct vk_texture *dynamic,
|
||||||
struct vk_texture *staging)
|
struct vk_texture *staging)
|
||||||
{
|
{
|
||||||
VkImageCopy region;
|
VkBufferImageCopy region;
|
||||||
|
|
||||||
retro_assert(dynamic->type == VULKAN_TEXTURE_DYNAMIC);
|
retro_assert(dynamic->type == VULKAN_TEXTURE_DYNAMIC);
|
||||||
retro_assert(staging->type == VULKAN_TEXTURE_STAGING);
|
retro_assert(staging->type == VULKAN_TEXTURE_STAGING);
|
||||||
|
|
||||||
vulkan_sync_texture_to_gpu(vk, staging);
|
vulkan_sync_texture_to_gpu(vk, staging);
|
||||||
vulkan_transition_texture(vk, cmd, staging);
|
|
||||||
|
|
||||||
/* We don't have to sync against previous TRANSFER,
|
/* We don't have to sync against previous TRANSFER,
|
||||||
* since we observed the completion by fences.
|
* since we observed the completion by fences.
|
||||||
|
@ -208,15 +362,14 @@ void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||||
|
|
||||||
memset(®ion, 0, sizeof(region));
|
memset(®ion, 0, sizeof(region));
|
||||||
region.extent.width = dynamic->width;
|
region.imageExtent.width = dynamic->width;
|
||||||
region.extent.height = dynamic->height;
|
region.imageExtent.height = dynamic->height;
|
||||||
region.extent.depth = 1;
|
region.imageExtent.depth = 1;
|
||||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.srcSubresource.layerCount = 1;
|
region.imageSubresource.layerCount = 1;
|
||||||
region.dstSubresource = region.srcSubresource;
|
|
||||||
|
|
||||||
vkCmdCopyImage(cmd,
|
vkCmdCopyBufferToImage(cmd,
|
||||||
staging->image, VK_IMAGE_LAYOUT_GENERAL,
|
staging->buffer,
|
||||||
dynamic->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
dynamic->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
1, ®ion);
|
1, ®ion);
|
||||||
|
|
||||||
|
@ -323,6 +476,7 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
VkSubresourceLayout layout;
|
VkSubresourceLayout layout;
|
||||||
VkDevice device = vk->context->device;
|
VkDevice device = vk->context->device;
|
||||||
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||||
|
VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||||
VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
||||||
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||||
VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT };
|
VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT };
|
||||||
|
@ -338,6 +492,10 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
info.extent.height = height;
|
info.extent.height = height;
|
||||||
info.extent.depth = 1;
|
info.extent.depth = 1;
|
||||||
info.arrayLayers = 1;
|
info.arrayLayers = 1;
|
||||||
|
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
buffer_info.size = width * height * vulkan_format_to_bpp(format);
|
||||||
|
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
/* For simplicity, always build mipmaps for
|
/* For simplicity, always build mipmaps for
|
||||||
* static textures, samplers can be used to enable it dynamically.
|
* static textures, samplers can be used to enable it dynamically.
|
||||||
|
@ -355,7 +513,7 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
if (type == VULKAN_TEXTURE_STREAMED)
|
if (type == VULKAN_TEXTURE_STREAMED)
|
||||||
{
|
{
|
||||||
VkFormatProperties format_properties;
|
VkFormatProperties format_properties;
|
||||||
VkFormatFeatureFlags required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
||||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
||||||
|
|
||||||
vkGetPhysicalDeviceFormatProperties(
|
vkGetPhysicalDeviceFormatProperties(
|
||||||
|
@ -396,23 +554,33 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VULKAN_TEXTURE_STAGING:
|
case VULKAN_TEXTURE_STAGING:
|
||||||
info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
info.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
info.tiling = VK_IMAGE_TILING_LINEAR;
|
info.tiling = VK_IMAGE_TILING_LINEAR;
|
||||||
info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VULKAN_TEXTURE_READBACK:
|
case VULKAN_TEXTURE_READBACK:
|
||||||
info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
|
info.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
info.tiling = VK_IMAGE_TILING_LINEAR;
|
info.tiling = VK_IMAGE_TILING_LINEAR;
|
||||||
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCreateImage(device, &info, NULL, &tex.image);
|
if (type != VULKAN_TEXTURE_STAGING && type != VULKAN_TEXTURE_READBACK)
|
||||||
|
{
|
||||||
|
vkCreateImage(device, &info, NULL, &tex.image);
|
||||||
#if 0
|
#if 0
|
||||||
vulkan_track_alloc(tex.image);
|
vulkan_track_alloc(tex.image);
|
||||||
#endif
|
#endif
|
||||||
vkGetImageMemoryRequirements(device, tex.image, &mem_reqs);
|
vkGetImageMemoryRequirements(device, tex.image, &mem_reqs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Linear staging textures are not guaranteed to be supported,
|
||||||
|
* use buffers instead. */
|
||||||
|
vkCreateBuffer(device, &buffer_info, NULL, &tex.buffer);
|
||||||
|
vkGetBufferMemoryRequirements(device, tex.buffer, &mem_reqs);
|
||||||
|
}
|
||||||
alloc.allocationSize = mem_reqs.size;
|
alloc.allocationSize = mem_reqs.size;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
|
@ -449,13 +617,14 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
{
|
{
|
||||||
/* Recreate texture but for STAGING this time ... */
|
/* Recreate texture but for STAGING this time ... */
|
||||||
RARCH_LOG("[Vulkan]: GPU supports linear images as textures, but not DEVICE_LOCAL. Falling back to copy path.\n");
|
RARCH_LOG("[Vulkan]: GPU supports linear images as textures, but not DEVICE_LOCAL. Falling back to copy path.\n");
|
||||||
type = VULKAN_TEXTURE_STAGING;
|
type = VULKAN_TEXTURE_STAGING;
|
||||||
vkDestroyImage(device, tex.image, NULL);
|
vkDestroyImage(device, tex.image, NULL);
|
||||||
|
tex.image = NULL;
|
||||||
|
info.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
|
||||||
info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||||
vkCreateImage(device, &info, NULL, &tex.image);
|
vkCreateBuffer(device, &buffer_info, NULL, &tex.buffer);
|
||||||
|
vkGetBufferMemoryRequirements(device, tex.buffer, &mem_reqs);
|
||||||
vkGetImageMemoryRequirements(device, tex.image, &mem_reqs);
|
|
||||||
|
|
||||||
alloc.allocationSize = mem_reqs.size;
|
alloc.allocationSize = mem_reqs.size;
|
||||||
alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(
|
alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(
|
||||||
|
@ -478,6 +647,8 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
vulkan_track_dealloc(old->image);
|
vulkan_track_dealloc(old->image);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (old && old->buffer != VK_NULL_HANDLE)
|
||||||
|
vkDestroyBuffer(vk->context->device, old->buffer, NULL);
|
||||||
|
|
||||||
/* We can pilfer the old memory and move it over to the new texture. */
|
/* We can pilfer the old memory and move it over to the new texture. */
|
||||||
if (old &&
|
if (old &&
|
||||||
|
@ -507,7 +678,10 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
memset(old, 0, sizeof(*old));
|
memset(old, 0, sizeof(*old));
|
||||||
}
|
}
|
||||||
|
|
||||||
vkBindImageMemory(device, tex.image, tex.memory, 0);
|
if (tex.image)
|
||||||
|
vkBindImageMemory(device, tex.image, tex.memory, 0);
|
||||||
|
if (tex.buffer)
|
||||||
|
vkBindBufferMemory(device, tex.buffer, tex.memory, 0);
|
||||||
|
|
||||||
if (type != VULKAN_TEXTURE_STAGING && type != VULKAN_TEXTURE_READBACK)
|
if (type != VULKAN_TEXTURE_STAGING && type != VULKAN_TEXTURE_READBACK)
|
||||||
{
|
{
|
||||||
|
@ -532,8 +706,14 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
else
|
else
|
||||||
tex.view = VK_NULL_HANDLE;
|
tex.view = VK_NULL_HANDLE;
|
||||||
|
|
||||||
if (info.tiling == VK_IMAGE_TILING_LINEAR)
|
if (tex.image && info.tiling == VK_IMAGE_TILING_LINEAR)
|
||||||
vkGetImageSubresourceLayout(device, tex.image, &subresource, &layout);
|
vkGetImageSubresourceLayout(device, tex.image, &subresource, &layout);
|
||||||
|
else if (tex.buffer)
|
||||||
|
{
|
||||||
|
layout.offset = 0;
|
||||||
|
layout.size = buffer_info.size;
|
||||||
|
layout.rowPitch = width * vulkan_format_to_bpp(format);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
memset(&layout, 0, sizeof(layout));
|
memset(&layout, 0, sizeof(layout));
|
||||||
|
|
||||||
|
@ -568,7 +748,7 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
}
|
}
|
||||||
else if (initial && type == VULKAN_TEXTURE_STATIC)
|
else if (initial && type == VULKAN_TEXTURE_STATIC)
|
||||||
{
|
{
|
||||||
VkImageCopy region;
|
VkBufferImageCopy region;
|
||||||
VkCommandBuffer staging;
|
VkCommandBuffer staging;
|
||||||
struct vk_texture tmp = vulkan_create_texture(vk, NULL,
|
struct vk_texture tmp = vulkan_create_texture(vk, NULL,
|
||||||
width, height, format, initial, NULL, VULKAN_TEXTURE_STAGING);
|
width, height, format, initial, NULL, VULKAN_TEXTURE_STAGING);
|
||||||
|
@ -583,12 +763,6 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
|
|
||||||
vkBeginCommandBuffer(staging, &begin_info);
|
vkBeginCommandBuffer(staging, &begin_info);
|
||||||
|
|
||||||
vulkan_image_layout_transition(vk, staging, tmp.image,
|
|
||||||
VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
|
|
||||||
VK_PIPELINE_STAGE_HOST_BIT,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
|
||||||
|
|
||||||
/* If doing mipmapping on upload, keep in general so we can easily do transfers to
|
/* If doing mipmapping on upload, keep in general so we can easily do transfers to
|
||||||
* and transfers from the images without having to
|
* and transfers from the images without having to
|
||||||
* mess around with lots of extra transitions at per-level granularity.
|
* mess around with lots of extra transitions at per-level granularity.
|
||||||
|
@ -603,16 +777,14 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||||
|
|
||||||
memset(®ion, 0, sizeof(region));
|
memset(®ion, 0, sizeof(region));
|
||||||
region.extent.width = width;
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.extent.height = height;
|
region.imageSubresource.layerCount = 1;
|
||||||
region.extent.depth = 1;
|
region.imageExtent.width = width;
|
||||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.imageExtent.height = height;
|
||||||
region.srcSubresource.layerCount = 1;
|
region.imageExtent.depth = 1;
|
||||||
region.dstSubresource = region.srcSubresource;
|
|
||||||
|
|
||||||
vkCmdCopyImage(staging,
|
vkCmdCopyBufferToImage(staging,
|
||||||
tmp.image,
|
tmp.buffer,
|
||||||
VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
tex.image,
|
tex.image,
|
||||||
tex.mipmap ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
tex.mipmap ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
1, ®ion);
|
1, ®ion);
|
||||||
|
@ -710,12 +882,18 @@ void vulkan_destroy_texture(
|
||||||
{
|
{
|
||||||
if (tex->mapped)
|
if (tex->mapped)
|
||||||
vkUnmapMemory(device, tex->memory);
|
vkUnmapMemory(device, tex->memory);
|
||||||
vkFreeMemory(device, tex->memory, NULL);
|
|
||||||
if (tex->view)
|
if (tex->view)
|
||||||
vkDestroyImageView(device, tex->view, NULL);
|
vkDestroyImageView(device, tex->view, NULL);
|
||||||
vkDestroyImage(device, tex->image, NULL);
|
if (tex->image)
|
||||||
|
vkDestroyImage(device, tex->image, NULL);
|
||||||
|
if (tex->buffer)
|
||||||
|
vkDestroyBuffer(device, tex->buffer, NULL);
|
||||||
|
if (tex->memory)
|
||||||
|
vkFreeMemory(device, tex->memory, NULL);
|
||||||
|
|
||||||
#ifdef VULKAN_DEBUG_TEXTURE_ALLOC
|
#ifdef VULKAN_DEBUG_TEXTURE_ALLOC
|
||||||
vulkan_track_dealloc(tex->image);
|
if (tex->image)
|
||||||
|
vulkan_track_dealloc(tex->image);
|
||||||
#endif
|
#endif
|
||||||
memset(tex, 0, sizeof(*tex));
|
memset(tex, 0, sizeof(*tex));
|
||||||
}
|
}
|
||||||
|
@ -762,6 +940,9 @@ static void vulkan_write_quad_descriptors(
|
||||||
|
|
||||||
void vulkan_transition_texture(vk_t *vk, VkCommandBuffer cmd, struct vk_texture *texture)
|
void vulkan_transition_texture(vk_t *vk, VkCommandBuffer cmd, struct vk_texture *texture)
|
||||||
{
|
{
|
||||||
|
if (!texture->image)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Transition to GENERAL layout for linear streamed textures.
|
/* Transition to GENERAL layout for linear streamed textures.
|
||||||
* We're using linear textures here, so only
|
* We're using linear textures here, so only
|
||||||
* GENERAL layout is supported.
|
* GENERAL layout is supported.
|
||||||
|
@ -782,14 +963,6 @@ void vulkan_transition_texture(vk_t *vk, VkCommandBuffer cmd, struct vk_texture
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VULKAN_TEXTURE_STAGING:
|
|
||||||
vulkan_image_layout_transition(vk, cmd, texture->image,
|
|
||||||
texture->layout, VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
|
|
||||||
VK_PIPELINE_STAGE_HOST_BIT,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
retro_assert(0 && "Attempting to transition invalid texture type.\n");
|
retro_assert(0 && "Attempting to transition invalid texture type.\n");
|
||||||
break;
|
break;
|
||||||
|
@ -1550,6 +1723,12 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
|
||||||
vkGetPhysicalDeviceMemoryProperties(vk->context.gpu,
|
vkGetPhysicalDeviceMemoryProperties(vk->context.gpu,
|
||||||
&vk->context.memory_properties);
|
&vk->context.memory_properties);
|
||||||
|
|
||||||
|
#ifdef VULKAN_EMULATE_MAILBOX
|
||||||
|
/* Win32 windowed mode seems to deal just fine with toggling VSync.
|
||||||
|
* Fullscreen however ... */
|
||||||
|
vk->emulate_mailbox = vk->fullscreen;
|
||||||
|
#endif
|
||||||
|
|
||||||
RARCH_LOG("[Vulkan]: Using GPU: %s\n", vk->context.gpu_properties.deviceName);
|
RARCH_LOG("[Vulkan]: Using GPU: %s\n", vk->context.gpu_properties.deviceName);
|
||||||
|
|
||||||
if (vk->context.device == VK_NULL_HANDLE)
|
if (vk->context.device == VK_NULL_HANDLE)
|
||||||
|
@ -2309,12 +2488,14 @@ static void vulkan_destroy_swapchain(gfx_ctx_vulkan_data_t *vk)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
|
vulkan_emulated_mailbox_deinit(&vk->mailbox);
|
||||||
if (vk->swapchain != VK_NULL_HANDLE)
|
if (vk->swapchain != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(vk->context.device);
|
vkDeviceWaitIdle(vk->context.device);
|
||||||
vkDestroySwapchainKHR(vk->context.device, vk->swapchain, NULL);
|
vkDestroySwapchainKHR(vk->context.device, vk->swapchain, NULL);
|
||||||
memset(vk->context.swapchain_images, 0, sizeof(vk->context.swapchain_images));
|
memset(vk->context.swapchain_images, 0, sizeof(vk->context.swapchain_images));
|
||||||
vk->swapchain = VK_NULL_HANDLE;
|
vk->swapchain = VK_NULL_HANDLE;
|
||||||
|
vk->context.has_acquired_swapchain = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
|
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
|
||||||
|
@ -2333,9 +2514,13 @@ static void vulkan_destroy_swapchain(gfx_ctx_vulkan_data_t *vk)
|
||||||
|
|
||||||
void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
|
void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
|
||||||
{
|
{
|
||||||
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||||
VkResult result = VK_SUCCESS;
|
VkResult result = VK_SUCCESS;
|
||||||
VkResult err = VK_SUCCESS;
|
VkResult err = VK_SUCCESS;
|
||||||
|
|
||||||
|
if (!vk->context.has_acquired_swapchain)
|
||||||
|
return;
|
||||||
|
vk->context.has_acquired_swapchain = false;
|
||||||
|
|
||||||
/* We're still waiting for a proper swapchain, so just fake it. */
|
/* We're still waiting for a proper swapchain, so just fake it. */
|
||||||
if (vk->swapchain == VK_NULL_HANDLE)
|
if (vk->swapchain == VK_NULL_HANDLE)
|
||||||
|
@ -2431,8 +2616,8 @@ static void vulkan_acquire_clear_fences(gfx_ctx_vulkan_data_t *vk)
|
||||||
vkDestroyFence(vk->context.device,
|
vkDestroyFence(vk->context.device,
|
||||||
vk->context.swapchain_fences[i], NULL);
|
vk->context.swapchain_fences[i], NULL);
|
||||||
vk->context.swapchain_fences[i] = VK_NULL_HANDLE;
|
vk->context.swapchain_fences[i] = VK_NULL_HANDLE;
|
||||||
vk->context.swapchain_fences_signalled[i] = false;
|
|
||||||
}
|
}
|
||||||
|
vk->context.swapchain_fences_signalled[i] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2449,10 +2634,26 @@ static void vulkan_acquire_wait_fences(gfx_ctx_vulkan_data_t *vk)
|
||||||
if (vk->context.swapchain_fences_signalled[index])
|
if (vk->context.swapchain_fences_signalled[index])
|
||||||
vkWaitForFences(vk->context.device, 1, next_fence, true, UINT64_MAX);
|
vkWaitForFences(vk->context.device, 1, next_fence, true, UINT64_MAX);
|
||||||
vkResetFences(vk->context.device, 1, next_fence);
|
vkResetFences(vk->context.device, 1, next_fence);
|
||||||
vk->context.swapchain_fences_signalled[index] = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
vkCreateFence(vk->context.device, &fence_info, NULL, next_fence);
|
vkCreateFence(vk->context.device, &fence_info, NULL, next_fence);
|
||||||
|
vk->context.swapchain_fences_signalled[index] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vulkan_create_wait_fences(gfx_ctx_vulkan_data_t *vk)
|
||||||
|
{
|
||||||
|
VkFenceCreateInfo fence_info =
|
||||||
|
{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < vk->context.num_swapchain_images; i++)
|
||||||
|
{
|
||||||
|
if (!vk->context.swapchain_fences[i])
|
||||||
|
{
|
||||||
|
vkCreateFence(vk->context.device, &fence_info, NULL,
|
||||||
|
&vk->context.swapchain_fences[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk)
|
void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk)
|
||||||
|
@ -2489,22 +2690,47 @@ retry:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCreateFence(vk->context.device, &fence_info, NULL, &fence);
|
retro_assert(!vk->context.has_acquired_swapchain);
|
||||||
|
|
||||||
err = vkAcquireNextImageKHR(vk->context.device,
|
if (vk->emulating_mailbox)
|
||||||
vk->swapchain, UINT64_MAX,
|
{
|
||||||
VK_NULL_HANDLE, fence, &vk->context.current_swapchain_index);
|
/* Non-blocking acquire. If we don't get a swapchain frame right away,
|
||||||
|
* just skip rendering to the swapchain this frame, similar to what
|
||||||
|
* MAILBOX would do. */
|
||||||
|
err = vulkan_emulated_mailbox_acquire_next_image(&vk->mailbox, &vk->context.current_swapchain_index);
|
||||||
|
fence = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vkCreateFence(vk->context.device, &fence_info, NULL, &fence);
|
||||||
|
err = vkAcquireNextImageKHR(vk->context.device,
|
||||||
|
vk->swapchain, UINT64_MAX,
|
||||||
|
VK_NULL_HANDLE, fence, &vk->context.current_swapchain_index);
|
||||||
|
}
|
||||||
|
|
||||||
if (err == VK_SUCCESS)
|
if (err == VK_SUCCESS)
|
||||||
vkWaitForFences(vk->context.device, 1, &fence, true, UINT64_MAX);
|
{
|
||||||
|
if (fence != VK_NULL_HANDLE)
|
||||||
|
vkWaitForFences(vk->context.device, 1, &fence, true, UINT64_MAX);
|
||||||
|
vk->context.has_acquired_swapchain = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vk->context.has_acquired_swapchain = false;
|
||||||
|
|
||||||
#ifdef WSI_HARDENING_TEST
|
#ifdef WSI_HARDENING_TEST
|
||||||
trigger_spurious_error_vkresult(&err);
|
trigger_spurious_error_vkresult(&err);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vkDestroyFence(vk->context.device, fence, NULL);
|
if (fence != VK_NULL_HANDLE)
|
||||||
|
vkDestroyFence(vk->context.device, fence, NULL);
|
||||||
|
|
||||||
if (err == VK_ERROR_OUT_OF_DATE_KHR)
|
if (err == VK_NOT_READY || err == VK_TIMEOUT)
|
||||||
|
{
|
||||||
|
/* Just pretend we have a swapchain index, round-robin style. */
|
||||||
|
vk->context.current_swapchain_index =
|
||||||
|
(vk->context.current_swapchain_index + 1) % vk->context.num_swapchain_images;
|
||||||
|
}
|
||||||
|
else if (err == VK_ERROR_OUT_OF_DATE_KHR)
|
||||||
{
|
{
|
||||||
/* Throw away the old swapchain and try again. */
|
/* Throw away the old swapchain and try again. */
|
||||||
vulkan_destroy_swapchain(vk);
|
vulkan_destroy_swapchain(vk);
|
||||||
|
@ -2563,10 +2789,19 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||||
VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
VkResult res;
|
||||||
|
|
||||||
vkDeviceWaitIdle(vk->context.device);
|
vkDeviceWaitIdle(vk->context.device);
|
||||||
vulkan_acquire_clear_fences(vk);
|
vulkan_acquire_clear_fences(vk);
|
||||||
|
|
||||||
|
if (swap_interval == 0 && vk->emulate_mailbox)
|
||||||
|
{
|
||||||
|
swap_interval = 1;
|
||||||
|
vk->emulating_mailbox = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vk->emulating_mailbox = false;
|
||||||
|
|
||||||
vk->created_new_swapchain = true;
|
vk->created_new_swapchain = true;
|
||||||
if (vk->swapchain != VK_NULL_HANDLE &&
|
if (vk->swapchain != VK_NULL_HANDLE &&
|
||||||
!vk->context.invalid_swapchain &&
|
!vk->context.invalid_swapchain &&
|
||||||
|
@ -2576,10 +2811,50 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||||
{
|
{
|
||||||
/* Do not bother creating a swapchain redundantly. */
|
/* Do not bother creating a swapchain redundantly. */
|
||||||
RARCH_LOG("[Vulkan]: Do not need to re-create swapchain.\n");
|
RARCH_LOG("[Vulkan]: Do not need to re-create swapchain.\n");
|
||||||
vk->created_new_swapchain = false;
|
vulkan_create_wait_fences(vk);
|
||||||
return true;
|
|
||||||
|
if (vk->emulating_mailbox && vk->mailbox.swapchain == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vulkan_emulated_mailbox_init(&vk->mailbox, vk->context.device, vk->swapchain);
|
||||||
|
vk->created_new_swapchain = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (!vk->emulating_mailbox && vk->mailbox.swapchain != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
/* We are tearing down, and entering a state where we are supposed to have
|
||||||
|
* acquired an image, so block until we have acquired. */
|
||||||
|
if (!vk->context.has_acquired_swapchain)
|
||||||
|
{
|
||||||
|
res = vulkan_emulated_mailbox_acquire_next_image_blocking(
|
||||||
|
&vk->mailbox,
|
||||||
|
&vk->context.current_swapchain_index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
res = VK_SUCCESS;
|
||||||
|
|
||||||
|
vulkan_emulated_mailbox_deinit(&vk->mailbox);
|
||||||
|
|
||||||
|
if (res == VK_SUCCESS)
|
||||||
|
{
|
||||||
|
vk->context.has_acquired_swapchain = true;
|
||||||
|
vk->created_new_swapchain = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vk->context.has_acquired_swapchain = false;
|
||||||
|
/* We failed for some reason, so create a new swapchain. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vk->created_new_swapchain = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vulkan_emulated_mailbox_deinit(&vk->mailbox);
|
||||||
|
|
||||||
present_mode_count = 0;
|
present_mode_count = 0;
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR(
|
vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||||
vk->context.gpu, vk->vk_surface,
|
vk->context.gpu, vk->vk_surface,
|
||||||
|
@ -2814,5 +3089,11 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||||
|
|
||||||
/* Force driver to reset swapchain image handles. */
|
/* Force driver to reset swapchain image handles. */
|
||||||
vk->context.invalid_swapchain = true;
|
vk->context.invalid_swapchain = true;
|
||||||
|
vk->context.has_acquired_swapchain = false;
|
||||||
|
vulkan_create_wait_fences(vk);
|
||||||
|
|
||||||
|
if (vk->emulating_mailbox)
|
||||||
|
vulkan_emulated_mailbox_init(&vk->mailbox, vk->context.device, vk->swapchain);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,7 @@ typedef struct vulkan_context
|
||||||
/* Used by screenshot to get blits with correct colorspace. */
|
/* Used by screenshot to get blits with correct colorspace. */
|
||||||
bool swapchain_is_srgb;
|
bool swapchain_is_srgb;
|
||||||
bool swap_interval_emulation_lock;
|
bool swap_interval_emulation_lock;
|
||||||
|
bool has_acquired_swapchain;
|
||||||
|
|
||||||
unsigned swapchain_width;
|
unsigned swapchain_width;
|
||||||
unsigned swapchain_height;
|
unsigned swapchain_height;
|
||||||
|
@ -127,13 +128,42 @@ typedef struct vulkan_context
|
||||||
#endif
|
#endif
|
||||||
} vulkan_context_t;
|
} vulkan_context_t;
|
||||||
|
|
||||||
|
struct vulkan_emulated_mailbox
|
||||||
|
{
|
||||||
|
sthread_t *thread;
|
||||||
|
VkDevice device;
|
||||||
|
VkSwapchainKHR swapchain;
|
||||||
|
slock_t *lock;
|
||||||
|
scond_t *cond;
|
||||||
|
|
||||||
|
unsigned index;
|
||||||
|
bool acquired;
|
||||||
|
bool request_acquire;
|
||||||
|
bool dead;
|
||||||
|
bool has_pending_request;
|
||||||
|
VkResult result;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool vulkan_emulated_mailbox_init(struct vulkan_emulated_mailbox *mailbox,
|
||||||
|
VkDevice device, VkSwapchainKHR swapchain);
|
||||||
|
void vulkan_emulated_mailbox_deinit(struct vulkan_emulated_mailbox *mailbox);
|
||||||
|
VkResult vulkan_emulated_mailbox_acquire_next_image(struct vulkan_emulated_mailbox *mailbox, unsigned *index);
|
||||||
|
VkResult vulkan_emulated_mailbox_acquire_next_image_blocking(struct vulkan_emulated_mailbox *mailbox, unsigned *index);
|
||||||
|
|
||||||
typedef struct gfx_ctx_vulkan_data
|
typedef struct gfx_ctx_vulkan_data
|
||||||
{
|
{
|
||||||
bool need_new_swapchain;
|
bool need_new_swapchain;
|
||||||
bool created_new_swapchain;
|
bool created_new_swapchain;
|
||||||
|
bool emulate_mailbox;
|
||||||
|
bool emulating_mailbox;
|
||||||
vulkan_context_t context;
|
vulkan_context_t context;
|
||||||
VkSurfaceKHR vk_surface;
|
VkSurfaceKHR vk_surface;
|
||||||
VkSwapchainKHR swapchain;
|
VkSwapchainKHR swapchain;
|
||||||
|
|
||||||
|
struct vulkan_emulated_mailbox mailbox;
|
||||||
|
/* Used to check if we need to use mailbox emulation or not.
|
||||||
|
* Only relevant on Windows for now. */
|
||||||
|
bool fullscreen;
|
||||||
} gfx_ctx_vulkan_data_t;
|
} gfx_ctx_vulkan_data_t;
|
||||||
|
|
||||||
struct vulkan_display_surface_info
|
struct vulkan_display_surface_info
|
||||||
|
@ -179,6 +209,7 @@ struct vk_texture
|
||||||
VkImage image;
|
VkImage image;
|
||||||
VkImageView view;
|
VkImageView view;
|
||||||
VkDeviceMemory memory;
|
VkDeviceMemory memory;
|
||||||
|
VkBuffer buffer;
|
||||||
|
|
||||||
VkFormat format;
|
VkFormat format;
|
||||||
|
|
||||||
|
|
|
@ -28,14 +28,14 @@ static void null_display_server_destroy(void *data)
|
||||||
(void)data;
|
(void)data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool null_set_window_opacity(void *data, unsigned opacity)
|
static bool null_display_server_set_window_opacity(void *data, unsigned opacity)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
(void)opacity;
|
(void)opacity;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool null_set_window_progress(void *data, int progress, bool finished)
|
static bool null_display_server_set_window_progress(void *data, int progress, bool finished)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
(void)progress;
|
(void)progress;
|
||||||
|
@ -46,8 +46,9 @@ static bool null_set_window_progress(void *data, int progress, bool finished)
|
||||||
const video_display_server_t dispserv_null = {
|
const video_display_server_t dispserv_null = {
|
||||||
null_display_server_init,
|
null_display_server_init,
|
||||||
null_display_server_destroy,
|
null_display_server_destroy,
|
||||||
null_set_window_opacity,
|
null_display_server_set_window_opacity,
|
||||||
null_set_window_progress,
|
null_display_server_set_window_progress,
|
||||||
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
"null"
|
"null"
|
||||||
|
|
|
@ -69,6 +69,7 @@ be received by your application before it calls any ITaskbarList3 method.
|
||||||
static unsigned win32_orig_width = 0;
|
static unsigned win32_orig_width = 0;
|
||||||
static unsigned win32_orig_height = 0;
|
static unsigned win32_orig_height = 0;
|
||||||
static unsigned win32_orig_refresh = 0;
|
static unsigned win32_orig_refresh = 0;
|
||||||
|
static int crt_center = 0;
|
||||||
|
|
||||||
static void* win32_display_server_init(void)
|
static void* win32_display_server_init(void)
|
||||||
{
|
{
|
||||||
|
@ -107,7 +108,7 @@ static void win32_display_server_destroy(void *data)
|
||||||
|
|
||||||
if (win32_orig_width > 0 && win32_orig_height > 0 )
|
if (win32_orig_width > 0 && win32_orig_height > 0 )
|
||||||
video_display_server_switch_resolution(win32_orig_width, win32_orig_height,
|
video_display_server_switch_resolution(win32_orig_width, win32_orig_height,
|
||||||
win32_orig_refresh , (float)win32_orig_refresh );
|
win32_orig_refresh , (float)win32_orig_refresh, crt_center );
|
||||||
|
|
||||||
#ifdef HAS_TASKBAR_EXT
|
#ifdef HAS_TASKBAR_EXT
|
||||||
if (g_taskbarList && win32_taskbar_is_created())
|
if (g_taskbarList && win32_taskbar_is_created())
|
||||||
|
@ -121,7 +122,7 @@ static void win32_display_server_destroy(void *data)
|
||||||
free(dispserv);
|
free(dispserv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool win32_set_window_opacity(void *data, unsigned opacity)
|
static bool win32_display_server_set_window_opacity(void *data, unsigned opacity)
|
||||||
{
|
{
|
||||||
HWND hwnd = win32_get_window();
|
HWND hwnd = win32_get_window();
|
||||||
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
||||||
|
@ -148,7 +149,7 @@ static bool win32_set_window_opacity(void *data, unsigned opacity)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool win32_set_window_progress(void *data, int progress, bool finished)
|
static bool win32_display_server_set_window_progress(void *data, int progress, bool finished)
|
||||||
{
|
{
|
||||||
HWND hwnd = win32_get_window();
|
HWND hwnd = win32_get_window();
|
||||||
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
||||||
|
@ -187,7 +188,7 @@ static bool win32_set_window_progress(void *data, int progress, bool finished)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool win32_set_window_decorations(void *data, bool on)
|
static bool win32_display_server_set_window_decorations(void *data, bool on)
|
||||||
{
|
{
|
||||||
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
||||||
|
|
||||||
|
@ -201,7 +202,7 @@ static bool win32_set_window_decorations(void *data, bool on)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool win32_display_server_set_resolution(void *data,
|
static bool win32_display_server_set_resolution(void *data,
|
||||||
unsigned width, unsigned height, int int_hz, float hz)
|
unsigned width, unsigned height, int int_hz, float hz, int center)
|
||||||
{
|
{
|
||||||
LONG res;
|
LONG res;
|
||||||
DEVMODE curDevmode;
|
DEVMODE curDevmode;
|
||||||
|
@ -286,10 +287,11 @@ static bool win32_display_server_set_resolution(void *data,
|
||||||
const video_display_server_t dispserv_win32 = {
|
const video_display_server_t dispserv_win32 = {
|
||||||
win32_display_server_init,
|
win32_display_server_init,
|
||||||
win32_display_server_destroy,
|
win32_display_server_destroy,
|
||||||
win32_set_window_opacity,
|
win32_display_server_set_window_opacity,
|
||||||
win32_set_window_progress,
|
win32_display_server_set_window_progress,
|
||||||
win32_set_window_decorations,
|
win32_display_server_set_window_decorations,
|
||||||
win32_display_server_set_resolution,
|
win32_display_server_set_resolution,
|
||||||
|
NULL, /* get_output_options */
|
||||||
"win32"
|
"win32"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,14 @@
|
||||||
#include "../video_driver.h" /* needed to set refresh rate in set resolution */
|
#include "../video_driver.h" /* needed to set refresh rate in set resolution */
|
||||||
#include "../video_crt_switch.h" /* needed to set aspect for low res in linux */
|
#include "../video_crt_switch.h" /* needed to set aspect for low res in linux */
|
||||||
|
|
||||||
static char old_mode[150];
|
static unsigned orig_width = 0;
|
||||||
static char new_mode[150];
|
static unsigned orig_height = 0;
|
||||||
static bool crt_en = false;
|
static char old_mode[250] = {0};
|
||||||
|
static char new_mode[250] = {0};
|
||||||
|
static char xrandr[250] = {0};
|
||||||
|
static char fbset[150] = {0};
|
||||||
|
static char output[250] = {0};
|
||||||
|
static bool crt_en = false;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -45,16 +50,35 @@ static void* x11_display_server_init(void)
|
||||||
|
|
||||||
static void x11_display_server_destroy(void *data)
|
static void x11_display_server_destroy(void *data)
|
||||||
{
|
{
|
||||||
dispserv_x11_t *dispserv = (dispserv_x11_t*)data;
|
dispserv_x11_t *dispserv = (dispserv_x11_t*)data;
|
||||||
|
int i = 0;
|
||||||
if (crt_en == true)
|
if (crt_en == true)
|
||||||
system("xrandr -s 704x480");
|
{
|
||||||
|
sprintf(output,"xrandr -s %dx%d", orig_width, orig_height);
|
||||||
|
system(output);
|
||||||
|
|
||||||
|
for (i =0; i < 3; i++)
|
||||||
|
{
|
||||||
|
sprintf(output,"xrandr --delmode %s%d %s", "VGA",i ,old_mode);
|
||||||
|
system(output);
|
||||||
|
sprintf(output,"xrandr --delmode %s-%d %s", "VGA",i ,old_mode);
|
||||||
|
system(output);
|
||||||
|
|
||||||
|
sprintf(output,"xrandr --delmode %s%d %s", "DVI",i ,old_mode);
|
||||||
|
system(output);
|
||||||
|
sprintf(output,"xrandr --delmode %s-%d %s", "DVI",i ,old_mode);
|
||||||
|
system(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(output,"xrandr --rmmode %s", old_mode);
|
||||||
|
system(output);
|
||||||
|
}
|
||||||
|
|
||||||
if (dispserv)
|
if (dispserv)
|
||||||
free(dispserv);
|
free(dispserv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool x11_set_window_opacity(void *data, unsigned opacity)
|
static bool x11_display_server_set_window_opacity(void *data, unsigned opacity)
|
||||||
{
|
{
|
||||||
dispserv_x11_t *serv = (dispserv_x11_t*)data;
|
dispserv_x11_t *serv = (dispserv_x11_t*)data;
|
||||||
Atom net_wm_opacity = XInternAtom(g_x11_dpy, "_NET_WM_WINDOW_OPACITY", False);
|
Atom net_wm_opacity = XInternAtom(g_x11_dpy, "_NET_WM_WINDOW_OPACITY", False);
|
||||||
|
@ -72,7 +96,7 @@ static bool x11_set_window_opacity(void *data, unsigned opacity)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool x11_set_window_decorations(void *data, bool on)
|
static bool x11_display_server_set_window_decorations(void *data, bool on)
|
||||||
{
|
{
|
||||||
dispserv_x11_t *serv = (dispserv_x11_t*)data;
|
dispserv_x11_t *serv = (dispserv_x11_t*)data;
|
||||||
|
|
||||||
|
@ -83,8 +107,8 @@ static bool x11_set_window_decorations(void *data, bool on)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool x11_set_resolution(void *data,
|
static bool x11_display_server_set_resolution(void *data,
|
||||||
unsigned width, unsigned height, int int_hz, float hz)
|
unsigned width, unsigned height, int int_hz, float hz, int center)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int hfp = 0;
|
int hfp = 0;
|
||||||
|
@ -95,22 +119,41 @@ static bool x11_set_resolution(void *data,
|
||||||
int vbp = 0;
|
int vbp = 0;
|
||||||
int hmax = 0;
|
int hmax = 0;
|
||||||
int vmax = 0;
|
int vmax = 0;
|
||||||
|
int pdefault = 8;
|
||||||
|
int pwidth = 0;
|
||||||
|
float roundw = 0.0f;
|
||||||
|
float roundh = 0.0f;
|
||||||
float pixel_clock = 0;
|
float pixel_clock = 0;
|
||||||
char xrandr[250];
|
|
||||||
char fbset[150];
|
|
||||||
char output[250];
|
|
||||||
|
|
||||||
crt_en = true;
|
crt_en = true;
|
||||||
|
|
||||||
hsp = width*1.16;
|
|
||||||
|
|
||||||
/* set core refresh from hz */
|
/* set core refresh from hz */
|
||||||
video_monitor_set_refresh_rate(hz);
|
video_monitor_set_refresh_rate(hz);
|
||||||
|
|
||||||
/* following code is the mode line genorator */
|
/* following code is the mode line genorator */
|
||||||
|
|
||||||
hfp = width+8;
|
hsp = width*1.140;
|
||||||
hbp = width*1.32;
|
hfp = width*1.055;
|
||||||
|
|
||||||
|
pwidth = width;
|
||||||
|
|
||||||
|
if (height < 400 && width > 400 )
|
||||||
|
pwidth = width/2;
|
||||||
|
|
||||||
|
|
||||||
|
roundw = roundf((float)pwidth/(float)height * 100)/100;
|
||||||
|
|
||||||
|
if (height > width ) {
|
||||||
|
roundw = roundf((float)height/(float)width * 100)/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roundw > 1.35)
|
||||||
|
roundw = 1.25;
|
||||||
|
|
||||||
|
if (roundw < 1.20)
|
||||||
|
roundw = 1.34;
|
||||||
|
|
||||||
|
hbp = width*roundw-8;
|
||||||
hmax = hbp;
|
hmax = hbp;
|
||||||
|
|
||||||
if (height < 241)
|
if (height < 241)
|
||||||
|
@ -133,22 +176,18 @@ static bool x11_set_resolution(void *data,
|
||||||
{
|
{
|
||||||
vmax = 285;
|
vmax = 285;
|
||||||
}
|
}
|
||||||
if (height > 240 && height < 260 && hz < 52)
|
|
||||||
{
|
|
||||||
vmax = 265;
|
|
||||||
}
|
|
||||||
if (height > 250 && height < 260 && hz < 52)
|
if (height > 250 && height < 260 && hz < 52)
|
||||||
{
|
{
|
||||||
vmax = 313;
|
vmax = 313;
|
||||||
}
|
}
|
||||||
if (height > 260 && height < 300)
|
if (height > 260 && height < 300)
|
||||||
{
|
{
|
||||||
vmax = 313;
|
vmax = 318;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (height > 400 && hz > 56)
|
if (height > 400 && hz > 56)
|
||||||
{
|
{
|
||||||
vmax = 523;
|
vmax = 533;
|
||||||
}
|
}
|
||||||
if (height > 520 && hz < 57)
|
if (height > 520 && hz < 57)
|
||||||
{
|
{
|
||||||
|
@ -157,35 +196,27 @@ static bool x11_set_resolution(void *data,
|
||||||
|
|
||||||
if (height > 300 && hz < 56)
|
if (height > 300 && hz < 56)
|
||||||
{
|
{
|
||||||
vmax = 627;
|
vmax = 615;
|
||||||
}
|
}
|
||||||
|
if (height > 500 && hz < 56)
|
||||||
if (hz < 53)
|
|
||||||
{
|
{
|
||||||
vfp = height+((vmax-height)*0.38);
|
vmax = 624;
|
||||||
}
|
}
|
||||||
if (hz > 56)
|
if (height > 300)
|
||||||
{
|
{
|
||||||
vfp = height+((vmax-height)*0.15);
|
pdefault = pdefault*2;
|
||||||
}
|
|
||||||
if (hz > 53 && hz < 56)
|
|
||||||
{
|
|
||||||
vfp = height+((vmax-height)*0.35);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( vfp < 1 )
|
vfp = height+((vmax-height)/2)-pdefault;
|
||||||
{
|
|
||||||
vfp = height+2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (height < 300)
|
if (height < 300)
|
||||||
{
|
{
|
||||||
vsp = vfp+3; /* needs to me 3 for progressive */
|
vsp = vfp+3; /* needs to me 3 for progressive */
|
||||||
} if (height > 300)
|
}
|
||||||
|
if (height > 300)
|
||||||
{
|
{
|
||||||
vsp = vfp+6; /* needs to me 6 for interlaced */
|
vsp = vfp+6; /* needs to me 6 for interlaced */
|
||||||
}
|
}
|
||||||
|
|
||||||
vbp = vmax;
|
vbp = vmax;
|
||||||
|
@ -201,7 +232,7 @@ static bool x11_set_resolution(void *data,
|
||||||
}
|
}
|
||||||
/* above code is the modeline genorator */
|
/* above code is the modeline genorator */
|
||||||
|
|
||||||
/* create progressive newmode from modline variables */
|
/* create interlaced newmode from modline variables */
|
||||||
if (height < 300)
|
if (height < 300)
|
||||||
{
|
{
|
||||||
snprintf(xrandr, sizeof(xrandr), "xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d -hsync -vsync", width, height, hz, pixel_clock, width, hfp, hsp, hbp, height, vfp, vsp, vbp);
|
snprintf(xrandr, sizeof(xrandr), "xrandr --newmode \"%dx%d_%0.2f\" %lf %d %d %d %d %d %d %d %d -hsync -vsync", width, height, hz, pixel_clock, width, hfp, hsp, hbp, height, vfp, vsp, vbp);
|
||||||
|
@ -257,18 +288,25 @@ static bool x11_set_resolution(void *data,
|
||||||
/* variable for old mode */
|
/* variable for old mode */
|
||||||
snprintf(old_mode, sizeof(old_mode), "%s", new_mode);
|
snprintf(old_mode, sizeof(old_mode), "%s", new_mode);
|
||||||
system("xdotool windowactivate $(xdotool search --class RetroArch)"); /* needs xdotool installed. needed to recaputure window. */
|
system("xdotool windowactivate $(xdotool search --class RetroArch)"); /* needs xdotool installed. needed to recaputure window. */
|
||||||
/* Second run needed as some times it runs to fast to capture first time */
|
/* Second run needed as some times it runs to fast to capture first time */
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *x11_display_server_get_output_options(void)
|
||||||
|
{
|
||||||
|
/* TODO/FIXME - hardcoded for now; list should be built up dynamically later */
|
||||||
|
return "HDMI-0|HDMI-1|HDMI-2|HDMI-3|DVI-0|DVI-1|DVI-2|DVI-3|VGA-0|VGA-1|VGA-2|VGA-3|Config";
|
||||||
|
}
|
||||||
|
|
||||||
const video_display_server_t dispserv_x11 = {
|
const video_display_server_t dispserv_x11 = {
|
||||||
x11_display_server_init,
|
x11_display_server_init,
|
||||||
x11_display_server_destroy,
|
x11_display_server_destroy,
|
||||||
x11_set_window_opacity,
|
x11_display_server_set_window_opacity,
|
||||||
NULL,
|
NULL,
|
||||||
x11_set_window_decorations,
|
x11_display_server_set_window_decorations,
|
||||||
x11_set_resolution, /* set_resolution */
|
x11_display_server_set_resolution,
|
||||||
|
x11_display_server_get_output_options,
|
||||||
"x11"
|
"x11"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -973,7 +973,7 @@ d3d12_gfx_init(const video_info_t* video, const input_driver_t** input, void** i
|
||||||
{
|
{
|
||||||
const char* ext = path_get_extension(settings->paths.path_shader);
|
const char* ext = path_get_extension(settings->paths.path_shader);
|
||||||
|
|
||||||
if (ext && !strcmp(ext, "slangp"))
|
if (ext && string_is_equal(ext, "slangp"))
|
||||||
d3d12_gfx_set_shader(d3d12, RARCH_SHADER_SLANG, settings->paths.path_shader);
|
d3d12_gfx_set_shader(d3d12, RARCH_SHADER_SLANG, settings->paths.path_shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1006,13 +1006,15 @@ static bool d3d8_restore(void *data)
|
||||||
|
|
||||||
static void d3d8_set_nonblock_state(void *data, bool state)
|
static void d3d8_set_nonblock_state(void *data, bool state)
|
||||||
{
|
{
|
||||||
unsigned interval = state ? 0 : 1;
|
int interval = 0;
|
||||||
d3d8_video_t *d3d = (d3d8_video_t*)data;
|
d3d8_video_t *d3d = (d3d8_video_t*)data;
|
||||||
|
|
||||||
if (!d3d)
|
if (!d3d)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
d3d->video_info.vsync = !state;
|
if (!state)
|
||||||
|
interval = 1;
|
||||||
|
d3d->video_info.vsync = !state;
|
||||||
|
|
||||||
#ifdef _XBOX
|
#ifdef _XBOX
|
||||||
d3d8_set_render_state(d3d->dev, D3D8_PRESENTATIONINTERVAL,
|
d3d8_set_render_state(d3d->dev, D3D8_PRESENTATIONINTERVAL,
|
||||||
|
|
|
@ -1059,14 +1059,19 @@ static bool d3d9_restore(void *data)
|
||||||
|
|
||||||
static void d3d9_set_nonblock_state(void *data, bool state)
|
static void d3d9_set_nonblock_state(void *data, bool state)
|
||||||
{
|
{
|
||||||
unsigned interval = state ? 0 : 1;
|
int interval = 0;
|
||||||
d3d9_video_t *d3d = (d3d9_video_t*)data;
|
d3d9_video_t *d3d = (d3d9_video_t*)data;
|
||||||
|
|
||||||
if (!d3d)
|
if (!d3d)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!state)
|
||||||
|
interval = 1;
|
||||||
|
|
||||||
d3d->video_info.vsync = !state;
|
d3d->video_info.vsync = !state;
|
||||||
|
|
||||||
|
(void)interval;
|
||||||
|
|
||||||
#ifdef _XBOX
|
#ifdef _XBOX
|
||||||
d3d9_set_render_state(d3d->dev,
|
d3d9_set_render_state(d3d->dev,
|
||||||
D3D9_PRESENTATIONINTERVAL,
|
D3D9_PRESENTATIONINTERVAL,
|
||||||
|
|
|
@ -952,6 +952,12 @@ static bool gl_frame(void *data, const void *frame,
|
||||||
if (!gl)
|
if (!gl)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
// Should be called once per frame
|
||||||
|
if(!appletMainLoop())
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
context_bind_hw_render(false);
|
context_bind_hw_render(false);
|
||||||
|
|
||||||
if (gl->core_context_in_use && gl->renderchain_driver->bind_vao)
|
if (gl->core_context_in_use && gl->renderchain_driver->bind_vao)
|
||||||
|
@ -1318,7 +1324,7 @@ static void gl_free(void *data)
|
||||||
|
|
||||||
static void gl_set_nonblock_state(void *data, bool state)
|
static void gl_set_nonblock_state(void *data, bool state)
|
||||||
{
|
{
|
||||||
unsigned interval = 0;
|
int interval = 0;
|
||||||
gl_t *gl = (gl_t*)data;
|
gl_t *gl = (gl_t*)data;
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
@ -1696,13 +1702,14 @@ static void *gl_init(const video_info_t *video,
|
||||||
{
|
{
|
||||||
gfx_ctx_mode_t mode;
|
gfx_ctx_mode_t mode;
|
||||||
gfx_ctx_input_t inp;
|
gfx_ctx_input_t inp;
|
||||||
unsigned interval, mip_level;
|
|
||||||
unsigned full_x, full_y;
|
unsigned full_x, full_y;
|
||||||
video_shader_ctx_filter_t shader_filter;
|
video_shader_ctx_filter_t shader_filter;
|
||||||
video_shader_ctx_info_t shader_info;
|
video_shader_ctx_info_t shader_info;
|
||||||
video_shader_ctx_ident_t ident_info;
|
video_shader_ctx_ident_t ident_info;
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
video_shader_ctx_wrap_t wrap_info = {0};
|
video_shader_ctx_wrap_t wrap_info = {0};
|
||||||
|
int interval = 0;
|
||||||
|
unsigned mip_level = 0;
|
||||||
unsigned win_width = 0;
|
unsigned win_width = 0;
|
||||||
unsigned win_height = 0;
|
unsigned win_height = 0;
|
||||||
unsigned temp_width = 0;
|
unsigned temp_width = 0;
|
||||||
|
@ -1755,6 +1762,10 @@ static void *gl_init(const video_info_t *video,
|
||||||
if (!video_context_driver_set_video_mode(&mode))
|
if (!video_context_driver_set_video_mode(&mode))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
#if !defined(RARCH_CONSOLE) || defined(HAVE_LIBNX)
|
||||||
|
rglgen_resolve_symbols(ctx_driver->get_proc_address);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Clear out potential error flags in case we use cached context. */
|
/* Clear out potential error flags in case we use cached context. */
|
||||||
glGetError();
|
glGetError();
|
||||||
|
|
||||||
|
@ -1768,10 +1779,6 @@ static void *gl_init(const video_info_t *video,
|
||||||
if (!string_is_empty(version))
|
if (!string_is_empty(version))
|
||||||
sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor);
|
sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor);
|
||||||
|
|
||||||
#ifndef RARCH_CONSOLE
|
|
||||||
rglgen_resolve_symbols(ctx_driver->get_proc_address);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
hwr = video_driver_get_hw_context();
|
hwr = video_driver_get_hw_context();
|
||||||
|
|
||||||
if (hwr->context_type == RETRO_HW_CONTEXT_OPENGL_CORE)
|
if (hwr->context_type == RETRO_HW_CONTEXT_OPENGL_CORE)
|
||||||
|
|
|
@ -892,7 +892,7 @@ static void wiiu_gfx_update_uniform_block(wiiu_video_t *wiiu, int pass, float *u
|
||||||
|
|
||||||
float *dst = ubo + uniformVars[i].offset;
|
float *dst = ubo + uniformVars[i].offset;
|
||||||
|
|
||||||
if (!strcmp(id, "OutputSize"))
|
if (string_is_equal(id, "OutputSize"))
|
||||||
{
|
{
|
||||||
((GX2_vec4 *)dst)->x = wiiu->pass[pass].color_buffer.surface.width;
|
((GX2_vec4 *)dst)->x = wiiu->pass[pass].color_buffer.surface.width;
|
||||||
((GX2_vec4 *)dst)->y = wiiu->pass[pass].color_buffer.surface.height;
|
((GX2_vec4 *)dst)->y = wiiu->pass[pass].color_buffer.surface.height;
|
||||||
|
@ -901,7 +901,7 @@ static void wiiu_gfx_update_uniform_block(wiiu_video_t *wiiu, int pass, float *u
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(id, "FinalViewportSize"))
|
if (string_is_equal(id, "FinalViewportSize"))
|
||||||
{
|
{
|
||||||
((GX2_vec4 *)dst)->x = wiiu->vp.width;
|
((GX2_vec4 *)dst)->x = wiiu->vp.width;
|
||||||
((GX2_vec4 *)dst)->y = wiiu->vp.height;
|
((GX2_vec4 *)dst)->y = wiiu->vp.height;
|
||||||
|
@ -910,7 +910,7 @@ static void wiiu_gfx_update_uniform_block(wiiu_video_t *wiiu, int pass, float *u
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(id, "FrameCount"))
|
if (string_is_equal(id, "FrameCount"))
|
||||||
{
|
{
|
||||||
*dst = wiiu->shader_preset->pass[pass].frame_count_mod ?
|
*dst = wiiu->shader_preset->pass[pass].frame_count_mod ?
|
||||||
frame_count % wiiu->shader_preset->pass[pass].frame_count_mod :
|
frame_count % wiiu->shader_preset->pass[pass].frame_count_mod :
|
||||||
|
@ -919,7 +919,7 @@ static void wiiu_gfx_update_uniform_block(wiiu_video_t *wiiu, int pass, float *u
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(id, "OriginalSize"))
|
if (string_is_equal(id, "OriginalSize"))
|
||||||
{
|
{
|
||||||
((GX2_vec4 *)dst)->x = wiiu->texture.surface.width;
|
((GX2_vec4 *)dst)->x = wiiu->texture.surface.width;
|
||||||
((GX2_vec4 *)dst)->y = wiiu->texture.surface.height;
|
((GX2_vec4 *)dst)->y = wiiu->texture.surface.height;
|
||||||
|
@ -928,7 +928,7 @@ static void wiiu_gfx_update_uniform_block(wiiu_video_t *wiiu, int pass, float *u
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(id, "SourceSize"))
|
if (string_is_equal(id, "SourceSize"))
|
||||||
{
|
{
|
||||||
GX2Surface *source = (pass > 0) ? &wiiu->pass[pass - 1].texture.surface : &wiiu->texture.surface;
|
GX2Surface *source = (pass > 0) ? &wiiu->pass[pass - 1].texture.surface : &wiiu->texture.surface;
|
||||||
((GX2_vec4 *)dst)->x = source->width;
|
((GX2_vec4 *)dst)->x = source->width;
|
||||||
|
@ -995,7 +995,7 @@ static void wiiu_gfx_update_uniform_block(wiiu_video_t *wiiu, int pass, float *u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(id, "MVP"))
|
if (string_is_equal(id, "MVP"))
|
||||||
{
|
{
|
||||||
memcpy(dst, wiiu->ubo_mvp, sizeof(*wiiu->ubo_mvp));
|
memcpy(dst, wiiu->ubo_mvp, sizeof(*wiiu->ubo_mvp));
|
||||||
continue;
|
continue;
|
||||||
|
@ -1004,7 +1004,7 @@ static void wiiu_gfx_update_uniform_block(wiiu_video_t *wiiu, int pass, float *u
|
||||||
|
|
||||||
for (int k = 0; k < wiiu->shader_preset->num_parameters; k++)
|
for (int k = 0; k < wiiu->shader_preset->num_parameters; k++)
|
||||||
{
|
{
|
||||||
if (!strcmp(id, wiiu->shader_preset->parameters[k].id))
|
if (string_is_equal(id, wiiu->shader_preset->parameters[k].id))
|
||||||
{
|
{
|
||||||
*dst = wiiu->shader_preset->parameters[k].current;
|
*dst = wiiu->shader_preset->parameters[k].current;
|
||||||
*(u32 *)dst = __builtin_bswap32(*(u32 *)dst);
|
*(u32 *)dst = __builtin_bswap32(*(u32 *)dst);
|
||||||
|
@ -1174,7 +1174,7 @@ static bool wiiu_gfx_frame(void *data, const void *frame,
|
||||||
|
|
||||||
for (int j = 0; j < wiiu->pass[i].gfd->ps->samplerVarCount; j++)
|
for (int j = 0; j < wiiu->pass[i].gfd->ps->samplerVarCount; j++)
|
||||||
{
|
{
|
||||||
if (!strcmp(wiiu->pass[i].gfd->ps->samplerVars[j].name, "Source"))
|
if (string_is_equal(wiiu->pass[i].gfd->ps->samplerVars[j].name, "Source"))
|
||||||
{
|
{
|
||||||
GX2SetPixelTexture(texture, wiiu->pass[i].gfd->ps->samplerVars[j].location);
|
GX2SetPixelTexture(texture, wiiu->pass[i].gfd->ps->samplerVars[j].location);
|
||||||
GX2SetPixelSampler(wiiu->shader_preset->pass[i].filter ?
|
GX2SetPixelSampler(wiiu->shader_preset->pass[i].filter ?
|
||||||
|
@ -1184,7 +1184,7 @@ static bool wiiu_gfx_frame(void *data, const void *frame,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(wiiu->pass[i].gfd->ps->samplerVars[j].name, "Original"))
|
if (string_is_equal(wiiu->pass[i].gfd->ps->samplerVars[j].name, "Original"))
|
||||||
{
|
{
|
||||||
GX2SetPixelTexture(&wiiu->texture, wiiu->pass[i].gfd->ps->samplerVars[j].location);
|
GX2SetPixelTexture(&wiiu->texture, wiiu->pass[i].gfd->ps->samplerVars[j].location);
|
||||||
GX2SetPixelSampler(wiiu->shader_preset->pass[0].filter ?
|
GX2SetPixelSampler(wiiu->shader_preset->pass[0].filter ?
|
||||||
|
@ -1245,7 +1245,7 @@ static bool wiiu_gfx_frame(void *data, const void *frame,
|
||||||
for (int k = 0; k < wiiu->shader_preset->luts; k++)
|
for (int k = 0; k < wiiu->shader_preset->luts; k++)
|
||||||
{
|
{
|
||||||
if (wiiu->luts[k].surface.image
|
if (wiiu->luts[k].surface.image
|
||||||
&& !strcmp(wiiu->pass[i].gfd->ps->samplerVars[j].name, wiiu->shader_preset->lut[k].id))
|
&& string_is_equal(wiiu->pass[i].gfd->ps->samplerVars[j].name, wiiu->shader_preset->lut[k].id))
|
||||||
{
|
{
|
||||||
GX2SetPixelTexture(&wiiu->luts[k], wiiu->pass[i].gfd->ps->samplerVars[j].location);
|
GX2SetPixelTexture(&wiiu->luts[k], wiiu->pass[i].gfd->ps->samplerVars[j].location);
|
||||||
GX2SetPixelSampler(wiiu->shader_preset->lut[k].filter ?
|
GX2SetPixelSampler(wiiu->shader_preset->lut[k].filter ?
|
||||||
|
|
|
@ -163,7 +163,8 @@ static void metal_viewport_info(void *data, struct video_viewport *vp)
|
||||||
|
|
||||||
static bool metal_read_viewport(void *data, uint8_t *buffer, bool is_idle)
|
static bool metal_read_viewport(void *data, uint8_t *buffer, bool is_idle)
|
||||||
{
|
{
|
||||||
return true;
|
MetalDriver *md = (__bridge MetalDriver *)data;
|
||||||
|
return [md.frameView readViewport:buffer isIdle:is_idle];
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintptr_t metal_load_texture(void *video_data, void *data,
|
static uintptr_t metal_load_texture(void *video_data, void *data,
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2018 - misson20000
|
||||||
|
* Copyright (C) 2018 - m4xw
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
@ -146,41 +162,41 @@ static bool switch_frame(void *data, const void *frame,
|
||||||
centerx = (1280-tgtw)/2;
|
centerx = (1280-tgtw)/2;
|
||||||
centery = (720-tgth)/2;
|
centery = (720-tgth)/2;
|
||||||
|
|
||||||
// clear image to black
|
/* clear image to black */
|
||||||
for(y = 0; y < 720; y++)
|
for(y = 0; y < 720; y++)
|
||||||
{
|
{
|
||||||
for(x = 0; x < 1280; x++)
|
for(x = 0; x < 1280; x++)
|
||||||
{
|
|
||||||
sw->image[y*1280+x] = 0xFF000000;
|
sw->image[y*1280+x] = 0xFF000000;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(width > 0 && height > 0) {
|
if(width > 0 && height > 0)
|
||||||
|
{
|
||||||
if(sw->last_width != width ||
|
if(sw->last_width != width ||
|
||||||
sw->last_height != height)
|
sw->last_height != height)
|
||||||
{
|
{
|
||||||
scaler_ctx_gen_reset(&sw->scaler);
|
scaler_ctx_gen_reset(&sw->scaler);
|
||||||
|
|
||||||
sw->scaler.in_width = width;
|
sw->scaler.in_width = width;
|
||||||
sw->scaler.in_height = height;
|
sw->scaler.in_height = height;
|
||||||
sw->scaler.in_stride = pitch;
|
sw->scaler.in_stride = pitch;
|
||||||
sw->scaler.in_fmt = sw->rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
|
sw->scaler.in_fmt = sw->rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
|
||||||
|
|
||||||
sw->scaler.out_width = tgtw;
|
sw->scaler.out_width = tgtw;
|
||||||
sw->scaler.out_height = tgth;
|
sw->scaler.out_height = tgth;
|
||||||
sw->scaler.out_stride = 1280 * sizeof(uint32_t);
|
sw->scaler.out_stride = 1280 * sizeof(uint32_t);
|
||||||
sw->scaler.out_fmt = SCALER_FMT_ABGR8888;
|
sw->scaler.out_fmt = SCALER_FMT_ABGR8888;
|
||||||
|
|
||||||
sw->scaler.scaler_type = SCALER_TYPE_POINT;
|
sw->scaler.scaler_type = SCALER_TYPE_POINT;
|
||||||
|
|
||||||
if(!scaler_ctx_gen_filter(&sw->scaler)) {
|
if(!scaler_ctx_gen_filter(&sw->scaler))
|
||||||
RARCH_ERR("failed to generate scaler for main image\n");
|
{
|
||||||
return false;
|
RARCH_ERR("failed to generate scaler for main image\n");
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
sw->last_width = width;
|
sw->last_width = width;
|
||||||
sw->last_height = height;
|
sw->last_height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
scaler_ctx_scale(&sw->scaler, sw->image + (centery * 1280) + centerx, frame);
|
scaler_ctx_scale(&sw->scaler, sw->image + (centery * 1280) + centerx, frame);
|
||||||
}
|
}
|
||||||
|
@ -213,10 +229,8 @@ static bool switch_frame(void *data, const void *frame,
|
||||||
&video_info->osd_stat_params;
|
&video_info->osd_stat_params;
|
||||||
|
|
||||||
if (osd_params)
|
if (osd_params)
|
||||||
{
|
|
||||||
font_driver_render_msg(video_info, NULL, video_info->stat_text,
|
font_driver_render_msg(video_info, NULL, video_info->stat_text,
|
||||||
(const struct font_params*)&video_info->osd_stat_params);
|
(const struct font_params*)&video_info->osd_stat_params);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -232,14 +246,12 @@ static bool switch_frame(void *data, const void *frame,
|
||||||
RARCH_LOG("message: %s\n", msg);
|
RARCH_LOG("message: %s\n", msg);
|
||||||
|
|
||||||
r = surface_dequeue_buffer(&sw->surface, &out_buffer);
|
r = surface_dequeue_buffer(&sw->surface, &out_buffer);
|
||||||
if(r != RESULT_OK) {
|
if(r != RESULT_OK)
|
||||||
return true; // just skip the frame
|
return true; /* just skip the frame */
|
||||||
}
|
|
||||||
|
|
||||||
r = surface_wait_buffer(&sw->surface);
|
r = surface_wait_buffer(&sw->surface);
|
||||||
if(r != RESULT_OK) {
|
if(r != RESULT_OK)
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
gfx_slow_swizzling_blit(out_buffer, sw->image, 1280, 720, 0, 0);
|
gfx_slow_swizzling_blit(out_buffer, sw->image, 1280, 720, 0, 0);
|
||||||
|
|
||||||
r = surface_queue_buffer(&sw->surface);
|
r = surface_queue_buffer(&sw->surface);
|
||||||
|
@ -333,6 +345,8 @@ static void switch_set_texture_frame(
|
||||||
sw->menu_texture.width != width ||
|
sw->menu_texture.width != width ||
|
||||||
sw->menu_texture.height != height)
|
sw->menu_texture.height != height)
|
||||||
{
|
{
|
||||||
|
struct scaler_ctx *sctx;
|
||||||
|
int xsf, ysf, sf;
|
||||||
if (sw->menu_texture.pixels)
|
if (sw->menu_texture.pixels)
|
||||||
free(sw->menu_texture.pixels);
|
free(sw->menu_texture.pixels);
|
||||||
|
|
||||||
|
@ -343,32 +357,32 @@ static void switch_set_texture_frame(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xsf = 1280 / width;
|
xsf = 1280 / width;
|
||||||
int ysf = 720 / height;
|
ysf = 720 / height;
|
||||||
int sf = xsf;
|
sf = xsf;
|
||||||
|
|
||||||
if (ysf < sf)
|
if (ysf < sf)
|
||||||
sf = ysf;
|
sf = ysf;
|
||||||
|
|
||||||
sw->menu_texture.width = width;
|
sw->menu_texture.width = width;
|
||||||
sw->menu_texture.height = height;
|
sw->menu_texture.height = height;
|
||||||
sw->menu_texture.tgtw = width * sf;
|
sw->menu_texture.tgtw = width * sf;
|
||||||
sw->menu_texture.tgth = height * sf;
|
sw->menu_texture.tgth = height * sf;
|
||||||
|
|
||||||
struct scaler_ctx *sctx = &sw->menu_texture.scaler;
|
sctx = &sw->menu_texture.scaler;
|
||||||
scaler_ctx_gen_reset(sctx);
|
scaler_ctx_gen_reset(sctx);
|
||||||
|
|
||||||
sctx->in_width = width;
|
sctx->in_width = width;
|
||||||
sctx->in_height = height;
|
sctx->in_height = height;
|
||||||
sctx->in_stride = width * (rgb32 ? 4 : 2);
|
sctx->in_stride = width * (rgb32 ? 4 : 2);
|
||||||
sctx->in_fmt = rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
|
sctx->in_fmt = rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
|
||||||
|
|
||||||
sctx->out_width = sw->menu_texture.tgtw;
|
sctx->out_width = sw->menu_texture.tgtw;
|
||||||
sctx->out_height = sw->menu_texture.tgth;
|
sctx->out_height = sw->menu_texture.tgth;
|
||||||
sctx->out_stride = 1280 * 4;
|
sctx->out_stride = 1280 * 4;
|
||||||
sctx->out_fmt = SCALER_FMT_ABGR8888;
|
sctx->out_fmt = SCALER_FMT_ABGR8888;
|
||||||
|
|
||||||
sctx->scaler_type = SCALER_TYPE_POINT;
|
sctx->scaler_type = SCALER_TYPE_POINT;
|
||||||
|
|
||||||
if (!scaler_ctx_gen_filter(sctx))
|
if (!scaler_ctx_gen_filter(sctx))
|
||||||
{
|
{
|
||||||
|
@ -383,6 +397,9 @@ static void switch_set_texture_frame(
|
||||||
static void switch_set_texture_enable(void *data, bool enable, bool full_screen)
|
static void switch_set_texture_enable(void *data, bool enable, bool full_screen)
|
||||||
{
|
{
|
||||||
switch_video_t *sw = data;
|
switch_video_t *sw = data;
|
||||||
|
if (!sw)
|
||||||
|
return;
|
||||||
|
|
||||||
sw->menu_texture.enable = enable;
|
sw->menu_texture.enable = enable;
|
||||||
sw->menu_texture.fullscreen = full_screen;
|
sw->menu_texture.fullscreen = full_screen;
|
||||||
}
|
}
|
||||||
|
@ -441,3 +458,5 @@ video_driver_t video_switch = {
|
||||||
#endif
|
#endif
|
||||||
switch_get_poke_interface,
|
switch_get_poke_interface,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* vim: set ts=3 sw=3 */
|
||||||
|
|
|
@ -0,0 +1,775 @@
|
||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2018 - misson20000
|
||||||
|
* Copyright (C) 2018 - m4xw
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include <retro_inline.h>
|
||||||
|
#include <retro_math.h>
|
||||||
|
#include <formats/image.h>
|
||||||
|
|
||||||
|
#include <formats/image.h>
|
||||||
|
#include <gfx/scaler/scaler.h>
|
||||||
|
#include <gfx/scaler/pixconv.h>
|
||||||
|
#include <gfx/video_frame.h>
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "../../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_MENU
|
||||||
|
#include "../../menu/menu_driver.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../font_driver.h"
|
||||||
|
|
||||||
|
#include "../../configuration.h"
|
||||||
|
#include "../../command.h"
|
||||||
|
#include "../../driver.h"
|
||||||
|
|
||||||
|
#include "../../retroarch.h"
|
||||||
|
#include "../../verbosity.h"
|
||||||
|
|
||||||
|
#include "../common/switch_common.h"
|
||||||
|
|
||||||
|
#ifndef HAVE_THREADS
|
||||||
|
#include "../../tasks/tasks_internal.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_NXRGUI
|
||||||
|
extern uint32_t *nx_backgroundImage;
|
||||||
|
/* Temp Overlay - kill it with fire */
|
||||||
|
extern uint32_t *tmp_overlay;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* (C) libtransistor */
|
||||||
|
static int pdep(uint32_t mask, uint32_t value)
|
||||||
|
{
|
||||||
|
uint32_t out = 0;
|
||||||
|
for (int shift = 0; shift < 32; shift++)
|
||||||
|
{
|
||||||
|
uint32_t bit = 1u << shift;
|
||||||
|
if (mask & bit)
|
||||||
|
{
|
||||||
|
if (value & 1)
|
||||||
|
out |= bit;
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t swizzle_x(uint32_t v) { return pdep(~0x7B4u, v); }
|
||||||
|
static uint32_t swizzle_y(uint32_t v) { return pdep(0x7B4, v); }
|
||||||
|
|
||||||
|
void gfx_slow_swizzling_blit(uint32_t *buffer, uint32_t *image, int w, int h, int tx, int ty, bool blend)
|
||||||
|
{
|
||||||
|
uint32_t *dest = buffer;
|
||||||
|
uint32_t *src = image;
|
||||||
|
int x0 = tx;
|
||||||
|
int y0 = ty;
|
||||||
|
int x1 = x0 + w;
|
||||||
|
int y1 = y0 + h;
|
||||||
|
const uint32_t tile_height = 128;
|
||||||
|
const uint32_t padded_width = 128 * 10;
|
||||||
|
|
||||||
|
/* we're doing this in pixels - should just shift the swizzles instead */
|
||||||
|
uint32_t offs_x0 = swizzle_x(x0);
|
||||||
|
uint32_t offs_y = swizzle_y(y0);
|
||||||
|
uint32_t x_mask = swizzle_x(~0u);
|
||||||
|
uint32_t y_mask = swizzle_y(~0u);
|
||||||
|
uint32_t incr_y = swizzle_x(padded_width);
|
||||||
|
|
||||||
|
/* step offs_x0 to the right row of tiles */
|
||||||
|
offs_x0 += incr_y * (y0 / tile_height);
|
||||||
|
|
||||||
|
uint32_t x, y;
|
||||||
|
for (y = y0; y < y1; y++)
|
||||||
|
{
|
||||||
|
uint32_t *dest_line = dest + offs_y;
|
||||||
|
uint32_t offs_x = offs_x0;
|
||||||
|
|
||||||
|
for (x = x0; x < x1; x++)
|
||||||
|
{
|
||||||
|
uint32_t pixel = *src++;
|
||||||
|
if (blend) /* supercheap masking */
|
||||||
|
{
|
||||||
|
uint32_t dst = dest_line[offs_x];
|
||||||
|
uint8_t src_a = ((pixel & 0xFF000000) >> 24);
|
||||||
|
|
||||||
|
if (src_a > 0)
|
||||||
|
pixel &= 0x00FFFFFF;
|
||||||
|
else
|
||||||
|
pixel = dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_line[offs_x] = pixel;
|
||||||
|
|
||||||
|
offs_x = (offs_x - x_mask) & x_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
offs_y = (offs_y - y_mask) & y_mask;
|
||||||
|
if (!offs_y)
|
||||||
|
offs_x0 += incr_y; /* wrap into next tile row */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* needed to clear surface completely as hw scaling doesn't always scale to full resoution perflectly */
|
||||||
|
static void clear_screen(switch_video_t *sw)
|
||||||
|
{
|
||||||
|
uint32_t *out_buffer = NULL;
|
||||||
|
gfxConfigureResolution(sw->vp.full_width, sw->vp.full_height);
|
||||||
|
|
||||||
|
out_buffer = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
|
||||||
|
|
||||||
|
memset(out_buffer, 0, gfxGetFramebufferSize());
|
||||||
|
|
||||||
|
gfxFlushBuffers();
|
||||||
|
gfxSwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *switch_init(const video_info_t *video,
|
||||||
|
const input_driver_t **input, void **input_data)
|
||||||
|
{
|
||||||
|
void *switchinput = NULL;
|
||||||
|
switch_video_t *sw = (switch_video_t *)calloc(1, sizeof(*sw));
|
||||||
|
if (!sw)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
printf("loading switch gfx driver, width: %d, height: %d threaded: %d smooth %d\n", video->width, video->height, video->is_threaded, video->smooth);
|
||||||
|
sw->vp.x = 0;
|
||||||
|
sw->vp.y = 0;
|
||||||
|
sw->vp.width = sw->o_width = video->width;
|
||||||
|
sw->vp.height = sw->o_height = video->height;
|
||||||
|
sw->overlay_enabled = false;
|
||||||
|
sw->overlay = NULL;
|
||||||
|
sw->in_menu = false;
|
||||||
|
|
||||||
|
sw->vp.full_width = 1280;
|
||||||
|
sw->vp.full_height = 720;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
sw->vp.width = MIN(sw->vp.width, sw->vp.full_width);
|
||||||
|
sw->vp.height = MIN(sw->vp.height, sw->vp.full_height);
|
||||||
|
|
||||||
|
sw->vsync = video->vsync;
|
||||||
|
sw->rgb32 = video->rgb32;
|
||||||
|
sw->keep_aspect = true;
|
||||||
|
sw->should_resize = true;
|
||||||
|
sw->o_size = true;
|
||||||
|
sw->is_threaded = video->is_threaded;
|
||||||
|
sw->smooth = video->smooth;
|
||||||
|
sw->menu_texture.enable = false;
|
||||||
|
|
||||||
|
/* Autoselect driver */
|
||||||
|
if (input && input_data)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
switchinput = input_switch.init(settings->arrays.input_joypad_driver);
|
||||||
|
*input = switchinput ? &input_switch : NULL;
|
||||||
|
*input_data = switchinput;
|
||||||
|
}
|
||||||
|
|
||||||
|
font_driver_init_osd(sw, false,
|
||||||
|
video->is_threaded,
|
||||||
|
FONT_DRIVER_RENDER_SWITCH);
|
||||||
|
|
||||||
|
clear_screen(sw);
|
||||||
|
|
||||||
|
return sw;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_update_viewport(switch_video_t *sw,
|
||||||
|
video_frame_info_t *video_info)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
float desired_aspect = 0.0f;
|
||||||
|
float width = sw->vp.full_width;
|
||||||
|
float height = sw->vp.full_height;
|
||||||
|
|
||||||
|
if (sw->o_size)
|
||||||
|
{
|
||||||
|
width = sw->o_width;
|
||||||
|
height = sw->o_height;
|
||||||
|
sw->vp.x = (int)(((float)sw->vp.full_width - width)) / 2;
|
||||||
|
sw->vp.y = (int)(((float)sw->vp.full_height - height)) / 2;
|
||||||
|
|
||||||
|
sw->vp.width = width;
|
||||||
|
sw->vp.height = height;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
desired_aspect = video_driver_get_aspect_ratio();
|
||||||
|
|
||||||
|
/* We crash if >1.0f */
|
||||||
|
printf("[Video] Aspect: %f\n", desired_aspect);
|
||||||
|
/*if (desired_aspect > 1.8f)
|
||||||
|
desired_aspect = 1.7778f;
|
||||||
|
|
||||||
|
if (desired_aspect < 1.2f && desired_aspect != 0.0f)
|
||||||
|
desired_aspect = 1.0f;*/
|
||||||
|
|
||||||
|
if (settings->bools.video_scale_integer)
|
||||||
|
{
|
||||||
|
video_viewport_get_scaled_integer(&sw->vp, sw->vp.full_width, sw->vp.full_height, desired_aspect, sw->keep_aspect);
|
||||||
|
}
|
||||||
|
else if (sw->keep_aspect)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_MENU)
|
||||||
|
if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
|
||||||
|
{
|
||||||
|
sw->vp.x = sw->vp.y = 0;
|
||||||
|
sw->vp.width = width;
|
||||||
|
sw->vp.height = height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
float delta;
|
||||||
|
float device_aspect = ((float)sw->vp.full_width) / sw->vp.full_height;
|
||||||
|
|
||||||
|
if (fabsf(device_aspect - desired_aspect) < 0.0001f)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the aspect ratios of screen and desired aspect
|
||||||
|
* ratio are sufficiently equal (floating point stuff),
|
||||||
|
* assume they are actually equal.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else if (device_aspect > desired_aspect)
|
||||||
|
{
|
||||||
|
delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f;
|
||||||
|
x = (int)roundf(width * (0.5f - delta));
|
||||||
|
width = (unsigned)roundf(2.0f * width * delta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f;
|
||||||
|
y = (int)roundf(height * (0.5f - delta));
|
||||||
|
height = (unsigned)roundf(2.0f * height * delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sw->vp.x = x;
|
||||||
|
sw->vp.y = y;
|
||||||
|
|
||||||
|
sw->vp.width = width;
|
||||||
|
sw->vp.height = height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sw->vp.x = sw->vp.y = 0;
|
||||||
|
sw->vp.width = width;
|
||||||
|
sw->vp.height = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = (switch_video_t *)data;
|
||||||
|
|
||||||
|
if (!sw)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sw->keep_aspect = true;
|
||||||
|
sw->o_size = false;
|
||||||
|
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
switch (aspect_ratio_idx)
|
||||||
|
{
|
||||||
|
case ASPECT_RATIO_SQUARE:
|
||||||
|
video_driver_set_viewport_square_pixel();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASPECT_RATIO_CORE:
|
||||||
|
video_driver_set_viewport_core();
|
||||||
|
sw->o_size = true;
|
||||||
|
sw->keep_aspect = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASPECT_RATIO_CONFIG:
|
||||||
|
video_driver_set_viewport_config();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASPECT_RATIO_CUSTOM:
|
||||||
|
if (settings->bools.video_scale_integer)
|
||||||
|
{
|
||||||
|
video_driver_set_viewport_core();
|
||||||
|
sw->o_size = true;
|
||||||
|
sw->keep_aspect = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
video_driver_set_aspect_ratio_value(aspectratio_lut[aspect_ratio_idx].value);
|
||||||
|
|
||||||
|
sw->should_resize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_frame(void *data, const void *frame,
|
||||||
|
unsigned width, unsigned height,
|
||||||
|
uint64_t frame_count, unsigned pitch,
|
||||||
|
const char *msg, video_frame_info_t *video_info)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = data;
|
||||||
|
uint32_t *out_buffer = NULL;
|
||||||
|
bool ffwd_mode = video_info->input_driver_nonblock_state;
|
||||||
|
|
||||||
|
if (!frame)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (ffwd_mode && !sw->is_threaded)
|
||||||
|
{
|
||||||
|
/* render every 4th frame when in ffwd mode and not threaded */
|
||||||
|
if ((frame_count % 4) != 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sw->should_resize || width != sw->last_width || height != sw->last_height)
|
||||||
|
{
|
||||||
|
printf("[Video] Requesting new size: width %i height %i\n", width, height);
|
||||||
|
printf("[Video] fw: %i fh: %i w: %i h: %i x: %i y: %i\n", sw->vp.full_width, sw->vp.full_height, sw->vp.width, sw->vp.height, sw->vp.x, sw->vp.y);
|
||||||
|
switch_update_viewport(sw, video_info);
|
||||||
|
printf("[Video] fw: %i fh: %i w: %i h: %i x: %i y: %i\n", sw->vp.full_width, sw->vp.full_height, sw->vp.width, sw->vp.height, sw->vp.x, sw->vp.y);
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
sw->vp.width = MIN(sw->vp.width, sw->vp.full_width);
|
||||||
|
sw->vp.height = MIN(sw->vp.height, sw->vp.full_height);
|
||||||
|
|
||||||
|
scaler_ctx_gen_reset(&sw->scaler);
|
||||||
|
|
||||||
|
sw->scaler.in_width = width;
|
||||||
|
sw->scaler.in_height = height;
|
||||||
|
sw->scaler.in_stride = pitch;
|
||||||
|
sw->scaler.in_fmt = sw->rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
|
||||||
|
|
||||||
|
if (!sw->smooth)
|
||||||
|
{
|
||||||
|
sw->scaler.out_width = sw->vp.width;
|
||||||
|
sw->scaler.out_height = sw->vp.height;
|
||||||
|
sw->scaler.out_stride = sw->vp.full_width * sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sw->scaler.out_width = width;
|
||||||
|
sw->scaler.out_height = height;
|
||||||
|
sw->scaler.out_stride = width * sizeof(uint32_t);
|
||||||
|
|
||||||
|
float screen_ratio = (float)sw->vp.full_width / sw->vp.full_height;
|
||||||
|
float tgt_ratio = (float)sw->vp.width / sw->vp.height;
|
||||||
|
|
||||||
|
sw->hw_scale.width = ceil(screen_ratio / tgt_ratio * sw->scaler.out_width);
|
||||||
|
sw->hw_scale.height = sw->scaler.out_height;
|
||||||
|
sw->hw_scale.x_offset = ceil((sw->hw_scale.width - sw->scaler.out_width) / 2.0);
|
||||||
|
if (!video_info->menu_is_alive)
|
||||||
|
{
|
||||||
|
clear_screen(sw);
|
||||||
|
gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sw->scaler.out_fmt = SCALER_FMT_ABGR8888;
|
||||||
|
|
||||||
|
sw->scaler.scaler_type = SCALER_TYPE_POINT;
|
||||||
|
|
||||||
|
if (!scaler_ctx_gen_filter(&sw->scaler))
|
||||||
|
{
|
||||||
|
printf("failed to generate scaler for main image\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sw->last_width = width;
|
||||||
|
sw->last_height = height;
|
||||||
|
|
||||||
|
sw->should_resize = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_buffer = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
|
||||||
|
|
||||||
|
if (sw->in_menu && !video_info->menu_is_alive && sw->smooth)
|
||||||
|
{
|
||||||
|
memset(out_buffer, 0, sw->vp.full_width * sw->vp.full_height * 4);
|
||||||
|
gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
|
||||||
|
}
|
||||||
|
sw->in_menu = video_info->menu_is_alive;
|
||||||
|
|
||||||
|
if (sw->menu_texture.enable)
|
||||||
|
{
|
||||||
|
menu_driver_frame(video_info);
|
||||||
|
|
||||||
|
if (sw->menu_texture.pixels)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_NXRGUI
|
||||||
|
gfx_slow_swizzling_blit(out_buffer, nx_backgroundImage, sw->vp.full_width, sw->vp.full_height, 0, 0, false);
|
||||||
|
#else
|
||||||
|
memset(out_buffer, 0, gfxGetFramebufferSize());
|
||||||
|
#endif
|
||||||
|
scaler_ctx_scale(&sw->menu_texture.scaler, sw->tmp_image + ((sw->vp.full_height - sw->menu_texture.tgth) / 2) * sw->vp.full_width + ((sw->vp.full_width - sw->menu_texture.tgtw) / 2), sw->menu_texture.pixels);
|
||||||
|
gfx_slow_swizzling_blit(out_buffer, sw->tmp_image, sw->vp.full_width, sw->vp.full_height, 0, 0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sw->smooth) /* bilinear */
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
unsigned x, y;
|
||||||
|
struct scaler_ctx *ctx = &sw->scaler;
|
||||||
|
scaler_ctx_scale_direct(ctx, sw->image, frame);
|
||||||
|
w = sw->scaler.out_width;
|
||||||
|
h = sw->scaler.out_height;
|
||||||
|
|
||||||
|
for (y = 0; y < h; y++)
|
||||||
|
for (x = 0; x < w; x++)
|
||||||
|
out_buffer[gfxGetFramebufferDisplayOffset(x + sw->hw_scale.x_offset, y)] = sw->image[y * w + x];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct scaler_ctx *ctx = &sw->scaler;
|
||||||
|
scaler_ctx_scale(ctx, sw->image + (sw->vp.y * sw->vp.full_width) + sw->vp.x, frame);
|
||||||
|
gfx_slow_swizzling_blit(out_buffer, sw->image, sw->vp.full_width, sw->vp.full_height, 0, 0, false);
|
||||||
|
#ifdef HAVE_NXRGUI
|
||||||
|
if (tmp_overlay)
|
||||||
|
gfx_slow_swizzling_blit(out_buffer, tmp_overlay, sw->vp.full_width, sw->vp.full_height, 0, 0, true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video_info->statistics_show && !sw->smooth)
|
||||||
|
{
|
||||||
|
struct font_params *osd_params = (struct font_params *)&video_info->osd_stat_params;
|
||||||
|
|
||||||
|
if (osd_params)
|
||||||
|
font_driver_render_msg(video_info, NULL, video_info->stat_text,
|
||||||
|
(const struct font_params *)&video_info->osd_stat_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg)
|
||||||
|
font_driver_render_msg(video_info, NULL, msg, NULL);
|
||||||
|
|
||||||
|
gfxFlushBuffers();
|
||||||
|
gfxSwapBuffers();
|
||||||
|
if (sw->vsync)
|
||||||
|
gfxWaitForVsync();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_set_nonblock_state(void *data, bool toggle)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = data;
|
||||||
|
sw->vsync = !toggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_alive(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_focus(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_suppress_screensaver(void *data, bool enable)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)enable;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_has_windowed(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_free(void *data)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = data;
|
||||||
|
if (sw->menu_texture.pixels)
|
||||||
|
free(sw->menu_texture.pixels);
|
||||||
|
|
||||||
|
free(sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_set_shader(void *data,
|
||||||
|
enum rarch_shader_type type, const char *path)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)type;
|
||||||
|
(void)path;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_set_rotation(void *data, unsigned rotation)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = data;
|
||||||
|
if (!sw)
|
||||||
|
return;
|
||||||
|
sw->rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_viewport_info(void *data, struct video_viewport *vp)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = data;
|
||||||
|
*vp = sw->vp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_read_viewport(void *data, uint8_t *buffer, bool is_idle)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)buffer;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_set_texture_frame(
|
||||||
|
void *data, const void *frame, bool rgb32,
|
||||||
|
unsigned width, unsigned height, float alpha)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = data;
|
||||||
|
size_t sz = width * height * (rgb32 ? 4 : 2);
|
||||||
|
|
||||||
|
if (!sw->menu_texture.pixels ||
|
||||||
|
sw->menu_texture.width != width ||
|
||||||
|
sw->menu_texture.height != height)
|
||||||
|
{
|
||||||
|
int xsf, ysf, sf;
|
||||||
|
struct scaler_ctx *sctx = NULL;
|
||||||
|
|
||||||
|
if (sw->menu_texture.pixels)
|
||||||
|
realloc(sw->menu_texture.pixels, sz);
|
||||||
|
else
|
||||||
|
sw->menu_texture.pixels = malloc(sz);
|
||||||
|
|
||||||
|
if (!sw->menu_texture.pixels)
|
||||||
|
{
|
||||||
|
printf("failed to allocate buffer for menu texture\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xsf = 1280 / width;
|
||||||
|
ysf = 720 / height;
|
||||||
|
sf = xsf;
|
||||||
|
|
||||||
|
if (ysf < sf)
|
||||||
|
sf = ysf;
|
||||||
|
|
||||||
|
sw->menu_texture.width = width;
|
||||||
|
sw->menu_texture.height = height;
|
||||||
|
sw->menu_texture.tgtw = width * sf;
|
||||||
|
sw->menu_texture.tgth = height * sf;
|
||||||
|
|
||||||
|
sctx = &sw->menu_texture.scaler;
|
||||||
|
scaler_ctx_gen_reset(sctx);
|
||||||
|
|
||||||
|
sctx->in_width = width;
|
||||||
|
sctx->in_height = height;
|
||||||
|
sctx->in_stride = width * (rgb32 ? 4 : 2);
|
||||||
|
sctx->in_fmt = rgb32 ? SCALER_FMT_ARGB8888 : SCALER_FMT_RGB565;
|
||||||
|
sctx->out_width = sw->menu_texture.tgtw;
|
||||||
|
sctx->out_height = sw->menu_texture.tgth;
|
||||||
|
sctx->out_stride = 1280 * 4;
|
||||||
|
sctx->out_fmt = SCALER_FMT_ABGR8888;
|
||||||
|
|
||||||
|
sctx->scaler_type = SCALER_TYPE_POINT;
|
||||||
|
|
||||||
|
if (!scaler_ctx_gen_filter(sctx))
|
||||||
|
{
|
||||||
|
printf("failed to generate scaler for menu texture\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(sw->menu_texture.pixels, frame, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_apply_state_changes(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_set_texture_enable(void *data, bool enable, bool full_screen)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = data;
|
||||||
|
|
||||||
|
if (!sw->menu_texture.enable && enable)
|
||||||
|
gfxConfigureResolution(sw->vp.full_width, sw->vp.full_height);
|
||||||
|
else if (!enable && sw->menu_texture.enable && sw->smooth)
|
||||||
|
{
|
||||||
|
clear_screen(sw);
|
||||||
|
gfxConfigureResolution(sw->hw_scale.width, sw->hw_scale.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
sw->menu_texture.enable = enable;
|
||||||
|
sw->menu_texture.fullscreen = full_screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_set_osd_msg(void *data,
|
||||||
|
video_frame_info_t *video_info,
|
||||||
|
const char *msg,
|
||||||
|
const void *params, void *font)
|
||||||
|
{
|
||||||
|
switch_video_t *sw = (switch_video_t *)data;
|
||||||
|
|
||||||
|
if (sw)
|
||||||
|
font_driver_render_msg(video_info, font, msg, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_OVERLAY
|
||||||
|
static void switch_overlay_enable(void *data, bool state)
|
||||||
|
{
|
||||||
|
printf("[Video] Enabled Overlay\n");
|
||||||
|
|
||||||
|
switch_video_t *swa = (switch_video_t *)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
swa->overlay_enabled = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_overlay_load(void *data,
|
||||||
|
const void *image_data, unsigned num_images)
|
||||||
|
{
|
||||||
|
switch_video_t *swa = (switch_video_t *)data;
|
||||||
|
struct texture_image *images = (struct texture_image *)image_data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
swa->overlay = images;
|
||||||
|
swa->overlay_enabled = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_overlay_tex_geom(void *data,
|
||||||
|
unsigned idx, float x, float y, float w, float h)
|
||||||
|
{
|
||||||
|
switch_video_t *swa = (switch_video_t *)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_overlay_vertex_geom(void *data,
|
||||||
|
unsigned idx, float x, float y, float w, float h)
|
||||||
|
{
|
||||||
|
switch_video_t *swa = (switch_video_t *)data;
|
||||||
|
|
||||||
|
if (!swa)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_overlay_full_screen(void *data, bool enable)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_overlay_set_alpha(void *data, unsigned idx, float mod)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)idx;
|
||||||
|
(void)mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const video_overlay_interface_t switch_overlay = {
|
||||||
|
switch_overlay_enable,
|
||||||
|
switch_overlay_load,
|
||||||
|
switch_overlay_tex_geom,
|
||||||
|
switch_overlay_vertex_geom,
|
||||||
|
switch_overlay_full_screen,
|
||||||
|
switch_overlay_set_alpha,
|
||||||
|
};
|
||||||
|
|
||||||
|
void switch_overlay_interface(void *data, const video_overlay_interface_t **iface)
|
||||||
|
{
|
||||||
|
switch_video_t *swa = (switch_video_t *)data;
|
||||||
|
if (!swa)
|
||||||
|
return;
|
||||||
|
*iface = &switch_overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const video_poke_interface_t switch_poke_interface = {
|
||||||
|
NULL, /* get_flags */
|
||||||
|
NULL, /* set_coords */
|
||||||
|
NULL, /* set_mvp */
|
||||||
|
NULL, /* load_texture */
|
||||||
|
NULL, /* unload_texture */
|
||||||
|
NULL, /* set_video_mode */
|
||||||
|
NULL, /* get_refresh_rate */
|
||||||
|
NULL, /* set_filtering */
|
||||||
|
NULL, /* get_video_output_size */
|
||||||
|
NULL, /* get_video_output_prev */
|
||||||
|
NULL, /* get_video_output_next */
|
||||||
|
NULL, /* get_current_framebuffer */
|
||||||
|
NULL, /* get_proc_address */
|
||||||
|
switch_set_aspect_ratio, /* set_aspect_ratio */
|
||||||
|
switch_apply_state_changes, /* apply_state_changes */
|
||||||
|
switch_set_texture_frame,
|
||||||
|
switch_set_texture_enable,
|
||||||
|
switch_set_osd_msg,
|
||||||
|
NULL, /* show_mouse */
|
||||||
|
NULL, /* grab_mouse_toggle */
|
||||||
|
NULL, /* get_current_shader */
|
||||||
|
NULL, /* get_current_software_framebuffer */
|
||||||
|
NULL, /* get_hw_render_interface */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void switch_get_poke_interface(void *data,
|
||||||
|
const video_poke_interface_t **iface)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
*iface = &switch_poke_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
video_driver_t video_switch = {
|
||||||
|
switch_init,
|
||||||
|
switch_frame,
|
||||||
|
switch_set_nonblock_state,
|
||||||
|
switch_alive,
|
||||||
|
switch_focus,
|
||||||
|
switch_suppress_screensaver,
|
||||||
|
switch_has_windowed,
|
||||||
|
switch_set_shader,
|
||||||
|
switch_free,
|
||||||
|
"switch",
|
||||||
|
NULL, /* set_viewport */
|
||||||
|
switch_set_rotation,
|
||||||
|
switch_viewport_info,
|
||||||
|
switch_read_viewport,
|
||||||
|
NULL, /* read_frame_raw */
|
||||||
|
#ifdef HAVE_OVERLAY
|
||||||
|
switch_overlay_interface, /* switch_overlay_interface */
|
||||||
|
#endif
|
||||||
|
switch_get_poke_interface,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* vim: set ts=3 sw=3 */
|
|
@ -77,7 +77,7 @@ static PFNVGCREATEEGLIMAGETARGETKHRPROC pvgCreateEGLImageTargetKHR;
|
||||||
|
|
||||||
static void vg_set_nonblock_state(void *data, bool state)
|
static void vg_set_nonblock_state(void *data, bool state)
|
||||||
{
|
{
|
||||||
unsigned interval = state ? 0 : 1;
|
int interval = state ? 0 : 1;
|
||||||
video_context_driver_swap_interval(&interval);
|
video_context_driver_swap_interval(&interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,13 +97,14 @@ static void *vg_init(const video_info_t *video,
|
||||||
gfx_ctx_mode_t mode;
|
gfx_ctx_mode_t mode;
|
||||||
gfx_ctx_input_t inp;
|
gfx_ctx_input_t inp;
|
||||||
gfx_ctx_aspect_t aspect_data;
|
gfx_ctx_aspect_t aspect_data;
|
||||||
unsigned interval;
|
|
||||||
unsigned temp_width = 0, temp_height = 0;
|
|
||||||
unsigned win_width, win_height;
|
unsigned win_width, win_height;
|
||||||
VGfloat clearColor[4] = {0, 0, 0, 1};
|
VGfloat clearColor[4] = {0, 0, 0, 1};
|
||||||
settings_t *settings = config_get_ptr();
|
int interval = 0;
|
||||||
vg_t *vg = (vg_t*)calloc(1, sizeof(vg_t));
|
unsigned temp_width = 0;
|
||||||
const gfx_ctx_driver_t *ctx = video_context_driver_init_first(
|
unsigned temp_height = 0;
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
vg_t *vg = (vg_t*)calloc(1, sizeof(vg_t));
|
||||||
|
const gfx_ctx_driver_t *ctx = video_context_driver_init_first(
|
||||||
vg, settings->arrays.video_context_driver,
|
vg, settings->arrays.video_context_driver,
|
||||||
GFX_CTX_OPENVG_API, 0, 0, false);
|
GFX_CTX_OPENVG_API, 0, 0, false);
|
||||||
|
|
||||||
|
|
|
@ -854,6 +854,8 @@ static void vulkan_init_static_resources(vk_t *vk)
|
||||||
uint32_t blank[4 * 4];
|
uint32_t blank[4 * 4];
|
||||||
VkCommandPoolCreateInfo pool_info = {
|
VkCommandPoolCreateInfo pool_info = {
|
||||||
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
|
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
|
||||||
|
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
|
|
||||||
/* Create the pipeline cache. */
|
/* Create the pipeline cache. */
|
||||||
VkPipelineCacheCreateInfo cache = {
|
VkPipelineCacheCreateInfo cache = {
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
||||||
|
@ -1092,8 +1094,8 @@ static void vulkan_init_readback(vk_t *vk)
|
||||||
* not initialized yet.
|
* not initialized yet.
|
||||||
*/
|
*/
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
bool *recording_enabled = recording_is_enabled();
|
bool recording_enabled = recording_is_enabled();
|
||||||
vk->readback.streamed = settings->bools.video_gpu_record && *recording_enabled;
|
vk->readback.streamed = settings->bools.video_gpu_record && recording_enabled;
|
||||||
|
|
||||||
if (!vk->readback.streamed)
|
if (!vk->readback.streamed)
|
||||||
return;
|
return;
|
||||||
|
@ -1119,10 +1121,10 @@ static void *vulkan_init(const video_info_t *video,
|
||||||
{
|
{
|
||||||
gfx_ctx_mode_t mode;
|
gfx_ctx_mode_t mode;
|
||||||
gfx_ctx_input_t inp;
|
gfx_ctx_input_t inp;
|
||||||
unsigned interval;
|
|
||||||
unsigned full_x, full_y;
|
unsigned full_x, full_y;
|
||||||
unsigned win_width;
|
unsigned win_width;
|
||||||
unsigned win_height;
|
unsigned win_height;
|
||||||
|
int interval = 0;
|
||||||
unsigned temp_width = 0;
|
unsigned temp_width = 0;
|
||||||
unsigned temp_height = 0;
|
unsigned temp_height = 0;
|
||||||
const gfx_ctx_driver_t *ctx_driver = NULL;
|
const gfx_ctx_driver_t *ctx_driver = NULL;
|
||||||
|
@ -1257,7 +1259,7 @@ static void vulkan_check_swapchain(vk_t *vk)
|
||||||
|
|
||||||
static void vulkan_set_nonblock_state(void *data, bool state)
|
static void vulkan_set_nonblock_state(void *data, bool state)
|
||||||
{
|
{
|
||||||
unsigned interval;
|
int interval = 0;
|
||||||
vk_t *vk = (vk_t*)data;
|
vk_t *vk = (vk_t*)data;
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
@ -1266,7 +1268,9 @@ static void vulkan_set_nonblock_state(void *data, bool state)
|
||||||
|
|
||||||
RARCH_LOG("[Vulkan]: VSync => %s\n", state ? "off" : "on");
|
RARCH_LOG("[Vulkan]: VSync => %s\n", state ? "off" : "on");
|
||||||
|
|
||||||
interval = state ? 0 : settings->uints.video_swap_interval;
|
if (!state)
|
||||||
|
interval = settings->uints.video_swap_interval;
|
||||||
|
|
||||||
video_context_driver_swap_interval(&interval);
|
video_context_driver_swap_interval(&interval);
|
||||||
|
|
||||||
/* Changing vsync might require recreating the swapchain, which means new VkImages
|
/* Changing vsync might require recreating the swapchain, which means new VkImages
|
||||||
|
@ -1509,23 +1513,22 @@ static void vulkan_set_viewport(void *data, unsigned viewport_width,
|
||||||
|
|
||||||
static void vulkan_readback(vk_t *vk)
|
static void vulkan_readback(vk_t *vk)
|
||||||
{
|
{
|
||||||
VkImageCopy region;
|
VkBufferImageCopy region;
|
||||||
struct vk_texture *staging;
|
struct vk_texture *staging;
|
||||||
struct video_viewport vp;
|
struct video_viewport vp;
|
||||||
|
VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER };
|
||||||
|
|
||||||
vulkan_viewport_info(vk, &vp);
|
vulkan_viewport_info(vk, &vp);
|
||||||
memset(®ion, 0, sizeof(region));
|
memset(®ion, 0, sizeof(region));
|
||||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.srcSubresource.layerCount = 1;
|
region.imageSubresource.layerCount = 1;
|
||||||
region.dstSubresource = region.srcSubresource;
|
region.imageOffset.x = vp.x;
|
||||||
|
region.imageOffset.y = vp.y;
|
||||||
|
region.imageExtent.width = vp.width;
|
||||||
|
region.imageExtent.height = vp.height;
|
||||||
|
region.imageExtent.depth = 1;
|
||||||
|
|
||||||
region.srcOffset.x = vp.x;
|
/* FIXME: We won't actually get format conversion with vkCmdCopyImageToBuffer, so have to check
|
||||||
region.srcOffset.y = vp.y;
|
|
||||||
region.extent.width = vp.width;
|
|
||||||
region.extent.height = vp.height;
|
|
||||||
region.extent.depth = 1;
|
|
||||||
|
|
||||||
/* FIXME: We won't actually get format conversion with vkCmdCopyImage, so have to check
|
|
||||||
* properly for this. BGRA seems to be the default for all swapchains. */
|
* properly for this. BGRA seems to be the default for all swapchains. */
|
||||||
if (vk->context->swapchain_format != VK_FORMAT_B8G8R8A8_UNORM)
|
if (vk->context->swapchain_format != VK_FORMAT_B8G8R8A8_UNORM)
|
||||||
RARCH_WARN("[Vulkan]: Backbuffer is not BGRA8888, readbacks might not work properly.\n");
|
RARCH_WARN("[Vulkan]: Backbuffer is not BGRA8888, readbacks might not work properly.\n");
|
||||||
|
@ -1537,25 +1540,18 @@ static void vulkan_readback(vk_t *vk)
|
||||||
VK_FORMAT_B8G8R8A8_UNORM,
|
VK_FORMAT_B8G8R8A8_UNORM,
|
||||||
NULL, NULL, VULKAN_TEXTURE_READBACK);
|
NULL, NULL, VULKAN_TEXTURE_READBACK);
|
||||||
|
|
||||||
/* Go through the long-winded dance of remapping image layouts. */
|
vkCmdCopyImageToBuffer(vk->cmd, vk->chain->backbuffer.image,
|
||||||
vulkan_image_layout_transition(vk, vk->cmd, staging->image,
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
0, VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
|
||||||
|
|
||||||
vkCmdCopyImage(vk->cmd, vk->chain->backbuffer.image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
staging->image,
|
staging->buffer,
|
||||||
VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
1, ®ion);
|
1, ®ion);
|
||||||
|
|
||||||
/* Make the data visible to host. */
|
/* Make the data visible to host. */
|
||||||
vulkan_image_layout_transition(vk, vk->cmd, staging->image,
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
|
barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
|
vkCmdPipelineBarrier(vk->cmd,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
VK_PIPELINE_STAGE_HOST_BIT);
|
VK_PIPELINE_STAGE_HOST_BIT, 0,
|
||||||
|
1, &barrier, 0, NULL, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vulkan_inject_black_frame(vk_t *vk, video_frame_info_t *video_info)
|
static void vulkan_inject_black_frame(vk_t *vk, video_frame_info_t *video_info)
|
||||||
|
@ -1784,7 +1780,7 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||||
(vulkan_filter_chain_t*)vk->filter_chain,
|
(vulkan_filter_chain_t*)vk->filter_chain,
|
||||||
vk->cmd, &vk->vk_vp);
|
vk->cmd, &vk->vk_vp);
|
||||||
/* Render to backbuffer. */
|
/* Render to backbuffer. */
|
||||||
if (chain->backbuffer.image != VK_NULL_HANDLE)
|
if (chain->backbuffer.image != VK_NULL_HANDLE && vk->context->has_acquired_swapchain)
|
||||||
{
|
{
|
||||||
rp_info.renderPass = vk->render_pass;
|
rp_info.renderPass = vk->render_pass;
|
||||||
rp_info.framebuffer = chain->backbuffer.framebuffer;
|
rp_info.framebuffer = chain->backbuffer.framebuffer;
|
||||||
|
@ -1880,6 +1876,7 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||||
vulkan_filter_chain_end_frame((vulkan_filter_chain_t*)vk->filter_chain, vk->cmd);
|
vulkan_filter_chain_end_frame((vulkan_filter_chain_t*)vk->filter_chain, vk->cmd);
|
||||||
|
|
||||||
if (chain->backbuffer.image != VK_NULL_HANDLE &&
|
if (chain->backbuffer.image != VK_NULL_HANDLE &&
|
||||||
|
vk->context->has_acquired_swapchain &&
|
||||||
(vk->readback.pending || vk->readback.streamed))
|
(vk->readback.pending || vk->readback.streamed))
|
||||||
{
|
{
|
||||||
/* We cannot safely read back from an image which
|
/* We cannot safely read back from an image which
|
||||||
|
@ -1911,7 +1908,8 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||||
|
|
||||||
vk->readback.pending = false;
|
vk->readback.pending = false;
|
||||||
}
|
}
|
||||||
else if (chain->backbuffer.image != VK_NULL_HANDLE)
|
else if (chain->backbuffer.image != VK_NULL_HANDLE &&
|
||||||
|
vk->context->has_acquired_swapchain)
|
||||||
{
|
{
|
||||||
/* Prepare backbuffer for presentation. */
|
/* Prepare backbuffer for presentation. */
|
||||||
vulkan_image_layout_transition(vk, vk->cmd,
|
vulkan_image_layout_transition(vk, vk->cmd,
|
||||||
|
@ -1971,8 +1969,11 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||||
|
|
||||||
submit_info.signalSemaphoreCount = 0;
|
submit_info.signalSemaphoreCount = 0;
|
||||||
|
|
||||||
if (vk->context->swapchain_semaphores[frame_index] != VK_NULL_HANDLE)
|
if (vk->context->swapchain_semaphores[frame_index] != VK_NULL_HANDLE &&
|
||||||
|
vk->context->has_acquired_swapchain)
|
||||||
|
{
|
||||||
signal_semaphores[submit_info.signalSemaphoreCount++] = vk->context->swapchain_semaphores[frame_index];
|
signal_semaphores[submit_info.signalSemaphoreCount++] = vk->context->swapchain_semaphores[frame_index];
|
||||||
|
}
|
||||||
|
|
||||||
if (vk->hw.signal_semaphore != VK_NULL_HANDLE)
|
if (vk->hw.signal_semaphore != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
|
@ -2014,7 +2015,9 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||||
/* Disable BFI during fast forward, slow-motion,
|
/* Disable BFI during fast forward, slow-motion,
|
||||||
* and pause to prevent flicker. */
|
* and pause to prevent flicker. */
|
||||||
if (
|
if (
|
||||||
video_info->black_frame_insertion
|
chain->backbuffer.image != VK_NULL_HANDLE
|
||||||
|
&& vk->context->has_acquired_swapchain
|
||||||
|
&& video_info->black_frame_insertion
|
||||||
&& !video_info->input_driver_nonblock_state
|
&& !video_info->input_driver_nonblock_state
|
||||||
&& !video_info->runloop_is_slowmotion
|
&& !video_info->runloop_is_slowmotion
|
||||||
&& !video_info->runloop_is_paused)
|
&& !video_info->runloop_is_paused)
|
||||||
|
@ -2023,7 +2026,8 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Vulkan doesn't directly support swap_interval > 1, so we fake it by duping out more frames. */
|
/* Vulkan doesn't directly support swap_interval > 1, so we fake it by duping out more frames. */
|
||||||
if (vk->context->swap_interval > 1 && !vk->context->swap_interval_emulation_lock)
|
if ( vk->context->swap_interval > 1
|
||||||
|
&& !vk->context->swap_interval_emulation_lock)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
vk->context->swap_interval_emulation_lock = true;
|
vk->context->swap_interval_emulation_lock = true;
|
||||||
|
|
|
@ -60,7 +60,7 @@ typedef struct
|
||||||
gfx_ctx_vulkan_data_t vk;
|
gfx_ctx_vulkan_data_t vk;
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
unsigned swap_interval;
|
int swap_interval;
|
||||||
#endif
|
#endif
|
||||||
} android_ctx_data_t;
|
} android_ctx_data_t;
|
||||||
|
|
||||||
|
@ -507,7 +507,7 @@ static void android_gfx_ctx_swap_buffers(void *data, void *data2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_gfx_ctx_set_swap_interval(void *data, unsigned swap_interval)
|
static void android_gfx_ctx_set_swap_interval(void *data, int swap_interval)
|
||||||
{
|
{
|
||||||
android_ctx_data_t *and = (android_ctx_data_t*)data;
|
android_ctx_data_t *and = (android_ctx_data_t*)data;
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ typedef struct gfx_ctx_cgl_data
|
||||||
int width, height;
|
int width, height;
|
||||||
} gfx_ctx_cgl_data_t;
|
} gfx_ctx_cgl_data_t;
|
||||||
|
|
||||||
static void gfx_ctx_cgl_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_cgl_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
gfx_ctx_cgl_data_t *cgl = (gfx_ctx_cgl_data_t*)data;
|
gfx_ctx_cgl_data_t *cgl = (gfx_ctx_cgl_data_t*)data;
|
||||||
GLint params = interval;
|
GLint params = interval;
|
||||||
|
|
|
@ -81,7 +81,7 @@ typedef struct gfx_ctx_drm_data
|
||||||
egl_ctx_data_t egl;
|
egl_ctx_data_t egl;
|
||||||
#endif
|
#endif
|
||||||
int fd;
|
int fd;
|
||||||
unsigned interval;
|
int interval;
|
||||||
unsigned fb_width;
|
unsigned fb_width;
|
||||||
unsigned fb_height;
|
unsigned fb_height;
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_drm_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_drm_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data;
|
gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data;
|
||||||
drm->interval = interval;
|
drm->interval = interval;
|
||||||
|
|
|
@ -49,14 +49,14 @@ static int emscripten_initial_width;
|
||||||
static int emscripten_initial_height;
|
static int emscripten_initial_height;
|
||||||
static enum gfx_ctx_api emscripten_api = GFX_CTX_NONE;
|
static enum gfx_ctx_api emscripten_api = GFX_CTX_NONE;
|
||||||
|
|
||||||
static void gfx_ctx_emscripten_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_emscripten_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
|
|
||||||
if (interval == 0)
|
if (interval == 0)
|
||||||
emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0);
|
emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0);
|
||||||
else
|
else
|
||||||
emscripten_set_main_loop_timing(EM_TIMING_RAF, (int)interval);
|
emscripten_set_main_loop_timing(EM_TIMING_RAF, interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_emscripten_get_canvas_size(int *width, int *height)
|
static void gfx_ctx_emscripten_get_canvas_size(int *width, int *height)
|
||||||
|
|
|
@ -45,7 +45,7 @@ static HDC win32_gdi_hdc;
|
||||||
|
|
||||||
static unsigned win32_gdi_major = 0;
|
static unsigned win32_gdi_major = 0;
|
||||||
static unsigned win32_gdi_minor = 0;
|
static unsigned win32_gdi_minor = 0;
|
||||||
static unsigned win32_gdi_interval = 0;
|
static int win32_gdi_interval = 0;
|
||||||
static enum gfx_ctx_api win32_gdi_api = GFX_CTX_NONE;
|
static enum gfx_ctx_api win32_gdi_api = GFX_CTX_NONE;
|
||||||
|
|
||||||
typedef struct gfx_ctx_gdi_data
|
typedef struct gfx_ctx_gdi_data
|
||||||
|
@ -308,7 +308,7 @@ static void gfx_ctx_gdi_show_mouse(void *data, bool state)
|
||||||
win32_show_cursor(state);
|
win32_show_cursor(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_gdi_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_gdi_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
(void)interval;
|
(void)interval;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#include "../video_driver.h"
|
#include "../video_driver.h"
|
||||||
|
|
||||||
static void gfx_ctx_null_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_null_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
(void)interval;
|
(void)interval;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
gfx_ctx_vulkan_data_t vk;
|
gfx_ctx_vulkan_data_t vk;
|
||||||
unsigned swap_interval;
|
int swap_interval;
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
} khr_display_ctx_data_t;
|
} khr_display_ctx_data_t;
|
||||||
|
@ -99,7 +99,8 @@ static bool gfx_ctx_khr_display_set_resize(void *data,
|
||||||
|
|
||||||
khr->width = width;
|
khr->width = width;
|
||||||
khr->height = height;
|
khr->height = height;
|
||||||
if (!vulkan_create_swapchain(&khr->vk, khr->width, khr->height, khr->swap_interval))
|
if (!vulkan_create_swapchain(&khr->vk, khr->width, khr->height,
|
||||||
|
khr->swap_interval))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Vulkan]: Failed to update swapchain.\n");
|
RARCH_ERR("[Vulkan]: Failed to update swapchain.\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -189,9 +190,11 @@ static bool gfx_ctx_khr_display_suppress_screensaver(void *data, bool enable)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_khr_display_set_swap_interval(void *data, unsigned swap_interval)
|
static void gfx_ctx_khr_display_set_swap_interval(void *data,
|
||||||
|
int swap_interval)
|
||||||
{
|
{
|
||||||
khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data;
|
khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data;
|
||||||
|
|
||||||
if (khr->swap_interval != swap_interval)
|
if (khr->swap_interval != swap_interval)
|
||||||
{
|
{
|
||||||
khr->swap_interval = swap_interval;
|
khr->swap_interval = swap_interval;
|
||||||
|
|
|
@ -88,7 +88,7 @@ typedef struct cocoa_ctx_data
|
||||||
bool core_hw_context_enable;
|
bool core_hw_context_enable;
|
||||||
#ifdef HAVE_VULKAN
|
#ifdef HAVE_VULKAN
|
||||||
gfx_ctx_vulkan_data_t vk;
|
gfx_ctx_vulkan_data_t vk;
|
||||||
unsigned swap_interval;
|
int swap_interval;
|
||||||
#endif
|
#endif
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
|
@ -299,7 +299,8 @@ static void *cocoagl_gfx_ctx_init(video_frame_info_t *video_info, void *video_dr
|
||||||
{
|
{
|
||||||
#if defined(HAVE_COCOATOUCH)
|
#if defined(HAVE_COCOATOUCH)
|
||||||
case GFX_CTX_OPENGL_ES_API:
|
case GFX_CTX_OPENGL_ES_API:
|
||||||
[apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL_ES];
|
// setViewType is not (yet?) defined for iOS
|
||||||
|
// [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL_ES];
|
||||||
break;
|
break;
|
||||||
#elif defined(HAVE_COCOA)
|
#elif defined(HAVE_COCOA)
|
||||||
case GFX_CTX_OPENGL_API:
|
case GFX_CTX_OPENGL_API:
|
||||||
|
@ -360,7 +361,7 @@ static bool cocoagl_gfx_ctx_bind_api(void *data, enum gfx_ctx_api api, unsigned
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cocoagl_gfx_ctx_swap_interval(void *data, unsigned interval)
|
static void cocoagl_gfx_ctx_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_VULKAN
|
#ifdef HAVE_VULKAN
|
||||||
cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data;
|
cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data;
|
||||||
|
@ -373,10 +374,10 @@ static void cocoagl_gfx_ctx_swap_interval(void *data, unsigned interval)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_COCOATOUCH) // < No way to disable Vsync on iOS?
|
#if defined(HAVE_COCOATOUCH) // < No way to disable Vsync on iOS?
|
||||||
// Just skip presents so fast forward still works.
|
// Just skip presents so fast forward still works.
|
||||||
g_is_syncing = interval ? true : false;
|
g_is_syncing = interval ? true : false;
|
||||||
g_fast_forward_skips = interval ? 0 : 3;
|
g_fast_forward_skips = interval ? 0 : 3;
|
||||||
#elif defined(HAVE_COCOA)
|
#elif defined(HAVE_COCOA)
|
||||||
GLint value = interval ? 1 : 0;
|
GLint value = interval ? 1 : 0;
|
||||||
[g_context setValues:&value forParameter:NSOpenGLCPSwapInterval];
|
[g_context setValues:&value forParameter:NSOpenGLCPSwapInterval];
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
@ -491,9 +492,10 @@ static bool cocoagl_gfx_ctx_set_video_mode(void *data,
|
||||||
case GFX_CTX_VULKAN_API:
|
case GFX_CTX_VULKAN_API:
|
||||||
#ifdef HAVE_VULKAN
|
#ifdef HAVE_VULKAN
|
||||||
RARCH_LOG("[macOS]: Native window size: %u x %u.\n", cocoa_ctx->width, cocoa_ctx->height);
|
RARCH_LOG("[macOS]: Native window size: %u x %u.\n", cocoa_ctx->width, cocoa_ctx->height);
|
||||||
if (!vulkan_surface_create(&cocoa_ctx->vk, VULKAN_WSI_MVK_MACOS, NULL,
|
if (!vulkan_surface_create(&cocoa_ctx->vk,
|
||||||
(BRIDGE void *)g_view, cocoa_ctx->width, cocoa_ctx->height,
|
VULKAN_WSI_MVK_MACOS, NULL,
|
||||||
cocoa_ctx->swap_interval))
|
(BRIDGE void *)g_view, cocoa_ctx->width, cocoa_ctx->height,
|
||||||
|
cocoa_ctx->swap_interval))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[macOS]: Failed to create surface.\n");
|
RARCH_ERR("[macOS]: Failed to create surface.\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -772,7 +774,8 @@ static bool cocoagl_gfx_ctx_set_resize(void *data, unsigned width, unsigned heig
|
||||||
cocoa_ctx->width = width;
|
cocoa_ctx->width = width;
|
||||||
cocoa_ctx->height = height;
|
cocoa_ctx->height = height;
|
||||||
|
|
||||||
if (vulkan_create_swapchain(&cocoa_ctx->vk, width, height, cocoa_ctx->swap_interval))
|
if (vulkan_create_swapchain(&cocoa_ctx->vk,
|
||||||
|
width, height, cocoa_ctx->swap_interval))
|
||||||
{
|
{
|
||||||
cocoa_ctx->vk.context.invalid_swapchain = true;
|
cocoa_ctx->vk.context.invalid_swapchain = true;
|
||||||
if (cocoa_ctx->vk.created_new_swapchain)
|
if (cocoa_ctx->vk.created_new_swapchain)
|
||||||
|
|
|
@ -244,7 +244,8 @@ static bool gfx_ctx_mali_fbdev_suppress_screensaver(void *data, bool enable)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_mali_fbdev_set_swap_interval(void *data, unsigned swap_interval)
|
static void gfx_ctx_mali_fbdev_set_swap_interval(void *data,
|
||||||
|
int swap_interval)
|
||||||
{
|
{
|
||||||
mali_ctx_data_t *mali = (mali_ctx_data_t*)data;
|
mali_ctx_data_t *mali = (mali_ctx_data_t*)data;
|
||||||
|
|
||||||
|
|
|
@ -225,7 +225,7 @@ static void gfx_ctx_opendingux_swap_buffers(void *data, void *data2)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_opendingux_set_swap_interval(
|
static void gfx_ctx_opendingux_set_swap_interval(
|
||||||
void *data, unsigned swap_interval)
|
void *data, int swap_interval)
|
||||||
{
|
{
|
||||||
opendingux_ctx_data_t *viv = (opendingux_ctx_data_t*)data;
|
opendingux_ctx_data_t *viv = (opendingux_ctx_data_t*)data;
|
||||||
|
|
||||||
|
|
|
@ -240,7 +240,7 @@ static bool osmesa_ctx_bind_api(void *data,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void osmesa_ctx_swap_interval(void *data, unsigned interval)
|
static void osmesa_ctx_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
(void)interval;
|
(void)interval;
|
||||||
|
|
|
@ -140,10 +140,10 @@ static void gfx_ctx_ps3_get_available_resolutions(void)
|
||||||
global->console.screen.resolutions.check = true;
|
global->console.screen.resolutions.check = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_ps3_set_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_ps3_set_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_PSGL)
|
#if defined(HAVE_PSGL)
|
||||||
if (interval)
|
if (interval == 1)
|
||||||
glEnable(GL_VSYNC_SCE);
|
glEnable(GL_VSYNC_SCE);
|
||||||
else
|
else
|
||||||
glDisable(GL_VSYNC_SCE);
|
glDisable(GL_VSYNC_SCE);
|
||||||
|
|
|
@ -417,7 +417,7 @@ dpi_fallback:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_qnx_set_swap_interval(void *data, unsigned swap_interval)
|
static void gfx_ctx_qnx_set_swap_interval(void *data, int swap_interval)
|
||||||
{
|
{
|
||||||
qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
|
qnx_ctx_data_t *qnx = (qnx_ctx_data_t*)data;
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ static bool sdl_ctx_bind_api(void *data,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl_ctx_swap_interval(void *data, unsigned interval)
|
static void sdl_ctx_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL2
|
||||||
|
|
|
@ -151,7 +151,7 @@ static void gfx_ctx_sixel_show_mouse(void *data, bool state)
|
||||||
(void)data;
|
(void)data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_sixel_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_sixel_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
(void)interval;
|
(void)interval;
|
||||||
|
|
|
@ -0,0 +1,287 @@
|
||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||||
|
* Copyright (C) 2018 - M4xw
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "../../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#include "../common/switch_common.h"
|
||||||
|
#include "../../frontend/frontend_driver.h"
|
||||||
|
|
||||||
|
static enum gfx_ctx_api ctx_nx_api = GFX_CTX_OPENGL_API;
|
||||||
|
switch_ctx_data_t *nx_ctx_ptr = NULL;
|
||||||
|
|
||||||
|
void switch_ctx_destroy(void *data)
|
||||||
|
{
|
||||||
|
switch_ctx_data_t *ctx_nx = (switch_ctx_data_t *)data;
|
||||||
|
|
||||||
|
if (ctx_nx)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
egl_destroy(&ctx_nx->egl);
|
||||||
|
#endif
|
||||||
|
ctx_nx->resize = false;
|
||||||
|
free(ctx_nx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_ctx_get_video_size(void *data,
|
||||||
|
unsigned *width, unsigned *height)
|
||||||
|
{
|
||||||
|
switch_ctx_data_t *ctx_nx = (switch_ctx_data_t *)data;
|
||||||
|
|
||||||
|
*width = 1280;
|
||||||
|
*height = 720;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *switch_ctx_init(video_frame_info_t *video_info, void *video_driver)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
EGLint n;
|
||||||
|
EGLint major, minor;
|
||||||
|
static const EGLint attribs[] = {
|
||||||
|
EGL_BLUE_SIZE, 8,
|
||||||
|
EGL_GREEN_SIZE, 8,
|
||||||
|
EGL_RED_SIZE, 8,
|
||||||
|
EGL_ALPHA_SIZE, 8,
|
||||||
|
EGL_NONE};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch_ctx_data_t *ctx_nx = (switch_ctx_data_t *)calloc(1, sizeof(*ctx_nx));
|
||||||
|
|
||||||
|
if (!ctx_nx)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nx_ctx_ptr = ctx_nx;
|
||||||
|
|
||||||
|
//setenv("MESA_NO_ERROR", "1", 1);
|
||||||
|
|
||||||
|
// Uncomment below to enable Mesa logging:
|
||||||
|
//setenv("EGL_LOG_LEVEL", "debug", 1);
|
||||||
|
//setenv("MESA_VERBOSE", "all", 1);
|
||||||
|
//setenv("NOUVEAU_MESA_DEBUG", "1", 1);
|
||||||
|
|
||||||
|
// Uncomment below to enable shader debugging in Nouveau:
|
||||||
|
//setenv("NV50_PROG_OPTIMIZE", "0", 1);
|
||||||
|
//setenv("NV50_PROG_DEBUG", "1", 1);
|
||||||
|
//setenv("NV50_PROG_CHIPSET", "0x120", 1);
|
||||||
|
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
if (!egl_init_context(&ctx_nx->egl, EGL_NONE, EGL_DEFAULT_DISPLAY,
|
||||||
|
&major, &minor, &n, attribs))
|
||||||
|
{
|
||||||
|
egl_report_error();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ctx_nx;
|
||||||
|
|
||||||
|
error:
|
||||||
|
printf("[NXGL]: EGL error: %d.\n", eglGetError());
|
||||||
|
switch_ctx_destroy(video_driver);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_ctx_check_window(void *data, bool *quit,
|
||||||
|
bool *resize, unsigned *width, unsigned *height, bool is_shutdown)
|
||||||
|
{
|
||||||
|
unsigned new_width, new_height;
|
||||||
|
|
||||||
|
switch_ctx_get_video_size(data, &new_width, &new_height);
|
||||||
|
|
||||||
|
if (new_width != *width || new_height != *height)
|
||||||
|
{
|
||||||
|
*width = new_width;
|
||||||
|
*height = new_height;
|
||||||
|
*resize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*quit = (bool)false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_ctx_set_video_mode(void *data,
|
||||||
|
video_frame_info_t *video_info,
|
||||||
|
unsigned width, unsigned height,
|
||||||
|
bool fullscreen)
|
||||||
|
{
|
||||||
|
// Create an EGL rendering context
|
||||||
|
static const EGLint contextAttributeList[] =
|
||||||
|
{
|
||||||
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||||
|
EGL_NONE};
|
||||||
|
|
||||||
|
switch_ctx_data_t *ctx_nx = (switch_ctx_data_t *)data;
|
||||||
|
|
||||||
|
ctx_nx->width = 1280;
|
||||||
|
ctx_nx->height = 720;
|
||||||
|
|
||||||
|
ctx_nx->native_window.width = ctx_nx->width;
|
||||||
|
ctx_nx->native_window.height = ctx_nx->height;
|
||||||
|
|
||||||
|
ctx_nx->refresh_rate = 60;
|
||||||
|
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
if (!egl_create_context(&ctx_nx->egl, contextAttributeList))
|
||||||
|
{
|
||||||
|
egl_report_error();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
if (!egl_create_surface(&ctx_nx->egl, &ctx_nx->native_window))
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
printf("[ctx_nx]: EGL error: %d.\n", eglGetError());
|
||||||
|
switch_ctx_destroy(data);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_ctx_input_driver(void *data,
|
||||||
|
const char *name,
|
||||||
|
const input_driver_t **input, void **input_data)
|
||||||
|
{
|
||||||
|
*input = NULL;
|
||||||
|
*input_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum gfx_ctx_api switch_ctx_get_api(void *data)
|
||||||
|
{
|
||||||
|
return ctx_nx_api;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_ctx_bind_api(void *data,
|
||||||
|
enum gfx_ctx_api api, unsigned major, unsigned minor)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
ctx_nx_api = api;
|
||||||
|
|
||||||
|
if (api == GFX_CTX_OPENGL_API)
|
||||||
|
if (eglBindAPI(EGL_OPENGL_API) != EGL_FALSE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_ctx_has_focus(void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool switch_ctx_suppress_screensaver(void *data, bool enable)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
(void)enable;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_ctx_set_swap_interval(void *data,
|
||||||
|
int swap_interval)
|
||||||
|
{
|
||||||
|
switch_ctx_data_t *ctx_nx = (switch_ctx_data_t *)data;
|
||||||
|
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
egl_set_swap_interval(&ctx_nx->egl, swap_interval);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_ctx_swap_buffers(void *data, void *data2)
|
||||||
|
{
|
||||||
|
switch_ctx_data_t *ctx_nx = (switch_ctx_data_t *)data;
|
||||||
|
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
egl_swap_buffers(&ctx_nx->egl);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static gfx_ctx_proc_t switch_ctx_get_proc_address(const char *symbol)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
return egl_get_proc_address(symbol);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_ctx_bind_hw_render(void *data, bool enable)
|
||||||
|
{
|
||||||
|
switch_ctx_data_t *ctx_nx = (switch_ctx_data_t *)data;
|
||||||
|
|
||||||
|
#ifdef HAVE_EGL
|
||||||
|
egl_bind_hw_render(&ctx_nx->egl, enable);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t switch_ctx_get_flags(void *data)
|
||||||
|
{
|
||||||
|
uint32_t flags = 0;
|
||||||
|
BIT32_SET(flags, GFX_CTX_FLAGS_NONE);
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_ctx_set_flags(void *data, uint32_t flags)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float switch_ctx_get_refresh_rate(void *data)
|
||||||
|
{
|
||||||
|
switch_ctx_data_t *ctx_nx = (switch_ctx_data_t *)data;
|
||||||
|
|
||||||
|
return ctx_nx->refresh_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gfx_ctx_driver_t switch_ctx = {
|
||||||
|
switch_ctx_init,
|
||||||
|
switch_ctx_destroy,
|
||||||
|
switch_ctx_get_api,
|
||||||
|
switch_ctx_bind_api,
|
||||||
|
switch_ctx_set_swap_interval,
|
||||||
|
switch_ctx_set_video_mode,
|
||||||
|
switch_ctx_get_video_size,
|
||||||
|
switch_ctx_get_refresh_rate,
|
||||||
|
NULL, /* get_video_output_size */
|
||||||
|
NULL, /* get_video_output_prev */
|
||||||
|
NULL, /* get_video_output_next */
|
||||||
|
NULL, /* get_metrics */
|
||||||
|
NULL,
|
||||||
|
NULL, /* update_title */
|
||||||
|
switch_ctx_check_window,
|
||||||
|
NULL, /* set_resize */
|
||||||
|
switch_ctx_has_focus,
|
||||||
|
switch_ctx_suppress_screensaver,
|
||||||
|
NULL, /* has_windowed */
|
||||||
|
switch_ctx_swap_buffers,
|
||||||
|
switch_ctx_input_driver,
|
||||||
|
switch_ctx_get_proc_address,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
"switch",
|
||||||
|
switch_ctx_get_flags,
|
||||||
|
switch_ctx_set_flags,
|
||||||
|
switch_ctx_bind_hw_render,
|
||||||
|
NULL,
|
||||||
|
NULL};
|
|
@ -330,7 +330,7 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_vc_set_swap_interval(void *data, unsigned swap_interval)
|
static void gfx_ctx_vc_set_swap_interval(void *data, int swap_interval)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_EGL
|
#ifdef HAVE_EGL
|
||||||
vc_ctx_data_t *vc = (vc_ctx_data_t*)data;
|
vc_ctx_data_t *vc = (vc_ctx_data_t*)data;
|
||||||
|
|
|
@ -221,7 +221,7 @@ static bool gfx_ctx_vivante_suppress_screensaver(void *data, bool enable)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_vivante_set_swap_interval(void *data, unsigned swap_interval)
|
static void gfx_ctx_vivante_set_swap_interval(void *data, int swap_interval)
|
||||||
{
|
{
|
||||||
vivante_ctx_data_t *viv = (vivante_ctx_data_t*)data;
|
vivante_ctx_data_t *viv = (vivante_ctx_data_t*)data;
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ typedef struct gfx_ctx_wayland_data
|
||||||
struct wl_touch *wl_touch;
|
struct wl_touch *wl_touch;
|
||||||
struct wl_seat *seat;
|
struct wl_seat *seat;
|
||||||
struct wl_shm *shm;
|
struct wl_shm *shm;
|
||||||
unsigned swap_interval;
|
int swap_interval;
|
||||||
bool core_hw_context_enable;
|
bool core_hw_context_enable;
|
||||||
|
|
||||||
unsigned buffer_scale;
|
unsigned buffer_scale;
|
||||||
|
@ -1232,7 +1232,7 @@ static void gfx_ctx_wl_destroy(void *data)
|
||||||
free(wl);
|
free(wl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_wl_set_swap_interval(void *data, unsigned swap_interval)
|
static void gfx_ctx_wl_set_swap_interval(void *data, int swap_interval)
|
||||||
{
|
{
|
||||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
|
|
||||||
#ifdef HAVE_OPENGL
|
#ifdef HAVE_OPENGL
|
||||||
#include "../common/gl_common.h"
|
#include "../common/gl_common.h"
|
||||||
|
#include <gfx/gl_capabilities.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_VULKAN
|
#ifdef HAVE_VULKAN
|
||||||
|
@ -90,6 +91,7 @@ static HGLRC win32_hw_hrc;
|
||||||
static HDC win32_hdc;
|
static HDC win32_hdc;
|
||||||
static bool win32_use_hw_ctx = false;
|
static bool win32_use_hw_ctx = false;
|
||||||
static bool win32_core_hw_context_enable = false;
|
static bool win32_core_hw_context_enable = false;
|
||||||
|
static bool wgl_adaptive_vsync = false;
|
||||||
|
|
||||||
#ifdef HAVE_VULKAN
|
#ifdef HAVE_VULKAN
|
||||||
static gfx_ctx_vulkan_data_t win32_vk;
|
static gfx_ctx_vulkan_data_t win32_vk;
|
||||||
|
@ -97,13 +99,45 @@ static gfx_ctx_vulkan_data_t win32_vk;
|
||||||
|
|
||||||
static unsigned win32_major = 0;
|
static unsigned win32_major = 0;
|
||||||
static unsigned win32_minor = 0;
|
static unsigned win32_minor = 0;
|
||||||
static unsigned win32_interval = 0;
|
static int win32_interval = 0;
|
||||||
static enum gfx_ctx_api win32_api = GFX_CTX_NONE;
|
static enum gfx_ctx_api win32_api = GFX_CTX_NONE;
|
||||||
|
|
||||||
#ifdef HAVE_DYNAMIC
|
#ifdef HAVE_DYNAMIC
|
||||||
static dylib_t dll_handle = NULL; /* Handle to OpenGL32.dll */
|
static dylib_t dll_handle = NULL; /* Handle to OpenGL32.dll */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENGL
|
||||||
|
static bool wgl_has_extension(const char *extension, const char *extensions)
|
||||||
|
{
|
||||||
|
const char *start = NULL;
|
||||||
|
const char *terminator = NULL;
|
||||||
|
const char *where = strchr(extension, ' ');
|
||||||
|
|
||||||
|
if (where || *extension == '\0')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!extensions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
start = extensions;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
where = strstr(start, extension);
|
||||||
|
if (!where)
|
||||||
|
break;
|
||||||
|
|
||||||
|
terminator = where + strlen(extension);
|
||||||
|
if (where == start || *(where - 1) == ' ')
|
||||||
|
if (*terminator == ' ' || *terminator == '\0')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
start = terminator;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct gfx_ctx_cgl_data
|
typedef struct gfx_ctx_cgl_data
|
||||||
{
|
{
|
||||||
void *empty;
|
void *empty;
|
||||||
|
@ -263,6 +297,23 @@ static void create_gl_context(HWND hwnd, bool *quit)
|
||||||
else
|
else
|
||||||
RARCH_ERR("[WGL]: wglCreateContextAttribsARB not supported.\n");
|
RARCH_ERR("[WGL]: wglCreateContextAttribsARB not supported.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
const char *(WINAPI * wglGetExtensionsStringARB) (HDC) = 0;
|
||||||
|
const char *extensions = NULL;
|
||||||
|
|
||||||
|
wglGetExtensionsStringARB = (const char *(WINAPI *) (HDC))
|
||||||
|
gfx_ctx_wgl_get_proc_address("wglGetExtensionsStringARB");
|
||||||
|
if (wglGetExtensionsStringARB)
|
||||||
|
extensions = wglGetExtensionsStringARB(win32_hdc);
|
||||||
|
RARCH_LOG("[WGL] extensions: %s\n", extensions);
|
||||||
|
if (wgl_has_extension("WGL_EXT_swap_control_tear", extensions))
|
||||||
|
{
|
||||||
|
RARCH_LOG("[WGL]: Adaptive VSync supported.\n");
|
||||||
|
wgl_adaptive_vsync = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -308,7 +359,7 @@ void create_graphics_context(HWND hwnd, bool *quit)
|
||||||
|
|
||||||
void *dinput_wgl;
|
void *dinput_wgl;
|
||||||
|
|
||||||
static void gfx_ctx_wgl_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_wgl_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
(void)data;
|
(void)data;
|
||||||
|
|
||||||
|
@ -322,7 +373,7 @@ static void gfx_ctx_wgl_swap_interval(void *data, unsigned interval)
|
||||||
if (!p_swap_interval)
|
if (!p_swap_interval)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RARCH_LOG("[WGL]: wglSwapInterval(%u)\n", win32_interval);
|
RARCH_LOG("[WGL]: wglSwapInterval(%i)\n", win32_interval);
|
||||||
if (!p_swap_interval(win32_interval))
|
if (!p_swap_interval(win32_interval))
|
||||||
RARCH_WARN("[WGL]: wglSwapInterval() failed.\n");
|
RARCH_WARN("[WGL]: wglSwapInterval() failed.\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -479,6 +530,7 @@ static void *gfx_ctx_wgl_init(video_frame_info_t *video_info, void *video_driver
|
||||||
dll_handle = dylib_load("OpenGL32.dll");
|
dll_handle = dylib_load("OpenGL32.dll");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
win32_window_reset();
|
win32_window_reset();
|
||||||
win32_monitor_init();
|
win32_monitor_init();
|
||||||
|
|
||||||
|
@ -572,6 +624,7 @@ static void gfx_ctx_wgl_destroy(void *data)
|
||||||
if (wgl)
|
if (wgl)
|
||||||
free(wgl);
|
free(wgl);
|
||||||
|
|
||||||
|
wgl_adaptive_vsync = false;
|
||||||
win32_core_hw_context_enable = false;
|
win32_core_hw_context_enable = false;
|
||||||
g_win32_inited = false;
|
g_win32_inited = false;
|
||||||
win32_major = 0;
|
win32_major = 0;
|
||||||
|
@ -584,6 +637,10 @@ static bool gfx_ctx_wgl_set_video_mode(void *data,
|
||||||
unsigned width, unsigned height,
|
unsigned width, unsigned height,
|
||||||
bool fullscreen)
|
bool fullscreen)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_VULKAN
|
||||||
|
win32_vk.fullscreen = fullscreen;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!win32_set_video_mode(NULL, width, height, fullscreen))
|
if (!win32_set_video_mode(NULL, width, height, fullscreen))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[WGL]: win32_set_video_mode failed.\n");
|
RARCH_ERR("[WGL]: win32_set_video_mode failed.\n");
|
||||||
|
@ -721,22 +778,51 @@ static void *gfx_ctx_wgl_get_context_data(void *data)
|
||||||
|
|
||||||
static uint32_t gfx_ctx_wgl_get_flags(void *data)
|
static uint32_t gfx_ctx_wgl_get_flags(void *data)
|
||||||
{
|
{
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
if (win32_core_hw_context_enable)
|
|
||||||
|
BIT32_SET(flags, GFX_CTX_FLAGS_NONE);
|
||||||
|
|
||||||
|
switch (win32_api)
|
||||||
{
|
{
|
||||||
BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT);
|
case GFX_CTX_OPENGL_API:
|
||||||
}
|
if (wgl_adaptive_vsync)
|
||||||
else
|
{
|
||||||
{
|
BIT32_SET(flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC);
|
||||||
BIT32_SET(flags, GFX_CTX_FLAGS_NONE);
|
}
|
||||||
|
|
||||||
|
if (win32_core_hw_context_enable)
|
||||||
|
{
|
||||||
|
BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GFX_CTX_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_wgl_set_flags(void *data, uint32_t flags)
|
static void gfx_ctx_wgl_set_flags(void *data, uint32_t flags)
|
||||||
{
|
{
|
||||||
if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT))
|
switch (win32_api)
|
||||||
win32_core_hw_context_enable = true;
|
{
|
||||||
|
case GFX_CTX_OPENGL_API:
|
||||||
|
#ifdef HAVE_OPENGL
|
||||||
|
if (BIT32_GET(flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC))
|
||||||
|
{
|
||||||
|
wgl_adaptive_vsync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT))
|
||||||
|
win32_core_hw_context_enable = true;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case GFX_CTX_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_wgl_get_video_output_size(void *data,
|
static void gfx_ctx_wgl_get_video_output_size(void *data,
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#ifdef HAVE_OPENGL
|
#ifdef HAVE_OPENGL
|
||||||
#include <GL/glx.h>
|
#include <GL/glx.h>
|
||||||
|
#include <gfx/gl_capabilities.h>
|
||||||
|
|
||||||
#ifndef GLX_SAMPLE_BUFFERS
|
#ifndef GLX_SAMPLE_BUFFERS
|
||||||
#define GLX_SAMPLE_BUFFERS 100000
|
#define GLX_SAMPLE_BUFFERS 100000
|
||||||
|
@ -100,13 +101,14 @@ typedef struct gfx_ctx_x_data
|
||||||
unsigned swap_mode;
|
unsigned swap_mode;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned g_interval;
|
int g_interval;
|
||||||
|
|
||||||
#ifdef HAVE_VULKAN
|
#ifdef HAVE_VULKAN
|
||||||
gfx_ctx_vulkan_data_t vk;
|
gfx_ctx_vulkan_data_t vk;
|
||||||
#endif
|
#endif
|
||||||
} gfx_ctx_x_data_t;
|
} gfx_ctx_x_data_t;
|
||||||
|
|
||||||
|
static bool x_adaptive_vsync = false;
|
||||||
static bool x_enable_msaa = false;
|
static bool x_enable_msaa = false;
|
||||||
static unsigned g_major = 0;
|
static unsigned g_major = 0;
|
||||||
static unsigned g_minor = 0;
|
static unsigned g_minor = 0;
|
||||||
|
@ -124,51 +126,25 @@ typedef struct Hints
|
||||||
} Hints;
|
} Hints;
|
||||||
|
|
||||||
/* We use long because X11 wants 32-bit pixels for 32-bit systems and 64 for 64... */
|
/* We use long because X11 wants 32-bit pixels for 32-bit systems and 64 for 64... */
|
||||||
|
/* ARGB*/
|
||||||
static const unsigned long retroarch_icon_data[] = {
|
static const unsigned long retroarch_icon_data[] = {
|
||||||
16, 16,
|
16, 16,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000,0x00000000,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0x00000000,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000,0xff333333,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000,0xff333333,0xfff2f2f2,0xff333333,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xff333333,0xfff2f2f2,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000,0xff333333,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xff333333,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xff333333,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
0x00000000,0xff333333,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
|
0x00000000,0xff333333,0xff333333,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xfff2f2f2,0xff333333,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
0x00000000,0xff333333,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0xff333333,0x00000000,0x00000000,
|
||||||
0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, 0xffffffff, 0x00000000,
|
0x00000000,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xfff2f2f2,0xff333333,0xff333333,0x00000000,0x00000000,
|
||||||
0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, 0xffffffff, 0xffffffff,
|
0x00000000,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0x00000000,0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x000000ff, 0xffffffff,
|
0x00000000,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0x00000000,0x00000000,
|
||||||
0xffffffff, 0x000000ff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff,
|
0x00000000,0x00000000,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0xff333333,0x00000000,0x00000000,0x00000000,
|
||||||
0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, 0x00000000, 0x00000000,
|
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000
|
||||||
0x00000000, 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff,
|
|
||||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0xffffffff,
|
|
||||||
0x000000ff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
||||||
0x000000ff, 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff,
|
|
||||||
0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, 0x000000ff, 0xffffffff,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x000000ff, 0x000000ff,
|
|
||||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
|
||||||
0x000000ff, 0x000000ff, 0x000000ff, 0xffffffff, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0xffffffff, 0xffffffff, 0x000000ff, 0x000000ff, 0x000000ff,
|
|
||||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
|
||||||
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, 0xffffffff, 0xffffffff,
|
|
||||||
0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, 0xffffffff, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x000000ff,
|
|
||||||
0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
|
|
||||||
0xffffffff, 0x000000ff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
|
|
||||||
0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAVE_OPENGL
|
#ifdef HAVE_OPENGL
|
||||||
|
@ -320,7 +296,7 @@ static void gfx_ctx_x_destroy(void *data)
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_x_swap_interval(void *data, unsigned interval)
|
static void gfx_ctx_x_swap_interval(void *data, int interval)
|
||||||
{
|
{
|
||||||
gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*)data;
|
gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*)data;
|
||||||
|
|
||||||
|
@ -333,18 +309,18 @@ static void gfx_ctx_x_swap_interval(void *data, unsigned interval)
|
||||||
|
|
||||||
if (g_pglSwapIntervalEXT)
|
if (g_pglSwapIntervalEXT)
|
||||||
{
|
{
|
||||||
RARCH_LOG("[GLX]: glXSwapIntervalEXT(%u)\n", x->g_interval);
|
RARCH_LOG("[GLX]: glXSwapIntervalEXT(%i)\n", x->g_interval);
|
||||||
g_pglSwapIntervalEXT(g_x11_dpy, x->g_glx_win, x->g_interval);
|
g_pglSwapIntervalEXT(g_x11_dpy, x->g_glx_win, x->g_interval);
|
||||||
}
|
}
|
||||||
else if (g_pglSwapInterval)
|
else if (g_pglSwapInterval)
|
||||||
{
|
{
|
||||||
RARCH_LOG("[GLX]: glXSwapInterval(%u)\n", x->g_interval);
|
RARCH_LOG("[GLX]: glXSwapInterval(%i)\n", x->g_interval);
|
||||||
if (g_pglSwapInterval(x->g_interval) != 0)
|
if (g_pglSwapInterval(x->g_interval) != 0)
|
||||||
RARCH_WARN("[GLX]: glXSwapInterval() failed.\n");
|
RARCH_WARN("[GLX]: glXSwapInterval() failed.\n");
|
||||||
}
|
}
|
||||||
else if (g_pglSwapIntervalSGI)
|
else if (g_pglSwapIntervalSGI)
|
||||||
{
|
{
|
||||||
RARCH_LOG("[GLX]: glXSwapIntervalSGI(%u)\n", x->g_interval);
|
RARCH_LOG("[GLX]: glXSwapIntervalSGI(%i)\n", x->g_interval);
|
||||||
if (g_pglSwapIntervalSGI(x->g_interval) != 0)
|
if (g_pglSwapIntervalSGI(x->g_interval) != 0)
|
||||||
RARCH_WARN("[GLX]: glXSwapIntervalSGI() failed.\n");
|
RARCH_WARN("[GLX]: glXSwapIntervalSGI() failed.\n");
|
||||||
}
|
}
|
||||||
|
@ -581,6 +557,11 @@ static void *gfx_ctx_x_init(video_frame_info_t *video_info, void *data)
|
||||||
{
|
{
|
||||||
case GFX_CTX_OPENGL_API:
|
case GFX_CTX_OPENGL_API:
|
||||||
#ifdef HAVE_OPENGL
|
#ifdef HAVE_OPENGL
|
||||||
|
if (GLXExtensionSupported(g_x11_dpy, "GLX_EXT_swap_control_tear"))
|
||||||
|
{
|
||||||
|
RARCH_LOG("[GLX]: GLX_EXT_swap_control_tear supported.\n");
|
||||||
|
x_adaptive_vsync = true;
|
||||||
|
}
|
||||||
if (GLXExtensionSupported(g_x11_dpy, "GLX_OML_sync_control") &&
|
if (GLXExtensionSupported(g_x11_dpy, "GLX_OML_sync_control") &&
|
||||||
GLXExtensionSupported(g_x11_dpy, "GLX_MESA_swap_control")
|
GLXExtensionSupported(g_x11_dpy, "GLX_MESA_swap_control")
|
||||||
)
|
)
|
||||||
|
@ -1167,30 +1148,56 @@ static void *gfx_ctx_x_get_context_data(void *data)
|
||||||
|
|
||||||
static uint32_t gfx_ctx_x_get_flags(void *data)
|
static uint32_t gfx_ctx_x_get_flags(void *data)
|
||||||
{
|
{
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*)data;
|
gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*)data;
|
||||||
if (x->core_hw_context_enable || x->g_core_es)
|
|
||||||
|
BIT32_SET(flags, GFX_CTX_FLAGS_NONE);
|
||||||
|
|
||||||
|
switch (x_api)
|
||||||
{
|
{
|
||||||
BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT);
|
case GFX_CTX_OPENGL_API:
|
||||||
}
|
case GFX_CTX_OPENGL_ES_API:
|
||||||
else
|
if (x_adaptive_vsync)
|
||||||
{
|
{
|
||||||
BIT32_SET(flags, GFX_CTX_FLAGS_NONE);
|
BIT32_SET(flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC);
|
||||||
}
|
}
|
||||||
if (x_enable_msaa)
|
|
||||||
{
|
if (x->core_hw_context_enable || x->g_core_es)
|
||||||
BIT32_SET(flags, GFX_CTX_FLAGS_MULTISAMPLING);
|
{
|
||||||
|
BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT);
|
||||||
|
}
|
||||||
|
if (x_enable_msaa)
|
||||||
|
{
|
||||||
|
BIT32_SET(flags, GFX_CTX_FLAGS_MULTISAMPLING);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GFX_CTX_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_x_set_flags(void *data, uint32_t flags)
|
static void gfx_ctx_x_set_flags(void *data, uint32_t flags)
|
||||||
{
|
{
|
||||||
gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*)data;
|
gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*)data;
|
||||||
if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT))
|
|
||||||
x->core_hw_context_enable = true;
|
switch (x_api)
|
||||||
if (BIT32_GET(flags, GFX_CTX_FLAGS_MULTISAMPLING))
|
{
|
||||||
x_enable_msaa = true;
|
case GFX_CTX_OPENGL_API:
|
||||||
|
case GFX_CTX_OPENGL_ES_API:
|
||||||
|
if (BIT32_GET(flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC))
|
||||||
|
x_adaptive_vsync = true;
|
||||||
|
if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT))
|
||||||
|
x->core_hw_context_enable = true;
|
||||||
|
if (BIT32_GET(flags, GFX_CTX_FLAGS_MULTISAMPLING))
|
||||||
|
x_enable_msaa = true;
|
||||||
|
break;
|
||||||
|
case GFX_CTX_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_x_make_current(bool release)
|
static void gfx_ctx_x_make_current(bool release)
|
||||||
|
|
|
@ -255,7 +255,7 @@ static EGLint *xegl_fill_attribs(xegl_ctx_data_t *xegl, EGLint *attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* forward declaration */
|
/* forward declaration */
|
||||||
static void gfx_ctx_xegl_set_swap_interval(void *data, unsigned swap_interval);
|
static void gfx_ctx_xegl_set_swap_interval(void *data, int swap_interval);
|
||||||
|
|
||||||
static bool gfx_ctx_xegl_set_video_mode(void *data,
|
static bool gfx_ctx_xegl_set_video_mode(void *data,
|
||||||
video_frame_info_t *video_info,
|
video_frame_info_t *video_info,
|
||||||
|
@ -561,7 +561,7 @@ static void gfx_ctx_xegl_bind_hw_render(void *data, bool enable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfx_ctx_xegl_set_swap_interval(void *data, unsigned swap_interval)
|
static void gfx_ctx_xegl_set_swap_interval(void *data, int swap_interval)
|
||||||
{
|
{
|
||||||
xegl_ctx_data_t *xegl = (xegl_ctx_data_t*)data;
|
xegl_ctx_data_t *xegl = (xegl_ctx_data_t*)data;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,350 @@
|
||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2018 - lifajucejo
|
||||||
|
* Copyright (C) 2018 - m4xw
|
||||||
|
* Copyright (C) 2018 - natinusala
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
|
#include <retro_math.h>
|
||||||
|
|
||||||
|
#include "../font_driver.h"
|
||||||
|
#include "../video_driver.h"
|
||||||
|
|
||||||
|
#include "../../verbosity.h"
|
||||||
|
|
||||||
|
#include "../common/switch_common.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct font_atlas *atlas;
|
||||||
|
|
||||||
|
const font_renderer_driver_t *font_driver;
|
||||||
|
void *font_data;
|
||||||
|
} switch_font_t;
|
||||||
|
|
||||||
|
static void *switch_font_init_font(void *data, const char *font_path,
|
||||||
|
float font_size, bool is_threaded)
|
||||||
|
{
|
||||||
|
switch_font_t *font = (switch_font_t *)calloc(1, sizeof(switch_font_t));
|
||||||
|
|
||||||
|
if (!font)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!font_renderer_create_default((const void **)&font->font_driver,
|
||||||
|
&font->font_data, font_path, font_size))
|
||||||
|
{
|
||||||
|
RARCH_WARN("Couldn't initialize font renderer.\n");
|
||||||
|
free(font);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
font->atlas = font->font_driver->get_atlas(font->font_data);
|
||||||
|
|
||||||
|
RARCH_LOG("Switch font driver initialized with backend %s\n", font->font_driver->ident);
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_font_free_font(void *data, bool is_threaded)
|
||||||
|
{
|
||||||
|
switch_font_t *font = (switch_font_t *)data;
|
||||||
|
|
||||||
|
if (!font)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (font->font_driver && font->font_data)
|
||||||
|
font->font_driver->free(font->font_data);
|
||||||
|
|
||||||
|
free(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int switch_font_get_message_width(void *data, const char *msg,
|
||||||
|
unsigned msg_len, float scale)
|
||||||
|
{
|
||||||
|
switch_font_t *font = (switch_font_t *)data;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
int delta_x = 0;
|
||||||
|
|
||||||
|
if (!font)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < msg_len; i++)
|
||||||
|
{
|
||||||
|
const char *msg_tmp = &msg[i];
|
||||||
|
unsigned code = utf8_walk(&msg_tmp);
|
||||||
|
unsigned skip = msg_tmp - &msg[i];
|
||||||
|
|
||||||
|
if (skip > 1)
|
||||||
|
i += skip - 1;
|
||||||
|
|
||||||
|
const struct font_glyph *glyph =
|
||||||
|
font->font_driver->get_glyph(font->font_data, code);
|
||||||
|
|
||||||
|
if (!glyph) /* Do something smarter here ... */
|
||||||
|
glyph = font->font_driver->get_glyph(font->font_data, '?');
|
||||||
|
|
||||||
|
if (!glyph)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
delta_x += glyph->advance_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return delta_x * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_font_render_line(
|
||||||
|
video_frame_info_t *video_info,
|
||||||
|
switch_font_t *font, const char *msg, unsigned msg_len,
|
||||||
|
float scale, const unsigned int color, float pos_x,
|
||||||
|
float pos_y, unsigned text_align)
|
||||||
|
{
|
||||||
|
int delta_x = 0;
|
||||||
|
int delta_y = 0;
|
||||||
|
|
||||||
|
unsigned fbWidth = 0;
|
||||||
|
unsigned fbHeight = 0;
|
||||||
|
|
||||||
|
uint32_t *out_buffer = (uint32_t *)gfxGetFramebuffer(&fbWidth, &fbHeight);
|
||||||
|
if (out_buffer)
|
||||||
|
{
|
||||||
|
int x = roundf(pos_x * fbWidth);
|
||||||
|
int y = roundf((1.0f - pos_y) * fbHeight);
|
||||||
|
|
||||||
|
switch (text_align)
|
||||||
|
{
|
||||||
|
case TEXT_ALIGN_RIGHT:
|
||||||
|
x -= switch_font_get_message_width(font, msg, msg_len, scale);
|
||||||
|
break;
|
||||||
|
case TEXT_ALIGN_CENTER:
|
||||||
|
x -= switch_font_get_message_width(font, msg, msg_len, scale) / 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < msg_len; i++)
|
||||||
|
{
|
||||||
|
int off_x, off_y, tex_x, tex_y, width, height;
|
||||||
|
const char *msg_tmp = &msg[i];
|
||||||
|
unsigned code = utf8_walk(&msg_tmp);
|
||||||
|
unsigned skip = msg_tmp - &msg[i];
|
||||||
|
|
||||||
|
if (skip > 1)
|
||||||
|
i += skip - 1;
|
||||||
|
|
||||||
|
const struct font_glyph *glyph =
|
||||||
|
font->font_driver->get_glyph(font->font_data, code);
|
||||||
|
|
||||||
|
if (!glyph) /* Do something smarter here ... */
|
||||||
|
glyph = font->font_driver->get_glyph(font->font_data, '?');
|
||||||
|
|
||||||
|
if (!glyph)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
off_x = x + glyph->draw_offset_x + delta_x;
|
||||||
|
off_y = y + glyph->draw_offset_y + delta_y;
|
||||||
|
width = glyph->width;
|
||||||
|
height = glyph->height;
|
||||||
|
|
||||||
|
tex_x = glyph->atlas_offset_x;
|
||||||
|
tex_y = glyph->atlas_offset_y;
|
||||||
|
|
||||||
|
for (int y = tex_y; y < tex_y + height; y++)
|
||||||
|
{
|
||||||
|
uint8_t *row = &font->atlas->buffer[y * font->atlas->width];
|
||||||
|
for (int x = tex_x; x < tex_x + width; x++)
|
||||||
|
{
|
||||||
|
if (!row[x])
|
||||||
|
continue;
|
||||||
|
int x1 = off_x + (x - tex_x);
|
||||||
|
int y1 = off_y + (y - tex_y);
|
||||||
|
if (x1 < fbWidth && y1 < fbHeight)
|
||||||
|
out_buffer[gfxGetFramebufferDisplayOffset(x1, y1)] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delta_x += glyph->advance_x;
|
||||||
|
delta_y += glyph->advance_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AVG_GLPYH_LIMIT 140
|
||||||
|
static void switch_font_render_message(
|
||||||
|
video_frame_info_t *video_info,
|
||||||
|
switch_font_t *font, const char *msg, float scale,
|
||||||
|
const unsigned int color, float pos_x, float pos_y,
|
||||||
|
unsigned text_align)
|
||||||
|
{
|
||||||
|
int lines = 0;
|
||||||
|
float line_height;
|
||||||
|
|
||||||
|
if (!msg || !*msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If the font height is not supported just draw as usual */
|
||||||
|
if (!font->font_driver->get_line_height)
|
||||||
|
{
|
||||||
|
int msgLen = strlen(msg);
|
||||||
|
if (msgLen <= AVG_GLPYH_LIMIT)
|
||||||
|
{
|
||||||
|
switch_font_render_line(video_info, font, msg, strlen(msg),
|
||||||
|
scale, color, pos_x, pos_y, text_align);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
line_height = scale / font->font_driver->get_line_height(font->font_data);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const char *delim = strchr(msg, '\n');
|
||||||
|
|
||||||
|
/* Draw the line */
|
||||||
|
if (delim)
|
||||||
|
{
|
||||||
|
unsigned msg_len = delim - msg;
|
||||||
|
if (msg_len <= AVG_GLPYH_LIMIT)
|
||||||
|
{
|
||||||
|
switch_font_render_line(video_info, font, msg, msg_len,
|
||||||
|
scale, color, pos_x, pos_y - (float)lines * line_height,
|
||||||
|
text_align);
|
||||||
|
}
|
||||||
|
msg += msg_len + 1;
|
||||||
|
lines++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned msg_len = strlen(msg);
|
||||||
|
if (msg_len <= AVG_GLPYH_LIMIT)
|
||||||
|
{
|
||||||
|
switch_font_render_line(video_info, font, msg, msg_len,
|
||||||
|
scale, color, pos_x, pos_y - (float)lines * line_height,
|
||||||
|
text_align);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_font_render_msg(
|
||||||
|
video_frame_info_t *video_info,
|
||||||
|
void *data, const char *msg,
|
||||||
|
const struct font_params *params)
|
||||||
|
{
|
||||||
|
float x, y, scale, drop_mod, drop_alpha;
|
||||||
|
int drop_x, drop_y;
|
||||||
|
unsigned max_glyphs;
|
||||||
|
enum text_alignment text_align;
|
||||||
|
unsigned color, color_dark, r, g, b,
|
||||||
|
alpha, r_dark, g_dark, b_dark, alpha_dark;
|
||||||
|
switch_font_t *font = (switch_font_t *)data;
|
||||||
|
unsigned width = video_info->width;
|
||||||
|
unsigned height = video_info->height;
|
||||||
|
|
||||||
|
if (!font || !msg || msg && !*msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (params)
|
||||||
|
{
|
||||||
|
x = params->x;
|
||||||
|
y = params->y;
|
||||||
|
scale = params->scale;
|
||||||
|
text_align = params->text_align;
|
||||||
|
drop_x = params->drop_x;
|
||||||
|
drop_y = params->drop_y;
|
||||||
|
drop_mod = params->drop_mod;
|
||||||
|
drop_alpha = params->drop_alpha;
|
||||||
|
|
||||||
|
r = FONT_COLOR_GET_RED(params->color);
|
||||||
|
g = FONT_COLOR_GET_GREEN(params->color);
|
||||||
|
b = FONT_COLOR_GET_BLUE(params->color);
|
||||||
|
alpha = FONT_COLOR_GET_ALPHA(params->color);
|
||||||
|
|
||||||
|
color = params->color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = 0.0f;
|
||||||
|
y = 0.0f;
|
||||||
|
scale = 1.0f;
|
||||||
|
text_align = TEXT_ALIGN_LEFT;
|
||||||
|
|
||||||
|
r = (video_info->font_msg_color_r * 255);
|
||||||
|
g = (video_info->font_msg_color_g * 255);
|
||||||
|
b = (video_info->font_msg_color_b * 255);
|
||||||
|
alpha = 255;
|
||||||
|
color = COLOR_ABGR(r, g, b, alpha);
|
||||||
|
|
||||||
|
drop_x = -2;
|
||||||
|
drop_y = -2;
|
||||||
|
drop_mod = 0.3f;
|
||||||
|
drop_alpha = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
max_glyphs = strlen(msg);
|
||||||
|
|
||||||
|
/*if (drop_x || drop_y)
|
||||||
|
max_glyphs *= 2;
|
||||||
|
|
||||||
|
if (drop_x || drop_y)
|
||||||
|
{
|
||||||
|
r_dark = r * drop_mod;
|
||||||
|
g_dark = g * drop_mod;
|
||||||
|
b_dark = b * drop_mod;
|
||||||
|
alpha_dark = alpha * drop_alpha;
|
||||||
|
color_dark = COLOR_ABGR(r_dark, g_dark, b_dark, alpha_dark);
|
||||||
|
|
||||||
|
switch_font_render_message(video_info, font, msg, scale, color_dark,
|
||||||
|
x + scale * drop_x / width, y +
|
||||||
|
scale * drop_y / height, text_align);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
switch_font_render_message(video_info, font, msg, scale,
|
||||||
|
color, x, y, text_align);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct font_glyph *switch_font_get_glyph(
|
||||||
|
void *data, uint32_t code)
|
||||||
|
{
|
||||||
|
switch_font_t *font = (switch_font_t *)data;
|
||||||
|
|
||||||
|
if (!font || !font->font_driver)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!font->font_driver->ident)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return font->font_driver->get_glyph((void *)font->font_driver, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void switch_font_bind_block(void *data, void *userdata)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
font_renderer_t switch_font =
|
||||||
|
{
|
||||||
|
switch_font_init_font,
|
||||||
|
switch_font_free_font,
|
||||||
|
switch_font_render_msg,
|
||||||
|
"switchfont",
|
||||||
|
switch_font_get_glyph,
|
||||||
|
switch_font_bind_block,
|
||||||
|
NULL, /* flush_block */
|
||||||
|
switch_font_get_message_width,
|
||||||
|
};
|
|
@ -524,6 +524,37 @@ static bool ctr_font_init_first(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
static const font_renderer_t *switch_font_backends[] = {
|
||||||
|
&switch_font,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool switch_font_init_first(
|
||||||
|
const void **font_driver, void **font_handle,
|
||||||
|
void *video_data, const char *font_path,
|
||||||
|
float font_size, bool is_threaded)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; switch_font_backends[i]; i++)
|
||||||
|
{
|
||||||
|
void *data = switch_font_backends[i]->init(
|
||||||
|
video_data, font_path, font_size,
|
||||||
|
is_threaded);
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
*font_driver = switch_font_backends[i];
|
||||||
|
*font_handle = data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WIIU
|
#ifdef WIIU
|
||||||
static const font_renderer_t *wiiu_font_backends[] = {
|
static const font_renderer_t *wiiu_font_backends[] = {
|
||||||
&wiiu_font,
|
&wiiu_font,
|
||||||
|
@ -630,6 +661,11 @@ static bool font_init_first(
|
||||||
return sixel_font_init_first(font_driver, font_handle,
|
return sixel_font_init_first(font_driver, font_handle,
|
||||||
video_data, font_path, font_size, is_threaded);
|
video_data, font_path, font_size, is_threaded);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
case FONT_DRIVER_RENDER_SWITCH:
|
||||||
|
return switch_font_init_first(font_driver, font_handle,
|
||||||
|
video_data, font_path, font_size, is_threaded);
|
||||||
|
#endif
|
||||||
#if defined(_WIN32) && !defined(_XBOX)
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
case FONT_DRIVER_RENDER_GDI:
|
case FONT_DRIVER_RENDER_GDI:
|
||||||
return gdi_font_init_first(font_driver, font_handle,
|
return gdi_font_init_first(font_driver, font_handle,
|
||||||
|
|
|
@ -173,6 +173,7 @@ extern font_renderer_t caca_font;
|
||||||
extern font_renderer_t gdi_font;
|
extern font_renderer_t gdi_font;
|
||||||
extern font_renderer_t vga_font;
|
extern font_renderer_t vga_font;
|
||||||
extern font_renderer_t sixel_font;
|
extern font_renderer_t sixel_font;
|
||||||
|
extern font_renderer_t switch_font;
|
||||||
|
|
||||||
extern font_renderer_driver_t stb_font_renderer;
|
extern font_renderer_driver_t stb_font_renderer;
|
||||||
extern font_renderer_driver_t stb_unicode_font_renderer;
|
extern font_renderer_driver_t stb_unicode_font_renderer;
|
||||||
|
|
|
@ -31,6 +31,7 @@ static unsigned ra_tmp_height = 0;
|
||||||
static unsigned ra_set_core_hz = 0;
|
static unsigned ra_set_core_hz = 0;
|
||||||
static unsigned orig_width = 0;
|
static unsigned orig_width = 0;
|
||||||
static unsigned orig_height = 0;
|
static unsigned orig_height = 0;
|
||||||
|
static int crt_center_adjust = 0;
|
||||||
|
|
||||||
static bool first_run = true;
|
static bool first_run = true;
|
||||||
|
|
||||||
|
@ -53,12 +54,25 @@ static void switch_crt_hz(void)
|
||||||
if (ra_core_hz == ra_tmp_core_hz)
|
if (ra_core_hz == ra_tmp_core_hz)
|
||||||
return;
|
return;
|
||||||
/* set hz float to an int for windows switching */
|
/* set hz float to an int for windows switching */
|
||||||
if (ra_core_hz < 53)
|
if (ra_core_hz < 100)
|
||||||
ra_set_core_hz = 50;
|
{
|
||||||
if (ra_core_hz >= 53 && ra_core_hz < 57)
|
if (ra_core_hz < 53)
|
||||||
ra_set_core_hz = 55;
|
ra_set_core_hz = 50;
|
||||||
if (ra_core_hz >= 57)
|
if (ra_core_hz >= 53 && ra_core_hz < 57)
|
||||||
ra_set_core_hz = 60;
|
ra_set_core_hz = 55;
|
||||||
|
if (ra_core_hz >= 57)
|
||||||
|
ra_set_core_hz = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ra_core_hz > 100)
|
||||||
|
{
|
||||||
|
if (ra_core_hz < 106)
|
||||||
|
ra_set_core_hz = 120;
|
||||||
|
if (ra_core_hz >= 106 && ra_core_hz < 114)
|
||||||
|
ra_set_core_hz = 110;
|
||||||
|
if (ra_core_hz >= 114)
|
||||||
|
ra_set_core_hz = 120;
|
||||||
|
}
|
||||||
|
|
||||||
video_monitor_set_refresh_rate(ra_set_core_hz);
|
video_monitor_set_refresh_rate(ra_set_core_hz);
|
||||||
|
|
||||||
|
@ -78,7 +92,7 @@ static void switch_res_crt(unsigned width, unsigned height)
|
||||||
if (height > 100)
|
if (height > 100)
|
||||||
{
|
{
|
||||||
video_display_server_switch_resolution(width, height,
|
video_display_server_switch_resolution(width, height,
|
||||||
ra_set_core_hz, ra_core_hz);
|
ra_set_core_hz, ra_core_hz, crt_center_adjust);
|
||||||
video_driver_apply_state_changes();
|
video_driver_apply_state_changes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,13 +114,13 @@ static void crt_screen_setup_aspect(unsigned width, unsigned height)
|
||||||
crt_aspect_ratio_switch(width, height);
|
crt_aspect_ratio_switch(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (height < 191 && height != 144)
|
if (height < 200 && height != 144)
|
||||||
{
|
{
|
||||||
crt_aspect_ratio_switch(width, height);
|
crt_aspect_ratio_switch(width, height);
|
||||||
height = 200;
|
height = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (height > 191)
|
if (height > 200)
|
||||||
crt_aspect_ratio_switch(width, height);
|
crt_aspect_ratio_switch(width, height);
|
||||||
|
|
||||||
if (height == 144 && ra_set_core_hz == 50)
|
if (height == 144 && ra_set_core_hz == 50)
|
||||||
|
@ -149,13 +163,23 @@ static void crt_screen_setup_aspect(unsigned width, unsigned height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void crt_switch_res_core(unsigned width, unsigned height, float hz)
|
void crt_switch_res_core(unsigned width, unsigned height, float hz, unsigned crt_mode, int crt_switch_center_adjust)
|
||||||
{
|
{
|
||||||
/* ra_core_hz float passed from within
|
/* ra_core_hz float passed from within
|
||||||
* void video_driver_monitor_adjust_system_rates(void) */
|
* void video_driver_monitor_adjust_system_rates(void) */
|
||||||
ra_core_width = width;
|
ra_core_width = width;
|
||||||
ra_core_height = height;
|
ra_core_height = height;
|
||||||
ra_core_hz = hz;
|
ra_core_hz = hz;
|
||||||
|
crt_center_adjust = crt_switch_center_adjust;
|
||||||
|
|
||||||
|
if (crt_mode == 2)
|
||||||
|
{
|
||||||
|
if (hz > 53)
|
||||||
|
ra_core_hz = hz*2;
|
||||||
|
|
||||||
|
if (hz <= 53)
|
||||||
|
ra_core_hz = 120.0f;
|
||||||
|
}
|
||||||
|
|
||||||
crt_check_first_run();
|
crt_check_first_run();
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
RETRO_BEGIN_DECLS
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
void crt_switch_res_core(unsigned width, unsigned height, float hz);
|
void crt_switch_res_core(unsigned width, unsigned height, float hz, unsigned crt_mode, int crt_switch_center_adjust);
|
||||||
|
|
||||||
void crt_aspect_ratio_switch(unsigned width, unsigned height);
|
void crt_aspect_ratio_switch(unsigned width, unsigned height);
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,8 @@ enum font_driver_render_api
|
||||||
FONT_DRIVER_RENDER_CACA,
|
FONT_DRIVER_RENDER_CACA,
|
||||||
FONT_DRIVER_RENDER_SIXEL,
|
FONT_DRIVER_RENDER_SIXEL,
|
||||||
FONT_DRIVER_RENDER_GDI,
|
FONT_DRIVER_RENDER_GDI,
|
||||||
FONT_DRIVER_RENDER_VGA
|
FONT_DRIVER_RENDER_VGA,
|
||||||
|
FONT_DRIVER_RENDER_SWITCH
|
||||||
};
|
};
|
||||||
|
|
||||||
enum text_alignment
|
enum text_alignment
|
||||||
|
|
|
@ -84,9 +84,16 @@ bool video_display_server_set_window_decorations(bool on)
|
||||||
|
|
||||||
|
|
||||||
bool video_display_server_switch_resolution(unsigned width, unsigned height,
|
bool video_display_server_switch_resolution(unsigned width, unsigned height,
|
||||||
int int_hz, float hz)
|
int int_hz, float hz, int center)
|
||||||
{
|
{
|
||||||
if (current_display_server && current_display_server->switch_resolution)
|
if (current_display_server && current_display_server->switch_resolution)
|
||||||
return current_display_server->switch_resolution(current_display_server_data, width, height, int_hz, hz);
|
return current_display_server->switch_resolution(current_display_server_data, width, height, int_hz, hz, center);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *video_display_server_get_output_options(void)
|
||||||
|
{
|
||||||
|
if (current_display_server && current_display_server->get_output_options)
|
||||||
|
return current_display_server->get_output_options(current_display_server_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -31,7 +31,8 @@ typedef struct video_display_server
|
||||||
bool (*set_window_progress)(void *data, int progress, bool finished);
|
bool (*set_window_progress)(void *data, int progress, bool finished);
|
||||||
bool (*set_window_decorations)(void *data, bool on);
|
bool (*set_window_decorations)(void *data, bool on);
|
||||||
bool (*switch_resolution)(void *data, unsigned width,
|
bool (*switch_resolution)(void *data, unsigned width,
|
||||||
unsigned height, int int_hz, float hz);
|
unsigned height, int int_hz, float hz, int center);
|
||||||
|
const char *(*get_output_options)(void *data);
|
||||||
const char *ident;
|
const char *ident;
|
||||||
} video_display_server_t;
|
} video_display_server_t;
|
||||||
|
|
||||||
|
@ -47,7 +48,9 @@ bool video_display_server_set_window_decorations(bool on);
|
||||||
|
|
||||||
bool video_display_server_switch_resolution(
|
bool video_display_server_switch_resolution(
|
||||||
unsigned width, unsigned height,
|
unsigned width, unsigned height,
|
||||||
int int_hz, float hz);
|
int int_hz, float hz, int center);
|
||||||
|
|
||||||
|
const char *video_display_server_get_output_options(void);
|
||||||
|
|
||||||
extern const video_display_server_t dispserv_win32;
|
extern const video_display_server_t dispserv_win32;
|
||||||
extern const video_display_server_t dispserv_x11;
|
extern const video_display_server_t dispserv_x11;
|
||||||
|
|
|
@ -354,6 +354,9 @@ static const video_driver_t *video_drivers[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const gfx_ctx_driver_t *gfx_ctx_drivers[] = {
|
static const gfx_ctx_driver_t *gfx_ctx_drivers[] = {
|
||||||
|
#if defined(HAVE_LIBNX) && defined(HAVE_OPENGL)
|
||||||
|
&switch_ctx,
|
||||||
|
#endif
|
||||||
#if defined(__CELLOS_LV2__)
|
#if defined(__CELLOS_LV2__)
|
||||||
&gfx_ctx_ps3,
|
&gfx_ctx_ps3,
|
||||||
#endif
|
#endif
|
||||||
|
@ -2643,7 +2646,7 @@ void video_driver_frame(const void *data, unsigned width,
|
||||||
width = 3840;
|
width = 3840;
|
||||||
if (video_info.crt_switch_resolution_super == 1920)
|
if (video_info.crt_switch_resolution_super == 1920)
|
||||||
width = 1920;
|
width = 1920;
|
||||||
crt_switch_res_core(width, height, video_driver_core_hz);
|
crt_switch_res_core(width, height, video_driver_core_hz, video_info.crt_switch_resolution, video_info.crt_switch_center_adjust);
|
||||||
}
|
}
|
||||||
else if (!video_info.crt_switch_resolution)
|
else if (!video_info.crt_switch_resolution)
|
||||||
video_driver_crt_switching_active = false;
|
video_driver_crt_switching_active = false;
|
||||||
|
@ -2741,8 +2744,9 @@ void video_driver_build_info(video_frame_info_t *video_info)
|
||||||
settings = config_get_ptr();
|
settings = config_get_ptr();
|
||||||
custom_vp = &settings->video_viewport_custom;
|
custom_vp = &settings->video_viewport_custom;
|
||||||
video_info->refresh_rate = settings->floats.video_refresh_rate;
|
video_info->refresh_rate = settings->floats.video_refresh_rate;
|
||||||
video_info->crt_switch_resolution = settings->bools.crt_switch_resolution;
|
video_info->crt_switch_resolution = settings->uints.crt_switch_resolution;
|
||||||
video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super;
|
video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super;
|
||||||
|
video_info->crt_switch_center_adjust = settings->ints.crt_switch_center_adjust;
|
||||||
video_info->black_frame_insertion = settings->bools.video_black_frame_insertion;
|
video_info->black_frame_insertion = settings->bools.video_black_frame_insertion;
|
||||||
video_info->hard_sync = settings->bools.video_hard_sync;
|
video_info->hard_sync = settings->bools.video_hard_sync;
|
||||||
video_info->hard_sync_frames = settings->uints.video_hard_sync_frames;
|
video_info->hard_sync_frames = settings->uints.video_hard_sync_frames;
|
||||||
|
@ -3028,7 +3032,7 @@ static const gfx_ctx_driver_t *video_context_driver_init(
|
||||||
ctx->bind_hw_render(ctx_data,
|
ctx->bind_hw_render(ctx_data,
|
||||||
video_info.shared_context && hw_render_ctx);
|
video_info.shared_context && hw_render_ctx);
|
||||||
|
|
||||||
video_context_driver_set_data(ctx_data);
|
video_context_data = ctx_data;
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
@ -3202,11 +3206,18 @@ bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool video_context_driver_swap_interval(unsigned *interval)
|
bool video_context_driver_swap_interval(int *interval)
|
||||||
{
|
{
|
||||||
|
gfx_ctx_flags_t flags;
|
||||||
|
int current_interval = *interval;
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
bool adaptive_vsync_enabled = video_driver_get_all_flags(&flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC) && settings->bools.video_adaptive_vsync;
|
||||||
|
|
||||||
if (!current_video_context.swap_interval)
|
if (!current_video_context.swap_interval)
|
||||||
return false;
|
return false;
|
||||||
current_video_context.swap_interval(video_context_data, *interval);
|
if (adaptive_vsync_enabled && current_interval == 1)
|
||||||
|
current_interval = -1;
|
||||||
|
current_video_context.swap_interval(video_context_data, current_interval);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3232,14 +3243,26 @@ bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics)
|
||||||
|
|
||||||
bool video_context_driver_get_refresh_rate(float *refresh_rate)
|
bool video_context_driver_get_refresh_rate(float *refresh_rate)
|
||||||
{
|
{
|
||||||
|
float refresh_holder = 0;
|
||||||
|
|
||||||
if (!current_video_context.get_refresh_rate || !refresh_rate)
|
if (!current_video_context.get_refresh_rate || !refresh_rate)
|
||||||
return false;
|
return false;
|
||||||
if (!video_context_data)
|
if (!video_context_data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (refresh_rate)
|
if (!video_driver_crt_switching_active)
|
||||||
*refresh_rate =
|
if (refresh_rate)
|
||||||
current_video_context.get_refresh_rate(video_context_data);
|
*refresh_rate =
|
||||||
|
current_video_context.get_refresh_rate(video_context_data);
|
||||||
|
|
||||||
|
if (video_driver_crt_switching_active)
|
||||||
|
{
|
||||||
|
if (refresh_rate)
|
||||||
|
refresh_holder =
|
||||||
|
current_video_context.get_refresh_rate(video_context_data);
|
||||||
|
if (refresh_holder != video_driver_core_hz) /* Fix for incorrect interlace detsction -- HARD SET VSNC TO REQUIRED REFRESH FOR CRT*/
|
||||||
|
*refresh_rate = video_driver_core_hz;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3317,22 +3340,9 @@ bool video_context_driver_show_mouse(bool *bool_data)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void video_context_driver_set_data(void *data)
|
static bool video_context_driver_get_flags(gfx_ctx_flags_t *flags)
|
||||||
{
|
{
|
||||||
video_context_data = data;
|
if (!current_video_context.get_flags)
|
||||||
}
|
|
||||||
|
|
||||||
bool video_driver_get_flags(gfx_ctx_flags_t *flags)
|
|
||||||
{
|
|
||||||
if (!flags || !video_driver_poke || !video_driver_poke->get_flags)
|
|
||||||
return false;
|
|
||||||
flags->flags = video_driver_poke->get_flags(video_driver_data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool video_context_driver_get_flags(gfx_ctx_flags_t *flags)
|
|
||||||
{
|
|
||||||
if (!flags || !current_video_context.get_flags)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (deferred_video_context_driver_set_flags)
|
if (deferred_video_context_driver_set_flags)
|
||||||
|
@ -3346,6 +3356,34 @@ bool video_context_driver_get_flags(gfx_ctx_flags_t *flags)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool video_driver_get_flags(gfx_ctx_flags_t *flags)
|
||||||
|
{
|
||||||
|
if (!video_driver_poke || !video_driver_poke->get_flags)
|
||||||
|
return false;
|
||||||
|
flags->flags = video_driver_poke->get_flags(video_driver_data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, enum display_flags flag)
|
||||||
|
{
|
||||||
|
if (!flags)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (video_driver_get_flags(flags))
|
||||||
|
if (BIT32_GET(flags->flags, flag))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
flags->flags = 0;
|
||||||
|
|
||||||
|
if (video_context_driver_get_flags(flags))
|
||||||
|
if (BIT32_GET(flags->flags, flag))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool video_context_driver_set_flags(gfx_ctx_flags_t *flags)
|
bool video_context_driver_set_flags(gfx_ctx_flags_t *flags)
|
||||||
{
|
{
|
||||||
if (!flags)
|
if (!flags)
|
||||||
|
|
|
@ -118,7 +118,8 @@ enum display_flags
|
||||||
GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES,
|
GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES,
|
||||||
GFX_CTX_FLAGS_HARD_SYNC,
|
GFX_CTX_FLAGS_HARD_SYNC,
|
||||||
GFX_CTX_FLAGS_BLACK_FRAME_INSERTION,
|
GFX_CTX_FLAGS_BLACK_FRAME_INSERTION,
|
||||||
GFX_CTX_FLAGS_MENU_FRAME_FILTERING
|
GFX_CTX_FLAGS_MENU_FRAME_FILTERING,
|
||||||
|
GFX_CTX_FLAGS_ADAPTIVE_VSYNC
|
||||||
};
|
};
|
||||||
|
|
||||||
enum shader_uniform_type
|
enum shader_uniform_type
|
||||||
|
@ -354,7 +355,7 @@ typedef struct video_info
|
||||||
*/
|
*/
|
||||||
unsigned height;
|
unsigned height;
|
||||||
|
|
||||||
unsigned swap_interval;
|
int swap_interval;
|
||||||
|
|
||||||
#ifdef GEKKO
|
#ifdef GEKKO
|
||||||
bool vfilter;
|
bool vfilter;
|
||||||
|
@ -408,7 +409,6 @@ typedef struct video_frame_info
|
||||||
bool black_frame_insertion;
|
bool black_frame_insertion;
|
||||||
bool hard_sync;
|
bool hard_sync;
|
||||||
bool fps_show;
|
bool fps_show;
|
||||||
bool crt_switch_resolution;
|
|
||||||
bool statistics_show;
|
bool statistics_show;
|
||||||
bool framecount_show;
|
bool framecount_show;
|
||||||
bool scale_integer;
|
bool scale_integer;
|
||||||
|
@ -429,11 +429,13 @@ typedef struct video_frame_info
|
||||||
|
|
||||||
int custom_vp_x;
|
int custom_vp_x;
|
||||||
int custom_vp_y;
|
int custom_vp_y;
|
||||||
|
int crt_switch_center_adjust;
|
||||||
|
|
||||||
unsigned hard_sync_frames;
|
unsigned hard_sync_frames;
|
||||||
unsigned aspect_ratio_idx;
|
unsigned aspect_ratio_idx;
|
||||||
unsigned max_swapchain_images;
|
unsigned max_swapchain_images;
|
||||||
unsigned monitor_index;
|
unsigned monitor_index;
|
||||||
|
unsigned crt_switch_resolution;
|
||||||
unsigned crt_switch_resolution_super;
|
unsigned crt_switch_resolution_super;
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
|
@ -522,7 +524,7 @@ typedef struct gfx_ctx_driver
|
||||||
unsigned major, unsigned minor);
|
unsigned major, unsigned minor);
|
||||||
|
|
||||||
/* Sets the swap interval. */
|
/* Sets the swap interval. */
|
||||||
void (*swap_interval)(void *data, unsigned);
|
void (*swap_interval)(void *data, int);
|
||||||
|
|
||||||
/* Sets video mode. Creates a window, etc. */
|
/* Sets video mode. Creates a window, etc. */
|
||||||
bool (*set_video_mode)(void*, video_frame_info_t *video_info, unsigned, unsigned, bool);
|
bool (*set_video_mode)(void*, video_frame_info_t *video_info, unsigned, unsigned, bool);
|
||||||
|
@ -1166,7 +1168,7 @@ void video_context_driver_destroy(void);
|
||||||
|
|
||||||
bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data);
|
bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data);
|
||||||
|
|
||||||
bool video_context_driver_swap_interval(unsigned *interval);
|
bool video_context_driver_swap_interval(int *interval);
|
||||||
|
|
||||||
bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc);
|
bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc);
|
||||||
|
|
||||||
|
@ -1184,12 +1186,6 @@ bool video_context_driver_get_context_data(void *data);
|
||||||
|
|
||||||
bool video_context_driver_show_mouse(bool *bool_data);
|
bool video_context_driver_show_mouse(bool *bool_data);
|
||||||
|
|
||||||
void video_context_driver_set_data(void *data);
|
|
||||||
|
|
||||||
bool video_driver_get_flags(gfx_ctx_flags_t *flags);
|
|
||||||
|
|
||||||
bool video_context_driver_get_flags(gfx_ctx_flags_t *flags);
|
|
||||||
|
|
||||||
bool video_context_driver_set_flags(gfx_ctx_flags_t *flags);
|
bool video_context_driver_set_flags(gfx_ctx_flags_t *flags);
|
||||||
|
|
||||||
bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics);
|
bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics);
|
||||||
|
@ -1248,6 +1244,9 @@ bool video_driver_started_fullscreen(void);
|
||||||
|
|
||||||
bool video_driver_is_threaded(void);
|
bool video_driver_is_threaded(void);
|
||||||
|
|
||||||
|
bool video_driver_get_all_flags(gfx_ctx_flags_t *flags,
|
||||||
|
enum display_flags flag);
|
||||||
|
|
||||||
extern video_driver_t video_gl;
|
extern video_driver_t video_gl;
|
||||||
extern video_driver_t video_vulkan;
|
extern video_driver_t video_vulkan;
|
||||||
extern video_driver_t video_metal;
|
extern video_driver_t video_metal;
|
||||||
|
@ -1299,6 +1298,7 @@ extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev;
|
||||||
extern const gfx_ctx_driver_t gfx_ctx_khr_display;
|
extern const gfx_ctx_driver_t gfx_ctx_khr_display;
|
||||||
extern const gfx_ctx_driver_t gfx_ctx_gdi;
|
extern const gfx_ctx_driver_t gfx_ctx_gdi;
|
||||||
extern const gfx_ctx_driver_t gfx_ctx_sixel;
|
extern const gfx_ctx_driver_t gfx_ctx_sixel;
|
||||||
|
extern const gfx_ctx_driver_t switch_ctx;
|
||||||
extern const gfx_ctx_driver_t gfx_ctx_null;
|
extern const gfx_ctx_driver_t gfx_ctx_null;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -940,6 +940,8 @@ FRONTEND
|
||||||
#include "../frontend/drivers/platform_psp.c"
|
#include "../frontend/drivers/platform_psp.c"
|
||||||
#elif defined(_3DS)
|
#elif defined(_3DS)
|
||||||
#include "../frontend/drivers/platform_ctr.c"
|
#include "../frontend/drivers/platform_ctr.c"
|
||||||
|
#elif defined(SWITCH) && defined(HAVE_LIBNX)
|
||||||
|
#include "../frontend/drivers/platform_switch.c"
|
||||||
#elif defined(XENON)
|
#elif defined(XENON)
|
||||||
#include "../frontend/drivers/platform_xenon.c"
|
#include "../frontend/drivers/platform_xenon.c"
|
||||||
#elif defined(__QNX__)
|
#elif defined(__QNX__)
|
||||||
|
@ -1135,7 +1137,6 @@ MENU
|
||||||
#ifdef HAVE_MENU
|
#ifdef HAVE_MENU
|
||||||
#include "../menu/menu_driver.c"
|
#include "../menu/menu_driver.c"
|
||||||
#include "../menu/menu_input.c"
|
#include "../menu/menu_input.c"
|
||||||
#include "../menu/menu_event.c"
|
|
||||||
#include "../menu/menu_entries.c"
|
#include "../menu/menu_entries.c"
|
||||||
#include "../menu/menu_setting.c"
|
#include "../menu/menu_setting.c"
|
||||||
#include "../menu/menu_cbs.c"
|
#include "../menu/menu_cbs.c"
|
||||||
|
@ -1215,6 +1216,10 @@ MENU
|
||||||
#include "../menu/drivers_display/menu_display_wiiu.c"
|
#include "../menu/drivers_display/menu_display_wiiu.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_LIBNX)
|
||||||
|
#include "../menu/drivers_display/menu_display_switch.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_CACA
|
#ifdef HAVE_CACA
|
||||||
#include "../menu/drivers_display/menu_display_caca.c"
|
#include "../menu/drivers_display/menu_display_caca.c"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1421,6 +1426,7 @@ HTTP SERVER
|
||||||
SSL
|
SSL
|
||||||
============================================================ */
|
============================================================ */
|
||||||
#if defined(HAVE_SSL)
|
#if defined(HAVE_SSL)
|
||||||
|
#if defined(HAVE_NETWORKING)
|
||||||
#include "../deps/mbedtls/aes.c"
|
#include "../deps/mbedtls/aes.c"
|
||||||
#include "../deps/mbedtls/aesni.c"
|
#include "../deps/mbedtls/aesni.c"
|
||||||
#include "../deps/mbedtls/arc4.c"
|
#include "../deps/mbedtls/arc4.c"
|
||||||
|
@ -1497,3 +1503,4 @@ SSL
|
||||||
|
|
||||||
#include "../libretro-common/net/net_socket_ssl.c"
|
#include "../libretro-common/net/net_socket_ssl.c"
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
|
@ -33,7 +33,9 @@ MENU
|
||||||
UI
|
UI
|
||||||
============================================================ */
|
============================================================ */
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
|
#ifndef __APPLE__
|
||||||
#define HAVE_MAIN /* also requires defining in frontend.c */
|
#define HAVE_MAIN /* also requires defining in frontend.c */
|
||||||
|
#endif
|
||||||
#include "../ui/drivers/ui_qt.cpp"
|
#include "../ui/drivers/ui_qt.cpp"
|
||||||
|
|
||||||
#include "../ui/drivers/qt/ui_qt_window.cpp"
|
#include "../ui/drivers/qt/ui_qt_window.cpp"
|
||||||
|
@ -53,6 +55,15 @@ UI
|
||||||
#include "../ui/drivers/qt/thumbnaildownload.cpp"
|
#include "../ui/drivers/qt/thumbnaildownload.cpp"
|
||||||
#include "../ui/drivers/qt/thumbnailpackdownload.cpp"
|
#include "../ui/drivers/qt/thumbnailpackdownload.cpp"
|
||||||
#include "../ui/drivers/qt/playlistthumbnaildownload.cpp"
|
#include "../ui/drivers/qt/playlistthumbnaildownload.cpp"
|
||||||
|
#include "../ui/drivers/moc_ui_qt.cpp"
|
||||||
|
#include "../ui/drivers/qt/moc_coreinfodialog.cpp"
|
||||||
|
#include "../ui/drivers/qt/moc_coreoptionsdialog.cpp"
|
||||||
|
#include "../ui/drivers/qt/moc_filedropwidget.cpp"
|
||||||
|
#include "../ui/drivers/qt/moc_flowlayout.cpp"
|
||||||
|
#include "../ui/drivers/qt/moc_playlistentrydialog.cpp"
|
||||||
|
#include "../ui/drivers/qt/moc_shaderparamsdialog.cpp"
|
||||||
|
#include "../ui/drivers/qt/moc_ui_qt_load_core_window.cpp"
|
||||||
|
#include "../ui/drivers/qt/moc_viewoptionsdialog.cpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*============================================================
|
/*============================================================
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
#include "../../config.h"
|
#include "../../config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
#include <switch.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../input_driver.h"
|
#include "../input_driver.h"
|
||||||
|
|
||||||
#define MAX_PADS 10
|
#define MAX_PADS 10
|
||||||
|
|
|
@ -2,8 +2,13 @@
|
||||||
#include "../../config.h"
|
#include "../../config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include<libtransistor/nx.h>
|
#ifdef HAVE_LIBNX
|
||||||
|
#include <switch.h>
|
||||||
|
#else
|
||||||
|
#include <libtransistor/nx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../configuration.h"
|
||||||
#include "../input_driver.h"
|
#include "../input_driver.h"
|
||||||
|
|
||||||
#include "../../tasks/tasks_internal.h"
|
#include "../../tasks/tasks_internal.h"
|
||||||
|
@ -13,10 +18,20 @@
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
|
||||||
|
#ifndef MAX_PADS
|
||||||
|
#define MAX_PADS 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#ifndef MAX_PADS
|
#ifndef MAX_PADS
|
||||||
#define MAX_PADS 10
|
#define MAX_PADS 10
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static uint16_t pad_state[MAX_PADS];
|
static uint16_t pad_state[MAX_PADS];
|
||||||
static int16_t analog_state[MAX_PADS][2][2];
|
static int16_t analog_state[MAX_PADS][2][2];
|
||||||
extern uint64_t lifecycle_state;
|
extern uint64_t lifecycle_state;
|
||||||
|
@ -40,10 +55,16 @@ static void switch_joypad_autodetect_add(unsigned autoconf_pad)
|
||||||
|
|
||||||
static bool switch_joypad_init(void *data)
|
static bool switch_joypad_init(void *data)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
unsigned i;
|
||||||
|
hidScanInput();
|
||||||
|
for (i = 0; i < MAX_PADS; i++)
|
||||||
|
switch_joypad_autodetect_add(i);
|
||||||
|
#else
|
||||||
hid_init();
|
hid_init();
|
||||||
|
|
||||||
switch_joypad_autodetect_add(0);
|
switch_joypad_autodetect_add(0);
|
||||||
switch_joypad_autodetect_add(1);
|
switch_joypad_autodetect_add(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -126,27 +147,80 @@ static bool switch_joypad_query_pad(unsigned pad)
|
||||||
|
|
||||||
static void switch_joypad_destroy(void)
|
static void switch_joypad_destroy(void)
|
||||||
{
|
{
|
||||||
|
#ifndef HAVE_LIBNX
|
||||||
hid_finalize();
|
hid_finalize();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNX
|
||||||
|
int lastMode = 0; // 0 = handheld, 1 = whatever
|
||||||
|
|
||||||
static void switch_joypad_poll(void)
|
static void switch_joypad_poll(void)
|
||||||
{
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
hidScanInput();
|
||||||
|
|
||||||
|
// TODO: Options via menu
|
||||||
|
/*if (settings->bools.split_joycon && !hidGetHandheldMode())
|
||||||
|
{
|
||||||
|
if (lastMode != 1)
|
||||||
|
{
|
||||||
|
RARCH_LOG("[HID] Enable Split Joycon!\n");
|
||||||
|
hidSetNpadJoyAssignmentModeSingleByDefault(CONTROLLER_PLAYER_1);
|
||||||
|
hidSetNpadJoyAssignmentModeSingleByDefault(CONTROLLER_PLAYER_2);
|
||||||
|
lastMode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (lastMode != 0)
|
||||||
|
{
|
||||||
|
RARCH_LOG("[HID] Disable Split Joycon!\n");
|
||||||
|
hidSetNpadJoyAssignmentModeDual(CONTROLLER_PLAYER_1);
|
||||||
|
hidSetNpadJoyAssignmentModeDual(CONTROLLER_PLAYER_2);
|
||||||
|
lastMode = 0;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_PADS; i++)
|
||||||
|
{
|
||||||
|
HidControllerID target = (i == 0) ? CONTROLLER_P1_AUTO : i;
|
||||||
|
pad_state[i] = hidKeysDown(target) | hidKeysHeld(target);
|
||||||
|
JoystickPosition joyPositionLeft, joyPositionRight;
|
||||||
|
hidJoystickRead(&joyPositionLeft, target, JOYSTICK_LEFT);
|
||||||
|
hidJoystickRead(&joyPositionRight, target, JOYSTICK_RIGHT);
|
||||||
|
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_X] = joyPositionLeft.dx;
|
||||||
|
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_Y] = -joyPositionLeft.dy;
|
||||||
|
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X] = joyPositionRight.dx;
|
||||||
|
analog_state[i][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y] = -joyPositionRight.dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void switch_joypad_poll(void)
|
||||||
|
{
|
||||||
|
int16_t lsx, lsy, rsx, rsy;
|
||||||
hid_controller_t *controllers = hid_get_shared_memory()->controllers;
|
hid_controller_t *controllers = hid_get_shared_memory()->controllers;
|
||||||
hid_controller_t *cont = &controllers[0];
|
hid_controller_t *cont = &controllers[0];
|
||||||
hid_controller_state_entry_t ent = cont->main.entries[cont->main.latest_idx];
|
hid_controller_state_entry_t ent = cont->main.entries[cont->main.latest_idx];
|
||||||
hid_controller_state_entry_t ent8 = (cont+8)->main.entries[(cont+8)->main.latest_idx];
|
hid_controller_state_entry_t ent8 = (cont+8)->main.entries[(cont+8)->main.latest_idx];
|
||||||
pad_state[0] = ent.button_state | ent8.button_state;
|
pad_state[0] = ent.button_state | ent8.button_state;
|
||||||
|
|
||||||
int16_t lsx, lsy, rsx, rsy;
|
lsx = ent.left_stick_x;
|
||||||
lsx = ent.left_stick_x;
|
lsy = ent.left_stick_y;
|
||||||
lsy = ent.left_stick_y;
|
rsx = ent.right_stick_x;
|
||||||
rsx = ent.right_stick_x;
|
rsy = ent.right_stick_y;
|
||||||
rsy = ent.right_stick_y;
|
|
||||||
if(ent8.left_stick_x != 0 || ent8.left_stick_y != 0) { // handheld overrides player 1
|
if (ent8.left_stick_x != 0 || ent8.left_stick_y != 0)
|
||||||
|
{
|
||||||
|
/* handheld overrides player 1 */
|
||||||
lsx = ent8.left_stick_x;
|
lsx = ent8.left_stick_x;
|
||||||
lsy = ent8.left_stick_y;
|
lsy = ent8.left_stick_y;
|
||||||
}
|
}
|
||||||
if(ent8.right_stick_x != 0 || ent8.right_stick_y != 0) { // handheld overrides player 1
|
|
||||||
|
if (ent8.right_stick_x != 0 || ent8.right_stick_y != 0)
|
||||||
|
{
|
||||||
|
/* handheld overrides player 1 */
|
||||||
rsx = ent8.right_stick_x;
|
rsx = ent8.right_stick_x;
|
||||||
rsy = ent8.right_stick_y;
|
rsy = ent8.right_stick_y;
|
||||||
}
|
}
|
||||||
|
@ -156,6 +230,7 @@ static void switch_joypad_poll(void)
|
||||||
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X] = rsx;
|
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X] = rsx;
|
||||||
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y] = -rsy;
|
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y] = -rsy;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
input_device_driver_t switch_joypad = {
|
input_device_driver_t switch_joypad = {
|
||||||
switch_joypad_init,
|
switch_joypad_init,
|
||||||
|
|
|
@ -668,7 +668,7 @@ const char* const input_builtin_autoconfs[] =
|
||||||
#ifdef __CELLOS_LV2__
|
#ifdef __CELLOS_LV2__
|
||||||
DECL_AUTOCONF_DEVICE("SixAxis Controller", "ps3", PS3INPUT_DEFAULT_BINDS),
|
DECL_AUTOCONF_DEVICE("SixAxis Controller", "ps3", PS3INPUT_DEFAULT_BINDS),
|
||||||
#endif
|
#endif
|
||||||
#ifdef __SWITCH__
|
#if defined(__SWITCH__) || defined(SWITCH)
|
||||||
DECL_AUTOCONF_DEVICE("Switch Controller", "switch", SWITCH_DEFAULT_BINDS),
|
DECL_AUTOCONF_DEVICE("Switch Controller", "switch", SWITCH_DEFAULT_BINDS),
|
||||||
#endif
|
#endif
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef EMSCRIPTEN
|
||||||
|
|
|
@ -28,7 +28,7 @@ RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
#define MAX_INPUT_DEVICES 16
|
#define MAX_INPUT_DEVICES 16
|
||||||
|
|
||||||
#define RARCH_MAX_KEYS 136
|
#define RARCH_MAX_KEYS 137
|
||||||
|
|
||||||
#define RARCH_FIRST_CUSTOM_BIND 16
|
#define RARCH_FIRST_CUSTOM_BIND 16
|
||||||
#define RARCH_FIRST_LIGHTGUN_BIND RARCH_ANALOG_BIND_LIST_END
|
#define RARCH_FIRST_LIGHTGUN_BIND RARCH_ANALOG_BIND_LIST_END
|
||||||
|
@ -85,7 +85,7 @@ enum
|
||||||
RARCH_STATE_SLOT_PLUS,
|
RARCH_STATE_SLOT_PLUS,
|
||||||
RARCH_STATE_SLOT_MINUS,
|
RARCH_STATE_SLOT_MINUS,
|
||||||
RARCH_REWIND,
|
RARCH_REWIND,
|
||||||
RARCH_MOVIE_RECORD_TOGGLE,
|
RARCH_BSV_RECORD_TOGGLE,
|
||||||
RARCH_PAUSE_TOGGLE,
|
RARCH_PAUSE_TOGGLE,
|
||||||
RARCH_FRAMEADVANCE,
|
RARCH_FRAMEADVANCE,
|
||||||
RARCH_RESET,
|
RARCH_RESET,
|
||||||
|
@ -111,6 +111,9 @@ enum
|
||||||
|
|
||||||
RARCH_MENU_TOGGLE,
|
RARCH_MENU_TOGGLE,
|
||||||
|
|
||||||
|
RARCH_RECORDING_TOGGLE,
|
||||||
|
RARCH_STREAMING_TOGGLE,
|
||||||
|
|
||||||
RARCH_BIND_LIST_END,
|
RARCH_BIND_LIST_END,
|
||||||
RARCH_BIND_LIST_END_NULL
|
RARCH_BIND_LIST_END_NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -325,7 +325,7 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = {
|
||||||
DECLARE_META_BIND(2, state_slot_increase, RARCH_STATE_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS),
|
DECLARE_META_BIND(2, state_slot_increase, RARCH_STATE_SLOT_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS),
|
||||||
DECLARE_META_BIND(2, state_slot_decrease, RARCH_STATE_SLOT_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS),
|
DECLARE_META_BIND(2, state_slot_decrease, RARCH_STATE_SLOT_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS),
|
||||||
DECLARE_META_BIND(1, rewind, RARCH_REWIND, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND),
|
DECLARE_META_BIND(1, rewind, RARCH_REWIND, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND),
|
||||||
DECLARE_META_BIND(2, movie_record_toggle, RARCH_MOVIE_RECORD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE),
|
DECLARE_META_BIND(2, movie_record_toggle, RARCH_BSV_RECORD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_BSV_RECORD_TOGGLE),
|
||||||
DECLARE_META_BIND(2, pause_toggle, RARCH_PAUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE),
|
DECLARE_META_BIND(2, pause_toggle, RARCH_PAUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE),
|
||||||
DECLARE_META_BIND(2, frame_advance, RARCH_FRAMEADVANCE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE),
|
DECLARE_META_BIND(2, frame_advance, RARCH_FRAMEADVANCE, MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE),
|
||||||
DECLARE_META_BIND(2, reset, RARCH_RESET, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET),
|
DECLARE_META_BIND(2, reset, RARCH_RESET, MENU_ENUM_LABEL_VALUE_INPUT_META_RESET),
|
||||||
|
@ -351,6 +351,8 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = {
|
||||||
#ifdef HAVE_MENU
|
#ifdef HAVE_MENU
|
||||||
DECLARE_META_BIND(1, menu_toggle, RARCH_MENU_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE),
|
DECLARE_META_BIND(1, menu_toggle, RARCH_MENU_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE),
|
||||||
#endif
|
#endif
|
||||||
|
DECLARE_META_BIND(2, recording_toggle, RARCH_RECORDING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RECORDING_TOGGLE),
|
||||||
|
DECLARE_META_BIND(2, streaming_toggle, RARCH_STREAMING_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STREAMING_TOGGLE),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -288,6 +288,7 @@ const struct input_key_map input_config_key_map[] = {
|
||||||
{ "euro", RETROK_EURO },
|
{ "euro", RETROK_EURO },
|
||||||
{ "undo", RETROK_UNDO },
|
{ "undo", RETROK_UNDO },
|
||||||
{ "clear", RETROK_CLEAR },
|
{ "clear", RETROK_CLEAR },
|
||||||
|
{ "oem102", RETROK_OEM_102 },
|
||||||
|
|
||||||
{ "nul", RETROK_UNKNOWN },
|
{ "nul", RETROK_UNKNOWN },
|
||||||
{ NULL, RETROK_UNKNOWN },
|
{ NULL, RETROK_UNKNOWN },
|
||||||
|
@ -328,7 +329,7 @@ const struct rarch_key_map rarch_key_map_sdl[] = {
|
||||||
{ SDLK_9, RETROK_9 },
|
{ SDLK_9, RETROK_9 },
|
||||||
{ SDLK_COLON, RETROK_COLON },
|
{ SDLK_COLON, RETROK_COLON },
|
||||||
{ SDLK_SEMICOLON, RETROK_SEMICOLON },
|
{ SDLK_SEMICOLON, RETROK_SEMICOLON },
|
||||||
{ SDLK_LESS, RETROK_LESS },
|
{ SDLK_LESS, RETROK_OEM_102 },
|
||||||
{ SDLK_EQUALS, RETROK_EQUALS },
|
{ SDLK_EQUALS, RETROK_EQUALS },
|
||||||
{ SDLK_GREATER, RETROK_GREATER },
|
{ SDLK_GREATER, RETROK_GREATER },
|
||||||
{ SDLK_QUESTION, RETROK_QUESTION },
|
{ SDLK_QUESTION, RETROK_QUESTION },
|
||||||
|
@ -574,6 +575,7 @@ const struct rarch_key_map rarch_key_map_dinput[] = {
|
||||||
{ DIK_SCROLL, RETROK_SCROLLOCK },
|
{ DIK_SCROLL, RETROK_SCROLLOCK },
|
||||||
{ DIK_CAPSLOCK, RETROK_CAPSLOCK },
|
{ DIK_CAPSLOCK, RETROK_CAPSLOCK },
|
||||||
{ DIK_NUMLOCK, RETROK_NUMLOCK },
|
{ DIK_NUMLOCK, RETROK_NUMLOCK },
|
||||||
|
{ DIK_OEM_102, RETROK_OEM_102 },
|
||||||
{ 0, RETROK_UNKNOWN },
|
{ 0, RETROK_UNKNOWN },
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -831,6 +833,7 @@ const struct rarch_key_map rarch_key_map_x11[] = {
|
||||||
/*{ ?, RETROK_POWER },*/
|
/*{ ?, RETROK_POWER },*/
|
||||||
{ XK_EuroSign, RETROK_EURO },
|
{ XK_EuroSign, RETROK_EURO },
|
||||||
{ XK_Undo, RETROK_UNDO },
|
{ XK_Undo, RETROK_UNDO },
|
||||||
|
/*{ ?, RETROK_OEM_102 },*/
|
||||||
/* FIXME(shizeeg): RetroArch can't handle these buttons atm.
|
/* FIXME(shizeeg): RetroArch can't handle these buttons atm.
|
||||||
* Do we really need RETROK_KP_INSERT, RETROK_KP_END,
|
* Do we really need RETROK_KP_INSERT, RETROK_KP_END,
|
||||||
* RETROK_KP_DOWN, RETROK_KP_PAGEDOWN ???
|
* RETROK_KP_DOWN, RETROK_KP_PAGEDOWN ???
|
||||||
|
@ -986,6 +989,7 @@ const struct rarch_key_map rarch_key_map_linux[] = {
|
||||||
{ KEY_EURO, RETROK_EURO },
|
{ KEY_EURO, RETROK_EURO },
|
||||||
#endif
|
#endif
|
||||||
{ KEY_UNDO, RETROK_UNDO },
|
{ KEY_UNDO, RETROK_UNDO },
|
||||||
|
/*{ ?, RETROK_OEM_102 },*/
|
||||||
{ 0, RETROK_UNKNOWN },
|
{ 0, RETROK_UNKNOWN },
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -1320,6 +1324,7 @@ const struct rarch_key_map rarch_key_map_apple_hid[] = {
|
||||||
/* { ?, RETROK_POWER }, */
|
/* { ?, RETROK_POWER }, */
|
||||||
/* { ?, RETROK_EURO }, */
|
/* { ?, RETROK_EURO }, */
|
||||||
/* { ?, RETROK_UNDO }, */
|
/* { ?, RETROK_UNDO }, */
|
||||||
|
{ KEY_NonUSBackslash, RETROK_OEM_102 },
|
||||||
{ 0, RETROK_UNKNOWN }
|
{ 0, RETROK_UNKNOWN }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -221,15 +221,19 @@ void input_mapper_poll(input_mapper_t *handle)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int invert = 1;
|
int invert = 1;
|
||||||
|
unsigned remap_axis_bind = remap_axis - RARCH_FIRST_CUSTOM_BIND;
|
||||||
|
|
||||||
if ( (k % 2 == 0 && remap_axis % 2 != 0) ||
|
if ( (k % 2 == 0 && remap_axis % 2 != 0) ||
|
||||||
(k % 2 != 0 && remap_axis % 2 == 0)
|
(k % 2 != 0 && remap_axis % 2 == 0)
|
||||||
)
|
)
|
||||||
invert = -1;
|
invert = -1;
|
||||||
|
|
||||||
handle->analog_value[i][
|
if (remap_axis_bind < sizeof(handle->analog_value[i]))
|
||||||
remap_axis - RARCH_FIRST_CUSTOM_BIND] =
|
{
|
||||||
current_axis_value * invert;
|
handle->analog_value[i][
|
||||||
|
remap_axis_bind] =
|
||||||
|
current_axis_value * invert;
|
||||||
|
}
|
||||||
#if 0
|
#if 0
|
||||||
RARCH_LOG("axis %d(%d) remapped to axis %d val %d\n",
|
RARCH_LOG("axis %d(%d) remapped to axis %d val %d\n",
|
||||||
j, k,
|
j, k,
|
||||||
|
|
|
@ -233,17 +233,17 @@ static void input_overlay_set_vertex_geom(input_overlay_t *ol)
|
||||||
ol->active->mod_x, ol->active->mod_y,
|
ol->active->mod_x, ol->active->mod_y,
|
||||||
ol->active->mod_w, ol->active->mod_h);
|
ol->active->mod_w, ol->active->mod_h);
|
||||||
|
|
||||||
for (i = 0; i < ol->active->size; i++)
|
if (ol->iface->vertex_geom)
|
||||||
{
|
for (i = 0; i < ol->active->size; i++)
|
||||||
struct overlay_desc *desc = &ol->active->descs[i];
|
{
|
||||||
|
struct overlay_desc *desc = &ol->active->descs[i];
|
||||||
|
|
||||||
if (!desc->image.pixels)
|
if (!desc->image.pixels)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ol->iface->vertex_geom)
|
|
||||||
ol->iface->vertex_geom(ol->iface_data, desc->image_index,
|
ol->iface->vertex_geom(ol->iface_data, desc->image_index,
|
||||||
desc->mod_x, desc->mod_y, desc->mod_w, desc->mod_h);
|
desc->mod_x, desc->mod_y, desc->mod_w, desc->mod_h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue