Compare commits

...
Author SHA1 Message Date
Autechre 36888612eb Reduce gfx_display_rotate_z calls in menu drivers (#12937)
* (Ozone) Take out gfx_display_rotate_z out of ozone_draw_icon -
lots of matrix rotates and multiplies were happening when
just calling it once would suffice

* (MaterialUI) Reduce calls to gfx_display_rotate_z

* (XMB) Cleanup
2021-09-05 03:46:52 +02:00
twinaphex f597138827 Cleanups 2021-09-04 21:40:37 +02:00
twinaphex 623e09dc47 Fix wording 2021-09-04 21:38:33 +02:00
twinaphex b05a0d5aed * Enable HDR for WinRT/UWP (only works on PC UWP for now, won't work on Xbox yet swapchain
issues with both D3D11/12)
* Add sublabel for Expand Gamut
*
2021-09-04 21:36:48 +02:00
MajorPainTheCactusandAutechre 536d18778b Fixed up HDR for UWP/WinRT builds (#12936)
Fixed D3D11 validation warnings
Fixed up technically incorrect labels

Co-authored-by: Autechre <[email protected]>
2021-09-04 21:13:24 +02:00
twinaphex 28d1788e1e (HDR) Add sublabels 2021-09-04 19:59:16 +02:00
Víctor "IlDucci 017f9f8939 Fetch translations from Crowdin 04-Sep-2021 (#12934) 2021-09-04 17:43:20 +02:00
Víctor "IlDucci 916ebb98e7 Fixing a couple of minor typos related to the HDR PR. (#12935) 2021-09-04 17:43:11 +02:00
twinaphex 85c0607696 Add to CHANGES.md 2021-09-04 10:32:43 +02:00
twinaphex 43838dc4ea Bump version 2021-09-04 10:30:46 +02:00
twinaphex f905012376 Simplify float_to_s16/s16_to_float functions for ARM NEON ASM codepath 2021-09-04 00:39:49 +02:00
twinaphex 6d1c0e96a3 Simplify sinc NEON code 2021-09-04 00:35:45 +02:00
Autechre 9a5f4602cc Add intrinsic NEON versions for float_to_s16/s16_to_float (#12933)
* Add intrinsic NEON versions for float_to_s16/s16_to_float courtesy
of davidgfnet

* Define -DDONT_WANT_ARM_OPTIMIZATIONS for resampler sinc - this should
default to intrinsic versions

* Default to ARM NEON intrinsic codepath and make the ASM codepaths
optional by defining HAVE_ARM_NEON_ASM_OPTIMIZATIONS

* (Pkg/apple/Android) Take out ASM files being compiled in
2021-09-04 00:25:21 +02:00
twinaphex 19f4504943 Prevent collision with quasi88 in statically linked cores 2021-09-03 21:29:38 +02:00
bulzipke 8adc24ecbc (3DS) Add bottom screen menu (#12470)
* (3DS) Add bottom screen menu
 -> User can save/load state on botom screen with thumbnail.
 -> Call a save_state_to_file() when RAM state has data to write a disk.
 -> If the bottom screen needs updating, swap the bottom framebuffers.

Add: SAVE/LODE STATE TO RAM
 -> This is useful for devices with slow I/O
 -> 3DS bottom save state use CMD_EVENT_SAVE_STATE_TO_RAM
 -> 3DS bottom load state use CMD_EVENT_LOAD_STATE when RAM state has no data
 -> 3DS bottom load state use CMD_EVENT_LOAD_STATE_FROM_RAM when RAM sate has data

* Rewrite path_get_state to retroarch_get_current_savestate_path

* Fix unterminated state_path
2021-09-03 18:14:03 +02:00
Autechre 51dcad6cb3 Merge pull request #12932 from jdgleaver/cheat-search
Add enhanced search functionality to the 'Cheats' menu
2021-09-03 17:03:58 +02:00
Autechre 204834f88e Merge pull request #12927 from 3rd-fork/master
code clean up and simplification of uwp vfs driver
2021-09-03 17:03:34 +02:00
Autechre e39784189e Merge pull request #12772 from DisasterMo/core_option_translation
New example_translation core options sample
2021-09-03 16:59:42 +02:00
Autechre 87b40b7c57 Merge pull request #12930 from bslenul/master
Update menu toggle combo list in retroarch.cfg
2021-09-03 16:49:13 +02:00
Autechre 588c1305c8 Merge pull request #12931 from jdgleaver/runahead-cheats
Fix cheats when using second instance runahead
2021-09-03 16:48:30 +02:00
jdgleaver 508b0c2ee2 Add enhanced search functionality to the 'Cheats' menu 2021-09-03 14:58:33 +01:00
jdgleaver 743aea1810 Fix cheats when using second instance runahead 2021-09-03 11:27:12 +01:00
bslenul 76f114a9fe Update menu toggle combo list 2021-09-03 12:10:05 +02:00
twinaphex 274638b89e (D3D11) Look at D3D11 feature level - if we are 11.0 or above,
we use Shader Model 5.0 instead of the default SM 4.0 - this fixes
FSR on D3D11 which requires SM5.0
2021-09-03 07:51:44 +02:00
twinaphex b900555494 (D3D11) Add logging after device creation so we can see which
feature level it used
2021-09-03 07:15:53 +02:00
twinaphex a0e4d64c3b menu_bind_state struct definitions need to be moved over to menu_input.h 2021-09-03 06:48:06 +02:00
twinaphex 93dbd746db (Android) Buildfix 2021-09-03 06:31:40 +02:00
Autechre 7b9cbc08d7 Add HDR support for D3D12 (rebased PR from MajorPainTheCactus) (#12917)
* Add HDR support

* Attempt to fix Mingw build and Metal builds

* (D3D12) Fix relative header includes

* Add missing hdr_sm5.hlsl.h

* (d3d12_common.c) Some C89 build fixes

* Fix MSVC build

* - Attempt to fix build on mingw/msys unix with dirty hack
- Fix shader compilation of hdr_sm5.hlsl.h on MSVC/Visual Studio -
the define was seen as an error and was causing the first pipeline
to error out
- Make sure we manually set handle of backBuffer to NULL

* Moving the release of the texture above the freeing of desc.srv_heap
and desc.rtv_heap solves the hard crashes on teardown/setup in RA -
it was crashing hard in d3d12_release_texture before

* Add HAVE_D3D12_HDR ifdef - needs to be disabled for WinRT for now
because of several things that are Windows desktop-specific right now
(GetWindowRect)

* Add dirty GUID hack - should work for both mingw/msys on Windows/Linux
as well as MSVC/Visual Studio (hopefully)

* Change HAVE_D3D12_HDR to HAVE_DXGI_HDR

* Move away from camelcase named variables

* Fix RARCH_ERR logs - they need a newline at the end

* d3d12_check_display_hdr_support - make it return a bool on return
and set d3d12->hdr.support and d3d12->hdr.enable outside of the
function

* (DXGI) Remove D3D12 dependencies from dxgi_check_display_hdr_support and
move it to dxgi_common.c instead

* (DXGI) move d3d12_swapchain_color_space over to dxgi_common.c and
rename it dxgi_swapchain_color_space

* (DXGI) move d3d12_set_hdr_metadata to dxgi_common.c and
rename it dxgi_set_hdr_metadata

* (DXGI) dxgi_check_display_hdr_support - better error handling?

* Fix typo

* Remove video_force_resolution

* (D3D12) Address TODO/FIXME

* (D3D12) Backport
https://github.com/libretro/RetroArch/pull/12916/commits/c1b6c0bff2aa33cde035b43cb31ac7e78ff2a07a
- Fixed resource transition for present when HDR is off
Fixed cel shader displaying all black as blending was enabled when the hdr shader was being applied - turned off blending during this shader

* Move d3d12_hdr_uniform_t to dxgi_common.h and
rename it dxgi_hdr_uniform_t

* (D3D11) Add HDR support

* Add TODO/FIXME notes

* Cache hdr_enable in video_frame_info_t

* Update comment
2021-09-03 06:15:25 +02:00
Tunip3 9228a6f8ab disable cpu model check on xbox as it doesn't work and can even crash the app for some users 2021-09-02 18:21:16 +01:00
Michael Burgardt f6f7d145d2 Add core options translation scripts 2021-09-02 19:07:28 +02:00
twinaphex 868865c388 Include "config.h" before including msg_hash.h - we were
getting a crash at startup of the Qt desktop interface because
we didn't do this
2021-09-02 01:12:24 +02:00
Autechre ad01f5d5b6 Merge pull request #12923 from jdgleaver/mixer-reinit
Ensure than menu sounds are re-enabled when calling CMD_EVENT_AUDIO_REINIT
2021-09-01 19:10:53 +02:00
jdgleaver 48d9df6bb7 Ensure than menu sounds are re-enabled when calling CMD_EVENT_AUDIO_REINIT 2021-09-01 17:59:46 +01:00
Autechre 11b88c748e Merge pull request #12921 from jdgleaver/menu-sounds-fix
Fix menu sounds (audio mixing) when using the 'sinc' resampler with quality lower than 'normal'
2021-09-01 17:57:34 +02:00
jdgleaver 547f04b894 Fix menu sounds (audio mixing) when using the 'sinc' resampler with quality lower than 'normal' 2021-09-01 15:55:58 +01:00
twinaphex 9ea6f15c1d (Ozone) Forgot to add ozone.c file 2021-08-31 18:43:58 +02:00
twinaphex d0d495edc3 Combine all ozone files into one - discussed internally first -
allows us to modify the scope of the global variables from public
to static - also allows for easier refactors amongst
XMB/materialui/Ozone/RGUI later
2021-08-31 18:42:43 +02:00
twinaphex a785bd8d80 Remove HAVE_STRIPES - unfinished and unusable menu driver right
now
2021-08-31 17:50:24 +02:00
Autechre 256713e888 Merge pull request #12914 from libretro/move-code-over-to-menu-driver
Move lots of menu code over to menu/menu_driver.c
2021-08-31 14:20:42 +02:00
twinaphex fb35460c6d Move more code over 2021-08-31 01:47:57 +02:00
twinaphex 5677799faf Move more code over 2021-08-31 01:27:36 +02:00
twinaphex fc4081cd8f Fix some builds 2021-08-31 00:55:46 +02:00
twinaphex 0db409d5b5 Move lots of menu code over to menu/menu_driver.c - moved at least
44Kb of code over
2021-08-31 00:43:04 +02:00
twinaphex 70ebc85b6c Buildfix for targets with no HAVE_OVERLAY defined 2021-08-30 22:58:53 +02:00
twinaphex dbf3e278dd menu_driver_toggle - cleanups 2021-08-30 22:31:30 +02:00
twinaphex 03c54a9854 Cleanup menu_event and nested functions so that we remove p_rarch
dependencies
2021-08-30 21:59:35 +02:00
twinaphex 8460618666 menu_input_get_mouse_hw_state - horiz mouse wheel up/down were inverted 2021-08-30 21:17:08 +02:00
twinaphex c6f2e52d62 Simplify menu_driver_toggle 2021-08-30 21:11:43 +02:00
twinaphex 7e61c7ab32 Optimize menu_input_get_mouse_hw_state 2021-08-30 20:55:27 +02:00
twinaphex b68ace9e3d Simplify several menu poll functions 2021-08-30 20:46:07 +02:00
twinaphex 37aa13bb47 (X11) get_video_mode - make sure parameter does not hide global
variable of the same name
2021-08-30 18:39:02 +02:00
twinaphex e384c2b099 Fix some warnings in retroarch.c - local variables hiding parameter
of the same name, local variable being unused on one platform because
it's only used within an ifdef, etc.
2021-08-30 18:27:55 +02:00
twinaphex 1bafa70837 Simplify config_load_file - get rid of end label 2021-08-30 17:52:50 +02:00
Autechre 2406894329 Merge pull request #12913 from libretro/move-code-over-to-configuration
Move code in retroarch.c over to configuration file
2021-08-30 17:45:50 +02:00
twinaphex 220dfe4dbf Move code in retroarch.c over to configuration file 2021-08-30 16:52:05 +02:00
twinaphex bfc7e824fe Rmeove some obsolete comments 2021-08-30 16:13:47 +02:00
twinaphex 2f14d2e4e2 Move some command functions over from retroarch.c to command.c - the
other ones have some dependencies on static locals in retroarch.c so
can't be easily transferred over for now
2021-08-30 16:08:50 +02:00
Autechre cd126f0236 Merge pull request #12911 from Jamiras/rcheevos102
(cheevos) upgrade to rcheevos 10.2
2021-08-30 05:19:04 +02:00
twinaphex d2283a5237 Use better already existing race guard 'audio_suspended' instead
of 'video_driver_is_switching_mode'
2021-08-30 05:08:09 +02:00
twinaphex d429ecf304 Safer way of avoiding the race condition in
audio_driver_sample/audio_driver_sample_batch - we can check
is_display_mode_switching to see if we're doing a fs/windowed toggle
(full teardown/setup), no audio should be processed at this point in
time
2021-08-30 04:52:28 +02:00
twinaphex d45945cda2 When audio driver write callback function fails, don't
turn audio off completely - look if audio_driver_output_samples_conv_buf
is non-NULL first before we attempt to write audio
2021-08-30 02:13:19 +02:00
twinaphex 943e14051c Increased safety for non-batched audio sample callback - fixes audio_driver_sample crashing in PCSX2 when toggling fullscreen 2021-08-30 01:54:49 +02:00
Autechre 4b6a82a3b0 Merge pull request #12908 from libretro/input-robustness-for-threaded-cores
Input robustness for threaded cores
2021-08-29 23:00:48 +02:00
twinaphex bf2e7b93f0 (Vulkan) Fix Vulkan validation layer - fix thanks to flyinghead -
see comments
2021-08-29 20:39:22 +02:00
twinaphex 24721e6a1d C89 buildfix for MSVC 2021-08-29 20:37:09 +02:00
twinaphex 0a1affba7a Simplify menu_input_get_mouse_hw_state/menu_input_read_mouse_hw 2021-08-29 19:05:38 +02:00
twinaphex a9f1dd3647 input_driver_poll; remove shadowed variable
menu_input_read_mouse_hw - cleanup + go through local pointer
variable for primary_joypad
2021-08-29 18:41:58 +02:00
twinaphex 540d192ecb Buildfix for Apple + make sure primary_joypad/secondary_joypad goes through local pointers; cut down on HAVE_MFI ifdefs in retroarch.c 2021-08-29 18:34:52 +02:00
twinaphex f1f3998d28 Prevent joypad objects being destroyed before their pointers are being
NULLed. Another thread could access a "half destroyed" object before
2021-08-29 18:06:08 +02:00
twinaphex 46fb61bede input_state_wrap - do not attempt to access joypad or sec_joypad
pointers if non-NULL
2021-08-29 16:57:41 +02:00
twinaphex cf7b30481b Get rid of gfx_widgets_draw_icon_blend - was just a duplicate of
gfx_widgets_draw_icon with blend_begin and blend_end wrapped around it
2021-08-29 15:21:40 +02:00
Brian Weiss 30db7d8cd3 upgrade to rcheevos 10.2 2021-08-28 13:58:33 -06:00
Autechre 2474fe3c2e Updating CODING-GUIDELINES - typo fix 2021-08-28 17:24:32 +02:00
twinaphex 5b3e5f5daa Update CODING-GUIDELINES 2021-08-28 17:22:24 +02:00
Autechre 861cb2953a Merge pull request #12902 from 4th-fork/master
set background colour for splash screen to black
2021-08-28 15:12:23 +02:00
Tunip3 6dfe20e247 set background colour for splash screen to black rather than the default light gray 2021-08-28 13:47:57 +01:00
Tunip3 bb0fe6c2d1 fix extraction issues 2021-08-26 23:18:42 +01:00
Tunip3 45a16fab1b clean up retro_vfs_file_open_impl 2021-08-25 23:12:29 +01:00
Tunip3 8396bd599d strip out unneeded uwp specific file io functions 2021-08-25 15:54:09 +01:00
226 changed files with 23257 additions and 20287 deletions

No files matched your search

+149 -148
View File
@@ -1,155 +1,156 @@
{
"configurations": [
{
"name": "Mac",
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}",
"${workspaceRoot}/libretro-common/include"
],
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
"configurations": [
{
"name": "Mac",
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}",
"${workspaceRoot}/libretro-common/include"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"macFrameworkPath": [
"/System/Library/Frameworks",
"/Library/Frameworks"
]
},
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}",
"${workspaceFolder}/libretro-common/include",
"${workspaceRoot}/libretro-common/include"
],
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"macFrameworkPath": [
"/System/Library/Frameworks",
"/Library/Frameworks"
]
},
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}",
"${workspaceFolder}/libretro-common/include",
"${workspaceRoot}/libretro-common/include"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "Win32",
"includePath": [
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt",
"${workspaceRoot}",
"${workspaceFolder}/libretro-common/include"
],
"defines": [
"_DEBUG",
"UNICODE"
],
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt",
"${workspaceRoot}"
"defines": [],
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "Win32",
"includePath": [
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt",
"${workspaceRoot}",
"${workspaceFolder}/libretro-common/include"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"cStandard": "c11",
"cppStandard": "c++17"
},
{
"name": "msys2-mingw32",
"includePath": [
"C:/msys64/mingw32/include",
"C:/msys64/mingw32/i686-w64-mingw32/include",
"${workspaceRoot}/libretro-common/include",
"${workspaceRoot}/include",
"${workspaceRoot}"
],
"defines": [
"_DEBUG",
"UNICODE"
],
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/msys64/mingw32/include",
"C:/msys64/mingw32/i686-w64-mingw32/include",
"${workspaceRoot}/libretro-common/include",
"${workspaceRoot}/include",
"${workspaceRoot}"
"defines": [
"_DEBUG",
"UNICODE"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "msys2-mingw64",
"includePath": [
"C:/msys64/mingw64/include",
"C:/msys64/mingw64/x86_64-w64-mingw32/include",
"${workspaceRoot}/libretro-common/include",
"${workspaceRoot}/include",
"${workspaceRoot}"
],
"defines": [
"_DEBUG",
"UNICODE"
],
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/msys64/mingw64/include",
"C:/msys64/mingw64/x86_64-w64-mingw32/include",
"${workspaceRoot}/libretro-common/include",
"${workspaceRoot}/include",
"${workspaceRoot}"
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"cStandard": "c11",
"cppStandard": "c++17",
"configurationProvider": "ms-vscode.makefile-tools"
},
{
"name": "msys2-mingw32",
"includePath": [
"C:/msys64/mingw32/include",
"C:/msys64/mingw32/i686-w64-mingw32/include",
"${workspaceRoot}/libretro-common/include",
"${workspaceRoot}/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "Switch",
"includePath": [
"/opt/devkitpro/devkitA64/aarch64-none-elf/include",
"/opt/devkitpro/devkitA64/lib/gcc/aarch64-none-elf/8.3.0/include",
"/opt/devkitpro/libnx/include",
"/opt/devkitpro/portlibs/switch/include",
"/opt/devkitpro/portlibs/switch/include/freetype2",
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE",
"__aarch64__",
"__SWITCH__",
"HAVE_LIBNX"
],
"windowsSdkVersion": "10.0.17763.0",
"compilerPath": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc",
"cStandard": "c11",
"cppStandard": "c++11",
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
"defines": [
"_DEBUG",
"UNICODE"
],
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/msys64/mingw32/include",
"C:/msys64/mingw32/i686-w64-mingw32/include",
"${workspaceRoot}/libretro-common/include",
"${workspaceRoot}/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "msys2-mingw64",
"includePath": [
"C:/msys64/mingw64/include",
"C:/msys64/mingw64/x86_64-w64-mingw32/include",
"${workspaceRoot}/libretro-common/include",
"${workspaceRoot}/include",
"${workspaceRoot}"
],
"defines": [
"_DEBUG",
"UNICODE"
],
"intelliSenseMode": "msvc-x64",
"browse": {
"path": [
"C:/msys64/mingw64/include",
"C:/msys64/mingw64/x86_64-w64-mingw32/include",
"${workspaceRoot}/libretro-common/include",
"${workspaceRoot}/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
}
},
{
"name": "Switch",
"includePath": [
"/opt/devkitpro/devkitA64/aarch64-none-elf/include",
"/opt/devkitpro/devkitA64/lib/gcc/aarch64-none-elf/8.3.0/include",
"/opt/devkitpro/libnx/include",
"/opt/devkitpro/portlibs/switch/include",
"/opt/devkitpro/portlibs/switch/include/freetype2",
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE",
"__aarch64__",
"__SWITCH__",
"HAVE_LIBNX"
],
"windowsSdkVersion": "10.0.17763.0",
"compilerPath": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc",
"cStandard": "c11",
"cppStandard": "c++11",
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
}
+39
View File
@@ -1,5 +1,44 @@
# Future
# 1.9.9
- 3DS: Add bottom touchscreen menu
- 3DS/SAVESTATES: Save and load save states to and from RAM
- AUDIO/MIXER: Ensure than menu sounds are re-enabled when calling CMD_EVENT_AUDIO_REINIT
- AUDIO/RESAMPLER/MIXER: Fix menu sounds (audio mixing) when using the 'sinc' resampler with quality lower than 'normal'
- AUDIO/CONVERSION/ARM NEON: Add intrinsic NEON versions for float_to_s16/s16_to_float - should lead to optimized codepaths for AArch64/ARMv7 architectures without being dependent on ASM codepaths.
- AUDIO/RESAMPLER/ARM NEON: Add intrinsic NEON version for lanczos sinc function - should lead to optimized codepaths for AArch64/ARMv7 architectures without being dependent on ASM codepaths.
- CHEEVOS: Upgrade to rcheevos 10.2
- CHEATS: Add enhanced search functionality to the 'Cheats' menu
- CHEATS/RUNAHEAD: Fix cheats when using second instance runahead
- CONFIG: Add option to (force-)write current core options to disk (Quick Menu)
- CORE INFO CACHE: Remove core path from core info cache. Should make core info caches portable now (for example: you can move RetroArch to a separate dir and they would still work).
- D3D11: Use Shader Model 5.0 for frontend shaders if D3D11 Feature level is at least 11.0 or higher. Should fix some new shaders that require SM 5.0 (like AMD FSR)
- D3D11: Add HDR support (disabled for UWP for now)
- D3D12: Add HDR support (disabled for UWP for now)
- EMSCRIPTEN: Fixed web player bug with filesystem and runtime
- INPUT/OVERLAY: Fix overlay input when analog to digital mapping is enabled
- INPUT/UDEV: Look for "ID_INPUT_KEY", not "ID_INPUT_KEYBOARD"
- INPUT/WINRAW: Fix crash when overlay is enabled
- MAC/METAL: Add Discord RPC support
- MENU: Allow 'Custom Aspect Ratio (X Position)/(Y Position)/(Width)/(Height)' to be entered manually via keyboard
- MENU: Allow 'Vertical Refresh Rate' to be entered manually via keyboard
- MENU/SHADERS: Highlight currently selected value in Shader Parameter drop-down lists
- STABILITY: Safer way of avoiding the race condition in
audio_driver_sample/audio_driver_sample_batch - we can check
audio-suspended to see if we're doing a fs/windowed toggle - enhances stability when fullscreen toggling/tearing down context
- STABILITY: When audio driver write callback function fails, don't
turn audio off completely - look if audio_driver_output_samples_conv_buf
is non-NULL first before we attempt to write audio - enhances stability when fullscreen toggling/tearing down context
- STABILITY: Input robustness for cores that use internal threading
(full teardown/setup), no audio should be processed at this point in
time
- VIDEO: Screen resolution list sanitizing
- VULKAN: Fix some Vulkan validation layer errors
- UWP: Updated icons courtesy of Danp142
- UWP/XBOX: Disable CPU model check on Xbox as it doesn't work and can even crash
- UWP/VFS/XBOX: Code cleanup and simplification of UWP VFS driver
# 1.9.8
- AUDIO/WINDOWS/WASAPI: Stop deactivating audio on fast forward
- CHEEVOS: Hide challenge indicators when resetting
+86 -43
View File
@@ -3,64 +3,107 @@ Struct ordering
For POD-types, try to order structs as follows (first to last):
* long double (8 bytes, 16 bytes [64bit x86], 12 bytes [32bit x86])
* double (8 bytes)
* int64_t (8 bytes, 8 bytes [32bit ARM], 4 bytes [32bit x86])
* uint64_t (4 bytes [32bit], 8 bytes [32bit ARM], 8 bytes [64bit])
* pointer (4 bytes [32bit], 8 bytes [64bit] [1])
* intptr_t (4 bytes [32bit], 8 bytes [64bit] [1])
* uintptr_t (4 bytes [32bit], 8 bytes [64bit] [1])
* ptrdiff_t (4 bytes [32bit], 8 bytes [64bit] [1])
* ssize_t (4 bytes [32bit], 8 bytes [64bit])
* size_t (4 bytes [32bit], 8 bytes [64bit])
* jmp_buf (4 bytes)
* long (4 bytes [64bit Win], 8 bytes [64bit non-Win], 4 bytes [32bit])
* int32_t (4 bytes)
* unsigned (4 bytes)
* float (4 bytes)
* int (4 bytes)
* enum (4 bytes)
* int16_t (2 bytes)
* char (1 byte)
* long double (8 bytes, 16 bytes [64bit x86], 12 bytes [32bit x86])
* double (8 bytes)
* int64_t (8 bytes, 8 bytes [32bit ARM],
4 bytes [32bit x86])
* uint64_t (4 bytes [32bit], 8 bytes [32bit ARM], 8 bytes [64bit])
* pointer (4 bytes [32bit], 8 bytes [64bit] [1])
* intptr_t (4 bytes [32bit], 8 bytes [64bit] [1])
* uintptr_t (4 bytes [32bit], 8 bytes [64bit] [1])
* ptrdiff_t (4 bytes [32bit], 8 bytes [64bit] [1])
* ssize_t (4 bytes [32bit], 8 bytes [64bit])
* size_t (4 bytes [32bit], 8 bytes [64bit])
* jmp_buf (4 bytes)
* long (4 bytes [64bit Win], 8 bytes [64bit non-Win],
4 bytes [32bit])
* int32_t (4 bytes)
* unsigned (4 bytes)
* float (4 bytes)
* int (4 bytes)
* enum (4 bytes)
* int16_t (2 bytes)
* char (1 byte)
* bool (1 byte)
[1] PS3 uses 4 byte pointers despite having a 64bit processor
[1] PS3 uses 4 byte pointers despite having a 64bit processor
Struct members should be sorted by alignment. Therefore, structs
should be sorted by the largest type inside them.
Struct members should be sorted by alignment. Therefore, structs
should be sorted by the largest type inside them.
For example, take a struct like this:
For example, take a struct like this:
typedef struct
{
size_t capacity;
bool old_format;
bool compress;
bool fuzzy_archive_match;
bool autofix_paths;
char path[PATH_MAX_LENGTH];
char base_content_directory[PATH_MAX_LENGTH];
} playlist_config_t;
typedef struct
{
size_t capacity;
bool old_format;
bool compress;
bool fuzzy_archive_match;
bool autofix_paths;
char path[PATH_MAX_LENGTH];
char base_content_directory[PATH_MAX_LENGTH];
} playlist_config_t;
size_t has the biggest alignment here, so 'struct playlist_config_t' inside a struct should come before or after size_t.
size_t has the biggest alignment here, so 'struct playlist_config_t'
inside a struct should come before or after size_t.
*** BEST PRACTICES ***
* If we have pointers and size variable pairs, it's best to interleave them to increase the probability they go in the same cacheline. It also makes the code more readable, that these two variables are connected.
* If we have pointers and size variable pairs, it's best to
interleave them to increase the probability they go in the
same cacheline. It also makes the code more readable, that
these two variables are connected.
Example:
struct a
{
char* b;
size_t b_len;
char* c;
size_t c_len;
};
struct a
{
char* b;
size_t b_len;
char* c;
size_t c_len;
};
Stack size
----------
You have to assume that stack size is going to be limited in RetroArch. Some game consoles (and other embedded systems) might have a default stack size as low as 128Kb or less. Be conservative with stack size but don't try to put very small structs on heap either [to avoid memory fragmentation among other things].
You have to assume that stack size is going to be limited in
RetroArch. Some game consoles (and other embedded systems)
might have a default stack size as low as 128Kb or less.
Be conservative with stack size but don't try to put very
small structs on heap either [to avoid memory fragmentation
among other things]. A balancing act here is necessary.
Be mindful that heap allocations are slow compared to stack.
Functions
---------
- Avoid doing small getter/setter functions. We want a function
to justify its function call overhead by doing a significant
body of work. Small one-line getter/setter functions for what
is predominantly C-style structs is not useful, plus it leads
to people thinking this function is more complex than it
actually is, thus obfuscating the sourcecode instead of it
being easier to read.
If you can find examples in the codebase that violate this
guideline, do not hesitate to point them out to us.
Variable declaration
--------------------
For C source files, we have to insist you stick to the following:
- Declare variables either at the start of a function or the start
of a code block, depending on the scope they need.
- Do not do initial for loop declarations. Refer to the bulletpoint above:
either declare them at the start of the function, or at the start
of the code block.
Not doing this would break compilation on platforms where we are compiling
these C source files in C89 compatibility mode. If such issues occur in pull
requests, we have to request that it be fixed.
VLA (Variable Length Array)
---------------------------
Do not use VLAs (Variable Length Array) in C source files. These are not
C89-compliant.
+2 -18
View File
@@ -134,7 +134,6 @@ ifneq ($(findstring Darwin,$(OS)),)
MINVERFLAGS=
ifeq ($(shell uname -p),arm)
MINVERFLAGS = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS (Metal, ARM 64bit)
MINVERFLAGS += -DDONT_WANT_ARM_ASM_OPTIMIZATIONS
else ifeq ($(HAVE_METAL),1)
MINVERFLAGS = -mmacosx-version-min=10.13 -stdlib=libc++ # macOS (Metal, x86 64bit)
else ifeq ($(shell uname -p),powerpc)
@@ -148,7 +147,6 @@ ifneq ($(findstring Darwin,$(OS)),)
# Build for a specific architecture when ARCH is defined as a switch
ifeq ($(ARCH),arm64)
MINVERFLAGS = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS (Metal, ARM 64bit)
MINVERFLAGS += -DDONT_WANT_ARM_ASM_OPTIMIZATIONS
ARCHFLAGS = -arch arm64
else ifeq ($(ARCH),x86_64)
ifeq ($(HAVE_METAL),1)
@@ -970,10 +968,6 @@ ifeq ($(HW_CONTEXT_MENU_DRIVERS), 1)
HAVE_XMB = 1
endif
ifeq ($(HAVE_STRIPES),)
HAVE_STRIPES = 0
endif
ifeq ($(HAVE_OZONE),)
HAVE_OZONE = 1
endif
@@ -981,7 +975,6 @@ else
HAVE_RGUI ?= 0
HAVE_MATERIALUI ?= 0
HAVE_XMB ?= 0
HAVE_STRIPES ?= 0
HAVE_OZONE ?= 0
endif
@@ -1013,22 +1006,12 @@ ifeq ($(HAVE_MENU), 1)
endif
ifeq ($(HAVE_OZONE), 1)
OBJ += menu/drivers/ozone/ozone.o \
menu/drivers/ozone/ozone_entries.o \
menu/drivers/ozone/ozone_display.o \
menu/drivers/ozone/ozone_texture.o \
menu/drivers/ozone/ozone_theme.o \
menu/drivers/ozone/ozone_sidebar.o
OBJ += menu/drivers/ozone.o
DEFINES += -DHAVE_OZONE
HAVE_ASSETS = 1
HAVE_MENU_SCREENSAVER = 1
endif
ifeq ($(HAVE_STRIPES), 1)
OBJ += menu/drivers/stripes.o
DEFINES += -DHAVE_STRIPES
endif
ifeq ($(HAVE_MENU_SCREENSAVER), 1)
OBJ += menu/menu_screensaver.o
endif
@@ -1048,6 +1031,7 @@ endif
ifeq ($(HAVE_MENU_COMMON), 1)
OBJ += menu/menu_setting.o \
menu/menu_driver.o \
menu/cbs/menu_cbs_ok.o \
menu/cbs/menu_cbs_cancel.o \
menu/cbs/menu_cbs_select.o \
+5
View File
@@ -2,6 +2,7 @@ TARGET := retroarch_3ds
LIBRETRO =
DEBUG = 0
CONSOLE_LOG = 0
GRIFFIN_BUILD = 1
WHOLE_ARCHIVE_LINK = 0
BUILD_3DSX = 1
@@ -154,6 +155,10 @@ else
CFLAGS += -O3
endif
ifeq ($(CONSOLE_LOG), 1)
CFLAGS += -DCONSOLE_LOG
endif
ifeq ($(LIBCTRU_NO_DEPRECATION), 1)
CFLAGS += -DLIBCTRU_NO_DEPRECATION
endif
+5
View File
@@ -2,6 +2,7 @@ TARGET := retroarch_3ds_salamander
LIBRETRO =
DEBUG = 0
CONSOLE_LOG = 0
BUILD_3DSX = 1
BUILD_3DS = 0
BUILD_CIA = 1
@@ -95,6 +96,10 @@ else
CFLAGS += -O3
endif
ifeq ($(CONSOLE_LOG), 1)
CFLAGS += -DCONSOLE_LOG
endif
CFLAGS += -I. -Ideps/7zip -Ideps/stb -Ilibretro-common/include -Ilibretro-common/include/compat/zlib
#CFLAGS += -DRARCH_INTERNAL
-1
View File
@@ -78,7 +78,6 @@ else
HAVE_MATERIALUI = 0
HAVE_XMB = 0
HAVE_OZONE = 0
HAVE_STRIPES = 0
endif
include Makefile.common
-6
View File
@@ -29,12 +29,6 @@
#include <audio/audio_resampler.h>
#if (defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_ASM_OPTIMIZATIONS)) || defined(HAVE_NEON)
#ifndef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
#define HAVE_ARM_NEON_ASM_OPTIMIZATIONS
#endif
#endif
/* Since SSE and NEON don't provide support for trigonometric functions
* we approximate those with polynoms
*
+72
View File
@@ -28,6 +28,10 @@
#include "verbosity.h"
#include "command.h"
#ifdef HAVE_CHEEVOS
#include "cheevos/cheevos.h"
#endif
#define CMD_BUF_SIZE 4096
#if defined(HAVE_COMMAND)
@@ -532,4 +536,72 @@ bool command_network_send(const char *cmd_)
}
#endif
bool command_show_osd_msg(command_t *cmd, const char* arg)
{
runloop_msg_queue_push(arg, 1, 180, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return true;
}
#if defined(HAVE_CHEEVOS)
bool command_read_ram(command_t *cmd, const char *arg)
{
unsigned i;
char *reply = NULL;
const uint8_t *data = NULL;
char *reply_at = NULL;
unsigned int nbytes = 0;
unsigned int alloc_size = 0;
unsigned int addr = -1;
unsigned int len = 0;
if (sscanf(arg, "%x %u", &addr, &nbytes) != 2)
return true;
/* We allocate more than needed, saving 20 bytes is not really relevant */
alloc_size = 40 + nbytes * 3;
reply = (char*)malloc(alloc_size);
reply[0] = '\0';
reply_at = reply + snprintf(
reply, alloc_size - 1, "READ_CORE_RAM" " %x", addr);
if ((data = rcheevos_patch_address(addr)))
{
for (i = 0; i < nbytes; i++)
snprintf(reply_at + 3 * i, 4, " %.2X", data[i]);
reply_at[3 * nbytes] = '\n';
len = reply_at + 3 * nbytes + 1 - reply;
}
else
{
strlcpy(reply_at, " -1\n", sizeof(reply) - strlen(reply));
len = reply_at + STRLEN_CONST(" -1\n") - reply;
}
cmd->replier(cmd, reply, len);
free(reply);
return true;
}
bool command_write_ram(command_t *cmd, const char *arg)
{
unsigned int addr = (unsigned int)strtoul(arg, (char**)&arg, 16);
uint8_t *data = (uint8_t *)rcheevos_patch_address(addr);
if (!data)
return false;
if (rcheevos_hardcore_active())
{
RARCH_LOG("Achievements hardcore mode disabled by WRITE_CORE_RAM\n");
rcheevos_pause_hardcore();
}
while (*arg)
{
*data = strtoul(arg, (char**)&arg, 16);
data++;
}
return true;
}
#endif
#endif
+6
View File
@@ -73,16 +73,22 @@ enum event_command
/* Loads core. */
CMD_EVENT_LOAD_CORE,
CMD_EVENT_LOAD_CORE_PERSIST,
#if defined(HAVE_RUNAHEAD) && (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
CMD_EVENT_LOAD_SECOND_CORE,
#endif
CMD_EVENT_UNLOAD_CORE,
CMD_EVENT_CLOSE_CONTENT,
CMD_EVENT_LOAD_STATE,
CMD_EVENT_LOAD_STATE_FROM_RAM,
/* Swaps the current state with what's on the undo load buffer */
CMD_EVENT_UNDO_LOAD_STATE,
/* Rewrites a savestate on disk */
CMD_EVENT_UNDO_SAVE_STATE,
CMD_EVENT_SAVE_STATE,
CMD_EVENT_SAVE_STATE_TO_RAM,
CMD_EVENT_SAVE_STATE_DECREMENT,
CMD_EVENT_SAVE_STATE_INCREMENT,
CMD_EVENT_RAM_STATE_TO_FILE,
/* Takes screenshot. */
CMD_EVENT_TAKE_SCREENSHOT,
/* Quits RetroArch. */
+15
View File
@@ -412,6 +412,21 @@
#define DEFAULT_SHADER_ENABLE false
#endif
/* Should we enable hdr when its supported*/
#define DEFAULT_VIDEO_HDR_ENABLE false
/* The maximum nunmber of nits the actual display can show - needs to be calibrated */
#define DEFAULT_VIDEO_HDR_MAX_NITS 1000.0f
/* The number of nits that paper white is at */
#define DEFAULT_VIDEO_HDR_PAPER_WHITE_NITS 200.0f
/* The contrast setting for hdr used to calculate the display gamma by dividing gamma 2.2 by this value */
#define DEFAULT_VIDEO_HDR_CONTRAST 1.0f
/* Should we expand the colour gamut when using hdr */
#define DEFAULT_VIDEO_HDR_EXPAND_GAMUT true
/* When presets are saved they will be saved using the #reference
* directive by default */
#define DEFAULT_VIDEO_SHADER_PRESET_SAVE_REFERENCE_ENABLE true
+674 -15
View File
@@ -259,6 +259,100 @@ enum midi_driver_enum
MIDI_NULL
};
#define DECLARE_BIND(base, bind, desc) { #base, desc, 0, bind, true }
#define DECLARE_META_BIND(level, base, bind, desc) { #base, desc, level, bind, true }
const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = {
DECLARE_BIND(b, RETRO_DEVICE_ID_JOYPAD_B, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B),
DECLARE_BIND(y, RETRO_DEVICE_ID_JOYPAD_Y, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y),
DECLARE_BIND(select, RETRO_DEVICE_ID_JOYPAD_SELECT,MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT),
DECLARE_BIND(start, RETRO_DEVICE_ID_JOYPAD_START, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START),
DECLARE_BIND(up, RETRO_DEVICE_ID_JOYPAD_UP, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP),
DECLARE_BIND(down, RETRO_DEVICE_ID_JOYPAD_DOWN, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN),
DECLARE_BIND(left, RETRO_DEVICE_ID_JOYPAD_LEFT, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT),
DECLARE_BIND(right, RETRO_DEVICE_ID_JOYPAD_RIGHT, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT),
DECLARE_BIND(a, RETRO_DEVICE_ID_JOYPAD_A, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A),
DECLARE_BIND(x, RETRO_DEVICE_ID_JOYPAD_X, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X),
DECLARE_BIND(l, RETRO_DEVICE_ID_JOYPAD_L, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L),
DECLARE_BIND(r, RETRO_DEVICE_ID_JOYPAD_R, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R),
DECLARE_BIND(l2, RETRO_DEVICE_ID_JOYPAD_L2, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2),
DECLARE_BIND(r2, RETRO_DEVICE_ID_JOYPAD_R2, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2),
DECLARE_BIND(l3, RETRO_DEVICE_ID_JOYPAD_L3, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3),
DECLARE_BIND(r3, RETRO_DEVICE_ID_JOYPAD_R3, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3),
DECLARE_BIND(l_x_plus, RARCH_ANALOG_LEFT_X_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS),
DECLARE_BIND(l_x_minus, RARCH_ANALOG_LEFT_X_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS),
DECLARE_BIND(l_y_plus, RARCH_ANALOG_LEFT_Y_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS),
DECLARE_BIND(l_y_minus, RARCH_ANALOG_LEFT_Y_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS),
DECLARE_BIND(r_x_plus, RARCH_ANALOG_RIGHT_X_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS),
DECLARE_BIND(r_x_minus, RARCH_ANALOG_RIGHT_X_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS),
DECLARE_BIND(r_y_plus, RARCH_ANALOG_RIGHT_Y_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS),
DECLARE_BIND(r_y_minus, RARCH_ANALOG_RIGHT_Y_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS),
DECLARE_BIND(gun_trigger, RARCH_LIGHTGUN_TRIGGER, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_TRIGGER ),
DECLARE_BIND(gun_offscreen_shot, RARCH_LIGHTGUN_RELOAD, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD ),
DECLARE_BIND(gun_aux_a, RARCH_LIGHTGUN_AUX_A, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_A ),
DECLARE_BIND(gun_aux_b, RARCH_LIGHTGUN_AUX_B, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_B ),
DECLARE_BIND(gun_aux_c, RARCH_LIGHTGUN_AUX_C, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_AUX_C ),
DECLARE_BIND(gun_start, RARCH_LIGHTGUN_START, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_START ),
DECLARE_BIND(gun_select, RARCH_LIGHTGUN_SELECT, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_SELECT ),
DECLARE_BIND(gun_dpad_up, RARCH_LIGHTGUN_DPAD_UP, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_UP ),
DECLARE_BIND(gun_dpad_down, RARCH_LIGHTGUN_DPAD_DOWN, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_DOWN ),
DECLARE_BIND(gun_dpad_left, RARCH_LIGHTGUN_DPAD_LEFT, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_LEFT ),
DECLARE_BIND(gun_dpad_right, RARCH_LIGHTGUN_DPAD_RIGHT, MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_DPAD_RIGHT ),
DECLARE_BIND(turbo, RARCH_TURBO_ENABLE, MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE),
DECLARE_META_BIND(1, toggle_fast_forward, RARCH_FAST_FORWARD_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY),
DECLARE_META_BIND(2, hold_fast_forward, RARCH_FAST_FORWARD_HOLD_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY),
DECLARE_META_BIND(1, toggle_slowmotion, RARCH_SLOWMOTION_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_KEY),
DECLARE_META_BIND(2, hold_slowmotion, RARCH_SLOWMOTION_HOLD_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION_HOLD_KEY),
DECLARE_META_BIND(1, load_state, RARCH_LOAD_STATE_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY),
DECLARE_META_BIND(1, save_state, RARCH_SAVE_STATE_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY),
DECLARE_META_BIND(2, toggle_fullscreen, RARCH_FULLSCREEN_TOGGLE_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY),
DECLARE_META_BIND(2, close_content, RARCH_CLOSE_CONTENT_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_CLOSE_CONTENT_KEY),
#ifdef HAVE_LAKKA
DECLARE_META_BIND(2, exit_emulator, RARCH_QUIT_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_RESTART_KEY),
#else
DECLARE_META_BIND(2, exit_emulator, RARCH_QUIT_KEY, MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY),
#endif
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(1, rewind, RARCH_REWIND, MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND),
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, 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, shader_next, RARCH_SHADER_NEXT, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT),
DECLARE_META_BIND(2, shader_prev, RARCH_SHADER_PREV, MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV),
DECLARE_META_BIND(2, cheat_index_plus, RARCH_CHEAT_INDEX_PLUS, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS),
DECLARE_META_BIND(2, cheat_index_minus, RARCH_CHEAT_INDEX_MINUS, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS),
DECLARE_META_BIND(2, cheat_toggle, RARCH_CHEAT_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE),
DECLARE_META_BIND(2, screenshot, RARCH_SCREENSHOT, MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT),
DECLARE_META_BIND(2, audio_mute, RARCH_MUTE, MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE),
DECLARE_META_BIND(2, osk_toggle, RARCH_OSK, MENU_ENUM_LABEL_VALUE_INPUT_META_OSK),
DECLARE_META_BIND(2, fps_toggle, RARCH_FPS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE),
DECLARE_META_BIND(2, send_debug_info, RARCH_SEND_DEBUG_INFO, MENU_ENUM_LABEL_VALUE_INPUT_META_SEND_DEBUG_INFO),
DECLARE_META_BIND(2, netplay_host_toggle, RARCH_NETPLAY_HOST_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_HOST_TOGGLE),
DECLARE_META_BIND(2, netplay_game_watch, RARCH_NETPLAY_GAME_WATCH, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH),
DECLARE_META_BIND(2, enable_hotkey, RARCH_ENABLE_HOTKEY, MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY),
DECLARE_META_BIND(2, volume_up, RARCH_VOLUME_UP, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP),
DECLARE_META_BIND(2, volume_down, RARCH_VOLUME_DOWN, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN),
DECLARE_META_BIND(2, overlay_next, RARCH_OVERLAY_NEXT, MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT),
DECLARE_META_BIND(2, disk_eject_toggle, RARCH_DISK_EJECT_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE),
DECLARE_META_BIND(2, disk_next, RARCH_DISK_NEXT, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT),
DECLARE_META_BIND(2, disk_prev, RARCH_DISK_PREV, MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV),
DECLARE_META_BIND(2, grab_mouse_toggle, RARCH_GRAB_MOUSE_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE),
DECLARE_META_BIND(2, game_focus_toggle, RARCH_GAME_FOCUS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE),
DECLARE_META_BIND(2, desktop_menu_toggle, RARCH_UI_COMPANION_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_UI_COMPANION_TOGGLE),
#ifdef HAVE_MENU
DECLARE_META_BIND(1, menu_toggle, RARCH_MENU_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE),
#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),
DECLARE_META_BIND(2, runahead_toggle, RARCH_RUNAHEAD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE),
DECLARE_META_BIND(2, ai_service, RARCH_AI_SERVICE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE),
};
#if defined(HAVE_METAL)
/* iOS supports both the OpenGL and Metal video drivers; default to OpenGL since Metal support is preliminary */
#if defined(HAVE_COCOATOUCH) && defined(HAVE_OPENGL)
@@ -1562,7 +1656,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("video_scale_integer", &settings->bools.video_scale_integer, true, DEFAULT_SCALE_INTEGER, false);
SETTING_BOOL("video_scale_integer_overscale", &settings->bools.video_scale_integer_overscale, true, DEFAULT_SCALE_INTEGER_OVERSCALE, false);
SETTING_BOOL("video_smooth", &settings->bools.video_smooth, true, DEFAULT_VIDEO_SMOOTH, false);
SETTING_BOOL("video_ctx_scaling", &settings->bools.video_ctx_scaling, true, DEFAULT_VIDEO_CTX_SCALING, false);
SETTING_BOOL("video_ctx_scaling", &settings->bools.video_ctx_scaling, true, DEFAULT_VIDEO_CTX_SCALING, false);
SETTING_BOOL("video_force_aspect", &settings->bools.video_force_aspect, true, DEFAULT_FORCE_ASPECT, false);
#if defined(DINGUX)
SETTING_BOOL("video_dingux_ipu_keep_aspect", &settings->bools.video_dingux_ipu_keep_aspect, true, DEFAULT_DINGUX_IPU_KEEP_ASPECT, false);
@@ -1572,6 +1666,8 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("auto_screenshot_filename", &settings->bools.auto_screenshot_filename, true, DEFAULT_AUTO_SCREENSHOT_FILENAME, false);
SETTING_BOOL("video_force_srgb_disable", &settings->bools.video_force_srgb_disable, true, false, false);
SETTING_BOOL("video_fullscreen", &settings->bools.video_fullscreen, true, DEFAULT_FULLSCREEN, false);
SETTING_BOOL("video_hdr_enable", &settings->bools.video_hdr_enable, true, DEFAULT_VIDEO_HDR_ENABLE, false);
SETTING_BOOL("video_hdr_expand_gamut", &settings->bools.video_hdr_expand_gamut, true, DEFAULT_VIDEO_HDR_EXPAND_GAMUT, false);
SETTING_BOOL("bundle_assets_extract_enable", &settings->bools.bundle_assets_extract_enable, true, DEFAULT_BUNDLE_ASSETS_EXTRACT_ENABLE, false);
SETTING_BOOL("video_vsync", &settings->bools.video_vsync, true, DEFAULT_VSYNC, false);
SETTING_BOOL("video_adaptive_vsync", &settings->bools.video_adaptive_vsync, true, DEFAULT_ADAPTIVE_VSYNC, false);
@@ -1945,6 +2041,10 @@ static struct config_float_setting *populate_settings_float(
SETTING_FLOAT("input_analog_sensitivity", &settings->floats.input_analog_sensitivity, true, DEFAULT_ANALOG_SENSITIVITY, false);
SETTING_FLOAT("video_msg_bgcolor_opacity", &settings->floats.video_msg_bgcolor_opacity, true, message_bgcolor_opacity, false);
SETTING_FLOAT("video_hdr_max_nits", &settings->floats.video_hdr_max_nits, true, DEFAULT_VIDEO_HDR_MAX_NITS, false);
SETTING_FLOAT("video_hdr_paper_white_nits", &settings->floats.video_hdr_paper_white_nits, true, DEFAULT_VIDEO_HDR_PAPER_WHITE_NITS, false);
SETTING_FLOAT("video_hdr_contrast", &settings->floats.video_hdr_contrast, true, DEFAULT_VIDEO_HDR_CONTRAST, false);
*size = count;
return tmp;
@@ -3083,7 +3183,6 @@ static bool config_load_file(global_t *global,
{
unsigned i;
char tmp_str[PATH_MAX_LENGTH];
bool ret = false;
unsigned tmp_uint = 0;
bool tmp_bool = false;
static bool first_load = true;
@@ -3098,24 +3197,33 @@ static bool config_load_file(global_t *global,
int size_settings_size = sizeof(settings->sizes) / sizeof(settings->sizes.placeholder);
int array_settings_size = sizeof(settings->arrays) / sizeof(settings->arrays.placeholder);
int path_settings_size = sizeof(settings->paths) / sizeof(settings->paths.placeholder);
struct config_bool_setting *bool_settings = populate_settings_bool (settings, &bool_settings_size);
struct config_float_setting *float_settings = populate_settings_float (settings, &float_settings_size);
struct config_int_setting *int_settings = populate_settings_int (settings, &int_settings_size);
struct config_uint_setting *uint_settings = populate_settings_uint (settings, &uint_settings_size);
struct config_size_setting *size_settings = populate_settings_size (settings, &size_settings_size);
struct config_array_setting *array_settings = populate_settings_array (settings, &array_settings_size);
struct config_path_setting *path_settings = populate_settings_path (settings, &path_settings_size);
struct config_bool_setting *bool_settings = NULL;
struct config_float_setting *float_settings = NULL;
struct config_int_setting *int_settings = NULL;
struct config_uint_setting *uint_settings = NULL;
struct config_size_setting *size_settings = NULL;
struct config_array_setting *array_settings = NULL;
struct config_path_setting *path_settings = NULL;
config_file_t *conf = path ? config_file_new_from_path_to_string(path) : open_default_config_file();
tmp_str[0] = '\0';
tmp_str[0] = '\0';
if (!conf)
{
first_load = false;
if (!path)
ret = true;
goto end;
return true;
return false;
}
bool_settings = populate_settings_bool (settings, &bool_settings_size);
float_settings = populate_settings_float (settings, &float_settings_size);
int_settings = populate_settings_int (settings, &int_settings_size);
uint_settings = populate_settings_uint (settings, &uint_settings_size);
size_settings = populate_settings_size (settings, &size_settings_size);
array_settings = populate_settings_array (settings, &array_settings_size);
path_settings = populate_settings_path (settings, &path_settings_size);
if (!path_is_empty(RARCH_PATH_CONFIG_APPEND))
{
/* Don't destroy append_config_path, store in temporary
@@ -3608,8 +3716,6 @@ static bool config_load_file(global_t *global,
settings->ints.content_favorites_size = (int)settings->uints.content_history_size;
}
ret = true;
end:
if (conf)
config_file_free(conf);
if (bool_settings)
@@ -3627,7 +3733,7 @@ end:
if (size_settings)
free(size_settings);
first_load = false;
return ret;
return true;
}
/**
@@ -4007,6 +4113,245 @@ static void video_driver_save_settings(global_t *global, config_file_t *conf)
global->console.screen.flicker_filter_index);
}
static void save_keybind_hat(config_file_t *conf, const char *key,
const struct retro_keybind *bind)
{
char config[16];
unsigned hat = (unsigned)GET_HAT(bind->joykey);
const char *dir = NULL;
config[0] = '\0';
switch (GET_HAT_DIR(bind->joykey))
{
case HAT_UP_MASK:
dir = "up";
break;
case HAT_DOWN_MASK:
dir = "down";
break;
case HAT_LEFT_MASK:
dir = "left";
break;
case HAT_RIGHT_MASK:
dir = "right";
break;
default:
break;
}
snprintf(config, sizeof(config), "h%u%s", hat, dir);
config_set_string(conf, key, config);
}
static void save_keybind_joykey(config_file_t *conf,
const char *prefix,
const char *base,
const struct retro_keybind *bind, bool save_empty)
{
char key[64];
key[0] = '\0';
fill_pathname_join_delim_concat(key, prefix,
base, '_', "_btn", sizeof(key));
if (bind->joykey == NO_BTN)
{
if (save_empty)
config_set_string(conf, key, "nul");
}
else if (GET_HAT_DIR(bind->joykey))
save_keybind_hat(conf, key, bind);
else
config_set_uint64(conf, key, bind->joykey);
}
static void save_keybind_axis(config_file_t *conf,
const char *prefix,
const char *base,
const struct retro_keybind *bind, bool save_empty)
{
char key[64];
unsigned axis = 0;
char dir = '\0';
key[0] = '\0';
fill_pathname_join_delim_concat(key,
prefix, base, '_',
"_axis",
sizeof(key));
if (bind->joyaxis == AXIS_NONE)
{
if (save_empty)
config_set_string(conf, key, "nul");
}
else if (AXIS_NEG_GET(bind->joyaxis) != AXIS_DIR_NONE)
{
dir = '-';
axis = AXIS_NEG_GET(bind->joyaxis);
}
else if (AXIS_POS_GET(bind->joyaxis) != AXIS_DIR_NONE)
{
dir = '+';
axis = AXIS_POS_GET(bind->joyaxis);
}
if (dir)
{
char config[16];
config[0] = '\0';
snprintf(config, sizeof(config), "%c%u", dir, axis);
config_set_string(conf, key, config);
}
}
static void save_keybind_mbutton(config_file_t *conf,
const char *prefix,
const char *base,
const struct retro_keybind *bind, bool save_empty)
{
char key[64];
key[0] = '\0';
fill_pathname_join_delim_concat(key, prefix,
base, '_', "_mbtn", sizeof(key));
switch (bind->mbutton)
{
case RETRO_DEVICE_ID_MOUSE_LEFT:
config_set_uint64(conf, key, 1);
break;
case RETRO_DEVICE_ID_MOUSE_RIGHT:
config_set_uint64(conf, key, 2);
break;
case RETRO_DEVICE_ID_MOUSE_MIDDLE:
config_set_uint64(conf, key, 3);
break;
case RETRO_DEVICE_ID_MOUSE_BUTTON_4:
config_set_uint64(conf, key, 4);
break;
case RETRO_DEVICE_ID_MOUSE_BUTTON_5:
config_set_uint64(conf, key, 5);
break;
case RETRO_DEVICE_ID_MOUSE_WHEELUP:
config_set_string(conf, key, "wu");
break;
case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
config_set_string(conf, key, "wd");
break;
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
config_set_string(conf, key, "whu");
break;
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
config_set_string(conf, key, "whd");
break;
default:
if (save_empty)
config_set_string(conf, key, "nul");
break;
}
}
/**
* input_config_save_keybind:
* @conf : pointer to config file object
* @prefix : prefix name of keybind
* @base : base name of keybind
* @bind : pointer to key binding object
* @kb : save keyboard binds
*
* Save a key binding to the config file.
*/
static void input_config_save_keybind(config_file_t *conf,
const char *prefix,
const char *base,
const struct retro_keybind *bind,
bool save_empty)
{
save_keybind_joykey (conf, prefix, base, bind, save_empty);
save_keybind_axis (conf, prefix, base, bind, save_empty);
save_keybind_mbutton(conf, prefix, base, bind, save_empty);
}
const char *input_config_get_prefix(unsigned user, bool meta)
{
static const char *bind_user_prefix[MAX_USERS] = {
"input_player1",
"input_player2",
"input_player3",
"input_player4",
"input_player5",
"input_player6",
"input_player7",
"input_player8",
"input_player9",
"input_player10",
"input_player11",
"input_player12",
"input_player13",
"input_player14",
"input_player15",
"input_player16",
};
if (meta)
{
if (user == 0)
return "input";
/* Don't bother with meta bind for anyone else than first user. */
return NULL;
}
return bind_user_prefix[user];
}
/**
* input_config_save_keybinds_user:
* @conf : pointer to config file object
* @user : user number
*
* Save the current keybinds of a user (@user) to the config file (@conf).
*/
static void input_config_save_keybinds_user(config_file_t *conf, unsigned user)
{
unsigned i = 0;
for (i = 0; input_config_bind_map_get_valid(i); i++)
{
char key[64];
char btn[64];
const struct input_bind_map *keybind =
(const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
bool meta = keybind ? keybind->meta : false;
const char *prefix = input_config_get_prefix(user, meta);
const struct retro_keybind *bind = &input_config_binds[user][i];
const char *base = NULL;
if (!prefix || !bind->valid || !keybind)
continue;
base = keybind->base;
key[0] = btn[0] = '\0';
fill_pathname_join_delim(key, prefix, base, '_', sizeof(key));
input_keymaps_translate_rk_to_str(bind->key, btn, sizeof(btn));
config_set_string(conf, key, btn);
input_config_save_keybind(conf, prefix, base, bind, true);
}
}
/**
* config_save_autoconf_profile:
* @device_name : Input device name
@@ -5029,3 +5374,317 @@ end:
config_file_free(config);
}
#endif
bool input_config_bind_map_get_valid(unsigned bind_index)
{
const struct input_bind_map *keybind =
(const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
if (!keybind)
return false;
return keybind->valid;
}
unsigned input_config_bind_map_get_meta(unsigned bind_index)
{
const struct input_bind_map *keybind =
(const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
if (!keybind)
return 0;
return keybind->meta;
}
const char *input_config_bind_map_get_base(unsigned bind_index)
{
const struct input_bind_map *keybind =
(const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
if (!keybind)
return NULL;
return keybind->base;
}
const char *input_config_bind_map_get_desc(unsigned bind_index)
{
const struct input_bind_map *keybind =
(const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
if (!keybind)
return NULL;
return msg_hash_to_str(keybind->desc);
}
uint8_t input_config_bind_map_get_retro_key(unsigned bind_index)
{
const struct input_bind_map *keybind =
(const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index);
if (!keybind)
return 0;
return keybind->retro_key;
}
void input_config_reset_autoconfig_binds(unsigned port)
{
unsigned i;
if (port >= MAX_USERS)
return;
for (i = 0; i < RARCH_BIND_LIST_END; i++)
{
input_autoconf_binds[port][i].joykey = NO_BTN;
input_autoconf_binds[port][i].joyaxis = AXIS_NONE;
if (input_autoconf_binds[port][i].joykey_label)
{
free(input_autoconf_binds[port][i].joykey_label);
input_autoconf_binds[port][i].joykey_label = NULL;
}
if (input_autoconf_binds[port][i].joyaxis_label)
{
free(input_autoconf_binds[port][i].joyaxis_label);
input_autoconf_binds[port][i].joyaxis_label = NULL;
}
}
}
void input_config_set_autoconfig_binds(unsigned port, void *data)
{
unsigned i;
config_file_t *config = (config_file_t*)data;
struct retro_keybind *binds = NULL;
if ((port >= MAX_USERS) || !config)
return;
binds = input_autoconf_binds[port];
for (i = 0; i < RARCH_BIND_LIST_END; i++)
{
const struct input_bind_map *keybind =
(const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i);
if (keybind)
{
char str[256];
const char *base = keybind->base;
str[0] = '\0';
fill_pathname_join_delim(str, "input", base, '_', sizeof(str));
input_config_parse_joy_button(str, config, "input", base, &binds[i]);
input_config_parse_joy_axis (str, config, "input", base, &binds[i]);
}
}
}
void input_config_parse_mouse_button(
char *s,
void *conf_data, const char *prefix,
const char *btn, void *bind_data)
{
int val;
char tmp[64];
char key[64];
config_file_t *conf = (config_file_t*)conf_data;
struct retro_keybind *bind = (struct retro_keybind*)bind_data;
tmp[0] = key[0] = '\0';
fill_pathname_join_delim(key, s, "mbtn", '_', sizeof(key));
if (config_get_array(conf, key, tmp, sizeof(tmp)))
{
bind->mbutton = NO_BTN;
if (tmp[0]=='w')
{
switch (tmp[1])
{
case 'u':
bind->mbutton = RETRO_DEVICE_ID_MOUSE_WHEELUP;
break;
case 'd':
bind->mbutton = RETRO_DEVICE_ID_MOUSE_WHEELDOWN;
break;
case 'h':
switch (tmp[2])
{
case 'u':
bind->mbutton = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP;
break;
case 'd':
bind->mbutton = RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN;
break;
}
break;
}
}
else
{
val = atoi(tmp);
switch (val)
{
case 1:
bind->mbutton = RETRO_DEVICE_ID_MOUSE_LEFT;
break;
case 2:
bind->mbutton = RETRO_DEVICE_ID_MOUSE_RIGHT;
break;
case 3:
bind->mbutton = RETRO_DEVICE_ID_MOUSE_MIDDLE;
break;
case 4:
bind->mbutton = RETRO_DEVICE_ID_MOUSE_BUTTON_4;
break;
case 5:
bind->mbutton = RETRO_DEVICE_ID_MOUSE_BUTTON_5;
break;
}
}
}
}
void input_config_parse_joy_axis(
char *s,
void *conf_data, const char *prefix,
const char *axis, void *bind_data)
{
char tmp[64];
char key[64];
char key_label[64];
config_file_t *conf = (config_file_t*)conf_data;
struct retro_keybind *bind = (struct retro_keybind*)bind_data;
struct config_entry_list *tmp_a = NULL;
tmp[0] = key[0] = key_label[0] = '\0';
fill_pathname_join_delim(key, s,
"axis", '_', sizeof(key));
fill_pathname_join_delim(key_label, s,
"axis_label", '_', sizeof(key_label));
if (config_get_array(conf, key, tmp, sizeof(tmp)))
{
if ( tmp[0] == 'n'
&& tmp[1] == 'u'
&& tmp[2] == 'l'
&& tmp[3] == '\0'
)
bind->joyaxis = AXIS_NONE;
else if (strlen(tmp) >= 2 && (*tmp == '+' || *tmp == '-'))
{
int i_axis = (int)strtol(tmp + 1, NULL, 0);
if (*tmp == '+')
bind->joyaxis = AXIS_POS(i_axis);
else
bind->joyaxis = AXIS_NEG(i_axis);
}
/* Ensure that D-pad emulation doesn't screw this over. */
bind->orig_joyaxis = bind->joyaxis;
}
tmp_a = config_get_entry(conf, key_label);
if (tmp_a && (!string_is_empty(tmp_a->value)))
{
if (bind->joyaxis_label &&
!string_is_empty(bind->joyaxis_label))
free(bind->joyaxis_label);
bind->joyaxis_label = strdup(tmp_a->value);
}
}
static uint16_t input_config_parse_hat(const char *dir)
{
if ( dir[0] == 'u'
&& dir[1] == 'p'
&& dir[2] == '\0'
)
return HAT_UP_MASK;
else if (
dir[0] == 'd'
&& dir[1] == 'o'
&& dir[2] == 'w'
&& dir[3] == 'n'
&& dir[4] == '\0'
)
return HAT_DOWN_MASK;
else if (
dir[0] == 'l'
&& dir[1] == 'e'
&& dir[2] == 'f'
&& dir[3] == 't'
&& dir[4] == '\0'
)
return HAT_LEFT_MASK;
else if (
dir[0] == 'r'
&& dir[1] == 'i'
&& dir[2] == 'g'
&& dir[3] == 'h'
&& dir[4] == 't'
&& dir[5] == '\0'
)
return HAT_RIGHT_MASK;
return 0;
}
void input_config_parse_joy_button(
char *s,
void *data, const char *prefix,
const char *btn, void *bind_data)
{
char tmp[64];
char key[64];
char key_label[64];
config_file_t *conf = (config_file_t*)data;
struct retro_keybind *bind = (struct retro_keybind*)bind_data;
struct config_entry_list *tmp_a = NULL;
tmp[0] = key[0] = key_label[0] = '\0';
fill_pathname_join_delim(key, s,
"btn", '_', sizeof(key));
fill_pathname_join_delim(key_label, s,
"btn_label", '_', sizeof(key_label));
if (config_get_array(conf, key, tmp, sizeof(tmp)))
{
btn = tmp;
if ( btn[0] == 'n'
&& btn[1] == 'u'
&& btn[2] == 'l'
&& btn[3] == '\0'
)
bind->joykey = NO_BTN;
else
{
if (*btn == 'h')
{
const char *str = btn + 1;
/* Parse hat? */
if (str && ISDIGIT((int)*str))
{
char *dir = NULL;
uint16_t hat = strtoul(str, &dir, 0);
uint16_t hat_dir = dir ? input_config_parse_hat(dir) : 0;
if (hat_dir)
bind->joykey = HAT_MAP(hat, hat_dir);
}
}
else
bind->joykey = strtoull(tmp, NULL, 0);
}
}
tmp_a = config_get_entry(conf, key_label);
if (tmp_a && !string_is_empty(tmp_a->value))
{
if (!string_is_empty(bind->joykey_label))
free(bind->joykey_label);
bind->joykey_label = strdup(tmp_a->value);
}
}
+53
View File
@@ -25,6 +25,10 @@
#include <retro_common_api.h>
#include <retro_miscellaneous.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gfx/video_defines.h"
#include "input/input_defines.h"
#include "led/led_defines.h"
@@ -33,6 +37,8 @@
#include "lakka.h"
#endif
#include "msg_hash.h"
#define configuration_set_float(settings, var, newvar) \
{ \
settings->modified = true; \
@@ -63,6 +69,8 @@
strlcpy(var, newvar, sizeof(var)); \
}
#define INPUT_CONFIG_BIND_MAP_GET(i) ((const struct input_bind_map*)&input_config_bind_map[(i)])
enum crt_switch_type
{
CRT_SWITCH_NONE = 0,
@@ -82,6 +90,25 @@ enum override_type
RETRO_BEGIN_DECLS
/* Input config. */
struct input_bind_map
{
const char *base;
enum msg_hash_enums desc;
/* Meta binds get input as prefix, not input_playerN".
* 0 = libretro related.
* 1 = Common hotkey.
* 2 = Uncommon/obscure hotkey.
*/
uint8_t meta;
uint8_t retro_key;
bool valid;
};
typedef struct settings
{
struct
@@ -318,6 +345,9 @@ typedef struct settings
float video_msg_color_g;
float video_msg_color_b;
float video_msg_bgcolor_opacity;
float video_hdr_max_nits;
float video_hdr_paper_white_nits;
float video_hdr_contrast;
float menu_scale_factor;
float menu_widget_scale_factor;
@@ -526,6 +556,8 @@ typedef struct settings
#ifdef HAVE_VIDEO_LAYOUT
bool video_layout_enable;
#endif
bool video_hdr_enable;
bool video_hdr_expand_gamut;
/* Accessibility */
bool accessibility_enable;
@@ -1049,6 +1081,27 @@ const char *config_get_all_timezones(void);
void config_set_timezone(char *timezone);
#endif
bool input_config_bind_map_get_valid(unsigned bind_index);
void input_config_parse_joy_button(
char *s,
void *data, const char *prefix,
const char *btn, void *bind_data);
void input_config_parse_joy_axis(
char *s,
void *conf_data, const char *prefix,
const char *axis, void *bind_data);
void input_config_parse_mouse_button(
char *s,
void *conf_data, const char *prefix,
const char *btn, void *bind_data);
const char *input_config_get_prefix(unsigned user, bool meta);
extern const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL];
RETRO_END_DECLS
#endif
+9
View File
@@ -45,6 +45,15 @@ bool content_load_ram_file(unsigned slot);
/* Save a RAM state from memory to disk. */
bool content_save_ram_file(unsigned slot, bool compress);
/* Load a state from memory. */
bool content_load_state_from_ram(void);
/* Save a state to memory. */
bool content_save_state_to_ram(void);
/* Save a ram state from memory to disk. */
bool content_ram_state_to_file(const char *path);
/* Load a state from disk to memory. */
bool content_load_state(const char* path, bool load_to_backup_buffer, bool autoload);
+21
View File
@@ -1,3 +1,24 @@
# v10.2.0
* add RC_MEMSIZE_16_BITS_BE, RC_MEMSIZE_24_BITS_BE, and RC_MEMSIZE_32_BITS_BE
* add secondary flag for RC_CONDITION_MEASURED that tells the UI when to show progress as raw vs. as a percentage
* add rapi calls for fetch_leaderboard_info, fetch_achievement_info and fetch_game_list
* add hash support for RC_CONSOLE_PSP
* add RCHEEVOS_URL_SSL compile flag to use https in rurl functions
* add space to "PC Engine" label
* update RC_CONSOLE_INTELLIVISION memory map to acknowledge non-8-bit addresses
* standardize to z64 format when hashing RC_CONSOLE_N64
* prevent generating hash for PSX disc when requesting RC_CONSOLE_PLAYSTATION2
* fix wrong error message being returned when a leaderboard was only slightly malformed
# v10.1.0
* add RC_RUNTIME_EVENT_ACHIEVEMENT_UNPRIMED
* add rc_runtime_validate_addresses
* add external memory to memory map for Magnavox Odyssey 2
* fix memory map base address for NeoGeo Pocket
* fix bitcount always returning 0 when used in rich presence
# v10.0.0
* add rapi sublibrary for communicating with server (eliminates need for client-side JSON parsing; client must still
+182
View File
@@ -0,0 +1,182 @@
#ifndef RC_API_INFO_H
#define RC_API_INFO_H
#include "rc_api_request.h"
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
/* --- Fetch Achievement Info --- */
/**
* API parameters for a fetch achievement info request.
*/
typedef struct rc_api_fetch_achievement_info_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The unique identifier of the achievement */
unsigned achievement_id;
/* The 1-based index of the first entry to retrieve */
unsigned first_entry;
/* The number of entries to retrieve */
unsigned count;
/* Non-zero to only return unlocks earned by the user's friends */
unsigned friends_only;
}
rc_api_fetch_achievement_info_request_t;
/* An achievement awarded entry */
typedef struct rc_api_achievement_awarded_entry_t {
/* The user associated to the entry */
const char* username;
/* When the achievement was awarded */
time_t awarded;
}
rc_api_achievement_awarded_entry_t;
/**
* Response data for a fetch achievement info request.
*/
typedef struct rc_api_fetch_achievement_info_response_t {
/* The unique identifier of the achievement */
unsigned id;
/* The unique identifier of the game to which the leaderboard is associated */
unsigned game_id;
/* The number of times the achievement has been awarded */
unsigned num_awarded;
/* The number of players that have earned at least one achievement for the game */
unsigned num_players;
/* An array of recently rewarded entries */
rc_api_achievement_awarded_entry_t* recently_awarded;
/* The number of items in the recently_awarded array */
unsigned num_recently_awarded;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_fetch_achievement_info_response_t;
int rc_api_init_fetch_achievement_info_request(rc_api_request_t* request, const rc_api_fetch_achievement_info_request_t* api_params);
int rc_api_process_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response, const char* server_response);
void rc_api_destroy_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response);
/* --- Fetch Leaderboard Info --- */
/**
* API parameters for a fetch leaderboard info request.
*/
typedef struct rc_api_fetch_leaderboard_info_request_t {
/* The unique identifier of the leaderboard */
unsigned leaderboard_id;
/* The number of entries to retrieve */
unsigned count;
/* The 1-based index of the first entry to retrieve */
unsigned first_entry;
/* The username of the player around whom the entries should be returned */
const char* username;
}
rc_api_fetch_leaderboard_info_request_t;
/* A leaderboard info entry */
typedef struct rc_api_lboard_info_entry_t {
/* The user associated to the entry */
const char* username;
/* The rank of the entry */
unsigned rank;
/* The index of the entry */
unsigned index;
/* The value of the entry */
int score;
/* When the entry was submitted */
time_t submitted;
}
rc_api_lboard_info_entry_t;
/**
* Response data for a fetch leaderboard info request.
*/
typedef struct rc_api_fetch_leaderboard_info_response_t {
/* The unique identifier of the leaderboard */
unsigned id;
/* The format to pass to rc_format_value to format the leaderboard value */
int format;
/* If non-zero, indicates that lower scores appear first */
int lower_is_better;
/* The title of the leaderboard */
const char* title;
/* The description of the leaderboard */
const char* description;
/* The definition of the leaderboard to be passed to rc_runtime_activate_lboard */
const char* definition;
/* The unique identifier of the game to which the leaderboard is associated */
unsigned game_id;
/* The author of the leaderboard */
const char* author;
/* When the leaderboard was first uploaded to the server */
time_t created;
/* When the leaderboard was last modified on the server */
time_t updated;
/* An array of requested entries */
rc_api_lboard_info_entry_t* entries;
/* The number of items in the entries array */
unsigned num_entries;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_fetch_leaderboard_info_response_t;
int rc_api_init_fetch_leaderboard_info_request(rc_api_request_t* request, const rc_api_fetch_leaderboard_info_request_t* api_params);
int rc_api_process_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response, const char* server_response);
void rc_api_destroy_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response);
/* --- Fetch Games List --- */
/**
* API parameters for a fetch games list request.
*/
typedef struct rc_api_fetch_games_list_request_t {
/* The unique identifier of the console to query */
unsigned console_id;
}
rc_api_fetch_games_list_request_t;
/* A game list entry */
typedef struct rc_api_game_list_entry_t {
/* The unique identifier of the game */
unsigned id;
/* The name of the game */
const char* name;
}
rc_api_game_list_entry_t;
/**
* Response data for a fetch games list request.
*/
typedef struct rc_api_fetch_games_list_response_t {
/* An array of requested entries */
rc_api_game_list_entry_t* entries;
/* The number of items in the entries array */
unsigned num_entries;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_fetch_games_list_response_t;
int rc_api_init_fetch_games_list_request(rc_api_request_t* request, const rc_api_fetch_games_list_request_t* api_params);
int rc_api_process_fetch_games_list_response(rc_api_fetch_games_list_response_t* response, const char* server_response);
void rc_api_destroy_fetch_games_list_response(rc_api_fetch_games_list_response_t* response);
#ifdef __cplusplus
}
#endif
#endif /* RC_API_INFO_H */
+2 -2
View File
@@ -36,9 +36,9 @@ int rc_api_init_fetch_image_request(rc_api_request_t* request, const rc_api_fetc
* API parameters for a resolve hash request.
*/
typedef struct rc_api_resolve_hash_request_t {
/* The username of the player */
/* Unused - hash lookup does not require credentials */
const char* username;
/* The API token from the login request */
/* Unused - hash lookup does not require credentials */
const char* api_token;
/* The generated hash of the game to be identified */
const char* game_hash;
+1 -1
View File
@@ -16,7 +16,7 @@ extern "C" {
/* generates a hash from a block of memory.
* returns non-zero on success, or zero on failure.
*/
int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer, size_t buffer_size);
int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* buffer, size_t buffer_size);
/* generates a hash from a file.
* returns non-zero on success, or zero on failure.
+3
View File
@@ -7,6 +7,8 @@ extern "C" {
#include "rc_error.h"
#include <stddef.h>
/*****************************************************************************\
| Forward Declarations (defined in rc_runtime_types.h) |
\*****************************************************************************/
@@ -94,6 +96,7 @@ int rc_runtime_activate_achievement(rc_runtime_t* runtime, unsigned id, const ch
void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, unsigned id);
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* runtime, unsigned id);
int rc_runtime_get_achievement_measured(const rc_runtime_t* runtime, unsigned id, unsigned* measured_value, unsigned* measured_target);
int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, unsigned id, char *buffer, size_t buffer_size);
int rc_runtime_activate_lboard(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
void rc_runtime_deactivate_lboard(rc_runtime_t* runtime, unsigned id);
+6
View File
@@ -51,6 +51,9 @@ enum {
RC_MEMSIZE_BIT_6,
RC_MEMSIZE_BIT_7,
RC_MEMSIZE_BITCOUNT,
RC_MEMSIZE_16_BITS_BE,
RC_MEMSIZE_24_BITS_BE,
RC_MEMSIZE_32_BITS_BE,
RC_MEMSIZE_VARIABLE
};
@@ -255,6 +258,9 @@ struct rc_trigger_t {
/* True if at least one condition has a non-zero required hit count */
char has_required_hits;
/* True if the measured value should be displayed as a percentage */
char measured_as_percent;
};
int rc_trigger_size(const char* memaddr);
+3
View File
@@ -11,6 +11,9 @@ int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value);
int rc_url_get_lboard_entries(char* buffer, size_t size, unsigned lboard_id, unsigned first_index, unsigned count);
int rc_url_get_lboard_entries_near_user(char* buffer, size_t size, unsigned lboard_id, const char* user_name, unsigned count);
int rc_url_get_gameid(char* buffer, size_t size, const char* hash);
int rc_url_get_patch(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned gameid);
+130 -49
View File
@@ -20,7 +20,7 @@ static char* g_imagehost = NULL;
/* --- rc_json --- */
static int rc_json_parse_object(const char** json_ptr, rc_json_field_t* fields, size_t field_count);
static int rc_json_parse_object(const char** json_ptr, rc_json_field_t* fields, size_t field_count, unsigned* fields_seen);
static int rc_json_parse_array(const char** json_ptr, rc_json_field_t* field);
static int rc_json_parse_field(const char** json_ptr, rc_json_field_t* field) {
@@ -68,7 +68,7 @@ static int rc_json_parse_field(const char** json_ptr, rc_json_field_t* field) {
break;
case '{': /* object */
result = rc_json_parse_object(json_ptr, NULL, 0);
result = rc_json_parse_object(json_ptr, NULL, 0, &field->array_size);
if (result != RC_OK)
return result;
@@ -127,13 +127,54 @@ static int rc_json_parse_array(const char** json_ptr, rc_json_field_t* field) {
return RC_OK;
}
static int rc_json_parse_object(const char** json_ptr, rc_json_field_t* fields, size_t field_count) {
rc_json_field_t non_matching_field;
rc_json_field_t* field;
static int rc_json_get_next_field(rc_json_object_field_iterator_t* iterator) {
const char* json = iterator->json;
while (isspace((unsigned char)*json))
++json;
if (*json != '"')
return RC_INVALID_JSON;
iterator->field.name = ++json;
while (*json != '"') {
if (!*json)
return RC_INVALID_JSON;
++json;
}
iterator->name_len = json - iterator->field.name;
++json;
while (isspace((unsigned char)*json))
++json;
if (*json != ':')
return RC_INVALID_JSON;
++json;
while (isspace((unsigned char)*json))
++json;
if (rc_json_parse_field(&json, &iterator->field) < 0)
return RC_INVALID_JSON;
while (isspace((unsigned char)*json))
++json;
iterator->json = json;
return RC_OK;
}
static int rc_json_parse_object(const char** json_ptr, rc_json_field_t* fields, size_t field_count, unsigned* fields_seen) {
rc_json_object_field_iterator_t iterator;
const char* json = *json_ptr;
const char* key_start;
size_t key_len;
size_t i;
unsigned num_fields = 0;
int result;
if (fields_seen)
*fields_seen = 0;
for (i = 0; i < field_count; ++i)
fields[i].value_start = fields[i].value_end = NULL;
@@ -147,61 +188,50 @@ static int rc_json_parse_object(const char** json_ptr, rc_json_field_t* fields,
return RC_OK;
}
memset(&iterator, 0, sizeof(iterator));
iterator.json = json;
do
{
while (isspace((unsigned char)*json))
++json;
result = rc_json_get_next_field(&iterator);
if (result != RC_OK)
return result;
if (*json != '"')
return RC_INVALID_JSON;
key_start = ++json;
while (*json != '"') {
if (!*json)
return RC_INVALID_JSON;
++json;
}
key_len = json - key_start;
++json;
while (isspace((unsigned char)*json))
++json;
if (*json != ':')
return RC_INVALID_JSON;
++json;
while (isspace((unsigned char)*json))
++json;
field = &non_matching_field;
for (i = 0; i < field_count; ++i) {
if (!fields[i].value_start && strncmp(fields[i].name, key_start, key_len) == 0 && fields[i].name[key_len] == '\0') {
field = &fields[i];
if (!fields[i].value_start && strncmp(fields[i].name, iterator.field.name, iterator.name_len) == 0 &&
fields[i].name[iterator.name_len] == '\0') {
fields[i].value_start = iterator.field.value_start;
fields[i].value_end = iterator.field.value_end;
fields[i].array_size = iterator.field.array_size;
break;
}
}
if (rc_json_parse_field(&json, field) < 0)
return RC_INVALID_JSON;
while (isspace((unsigned char)*json))
++json;
if (*json != ',')
++num_fields;
if (*iterator.json != ',')
break;
++json;
++iterator.json;
} while (1);
if (*json != '}')
if (*iterator.json != '}')
return RC_INVALID_JSON;
*json_ptr = ++json;
if (fields_seen)
*fields_seen = num_fields;
*json_ptr = ++iterator.json;
return RC_OK;
}
int rc_json_get_next_object_field(rc_json_object_field_iterator_t* iterator) {
if (*iterator->json != ',' && *iterator->json != '{')
return 0;
++iterator->json;
return (rc_json_get_next_field(iterator) == RC_OK);
}
int rc_json_parse_response(rc_api_response_t* response, const char* json, rc_json_field_t* fields, size_t field_count) {
#ifndef NDEBUG
if (field_count < 2)
@@ -213,7 +243,7 @@ int rc_json_parse_response(rc_api_response_t* response, const char* json, rc_jso
#endif
if (*json == '{') {
int result = rc_json_parse_object(&json, fields, field_count);
int result = rc_json_parse_object(&json, fields, field_count, NULL);
rc_json_get_optional_string(&response->error_message, response, &fields[1], "Error", NULL);
rc_json_get_optional_bool(&response->succeeded, &fields[0], "Success", 1);
@@ -266,11 +296,15 @@ static int rc_json_missing_field(rc_api_response_t* response, const rc_json_fiel
int rc_json_get_required_object(rc_json_field_t* fields, size_t field_count, rc_api_response_t* response, rc_json_field_t* field, const char* field_name) {
const char* json = field->value_start;
#ifndef NDEBUG
if (strcmp(field->name, field_name) != 0)
return 0;
#endif
if (!json)
return rc_json_missing_field(response, field);
return (rc_json_parse_object(&json, fields, field_count) == RC_OK);
return (rc_json_parse_object(&json, fields, field_count, &field->array_size) == RC_OK);
}
static int rc_json_get_array_entry_value(rc_json_field_t* field, rc_json_field_t* iterator) {
@@ -322,6 +356,11 @@ int rc_json_get_required_unum_array(unsigned** entries, unsigned* num_entries, r
}
int rc_json_get_required_array(unsigned* num_entries, rc_json_field_t* iterator, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
#ifndef NDEBUG
if (strcmp(field->name, field_name) != 0)
return 0;
#endif
if (!field->value_start || *field->value_start != '[') {
*num_entries = 0;
return rc_json_missing_field(response, field);
@@ -341,7 +380,7 @@ int rc_json_get_array_entry_object(rc_json_field_t* fields, size_t field_count,
while (isspace((unsigned char)*iterator->value_start))
++iterator->value_start;
rc_json_parse_object(&iterator->value_start, fields, field_count);
rc_json_parse_object(&iterator->value_start, fields, field_count, NULL);
while (isspace((unsigned char)*iterator->value_start))
++iterator->value_start;
@@ -358,7 +397,7 @@ static unsigned rc_json_decode_hex4(const char* input) {
memcpy(hex, input, 4);
hex[4] = '\0';
return strtol(hex, NULL, 16);
return (unsigned)strtoul(hex, NULL, 16);
}
static int rc_json_ucs32_to_utf8(unsigned char* dst, unsigned ucs32_char) {
@@ -604,6 +643,48 @@ int rc_json_get_required_unum(unsigned* out, rc_api_response_t* response, const
return rc_json_missing_field(response, field);
}
int rc_json_get_datetime(time_t* out, const rc_json_field_t* field, const char* field_name) {
struct tm tm;
#ifndef NDEBUG
if (strcmp(field->name, field_name) != 0)
return 0;
#endif
if (*field->value_start == '\"') {
memset(&tm, 0, sizeof(tm));
if (sscanf(field->value_start + 1, "%d-%d-%d %d:%d:%d",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) {
tm.tm_mon--; /* 0-based */
tm.tm_year -= 1900; /* 1900 based */
/* mktime converts a struct tm to a time_t using the local timezone.
* the input string is UTC. since timegm is not universally cross-platform,
* figure out the offset between UTC and local time by applying the
* timezone conversion twice and manually removing the difference */
{
time_t local_timet = mktime(&tm);
struct tm* gmt_tm = gmtime(&local_timet);
time_t skewed_timet = mktime(gmt_tm); /* applies local time adjustment second time */
time_t tz_offset = skewed_timet - local_timet;
*out = local_timet - tz_offset;
}
return 1;
}
}
*out = 0;
return 0;
}
int rc_json_get_required_datetime(time_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
if (rc_json_get_datetime(out, field, field_name))
return 1;
return rc_json_missing_field(response, field);
}
int rc_json_get_bool(int* out, const rc_json_field_t* field, const char* field_name) {
const char* src = field->value_start;
+11
View File
@@ -4,6 +4,7 @@
#include "rc_api_request.h"
#include <stddef.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
@@ -30,11 +31,19 @@ typedef struct rc_json_field_t {
}
rc_json_field_t;
typedef struct rc_json_object_field_iterator_t {
rc_json_field_t field;
const char* json;
size_t name_len;
}
rc_json_object_field_iterator_t;
int rc_json_parse_response(rc_api_response_t* response, const char* json, rc_json_field_t* fields, size_t field_count);
int rc_json_get_string(const char** out, rc_api_buffer_t* buffer, const rc_json_field_t* field, const char* field_name);
int rc_json_get_num(int* out, const rc_json_field_t* field, const char* field_name);
int rc_json_get_unum(unsigned* out, const rc_json_field_t* field, const char* field_name);
int rc_json_get_bool(int* out, const rc_json_field_t* field, const char* field_name);
int rc_json_get_datetime(time_t* out, const rc_json_field_t* field, const char* field_name);
void rc_json_get_optional_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name, const char* default_value);
void rc_json_get_optional_num(int* out, const rc_json_field_t* field, const char* field_name, int default_value);
void rc_json_get_optional_unum(unsigned* out, const rc_json_field_t* field, const char* field_name, int default_value);
@@ -43,10 +52,12 @@ int rc_json_get_required_string(const char** out, rc_api_response_t* response, c
int rc_json_get_required_num(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_unum(unsigned* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_bool(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_datetime(time_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_object(rc_json_field_t* fields, size_t field_count, rc_api_response_t* response, rc_json_field_t* field, const char* field_name);
int rc_json_get_required_unum_array(unsigned** entries, unsigned* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_required_array(unsigned* num_entries, rc_json_field_t* iterator, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
int rc_json_get_array_entry_object(rc_json_field_t* fields, size_t field_count, rc_json_field_t* iterator);
int rc_json_get_next_object_field(rc_json_object_field_iterator_t* iterator);
void rc_buf_init(rc_api_buffer_t* buffer);
void rc_buf_destroy(rc_api_buffer_t* buffer);
+328
View File
@@ -0,0 +1,328 @@
#include "rc_api_info.h"
#include "rc_api_common.h"
#include "rc_runtime_types.h"
#include <stdlib.h>
#include <string.h>
/* --- Fetch Achievement Info --- */
int rc_api_init_fetch_achievement_info_request(rc_api_request_t* request, const rc_api_fetch_achievement_info_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (api_params->achievement_id == 0)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
if (rc_api_url_build_dorequest(&builder, "achievementwondata", api_params->username, api_params->api_token)) {
rc_url_builder_append_unum_param(&builder, "a", api_params->achievement_id);
if (api_params->friends_only)
rc_url_builder_append_unum_param(&builder, "f", 1);
if (api_params->first_entry > 1)
rc_url_builder_append_unum_param(&builder, "o", api_params->first_entry - 1); /* number of entries to skip */
rc_url_builder_append_unum_param(&builder, "c", api_params->count);
request->post_data = rc_url_builder_finalize(&builder);
}
return builder.result;
}
int rc_api_process_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response, const char* server_response) {
rc_api_achievement_awarded_entry_t* entry;
rc_json_field_t iterator;
unsigned timet;
int result;
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"AchievementID"},
{"Response"}
/* unused fields
{"Offset"},
{"Count"},
{"FriendsOnly"},
* unused fields */
};
rc_json_field_t response_fields[] = {
{"NumEarned"},
{"TotalPlayers"},
{"GameID"},
{"RecentWinner"} /* array */
};
rc_json_field_t entry_fields[] = {
{"User"},
{"DateAwarded"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
if (!rc_json_get_required_unum(&response->id, &response->response, &fields[2], "AchievementID"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_object(response_fields, sizeof(response_fields) / sizeof(response_fields[0]), &response->response, &fields[3], "Response"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->num_awarded, &response->response, &response_fields[0], "NumEarned"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->num_players, &response->response, &response_fields[1], "TotalPlayers"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->game_id, &response->response, &response_fields[2], "GameID"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_array(&response->num_recently_awarded, &iterator, &response->response, &response_fields[3], "RecentWinner"))
return RC_MISSING_VALUE;
if (response->num_recently_awarded) {
response->recently_awarded = (rc_api_achievement_awarded_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_recently_awarded * sizeof(rc_api_achievement_awarded_entry_t));
if (!response->recently_awarded)
return RC_OUT_OF_MEMORY;
entry = response->recently_awarded;
while (rc_json_get_array_entry_object(entry_fields, sizeof(entry_fields) / sizeof(entry_fields[0]), &iterator)) {
if (!rc_json_get_required_string(&entry->username, &response->response, &entry_fields[0], "User"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&timet, &response->response, &entry_fields[1], "DateAwarded"))
return RC_MISSING_VALUE;
entry->awarded = (time_t)timet;
++entry;
}
}
return RC_OK;
}
void rc_api_destroy_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
/* --- Fetch Leaderboard Info --- */
int rc_api_init_fetch_leaderboard_info_request(rc_api_request_t* request, const rc_api_fetch_leaderboard_info_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (api_params->leaderboard_id == 0)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
rc_url_builder_append_str_param(&builder, "r", "lbinfo");
rc_url_builder_append_unum_param(&builder, "i", api_params->leaderboard_id);
if (api_params->username)
rc_url_builder_append_str_param(&builder, "u", api_params->username);
else if (api_params->first_entry > 1)
rc_url_builder_append_unum_param(&builder, "o", api_params->first_entry - 1); /* number of entries to skip */
rc_url_builder_append_unum_param(&builder, "c", api_params->count);
request->post_data = rc_url_builder_finalize(&builder);
return builder.result;
}
int rc_api_process_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response, const char* server_response) {
rc_api_lboard_info_entry_t* entry;
rc_json_field_t iterator;
unsigned timet;
int result;
size_t len;
char format[16];
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"LeaderboardData"}
};
rc_json_field_t leaderboarddata_fields[] = {
{"LBID"},
{"LBFormat"},
{"LowerIsBetter"},
{"LBTitle"},
{"LBDesc"},
{"LBMem"},
{"GameID"},
{"LBAuthor"},
{"LBCreated"},
{"LBUpdated"},
{"Entries"} /* array */
/* unused fields
{"GameTitle"},
{"ConsoleID"},
{"ConsoleName"},
{"ForumTopicID"},
{"GameIcon"},
* unused fields */
};
rc_json_field_t entry_fields[] = {
{"User"},
{"Rank"},
{"Index"},
{"Score"},
{"DateSubmitted"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
if (!rc_json_get_required_object(leaderboarddata_fields, sizeof(leaderboarddata_fields) / sizeof(leaderboarddata_fields[0]), &response->response, &fields[2], "LeaderboardData"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->id, &response->response, &leaderboarddata_fields[0], "LBID"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_num(&response->lower_is_better, &response->response, &leaderboarddata_fields[2], "LowerIsBetter"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&response->title, &response->response, &leaderboarddata_fields[3], "LBTitle"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&response->description, &response->response, &leaderboarddata_fields[4], "LBDesc"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&response->definition, &response->response, &leaderboarddata_fields[5], "LBMem"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->game_id, &response->response, &leaderboarddata_fields[6], "GameID"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_string(&response->author, &response->response, &leaderboarddata_fields[7], "LBAuthor"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_datetime(&response->created, &response->response, &leaderboarddata_fields[8], "LBCreated"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_datetime(&response->updated, &response->response, &leaderboarddata_fields[9], "LBUpdated"))
return RC_MISSING_VALUE;
if (!leaderboarddata_fields[1].value_end)
return RC_MISSING_VALUE;
len = leaderboarddata_fields[1].value_end - leaderboarddata_fields[1].value_start - 2;
if (len < sizeof(format) - 1) {
memcpy(format, leaderboarddata_fields[1].value_start + 1, len);
format[len] = '\0';
response->format = rc_parse_format(format);
}
else {
response->format = RC_FORMAT_VALUE;
}
if (!rc_json_get_required_array(&response->num_entries, &iterator, &response->response, &leaderboarddata_fields[10], "Entries"))
return RC_MISSING_VALUE;
if (response->num_entries) {
response->entries = (rc_api_lboard_info_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_lboard_info_entry_t));
if (!response->entries)
return RC_OUT_OF_MEMORY;
entry = response->entries;
while (rc_json_get_array_entry_object(entry_fields, sizeof(entry_fields) / sizeof(entry_fields[0]), &iterator)) {
if (!rc_json_get_required_string(&entry->username, &response->response, &entry_fields[0], "User"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&entry->rank, &response->response, &entry_fields[1], "Rank"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&entry->index, &response->response, &entry_fields[2], "Index"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_num(&entry->score, &response->response, &entry_fields[3], "Score"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&timet, &response->response, &entry_fields[4], "DateSubmitted"))
return RC_MISSING_VALUE;
entry->submitted = (time_t)timet;
++entry;
}
}
return RC_OK;
}
void rc_api_destroy_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
/* --- Fetch Games List --- */
int rc_api_init_fetch_games_list_request(rc_api_request_t* request, const rc_api_fetch_games_list_request_t* api_params) {
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (api_params->console_id == 0)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
rc_url_builder_append_str_param(&builder, "r", "gameslist");
rc_url_builder_append_unum_param(&builder, "c", api_params->console_id);
request->post_data = rc_url_builder_finalize(&builder);
return builder.result;
}
int rc_api_process_fetch_games_list_response(rc_api_fetch_games_list_response_t* response, const char* server_response) {
rc_api_game_list_entry_t* entry;
rc_json_object_field_iterator_t iterator;
int result;
char* end;
rc_json_field_t fields[] = {
{"Success"},
{"Error"},
{"Response"}
};
memset(response, 0, sizeof(*response));
rc_buf_init(&response->response.buffer);
result = rc_json_parse_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
if (!fields[2].value_start) {
/* call rc_json_get_required_object to generate the error message */
rc_json_get_required_object(NULL, 0, &response->response, &fields[2], "Response");
return RC_MISSING_VALUE;
}
response->num_entries = fields[2].array_size;
rc_buf_reserve(&response->response.buffer, response->num_entries * (32 + sizeof(rc_api_game_list_entry_t)));
response->entries = (rc_api_game_list_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_game_list_entry_t));
if (!response->entries)
return RC_OUT_OF_MEMORY;
memset(&iterator, 0, sizeof(iterator));
iterator.json = fields[2].value_start;
entry = response->entries;
while (rc_json_get_next_object_field(&iterator)) {
entry->id = strtol(iterator.field.name, &end, 10);
iterator.field.name = "";
if (!rc_json_get_string(&entry->name, &response->response.buffer, &iterator.field, ""))
return RC_MISSING_VALUE;
++entry;
}
return RC_OK;
}
void rc_api_destroy_fetch_games_list_response(rc_api_fetch_games_list_response_t* response) {
rc_buf_destroy(&response->response.buffer);
}
+6 -7
View File
@@ -20,10 +20,9 @@ int rc_api_init_resolve_hash_request(rc_api_request_t* request, const rc_api_res
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
if (rc_api_url_build_dorequest(&builder, "gameid", api_params->username, api_params->api_token)) {
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
request->post_data = rc_url_builder_finalize(&builder);
}
rc_url_builder_append_str_param(&builder, "r", "gameid");
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
request->post_data = rc_url_builder_finalize(&builder);
return builder.result;
}
@@ -130,7 +129,7 @@ int rc_api_process_fetch_game_data_response(rc_api_fetch_game_data_response_t* r
if (result != RC_OK)
return result;
if (!rc_json_get_required_object(patchdata_fields, sizeof(patchdata_fields) / sizeof(patchdata_fields[0]), &response->response, &fields[2], "Response"))
if (!rc_json_get_required_object(patchdata_fields, sizeof(patchdata_fields) / sizeof(patchdata_fields[0]), &response->response, &fields[2], "PatchData"))
return RC_MISSING_VALUE;
if (!rc_json_get_required_unum(&response->id, &response->response, &patchdata_fields[0], "ID"))
@@ -440,8 +439,8 @@ int rc_api_process_submit_lboard_entry_response(rc_api_submit_lboard_entry_respo
{"Rank"},
{"Score"}
/* unused fields
{ "DateSumitted" },
* unused fields */
{"DateSubmitted"},
* unused fields */
};
rc_json_field_t rank_info_fields[] = {
+1
View File
@@ -144,6 +144,7 @@ void rc_init_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, in
parse->measured_target = 0;
parse->lines_read = 0;
parse->has_required_hits = 0;
parse->measured_as_percent = 0;
}
void rc_destroy_parse_state(rc_parse_state_t* parse)
+1
View File
@@ -55,6 +55,7 @@ int rc_snprintf(char* buffer, size_t size, const char* format, ...)
va_start(args, format);
/* assume buffer is large enough and ignore size */
(void)size;
result = vsprintf(buffer, format, args);
va_end(args);
+7 -2
View File
@@ -86,6 +86,11 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
case 'i': case 'I': self->type = RC_CONDITION_ADD_ADDRESS; can_modify = 1; break;
case 't': case 'T': self->type = RC_CONDITION_TRIGGER; break;
case 'z': case 'Z': self->type = RC_CONDITION_RESET_NEXT_IF; break;
case 'g': case 'G':
parse->measured_as_percent = 1;
self->type = RC_CONDITION_MEASURED;
break;
/* e f h j k l s u v w x y */
default: parse->offset = RC_INVALID_CONDITION_TYPE; return 0;
}
@@ -95,7 +100,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
self->type = RC_CONDITION_STANDARD;
}
result = rc_parse_operand(&self->operand1, &aux, 1, is_indirect, parse);
result = rc_parse_operand(&self->operand1, &aux, is_indirect, parse);
if (result < 0) {
parse->offset = result;
return 0;
@@ -158,7 +163,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
break;
}
result = rc_parse_operand(&self->operand2, &aux, 1, is_indirect, parse);
result = rc_parse_operand(&self->operand2, &aux, is_indirect, parse);
if (result < 0) {
parse->offset = result;
return 0;
+9 -8
View File
@@ -18,7 +18,7 @@ static void rc_update_condition_pause(rc_condition_t* condition, int* in_pause)
case RC_CONDITION_OR_NEXT:
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_RESET_NEXT_IF:
condition->pause = *in_pause;
condition->pause = (char)*in_pause;
break;
default:
@@ -140,7 +140,7 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in
return self;
}
static void rc_condset_update_indirect_memrefs(rc_condset_t* self, rc_condition_t* condition, int processing_pause, rc_eval_state_t* eval_state) {
static void rc_condset_update_indirect_memrefs(rc_condition_t* condition, int processing_pause, rc_eval_state_t* eval_state) {
for (; condition != 0; condition = condition->next) {
if (condition->pause != processing_pause)
continue;
@@ -210,7 +210,7 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
}
/* STEP 2: evaluate the current condition */
condition->is_true = rc_test_condition(condition, eval_state);
condition->is_true = (char)rc_test_condition(condition, eval_state);
eval_state->add_value = 0;
eval_state->add_address = 0;
@@ -311,10 +311,10 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
* if the set has any indirect memrefs, manually update them now so the deltas are correct */
if (self->has_indirect_memrefs) {
/* first, update any indirect memrefs in the remaining part of the pause subset */
rc_condset_update_indirect_memrefs(self, condition->next, 1, eval_state);
rc_condset_update_indirect_memrefs(condition->next, 1, eval_state);
/* then, update all indirect memrefs in the non-pause subset */
rc_condset_update_indirect_memrefs(self, self->conditions, 0, eval_state);
rc_condset_update_indirect_memrefs(self->conditions, 0, eval_state);
}
return 1;
@@ -371,7 +371,7 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
/* if not suppressed, update the measured value */
if (measured_value > eval_state->measured_value && can_measure) {
eval_state->measured_value = measured_value;
eval_state->measured_from_hits = measured_from_hits;
eval_state->measured_from_hits = (char)measured_from_hits;
}
return set_valid;
@@ -384,8 +384,9 @@ int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state) {
}
if (self->has_pause) {
if ((self->is_paused = rc_test_condset_internal(self, 1, eval_state))) {
/* one or more Pause conditions exists, if any of them are true, stop processing this group */
/* one or more Pause conditions exists, if any of them are true, stop processing this group */
self->is_paused = (char)rc_test_condset_internal(self, 1, eval_state);
if (self->is_paused) {
eval_state->primed = 0;
return 0;
}
+41 -15
View File
@@ -136,7 +136,7 @@ const char* rc_console_name(int console_id)
return "PC-FX";
case RC_CONSOLE_PC_ENGINE:
return "PCEngine";
return "PC Engine";
case RC_CONSOLE_PLAYSTATION:
return "PlayStation";
@@ -323,19 +323,45 @@ static const rc_memory_region_t _rc_memory_regions_game_gear[] = {
static const rc_memory_regions_t rc_memory_regions_game_gear = { _rc_memory_regions_game_gear, 1 };
/* ===== Intellivision ===== */
/* http://wiki.intellivision.us/index.php%3Ftitle%3DMemory_Map */
/* http://wiki.intellivision.us/index.php/Memory_Map */
/* NOTE: Intellivision memory addresses point at 16-bit values. FreeIntv exposes them as little-endian
* 32-bit values. As such, the addresses are off by a factor of 4 _and_ the data is only where we
* expect it on little-endian systems.
*/
static const rc_memory_region_t _rc_memory_regions_intellivision[] = {
{ 0x000000U, 0x00007FU, 0x000000U, RC_MEMORY_TYPE_VIDEO_RAM, "STIC Registers" },
{ 0x000080U, 0x0000FFU, 0x000080U, RC_MEMORY_TYPE_UNUSED, "" },
{ 0x000100U, 0x00035FU, 0x000100U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x000360U, 0x0003FFU, 0x000360U, RC_MEMORY_TYPE_UNUSED, "" },
{ 0x000400U, 0x000FFFU, 0x000400U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
{ 0x001000U, 0x001FFFU, 0x001000U, RC_MEMORY_TYPE_UNUSED, "" },
{ 0x002000U, 0x002FFFU, 0x002000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
{ 0x003000U, 0x003FFFU, 0x003000U, RC_MEMORY_TYPE_VIDEO_RAM, "Video RAM" },
{ 0x004000U, 0x00FFFFU, 0x004000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
/* For backwards compatibility, register a 128-byte chunk of video RAM so the system memory
* will start at $0080. $0000-$007F previously tried to map to the STIC video registers as
* RETRO_MEMORY_VIDEO_RAM, and FreeIntv didn't expose any RETRO_MEMORY_VIDEO_RAM, so the first
* byte of RETRO_MEMORY_SYSTEM_RAM was registered at $0080. The data at $0080 is actually the
* STIC registers (4 bytes each), so we need to provide an arbitrary 128-byte padding that
* claims to be video RAM to ensure the system RAM ends up at the right address.
*/
{ 0x000000U, 0x00007FU, 0xFFFFFFU, RC_MEMORY_TYPE_VIDEO_RAM, "" },
/* RetroAchievements address = real address x4 + 0x80.
* These all have to map to RETRO_MEMORY_SYSTEM_RAM (even the video-related fields) as the
* entire block is exposed as a single entity by FreeIntv */
/* $0000-$007F: STIC registers, $0040-$007F are readonly */
{ 0x000080U, 0x00027FU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "STIC Registers" },
/* $0080-$00FF: unused */
{ 0x000280U, 0x00047FU, 0x000080U, RC_MEMORY_TYPE_UNUSED, "" },
/* $0100-$035F: system RAM, $0100-$01EF is scratch memory and only 8-bits per address */
{ 0x000480U, 0x000DFFU, 0x000100U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
/* $0360-$03FF: unused */
{ 0x000E00U, 0x00107FU, 0x000360U, RC_MEMORY_TYPE_UNUSED, "" },
/* $0400-$0FFF: cartridge RAM */
{ 0x001080U, 0x00407FU, 0x000400U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
/* $1000-$1FFF: unused */
{ 0x004080U, 0x00807FU, 0x001000U, RC_MEMORY_TYPE_UNUSED, "" },
/* $2000-$2FFF: cartridge RAM */
{ 0x008080U, 0x00C07FU, 0x002000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
/* $3000-$3FFF: video RAM */
{ 0x00C080U, 0x01007FU, 0x003000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Video RAM" },
/* $4000-$FFFF: cartridge RAM */
{ 0x010080U, 0x04007FU, 0x004000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
};
static const rc_memory_regions_t rc_memory_regions_intellivision = { _rc_memory_regions_intellivision, 9 };
static const rc_memory_regions_t rc_memory_regions_intellivision = { _rc_memory_regions_intellivision, 10 };
/* ===== Magnavox Odyssey 2 ===== */
/* https://sudonull.com/post/76885-Architecture-and-programming-Philips-Videopac-Magnavox-Odyssey-2 */
@@ -447,13 +473,13 @@ static const rc_memory_regions_t rc_memory_regions_pc8800 = { _rc_memory_regions
/* ===== PC Engine ===== */
/* http://www.archaicpixels.com/Memory_Map */
static const rc_memory_region_t _rc_memory_regions_pcengine[] = {
static const rc_memory_region_t _rc_memory_regions_pc_engine[] = {
{ 0x000000U, 0x001FFFU, 0x1F0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x002000U, 0x011FFFU, 0x100000U, RC_MEMORY_TYPE_SYSTEM_RAM, "CD RAM" },
{ 0x012000U, 0x041FFFU, 0x0D0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Super System Card RAM" },
{ 0x042000U, 0x0427FFU, 0x1EE000U, RC_MEMORY_TYPE_SAVE_RAM, "CD Battery-backed RAM" }
};
static const rc_memory_regions_t rc_memory_regions_pcengine = { _rc_memory_regions_pcengine, 4 };
static const rc_memory_regions_t rc_memory_regions_pc_engine = { _rc_memory_regions_pc_engine, 4 };
/* ===== PC-FX ===== */
/* http://daifukkat.su/pcfx/data/memmap.html */
@@ -679,7 +705,7 @@ const rc_memory_regions_t* rc_console_memory_regions(int console_id)
return &rc_memory_regions_pc8800;
case RC_CONSOLE_PC_ENGINE:
return &rc_memory_regions_pcengine;
return &rc_memory_regions_pc_engine;
case RC_CONSOLE_PCFX:
return &rc_memory_regions_pcfx;
+11 -25
View File
@@ -29,10 +29,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
memaddr += 4;
rc_parse_trigger_internal(&self->start, &memaddr, parse);
self->start.memrefs = 0;
if (parse->offset < 0) {
return;
}
}
else if ((memaddr[0] == 'c' || memaddr[0] == 'C') &&
(memaddr[1] == 'a' || memaddr[1] == 'A') &&
@@ -46,10 +42,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
memaddr += 4;
rc_parse_trigger_internal(&self->cancel, &memaddr, parse);
self->cancel.memrefs = 0;
if (parse->offset < 0) {
return;
}
}
else if ((memaddr[0] == 's' || memaddr[0] == 'S') &&
(memaddr[1] == 'u' || memaddr[1] == 'U') &&
@@ -63,10 +55,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
memaddr += 4;
rc_parse_trigger_internal(&self->submit, &memaddr, parse);
self->submit.memrefs = 0;
if (parse->offset < 0) {
return;
}
}
else if ((memaddr[0] == 'v' || memaddr[0] == 'V') &&
(memaddr[1] == 'a' || memaddr[1] == 'A') &&
@@ -80,10 +68,6 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
memaddr += 4;
rc_parse_value_internal(&self->value, &memaddr, parse);
self->value.memrefs = 0;
if (parse->offset < 0) {
return;
}
}
else if ((memaddr[0] == 'p' || memaddr[0] == 'P') &&
(memaddr[1] == 'r' || memaddr[1] == 'R') &&
@@ -99,20 +83,22 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
self->progress = RC_ALLOC(rc_value_t, parse);
rc_parse_value_internal(self->progress, &memaddr, parse);
self->progress->memrefs = 0;
if (parse->offset < 0) {
return;
}
}
else {
/* encountered an error parsing one of the parts */
if (parse->offset < 0)
return;
/* end of string, or end of quoted string - stop processing */
if (memaddr[0] == '\0' || memaddr[0] == '\"')
break;
/* expect two colons between fields */
if (memaddr[0] != ':' || memaddr[1] != ':') {
parse->offset = RC_INVALID_LBOARD_FIELD;
return;
}
if (memaddr[0] != ':' || memaddr[1] != ':') {
break;
}
memaddr += 2;
}
+95 -52
View File
@@ -53,6 +53,11 @@ int rc_parse_memref(const char** memaddr, char* size, unsigned* address) {
aux++;
switch (*aux++) {
/* ordered by estimated frequency in case compiler doesn't build a jump table */
case 'h': case 'H': *size = RC_MEMSIZE_8_BITS; break;
case ' ': *size = RC_MEMSIZE_16_BITS; break;
case 'x': case 'X': *size = RC_MEMSIZE_32_BITS; break;
case 'm': case 'M': *size = RC_MEMSIZE_BIT_0; break;
case 'n': case 'N': *size = RC_MEMSIZE_BIT_1; break;
case 'o': case 'O': *size = RC_MEMSIZE_BIT_2; break;
@@ -64,17 +69,21 @@ int rc_parse_memref(const char** memaddr, char* size, unsigned* address) {
case 'l': case 'L': *size = RC_MEMSIZE_LOW; break;
case 'u': case 'U': *size = RC_MEMSIZE_HIGH; break;
case 'k': case 'K': *size = RC_MEMSIZE_BITCOUNT; break;
case 'h': case 'H': *size = RC_MEMSIZE_8_BITS; break;
case 'w': case 'W': *size = RC_MEMSIZE_24_BITS; break;
case 'x': case 'X': *size = RC_MEMSIZE_32_BITS; break;
case 'g': case 'G': *size = RC_MEMSIZE_32_BITS_BE; break;
case 'i': case 'I': *size = RC_MEMSIZE_16_BITS_BE; break;
case 'j': case 'J': *size = RC_MEMSIZE_24_BITS_BE; break;
/* case 'v': case 'V': */
/* case 'y': case 'Y': 64 bit? */
/* case 'z': case 'Z': 128 bit? */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
/* legacy support - addresses without a size prefix are assumed to be 16-bit */
aux--;
/* fallthrough */
case ' ':
*size = RC_MEMSIZE_16_BITS;
break;
@@ -97,10 +106,24 @@ int rc_parse_memref(const char** memaddr, char* size, unsigned* address) {
static const unsigned char rc_bits_set[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
unsigned rc_transform_memref_value(unsigned value, char size)
{
unsigned rc_transform_memref_value(unsigned value, char size) {
switch (size)
{
case RC_MEMSIZE_8_BITS:
value = (value & 0x000000ff);
break;
case RC_MEMSIZE_16_BITS:
value = (value & 0x0000ffff);
break;
case RC_MEMSIZE_24_BITS:
value = (value & 0x00ffffff);
break;
case RC_MEMSIZE_32_BITS:
break;
case RC_MEMSIZE_BIT_0:
value = (value >> 0) & 1;
break;
@@ -146,6 +169,24 @@ unsigned rc_transform_memref_value(unsigned value, char size)
+ rc_bits_set[((value >> 4) & 0x0F)];
break;
case RC_MEMSIZE_16_BITS_BE:
value = ((value & 0xFF00) >> 8) |
((value & 0x00FF) << 8);
break;
case RC_MEMSIZE_24_BITS_BE:
value = ((value & 0xFF0000) >> 16) |
(value & 0x00FF00) |
((value & 0x0000FF) << 16);
break;
case RC_MEMSIZE_32_BITS_BE:
value = ((value & 0xFF000000) >> 24) |
((value & 0x00FF0000) >> 8) |
((value & 0x0000FF00) << 8) |
((value & 0x000000FF) << 24);
break;
default:
break;
}
@@ -153,35 +194,48 @@ unsigned rc_transform_memref_value(unsigned value, char size)
return value;
}
char rc_memref_shared_size(char size)
{
switch (size) {
case RC_MEMSIZE_BIT_0:
case RC_MEMSIZE_BIT_1:
case RC_MEMSIZE_BIT_2:
case RC_MEMSIZE_BIT_3:
case RC_MEMSIZE_BIT_4:
case RC_MEMSIZE_BIT_5:
case RC_MEMSIZE_BIT_6:
case RC_MEMSIZE_BIT_7:
case RC_MEMSIZE_LOW:
case RC_MEMSIZE_HIGH:
case RC_MEMSIZE_BITCOUNT:
/* these can all share an 8-bit memref and just mask off the appropriate data in rc_transform_memref_value */
return RC_MEMSIZE_8_BITS;
/* all sizes less than 8-bits (1 byte) are mapped to 8-bits. 24-bit is mapped to 32-bit
* as we don't expect the client to understand a request for 3 bytes. all other reads are
* mapped to the little-endian read of the same size. */
static const char rc_memref_shared_sizes[] = {
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_8_BITS */
RC_MEMSIZE_16_BITS, /* RC_MEMSIZE_16_BITS */
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_24_BITS */
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_32_BITS */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_LOW */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_HIGH */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BIT_0 */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BIT_1 */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BIT_2 */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BIT_3 */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BIT_4 */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BIT_5 */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BIT_6 */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BIT_7 */
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_BITCOUNT */
RC_MEMSIZE_16_BITS, /* RC_MEMSIZE_16_BITS_BE */
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_24_BITS_BE */
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_32_BITS_BE */
RC_MEMSIZE_32_BITS /* RC_MEMSIZE_VARIABLE */
};
default:
return size;
}
char rc_memref_shared_size(char size) {
const size_t index = (size_t)size;
if (index >= sizeof(rc_memref_shared_sizes) / sizeof(rc_memref_shared_sizes[0]))
return size;
return rc_memref_shared_sizes[index];
}
static unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void* ud) {
unsigned value;
char shared_size;
if (!peek)
return 0;
switch (size)
shared_size = rc_memref_shared_size(size);
switch (shared_size)
{
case RC_MEMSIZE_8_BITS:
value = peek(address, 1, ud);
@@ -191,28 +245,17 @@ static unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void*
value = peek(address, 2, ud);
break;
case RC_MEMSIZE_24_BITS:
/* peek 4 bytes - don't expect the caller to understand 24-bit numbers */
value = peek(address, 4, ud) & 0x00FFFFFF;
break;
case RC_MEMSIZE_32_BITS:
value = peek(address, 4, ud);
break;
default:
if (rc_memref_shared_size(size) == RC_MEMSIZE_8_BITS)
{
value = peek(address, 1, ud);
value = rc_transform_memref_value(value, size);
}
else
{
value = 0;
}
break;
return 0;
}
if (shared_size != size)
value = rc_transform_memref_value(value, size);
return value;
}
@@ -242,17 +285,7 @@ void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs)
*memrefs = 0;
}
unsigned rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state) {
/* if this is an indirect reference, handle the indirection. */
if (memref->value.is_indirect) {
const unsigned new_address = memref->address + eval_state->add_address;
rc_update_memref_value(&memref->value, rc_peek_value(new_address, memref->value.size, eval_state->peek, eval_state->peek_userdata));
}
return rc_get_memref_value_value(&memref->value, operand_type);
}
unsigned rc_get_memref_value_value(rc_memref_value_t* memref, int operand_type) {
static unsigned rc_get_memref_value_value(rc_memref_value_t* memref, int operand_type) {
switch (operand_type)
{
/* most common case explicitly first, even though it could be handled by default case.
@@ -271,3 +304,13 @@ unsigned rc_get_memref_value_value(rc_memref_value_t* memref, int operand_type)
return memref->prior;
}
}
unsigned rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state) {
/* if this is an indirect reference, handle the indirection. */
if (memref->value.is_indirect) {
const unsigned new_address = memref->address + eval_state->add_address;
rc_update_memref_value(&memref->value, rc_peek_value(new_address, memref->value.size, eval_state->peek, eval_state->peek_userdata));
}
return rc_get_memref_value_value(&memref->value, operand_type);
}
+55 -43
View File
@@ -103,7 +103,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
return ret;
size = rc_memref_shared_size(self->size);
self->value.memref = rc_alloc_memref(parse, address, size, is_indirect);
self->value.memref = rc_alloc_memref(parse, address, size, (char)is_indirect);
if (parse->offset < 0)
return parse->offset;
@@ -111,12 +111,13 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
return RC_OK;
}
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, int is_indirect, rc_parse_state_t* parse) {
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse) {
const char* aux = *memaddr;
char* end;
int ret;
unsigned long value;
int negative;
int allow_decimal = 0;
self->size = RC_MEMSIZE_32_BITS;
@@ -128,14 +129,11 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, i
}
value = strtoul(++aux, &end, 16);
if (end == aux) {
if (end == aux)
return RC_INVALID_CONST_OPERAND;
}
if (value > 0xffffffffU) {
if (value > 0xffffffffU)
value = 0xffffffffU;
}
self->type = RC_OPERAND_CONST;
self->value.num = (unsigned)value;
@@ -144,47 +142,61 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, i
break;
case 'f': case 'F': /* floating point constant */
self->value.dbl = strtod(++aux, &end);
if (end == aux) {
return RC_INVALID_FP_OPERAND;
}
if (floor(self->value.dbl) == self->value.dbl) {
self->type = RC_OPERAND_CONST;
self->value.num = (unsigned)floor(self->value.dbl);
}
else {
self->type = RC_OPERAND_FP;
}
aux = end;
break;
allow_decimal = 1;
/* fall through */
case 'v': case 'V': /* signed integer constant */
++aux;
/* fallthrough */
/* fall through */
case '+': case '-': /* signed integer constant */
negative = 0;
if (*aux == '-')
{
if (*aux == '-') {
negative = 1;
++aux;
}
else if (*aux == '+')
{
else if (*aux == '+') {
++aux;
}
value = strtoul(aux, &end, 10);
if (end == aux) {
return RC_INVALID_CONST_OPERAND;
if (*end == '.' && allow_decimal) {
/* custom parser for decimal values to ignore locale */
unsigned long shift = 1;
unsigned long fraction = 0;
aux = end + 1;
if (*aux < '0' || *aux > '9')
return RC_INVALID_FP_OPERAND;
do {
fraction *= 10;
fraction += (*aux - '0');
shift *= 10;
++aux;
} while (*aux >= '0' && *aux <= '9');
/* if fractional part is 0, convert to an integer constant */
if (fraction != 0) {
/* non-zero fractional part, convert to double and merge in integer portion */
const double dbl_fraction = ((double)fraction) / ((double)shift);
if (negative)
self->value.dbl = ((double)(-((long)value))) - dbl_fraction;
else
self->value.dbl = (double)value + dbl_fraction;
self->type = RC_OPERAND_FP;
break;
}
} else {
/* not a floating point value, make sure something was read and advance the read pointer */
if (end == aux)
return allow_decimal ? RC_INVALID_FP_OPERAND : RC_INVALID_CONST_OPERAND;
aux = end;
}
if (value > 0x7fffffffU) {
if (value > 0x7fffffffU)
value = 0x7fffffffU;
}
self->type = RC_OPERAND_CONST;
@@ -193,7 +205,6 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, i
else
self->value.num = (unsigned)value;
aux = end;
break;
case '0':
@@ -202,9 +213,8 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, i
default:
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
if (ret < 0) {
if (ret < 0)
return ret;
}
break;
}
@@ -213,14 +223,11 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, i
case '1': case '2': case '3': case '4': case '5': /* unsigned integer constant */
case '6': case '7': case '8': case '9':
value = strtoul(aux, &end, 10);
if (end == aux) {
if (end == aux)
return RC_INVALID_CONST_OPERAND;
}
if (value > 0xffffffffU) {
if (value > 0xffffffffU)
value = 0xffffffffU;
}
self->type = RC_OPERAND_CONST;
self->value.num = (unsigned)value;
@@ -231,9 +238,8 @@ int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, i
case '@':
ret = rc_parse_operand_lua(self, &aux, parse);
if (ret < 0) {
if (ret < 0)
return ret;
}
break;
}
@@ -340,6 +346,7 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
break;
case RC_MEMSIZE_16_BITS:
case RC_MEMSIZE_16_BITS_BE:
value = ((value >> 12) & 0x0f) * 1000
+ ((value >> 8) & 0x0f) * 100
+ ((value >> 4) & 0x0f) * 10
@@ -347,6 +354,7 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
break;
case RC_MEMSIZE_24_BITS:
case RC_MEMSIZE_24_BITS_BE:
value = ((value >> 20) & 0x0f) * 100000
+ ((value >> 16) & 0x0f) * 10000
+ ((value >> 12) & 0x0f) * 1000
@@ -356,6 +364,7 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
break;
case RC_MEMSIZE_32_BITS:
case RC_MEMSIZE_32_BITS_BE:
case RC_MEMSIZE_VARIABLE:
value = ((value >> 28) & 0x0f) * 10000000
+ ((value >> 24) & 0x0f) * 1000000
@@ -385,14 +394,17 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
break;
case RC_MEMSIZE_16_BITS:
case RC_MEMSIZE_16_BITS_BE:
value ^= 0xffff;
break;
case RC_MEMSIZE_24_BITS:
case RC_MEMSIZE_24_BITS_BE:
value ^= 0xffffff;
break;
case RC_MEMSIZE_32_BITS:
case RC_MEMSIZE_32_BITS_BE:
case RC_MEMSIZE_VARIABLE:
value ^= 0xffffffff;
break;
+2 -2
View File
@@ -99,6 +99,7 @@ typedef struct {
int lines_read;
char has_required_hits;
char measured_as_percent;
}
rc_parse_state_t;
@@ -116,7 +117,6 @@ int rc_parse_memref(const char** memaddr, char* size, unsigned* address);
void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud);
void rc_update_memref_value(rc_memref_value_t* memref, unsigned value);
unsigned rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state);
unsigned rc_get_memref_value_value(rc_memref_value_t* memref, int operand_type);
char rc_memref_shared_size(char size);
unsigned rc_transform_memref_value(unsigned value, char size);
@@ -131,7 +131,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
int rc_evaluate_condition_value(rc_condition_t* self, rc_eval_state_t* eval_state);
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, int is_indirect, rc_parse_state_t* parse);
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse);
unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state);
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse);
+6
View File
@@ -89,6 +89,11 @@ static const rc_disallowed_setting_t _rc_disallowed_ppsspp_settings[] = {
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_smsplus_settings[] = {
{ "smsplus_region", "pal" },
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_snes9x_settings[] = {
{ "snes9x_region", "pal" },
{ NULL, NULL }
@@ -112,6 +117,7 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
{ "PPSSPP", _rc_disallowed_ppsspp_settings },
{ "PCSX-ReARMed", _rc_disallowed_pcsx_rearmed_settings },
{ "PicoDrive", _rc_disallowed_picodrive_settings },
{ "SMS Plus GX", _rc_disallowed_smsplus_settings },
{ "Snes9x", _rc_disallowed_snes9x_settings },
{ "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings },
{ NULL, NULL }
+3 -3
View File
@@ -383,7 +383,7 @@ static const char* rc_parse_richpresence_lookup(rc_richpresence_lookup_t* lookup
base = 10;
}
first = strtoul(line, &endptr, base);
first = (unsigned)strtoul(line, &endptr, base);
/* check for a range */
if (*endptr != '-') {
@@ -401,7 +401,7 @@ static const char* rc_parse_richpresence_lookup(rc_richpresence_lookup_t* lookup
base = 10;
}
last = strtoul(line, &endptr, base);
last = (unsigned)strtoul(line, &endptr, base);
}
/* ignore spaces after the number - was previously ignored as string was split on equals */
@@ -493,7 +493,7 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
memcpy(format, line, chars);
format[chars] = '\0';
lookup->format = rc_parse_format(format);
lookup->format = (unsigned short)rc_parse_format(format);
} else {
lookup->format = RC_FORMAT_VALUE;
}
+29 -1
View File
@@ -1,5 +1,6 @@
#include "rc_runtime.h"
#include "rc_internal.h"
#include "rc_compat.h"
#include "../rhash/md5.h"
@@ -241,6 +242,33 @@ int rc_runtime_get_achievement_measured(const rc_runtime_t* runtime, unsigned id
return 1;
}
int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, unsigned id, char* buffer, size_t buffer_size)
{
const rc_trigger_t* trigger = rc_runtime_get_achievement(runtime, id);
unsigned value;
if (!buffer || !buffer_size)
return 0;
if (!trigger || /* no trigger */
trigger->measured_target == 0 || /* not measured */
!rc_trigger_state_active(trigger->state)) { /* don't report measured value for inactive triggers */
*buffer = '\0';
return 0;
}
/* cap the value at the target so we can count past the target: "107 >= 100" */
value = trigger->measured_value;
if (value > trigger->measured_target)
value = trigger->measured_target;
if (trigger->measured_as_percent) {
unsigned percent = (unsigned)(((unsigned long long)value * 100) / trigger->measured_target);
return snprintf(buffer, buffer_size, "%u%%", percent);
}
return snprintf(buffer, buffer_size, "%u/%u", value, trigger->measured_target);
}
static void rc_runtime_deactivate_lboard_by_index(rc_runtime_t* self, unsigned index) {
if (self->lboards[index].owns_memrefs) {
/* if the lboard has one or more memrefs in its buffer, we can't free the buffer.
@@ -507,7 +535,7 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
if (new_state == old_state)
continue;
/* raise an UNPRIMED event when changing from UNPRIMED to anything else */
/* raise an UNPRIMED event when changing from PRIMED to anything else */
if (old_state == RC_TRIGGER_STATE_PRIMED) {
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_UNPRIMED;
runtime_event.id = self->triggers[i].id;
+8 -2
View File
@@ -247,7 +247,7 @@ static int rc_runtime_progress_read_condset(rc_runtime_progress_t* progress, rc_
rc_condition_t* cond;
unsigned flags;
condset->is_paused = rc_runtime_progress_read_uint(progress);
condset->is_paused = (char)rc_runtime_progress_read_uint(progress);
cond = condset->conditions;
while (cond) {
@@ -257,12 +257,18 @@ static int rc_runtime_progress_read_condset(rc_runtime_progress_t* progress, rc_
cond->is_true = (flags & RC_COND_FLAG_IS_TRUE) ? 1 : 0;
if (flags & RC_COND_FLAG_OPERAND1_IS_INDIRECT_MEMREF) {
if (!rc_operand_is_memref(&cond->operand1)) /* this should never happen, but better safe than sorry */
return RC_INVALID_STATE;
cond->operand1.value.memref->value.value = rc_runtime_progress_read_uint(progress);
cond->operand1.value.memref->value.prior = rc_runtime_progress_read_uint(progress);
cond->operand1.value.memref->value.changed = (flags & RC_COND_FLAG_OPERAND1_MEMREF_CHANGED_THIS_FRAME) ? 1 : 0;
}
if (flags & RC_COND_FLAG_OPERAND2_IS_INDIRECT_MEMREF) {
if (!rc_operand_is_memref(&cond->operand2)) /* this should never happen, but better safe than sorry */
return RC_INVALID_STATE;
cond->operand2.value.memref->value.value = rc_runtime_progress_read_uint(progress);
cond->operand2.value.memref->value.prior = rc_runtime_progress_read_uint(progress);
cond->operand2.value.memref->value.changed = (flags & RC_COND_FLAG_OPERAND2_MEMREF_CHANGED_THIS_FRAME) ? 1 : 0;
@@ -305,7 +311,7 @@ static int rc_runtime_progress_read_trigger(rc_runtime_progress_t* progress, rc_
rc_condset_t* condset;
int result;
trigger->state = rc_runtime_progress_read_uint(progress);
trigger->state = (char)rc_runtime_progress_read_uint(progress);
trigger->measured_value = rc_runtime_progress_read_uint(progress);
if (trigger->requirement) {
+2
View File
@@ -13,6 +13,7 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
/* reset in case multiple triggers are parsed by the same parse_state */
parse->measured_target = 0;
parse->has_required_hits = 0;
parse->measured_as_percent = 0;
if (*aux == 's' || *aux == 'S') {
self->requirement = 0;
@@ -43,6 +44,7 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
self->measured_value = 0;
self->measured_target = parse->measured_target;
self->measured_as_percent = parse->measured_as_percent;
self->state = RC_TRIGGER_STATE_WAITING;
self->has_hits = 0;
self->has_required_hits = parse->has_required_hits;
+13 -11
View File
@@ -72,17 +72,14 @@ void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_stat
*ptr++ = '*';
buffer_ptr = *memaddr + 1;
if (*buffer_ptr == '-') {
/* negative value automatically needs prefix, 'f' handles both float and digits, so use it */
if (*buffer_ptr == '-' || *buffer_ptr == '+')
++buffer_ptr; /* ignore sign */
/* if it looks like a floating point number, add the 'f' prefix */
while (isdigit((unsigned char)*buffer_ptr))
++buffer_ptr;
if (*buffer_ptr == '.')
*ptr++ = 'f';
}
else {
/* if it looks like a floating point number, add the 'f' prefix */
while (isdigit((unsigned char)*buffer_ptr))
++buffer_ptr;
if (*buffer_ptr == '.')
*ptr++ = 'f';
}
break;
default:
@@ -95,7 +92,12 @@ void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_stat
buffer_ptr = buffer;
cond = rc_parse_condition(&buffer_ptr, parse, 0);
if (parse->offset < 0) {
if (parse->offset < 0)
return;
if (*buffer_ptr) {
/* whatever we copied as a single condition was not fully consumed */
parse->offset = RC_INVALID_COMPARISON;
return;
}
+281 -20
View File
@@ -118,7 +118,11 @@ void* rc_file_open(const char* path)
void* handle;
if (!filereader)
{
rc_hash_init_custom_filereader(NULL);
if (!filereader)
return NULL;
}
handle = filereader->open(path);
if (handle && verbose_message_callback)
@@ -360,7 +364,7 @@ static int rc_hash_finalize(md5_state_t* md5, char hash[33])
return 1;
}
static int rc_hash_buffer(char hash[33], uint8_t* buffer, size_t buffer_size)
static int rc_hash_buffer(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
md5_state_t md5;
md5_init(&md5);
@@ -410,9 +414,9 @@ static int rc_hash_cd_file(md5_state_t* md5, void* track_handle, uint32_t sector
{
md5_append(md5, buffer, (int)num_read);
size -= (unsigned)num_read;
if (size == 0)
if (size <= (unsigned)num_read)
break;
size -= (unsigned)num_read;
++sector;
if (size >= sizeof(buffer))
@@ -494,7 +498,7 @@ static int rc_hash_3do(char hash[33], const char* path)
block_location *= block_size;
/* the file size is at offset 0x10 (assume 0x10 is always 0) */
size = buffer[offset + 0x11] * 65536 + buffer[offset + 0x12] * 256 + buffer[offset + 0x13];
size = (size_t)buffer[offset + 0x11] * 65536 + buffer[offset + 0x12] * 256 + buffer[offset + 0x13];
if (verbose_message_callback)
{
@@ -557,7 +561,7 @@ static int rc_hash_3do(char hash[33], const char* path)
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_7800(char hash[33], uint8_t* buffer, size_t buffer_size)
static int rc_hash_7800(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it */
if (memcmp(&buffer[1], "ATARI7800", 9) == 0)
@@ -644,7 +648,7 @@ static int rc_hash_arcade(char hash[33], const char* path)
return rc_hash_buffer(hash, (uint8_t*)filename, filename_length);
}
static int rc_hash_lynx(char hash[33], uint8_t* buffer, size_t buffer_size)
static int rc_hash_lynx(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it */
if (buffer[0] == 'L' && buffer[1] == 'Y' && buffer[2] == 'N' && buffer[3] == 'X' && buffer[4] == 0)
@@ -658,7 +662,7 @@ static int rc_hash_lynx(char hash[33], uint8_t* buffer, size_t buffer_size)
return rc_hash_buffer(hash, buffer, buffer_size);
}
static int rc_hash_nes(char hash[33], uint8_t* buffer, size_t buffer_size)
static int rc_hash_nes(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it */
if (buffer[0] == 'N' && buffer[1] == 'E' && buffer[2] == 'S' && buffer[3] == 0x1A)
@@ -679,6 +683,212 @@ static int rc_hash_nes(char hash[33], uint8_t* buffer, size_t buffer_size)
return rc_hash_buffer(hash, buffer, buffer_size);
}
static void rc_hash_v64_to_z64(uint8_t* buffer, const uint8_t* stop)
{
uint32_t* ptr = (uint32_t*)buffer;
const uint32_t* stop32 = (const uint32_t*)stop;
while (ptr < stop32)
{
uint32_t temp = *ptr;
temp = (temp & 0xFF00FF00) >> 8 |
(temp & 0x00FF00FF) << 8;
*ptr++ = temp;
}
}
static void rc_hash_n64_to_z64(uint8_t* buffer, const uint8_t* stop)
{
uint32_t* ptr = (uint32_t*)buffer;
const uint32_t* stop32 = (const uint32_t*)stop;
while (ptr < stop32)
{
uint32_t temp = *ptr;
temp = (temp & 0xFF000000) >> 24 |
(temp & 0x00FF0000) >> 8 |
(temp & 0x0000FF00) << 8 |
(temp & 0x000000FF) << 24;
*ptr++ = temp;
}
}
static int rc_hash_n64(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
uint8_t* swapbuffer;
uint8_t* stop;
const size_t swapbuffer_size = 65536;
md5_state_t md5;
size_t remaining;
int is_v64;
if (buffer[0] == 0x80) /* z64 format (big endian [native]) */
{
return rc_hash_buffer(hash, buffer, buffer_size);
}
else if (buffer[0] == 0x37) /* v64 format (byteswapped) */
{
rc_hash_verbose("converting v64 to z64");
is_v64 = 1;
}
else if (buffer[0] == 0x40) /* n64 format (little endian) */
{
rc_hash_verbose("converting n64 to z64");
is_v64 = 0;
}
else
{
rc_hash_verbose("Not a Nintendo 64 ROM");
return 0;
}
swapbuffer = (uint8_t*)malloc(swapbuffer_size);
if (!swapbuffer)
return rc_hash_error("Could not allocate temporary buffer");
stop = swapbuffer + swapbuffer_size;
md5_init(&md5);
if (buffer_size > MAX_BUFFER_SIZE)
remaining = MAX_BUFFER_SIZE;
else
remaining = (size_t)buffer_size;
if (verbose_message_callback)
{
char message[64];
snprintf(message, sizeof(message), "Hashing %u bytes", (unsigned)remaining);
verbose_message_callback(message);
}
while (remaining >= swapbuffer_size)
{
memcpy(swapbuffer, buffer, swapbuffer_size);
if (is_v64)
rc_hash_v64_to_z64(swapbuffer, stop);
else
rc_hash_n64_to_z64(swapbuffer, stop);
md5_append(&md5, swapbuffer, (int)swapbuffer_size);
buffer += swapbuffer_size;
remaining -= swapbuffer_size;
}
if (remaining > 0)
{
memcpy(swapbuffer, buffer, remaining);
stop = swapbuffer + remaining;
if (is_v64)
rc_hash_v64_to_z64(swapbuffer, stop);
else
rc_hash_n64_to_z64(swapbuffer, stop);
md5_append(&md5, swapbuffer, (int)remaining);
}
free(swapbuffer);
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_n64_file(char hash[33], const char* path)
{
uint8_t* buffer;
uint8_t* stop;
const size_t buffer_size = 65536;
md5_state_t md5;
size_t remaining;
void* file_handle;
int is_v64 = 0;
int is_n64 = 0;
file_handle = rc_file_open(path);
if (!file_handle)
return rc_hash_error("Could not open file");
buffer = (uint8_t*)malloc(buffer_size);
if (!buffer)
{
rc_file_close(file_handle);
return rc_hash_error("Could not allocate temporary buffer");
}
stop = buffer + buffer_size;
/* read first byte so we can detect endianness */
rc_file_seek(file_handle, 0, SEEK_SET);
rc_file_read(file_handle, buffer, 1);
if (buffer[0] == 0x80) /* z64 format (big endian [native]) */
{
}
else if (buffer[0] == 0x37) /* v64 format (byteswapped) */
{
rc_hash_verbose("converting v64 to z64");
is_v64 = 1;
}
else if (buffer[0] == 0x40) /* n64 format (little endian) */
{
rc_hash_verbose("converting n64 to z64");
is_n64 = 1;
}
else
{
free(buffer);
rc_file_close(file_handle);
rc_hash_verbose("Not a Nintendo 64 ROM");
return 0;
}
/* calculate total file size */
rc_file_seek(file_handle, 0, SEEK_END);
remaining = (size_t)rc_file_tell(file_handle);
if (remaining > MAX_BUFFER_SIZE)
remaining = MAX_BUFFER_SIZE;
if (verbose_message_callback)
{
char message[64];
snprintf(message, sizeof(message), "Hashing %u bytes", (unsigned)remaining);
verbose_message_callback(message);
}
/* begin hashing */
md5_init(&md5);
rc_file_seek(file_handle, 0, SEEK_SET);
while (remaining >= buffer_size)
{
rc_file_read(file_handle, buffer, (int)buffer_size);
if (is_v64)
rc_hash_v64_to_z64(buffer, stop);
else if (is_n64)
rc_hash_n64_to_z64(buffer, stop);
md5_append(&md5, buffer, (int)buffer_size);
remaining -= buffer_size;
}
if (remaining > 0)
{
rc_file_read(file_handle, buffer, (int)remaining);
stop = buffer + remaining;
if (is_v64)
rc_hash_v64_to_z64(buffer, stop);
else if (is_n64)
rc_hash_n64_to_z64(buffer, stop);
md5_append(&md5, buffer, (int)remaining);
}
/* cleanup */
rc_file_close(file_handle);
free(buffer);
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_nintendo_ds(char hash[33], const char* path)
{
uint8_t header[512];
@@ -790,7 +1000,7 @@ static int rc_hash_nintendo_ds(char hash[33], const char* path)
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_pce(char hash[33], uint8_t* buffer, size_t buffer_size)
static int rc_hash_pce(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it (expect ROM data to be multiple of 128KB) */
uint32_t calc_size = ((uint32_t)buffer_size / 0x20000) * 0x20000;
@@ -1095,6 +1305,7 @@ static int rc_hash_find_playstation_executable(void* track_handle, const char* b
size = (unsigned)rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer) - 1);
buffer[size] = '\0';
sector = 0;
for (ptr = (char*)buffer; *ptr; ++ptr)
{
if (strncmp(ptr, boot_key, boot_key_len) == 0)
@@ -1170,7 +1381,7 @@ static int rc_hash_psx(char hash[33], const char* path)
{
rc_hash_error("Could not locate primary executable");
}
else if ((rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer))) < sizeof(buffer))
else if (rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer)) < sizeof(buffer))
{
rc_hash_error("Could not read primary executable");
}
@@ -1227,7 +1438,7 @@ static int rc_hash_ps2(char hash[33], const char* path)
{
rc_hash_error("Could not locate primary executable");
}
else if ((rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer))) < sizeof(buffer))
else if (rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer)) < sizeof(buffer))
{
rc_hash_error("Could not read primary executable");
}
@@ -1258,6 +1469,40 @@ static int rc_hash_ps2(char hash[33], const char* path)
return result;
}
static int rc_hash_psp(char hash[33], const char* path)
{
void* track_handle;
uint32_t sector;
unsigned size;
md5_state_t md5;
track_handle = rc_cd_open_track(path, 1);
if (!track_handle)
return rc_hash_error("Could not open track");
/* http://www.romhacking.net/forum/index.php?topic=30899.0
* PSP_GAME/PARAM.SFO contains key/value pairs identifying the game for the system (i.e. serial number,
* name, version). PSP_GAME/SYSDIR/EBOOT.BIN is the encrypted primary executable.
*/
sector = rc_cd_find_file_sector(track_handle, "PSP_GAME\\PARAM.SFO", &size);
if (!sector)
return rc_hash_error("Not a PSP game disc");
md5_init(&md5);
if (!rc_hash_cd_file(&md5, track_handle, sector, NULL, size, "PSP_GAME\\PARAM.SFO"))
return 0;
sector = rc_cd_find_file_sector(track_handle, "PSP_GAME\\SYSDIR\\EBOOT.BIN", &size);
if (!sector)
return rc_hash_error("Could not find primary executable");
if (!rc_hash_cd_file(&md5, track_handle, sector, NULL, size, "PSP_GAME\\SYSDIR\\EBOOT.BIN"))
return 0;
rc_cd_close_track(track_handle);
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_sega_cd(char hash[33], const char* path)
{
uint8_t buffer[512];
@@ -1287,7 +1532,7 @@ static int rc_hash_sega_cd(char hash[33], const char* path)
return rc_hash_buffer(hash, buffer, sizeof(buffer));
}
static int rc_hash_snes(char hash[33], uint8_t* buffer, size_t buffer_size)
static int rc_hash_snes(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it */
uint32_t calc_size = ((uint32_t)buffer_size / 0x2000) * 0x2000;
@@ -1302,7 +1547,7 @@ static int rc_hash_snes(char hash[33], uint8_t* buffer, size_t buffer_size)
return rc_hash_buffer(hash, buffer, buffer_size);
}
int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer, size_t buffer_size)
int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* buffer, size_t buffer_size)
{
switch (console_id)
{
@@ -1327,7 +1572,6 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer,
case RC_CONSOLE_MEGA_DRIVE:
case RC_CONSOLE_MSX:
case RC_CONSOLE_NEOGEO_POCKET:
case RC_CONSOLE_NINTENDO_64:
case RC_CONSOLE_ORIC:
case RC_CONSOLE_PC8800:
case RC_CONSOLE_POKEMON_MINI:
@@ -1349,6 +1593,9 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer,
case RC_CONSOLE_NINTENDO:
return rc_hash_nes(hash, buffer, buffer_size);
case RC_CONSOLE_NINTENDO_64:
return rc_hash_n64(hash, buffer, buffer_size);
case RC_CONSOLE_PC_ENGINE: /* NOTE: does not support PCEngine CD */
return rc_hash_pce(hash, buffer, buffer_size);
@@ -1357,7 +1604,7 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer,
}
}
static int rc_hash_whole_file(char hash[33], int console_id, const char* path)
static int rc_hash_whole_file(char hash[33], const char* path)
{
md5_state_t md5;
uint8_t* buffer;
@@ -1608,7 +1855,6 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
case RC_CONSOLE_MASTER_SYSTEM:
case RC_CONSOLE_MEGA_DRIVE:
case RC_CONSOLE_NEOGEO_POCKET:
case RC_CONSOLE_NINTENDO_64:
case RC_CONSOLE_ORIC:
case RC_CONSOLE_POKEMON_MINI:
case RC_CONSOLE_SEGA_32X:
@@ -1619,7 +1865,7 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
case RC_CONSOLE_VIRTUAL_BOY:
case RC_CONSOLE_WONDERSWAN:
/* generic whole-file hash - don't buffer */
return rc_hash_whole_file(hash, console_id, path);
return rc_hash_whole_file(hash, path);
case RC_CONSOLE_MSX:
case RC_CONSOLE_PC8800:
@@ -1627,7 +1873,7 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
if (rc_path_compare_extension(path, "m3u"))
return rc_hash_generate_from_playlist(hash, console_id, path);
return rc_hash_whole_file(hash, console_id, path);
return rc_hash_whole_file(hash, path);
case RC_CONSOLE_ATARI_7800:
case RC_CONSOLE_ATARI_LYNX:
@@ -1645,6 +1891,9 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
case RC_CONSOLE_ARCADE:
return rc_hash_arcade(hash, path);
case RC_CONSOLE_NINTENDO_64:
return rc_hash_n64_file(hash, path);
case RC_CONSOLE_NINTENDO_DS:
return rc_hash_nintendo_ds(hash, path);
@@ -1675,6 +1924,9 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
return rc_hash_ps2(hash, path);
case RC_CONSOLE_PSP:
return rc_hash_psp(hash, path);
case RC_CONSOLE_DREAMCAST:
if (rc_path_compare_extension(path, "m3u"))
return rc_hash_generate_from_playlist(hash, console_id, path);
@@ -1690,7 +1942,7 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
}
}
static void rc_hash_iterator_append_console(struct rc_hash_iterator* iterator, int console_id)
static void rc_hash_iterator_append_console(struct rc_hash_iterator* iterator, uint8_t console_id)
{
int i = 0;
while (iterator->consoles[i] != 0)
@@ -1916,8 +2168,9 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
if (rc_path_compare_extension(ext, "iso"))
{
iterator->consoles[0] = RC_CONSOLE_PLAYSTATION_2;
iterator->consoles[1] = RC_CONSOLE_3DO;
iterator->consoles[2] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
iterator->consoles[1] = RC_CONSOLE_PSP;
iterator->consoles[2] = RC_CONSOLE_3DO;
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
need_path = 1;
}
break;
@@ -2061,6 +2314,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
{
iterator->consoles[0] = RC_CONSOLE_VIRTUAL_BOY;
}
else if (rc_path_compare_extension(ext, "v64"))
{
iterator->consoles[0] = RC_CONSOLE_NINTENDO_64;
}
break;
case 'w':
@@ -2081,6 +2338,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
iterator->consoles[0] = RC_CONSOLE_ARCADE;
need_path = 1;
}
else if (rc_path_compare_extension(ext, "z64"))
{
iterator->consoles[0] = RC_CONSOLE_NINTENDO_64;
}
break;
}
+45 -16
View File
@@ -6,6 +6,12 @@
#include <stdio.h>
#include <string.h>
#if RCHEEVOS_URL_SSL
#define RCHEEVOS_URL_PROTOCOL "https"
#else
#define RCHEEVOS_URL_PROTOCOL "http"
#endif
static int rc_url_encode(char* encoded, size_t len, const char* str) {
for (;;) {
switch (*str) {
@@ -67,7 +73,7 @@ int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const
written = snprintf(
buffer,
size,
"http://retroachievements.org/dorequest.php?r=awardachievement&u=%s&t=%s&a=%u&h=%d",
RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php?r=awardachievement&u=%s&t=%s&a=%u&h=%d",
urle_user_name,
urle_login_token,
cheevo_id,
@@ -106,7 +112,7 @@ int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const
written = snprintf(
buffer,
size,
"http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
urle_user_name,
urle_login_token,
lboard_id,
@@ -122,7 +128,7 @@ int rc_url_get_gameid(char* buffer, size_t size, const char* hash) {
int written = snprintf(
buffer,
size,
"http://retroachievements.org/dorequest.php?r=gameid&m=%s",
RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php?r=gameid&m=%s",
hash
);
@@ -145,7 +151,7 @@ int rc_url_get_patch(char* buffer, size_t size, const char* user_name, const cha
written = snprintf(
buffer,
size,
"http://retroachievements.org/dorequest.php?r=patch&u=%s&t=%s&g=%u",
RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php?r=patch&u=%s&t=%s&g=%u",
urle_user_name,
urle_login_token,
gameid
@@ -181,7 +187,7 @@ int rc_url_login_with_password(char* buffer, size_t size, const char* user_name,
written = snprintf(
buffer,
size,
"http://retroachievements.org/dorequest.php?r=login&u=%s&p=%s",
RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php?r=login&u=%s&p=%s",
urle_user_name,
urle_password
);
@@ -205,7 +211,7 @@ int rc_url_login_with_token(char* buffer, size_t size, const char* user_name, co
written = snprintf(
buffer,
size,
"http://retroachievements.org/dorequest.php?r=login&u=%s&t=%s",
RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php?r=login&u=%s&t=%s",
urle_user_name,
urle_login_token
);
@@ -229,7 +235,7 @@ int rc_url_get_unlock_list(char* buffer, size_t size, const char* user_name, con
written = snprintf(
buffer,
size,
"http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=%d",
RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=%d",
urle_user_name,
urle_login_token,
gameid,
@@ -255,7 +261,7 @@ int rc_url_post_playing(char* buffer, size_t size, const char* user_name, const
written = snprintf(
buffer,
size,
"http://retroachievements.org/dorequest.php?r=postactivity&u=%s&t=%s&a=3&m=%u",
RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php?r=postactivity&u=%s&t=%s&a=3&m=%u",
urle_user_name,
urle_login_token,
gameid
@@ -300,8 +306,7 @@ static int rc_url_append_unum(char* buffer, size_t buffer_size, size_t* buffer_o
char num[16];
int chars = snprintf(num, sizeof(num), "%u", value);
if (chars + written < (int)buffer_size)
{
if (chars + written < (int)buffer_size) {
memcpy(&buffer[written], num, chars + 1);
*buffer_offset = written + chars;
return 0;
@@ -314,13 +319,11 @@ static int rc_url_append_unum(char* buffer, size_t buffer_size, size_t* buffer_o
static int rc_url_append_str(char* buffer, size_t buffer_size, size_t* buffer_offset, const char* param, const char* value)
{
int written = rc_url_append_param_equals(buffer, buffer_size, *buffer_offset, param);
if (written > 0)
{
if (written > 0) {
buffer += written;
buffer_size -= written;
if (rc_url_encode(buffer, buffer_size, value) == 0)
{
if (rc_url_encode(buffer, buffer_size, value) == 0) {
written += (int)strlen(buffer);
*buffer_offset = written;
return 0;
@@ -333,7 +336,7 @@ static int rc_url_append_str(char* buffer, size_t buffer_size, size_t* buffer_of
static int rc_url_build_dorequest(char* url_buffer, size_t url_buffer_size, size_t* buffer_offset,
const char* api, const char* user_name)
{
const char* base_url = "http://retroachievements.org/dorequest.php";
const char* base_url = RCHEEVOS_URL_PROTOCOL"://retroachievements.org/dorequest.php";
size_t written = strlen(base_url);
int failure = 0;
@@ -343,7 +346,8 @@ static int rc_url_build_dorequest(char* url_buffer, size_t url_buffer_size, size
url_buffer[written++] = '?';
failure |= rc_url_append_str(url_buffer, url_buffer_size, &written, "r", api);
failure |= rc_url_append_str(url_buffer, url_buffer_size, &written, "u", user_name);
if (user_name)
failure |= rc_url_append_str(url_buffer, url_buffer_size, &written, "u", user_name);
*buffer_offset += written;
return failure;
@@ -371,3 +375,28 @@ int rc_url_ping(char* url_buffer, size_t url_buffer_size, char* post_buffer, siz
return failure;
}
int rc_url_get_lboard_entries(char* buffer, size_t size, unsigned lboard_id, unsigned first_index, unsigned count)
{
size_t written = 0;
int failure = rc_url_build_dorequest(buffer, size, &written, "lbinfo", NULL);
failure |= rc_url_append_unum(buffer, size, &written, "i", lboard_id);
if (first_index > 1)
failure |= rc_url_append_unum(buffer, size, &written, "o", first_index - 1);
failure |= rc_url_append_unum(buffer, size, &written, "c", count);
return failure;
}
int rc_url_get_lboard_entries_near_user(char* buffer, size_t size, unsigned lboard_id, const char* user_name, unsigned count)
{
size_t written = 0;
int failure = rc_url_build_dorequest(buffer, size, &written, "lbinfo", NULL);
failure |= rc_url_append_unum(buffer, size, &written, "i", lboard_id);
failure |= rc_url_append_str(buffer, size, &written, "u", user_name);
failure |= rc_url_append_unum(buffer, size, &written, "c", count);
return failure;
}
#undef RCHEEVOS_URL_PROTOCOL
-4
View File
@@ -143,10 +143,6 @@ bool fill_pathname_application_data(char *s, size_t len)
const char* xmb_theme_ident(void);
#endif
#ifdef HAVE_STRIPES
const char* stripes_theme_ident(void);
#endif
void fill_pathname_application_special(char *s,
size_t len, enum application_special_type type)
{
+10 -4
View File
@@ -162,8 +162,10 @@ static void frontend_ctr_deinit(void* data)
verbosity_enable();
retro_main_log_file_init(NULL, false);
#ifdef CONSOLE_LOG
if (ctr_bottom_screen_enabled && (ctr_fork_mode == FRONTEND_FORK_NONE))
wait_for_input();
#endif
CFGU_GetModelNintendo2DS(&not_2DS);
@@ -419,13 +421,15 @@ void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id)
id,
(u32*)gfxBottomFramebuffers[id],
(u32*)gfxBottomFramebuffers[id],
240 * 2,
GSP_RGB565_OES);
240 * 3,
GSP_BGR8_OES);
}
}
#endif
#ifdef CONSOLE_LOG
PrintConsole* ctrConsole;
#endif
static void frontend_ctr_init(void* data)
{
@@ -436,10 +440,10 @@ static void frontend_ctr_init(void* data)
verbosity_enable();
gfxInit(GSP_BGR8_OES, GSP_RGB565_OES, false);
gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false);
u32 topSize = 400 * 240 * 3;
u32 bottomSize = 320 * 240 * 2;
u32 bottomSize = 320 * 240 * 3;
#ifdef USE_CTRULIB_2
linearFree(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL));
@@ -473,7 +477,9 @@ static void frontend_ctr_init(void* data)
gfxSetFramebufferInfo(GFX_BOTTOM, 0);
gfxSet3D(true);
#ifdef CONSOLE_LOG
ctrConsole = consoleInit(GFX_BOTTOM, NULL);
#endif
/* enable access to all service calls when possible. */
if (svchax_init)
+34 -4
View File
@@ -21,8 +21,11 @@
#define COLOR_ABGR(r, g, b, a) (((unsigned)(a) << 24) | ((b) << 16) | ((g) << 8) | ((r) << 0))
#define CTR_TOP_FRAMEBUFFER_WIDTH 400
#define CTR_TOP_FRAMEBUFFER_HEIGHT 240
#define CTR_TOP_FRAMEBUFFER_WIDTH 400
#define CTR_TOP_FRAMEBUFFER_HEIGHT 240
#define CTR_BOTTOM_FRAMEBUFFER_WIDTH 320
#define CTR_BOTTOM_FRAMEBUFFER_HEIGHT 240
#define CTR_STATE_DATE_SIZE 11
#ifdef USE_CTRULIB_2
extern u8* gfxTopLeftFramebuffers[2];
@@ -30,7 +33,9 @@ extern u8* gfxTopRightFramebuffers[2];
extern u8* gfxBottomFramebuffers[2];
#endif
#ifdef CONSOLE_LOG
extern PrintConsole* ctrConsole;
#endif
extern const u8 ctr_sprite_shbin[];
extern const u32 ctr_sprite_shbin_size;
@@ -58,6 +63,13 @@ typedef enum
CTR_VIDEO_MODE_LAST
} ctr_video_mode_enum;
typedef enum
{
CTR_BOTTOM_MENU_NOT_AVAILABLE = 0,
CTR_BOTTOM_MENU_DEFAULT,
CTR_BOTTOM_MENU_SELECT,
} ctr_bottom_menu;
typedef struct ctr_video
{
struct
@@ -67,6 +79,7 @@ typedef struct ctr_video
void* left;
void* right;
}top;
void* bottom;
}drawbuffers;
void* depthbuffer;
@@ -116,11 +129,10 @@ typedef struct ctr_video
bool overlay_full_screen;
#endif
void* empty_framebuffer;
aptHookCookie lcd_aptHook;
ctr_video_mode_enum video_mode;
int current_buffer_top;
int current_buffer_bottom;
bool p3d_event_pending;
bool ppf_event_pending;
@@ -133,6 +145,17 @@ typedef struct ctr_video
int size;
}vertex_cache;
bool init_bottom_menu;
bool refresh_bottom_menu;
bool render_font_bottom;
bool render_state_from_png_file;
bool state_data_on_ram;
bool state_data_exist;
char state_date[CTR_STATE_DATE_SIZE];
int state_slot;
ctr_bottom_menu bottom_menu;
ctr_bottom_menu prev_bottom_menu;
struct ctr_bottom_texture_data *bottom_textures;
} ctr_video_t;
typedef struct ctr_texture
@@ -156,6 +179,13 @@ struct ctr_overlay_data
};
#endif
struct ctr_bottom_texture_data
{
uintptr_t texture;
ctr_vertex_t* frame_coords;
ctr_scale_vector_t scale_vector;
};
static INLINE void ctr_set_scale_vector(ctr_scale_vector_t* vec,
int viewport_width, int viewport_height,
int texture_width, int texture_height)
+33 -11
View File
@@ -226,30 +226,52 @@ bool d3d11_init_shader(
LPCSTR gs_entry,
const D3D11_INPUT_ELEMENT_DESC* input_element_descs,
UINT num_elements,
d3d11_shader_t* out)
d3d11_shader_t* out,
enum d3d11_feature_level_hint hint)
{
D3DBlob vs_code = NULL;
D3DBlob ps_code = NULL;
D3DBlob gs_code = NULL;
D3DBlob vs_code = NULL;
D3DBlob ps_code = NULL;
D3DBlob gs_code = NULL;
bool success = true;
const char *vs_str = NULL;
const char *ps_str = NULL;
const char *gs_str = NULL;
bool success = true;
switch (hint)
{
case D3D11_FEATURE_LEVEL_HINT_11_0:
case D3D11_FEATURE_LEVEL_HINT_11_1:
case D3D11_FEATURE_LEVEL_HINT_12_0:
case D3D11_FEATURE_LEVEL_HINT_12_1:
case D3D11_FEATURE_LEVEL_HINT_12_2:
vs_str = "vs_5_0";
ps_str = "ps_5_0";
gs_str = "gs_5_0";
break;
case D3D11_FEATURE_LEVEL_HINT_DONTCARE:
default:
vs_str = "vs_4_0";
ps_str = "ps_4_0";
gs_str = "gs_4_0";
break;
}
if (!src) /* LPCWSTR filename */
{
if (vs_entry && !d3d_compile_from_file((LPCWSTR)src_name, vs_entry, "vs_4_0", &vs_code))
if (vs_entry && !d3d_compile_from_file((LPCWSTR)src_name, vs_entry, vs_str, &vs_code))
success = false;
if (ps_entry && !d3d_compile_from_file((LPCWSTR)src_name, ps_entry, "ps_4_0", &ps_code))
if (ps_entry && !d3d_compile_from_file((LPCWSTR)src_name, ps_entry, ps_str, &ps_code))
success = false;
if (gs_entry && !d3d_compile_from_file((LPCWSTR)src_name, gs_entry, "gs_4_0", &gs_code))
if (gs_entry && !d3d_compile_from_file((LPCWSTR)src_name, gs_entry, gs_str, &gs_code))
success = false;
}
else /* char array */
{
if (vs_entry && !d3d_compile(src, size, (LPCSTR)src_name, vs_entry, "vs_4_0", &vs_code))
if (vs_entry && !d3d_compile(src, size, (LPCSTR)src_name, vs_entry, vs_str, &vs_code))
success = false;
if (ps_entry && !d3d_compile(src, size, (LPCSTR)src_name, ps_entry, "ps_4_0", &ps_code))
if (ps_entry && !d3d_compile(src, size, (LPCSTR)src_name, ps_entry, ps_str, &ps_code))
success = false;
if (gs_entry && !d3d_compile(src, size, (LPCSTR)src_name, gs_entry, "gs_4_0", &gs_code))
if (gs_entry && !d3d_compile(src, size, (LPCSTR)src_name, gs_entry, gs_str, &gs_code))
success = false;
}
+41 -1
View File
@@ -2529,6 +2529,9 @@ typedef struct
D3D11RasterizerState scissor_disabled;
D3D11Buffer ubo;
d3d11_uniform_t ubo_values;
#ifdef HAVE_DXGI_HDR
d3d11_texture_t back_buffer;
#endif
D3D11SamplerState samplers[RARCH_FILTER_MAX][RARCH_WRAP_MAX];
D3D11BlendState blend_enable;
D3D11BlendState blend_disable;
@@ -2549,6 +2552,12 @@ typedef struct
bool has_flip_model;
bool has_allow_tearing;
d3d11_shader_t shaders[GFX_MAX_SHADERS];
#ifdef HAVE_DXGI_HDR
enum dxgi_swapchain_bit_depth
chain_bit_depth;
DXGI_COLOR_SPACE_TYPE chain_color_space;
DXGI_FORMAT chain_formats[DXGI_SWAPCHAIN_BIT_DEPTH_COUNT];
#endif
#ifdef __WINRT__
DXGIFactory2 factory;
#else
@@ -2562,6 +2571,20 @@ typedef struct
struct retro_hw_render_interface_d3d11 iface;
} hw;
#ifdef HAVE_DXGI_HDR
struct
{
dxgi_hdr_uniform_t ubo_values;
D3D11Buffer ubo;
float max_output_nits;
float min_output_nits;
float max_cll;
float max_fall;
bool support;
bool enable;
} hdr;
#endif
struct
{
d3d11_shader_t shader;
@@ -2641,6 +2664,22 @@ void d3d11_update_texture(
DXGI_FORMAT d3d11_get_closest_match(
D3D11Device device, DXGI_FORMAT desired_format, UINT desired_format_support);
enum d3d11_feature_level_hint
{
D3D11_FEATURE_LEVEL_HINT_DONTCARE,
D3D11_FEATURE_LEVEL_HINT_1_0_CORE,
D3D11_FEATURE_LEVEL_HINT_9_1,
D3D11_FEATURE_LEVEL_HINT_9_2,
D3D11_FEATURE_LEVEL_HINT_9_3,
D3D11_FEATURE_LEVEL_HINT_10_0,
D3D11_FEATURE_LEVEL_HINT_10_1,
D3D11_FEATURE_LEVEL_HINT_11_0,
D3D11_FEATURE_LEVEL_HINT_11_1,
D3D11_FEATURE_LEVEL_HINT_12_0,
D3D11_FEATURE_LEVEL_HINT_12_1,
D3D11_FEATURE_LEVEL_HINT_12_2
};
bool d3d11_init_shader(
D3D11Device device,
const char* src,
@@ -2651,7 +2690,8 @@ bool d3d11_init_shader(
LPCSTR gs_entry,
const D3D11_INPUT_ELEMENT_DESC* input_element_descs,
UINT num_elements,
d3d11_shader_t* out);
d3d11_shader_t* out,
enum d3d11_feature_level_hint hint);
static INLINE void d3d11_release_shader(d3d11_shader_t* shader)
{
+104 -17
View File
@@ -174,7 +174,6 @@ bool d3d12_init_base(d3d12_video_t* d3d12)
#else
DXGICreateFactory(&d3d12->factory);
#endif
{
int i = 0;
settings_t *settings = config_get_ptr();
@@ -200,7 +199,6 @@ bool d3d12_init_base(d3d12_video_t* d3d12)
if (FAILED(DXGIEnumAdapters(d3d12->factory, i, &adapter)))
break;
#endif
IDXGIAdapter_GetDesc(adapter, &desc);
utf16_to_char_string((const uint16_t*)desc.Description, str, sizeof(str));
@@ -284,13 +282,30 @@ bool d3d12_init_swapchain(d3d12_video_t* d3d12,
{
unsigned i;
HRESULT hr;
HWND hwnd;
#ifdef __WINRT__
DXGI_SWAP_CHAIN_DESC1 desc;
memset(&desc, 0, sizeof(DXGI_SWAP_CHAIN_DESC1));
DXGI_SWAP_CHAIN_DESC1 desc = {{0}};
#else
DXGI_SWAP_CHAIN_DESC desc;
HWND hwnd = (HWND)corewindow;
memset(&desc, 0, sizeof(DXGI_SWAP_CHAIN_DESC));
DXGI_SWAP_CHAIN_DESC desc = {{0}};
#endif
#ifdef HAVE_DXGI_HDR
DXGI_COLOR_SPACE_TYPE color_space;
d3d12->chain.formats[DXGI_SWAPCHAIN_BIT_DEPTH_8] = DXGI_FORMAT_R8G8B8A8_UNORM;
d3d12->chain.formats[DXGI_SWAPCHAIN_BIT_DEPTH_10] = DXGI_FORMAT_R10G10B10A2_UNORM;
d3d12->chain.formats[DXGI_SWAPCHAIN_BIT_DEPTH_16] = DXGI_FORMAT_R16G16B16A16_UNORM;
#endif
hwnd = (HWND)corewindow;
#ifdef HAVE_DXGI_HDR
if (!(d3d12->hdr.support =
dxgi_check_display_hdr_support(d3d12->factory, hwnd)))
d3d12->hdr.enable = false;
d3d12->chain.bit_depth = d3d12->hdr.enable
? DXGI_SWAPCHAIN_BIT_DEPTH_10
: DXGI_SWAPCHAIN_BIT_DEPTH_8;
#endif
desc.BufferCount = countof(d3d12->chain.renderTargets);
@@ -298,24 +313,37 @@ bool d3d12_init_swapchain(d3d12_video_t* d3d12,
#ifdef __WINRT__
desc.Width = width;
desc.Height = height;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
#else
desc.BufferDesc.Width = width;
desc.BufferDesc.Height = height;
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.BufferDesc.RefreshRate.Numerator = 0;
desc.BufferDesc.RefreshRate.Denominator = 1;
#endif
#ifdef HAVE_DXGI_HDR
#ifdef __WINRT__
desc.Format = d3d12->chain.formats[d3d12->chain.bit_depth];
#else
desc.BufferDesc.Format = d3d12->chain.formats[d3d12->chain.bit_depth];
#endif
#else
#ifdef __WINRT__
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
#else
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
#endif
#endif
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
#ifdef HAVE_WINDOW
desc.OutputWindow = hwnd;
desc.Windowed = TRUE;
desc.OutputWindow = hwnd;
desc.Windowed = TRUE;
#endif
#if 0
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
#else
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
#endif
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
@@ -334,6 +362,34 @@ bool d3d12_init_swapchain(d3d12_video_t* d3d12,
DXGIMakeWindowAssociation(d3d12->factory, hwnd, DXGI_MWA_NO_ALT_ENTER);
#endif
#ifdef HAVE_DXGI_HDR
/* Check display HDR support and
initialize ST.2084 support to match
the display's support. */
#if 0
d3d12->hdr.max_output_nits = 300.0f;
d3d12->hdr.min_output_nits = 0.001f;
d3d12->hdr.max_cll = 0.0f;
d3d12->hdr.max_fall = 0.0f;
#endif
color_space =
d3d12->hdr.enable
? DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
dxgi_swapchain_color_space(d3d12->chain.handle,
&d3d12->chain.color_space, color_space);
dxgi_set_hdr_metadata(
d3d12->chain.handle,
d3d12->hdr.support,
d3d12->chain.bit_depth,
d3d12->chain.color_space,
d3d12->hdr.max_output_nits,
d3d12->hdr.min_output_nits,
d3d12->hdr.max_cll,
d3d12->hdr.max_fall);
#endif
d3d12->chain.frame_index = DXGIGetCurrentBackBufferIndex(d3d12->chain.handle);
for (i = 0; i < countof(d3d12->chain.renderTargets); i++)
@@ -343,10 +399,28 @@ bool d3d12_init_swapchain(d3d12_video_t* d3d12,
d3d12->device, d3d12->chain.renderTargets[i], NULL, d3d12->chain.desc_handles[i]);
}
d3d12->chain.viewport.Width = width;
d3d12->chain.viewport.Height = height;
d3d12->chain.scissorRect.right = width;
d3d12->chain.scissorRect.bottom = height;
#ifdef HAVE_DXGI_HDR
memset(&d3d12->chain.back_buffer,
0, sizeof(d3d12->chain.back_buffer));
d3d12->chain.back_buffer.desc.Width = width;
d3d12->chain.back_buffer.desc.Height = height;
d3d12->chain.back_buffer.desc.Format =
DXGI_FORMAT_R8G8B8A8_UNORM;
d3d12->chain.back_buffer.desc.Flags =
D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
d3d12->chain.back_buffer.srv_heap =
&d3d12->desc.srv_heap;
d3d12->chain.back_buffer.rt_view.ptr =
d3d12->desc.rtv_heap.cpu.ptr
+ (countof(d3d12->chain.renderTargets))
* d3d12->desc.rtv_heap.stride;
d3d12_init_texture(d3d12->device, &d3d12->chain.back_buffer);
#endif
d3d12->chain.viewport.Width = width;
d3d12->chain.viewport.Height = height;
d3d12->chain.scissorRect.right = width;
d3d12->chain.scissorRect.bottom = height;
return true;
}
@@ -619,6 +693,19 @@ D3D12_RENDER_TARGET_BLEND_DESC d3d12_blend_enable_desc = {
D3D12_COLOR_WRITE_ENABLE_ALL,
};
D3D12_RENDER_TARGET_BLEND_DESC d3d12_blend_disable_desc = {
FALSE,
FALSE,
D3D12_BLEND_SRC_ALPHA,
D3D12_BLEND_INV_SRC_ALPHA,
D3D12_BLEND_OP_ADD,
D3D12_BLEND_SRC_ALPHA,
D3D12_BLEND_INV_SRC_ALPHA,
D3D12_BLEND_OP_ADD,
D3D12_LOGIC_OP_NOOP,
D3D12_COLOR_WRITE_ENABLE_ALL,
};
bool d3d12_init_pipeline(
D3D12Device device,
D3DBlob vs_code,
+26 -2
View File
@@ -1385,6 +1385,9 @@ typedef struct
{
DXGISwapChain handle;
D3D12Resource renderTargets[2];
#ifdef HAVE_DXGI_HDR
d3d12_texture_t back_buffer;
#endif
D3D12_CPU_DESCRIPTOR_HANDLE desc_handles[2];
D3D12_VIEWPORT viewport;
D3D12_RECT scissorRect;
@@ -1392,6 +1395,11 @@ typedef struct
int frame_index;
bool vsync;
unsigned swap_interval;
#ifdef HAVE_DXGI_HDR
enum dxgi_swapchain_bit_depth bit_depth;
DXGI_COLOR_SPACE_TYPE color_space;
DXGI_FORMAT formats[DXGI_SWAPCHAIN_BIT_DEPTH_COUNT];
#endif
} chain;
struct
@@ -1407,6 +1415,21 @@ typedef struct
int rotation;
} frame;
#ifdef HAVE_DXGI_HDR
struct
{
dxgi_hdr_uniform_t ubo_values;
D3D12Resource ubo;
D3D12_CONSTANT_BUFFER_VIEW_DESC ubo_view;
float max_output_nits;
float min_output_nits;
float max_cll;
float max_fall;
bool support;
bool enable;
} hdr;
#endif
struct
{
D3D12Resource vbo;
@@ -1490,19 +1513,20 @@ typedef enum {
ROOT_ID_SAMPLER_T,
ROOT_ID_UBO,
ROOT_ID_PC,
ROOT_ID_MAX,
ROOT_ID_MAX
} root_signature_parameter_index_t;
typedef enum {
CS_ROOT_ID_TEXTURE_T = 0,
CS_ROOT_ID_UAV_T,
CS_ROOT_ID_CONSTANTS,
CS_ROOT_ID_MAX,
CS_ROOT_ID_MAX
} compute_root_index_t;
RETRO_BEGIN_DECLS
extern D3D12_RENDER_TARGET_BLEND_DESC d3d12_blend_enable_desc;
extern D3D12_RENDER_TARGET_BLEND_DESC d3d12_blend_disable_desc;
bool d3d12_init_base(d3d12_video_t* d3d12);
+2 -1
View File
@@ -140,7 +140,8 @@ bool d3d_compile(const char* src, size_t size, LPCSTR src_name, LPCSTR entrypoin
{
if (error_msg)
{
RARCH_ERR("D3DCompile failed :\n%s\n", (const char*)D3DGetBufferPointer(error_msg));
const char* msg = (const char*)D3DGetBufferPointer(error_msg);
RARCH_ERR("D3DCompile failed :\n%s\n", msg); /* Place a breakpoint here, if you want, to see shader compilation issues */
Release(error_msg);
}
return false;
+302
View File
@@ -31,6 +31,21 @@
#include "../frontend/frontend_driver.h"
#include "win32_common.h"
const GUID DECLSPEC_SELECTANY libretro_IID_IDXGIOutput6 = { 0x068346e8,0xaaec,
0x4b84, {0xad,0xd7,0x13,0x7f,0x51,0x3f,0x77,0xa1 } };
#ifdef HAVE_DXGI_HDR
/* TODO/FIXME - globals */
static DXGI_HDR_METADATA_HDR10 g_hdr10_meta_data = {0};
typedef enum hdr_root_constants
{
HDR_ROOT_CONSTANTS_REFERENCE_WHITE_NITS = 0,
HDR_ROOT_CONSTANTS_DISPLAY_CURVE,
HDR_ROOT_CONSTANTS_COUNT
} hdr_root_constants_t;
#endif
#if defined(HAVE_DYNAMIC) && !defined(__WINRT__)
#include <dynamic/dylib.h>
@@ -347,3 +362,290 @@ DXGI_FORMAT glslang_format_to_dxgi(glslang_format fmt)
return DXGI_FORMAT_UNKNOWN;
}
#ifdef HAVE_DXGI_HDR
typedef struct display_chromaticities
{
float red_x;
float red_y;
float green_x;
float green_y;
float blue_x;
float blue_y;
float white_x;
float white_y;
} display_chromaticities_t;
inline static int dxgi_compute_intersection_area(
int ax1, int ay1, int ax2, int ay2,
int bx1, int by1, int bx2, int by2)
{
return max(0, min(ax2, bx2) -
max(ax1, bx1))
* max(0, min(ay2, by2) - max(ay1, by1));
}
#ifdef __WINRT__
bool dxgi_check_display_hdr_support(DXGIFactory2 factory, HWND hwnd)
#else
bool dxgi_check_display_hdr_support(DXGIFactory factory, HWND hwnd)
#endif
{
DXGIOutput6 output6 = NULL;
DXGIOutput best_output = NULL;
DXGIOutput current_output = NULL;
DXGIAdapter dxgi_adapter = NULL;
UINT i = 0;
bool supported = false;
float best_intersect_area = -1;
#ifdef __WINRT__
if (!DXGIIsCurrent2(factory))
{
if (FAILED(DXGICreateFactory2(&factory)))
{
RARCH_ERR("[DXGI]: Failed to create DXGI factory\n");
return false;
}
}
if (FAILED(DXGIEnumAdapters2(factory, 0, &dxgi_adapter)))
{
RARCH_ERR("[DXGI]: Failed to enumerate adapters\n");
return false;
}
#else
if (!DXGIIsCurrent(factory))
{
if (FAILED(DXGICreateFactory(&factory)))
{
RARCH_ERR("[DXGI]: Failed to create DXGI factory\n");
return false;
}
}
if (FAILED(DXGIEnumAdapters(factory, 0, &dxgi_adapter)))
{
RARCH_ERR("[DXGI]: Failed to enumerate adapters\n");
return false;
}
#endif
while ( DXGIEnumOutputs(dxgi_adapter, i, &current_output)
!= DXGI_ERROR_NOT_FOUND)
{
RECT r, rect;
DXGI_OUTPUT_DESC desc;
int intersect_area;
int bx1, by1, bx2, by2;
int ax1 = 0;
int ay1 = 0;
int ax2 = 0;
int ay2 = 0;
if (win32_get_client_rect(&rect))
{
ax1 = rect.left;
ay1 = rect.top;
ax2 = rect.right;
ay2 = rect.bottom;
}
/* Get the rectangle bounds of current output */
if (FAILED(DXGIGetOutputDesc(current_output, &desc)))
{
RARCH_ERR("[DXGI]: Failed to get DXGI output description\n");
goto error;
}
/* TODO/FIXME - DesktopCoordinates won't work for WinRT */
r = desc.DesktopCoordinates;
bx1 = r.left;
by1 = r.top;
bx2 = r.right;
by2 = r.bottom;
/* Compute the intersection */
intersect_area = dxgi_compute_intersection_area(
ax1, ay1, ax2, ay2, bx1, by1, bx2, by2);
if (intersect_area > best_intersect_area)
{
best_output = current_output;
AddRef(best_output);
best_intersect_area = (float)intersect_area;
}
i++;
}
if (SUCCEEDED(best_output->lpVtbl->QueryInterface(
best_output,
&libretro_IID_IDXGIOutput6, (void**)&output6)))
{
DXGI_OUTPUT_DESC1 desc1;
if (SUCCEEDED(DXGIGetOutputDesc1(output6, &desc1)))
{
supported = (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
if (supported)
video_driver_set_hdr_support();
else
{
settings_t* settings = config_get_ptr();
settings->modified = true;
settings->bools.video_hdr_enable = false;
video_driver_unset_hdr_support();
}
}
else
{
RARCH_ERR("[DXGI]: Failed to get DXGI Output 6 description\n");
}
Release(output6);
}
else
{
RARCH_ERR("[DXGI]: Failed to get DXGI Output 6 from best output\n");
}
error:
Release(best_output);
Release(current_output);
Release(dxgi_adapter);
return supported;
}
void dxgi_swapchain_color_space(
DXGISwapChain chain_handle,
DXGI_COLOR_SPACE_TYPE *chain_color_space,
DXGI_COLOR_SPACE_TYPE color_space)
{
if (*chain_color_space != color_space)
{
UINT color_space_support = 0;
if (SUCCEEDED(DXGICheckColorSpaceSupport(
chain_handle, color_space,
&color_space_support))
&& ((color_space_support &
DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)
== DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
{
if (FAILED(DXGISetColorSpace1(chain_handle, color_space)))
{
RARCH_ERR("[DXGI]: Failed to set DXGI swapchain colour space\n");
/* TODO/FIXME/CLARIFICATION: Was this fall-through intentional?
* Should chain color space still be set even when this fails?
* Going to assume this was wrong and early return instead
*/
return;
}
*chain_color_space = color_space;
}
}
}
void dxgi_set_hdr_metadata(
DXGISwapChain handle,
bool hdr_supported,
enum dxgi_swapchain_bit_depth chain_bit_depth,
DXGI_COLOR_SPACE_TYPE chain_color_space,
float max_output_nits,
float min_output_nits,
float max_cll,
float max_fall
)
{
static const display_chromaticities_t
display_chromaticity_list[] =
{
{ 0.64000f, 0.33000f, 0.30000f, 0.60000f, 0.15000f, 0.06000f, 0.31270f, 0.32900f }, /* Rec709 */
{ 0.70800f, 0.29200f, 0.17000f, 0.79700f, 0.13100f, 0.04600f, 0.31270f, 0.32900f }, /* Rec2020 */
};
const display_chromaticities_t* chroma = NULL;
DXGI_HDR_METADATA_HDR10 hdr10_meta_data = {0};
int selected_chroma = 0;
if (!handle)
return;
/* Clear the hdr meta data if the monitor does not support HDR */
if (!hdr_supported)
{
if (FAILED(DXGISetHDRMetaData(handle,
DXGI_HDR_METADATA_TYPE_NONE, 0, NULL)))
{
RARCH_ERR("[DXGI]: Failed to set HDR meta data to none\n");
}
return;
}
/* Now select the chromacity based on colour space */
if ( chain_bit_depth == DXGI_SWAPCHAIN_BIT_DEPTH_10
&& chain_color_space ==
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
selected_chroma = 1;
else
{
if (FAILED(DXGISetHDRMetaData(handle,
DXGI_HDR_METADATA_TYPE_NONE, 0, NULL)))
{
RARCH_ERR("[DXGI]: Failed to set HDR meta data to none\n");
}
return;
}
/* Set the HDR meta data */
chroma =
&display_chromaticity_list[selected_chroma];
hdr10_meta_data.RedPrimary[0] =
(UINT16)(chroma->red_x * 50000.0f);
hdr10_meta_data.RedPrimary[1] =
(UINT16)(chroma->red_y * 50000.0f);
hdr10_meta_data.GreenPrimary[0] =
(UINT16)(chroma->green_x * 50000.0f);
hdr10_meta_data.GreenPrimary[1] =
(UINT16)(chroma->green_y * 50000.0f);
hdr10_meta_data.BluePrimary[0] =
(UINT16)(chroma->blue_x * 50000.0f);
hdr10_meta_data.BluePrimary[1] =
(UINT16)(chroma->blue_y * 50000.0f);
hdr10_meta_data.WhitePoint[0] =
(UINT16)(chroma->white_x * 50000.0f);
hdr10_meta_data.WhitePoint[1] =
(UINT16)(chroma->white_y * 50000.0f);
hdr10_meta_data.MaxMasteringLuminance =
(UINT)(max_output_nits * 10000.0f);
hdr10_meta_data.MinMasteringLuminance =
(UINT)(min_output_nits * 10000.0f);
hdr10_meta_data.MaxContentLightLevel =
(UINT16)(max_cll);
hdr10_meta_data.MaxFrameAverageLightLevel =
(UINT16)(max_fall);
if(g_hdr10_meta_data.RedPrimary != hdr10_meta_data.RedPrimary ||
g_hdr10_meta_data.GreenPrimary != hdr10_meta_data.GreenPrimary ||
g_hdr10_meta_data.BluePrimary != hdr10_meta_data.BluePrimary ||
g_hdr10_meta_data.WhitePoint != hdr10_meta_data.WhitePoint ||
g_hdr10_meta_data.MaxContentLightLevel != hdr10_meta_data.MaxContentLightLevel ||
g_hdr10_meta_data.MaxMasteringLuminance != hdr10_meta_data.MaxMasteringLuminance ||
g_hdr10_meta_data.MinMasteringLuminance != hdr10_meta_data.MinMasteringLuminance ||
g_hdr10_meta_data.MaxFrameAverageLightLevel != hdr10_meta_data.MaxFrameAverageLightLevel)
{
if (FAILED(DXGISetHDRMetaData(handle,
DXGI_HDR_METADATA_TYPE_HDR10,
sizeof(DXGI_HDR_METADATA_HDR10), &hdr10_meta_data)))
{
RARCH_ERR("[DXGI]: Failed to set HDR meta data for HDR10\n");
return;
}
g_hdr10_meta_data = hdr10_meta_data;
}
}
#endif
+75 -4
View File
@@ -2,6 +2,39 @@
#include <retro_inline.h>
#ifndef HAVE_DXGI_HDR
#define HAVE_DXGI_HDR
#endif
#ifdef HAVE_DXGI_HDR
#ifndef ALIGN
#ifdef _MSC_VER
#define ALIGN(x) __declspec(align(x))
#else
#define ALIGN(x) __attribute__((aligned(x)))
#endif
#endif
#include <gfx/math/matrix_4x4.h>
typedef struct ALIGN(16)
{
math_matrix_4x4 mvp;
float contrast; /* 2.0f */
float paperWhiteNits; /* 200.0f */
float maxNits; /* 1000.0f */
float expandGamut; /* 1.0f */
} dxgi_hdr_uniform_t;
enum dxgi_swapchain_bit_depth
{
DXGI_SWAPCHAIN_BIT_DEPTH_8 = 0,
DXGI_SWAPCHAIN_BIT_DEPTH_10,
DXGI_SWAPCHAIN_BIT_DEPTH_16,
DXGI_SWAPCHAIN_BIT_DEPTH_COUNT
};
#endif
#ifdef __MINGW32__
#define __REQUIRED_RPCNDR_H_VERSION__ 475
/* Pointer parameters */
@@ -233,7 +266,7 @@
#endif
#include <assert.h>
#include <dxgi1_5.h>
#include <dxgi1_6.h>
#ifndef countof
#define countof(a) (sizeof(a) / sizeof(*a))
@@ -281,6 +314,7 @@ typedef IDXGIResource* DXGIResource;
typedef IDXGIKeyedMutex* DXGIKeyedMutex;
typedef IDXGISurface1* DXGISurface;
typedef IDXGIOutput* DXGIOutput;
typedef IDXGIOutput6* DXGIOutput6;
typedef IDXGIDevice* DXGIDevice;
typedef IDXGIFactory1* DXGIFactory;
#ifdef __WINRT__
@@ -292,7 +326,7 @@ typedef IDXGIOutputDuplication* DXGIOutputDuplication;
typedef IDXGIDecodeSwapChain* DXGIDecodeSwapChain;
typedef IDXGIFactoryMedia* DXGIFactoryMedia;
typedef IDXGISwapChainMedia* DXGISwapChainMedia;
typedef IDXGISwapChain3* DXGISwapChain;
typedef IDXGISwapChain4* DXGISwapChain;
#if !defined(__cplusplus) || defined(CINTERFACE)
static INLINE ULONG DXGIReleaseDeviceSubObject(DXGIDeviceSubObject device_sub_object)
@@ -392,6 +426,14 @@ static INLINE HRESULT DXGIGetDisplaySurfaceData(DXGIOutput output, DXGISurface d
{
return output->lpVtbl->GetDisplaySurfaceData(output, (IDXGISurface*)destination);
}
static INLINE HRESULT DXGIGetOutputDesc(DXGIOutput output, DXGI_OUTPUT_DESC* desc)
{
return output->lpVtbl->GetDesc(output, desc);
}
static INLINE HRESULT DXGIGetOutputDesc1(DXGIOutput6 output, DXGI_OUTPUT_DESC1* desc)
{
return output->lpVtbl->GetDesc1(output, desc);
}
static INLINE ULONG DXGIReleaseDevice(DXGIDevice device) { return device->lpVtbl->Release(device); }
static INLINE HRESULT DXGICreateSurface(
DXGIDevice device,
@@ -457,6 +499,12 @@ static INLINE BOOL DXGIIsCurrent(DXGIFactory factory)
{
return factory->lpVtbl->IsCurrent(factory);
}
#ifdef __WINRT__
static INLINE BOOL DXGIIsCurrent2(DXGIFactory2 factory)
{
return factory->lpVtbl->IsCurrent(factory);
}
#endif
static INLINE ULONG DXGIReleaseAdapter(DXGIAdapter adapter)
{
return adapter->lpVtbl->Release(adapter);
@@ -769,11 +817,14 @@ static INLINE HRESULT DXGICheckColorSpaceSupport(
{
return swap_chain->lpVtbl->CheckColorSpaceSupport(swap_chain, color_space, color_space_support);
}
static INLINE HRESULT
DXGISetColorSpace1(DXGISwapChain swap_chain, DXGI_COLOR_SPACE_TYPE color_space)
static INLINE HRESULT DXGISetColorSpace1(DXGISwapChain swap_chain, DXGI_COLOR_SPACE_TYPE color_space)
{
return swap_chain->lpVtbl->SetColorSpace1(swap_chain, color_space);
}
static INLINE HRESULT DXGISetHDRMetaData(DXGISwapChain swap_chain, DXGI_HDR_METADATA_TYPE type, UINT size, void *metaData)
{
return swap_chain->lpVtbl->SetHDRMetaData(swap_chain, type, size, metaData);
}
#endif
/* end of auto-generated */
@@ -821,6 +872,26 @@ void dxgi_copy(
int dst_pitch,
void* dst_data);
#ifdef HAVE_DXGI_HDR
#ifdef __WINRT__
bool dxgi_check_display_hdr_support(DXGIFactory2 factory, HWND hwnd);
#else
bool dxgi_check_display_hdr_support(DXGIFactory factory, HWND hwnd);
#endif
void dxgi_swapchain_color_space(DXGISwapChain handle, DXGI_COLOR_SPACE_TYPE
*chain_color_space, DXGI_COLOR_SPACE_TYPE color_space);
void dxgi_set_hdr_metadata(
DXGISwapChain handle,
bool hdr_supported,
enum dxgi_swapchain_bit_depth chain_bit_depth,
DXGI_COLOR_SPACE_TYPE chain_color_space,
float max_output_nits,
float min_output_nits,
float max_cll,
float max_fall
);
#endif
DXGI_FORMAT glslang_format_to_dxgi(glslang_format fmt);
RETRO_END_DECLS
+11
View File
@@ -932,6 +932,12 @@ static LRESULT CALLBACK wnd_proc_common(
/* fall-through */
case WM_MOVE:
win32_save_position();
#if 0
#if !defined(_XBOX)
if(d3d12)
d3d12_check_display_hdr_support(d3d12, hwnd);
#endif
#endif
break;
case WM_SIZE:
/* Do not send resize message if we minimize. */
@@ -2345,6 +2351,11 @@ HWND win32_get_window(void)
#endif
}
bool win32_get_client_rect(RECT* rect)
{
return GetWindowRect(main_window.hwnd, &rect);
}
void win32_window_reset(void)
{
win32_common_state_t
+2
View File
@@ -97,6 +97,8 @@ void win32_show_cursor(void *data, bool state);
HWND win32_get_window(void);
bool win32_get_client_rect(RECT* rect);
bool is_running_on_xbox(void);
bool win32_has_focus(void *data);
+2 -2
View File
@@ -277,7 +277,7 @@ float x11_get_refresh_rate(void *data)
static bool get_video_mode(
Display *dpy, unsigned width, unsigned height,
XF86VidModeModeInfo *mode, XF86VidModeModeInfo *desktop_mode)
XF86VidModeModeInfo *mode, XF86VidModeModeInfo *x11_desktop_mode)
{
int i, num_modes = 0;
bool ret = false;
@@ -296,7 +296,7 @@ static bool get_video_mode(
return false;
}
*desktop_mode = *modes[0];
*x11_desktop_mode = *modes[0];
/* If we use black frame insertion, we fake a 60 Hz monitor
* for 120 Hz one, etc, so try to match that. */
+4
View File
@@ -270,6 +270,10 @@ static const video_poke_interface_t caca_poke_interface = {
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void caca_gfx_get_poke_interface(void *data,
+686 -55
View File
@@ -50,6 +50,16 @@
#include "../../tasks/tasks_internal.h"
#endif
enum
{
CTR_TEXTURE_BOTTOM_MENU,
CTR_TEXTURE_STATE_THUMBNAIL,
CTR_TEXTURE_LAST
};
/* TODO/FIXME - global referenced outside */
extern uint64_t lifecycle_state;
/* An annoyance...
* Have to keep track of bottom screen enable state
* externally, otherwise cannot detect current state
@@ -244,6 +254,551 @@ static void ctr_update_viewport(
}
static const char *ctr_texture_path(unsigned id)
{
switch (id)
{
case CTR_TEXTURE_BOTTOM_MENU:
return "ctr/bottom_menu.png";
case CTR_TEXTURE_STATE_THUMBNAIL:
{
static char texture_path[PATH_MAX_LENGTH];
char state_path[PATH_MAX_LENGTH];
if (!retroarch_get_current_savestate_path(state_path,
sizeof(state_path)))
return NULL;
snprintf(texture_path, sizeof(texture_path),
"%s.png", state_path);
return path_basename(texture_path);
}
}
return NULL;
}
static void ctr_update_state_date(void *data)
{
ctr_video_t *ctr = (ctr_video_t*)data;
time_t now = time(NULL);
struct tm *t = localtime(&now);
sprintf(ctr->state_date, "%02d/%02d/%d",
t->tm_mon + 1, t->tm_mday, t->tm_year + 1900);
}
static bool ctr_update_state_date_from_file(void *data)
{
char state_path[PATH_MAX_LENGTH];
ctr_video_t *ctr = (ctr_video_t*)data;
if (!retroarch_get_current_savestate_path(state_path, sizeof(state_path)))
return false;
#ifdef USE_CTRULIB_2
time_t mtime;
bool file_exists = archive_getmtime(state_path + 5, &mtime) == 0;
#else
u64 mtime;
bool file_exists = sdmc_getmtime(state_path + 5, &mtime) == 0;
#endif
if (!file_exists)
{
ctr->state_data_exist = false;
snprintf(ctr->state_date, sizeof(ctr->state_date), "00/00/0000");
return false;
}
ctr->state_data_exist = true;
#ifdef USE_CTRULIB_2
struct tm *t = localtime(&mtime);
#else
time_t ft = mtime;
struct tm *t = localtime(&ft);
#endif
sprintf(ctr->state_date, "%02d/%02d/%d",
t->tm_mon + 1, t->tm_mday, t->tm_year + 1900);
return true;
}
static void ctr_state_thumbnail_geom(void *data)
{
ctr_video_t *ctr = (ctr_video_t *) data;
struct ctr_bottom_texture_data *o = NULL;
const int target_width = 120;
const int target_height = 90;
unsigned width, height;
if (ctr)
o = &ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
if (!o)
return;
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
if (!texture)
return;
float scale = (float) target_width / texture->active_width;
if (target_width > texture->active_width * scale) {
scale = (float) (target_width + 1) / texture->active_width;
}
o->frame_coords->u0 = 0;
o->frame_coords->v0 = 0;
o->frame_coords->u1 = texture->active_width;
o->frame_coords->v1 = texture->active_height;
int x_offset = 184;
int y_offset = 46 + (target_height - texture->active_height * scale) / 2;
o->frame_coords->x0 = x_offset;
o->frame_coords->y0 = y_offset;
o->frame_coords->x1 = o->frame_coords->x0 + texture->active_width * scale;
o->frame_coords->y1 = o->frame_coords->y0 + texture->active_height * scale;
ctr_set_scale_vector(&o->scale_vector,
CTR_BOTTOM_FRAMEBUFFER_WIDTH,
CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
texture->width,
texture->height);
}
static bool ctr_load_bottom_texture(void *data)
{
unsigned i;
const char *dir_assets;
ctr_video_t *ctr = (ctr_video_t *)data;
settings_t *settings = config_get_ptr();
for (i = 0; i < CTR_TEXTURE_LAST; i++)
{
if (i == CTR_TEXTURE_STATE_THUMBNAIL)
dir_assets = dir_get_ptr(RARCH_DIR_SAVESTATE);
else
dir_assets = settings->paths.directory_assets;
if (gfx_display_reset_textures_list(
ctr_texture_path(i), dir_assets,
&ctr->bottom_textures[i].texture,
TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
{
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[i];
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
if (i == CTR_TEXTURE_STATE_THUMBNAIL)
{
ctr_state_thumbnail_geom(ctr);
ctr->render_state_from_png_file = true;
}
else
{
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
o->frame_coords->u0 = 0;
o->frame_coords->v0 = 0;
o->frame_coords->u1 = texture->width;
o->frame_coords->v1 = texture->height;
o->frame_coords->x0 = 0;
o->frame_coords->y0 = 0;
o->frame_coords->x1 = o->frame_coords->x0 + texture->width;
o->frame_coords->y1 = o->frame_coords->y0 + texture->height;
ctr_set_scale_vector(&o->scale_vector,
CTR_BOTTOM_FRAMEBUFFER_WIDTH,
CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
texture->width,
texture->height);
}
}
else if (i == CTR_TEXTURE_BOTTOM_MENU)
return false;
}
return true;
}
static void save_state_to_file(void *data)
{
ctr_video_t *ctr = (ctr_video_t*)data;
char state_path[PATH_MAX_LENGTH];
global_t *global = global_get_ptr();
const char *name_savestate = global->name.savestate;
if (ctr->state_slot > 0)
snprintf(state_path, sizeof(state_path), "%s%d", name_savestate,
ctr->state_slot);
else if (ctr->state_slot < 0)
fill_pathname_join_delim(state_path,
name_savestate, "auto", '.', sizeof(state_path));
else
strlcpy(state_path, name_savestate, sizeof(state_path));
command_event(CMD_EVENT_RAM_STATE_TO_FILE, state_path);
}
static void bottom_menu_control(void* data, bool lcd_bottom)
{
touchPosition state_tmp_touch;
uint32_t state_tmp = 0;
ctr_video_t *ctr = (ctr_video_t*)data;
settings_t *settings = config_get_ptr();
int config_slot = settings->ints.state_slot;
if (!ctr->init_bottom_menu)
{
if (ctr_load_bottom_texture(ctr))
{
ctr_update_state_date_from_file(ctr);
ctr->bottom_menu = CTR_BOTTOM_MENU_DEFAULT;
}
ctr->init_bottom_menu = true;
}
BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE);
state_tmp = hidKeysDown();
hidTouchRead(&state_tmp_touch);
if (state_tmp & KEY_TOUCH)
{
#ifdef CONSOLE_LOG
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
return;
#endif
if (!rarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
return;
if (!lcd_bottom ||
ctr->bottom_menu == CTR_BOTTOM_MENU_NOT_AVAILABLE)
{
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
return;
}
switch (ctr->bottom_menu)
{
case CTR_BOTTOM_MENU_DEFAULT:
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
break;
case CTR_BOTTOM_MENU_SELECT:
if (state_tmp_touch.px > 8 &&
state_tmp_touch.px < 164 &&
state_tmp_touch.py > 9 &&
state_tmp_touch.py < 86)
{
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
}
else if (state_tmp_touch.px > 8 &&
state_tmp_touch.px < 164 &&
state_tmp_touch.py > 99 &&
state_tmp_touch.py < 230)
{
char screenshot_full_path[PATH_MAX_LENGTH];
struct ctr_bottom_texture_data *o =
&ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
if (texture)
linearFree(texture->data);
else
{
o->texture = (uintptr_t) calloc(1, sizeof(ctr_texture_t));
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
texture = (ctr_texture_t *) o->texture;
}
texture->width = ctr->texture_width;
texture->height = ctr->texture_width;
texture->active_width = ctr->frame_coords->u1;
texture->active_height = ctr->frame_coords->v1;
texture->data = linearAlloc(
ctr->texture_width * ctr->texture_height *
(ctr->rgb32? 4:2));
memcpy(texture->data, ctr->texture_swizzled,
ctr->texture_width * ctr->texture_height *
(ctr->rgb32? 4:2));
ctr_state_thumbnail_geom(ctr);
ctr->state_data_exist = true;
ctr->state_data_on_ram = true;
ctr->render_state_from_png_file = false;
ctr_update_state_date(ctr);
command_event(CMD_EVENT_SAVE_STATE_TO_RAM, NULL);
if (settings->bools.savestate_thumbnail_enable)
{
sprintf(screenshot_full_path, "%s/%s",
dir_get_ptr(RARCH_DIR_SAVESTATE),
ctr_texture_path(CTR_TEXTURE_STATE_THUMBNAIL));
take_screenshot(NULL, screenshot_full_path, true,
video_driver_cached_frame_has_valid_framebuffer(),
true, true);
}
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
}
else if (state_tmp_touch.px > 176 &&
state_tmp_touch.px < 311 &&
state_tmp_touch.py > 9 &&
state_tmp_touch.py < 230 &&
ctr->state_data_exist)
{
if (ctr->state_data_on_ram)
command_event(CMD_EVENT_LOAD_STATE_FROM_RAM, NULL);
else
command_event(CMD_EVENT_LOAD_STATE, NULL);
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
}
break;
}
ctr->refresh_bottom_menu = true;
}
if (ctr->bottom_menu == CTR_BOTTOM_MENU_NOT_AVAILABLE ||
!rarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
return;
if (ctr->state_slot != config_slot)
{
if (ctr->state_data_on_ram)
{
save_state_to_file(ctr);
ctr->state_data_on_ram = false;
}
ctr->state_slot = config_slot;
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
if (texture)
{
linearFree(texture->data);
linearFree(o->frame_coords);
o->texture = 0;
}
if (ctr_update_state_date_from_file(ctr))
{
if(gfx_display_reset_textures_list(
ctr_texture_path(CTR_TEXTURE_STATE_THUMBNAIL),
dir_get_ptr(RARCH_DIR_SAVESTATE),
&o->texture,
TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
{
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
ctr_state_thumbnail_geom(ctr);
ctr->render_state_from_png_file = true;
}
}
ctr->refresh_bottom_menu = true;
}
if (menu_driver_is_alive())
ctr->bottom_menu = CTR_BOTTOM_MENU_SELECT;
else
ctr->bottom_menu = CTR_BOTTOM_MENU_DEFAULT;
if (ctr->prev_bottom_menu != ctr->bottom_menu)
{
ctr->prev_bottom_menu = ctr->bottom_menu;
ctr->refresh_bottom_menu = true;
}
}
static void font_driver_render_msg_bottom(
void *data,
const char *msg,
const void *_params,
void *font_data)
{
ctr_video_t *ctr = (ctr_video_t*)data;
ctr->render_font_bottom = true;
font_driver_render_msg(ctr, msg, _params, font_data);
ctr->render_font_bottom = false;
}
static void ctr_render_bottom_screen(void *data)
{
ctr_video_t *ctr = (ctr_video_t*)data;
if (!ctr)
return;
if (!ctr->refresh_bottom_menu)
return;
struct font_params params = { 0, };
params.text_align = TEXT_ALIGN_CENTER;
params.color = COLOR_ABGR(255, 255, 255, 255);
switch (ctr->bottom_menu)
{
case CTR_BOTTOM_MENU_NOT_AVAILABLE:
{
params.scale = 1.6f;
params.x = 0.0f;
params.y = 0.5f;
font_driver_render_msg_bottom(ctr,
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_ASSET_NOT_FOUND),
&params, NULL);
}
break;
case CTR_BOTTOM_MENU_DEFAULT:
{
params.scale = 1.6f;
params.x = 0.0f;
params.y = 0.5f;
font_driver_render_msg_bottom(ctr,
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_DEFAULT),
&params, NULL);
}
break;
case CTR_BOTTOM_MENU_SELECT:
{
params.scale = 1.48f;
params.color = COLOR_ABGR(255, 255, 255, 255);
/* draw state thumbnail */
if (ctr->state_data_exist) {
struct ctr_bottom_texture_data *o = (struct ctr_bottom_texture_data*)
&ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
if (texture)
{
GPU_TEXCOLOR colorType = GPU_RGBA8;
if (!ctr->render_state_from_png_file && !ctr->rgb32)
colorType = GPU_RGB565;
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(texture->data),
texture->width, texture->height,
GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
colorType);
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
ctrGuSetVertexShaderFloatUniform(0, (float*)&o->scale_vector, 1);
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(o->frame_coords));
GPU_SetViewport(NULL,
VIRT_TO_PHYS(ctr->drawbuffers.bottom),
0, 0, CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
CTR_BOTTOM_FRAMEBUFFER_WIDTH);
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
}
else
{
params.x = 0.266f;
params.y = 0.64f;
font_driver_render_msg_bottom(ctr,
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_NO_STATE_THUMBNAIL),
&params, NULL);
}
}
else
{
params.x = 0.266f;
params.y = 0.64f;
font_driver_render_msg_bottom(ctr,
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_NO_STATE_DATA),
&params, NULL);
}
/* draw bottom menu */
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[CTR_TEXTURE_BOTTOM_MENU];
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(texture->data),
texture->width, texture->height,
GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
GPU_RGBA8);
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
ctrGuSetVertexShaderFloatUniform(0, (float*)&o->scale_vector, 1);
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(o->frame_coords));
GPU_SetViewport(NULL,
VIRT_TO_PHYS(ctr->drawbuffers.bottom),
0, 0, CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
CTR_BOTTOM_FRAMEBUFFER_WIDTH);
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
/* draw resume game */
params.x = -0.178f;
params.y = 0.78f;
font_driver_render_msg_bottom(ctr,
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_RESUME),
&params, NULL);
/* draw create restore point */
params.x = -0.178f;
params.y = 0.33f;
font_driver_render_msg_bottom(ctr,
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_SAVE_STATE),
&params, NULL);
/* draw load restore point */
params.x = 0.266f;
params.y = 0.24f;
font_driver_render_msg_bottom(ctr,
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_LOAD_STATE),
&params, NULL);
/* draw date */
params.x = 0.266f;
params.y = 0.87f;
font_driver_render_msg_bottom(ctr, ctr->state_date,
&params, NULL);
}
break;
}
}
static void ctr_set_bottom_screen_enable(bool enabled)
{
Handle lcd_handle;
u8 not_2DS;
CFGU_GetModelNintendo2DS(&not_2DS);
if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = enabled? 0x00110040: 0x00120040;
cmdbuf[1] = 2;
svcSendSyncRequest(lcd_handle);
svcCloseHandle(lcd_handle);
}
ctr_bottom_screen_enabled = enabled;
}
static void ctr_lcd_aptHook(APT_HookType hook, void* param)
{
ctr_video_t *ctr = (ctr_video_t*)param;
@@ -303,16 +858,12 @@ static void ctr_lcd_aptHook(APT_HookType hook, void* param)
if ((hook == APTHOOK_ONSUSPEND) || (hook == APTHOOK_ONRESTORE) || (hook == APTHOOK_ONWAKEUP))
{
Handle lcd_handle;
u8 not_2DS;
CFGU_GetModelNintendo2DS(&not_2DS);
if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0)
ctr_set_bottom_screen_enable(hook == APTHOOK_ONSUSPEND);
if (ctr->state_data_on_ram)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = ((hook == APTHOOK_ONSUSPEND) || ctr_bottom_screen_enabled)? 0x00110040: 0x00120040;
cmdbuf[1] = 2;
svcSendSyncRequest(lcd_handle);
svcCloseHandle(lcd_handle);
save_state_to_file(ctr);
ctr->state_data_on_ram = false;
}
}
@@ -342,34 +893,11 @@ static bool ctr_tasks_finder(retro_task_t *task,void *userdata)
task_finder_data_t ctr_tasks_finder_data = {ctr_tasks_finder, NULL};
#endif
static void ctr_set_bottom_screen_enable(void* data, bool enabled)
{
Handle lcd_handle;
u8 not_2DS;
ctr_video_t *ctr = (ctr_video_t*)data;
if (!ctr)
return;
gfxBottomFramebuffers[0] = enabled ? (u8*)ctrConsole->frameBuffer:
(u8*)ctr->empty_framebuffer;
CFGU_GetModelNintendo2DS(&not_2DS);
if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = enabled? 0x00110040: 0x00120040;
cmdbuf[1] = 2;
svcSendSyncRequest(lcd_handle);
svcCloseHandle(lcd_handle);
}
ctr_bottom_screen_enabled = enabled;
}
static void* ctr_init(const video_info_t* video,
input_driver_t** input, void** input_data)
{
size_t i;
float refresh_rate;
u8 device_model = 0xFF;
void* ctrinput = NULL;
@@ -392,6 +920,7 @@ static void* ctr_init(const video_info_t* video,
ctr->drawbuffers.top.left = vramAlloc(CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * 2 * sizeof(uint32_t));
ctr->drawbuffers.top.right = (void*)((uint32_t*)ctr->drawbuffers.top.left + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT);
ctr->drawbuffers.bottom = vramAlloc(CTR_BOTTOM_FRAMEBUFFER_WIDTH * CTR_BOTTOM_FRAMEBUFFER_HEIGHT * 2 * sizeof(uint32_t));
ctr->display_list_size = 0x4000;
ctr->display_list = linearAlloc(ctr->display_list_size * sizeof(uint32_t));
@@ -401,6 +930,22 @@ static void* ctr_init(const video_info_t* video,
ctr->vertex_cache.buffer = linearAlloc(ctr->vertex_cache.size * sizeof(ctr_vertex_t));
ctr->vertex_cache.current = ctr->vertex_cache.buffer;
ctr->bottom_textures = (struct ctr_bottom_texture_data *)calloc(CTR_TEXTURE_LAST,
sizeof(*ctr->bottom_textures));
ctr->init_bottom_menu = false;
ctr->state_data_exist = false;
ctr->state_data_on_ram = false;
ctr->render_font_bottom = false;
ctr->refresh_bottom_menu = true;
ctr->render_state_from_png_file = false;
ctr->bottom_menu = CTR_BOTTOM_MENU_NOT_AVAILABLE;
ctr->prev_bottom_menu = CTR_BOTTOM_MENU_NOT_AVAILABLE;
ctr->state_slot = settings->ints.state_slot;
snprintf(ctr->state_date, sizeof(ctr->state_date), "%s", "00/00/0000");
ctr->state_date[CTR_STATE_DATE_SIZE - 1] = '\0';
ctr->rgb32 = video->rgb32;
ctr->texture_width = video->input_scale * RARCH_SCALE_BASE;
ctr->texture_height = video->input_scale * RARCH_SCALE_BASE;
@@ -512,6 +1057,7 @@ static void* ctr_init(const video_info_t* video,
ctr->smooth = video->smooth;
ctr->vsync = video->vsync;
ctr->current_buffer_top = 0;
ctr->current_buffer_bottom = 0;
/* Only O3DS and O3DSXL support running in 'dual-framebuffer'
* mode with the parallax barrier disabled
@@ -520,9 +1066,6 @@ static void* ctr_init(const video_info_t* video,
CFGU_GetSystemModel(&device_model); /* (0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL) */
ctr->supports_parallax_disable = (device_model == 0) || (device_model == 1);
ctr->empty_framebuffer = linearAlloc(320 * 240 * 2);
memset(ctr->empty_framebuffer, 0, 320 * 240 * 2);
refresh_rate = (32730.0 * 8192.0) / 4481134.0;
driver_ctl(RARCH_DRIVER_CTL_SET_REFRESH_RATE, &refresh_rate);
@@ -539,7 +1082,7 @@ static void* ctr_init(const video_info_t* video,
/* Set bottom screen enable state, if required */
if (lcd_bottom != ctr_bottom_screen_enabled)
ctr_set_bottom_screen_enable(ctr, lcd_bottom);
ctr_set_bottom_screen_enable(lcd_bottom);
gspSetEventCallback(GSPGPU_EVENT_VBlank0,
(ThreadFunc)ctr_vsync_hook, ctr, false);
@@ -557,12 +1100,10 @@ static bool ctr_frame(void* data, const void* frame,
unsigned pitch, const char* msg, video_frame_info_t *video_info)
{
static uint64_t currentTick,lastTick;
touchPosition state_tmp_touch;
extern GSPGPU_FramebufferInfo topFramebufferInfo;
extern GSPGPU_FramebufferInfo topFramebufferInfo, bottomFramebufferInfo;
extern u8* gfxSharedMemory;
extern u8 gfxThreadID;
uint32_t diff;
uint32_t state_tmp = 0;
ctr_video_t *ctr = (ctr_video_t*)data;
static float fps = 0.0;
static int total_frames = 0;
@@ -584,6 +1125,7 @@ static bool ctr_frame(void* data, const void* frame,
#ifdef HAVE_GFX_WIDGETS
bool widgets_active = video_info->widgets_active;
#endif
bool lcd_bottom = false;
if (!width || !height || !settings)
{
@@ -591,12 +1133,10 @@ static bool ctr_frame(void* data, const void* frame,
return true;
}
state_tmp = hidKeysDown();
hidTouchRead(&state_tmp_touch);
if((state_tmp & KEY_TOUCH) && (state_tmp_touch.py < 120))
{
ctr_set_bottom_screen_enable(ctr, !ctr_bottom_screen_enabled);
}
lcd_bottom = settings->bools.video_3ds_lcd_bottom;
if (lcd_bottom != ctr_bottom_screen_enabled)
ctr_set_bottom_screen_enable(lcd_bottom);
bottom_menu_control(data, lcd_bottom);
if (ctr->p3d_event_pending)
{
@@ -742,11 +1282,23 @@ static bool ctr_frame(void* data, const void* frame,
custom_vp_height
);
ctrGuSetMemoryFill(true, (u32*)ctr->drawbuffers.top.left, 0x00000000,
(u32*)ctr->drawbuffers.top.left + 2 * CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT,
0x201, NULL, 0x00000000,
0,
0x201);
if (ctr->refresh_bottom_menu)
{
ctrGuSetMemoryFill(true, (u32*)ctr->drawbuffers.top.left, 0x00000000,
(u32*)ctr->drawbuffers.top.left + 2 * CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT,
0x201,
(u32*)ctr->drawbuffers.bottom, 0x00000000,
(u32*)ctr->drawbuffers.bottom + 2 * CTR_BOTTOM_FRAMEBUFFER_WIDTH * CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
0x201);
}
else
{
ctrGuSetMemoryFill(true, (u32*)ctr->drawbuffers.top.left, 0x00000000,
(u32*)ctr->drawbuffers.top.left + 2 * CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT,
0x201, NULL, 0x00000000,
0,
0x201);
}
GPUCMD_SetBufferOffset(0);
@@ -923,6 +1475,12 @@ static bool ctr_frame(void* data, const void* frame,
gfx_widgets_frame(video_info);
#endif
#ifndef CONSOLE_LOG
if (ctr_bottom_screen_enabled &&
rarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
ctr_render_bottom_screen(ctr);
#endif
if (msg)
font_driver_render_msg(ctr, msg, NULL, NULL);
@@ -943,10 +1501,21 @@ static bool ctr_frame(void* data, const void* frame,
CTRGU_RGBA8,
gfxTopRightFramebuffers[ctr->current_buffer_top], 240, CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE);
#ifndef CONSOLE_LOG
ctrGuDisplayTransfer(true,
ctr->drawbuffers.bottom,
240,
320,
CTRGU_RGBA8,
gfxBottomFramebuffers[ctr->current_buffer_bottom],
240,
CTRGU_RGB8,
CTRGU_MULTISAMPLE_NONE);
#endif
/* Swap buffers : */
#ifdef USE_CTRULIB_2
u32 *buf0, *buf1;
u32 *buf0, *buf1, *bottom;
u32 stride;
buf0 = (u32*)gfxTopLeftFramebuffers[ctr->current_buffer_top];
@@ -970,6 +1539,16 @@ static bool ctr_frame(void* data, const void* frame,
gspPresentBuffer(GFX_TOP, ctr->current_buffer_top, buf0, buf1,
stride, (1<<8)|((1^bit5)<<6)|((bit5)<<5)|GSP_BGR8_OES);
#ifndef CONSOLE_LOG
if (ctr->refresh_bottom_menu)
{
bottom = (u32*)gfxBottomFramebuffers[ctr->current_buffer_bottom];
stride = 240 * 3;
gspPresentBuffer(GFX_BOTTOM, ctr->current_buffer_bottom, bottom, bottom,
stride, GSP_BGR8_OES);
}
#endif
#else
topFramebufferInfo.
active_framebuf = ctr->current_buffer_top;
@@ -990,7 +1569,7 @@ static bool ctr_frame(void* data, const void* frame,
framebuf1_vaddr = (u32*)gfxTopRightFramebuffers[ctr->current_buffer_top];
else
topFramebufferInfo.
framebuf1_vaddr = topFramebufferInfo.framebuf0_vaddr;
framebuf1_vaddr = topFramebufferInfo.framebuf0_vaddr;
topFramebufferInfo.
framebuf_widthbytesize = 240 * 3;
@@ -1008,11 +1587,43 @@ static bool ctr_frame(void* data, const void* frame,
framebufferInfoHeader[0x0] ^= 1;
framebufferInfo[framebufferInfoHeader[0x0]] = topFramebufferInfo;
framebufferInfoHeader[0x1] = 1;
#ifndef CONSOLE_LOG
if (ctr->refresh_bottom_menu)
{
bottomFramebufferInfo.
active_framebuf = ctr->current_buffer_bottom;
bottomFramebufferInfo.
framebuf0_vaddr = (u32*)gfxBottomFramebuffers[
ctr->current_buffer_bottom];
bottomFramebufferInfo.
framebuf1_vaddr = (u32*)(gfxBottomFramebuffers[
ctr->current_buffer_bottom] + 240 * 3);
bottomFramebufferInfo.
framebuf_widthbytesize = 240 * 3;
bottomFramebufferInfo.format = GSP_BGR8_OES;
bottomFramebufferInfo.
framebuf_dispselect = ctr->current_buffer_bottom;
bottomFramebufferInfo.unk = 0x00000000;
u8* framebufferInfoHeader2 = gfxSharedMemory+0x200+gfxThreadID*0x80+0x40;
GSPGPU_FramebufferInfo*
framebufferInfo2 =
(GSPGPU_FramebufferInfo*)&framebufferInfoHeader2[0x4];
framebufferInfoHeader2[0x0] ^= 1;
framebufferInfo2[framebufferInfoHeader2[0x0]] = bottomFramebufferInfo;
framebufferInfoHeader2[0x1] = 1;
}
#endif
#endif
ctr->current_buffer_top ^= 1;
ctr->current_buffer_bottom ^= 1;
ctr->p3d_event_pending = true;
ctr->ppf_event_pending = true;
ctr->refresh_bottom_menu = false;
return true;
}
@@ -1047,16 +1658,33 @@ static bool ctr_suppress_screensaver(void* data, bool enable)
static void ctr_free(void* data)
{
unsigned i;
ctr_video_t* ctr = (ctr_video_t*)data;
if (!ctr)
return;
if (ctr->state_data_on_ram)
save_state_to_file(ctr);
aptUnhook(&ctr->lcd_aptHook);
gspSetEventCallback(GSPGPU_EVENT_VBlank0, NULL, NULL, true);
shaderProgramFree(&ctr->shader);
DVLB_Free(ctr->dvlb);
vramFree(ctr->drawbuffers.top.left);
vramFree(ctr->drawbuffers.bottom);
for (i = 0; i < CTR_TEXTURE_LAST; i++)
{
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[i];
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
if (texture)
{
linearFree(texture->data);
linearFree(o->frame_coords);
o->texture = 0;
}
}
free(ctr->bottom_textures);
linearFree(ctr->display_list);
linearFree(ctr->texture_linear);
linearFree(ctr->texture_swizzled);
@@ -1064,7 +1692,6 @@ static void ctr_free(void* data)
linearFree(ctr->menu.texture_linear);
linearFree(ctr->menu.texture_swizzled);
linearFree(ctr->menu.frame_coords);
linearFree(ctr->empty_framebuffer);
linearFree(ctr->vertex_cache.buffer);
linearFree(ctr);
#if 0
@@ -1535,7 +2162,11 @@ static const video_poke_interface_t ctr_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void ctr_get_poke_interface(void* data,
+5 -1
View File
@@ -1008,7 +1008,7 @@ static void *d3d10_gfx_init(const video_info_t* video,
#else
DXGICreateFactory(&d3d10->factory);
#endif
{
int i = 0;
int gpu_index = settings->ints.d3d10_gpu_index;
@@ -1800,6 +1800,10 @@ static const video_poke_interface_t d3d10_poke_interface = {
#else
NULL, /* get_hw_render_interface */
#endif
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void d3d10_gfx_get_poke_interface(void* data, const video_poke_interface_t** iface)
+454 -39
View File
@@ -255,6 +255,79 @@ static void d3d11_get_overlay_interface(
}
#endif
#ifdef HAVE_DXGI_HDR
static void d3d11_set_hdr_max_nits(void *data, float max_nits)
{
D3D11_MAPPED_SUBRESOURCE mapped_ubo;
d3d11_video_t* d3d11 = (d3d11_video_t*)data;
d3d11->hdr.max_output_nits = max_nits;
d3d11->hdr.ubo_values.maxNits = max_nits;
D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo,
0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mapped_ubo);
{
dxgi_hdr_uniform_t *ubo = (dxgi_hdr_uniform_t*)mapped_ubo.pData;
*ubo = d3d11->hdr.ubo_values;
}
D3D11UnmapBuffer(d3d11->context, d3d11->hdr.ubo, 0);
dxgi_set_hdr_metadata(
d3d11->swapChain,
d3d11->hdr.support,
d3d11->chain_bit_depth,
d3d11->chain_color_space,
d3d11->hdr.max_output_nits,
d3d11->hdr.min_output_nits,
d3d11->hdr.max_cll,
d3d11->hdr.max_fall);
}
static void d3d11_set_hdr_paper_white_nits(void* data, float paper_white_nits)
{
D3D11_MAPPED_SUBRESOURCE mapped_ubo;
dxgi_hdr_uniform_t *ubo = NULL;
d3d11_video_t *d3d11 = (d3d11_video_t*)data;
d3d11->hdr.ubo_values.paperWhiteNits = paper_white_nits;
D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo,
0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo);
ubo = (dxgi_hdr_uniform_t*)mapped_ubo.pData;
*ubo = d3d11->hdr.ubo_values;
D3D11UnmapBuffer(d3d11->context, d3d11->hdr.ubo, 0);
}
static void d3d11_set_hdr_contrast(void* data, float contrast)
{
D3D11_MAPPED_SUBRESOURCE mapped_ubo;
dxgi_hdr_uniform_t *ubo = NULL;
d3d11_video_t* d3d11 = (d3d11_video_t*)data;
d3d11->hdr.ubo_values.contrast = contrast;
D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo,
0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo);
ubo = (dxgi_hdr_uniform_t*)mapped_ubo.pData;
*ubo = d3d11->hdr.ubo_values;
D3D11UnmapBuffer(d3d11->context, d3d11->hdr.ubo, 0);
}
static void d3d11_set_hdr_expand_gamut(void* data, bool expand_gamut)
{
D3D11_MAPPED_SUBRESOURCE mapped_ubo;
dxgi_hdr_uniform_t *ubo = NULL;
d3d11_video_t* d3d11 = (d3d11_video_t*)data;
d3d11->hdr.ubo_values.expandGamut = expand_gamut;
D3D11MapBuffer(d3d11->context, d3d11->hdr.ubo, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo);
ubo = (dxgi_hdr_uniform_t*)mapped_ubo.pData;
*ubo = d3d11->hdr.ubo_values;
D3D11UnmapBuffer(d3d11->context, d3d11->hdr.ubo, 0);
}
#endif
static void d3d11_set_filtering(void* data, unsigned index,
bool smooth, bool ctx_scaling)
{
@@ -360,13 +433,39 @@ static void d3d11_free_shader_preset(d3d11_video_t* d3d11)
static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const char* path)
{
#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
enum d3d11_feature_level_hint
feat_level_hint = D3D11_FEATURE_LEVEL_HINT_DONTCARE;
unsigned i;
d3d11_texture_t* source = NULL;
d3d11_video_t* d3d11 = (d3d11_video_t*)data;
unsigned shader_model = 40;
if (!d3d11)
return false;
/* Feature Level 11.0 and up should all support Shader Model 5.0 */
switch (d3d11->supportedFeatureLevel)
{
case D3D_FEATURE_LEVEL_11_0:
shader_model = 50;
feat_level_hint = D3D11_FEATURE_LEVEL_HINT_11_0;
break;
case D3D_FEATURE_LEVEL_11_1:
shader_model = 50;
feat_level_hint = D3D11_FEATURE_LEVEL_HINT_11_1;
break;
case D3D_FEATURE_LEVEL_12_0:
shader_model = 50;
feat_level_hint = D3D11_FEATURE_LEVEL_HINT_12_0;
break;
case D3D_FEATURE_LEVEL_12_1:
shader_model = 50;
feat_level_hint = D3D11_FEATURE_LEVEL_HINT_12_1;
break;
default:
break;
}
D3D11Flush(d3d11->context);
d3d11_free_shader_preset(d3d11);
@@ -426,7 +525,8 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const
/* clang-format on */
if (!slang_process(
d3d11->shader_preset, i, RARCH_SHADER_HLSL, 40, &semantics_map,
d3d11->shader_preset, i, RARCH_SHADER_HLSL, shader_model,
&semantics_map,
&d3d11->pass[i].semantics))
goto error;
@@ -457,12 +557,16 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const
if (!d3d11_init_shader(
d3d11->device, vs_src, 0, vs_path, "main", NULL, NULL, desc, countof(desc),
&d3d11->pass[i].shader))
&d3d11->pass[i].shader,
feat_level_hint
))
save_hlsl = true;
if (!d3d11_init_shader(
d3d11->device, ps_src, 0, ps_path, NULL, "main", NULL, NULL, 0,
&d3d11->pass[i].shader))
&d3d11->pass[i].shader,
feat_level_hint
))
save_hlsl = true;
if (save_hlsl)
@@ -559,6 +663,10 @@ static void d3d11_gfx_free(void* data)
d3d11_release_texture(&d3d11->menu.texture);
Release(d3d11->menu.vbo);
#ifdef HAVE_DXGI_HDR
Release(d3d11->hdr.ubo);
#endif
d3d11_release_shader(&d3d11->sprites.shader);
d3d11_release_shader(&d3d11->sprites.shader_font);
Release(d3d11->sprites.vbo);
@@ -580,6 +688,10 @@ static void d3d11_gfx_free(void* data)
Release(d3d11->samplers[RARCH_FILTER_NEAREST][i]);
}
#ifdef HAVE_DXGI_HDR
d3d11_release_texture(&d3d11->back_buffer);
#endif
Release(d3d11->scissor_enabled);
Release(d3d11->scissor_disabled);
Release(d3d11->swapChain);
@@ -607,6 +719,10 @@ static void d3d11_gfx_free(void* data)
}
}
#ifdef HAVE_DXGI_HDR
video_driver_unset_hdr_support();
#endif
#ifdef HAVE_MONITOR
win32_monitor_from_window();
#endif
@@ -622,6 +738,7 @@ static bool d3d11_init_swapchain(d3d11_video_t* d3d11,
D3D11DeviceContext *cached_context,
void *corewindow)
{
HWND hwnd;
#ifdef __WINRT__
IDXGIFactory2* dxgiFactory = NULL;
#else
@@ -646,19 +763,51 @@ static bool d3d11_init_swapchain(d3d11_video_t* d3d11,
#endif
UINT number_feature_levels = ARRAY_SIZE(requested_feature_levels);
#ifdef HAVE_DXGI_HDR
DXGI_COLOR_SPACE_TYPE color_space;
d3d11->chain_formats[DXGI_SWAPCHAIN_BIT_DEPTH_8] = DXGI_FORMAT_R8G8B8A8_UNORM;
d3d11->chain_formats[DXGI_SWAPCHAIN_BIT_DEPTH_10] = DXGI_FORMAT_R10G10B10A2_UNORM;
d3d11->chain_formats[DXGI_SWAPCHAIN_BIT_DEPTH_16] = DXGI_FORMAT_R16G16B16A16_UNORM;
#endif
hwnd = (HWND)corewindow;
#ifdef HAVE_DXGI_HDR
if (!(d3d11->hdr.support =
dxgi_check_display_hdr_support(d3d11->factory, hwnd)))
d3d11->hdr.enable = false;
d3d11->chain_bit_depth = d3d11->hdr.enable
? DXGI_SWAPCHAIN_BIT_DEPTH_10
: DXGI_SWAPCHAIN_BIT_DEPTH_8;
#endif
#ifdef __WINRT__
/* Flip model forces us to do double-buffering */
desc.BufferCount = 2;
desc.Width = width;
desc.Height = height;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
#ifdef HAVE_DXGI_HDR
if (d3d11->hdr.support)
desc.Format = d3d11->chain_formats[
d3d11->chain_bit_depth];
else
#endif
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
#else
desc.BufferCount = 2;
desc.BufferDesc.Width = width;
desc.BufferDesc.Height = height;
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
#ifdef HAVE_DXGI_HDR
if (d3d11->hdr.support)
desc.BufferDesc.Format = d3d11->chain_formats[
d3d11->chain_bit_depth];
else
#endif
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.BufferDesc.RefreshRate.Numerator = 60;
desc.BufferDesc.RefreshRate.Denominator = 1;
#endif
@@ -695,6 +844,39 @@ static bool d3d11_init_swapchain(d3d11_video_t* d3d11,
D3D11_SDK_VERSION, &d3d11->device,
&d3d11->supportedFeatureLevel, &d3d11->context)))
return false;
switch (d3d11->supportedFeatureLevel)
{
case D3D_FEATURE_LEVEL_9_1:
RARCH_LOG("[D3D11] Device created (Feature Level: 9.1)\n");
break;
case D3D_FEATURE_LEVEL_9_2:
RARCH_LOG("[D3D11] Device created (Feature Level: 9.2)\n");
break;
case D3D_FEATURE_LEVEL_9_3:
RARCH_LOG("[D3D11] Device created (Feature Level: 9.3)\n");
break;
case D3D_FEATURE_LEVEL_10_0:
RARCH_LOG("[D3D11] Device created (Feature Level: 10.0)\n");
break;
case D3D_FEATURE_LEVEL_10_1:
RARCH_LOG("[D3D11] Device created (Feature Level: 10.1)\n");
break;
case D3D_FEATURE_LEVEL_11_0:
RARCH_LOG("[D3D11] Device created (Feature Level: 11.0)\n");
break;
case D3D_FEATURE_LEVEL_11_1:
RARCH_LOG("[D3D11] Device created (Feature Level: 11.1)\n");
break;
case D3D_FEATURE_LEVEL_12_0:
RARCH_LOG("[D3D11] Device created (Feature Level: 12.0)\n");
break;
case D3D_FEATURE_LEVEL_12_1:
RARCH_LOG("[D3D11] Device created (Feature Level: 12.1)\n");
break;
default:
RARCH_LOG("[D3D11] Device created (Feature Level: N/A)\n");
break;
}
}
d3d11->device->lpVtbl->QueryInterface(
@@ -777,7 +959,44 @@ static bool d3d11_init_swapchain(d3d11_video_t* d3d11,
}
#endif
#endif // __WINRT__
#endif /* __WINRT__ */
#ifdef HAVE_DXGI_HDR
/* Check display HDR support and
initialize ST.2084 support to match
the display's support. */
#if 0
d3d11->hdr.max_output_nits = 300.0f;
d3d11->hdr.min_output_nits = 0.001f;
d3d11->hdr.max_cll = 0.0f;
d3d11->hdr.max_fall = 0.0f;
#endif
color_space =
d3d11->hdr.enable
? DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
dxgi_swapchain_color_space(
d3d11->swapChain,
&d3d11->chain_color_space,
color_space);
dxgi_set_hdr_metadata(
d3d11->swapChain,
d3d11->hdr.support,
d3d11->chain_bit_depth,
d3d11->chain_color_space,
d3d11->hdr.max_output_nits,
d3d11->hdr.min_output_nits,
d3d11->hdr.max_cll,
d3d11->hdr.max_fall);
memset(&d3d11->back_buffer, 0, sizeof(d3d11->back_buffer));
d3d11->back_buffer.desc.Width = width;
d3d11->back_buffer.desc.Height = height;
d3d11->back_buffer.desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
d3d11->back_buffer.desc.BindFlags = D3D11_BIND_RENDER_TARGET;
d3d11_init_texture(d3d11->device, &d3d11->back_buffer);
#endif
dxgiFactory->lpVtbl->Release(dxgiFactory);
adapter->lpVtbl->Release(adapter);
@@ -840,6 +1059,19 @@ static void *d3d11_gfx_init(const video_info_t* video,
d3d_input_driver(settings->arrays.input_driver, settings->arrays.input_joypad_driver, input, input_data);
#ifdef __WINRT__
DXGICreateFactory2(&d3d11->factory);
#else
DXGICreateFactory(&d3d11->factory);
#endif
#ifdef HAVE_DXGI_HDR
d3d11->hdr.enable = settings->bools.video_hdr_enable;
d3d11->hdr.max_output_nits = settings->floats.video_hdr_max_nits;
d3d11->hdr.min_output_nits = 0.001f;
d3d11->hdr.max_cll = 0.0f;
d3d11->hdr.max_fall = 0.0f;
#endif
#ifdef __WINRT__
if (!d3d11_init_swapchain(d3d11,
d3d11->vp.full_width,
@@ -905,6 +1137,39 @@ static void *d3d11_gfx_init(const video_info_t* video,
d3d11_gfx_set_rotation(d3d11, 0);
#ifdef HAVE_DXGI_HDR
if (d3d11->hdr.enable)
{
D3D11_BUFFER_DESC desc;
D3D11_SUBRESOURCE_DATA ubo_data;
matrix_4x4_ortho(d3d11->mvp_no_rot, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
d3d11->hdr.ubo_values.mvp =
d3d11->mvp_no_rot;
d3d11->hdr.ubo_values.maxNits =
settings->floats.video_hdr_max_nits;
d3d11->hdr.ubo_values.paperWhiteNits =
settings->floats.video_hdr_paper_white_nits;
d3d11->hdr.ubo_values.contrast =
settings->floats.video_hdr_contrast;
d3d11->hdr.ubo_values.expandGamut =
settings->bools.video_hdr_expand_gamut;
desc.ByteWidth = sizeof(dxgi_hdr_uniform_t);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
desc.StructureByteStride = 0;
ubo_data.pSysMem = &d3d11->hdr.ubo_values.mvp;
ubo_data.SysMemPitch = 0;
ubo_data.SysMemSlicePitch = 0;
D3D11CreateBuffer(d3d11->device, &desc, &ubo_data, &d3d11->hdr.ubo);
}
#endif
{
D3D11_SAMPLER_DESC desc = { D3D11_FILTER_MIN_MAG_MIP_POINT };
desc.MaxAnisotropy = 1;
@@ -974,6 +1239,35 @@ static void *d3d11_gfx_init(const video_info_t* video,
D3D11CreateBuffer(d3d11->device, &desc, NULL, &d3d11->sprites.vbo);
}
#ifdef HAVE_DXGI_HDR
if (d3d11->hdr.enable)
{
D3D11_INPUT_ELEMENT_DESC desc[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0,
offsetof(d3d11_vertex_t, position),
D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0,
offsetof(d3d11_vertex_t, texcoord),
D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0,
offsetof(d3d11_vertex_t, color),
D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
static const char shader[] =
#include "d3d_shaders/hdr_sm5.hlsl.h"
;
if (!d3d11_init_shader(
d3d11->device, shader, sizeof(shader),
NULL, "VSMain", "PSMain", NULL, desc,
countof(desc), &d3d11->shaders[VIDEO_SHADER_STOCK_HDR],
D3D11_FEATURE_LEVEL_HINT_DONTCARE
))
goto error;
}
#endif
{
D3D11_INPUT_ELEMENT_DESC desc[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d11_vertex_t, position),
@@ -990,7 +1284,9 @@ static void *d3d11_gfx_init(const video_info_t* video,
if (!d3d11_init_shader(
d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", NULL, desc,
countof(desc), &d3d11->shaders[VIDEO_SHADER_STOCK_BLEND]))
countof(desc), &d3d11->shaders[VIDEO_SHADER_STOCK_BLEND],
D3D11_FEATURE_LEVEL_HINT_DONTCARE
))
goto error;
}
@@ -1018,11 +1314,13 @@ static void *d3d11_gfx_init(const video_info_t* video,
if (!d3d11_init_shader(
d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", "GSMain", desc,
countof(desc), &d3d11->sprites.shader))
countof(desc), &d3d11->sprites.shader,
D3D11_FEATURE_LEVEL_HINT_DONTCARE))
goto error;
if (!d3d11_init_shader(
d3d11->device, shader, sizeof(shader), NULL, "VSMain", "PSMainA8", "GSMain", desc,
countof(desc), &d3d11->sprites.shader_font))
countof(desc), &d3d11->sprites.shader_font,
D3D11_FEATURE_LEVEL_HINT_DONTCARE))
goto error;
}
@@ -1042,12 +1340,14 @@ static void *d3d11_gfx_init(const video_info_t* video,
if (!d3d11_init_shader(
d3d11->device, ribbon, sizeof(ribbon), NULL, "VSMain", "PSMain", NULL, desc,
countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU]))
countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU],
D3D11_FEATURE_LEVEL_HINT_DONTCARE))
goto error;
if (!d3d11_init_shader(
d3d11->device, ribbon_simple, sizeof(ribbon_simple), NULL, "VSMain", "PSMain", NULL,
desc, countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_2]))
desc, countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_2],
D3D11_FEATURE_LEVEL_HINT_DONTCARE))
goto error;
}
@@ -1074,21 +1374,25 @@ static void *d3d11_gfx_init(const video_info_t* video,
if (!d3d11_init_shader(
d3d11->device, simple_snow, sizeof(simple_snow), NULL, "VSMain", "PSMain", NULL,
desc, countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_3]))
desc, countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_3],
D3D11_FEATURE_LEVEL_HINT_DONTCARE))
goto error;
if (!d3d11_init_shader(
d3d11->device, snow, sizeof(snow), NULL, "VSMain", "PSMain", NULL, desc,
countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_4]))
countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_4],
D3D11_FEATURE_LEVEL_HINT_DONTCARE))
goto error;
if (!d3d11_init_shader(
d3d11->device, bokeh, sizeof(bokeh), NULL, "VSMain", "PSMain", NULL, desc,
countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_5]))
countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_5],
D3D11_FEATURE_LEVEL_HINT_DONTCARE))
goto error;
if (!d3d11_init_shader(
d3d11->device, snowflake, sizeof(snowflake), NULL, "VSMain", "PSMain", NULL, desc,
countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_6]))
countof(desc), &d3d11->shaders[VIDEO_SHADER_MENU_6],
D3D11_FEATURE_LEVEL_HINT_DONTCARE))
goto error;
}
}
@@ -1156,12 +1460,6 @@ static void *d3d11_gfx_init(const video_info_t* video,
d3d11->hw.iface.D3DCompile = D3DCompile;
}
#ifdef __WINRT__
DXGICreateFactory2(&d3d11->factory);
#else
DXGICreateFactory(&d3d11->factory);
#endif
{
int i = 0;
int gpu_index = settings->ints.d3d11_gpu_index;
@@ -1384,32 +1682,91 @@ static bool d3d11_gfx_frame(
#ifdef HAVE_GFX_WIDGETS
bool widgets_active = video_info->widgets_active;
#endif
#ifdef HAVE_DXGI_HDR
bool video_hdr_enable = video_info->hdr_enable;
if ( d3d11->resize_chain ||
(d3d11->hdr.enable != video_hdr_enable))
#else
if (d3d11->resize_chain)
#endif
{
UINT swapchain_flags = d3d11->has_allow_tearing
UINT swapchain_flags = d3d11->has_allow_tearing
? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
DXGIResizeBuffers(d3d11->swapChain, 0, 0, 0, DXGI_FORMAT_UNKNOWN,
swapchain_flags);
#ifdef HAVE_DXGI_HDR
d3d11->hdr.enable = video_hdr_enable;
d3d11->viewport.Width = video_width;
d3d11->viewport.Height = video_height;
d3d11->scissor.right = video_width;
d3d11->scissor.bottom = video_height;
if(d3d11->hdr.enable)
d3d11_release_texture(&d3d11->back_buffer);
DXGIResizeBuffers(d3d11->swapChain, 0, 0, 0,
d3d11->chain_formats[d3d11->chain_bit_depth],
swapchain_flags);
#else
DXGIResizeBuffers(d3d11->swapChain, 0, 0, 0,
DXGI_FORMAT_UNKNOWN,
swapchain_flags);
#endif
d3d11->viewport.Width = video_width;
d3d11->viewport.Height = video_height;
d3d11->scissor.right = video_width;
d3d11->scissor.bottom = video_height;
d3d11->ubo_values.OutputSize.width = d3d11->viewport.Width;
d3d11->ubo_values.OutputSize.height = d3d11->viewport.Height;
d3d11->resize_chain = false;
d3d11->resize_viewport = true;
d3d11->resize_chain = false;
d3d11->resize_viewport = true;
video_driver_set_size(video_width, video_height);
#ifdef HAVE_DXGI_HDR
#ifdef __WINRT__
if (!(d3d11->hdr.support =
dxgi_check_display_hdr_support(d3d11->factory, uwp_get_corewindow())))
d3d11->hdr.enable = false;
#else
if (!(d3d11->hdr.support =
dxgi_check_display_hdr_support(d3d11->factory, main_window.hwnd)))
d3d11->hdr.enable = false;
#endif
if(d3d11->hdr.enable)
{
memset(&d3d11->back_buffer, 0, sizeof(d3d11->back_buffer));
d3d11->back_buffer.desc.Width = video_width;
d3d11->back_buffer.desc.Height = video_height;
d3d11->back_buffer.desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
d3d11->back_buffer.desc.BindFlags = D3D11_BIND_RENDER_TARGET;
d3d11_init_texture(d3d11->device, &d3d11->back_buffer);
dxgi_swapchain_color_space(
d3d11->swapChain,
&d3d11->chain_color_space,
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
}
else
dxgi_swapchain_color_space(
d3d11->swapChain,
&d3d11->chain_color_space,
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
dxgi_set_hdr_metadata(
d3d11->swapChain,
d3d11->hdr.support,
d3d11->chain_bit_depth,
d3d11->chain_color_space,
d3d11->hdr.max_output_nits,
d3d11->hdr.min_output_nits,
d3d11->hdr.max_cll,
d3d11->hdr.max_fall);
#endif
}
{
D3D11Texture2D backBuffer;
DXGIGetSwapChainBufferD3D11(d3d11->swapChain, 0, &backBuffer);
D3D11CreateTexture2DRenderTargetView(d3d11->device, backBuffer, NULL, &rtv);
Release(backBuffer);
D3D11Texture2D back_buffer;
DXGIGetSwapChainBufferD3D11(d3d11->swapChain, 0, &back_buffer);
D3D11CreateTexture2DRenderTargetView(d3d11->device, back_buffer, NULL, &rtv);
Release(back_buffer);
}
/* custom viewport doesn't call apply_state_changes, so we can't rely on this for now */
@@ -1593,9 +1950,6 @@ static bool d3d11_gfx_frame(
}
D3D11SetRenderTargets(context, 1, &d3d11->pass[i].rt.rt_view, NULL);
#if 0
D3D11ClearRenderTargetView(context, d3d11->pass[i].rt.rt_view, d3d11->clearcolor);
#endif
D3D11SetViewports(context, 1, &d3d11->pass[i].viewport);
D3D11Draw(context, 4, 0);
@@ -1603,8 +1957,20 @@ static bool d3d11_gfx_frame(
}
}
D3D11SetRenderTargets(context, 1, &rtv, NULL);
D3D11ClearRenderTargetView(context, rtv, d3d11->clearcolor);
#ifdef HAVE_DXGI_HDR
if(d3d11->hdr.enable)
{
D3D11SetRenderTargets(context, 1, &d3d11->back_buffer.rt_view, NULL);
D3D11ClearRenderTargetView(context, d3d11->back_buffer.rt_view, d3d11->clearcolor);
}
else
#endif
{
D3D11SetRenderTargets(context, 1, &rtv, NULL);
D3D11ClearRenderTargetView(context, rtv, d3d11->clearcolor);
}
D3D11SetViewports(context, 1, &d3d11->frame.viewport);
if (texture)
@@ -1702,6 +2068,44 @@ static bool d3d11_gfx_frame(
#if defined(_WIN32) && !defined(__WINRT__)
win32_update_title();
#endif
#ifdef HAVE_DXGI_HDR
/* Copy over back buffer to swap chain render targets */
if(d3d11->hdr.enable)
{
ID3D11ShaderResourceView* nullSRV[1] = {NULL};
D3D11SetRenderTargets(context, 1, &rtv, NULL);
D3D11ClearRenderTargetView(context, rtv,
d3d11->clearcolor);
D3D11SetViewports(context, 1,
&d3d11->viewport);
D3D11SetScissorRects(context, 1,
&d3d11->scissor);
d3d11_set_shader(context,
&d3d11->shaders[VIDEO_SHADER_STOCK_HDR]);
D3D11SetVShaderConstantBuffer(context, 0,
d3d11->hdr.ubo);
D3D11SetPShaderResources(context, 0, 1,
&d3d11->back_buffer.view);
D3D11SetPShaderSamplers(context, 0, 1,
&d3d11->samplers[RARCH_FILTER_UNSPEC][RARCH_WRAP_DEFAULT]);
D3D11SetPShaderConstantBuffer(context, 0, d3d11->hdr.ubo);
D3D11SetVertexBuffer(context, 0, d3d11->frame.vbo,
sizeof(d3d11_vertex_t), 0);
D3D11SetRasterizerState(context, d3d11->scissor_disabled);
D3D11SetBlendState(context, d3d11->blend_disable, NULL,
D3D11_DEFAULT_SAMPLE_MASK);
D3D11SetPrimitiveTopology(context,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D11Draw(context, 4, 0);
D3D11SetPShaderResources(context, 0, 1, nullSRV);
}
#endif
DXGIPresent(d3d11->swapChain, !!vsync, present_flags);
Release(rtv);
@@ -1957,6 +2361,17 @@ static const video_poke_interface_t d3d11_poke_interface = {
d3d11_gfx_get_current_shader,
NULL, /* get_current_software_framebuffer */
d3d11_get_hw_render_interface,
#ifdef HAVE_DXGI_HDR
d3d11_set_hdr_max_nits,
d3d11_set_hdr_paper_white_nits,
d3d11_set_hdr_contrast,
d3d11_set_hdr_expand_gamut
#else
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
#endif
};
static void d3d11_gfx_get_poke_interface(void* data,
+467 -91
View File
@@ -238,6 +238,78 @@ static void d3d12_get_overlay_interface(void* data, const video_overlay_interfac
}
#endif
#if 0
d3d12->hdr.max_output_nits = settings->floats.video_hdr_max_nits;
d3d12->hdr.ubo_values.maxNits = settings->floats.video_hdr_max_nits;
d3d12->hdr.ubo_values.paperWhiteNits = settings->floats.video_hdr_paper_white_nits;
d3d12->hdr.ubo_values.contrast = settings->floats.video_hdr_contrast;
d3d12->hdr.ubo_values.expandGamut = settings->bools.video_hdr_expand_gamut;
#endif
#ifdef HAVE_DXGI_HDR
static void d3d12_set_hdr_max_nits(void* data, float max_nits)
{
dxgi_hdr_uniform_t *mapped_ubo = NULL;
D3D12_RANGE read_range = { 0, 0 };
d3d12_video_t *d3d12 = (d3d12_video_t*)data;
d3d12->hdr.max_output_nits = max_nits;
d3d12->hdr.ubo_values.maxNits = max_nits;
D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->hdr.ubo_values;
D3D12Unmap(d3d12->hdr.ubo, 0, NULL);
dxgi_set_hdr_metadata(
d3d12->chain.handle,
d3d12->hdr.support,
d3d12->chain.bit_depth,
d3d12->chain.color_space,
d3d12->hdr.max_output_nits,
d3d12->hdr.min_output_nits,
d3d12->hdr.max_cll,
d3d12->hdr.max_fall);
}
static void d3d12_set_hdr_paper_white_nits(void* data, float paper_white_nits)
{
D3D12_RANGE read_range = { 0, 0 };
dxgi_hdr_uniform_t *mapped_ubo = NULL;
d3d12_video_t *d3d12 = (d3d12_video_t*)data;
d3d12->hdr.ubo_values.paperWhiteNits = paper_white_nits;
D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->hdr.ubo_values;
D3D12Unmap(d3d12->hdr.ubo, 0, NULL);
}
static void d3d12_set_hdr_contrast(void* data, float contrast)
{
D3D12_RANGE read_range = { 0, 0 };
d3d12_video_t *d3d12 = (d3d12_video_t*)data;
dxgi_hdr_uniform_t *mapped_ubo = NULL;
d3d12->hdr.ubo_values.contrast = contrast;
D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->hdr.ubo_values;
D3D12Unmap(d3d12->hdr.ubo, 0, NULL);
}
static void d3d12_set_hdr_expand_gamut(void* data, bool expand_gamut)
{
D3D12_RANGE read_range = { 0, 0 };
dxgi_hdr_uniform_t *mapped_ubo = NULL;
d3d12_video_t *d3d12 = (d3d12_video_t*)data;
d3d12->hdr.ubo_values.expandGamut = expand_gamut;
D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->hdr.ubo_values;
D3D12Unmap(d3d12->hdr.ubo, 0, NULL);
}
#endif
static void d3d12_set_filtering(void* data, unsigned index, bool smooth, bool ctx_scaling)
{
int i;
@@ -494,9 +566,18 @@ static bool d3d12_gfx_set_shader(void* data, enum rarch_shader_type type, const
if (!d3d12->pass[i].pipe)
goto error;
#ifdef HAVE_DXGI_HDR
d3d12->pass[i].rt.rt_view.ptr =
d3d12->desc.rtv_heap.cpu.ptr +
(countof(d3d12->chain.renderTargets) + (2 * i)) * d3d12->desc.rtv_heap.stride;
d3d12->desc.rtv_heap.cpu.ptr +
(countof(d3d12->chain.renderTargets) + 1 + (2 * i))
* d3d12->desc.rtv_heap.stride;
#else
d3d12->pass[i].rt.rt_view.ptr =
d3d12->desc.rtv_heap.cpu.ptr +
(countof(d3d12->chain.renderTargets) + (2 * i))
* d3d12->desc.rtv_heap.stride;
#endif
d3d12->pass[i].feedback.rt_view.ptr = d3d12->pass[i].rt.rt_view.ptr + d3d12->desc.rtv_heap.stride;
d3d12->pass[i].textures.ptr =
@@ -562,12 +643,51 @@ static bool d3d12_gfx_init_pipelines(d3d12_video_t* d3d12)
settings_t * settings = config_get_ptr();
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = { d3d12->desc.rootSignature };
desc.BlendState.RenderTarget[0] = d3d12_blend_disable_desc;
#ifdef HAVE_DXGI_HDR
desc.RTVFormats[0] = DXGI_FORMAT_R10G10B10A2_UNORM;
{
static const char shader[] =
#include "d3d_shaders/hdr_sm5.hlsl.h"
;
static const D3D12_INPUT_ELEMENT_DESC inputElementDesc[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_vertex_t, position),
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_vertex_t, texcoord),
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d12_vertex_t, color),
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};
if (!d3d_compile(shader, sizeof(shader), NULL, "VSMain", "vs_5_0", &vs_code))
goto error;
if (!d3d_compile(shader, sizeof(shader), NULL, "PSMain", "ps_5_0", &ps_code))
goto error;
desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
desc.InputLayout.pInputElementDescs = inputElementDesc;
desc.InputLayout.NumElements = countof(inputElementDesc);
if (!d3d12_init_pipeline(
d3d12->device, vs_code, ps_code, NULL, &desc,
&d3d12->pipes[VIDEO_SHADER_STOCK_HDR]))
goto error;
Release(vs_code);
Release(ps_code);
vs_code = NULL;
ps_code = NULL;
}
#endif
desc.BlendState.RenderTarget[0] = d3d12_blend_enable_desc;
desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
{
static const char shader[] =
#include "../drivers/d3d_shaders/opaque_sm5.hlsl.h"
#include "d3d_shaders/opaque_sm5.hlsl.h"
;
static const D3D12_INPUT_ELEMENT_DESC inputElementDesc[] = {
@@ -839,6 +959,10 @@ static void d3d12_gfx_free(void* data)
Release(d3d12->sprites.vbo);
Release(d3d12->menu_pipeline_vbo);
#ifdef HAVE_DXGI_HDR
Release(d3d12->hdr.ubo);
#endif
Release(d3d12->frame.ubo);
Release(d3d12->frame.vbo);
Release(d3d12->frame.texture[0].handle);
@@ -847,6 +971,10 @@ static void d3d12_gfx_free(void* data)
Release(d3d12->menu.texture.handle);
Release(d3d12->menu.texture.upload_buffer);
#ifdef HAVE_DXGI_HDR
d3d12_release_texture(&d3d12->chain.back_buffer);
d3d12->chain.back_buffer.handle = NULL;
#endif
free(d3d12->desc.sampler_heap.map);
free(d3d12->desc.srv_heap.map);
free(d3d12->desc.rtv_heap.map);
@@ -890,6 +1018,10 @@ static void d3d12_gfx_free(void* data)
}
}
#ifdef HAVE_DXGI_HDR
video_driver_unset_hdr_support();
#endif
#ifdef HAVE_MONITOR
win32_monitor_from_window();
#endif
@@ -951,6 +1083,14 @@ static void *d3d12_gfx_init(const video_info_t* video,
goto error;
}
#ifdef HAVE_DXGI_HDR
d3d12->hdr.enable = settings->bools.video_hdr_enable;
d3d12->hdr.max_output_nits = settings->floats.video_hdr_max_nits;
d3d12->hdr.min_output_nits = 0.001f;
d3d12->hdr.max_cll = 0.0f;
d3d12->hdr.max_fall = 0.0f;
#endif
d3d_input_driver(settings->arrays.input_driver, settings->arrays.input_joypad_driver, input, input_data);
if (!d3d12_init_base(d3d12))
@@ -1007,6 +1147,26 @@ static void *d3d12_gfx_init(const video_info_t* video,
D3D12Unmap(d3d12->ubo, 0, NULL);
}
#ifdef HAVE_DXGI_HDR
d3d12->hdr.ubo_view.SizeInBytes = sizeof(dxgi_hdr_uniform_t);
d3d12->hdr.ubo_view.BufferLocation =
d3d12_create_buffer(d3d12->device, d3d12->hdr.ubo_view.SizeInBytes, &d3d12->hdr.ubo);
d3d12->hdr.ubo_values.mvp = d3d12->mvp_no_rot;
d3d12->hdr.ubo_values.maxNits = settings->floats.video_hdr_max_nits;
d3d12->hdr.ubo_values.paperWhiteNits = settings->floats.video_hdr_paper_white_nits;
d3d12->hdr.ubo_values.contrast = settings->floats.video_hdr_contrast;
d3d12->hdr.ubo_values.expandGamut = settings->bools.video_hdr_expand_gamut;
{
dxgi_hdr_uniform_t* mapped_ubo;
D3D12_RANGE read_range = { 0, 0 };
D3D12Map(d3d12->hdr.ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->hdr.ubo_values;
D3D12Unmap(d3d12->hdr.ubo, 0, NULL);
}
#endif
d3d12_gfx_set_rotation(d3d12, 0);
video_driver_set_size(d3d12->vp.full_width, d3d12->vp.full_height);
d3d12->chain.viewport.Width = d3d12->vp.full_width;
@@ -1197,53 +1357,132 @@ static bool d3d12_gfx_frame(
#ifdef HAVE_GFX_WIDGETS
bool widgets_active = video_info->widgets_active;
#endif
#ifdef HAVE_DXGI_HDR
bool video_hdr_enable = video_info->hdr_enable;
if (d3d12->resize_chain || (d3d12->hdr.enable != video_hdr_enable))
#else
if (d3d12->resize_chain)
#endif
{
unsigned i;
#ifdef HAVE_DXGI_HDR
d3d12->hdr.enable = video_hdr_enable;
#endif
for (i = 0; i < countof(d3d12->chain.renderTargets); i++)
Release(d3d12->chain.renderTargets[i]);
DXGIResizeBuffers(d3d12->chain.handle, 0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
#ifdef HAVE_DXGI_HDR
if (d3d12->hdr.enable)
{
d3d12_release_texture(&d3d12->chain.back_buffer);
d3d12->chain.back_buffer.handle = NULL;
}
DXGIResizeBuffers(d3d12->chain.handle,
countof(d3d12->chain.renderTargets),
video_width,
video_height,
d3d12->chain.formats[d3d12->chain.bit_depth],
DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
#else
DXGIResizeBuffers(d3d12->chain.handle,
0,
0,
0,
DXGI_FORMAT_UNKNOWN,
DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
#endif
for (i = 0; i < countof(d3d12->chain.renderTargets); i++)
{
DXGIGetSwapChainBuffer(d3d12->chain.handle, i, &d3d12->chain.renderTargets[i]);
DXGIGetSwapChainBuffer(d3d12->chain.handle, i,
&d3d12->chain.renderTargets[i]);
D3D12CreateRenderTargetView(
d3d12->device, d3d12->chain.renderTargets[i], NULL, d3d12->chain.desc_handles[i]);
d3d12->device, d3d12->chain.renderTargets[i],
NULL, d3d12->chain.desc_handles[i]);
}
d3d12->chain.viewport.Width = video_width;
d3d12->chain.viewport.Height = video_height;
d3d12->chain.scissorRect.right = video_width;
d3d12->chain.scissorRect.bottom = video_height;
d3d12->resize_chain = false;
d3d12->resize_viewport = true;
d3d12->chain.viewport.Width = video_width;
d3d12->chain.viewport.Height = video_height;
d3d12->chain.scissorRect.right = video_width;
d3d12->chain.scissorRect.bottom = video_height;
d3d12->resize_chain = false;
d3d12->resize_viewport = true;
d3d12->ubo_values.OutputSize.width = d3d12->chain.viewport.Width;
d3d12->ubo_values.OutputSize.height = d3d12->chain.viewport.Height;
video_driver_set_size(video_width, video_height);
#ifdef HAVE_DXGI_HDR
#ifdef __WINRT__
if (!(d3d12->hdr.support =
dxgi_check_display_hdr_support(d3d12->factory, uwp_get_corewindow())))
d3d12->hdr.enable = false;
#else
if (!(d3d12->hdr.support =
dxgi_check_display_hdr_support(d3d12->factory, main_window.hwnd)))
d3d12->hdr.enable = false;
#endif
if(d3d12->hdr.enable)
{
memset(&d3d12->chain.back_buffer,
0, sizeof(d3d12->chain.back_buffer));
d3d12->chain.back_buffer.desc.Width = video_width;
d3d12->chain.back_buffer.desc.Height = video_height;
d3d12->chain.back_buffer.desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
d3d12->chain.back_buffer.desc.Flags =
D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
d3d12->chain.back_buffer.srv_heap = &d3d12->desc.srv_heap;
d3d12->chain.back_buffer.rt_view.ptr =
d3d12->desc.rtv_heap.cpu.ptr
+ countof(d3d12->chain.renderTargets)
* d3d12->desc.rtv_heap.stride;
d3d12_init_texture(d3d12->device, &d3d12->chain.back_buffer);
dxgi_swapchain_color_space(d3d12->chain.handle,
&d3d12->chain.color_space,
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
}
else
dxgi_swapchain_color_space(d3d12->chain.handle,
&d3d12->chain.color_space,
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
dxgi_set_hdr_metadata(
d3d12->chain.handle,
d3d12->hdr.support,
d3d12->chain.bit_depth,
d3d12->chain.color_space,
d3d12->hdr.max_output_nits,
d3d12->hdr.min_output_nits,
d3d12->hdr.max_cll,
d3d12->hdr.max_fall);
#endif
}
D3D12ResetCommandAllocator(d3d12->queue.allocator);
D3D12ResetGraphicsCommandList(
d3d12->queue.cmd, d3d12->queue.allocator, d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
d3d12->queue.cmd, d3d12->queue.allocator,
d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
{
D3D12DescriptorHeap desc_heaps[] = { d3d12->desc.srv_heap.handle,
d3d12->desc.sampler_heap.handle };
D3D12SetDescriptorHeaps(d3d12->queue.cmd, countof(desc_heaps), desc_heaps);
D3D12SetDescriptorHeaps(d3d12->queue.cmd,
countof(desc_heaps), desc_heaps);
}
#if 0 /* custom viewport doesn't call apply_state_changes, so we can't rely on this for now */
#if 0
/* Custom viewport doesn't call apply_state_changes,
so we can't rely on this for now */
if (d3d12->resize_viewport)
#endif
d3d12_update_viewport(d3d12, false);
D3D12IASetPrimitiveTopology(d3d12->queue.cmd, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D12IASetPrimitiveTopology(d3d12->queue.cmd,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
if (frame && width && height)
{
@@ -1260,7 +1499,8 @@ static bool d3d12_gfx_frame(
if (d3d12->resize_render_targets)
{
/* release all render targets first to avoid memory fragmentation */
/* Release all render targets first
to avoid memory fragmentation */
for (i = 0; i < d3d12->shader_preset->passes; i++)
{
d3d12_release_texture(&d3d12->pass[i].rt);
@@ -1277,9 +1517,10 @@ static bool d3d12_gfx_frame(
else
{
int k;
/* todo: what about frame-duping ?
/* TODO/FIXME: what about frame-duping ?
* maybe clone d3d12_texture_t with AddRef */
d3d12_texture_t tmp = d3d12->frame.texture[d3d12->shader_preset->history_size];
d3d12_texture_t tmp =
d3d12->frame.texture[d3d12->shader_preset->history_size];
for (k = d3d12->shader_preset->history_size; k > 0; k--)
d3d12->frame.texture[k] = d3d12->frame.texture[k - 1];
d3d12->frame.texture[0] = tmp;
@@ -1287,8 +1528,9 @@ static bool d3d12_gfx_frame(
}
}
/* either no history, or we moved a texture of a different size in the front slot */
if (d3d12->frame.texture[0].desc.Width != width ||
/* Either no history, or we moved a texture
of a different size in the front slot */
if (d3d12->frame.texture[0].desc.Width != width ||
d3d12->frame.texture[0].desc.Height != height)
{
d3d12->frame.texture[0].desc.Width = width;
@@ -1300,7 +1542,8 @@ static bool d3d12_gfx_frame(
if (d3d12->resize_render_targets)
d3d12_init_render_targets(d3d12, width, height);
d3d12_update_texture(width, height, pitch, d3d12->format, frame, &d3d12->frame.texture[0]);
d3d12_update_texture(width, height, pitch, d3d12->format,
frame, &d3d12->frame.texture[0]);
d3d12_upload_texture(d3d12->queue.cmd, &d3d12->frame.texture[0],
d3d12);
@@ -1311,7 +1554,8 @@ static bool d3d12_gfx_frame(
if (d3d12->shader_preset)
{
D3D12SetGraphicsRootSignature(d3d12->queue.cmd, d3d12->desc.sl_rootSignature);
D3D12SetGraphicsRootSignature(d3d12->queue.cmd,
d3d12->desc.sl_rootSignature);
for (i = 0; i < d3d12->shader_preset->passes; i++)
{
@@ -1330,16 +1574,17 @@ static bool d3d12_gfx_frame(
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->pass[i].pipe);
if (d3d12->shader_preset->pass[i].frame_count_mod)
d3d12->pass[i].frame_count =
frame_count % d3d12->shader_preset->pass[i].frame_count_mod;
d3d12->pass[i].frame_count = frame_count
% d3d12->shader_preset->pass[i].frame_count_mod;
else
d3d12->pass[i].frame_count = frame_count;
#ifdef HAVE_REWIND
d3d12->pass[i].frame_direction = state_manager_frame_is_reversed() ? -1 : 1;
#else
d3d12->pass[i].frame_direction = 1;
if (state_manager_frame_is_reversed())
d3d12->pass[i].frame_direction = -1;
else
#endif
d3d12->pass[i].frame_direction = 1;
for (j = 0; j < SLANG_CBUFFER_MAX; j++)
{
@@ -1351,17 +1596,21 @@ static bool d3d12_gfx_frame(
uint8_t* mapped_data = NULL;
uniform_sem_t* uniform = buffer_sem->uniforms;
D3D12Map(d3d12->pass[i].buffers[j], 0, &range, (void**)&mapped_data);
D3D12Map(d3d12->pass[i].buffers[j], 0, &range,
(void**)&mapped_data);
while (uniform->size)
{
if (uniform->data)
memcpy(mapped_data + uniform->offset, uniform->data, uniform->size);
memcpy(mapped_data + uniform->offset,
uniform->data, uniform->size);
uniform++;
}
D3D12Unmap(d3d12->pass[i].buffers[j], 0, NULL);
D3D12SetGraphicsRootConstantBufferView(
d3d12->queue.cmd, j == SLANG_CBUFFER_UBO ? ROOT_ID_UBO : ROOT_ID_PC,
d3d12->queue.cmd, j == SLANG_CBUFFER_UBO
? ROOT_ID_UBO
: ROOT_ID_PC,
d3d12->pass[i].buffer_view[j].BufferLocation);
}
}
@@ -1375,15 +1624,19 @@ static bool d3d12_gfx_frame(
{
{
D3D12_CPU_DESCRIPTOR_HANDLE handle = {
d3d12->pass[i].textures.ptr - d3d12->desc.srv_heap.gpu.ptr +
d3d12->desc.srv_heap.cpu.ptr +
texture_sem->binding * d3d12->desc.srv_heap.stride
d3d12->pass[i].textures.ptr
- d3d12->desc.srv_heap.gpu.ptr
+ d3d12->desc.srv_heap.cpu.ptr
+ texture_sem->binding * d3d12->desc.srv_heap.stride
};
d3d12_texture_t* tex = (d3d12_texture_t*)texture_sem->texture_data;
d3d12_texture_t* tex =
(d3d12_texture_t*)texture_sem->texture_data;
D3D12_SHADER_RESOURCE_VIEW_DESC desc = { tex->desc.Format };
desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
desc.Shader4ComponentMapping =
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
desc.ViewDimension =
D3D12_SRV_DIMENSION_TEXTURE2D;
desc.Texture2D.MipLevels = tex->desc.MipLevels;
D3D12CreateShaderResourceView(d3d12->device,
@@ -1392,9 +1645,11 @@ static bool d3d12_gfx_frame(
{
D3D12_CPU_DESCRIPTOR_HANDLE handle = {
d3d12->pass[i].samplers.ptr - d3d12->desc.sampler_heap.gpu.ptr +
d3d12->desc.sampler_heap.cpu.ptr +
texture_sem->binding * d3d12->desc.sampler_heap.stride
d3d12->pass[i].samplers.ptr
- d3d12->desc.sampler_heap.gpu.ptr
+ d3d12->desc.sampler_heap.cpu.ptr
+ texture_sem->binding
* d3d12->desc.sampler_heap.stride
};
D3D12_SAMPLER_DESC desc = { D3D12_FILTER_MIN_MAG_MIP_LINEAR };
@@ -1435,29 +1690,37 @@ static bool d3d12_gfx_frame(
}
D3D12SetGraphicsRootDescriptorTable(
d3d12->queue.cmd, ROOT_ID_TEXTURE_T, d3d12->pass[i].textures);
d3d12->queue.cmd, ROOT_ID_TEXTURE_T,
d3d12->pass[i].textures);
D3D12SetGraphicsRootDescriptorTable(
d3d12->queue.cmd, ROOT_ID_SAMPLER_T, d3d12->pass[i].samplers);
d3d12->queue.cmd, ROOT_ID_SAMPLER_T,
d3d12->pass[i].samplers);
}
if (d3d12->pass[i].rt.handle)
{
d3d12_resource_transition(
d3d12->queue.cmd, d3d12->pass[i].rt.handle,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12OMSetRenderTargets(d3d12->queue.cmd, 1, &d3d12->pass[i].rt.rt_view, FALSE, NULL);
D3D12OMSetRenderTargets(d3d12->queue.cmd, 1,
&d3d12->pass[i].rt.rt_view, FALSE, NULL);
#if 0
D3D12ClearRenderTargetView(
d3d12->queue.cmd, d3d12->pass[i].rt.rt_view, d3d12->chain.clearcolor, 0, NULL);
d3d12->queue.cmd, d3d12->pass[i].rt.rt_view,
d3d12->chain.clearcolor, 0, NULL);
#endif
D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->pass[i].viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->pass[i].scissorRect);
D3D12RSSetViewports(d3d12->queue.cmd, 1,
&d3d12->pass[i].viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1,
&d3d12->pass[i].scissorRect);
D3D12DrawInstanced(d3d12->queue.cmd, 4, 1, 0, 0);
d3d12_resource_transition(
d3d12->queue.cmd, d3d12->pass[i].rt.handle, D3D12_RESOURCE_STATE_RENDER_TARGET,
d3d12->queue.cmd, d3d12->pass[i].rt.handle,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
texture = &d3d12->pass[i].rt;
}
@@ -1471,31 +1734,68 @@ static bool d3d12_gfx_frame(
if (texture)
{
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
D3D12SetGraphicsRootSignature(d3d12->queue.cmd, d3d12->desc.rootSignature);
D3D12SetPipelineState(d3d12->queue.cmd,
d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
D3D12SetGraphicsRootSignature(d3d12->queue.cmd,
d3d12->desc.rootSignature);
d3d12_set_texture(d3d12->queue.cmd, &d3d12->frame.texture[0]);
d3d12_set_sampler(d3d12->queue.cmd, d3d12->samplers[RARCH_FILTER_UNSPEC][RARCH_WRAP_DEFAULT]);
d3d12_set_sampler(d3d12->queue.cmd,
d3d12->samplers[RARCH_FILTER_UNSPEC][RARCH_WRAP_DEFAULT]);
D3D12SetGraphicsRootConstantBufferView(
d3d12->queue.cmd, ROOT_ID_UBO, d3d12->frame.ubo_view.BufferLocation);
d3d12->queue.cmd, ROOT_ID_UBO,
d3d12->frame.ubo_view.BufferLocation);
}
d3d12->chain.frame_index = DXGIGetCurrentBackBufferIndex(d3d12->chain.handle);
d3d12_resource_transition(
d3d12->queue.cmd, d3d12->chain.renderTargets[d3d12->chain.frame_index],
D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
d3d12->chain.frame_index = DXGIGetCurrentBackBufferIndex(
d3d12->chain.handle);
D3D12OMSetRenderTargets(
d3d12->queue.cmd, 1, &d3d12->chain.desc_handles[d3d12->chain.frame_index], FALSE, NULL);
D3D12ClearRenderTargetView(
d3d12->queue.cmd, d3d12->chain.desc_handles[d3d12->chain.frame_index],
d3d12->chain.clearcolor, 0, NULL);
#ifdef HAVE_DXGI_HDR
if(d3d12->hdr.enable)
{
d3d12_resource_transition(
d3d12->queue.cmd, d3d12->chain.back_buffer.handle,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12OMSetRenderTargets(
d3d12->queue.cmd, 1,
&d3d12->chain.back_buffer.rt_view, FALSE, NULL);
/* TODO/FIXME - fix this warning that shows up with Debug logging
* EXECUTIONWARNING #820: CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE
* We need to set clear value during resource creation to NULL for
* D3D12_RESOURCE_DIMENSION_BUFFER, yet we get spammed with this
* warning
*/
D3D12ClearRenderTargetView(
d3d12->queue.cmd, d3d12->chain.back_buffer.rt_view,
d3d12->chain.clearcolor, 0, NULL);
}
else
#endif
{
d3d12_resource_transition(
d3d12->queue.cmd,
d3d12->chain.renderTargets[d3d12->chain.frame_index],
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12OMSetRenderTargets(
d3d12->queue.cmd, 1,
&d3d12->chain.desc_handles[d3d12->chain.frame_index],
FALSE, NULL);
D3D12ClearRenderTargetView(
d3d12->queue.cmd,
d3d12->chain.desc_handles[d3d12->chain.frame_index],
d3d12->chain.clearcolor, 0, NULL);
}
D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->frame.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->frame.scissorRect);
D3D12DrawInstanced(d3d12->queue.cmd, 4, 1, 0, 0);
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
D3D12SetPipelineState(d3d12->queue.cmd,
d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
D3D12SetGraphicsRootSignature(d3d12->queue.cmd, d3d12->desc.rootSignature);
if (d3d12->menu.enabled && d3d12->menu.texture.handle)
@@ -1520,7 +1820,8 @@ static bool d3d12_gfx_frame(
d3d12->sprites.pipe = d3d12->sprites.pipe_noblend;
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe);
D3D12IASetPrimitiveTopology(d3d12->queue.cmd, D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
D3D12IASetPrimitiveTopology(d3d12->queue.cmd,
D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
d3d12->sprites.enabled = true;
@@ -1529,9 +1830,12 @@ static bool d3d12_gfx_frame(
if (d3d12->menu.enabled)
#endif
{
D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->sprites.vbo_view);
D3D12RSSetViewports(d3d12->queue.cmd, 1,
&d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1,
&d3d12->chain.scissorRect);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1,
&d3d12->sprites.vbo_view);
}
#endif
@@ -1544,10 +1848,14 @@ static bool d3d12_gfx_frame(
{
if (osd_params)
{
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe_blend);
D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->sprites.vbo_view);
D3D12SetPipelineState(d3d12->queue.cmd,
d3d12->sprites.pipe_blend);
D3D12RSSetViewports(d3d12->queue.cmd, 1,
&d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1,
&d3d12->chain.scissorRect);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1,
&d3d12->sprites.vbo_view);
font_driver_render_msg(d3d12, stat_text,
(const struct font_params*)osd_params, NULL);
}
@@ -1557,17 +1865,21 @@ static bool d3d12_gfx_frame(
{
if (d3d12->overlays.fullscreen)
{
D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
D3D12RSSetViewports(d3d12->queue.cmd, 1,
&d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1,
&d3d12->chain.scissorRect);
}
else
{
D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->frame.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->frame.scissorRect);
D3D12RSSetViewports(d3d12->queue.cmd, 1,
&d3d12->frame.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1,
&d3d12->frame.scissorRect);
}
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->overlays.vbo_view);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1,
&d3d12->overlays.vbo_view);
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe_blend);
D3D12SetGraphicsRootDescriptorTable(
@@ -1582,7 +1894,8 @@ static bool d3d12_gfx_frame(
d3d12);
D3D12SetGraphicsRootDescriptorTable(
d3d12->queue.cmd, ROOT_ID_TEXTURE_T, d3d12->overlays.textures[i].gpu_descriptor[0]);
d3d12->queue.cmd, ROOT_ID_TEXTURE_T,
d3d12->overlays.textures[i].gpu_descriptor[0]);
D3D12DrawInstanced(d3d12->queue.cmd, 1, 1, i, 0);
}
}
@@ -1595,31 +1908,83 @@ static bool d3d12_gfx_frame(
if (msg && *msg)
{
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe_blend);
D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->sprites.vbo_view);
D3D12SetPipelineState(d3d12->queue.cmd,
d3d12->sprites.pipe_blend);
D3D12RSSetViewports(d3d12->queue.cmd, 1,
&d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1,
&d3d12->chain.scissorRect);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1,
&d3d12->sprites.vbo_view);
font_driver_render_msg(d3d12, msg, NULL, NULL);
}
d3d12->sprites.enabled = false;
#ifdef HAVE_DXGI_HDR
/* Copy over back buffer to swap chain render targets */
if (d3d12->hdr.enable)
{
d3d12_resource_transition(
d3d12->queue.cmd,
d3d12->chain.renderTargets[d3d12->chain.frame_index],
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET);
d3d12_resource_transition(
d3d12->queue.cmd, d3d12->chain.back_buffer.handle,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
D3D12SetPipelineState(d3d12->queue.cmd,
d3d12->pipes[VIDEO_SHADER_STOCK_HDR]);
D3D12OMSetRenderTargets(
d3d12->queue.cmd, 1,
&d3d12->chain.desc_handles[d3d12->chain.frame_index],
FALSE, NULL);
D3D12ClearRenderTargetView(
d3d12->queue.cmd,
d3d12->chain.desc_handles[d3d12->chain.frame_index],
d3d12->chain.clearcolor, 0, NULL);
D3D12SetGraphicsRootSignature(d3d12->queue.cmd,
d3d12->desc.rootSignature);
d3d12_set_texture(d3d12->queue.cmd, &d3d12->chain.back_buffer);
d3d12_set_sampler(d3d12->queue.cmd,
d3d12->samplers[RARCH_FILTER_UNSPEC][RARCH_WRAP_DEFAULT]);
D3D12SetGraphicsRootConstantBufferView(
d3d12->queue.cmd, ROOT_ID_UBO,
d3d12->hdr.ubo_view.BufferLocation);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1,
&d3d12->frame.vbo_view);
D3D12IASetPrimitiveTopology(d3d12->queue.cmd,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D12RSSetViewports(d3d12->queue.cmd, 1,
&d3d12->chain.viewport);
D3D12RSSetScissorRects(d3d12->queue.cmd, 1,
&d3d12->chain.scissorRect);
D3D12DrawInstanced(d3d12->queue.cmd, 4, 1, 0, 0);
}
#endif
d3d12_resource_transition(
d3d12->queue.cmd, d3d12->chain.renderTargets[d3d12->chain.frame_index],
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
d3d12->queue.cmd,
d3d12->chain.renderTargets[d3d12->chain.frame_index],
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT);
D3D12CloseGraphicsCommandList(d3d12->queue.cmd);
D3D12ExecuteGraphicsCommandLists(d3d12->queue.handle, 1, &d3d12->queue.cmd);
D3D12ExecuteGraphicsCommandLists(d3d12->queue.handle, 1,
&d3d12->queue.cmd);
#if defined(_WIN32) && !defined(__WINRT__)
win32_update_title();
#endif
#if 1
DXGIPresent(d3d12->chain.handle, sync_interval, present_flags);
#else
DXGI_PRESENT_PARAMETERS pp = { 0 };
DXGIPresent1(d3d12->swapchain, 0, 0, &pp);
#endif
/* Sync after Present for minimal delay */
d3d12_gfx_sync(d3d12);
@@ -1890,6 +2255,17 @@ static const video_poke_interface_t d3d12_poke_interface = {
d3d12_gfx_get_current_shader,
NULL, /* get_current_software_framebuffer */
NULL, /* get_hw_render_interface */
#ifdef HAVE_DXGI_HDR
d3d12_set_hdr_max_nits,
d3d12_set_hdr_paper_white_nits,
d3d12_set_hdr_contrast,
d3d12_set_hdr_expand_gamut,
#else
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
#endif
};
static void d3d12_gfx_get_poke_interface(void* data, const video_poke_interface_t** iface)
+5 -1
View File
@@ -1831,7 +1831,11 @@ static const video_poke_interface_t d3d_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void d3d8_get_poke_interface(void *data,
+5 -1
View File
@@ -1976,7 +1976,11 @@ static const video_poke_interface_t d3d9_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void d3d9_get_poke_interface(void *data,
+120
View File
@@ -0,0 +1,120 @@
#define SRC(...) #__VA_ARGS__
SRC(
struct UBO
{
float4x4 modelViewProj;
float contrast; /* 2.0f; */
float paperWhiteNits; /* 200.0f; */
float maxNits; /* 1000.0f; */
float expandGamut; /* 1.0f; */
};
uniform UBO global;
struct PSInput
{
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
float4 color : COLOR;
};
PSInput VSMain(float4 position : POSITION, float2 texcoord : TEXCOORD0, float4 color : COLOR)
{
PSInput result;
result.position = mul(global.modelViewProj, position);
result.texcoord = texcoord;
result.color = color;
return result;
}
uniform sampler s0;
uniform Texture2D <float4> t0;
static const float kMaxNitsFor2084 = 10000.0f;
static const float kEpsilon = 0.0001f;
static const float kLumaChannelRatio = 0.25f;
static const float3x3 k709to2020 =
{
{ 0.6274040f, 0.3292820f, 0.0433136f },
{ 0.0690970f, 0.9195400f, 0.0113612f },
{ 0.0163916f, 0.0880132f, 0.8955950f }
};
static const float3x3 kP3to2020 =
{
{ 0.753845f, 0.198593f, 0.047562f },
{ 0.0457456f, 0.941777f, 0.0124772f },
{ -0.00121055f, 0.0176041f, 0.983607f }
};
/* START Converted from (Copyright (c) Microsoft Corporation - Licensed under the MIT License.) https://github.com/microsoft/Xbox-ATG-Samples/tree/master/Kits/ATGTK/HDR */
static const float3x3 kExpanded709to2020 =
{
{ 0.6274040f, 0.3292820f, 0.0433136f },
{ 0.0457456, 0.941777, 0.0124772 },
{ -0.00121055, 0.0176041, 0.983607 }
};
float3 LinearToST2084(float3 normalizedLinearValue)
{
float3 ST2084 = pow((0.8359375f + 18.8515625f * pow(abs(normalizedLinearValue), 0.1593017578f)) / (1.0f + 18.6875f * pow(abs(normalizedLinearValue), 0.1593017578f)), 78.84375f);
return ST2084; /* Don't clamp between [0..1], so we can still perform operations on scene values higher than 10,000 nits */
}
/* END Converted from (Copyright (c) Microsoft Corporation - Licensed under the MIT License.) https://github.com/microsoft/Xbox-ATG-Samples/tree/master/Kits/ATGTK/HDR */
float3 SRGBToLinear(float3 color)
{
float3 scale = color / 12.92f;
float3 gamma = pow(abs(color + 0.055f) / 1.055f, 2.4f);
return float3( color.x < 0.04045f ? scale.x : gamma.x,
color.y < 0.04045f ? scale.y : gamma.y,
color.z < 0.04045f ? scale.z : gamma.z);
}
float4 Hdr(float4 sdr)
{
sdr.xyz = pow(abs(sdr.xyz), 2.2f / global.contrast); /* Display Gamma - needs to be determined by calibration screen but should be in the 0.8 - 1.4 range */
float luma = dot(sdr.xyz, float3(0.2126, 0.7152, 0.0722)); /* Rec BT.709 luma coefficients - https://en.wikipedia.org/wiki/Luma_(video) */
/* Inverse reinhard tonemap */
float maxValue = (global.maxNits / global.paperWhiteNits) + kEpsilon;
float elbow = maxValue / (maxValue - 1.0f); /* Convert (1.0 + epsilon) to infinite to range 1001 -> 1.0 */
float offset = 1.0f - ((0.5f * elbow) / (elbow - 0.5f)); /* Convert 1001 to 1.0 to range 0.5 -> 1.0 */
float hdrLumaInvTonemap = offset + ((luma * elbow) / (elbow - luma));
float sdrLumaInvTonemap = luma / ((1.0f + kEpsilon) - luma); /* Convert the srd < 0.5 to 0.0 -> 1.0 range */
float lumaInvTonemap = (luma > 0.5f) ? hdrLumaInvTonemap : sdrLumaInvTonemap;
float3 perLuma = sdr.xyz / (luma + kEpsilon) * lumaInvTonemap;
float3 hdrInvTonemap = offset + ((sdr.xyz * elbow) / (elbow - sdr.xyz));
float3 sdrInvTonemap = sdr.xyz / ((1.0f + kEpsilon) - sdr.xyz); /* Convert the srd < 0.5 to 0.0 -> 1.0 range */
float3 perChannel = float3(sdr.x > 0.5f ? hdrInvTonemap.x : sdrInvTonemap.x,
sdr.y > 0.5f ? hdrInvTonemap.y : sdrInvTonemap.y,
sdr.z > 0.5f ? hdrInvTonemap.z : sdrInvTonemap.z);
float3 hdr = lerp(perLuma, perChannel, kLumaChannelRatio);
/* Now convert into HDR10 */
float3 rec2020 = mul(k709to2020, hdr);
if(global.expandGamut > 0.0f)
{
rec2020 = mul( kExpanded709to2020, hdr);
}
float3 linearColour = rec2020 * (global.paperWhiteNits / kMaxNitsFor2084);
float3 hdr10 = LinearToST2084(linearColour);
return float4(hdr10, sdr.w);
}
float4 PSMain(PSInput input) : SV_TARGET
{
float4 sdr = input.color * t0.Sample(s0, input.texcoord);
return Hdr(sdr);
};
)
+5 -1
View File
@@ -600,7 +600,11 @@ static const video_poke_interface_t dispmanx_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void dispmanx_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -956,7 +956,11 @@ static const video_poke_interface_t drm_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void drm_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -1498,7 +1498,11 @@ static const video_poke_interface_t exynos_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void exynos_gfx_get_poke_interface(void *data,
+4
View File
@@ -386,6 +386,10 @@ static const video_poke_interface_t fpga_poke_interface = {
#ifdef HAVE_MENU
NULL,
#endif
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void fpga_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -724,7 +724,11 @@ static const video_poke_interface_t gdi_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void gdi_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -4588,7 +4588,11 @@ static const video_poke_interface_t gl2_poke_interface = {
NULL,
gl2_get_current_shader,
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void gl2_get_poke_interface(void *data,
+5 -1
View File
@@ -1448,7 +1448,11 @@ static const video_poke_interface_t gl1_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void gl1_gfx_get_poke_interface(void *data,
+4
View File
@@ -2287,6 +2287,10 @@ static const video_poke_interface_t gl_core_poke_interface = {
gl_core_get_current_shader,
NULL,
NULL,
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void gl_core_get_poke_interface(void *data,
+4
View File
@@ -1735,6 +1735,10 @@ static const video_poke_interface_t wiiu_poke_interface = {
wiiu_gfx_get_current_shader,
NULL, /* get_current_software_framebuffer */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void wiiu_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -1372,7 +1372,11 @@ static const video_poke_interface_t gx_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void gx_get_poke_interface(void *data,
+25 -13
View File
@@ -399,19 +399,31 @@ static uint32_t metal_get_flags(void *data)
}
static const video_poke_interface_t metal_poke_interface = {
.get_flags = metal_get_flags,
.load_texture = metal_load_texture,
.unload_texture = metal_unload_texture,
.set_video_mode = metal_set_video_mode,
.get_refresh_rate = metal_get_refresh_rate,
.set_filtering = metal_set_filtering,
.set_aspect_ratio = metal_set_aspect_ratio,
.apply_state_changes = metal_apply_state_changes,
.set_texture_frame = metal_set_texture_frame,
.set_texture_enable = metal_set_texture_enable,
.set_osd_msg = font_driver_render_msg,
.show_mouse = metal_show_mouse,
.get_current_shader = metal_get_current_shader,
metal_get_flags,
metal_load_texture,
metal_unload_texture,
metal_set_video_mode,
metal_get_refresh_rate,
metal_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 */
metal_set_aspect_ratio,
metal_apply_state_changes,
metal_set_texture_frame,
metal_set_texture_enable,
font_driver_render_msg,
metal_show_mouse,
NULL, /* grab_mouse_toggle */
metal_get_current_shader,
NULL, /* get_current_software_framebuffer */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void metal_get_poke_interface(void *data,
+5 -1
View File
@@ -1123,7 +1123,11 @@ static const video_poke_interface_t omap_gfx_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void omap_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -465,7 +465,11 @@ static const video_poke_interface_t ps2_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
ps2_get_hw_render_interface /* get_hw_render_interface */
ps2_get_hw_render_interface, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void ps2_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -802,7 +802,11 @@ static const video_poke_interface_t psp_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void psp_get_poke_interface(void *data,
+5 -1
View File
@@ -720,7 +720,11 @@ static const video_poke_interface_t rsx_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void rsx_get_poke_interface(void* data,
+5 -1
View File
@@ -1106,7 +1106,11 @@ static const video_poke_interface_t sdl_dingux_poke_interface = {
NULL, /* sdl_grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void sdl_dingux_get_poke_interface(void *data, const video_poke_interface_t **iface)
+5 -1
View File
@@ -547,7 +547,11 @@ static const video_poke_interface_t sdl_poke_interface = {
sdl_grab_mouse_toggle,
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void sdl_get_poke_interface(void *data, const video_poke_interface_t **iface)
+5 -1
View File
@@ -1393,7 +1393,11 @@ static const video_poke_interface_t sdl_rs90_poke_interface = {
NULL, /* sdl_grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void sdl_rs90_get_poke_interface(void *data, const video_poke_interface_t **iface)
+4
View File
@@ -551,6 +551,10 @@ static const video_poke_interface_t sixel_poke_interface = {
NULL,
NULL,
NULL,
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void sixel_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -951,7 +951,11 @@ static const video_poke_interface_t sunxi_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void sunxi_gfx_get_poke_interface(void *data,
+4
View File
@@ -397,6 +397,10 @@ static const video_poke_interface_t switch_poke_interface = {
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void switch_get_poke_interface(void *data,
+4
View File
@@ -682,6 +682,10 @@ static const video_poke_interface_t switch_poke_interface = {
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void switch_get_poke_interface(void *data,
+5 -1
View File
@@ -385,7 +385,11 @@ static const video_poke_interface_t vga_poke_interface = {
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void vga_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -824,7 +824,11 @@ static const video_poke_interface_t vita_poke_interface = {
NULL,
NULL,
vita_get_current_sw_framebuffer,
NULL
NULL,
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void vita2d_gfx_get_poke_interface(void *data,
+5 -1
View File
@@ -1894,7 +1894,7 @@ static bool vulkan_frame(void *data, const void *frame,
if (vk->hw.enable)
{
/* Does this make that this can happen at all? */
if (vk->hw.image)
if (vk->hw.image && vk->hw.image->create_info.image)
{
input.image = vk->hw.image->create_info.image;
input.view = vk->hw.image->image_view;
@@ -2638,6 +2638,10 @@ static const video_poke_interface_t vulkan_poke_interface = {
vulkan_get_current_shader,
vulkan_get_current_sw_framebuffer,
vulkan_get_hw_render_interface,
NULL, /* set_hdr_max_nits */
NULL, /* set_hdr_paper_white_nits */
NULL, /* set_hdr_contrast */
NULL /* set_hdr_expand_gamut */
};
static void vulkan_get_poke_interface(void *data,
+46 -19
View File
@@ -42,7 +42,8 @@
typedef struct
{
ctr_texture_t texture;
ctr_scale_vector_t scale_vector;
ctr_scale_vector_t scale_vector_top;
ctr_scale_vector_t scale_vector_bottom;
const font_renderer_driver_t* font_driver;
void* font_data;
} ctr_font_t;
@@ -95,7 +96,15 @@ static void* ctr_font_init_font(void* data, const char* font_path,
linearFree(tmp);
#endif
ctr_set_scale_vector(&font->scale_vector, 400, 240, font->texture.width, font->texture.height);
ctr_set_scale_vector(&font->scale_vector_top,
CTR_TOP_FRAMEBUFFER_WIDTH,
CTR_TOP_FRAMEBUFFER_HEIGHT,
font->texture.width, font->texture.height);
ctr_set_scale_vector(&font->scale_vector_bottom,
CTR_BOTTOM_FRAMEBUFFER_WIDTH,
CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
font->texture.width, font->texture.height);
return font;
}
@@ -174,11 +183,12 @@ static void ctr_font_render_line(
switch (text_align)
{
case TEXT_ALIGN_RIGHT:
x -= ctr_font_get_message_width(font, msg, msg_len, scale);
x += width - ctr_font_get_message_width(font, msg, msg_len, scale);
break;
case TEXT_ALIGN_CENTER:
x -= ctr_font_get_message_width(font, msg, msg_len, scale) / 2;
x += width / 2 -
ctr_font_get_message_width(font, msg, msg_len, scale) / 2;
break;
}
@@ -231,7 +241,11 @@ static void ctr_font_render_line(
return;
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
ctrGuSetVertexShaderFloatUniform(0, (float*)&font->scale_vector, 1);
if (!ctr->render_font_bottom)
ctrGuSetVertexShaderFloatUniform(0, (float*)&font->scale_vector_top, 1);
else
ctrGuSetVertexShaderFloatUniform(0, (float*)&font->scale_vector_bottom, 1);
GSPGPU_FlushDataCache(ctr->vertex_cache.current,
(v - ctr->vertex_cache.current) * sizeof(ctr_vertex_t));
ctrGuSetAttributeBuffers(2,
@@ -261,20 +275,31 @@ static void ctr_font_render_line(
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
GPU_L8);
GPU_SetViewport(NULL,
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
ctr->video_mode == CTR_VIDEO_MODE_2D_800X240
? CTR_TOP_FRAMEBUFFER_WIDTH * 2 : CTR_TOP_FRAMEBUFFER_WIDTH);
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, v - ctr->vertex_cache.current);
if (ctr->video_mode == CTR_VIDEO_MODE_3D)
if (!ctr->render_font_bottom)
{
GPU_SetViewport(NULL,
VIRT_TO_PHYS(ctr->drawbuffers.top.right),
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
CTR_TOP_FRAMEBUFFER_WIDTH);
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
ctr->video_mode == CTR_VIDEO_MODE_2D_800X240
? CTR_TOP_FRAMEBUFFER_WIDTH * 2 : CTR_TOP_FRAMEBUFFER_WIDTH);
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, v - ctr->vertex_cache.current);
if (ctr->video_mode == CTR_VIDEO_MODE_3D)
{
GPU_SetViewport(NULL,
VIRT_TO_PHYS(ctr->drawbuffers.top.right),
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
CTR_TOP_FRAMEBUFFER_WIDTH);
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, v - ctr->vertex_cache.current);
}
}
else
{
GPU_SetViewport(NULL,
VIRT_TO_PHYS(ctr->drawbuffers.bottom),
0, 0, CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
CTR_BOTTOM_FRAMEBUFFER_WIDTH);
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, v - ctr->vertex_cache.current);
}
@@ -363,8 +388,10 @@ static void ctr_font_render_msg(
alpha, r_dark, g_dark, b_dark, alpha_dark;
ctr_font_t * font = (ctr_font_t*)data;
ctr_video_t *ctr = (ctr_video_t*)userdata;
unsigned width = ctr->vp.full_width;
unsigned height = ctr->vp.full_height;
unsigned width = ctr->render_font_bottom ?
CTR_BOTTOM_FRAMEBUFFER_WIDTH : CTR_TOP_FRAMEBUFFER_WIDTH;
unsigned height = ctr->render_font_bottom ?
CTR_BOTTOM_FRAMEBUFFER_HEIGHT : CTR_TOP_FRAMEBUFFER_HEIGHT;
settings_t *settings = config_get_ptr();
float video_msg_pos_x = settings->floats.video_msg_pos_x;
float video_msg_pos_y = settings->floats.video_msg_pos_y;
+10 -64
View File
@@ -159,6 +159,7 @@ static float gfx_display_get_widget_dpi_scale(
return adjusted_scale;
}
#if defined(HAVE_MENU) && defined(HAVE_XMB)
static float gfx_display_get_widget_pixel_scale(
gfx_display_t *p_disp,
settings_t *settings,
@@ -237,7 +238,7 @@ static float gfx_display_get_widget_pixel_scale(
return adjusted_scale;
}
#endif
static void msg_widget_msg_transition_animation_done(void *userdata)
{
@@ -715,66 +716,6 @@ void gfx_widgets_draw_icon(
dispctx->draw(&draw, userdata, video_width, video_height);
}
#ifdef HAVE_TRANSLATE
static void gfx_widgets_draw_icon_blend(
void *userdata,
gfx_display_t *p_disp,
gfx_display_ctx_driver_t *dispctx,
unsigned video_width,
unsigned video_height,
unsigned icon_width,
unsigned icon_height,
uintptr_t texture,
float x, float y,
float rotation,
float scale_factor,
float *color)
{
math_matrix_4x4 mymat;
gfx_display_ctx_draw_t draw;
struct video_coords coords;
gfx_display_ctx_rotate_draw_t rotate_draw;
rotate_draw.matrix = &mymat;
rotate_draw.rotation = rotation;
rotate_draw.scale_x = scale_factor;
rotate_draw.scale_y = scale_factor;
rotate_draw.scale_z = 1;
rotate_draw.scale_enable = true;
gfx_display_rotate_z(p_disp, &rotate_draw, userdata);
coords.vertices = 4;
coords.vertex = NULL;
coords.tex_coord = NULL;
coords.lut_tex_coord = NULL;
coords.color = color;
draw.x = x;
draw.y = video_height - y - icon_height;
draw.width = icon_width;
draw.height = icon_height;
draw.scale_factor = scale_factor;
draw.rotation = rotation;
draw.coords = &coords;
draw.matrix_data = &mymat;
draw.texture = texture;
draw.prim_type = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
draw.pipeline_id = 0;
if (dispctx)
{
if (dispctx->blend_begin)
dispctx->blend_begin(userdata);
if (draw.height > 0 && draw.width > 0)
if (dispctx->draw)
dispctx->draw(&draw, userdata, video_width, video_height);
if (dispctx->blend_end)
dispctx->blend_end(userdata);
}
}
#endif
void gfx_widgets_draw_text(
gfx_widget_font_data_t* font_data,
const char *text,
@@ -908,7 +849,7 @@ static void gfx_widgets_font_init(
font_data->line_descender = (float)font_driver_get_line_descender(font_data->font, 1.0f);
font_data->line_centre_offset = (float)font_driver_get_line_centre_offset(font_data->font, 1.0f);
font_data->usage_count = 0;
font_data->usage_count = 0;
}
@@ -1650,10 +1591,12 @@ void gfx_widgets_frame(void *data)
gfx_display_set_alpha(p_dispwidget->pure_white, 1.0f);
if (p_dispwidget->ai_service_overlay_texture)
gfx_widgets_draw_icon_blend(
{
if (dispctx->blend_begin)
dispctx->blend_begin(userdata);
gfx_widgets_draw_icon(
userdata,
p_disp,
dispctx,
video_width,
video_height,
video_width,
@@ -1665,6 +1608,9 @@ void gfx_widgets_frame(void *data)
1,
p_dispwidget->pure_white
);
if (dispctx->blend_end)
dispctx->blend_end(userdata);
}
/* top line */
gfx_display_draw_quad(
-2
View File
@@ -54,7 +54,6 @@ ldflags := -dynamiclib
MINVERFLAGS=
ifeq ($(shell uname -p),arm)
MINVERFLAGS = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS (Metal, ARM 64bit)
MINVERFLAGS += -DDONT_WANT_ARM_ASM_OPTIMIZATIONS
else ifeq ($(HAVE_METAL),1)
MINVERFLAGS = -mmacosx-version-min=10.13 -stdlib=libc++ # macOS (Metal, x86 64bit)
else ifeq ($(shell uname -p),powerpc)
@@ -68,7 +67,6 @@ ldflags := -dynamiclib
# Build for a specific architecture when ARCH is defined as a switch
ifeq ($(ARCH),arm64)
MINVERFLAGS = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS (Metal, ARM 64bit)
MINVERFLAGS += -DDONT_WANT_ARM_ASM_OPTIMIZATIONS
ARCHFLAGS = -arch arm64
else ifeq ($(ARCH),x86_64)
ifeq ($(HAVE_METAL),1)
+85 -1
View File
@@ -366,6 +366,34 @@ static bool video_thread_handle_packet(
/* Never reply on no command. Possible deadlock if
* thread sends command right after frame update. */
break;
case CMD_POKE_SET_HDR_MAX_NITS:
if (thr->poke && thr->poke->set_hdr_max_nits)
thr->poke->set_hdr_max_nits(thr->driver_data,
pkt.data.hdr.max_nits);
video_thread_reply(thr, &pkt);
break;
case CMD_POKE_SET_HDR_PAPER_WHITE_NITS:
if (thr->poke && thr->poke->set_hdr_paper_white_nits)
thr->poke->set_hdr_paper_white_nits(thr->driver_data,
pkt.data.hdr.paper_white_nits);
video_thread_reply(thr, &pkt);
break;
case CMD_POKE_SET_HDR_CONTRAST:
if (thr->poke && thr->poke->set_hdr_contrast)
thr->poke->set_hdr_contrast(thr->driver_data,
pkt.data.hdr.contrast);
video_thread_reply(thr, &pkt);
break;
case CMD_POKE_SET_HDR_EXPAND_GAMUT:
if (thr->poke && thr->poke->set_hdr_expand_gamut)
thr->poke->set_hdr_expand_gamut(thr->driver_data,
pkt.data.hdr.expand_gamut);
video_thread_reply(thr, &pkt);
break;
default:
video_thread_reply(thr, &pkt);
break;
@@ -931,6 +959,58 @@ static void thread_set_filtering(void *data, unsigned idx, bool smooth, bool ctx
video_thread_send_and_wait_user_to_thread(thr, &pkt);
}
static void thread_set_hdr_max_nits(void *data, float max_nits)
{
thread_packet_t pkt;
thread_video_t *thr = (thread_video_t*)data;
if (!thr)
return;
pkt.type = CMD_POKE_SET_HDR_MAX_NITS;
pkt.data.hdr.max_nits = max_nits;
video_thread_send_and_wait_user_to_thread(thr, &pkt);
}
static void thread_set_hdr_paper_white_nits(void *data, float paper_white_nits)
{
thread_packet_t pkt;
thread_video_t *thr = (thread_video_t*)data;
if (!thr)
return;
pkt.type = CMD_POKE_SET_HDR_PAPER_WHITE_NITS;
pkt.data.hdr.paper_white_nits = paper_white_nits;
video_thread_send_and_wait_user_to_thread(thr, &pkt);
}
static void thread_set_hdr_contrast(void *data, float contrast)
{
thread_packet_t pkt;
thread_video_t *thr = (thread_video_t*)data;
if (!thr)
return;
pkt.type = CMD_POKE_SET_HDR_CONTRAST;
pkt.data.hdr.contrast = contrast;
video_thread_send_and_wait_user_to_thread(thr, &pkt);
}
static void thread_set_hdr_expand_gamut(void *data, bool expand_gamut)
{
thread_packet_t pkt;
thread_video_t *thr = (thread_video_t*)data;
if (!thr)
return;
pkt.type = CMD_POKE_SET_HDR_EXPAND_GAMUT;
pkt.data.hdr.expand_gamut = expand_gamut;
video_thread_send_and_wait_user_to_thread(thr, &pkt);
}
static void thread_get_video_output_size(void *data,
unsigned *width, unsigned *height)
{
@@ -1132,7 +1212,11 @@ static const video_poke_interface_t thread_poke = {
thread_get_current_shader,
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
NULL, /* get_hw_render_interface */
thread_set_hdr_max_nits,
thread_set_hdr_paper_white_nits,
thread_set_hdr_contrast,
thread_set_hdr_expand_gamut
};
static void video_thread_get_poke_interface(
+13
View File
@@ -57,6 +57,11 @@ enum thread_cmd
CMD_POKE_SHOW_MOUSE,
CMD_POKE_GRAB_MOUSE_TOGGLE,
CMD_POKE_SET_HDR_MAX_NITS,
CMD_POKE_SET_HDR_PAPER_WHITE_NITS,
CMD_POKE_SET_HDR_CONTRAST,
CMD_POKE_SET_HDR_EXPAND_GAMUT,
CMD_DUMMY = INT_MAX
};
@@ -150,6 +155,14 @@ struct thread_packet
bool is_threaded;
enum font_driver_render_api api;
} font_init;
struct
{
float max_nits;
float paper_white_nits;
float contrast;
bool expand_gamut;
} hdr;
} data;
enum thread_cmd type;
};
+2 -10
View File
@@ -1369,6 +1369,7 @@ MENU
#endif
#ifdef HAVE_MENU
#include "../menu/menu_driver.c"
#include "../menu/menu_setting.c"
#if defined(HAVE_MATERIALUI) || defined(HAVE_XMB) || defined(HAVE_OZONE)
#include "../menu/menu_screensaver.c"
@@ -1406,16 +1407,7 @@ MENU
#endif
#ifdef HAVE_OZONE
#include "../menu/drivers/ozone/ozone.c"
#include "../menu/drivers/ozone/ozone_display.c"
#include "../menu/drivers/ozone/ozone_entries.c"
#include "../menu/drivers/ozone/ozone_sidebar.c"
#include "../menu/drivers/ozone/ozone_texture.c"
#include "../menu/drivers/ozone/ozone_theme.c"
#endif
#ifdef HAVE_STRIPES
#include "../menu/drivers/stripes.c"
#include "../menu/drivers/ozone.c"
#endif
#ifdef HAVE_MATERIALUI
-8
View File
@@ -32,9 +32,6 @@
static uint32_t pad_state;
static int16_t analog_state[DEFAULT_MAX_PADS][2][2];
/* TODO/FIXME - global referenced outside */
extern uint64_t lifecycle_state;
static const char *ctr_joypad_name(unsigned pad)
{
return "3DS Controller";
@@ -193,11 +190,6 @@ static void ctr_joypad_poll(void)
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_X] = ctr_joypad_fix_range(state_tmp_right_analog.dx);
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_Y] = -ctr_joypad_fix_range(state_tmp_right_analog.dy);
BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE);
if((state_tmp & KEY_TOUCH) && (state_tmp_touch.py > 120))
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
/* panic button */
if((state_tmp & KEY_START) &&
(state_tmp & KEY_SELECT) &&
-21
View File
@@ -650,29 +650,8 @@ size_t input_config_get_device_name_size(unsigned port);
/*****************************************************************************/
/**
* Save the current keybinds on a port to the config file.
*
* @param conf pointer to config file object
* @param user user number (ie port - TODO: change to port nomenclature)
*/
void input_config_save_keybinds_user(void *data, unsigned user);
const struct retro_keybind *input_config_get_bind_auto(unsigned port, unsigned id);
/**
* Save a key binding to the config file.
*
* @param conf pointer to config file object
* @param prefix prefix name of keybind
* @param base base name of keybind
* @param bind pointer to key binding object
* @param kb save keyboard binds
*/
void input_config_save_keybind(void *data, const char *prefix,
const char *base, const struct retro_keybind *bind,
bool save_empty);
void input_config_reset_autoconfig_binds(unsigned port);
void input_config_reset(void);
+4
View File
@@ -0,0 +1,4 @@
{
"main-desc": "RetroArch is an open-source project that makes use of a powerful development interface called Libretro. Libretro is an interface that allows you to make cross-platform applications that can use rich features such as OpenGL, cross-platform camera support, location support, and more in the future.\n\nIt comes with its own built-in collection of applications to provide you with a 'one-stop-shop' for entertainment.\n\nLibretro and RetroArch are perfectly suited for creating games, emulators and multimedia programs. If you want to learn more, go to our website (listed below).\nIMPORTANT!!!\n\nRetroArch is a multi-versatile program, that means that in order for it to do anything, you need modular programs that we call 'cores'. These cores DO NOT COME OUT OF THE BOX. You need to go to \"Online Updater -> Core Updater\" from within the app to download them.\n\nFEATURES:\n* Eye-candy menus to choose from!\n* Scan files / directories and add them to game system collections!\n* View database information about each game once added to a collection!\n* Download programs ('cores') online\n* Update everything!\n* Download Game & Watch games and play them with our exclusive Game & Watch emulator!\n* Built-in input remapping\n* Ability to remap controls\n* Ability to enter and load cheats\n* Multi-language support!\n* Over 80+ programs('cores') now and counting!\n* Play multiplayer with NetPlay!\n* Take screenshots, save states and more!\n\n* No DRM\n* No restrictions on usage\n* Open-source\n* No push ads\n* No spying\n* No ads period\n\nJoin us on discord for support and netplay matchmaking\nhttps://discord.gg/C4amCeV\n\nVisit our Youtube channel here for tutorials, gameplays, news and development progress!\nhttps://www.youtube.com/user/libretro\nhttps://www.youtube.com/RetroArchOfficial\n\nFor info and help, see our documentation site -\nhttps://docs.libretro.com/\n\nVisit our website!\nhttps://www.retroarch.com/\n\nwww.libretro.com",
"short-desc": "Retro games and emulators on your device!"
}
+3 -4
View File
@@ -1545,10 +1545,6 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO,
"نسبة الجوانب المخصصة"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO,
"قيمة النقاط العائمة لنسبة عرض الفيديو (العرض / الارتفاع)، تستخدم إذا تم تعيين نسبة الجوانب إلى 'نسبة الجوانب المخصصة'."
)
#if defined(DINGUX)
#endif
MSG_HASH(
@@ -1576,6 +1572,9 @@ MSG_HASH(
"ارتفاع العرض المخصص الذي يتم استخدامه إذا تم تعيين نسبة الجانب إلى 'نسبة الجوانب المخصصة'."
)
/* Settings > Video > HDR */
/* Settings > Video > Synchronization */
MSG_HASH(
+3
View File
@@ -736,6 +736,9 @@ MSG_HASH(
#if defined(DINGUX)
#endif
/* Settings > Video > HDR */
/* Settings > Video > Synchronization */
+27 -4
View File
@@ -1284,6 +1284,10 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_SCALING_SETTINGS,
"更改视频缩放设置。"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_HDR_SETTINGS,
"更改视频 hdr 设置。"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_SYNCHRONIZATION_SETTINGS,
"同步"
@@ -1354,6 +1358,22 @@ MSG_HASH(
"最近邻"
)
#if defined(RS90)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE,
"图像插值"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE,
"当“整数缩放”被禁用时,指定图像内插法。“最近的邻里”对性能影响最小。"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_POINT,
"最近的邻里点"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ,
"半线性"
)
#endif
#endif
MSG_HASH(
@@ -1466,6 +1486,10 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_GPU_INDEX,
"GPU 编号"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_GPU_INDEX,
"选择要使用的显卡。"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE,
"垂直刷新率"
@@ -1605,10 +1629,6 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO,
"自定义宽高比"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_ASPECT_RATIO,
"视频宽高比的浮点数值 (宽度/高度),如果宽高比设置为「自定义宽高比」,则使用此数值。"
)
#if defined(DINGUX)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_IPU_KEEP_ASPECT,
@@ -1660,6 +1680,9 @@ MSG_HASH(
"在图像边缘切掉一些像素,这通常是游戏开发者有意留下的白边或黑边,甚至也有可能包含垃圾像素。"
)
/* Settings > Video > HDR */
/* Settings > Video > Synchronization */
MSG_HASH(
Loaded 100 of 226 files, more files were not shown because too many files have changed in this diff. Show more