mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-09 11:41:35 -10:00
Compare commits
79
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36888612eb | ||
|
|
f597138827 | ||
|
|
623e09dc47 | ||
|
|
b05a0d5aed | ||
|
|
536d18778b | ||
|
|
28d1788e1e | ||
|
|
017f9f8939 | ||
|
|
916ebb98e7 | ||
|
|
85c0607696 | ||
|
|
43838dc4ea | ||
|
|
f905012376 | ||
|
|
6d1c0e96a3 | ||
|
|
9a5f4602cc | ||
|
|
19f4504943 | ||
|
|
8adc24ecbc | ||
|
|
51dcad6cb3 | ||
|
|
204834f88e | ||
|
|
e39784189e | ||
|
|
87b40b7c57 | ||
|
|
588c1305c8 | ||
|
|
508b0c2ee2 | ||
|
|
743aea1810 | ||
|
|
76f114a9fe | ||
|
|
274638b89e | ||
|
|
b900555494 | ||
|
|
a0e4d64c3b | ||
|
|
93dbd746db | ||
|
|
7b9cbc08d7 | ||
|
|
9228a6f8ab | ||
|
|
f6f7d145d2 | ||
|
|
868865c388 | ||
|
|
ad01f5d5b6 | ||
|
|
48d9df6bb7 | ||
|
|
11b88c748e | ||
|
|
547f04b894 | ||
|
|
9ea6f15c1d | ||
|
|
d0d495edc3 | ||
|
|
a785bd8d80 | ||
|
|
256713e888 | ||
|
|
fb35460c6d | ||
|
|
5677799faf | ||
|
|
fc4081cd8f | ||
|
|
0db409d5b5 | ||
|
|
70ebc85b6c | ||
|
|
dbf3e278dd | ||
|
|
03c54a9854 | ||
|
|
8460618666 | ||
|
|
c6f2e52d62 | ||
|
|
7e61c7ab32 | ||
|
|
b68ace9e3d | ||
|
|
37aa13bb47 | ||
|
|
e384c2b099 | ||
|
|
1bafa70837 | ||
|
|
2406894329 | ||
|
|
220dfe4dbf | ||
|
|
bfc7e824fe | ||
|
|
2f14d2e4e2 | ||
|
|
cd126f0236 | ||
|
|
d2283a5237 | ||
|
|
d429ecf304 | ||
|
|
d45945cda2 | ||
|
|
943e14051c | ||
|
|
4b6a82a3b0 | ||
|
|
bf2e7b93f0 | ||
|
|
24721e6a1d | ||
|
|
0a1affba7a | ||
|
|
a9f1dd3647 | ||
|
|
540d192ecb | ||
|
|
f1f3998d28 | ||
|
|
46fb61bede | ||
|
|
cf7b30481b | ||
|
|
30db7d8cd3 | ||
|
|
2474fe3c2e | ||
|
|
5b3e5f5daa | ||
|
|
861cb2953a | ||
|
|
6dfe20e247 | ||
|
|
bb0fe6c2d1 | ||
|
|
45a16fab1b | ||
|
|
8396bd599d |
No files matched your search
Vendored
+149
-148
@@ -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
@@ -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
@@ -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
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -78,7 +78,6 @@ else
|
||||
HAVE_MATERIALUI = 0
|
||||
HAVE_XMB = 0
|
||||
HAVE_OZONE = 0
|
||||
HAVE_STRIPES = 0
|
||||
endif
|
||||
|
||||
include Makefile.common
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
Vendored
+21
@@ -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
|
||||
|
||||
Vendored
+182
@@ -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
@@ -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;
|
||||
|
||||
Vendored
+1
-1
@@ -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.
|
||||
|
||||
Vendored
+3
@@ -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
@@ -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);
|
||||
|
||||
Vendored
+3
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Vendored
+328
@@ -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
@@ -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[] = {
|
||||
|
||||
Vendored
+1
@@ -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)
|
||||
|
||||
Vendored
+1
@@ -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
@@ -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;
|
||||
|
||||
Vendored
+9
-8
@@ -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
@@ -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;
|
||||
|
||||
Vendored
+11
-25
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+95
-52
@@ -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);
|
||||
}
|
||||
Vendored
+55
-43
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Vendored
+29
-1
@@ -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
@@ -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) {
|
||||
|
||||
Vendored
+2
@@ -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;
|
||||
|
||||
Vendored
+13
-11
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+281
-20
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+45
-16
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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(¬_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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, ¤t_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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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),
|
||||
¶ms, 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),
|
||||
¶ms, 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),
|
||||
¶ms, 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),
|
||||
¶ms, 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),
|
||||
¶ms, 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),
|
||||
¶ms, 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),
|
||||
¶ms, NULL);
|
||||
|
||||
/* draw date */
|
||||
params.x = 0.266f;
|
||||
params.y = 0.87f;
|
||||
font_driver_render_msg_bottom(ctr, ctr->state_date,
|
||||
¶ms, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ctr_set_bottom_screen_enable(bool enabled)
|
||||
{
|
||||
Handle lcd_handle;
|
||||
u8 not_2DS;
|
||||
|
||||
CFGU_GetModelNintendo2DS(¬_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(¬_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(¬_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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
)
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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) &&
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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(
|
||||
|
||||
@@ -736,6 +736,9 @@ MSG_HASH(
|
||||
#if defined(DINGUX)
|
||||
#endif
|
||||
|
||||
/* Settings > Video > HDR */
|
||||
|
||||
|
||||
/* Settings > Video > Synchronization */
|
||||
|
||||
|
||||
|
||||
+27
-4
@@ -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
Reference in new issue
Block a user