Compare commits
336 Commits
Author | SHA1 | Date | |
---|---|---|---|
c9942b35bb | |||
ffe6904502 | |||
fcf9d29a62 | |||
9d7e68b7fc | |||
0a976f30c1 | |||
8e05af4389 | |||
d2b719ac5a | |||
4accbeba0d | |||
ee26b5b82f | |||
12a5265db1 | |||
eb8b463ca8 | |||
72c1785bf0 | |||
a2aca3dde6 | |||
c5f2267306 | |||
911fe5610c | |||
b3e0078041 | |||
eeb1ff7965 | |||
8721456944 | |||
a23fbae391 | |||
0a8f11ca63 | |||
8f194b5fff | |||
3b050668bb | |||
d054eea0c4 | |||
b9021ea469 | |||
223627c381 | |||
ad4339464a | |||
32cb44d2b9 | |||
39edca2cf7 | |||
0a3acc25d2 | |||
3f0bcf5913 | |||
2384c8f811 | |||
c26cb68a0c | |||
c34bc45bf1 | |||
19617f32c8 | |||
8396ce0b47 | |||
07f85cf639 | |||
dfd8ded206 | |||
06caa535d6 | |||
42bed30b98 | |||
74e75f1996 | |||
f04a6a4d83 | |||
33be1b744b | |||
2c9e0ec723 | |||
d1ac33b18b | |||
c00bdc4214 | |||
74be64b60a | |||
11ca327951 | |||
631da59392 | |||
e861c456c9 | |||
c3ab060576 | |||
94ee7c68fc | |||
8e8097e7c0 | |||
52683adedd | |||
e47c47245f | |||
004b83c978 | |||
4bff44c9a9 | |||
18ff007ff2 | |||
e41ceb3c88 | |||
14880862bc | |||
e651bb41bc | |||
8e93039ef9 | |||
65b02f35c7 | |||
d42ccb387a | |||
ee0a7476b3 | |||
45ffc56733 | |||
be8ee3d706 | |||
ab688170f0 | |||
274f6093f3 | |||
9662425337 | |||
6fde9b3354 | |||
e5907f0979 | |||
2855d30815 | |||
546c7b3bfd | |||
41c10cd5a7 | |||
bc77e16653 | |||
6ba83db6dd | |||
96effa46e4 | |||
e7a1318773 | |||
ffc9e34281 | |||
20fc09df13 | |||
6c78abb015 | |||
0d3434734a | |||
42a6f7a42e | |||
95e6428d33 | |||
d9ed4600ca | |||
612647f94f | |||
6a16a8f60d | |||
1ffd9f08af | |||
c855d84492 | |||
d461778296 | |||
3fe0130fdb | |||
b0880f0ef8 | |||
0bb2e8c618 | |||
84ccb45c5c | |||
f8b853d001 | |||
61e0725d9d | |||
2b9ab33af3 | |||
09350f71e8 | |||
582c438441 | |||
bc10681156 | |||
faefc5cfe1 | |||
fd09f1471e | |||
c1c68a3487 | |||
5849d29fc1 | |||
b31b6e35a2 | |||
79a53c8003 | |||
fd9525acc2 | |||
938ec204f5 | |||
7c8bfbb078 | |||
d7bf139e85 | |||
df7f1b13cb | |||
e08e644e73 | |||
ccf36b5e25 | |||
b6427d0ee0 | |||
5c401b8ea0 | |||
bd3571db5a | |||
b18710e4df | |||
69b66cb41d | |||
a5f86e9813 | |||
920492925c | |||
0381081c5d | |||
382b64d3c0 | |||
a629aa0dde | |||
b29f263e1b | |||
48d3093fc8 | |||
f77491196c | |||
0fce3e556f | |||
12e69913c2 | |||
89217f8c4b | |||
247b6900c7 | |||
1e42a40640 | |||
7eab7b4151 | |||
e9ccd51286 | |||
9f385ddeb7 | |||
ab73566acc | |||
1e3971038f | |||
306943532c | |||
27698b0c93 | |||
d6cab3ab40 | |||
cbd9a6ffe3 | |||
4752818920 | |||
131129062b | |||
fad1ee7140 | |||
b9ca7bef3f | |||
0e0771ad74 | |||
489248e77f | |||
f593268476 | |||
8fcc3d2121 | |||
a3a8964d46 | |||
c8d614139c | |||
25fe723fa6 | |||
2335b47f4b | |||
10a7b60b12 | |||
98ab3c9610 | |||
0ca25b64e1 | |||
694e49b857 | |||
381db8452b | |||
e2076f2385 | |||
9c206db630 | |||
447f29285f | |||
26a9002d97 | |||
a12748d79e | |||
5abfdff66a | |||
8a315d0c8f | |||
4ee36e05b6 | |||
11061f36e6 | |||
6d286d5f8c | |||
4619ed086c | |||
3843122cf8 | |||
d320eef663 | |||
a7a9b94a30 | |||
a9f2a69487 | |||
78965ba18d | |||
52c41d185b | |||
c5c041de89 | |||
e46a88f24a | |||
8779cb7785 | |||
a6ca7dca61 | |||
cce6a79a91 | |||
230a463a39 | |||
83e734bd6a | |||
72ee29669a | |||
b1a02e1710 | |||
2c34f41747 | |||
60d59730a9 | |||
850ec1f8b8 | |||
3da6c25fd8 | |||
0e987959a6 | |||
410b8b8809 | |||
d3392ae0b1 | |||
98e0ecf6a7 | |||
ad45b9880d | |||
0d1646e4df | |||
96f0746ab9 | |||
09dcd48257 | |||
62fc1f835e | |||
3b351c33d1 | |||
793485d201 | |||
3ef5ab7323 | |||
618c80c803 | |||
f7cb308243 | |||
b8583f9af3 | |||
33bf2b7c2d | |||
d48e6c04ce | |||
88f34a7d69 | |||
c8e9b465e2 | |||
278198f5f5 | |||
58718e6bd6 | |||
a814b21693 | |||
5478a4d634 | |||
8f87586495 | |||
7e3a0f524c | |||
922019cc22 | |||
41e9cdb645 | |||
e90add52d2 | |||
3c6ca2cc82 | |||
d1039d9a81 | |||
8b8cee1a5a | |||
5dc92cd72b | |||
d1503605a7 | |||
6426f7a319 | |||
3b9ed5234d | |||
763127605e | |||
b86b19d366 | |||
3dd74c69c5 | |||
01af8e3f2c | |||
474cccda33 | |||
6057b18172 | |||
6a4ff8fa24 | |||
3c79360fd3 | |||
939aafed40 | |||
23417787f8 | |||
8946c1a7de | |||
5fe910b18f | |||
3944cbdc19 | |||
8ac3dd1840 | |||
ff34287e4b | |||
81f2a0eaa1 | |||
f11715a4f4 | |||
89c51371f7 | |||
8076d893db | |||
72f8d520c9 | |||
f9274f8b9a | |||
3c09c03180 | |||
52251e3908 | |||
921444c2c9 | |||
89d234f642 | |||
13771b805b | |||
2a71059490 | |||
053221f155 | |||
4868c361e7 | |||
0c30dbf33e | |||
53370e81e2 | |||
b3fb260c84 | |||
599ca7caf7 | |||
abc0fd5e7b | |||
309b25d201 | |||
9ac7ef20b0 | |||
ebade3594d | |||
dca159d79f | |||
7007d5822a | |||
6f0fdf037f | |||
58621b0eb6 | |||
e8eef5c586 | |||
2b37997a95 | |||
558062efd7 | |||
5e880a4f26 | |||
238956f773 | |||
a5351bc596 | |||
5b6e99b194 | |||
3f3b4a2802 | |||
c19e8d36c9 | |||
2ec31f404b | |||
28a2805450 | |||
2601a1df6c | |||
96d5bb553b | |||
b4d0f442c8 | |||
2a68cab7d6 | |||
009d73fdf6 | |||
42af22f8fd | |||
b85d15b035 | |||
130e376c0c | |||
f884986257 | |||
e23dc3efb1 | |||
dd5e95d7c6 | |||
b72289eadd | |||
7a5d4f03da | |||
18fa277c71 | |||
73cc764091 | |||
9dea514d45 | |||
0bfaa035b9 | |||
85df778785 | |||
e54a92c252 | |||
9145d4cec8 | |||
c611592db6 | |||
6aba809da8 | |||
f0449d79fd | |||
33481ada7f | |||
67195974e7 | |||
70c2376fd0 | |||
177c7de4f9 | |||
eea914ba84 | |||
62e88fbeb3 | |||
5ce27d8341 | |||
eaf62eb635 | |||
9675811bbe | |||
945faf8e92 | |||
9403049671 | |||
40159d9779 | |||
f63653a5b9 | |||
c71dbb5d19 | |||
0f4df2c012 | |||
c6fc4f5a87 | |||
916afa194d | |||
6f2cd11a85 | |||
14652d52bc | |||
a57ee7cdf2 | |||
dbd3e6c29b | |||
665cbca17c | |||
efb9e9f40f | |||
8d35118f63 | |||
553c85456e | |||
68ca206d53 | |||
e30e977140 | |||
f13738d252 | |||
04b927ab7f | |||
993d172de9 | |||
695447611e | |||
06bacfbd72 | |||
cf8bc35d46 | |||
ef859bab84 | |||
a2d0669562 | |||
95365ad6ba | |||
1963b649e8 | |||
db7cdb741c | |||
0fe61ba040 |
@ -5,6 +5,7 @@ pip3 install macpack
|
||||
|
||||
export FFMPEG_VER=5.1
|
||||
export QT_VER=5.15.8
|
||||
export VULKAN_SDK_VER=1.3.236.0
|
||||
|
||||
mkdir tmp
|
||||
cd tmp/
|
||||
@ -18,3 +19,9 @@ cp -rv $(pwd)/ffmpeg-${FFMPEG_VER}/* /
|
||||
wget https://github.com/SachinVin/ext-macos-bin/raw/main/qt/qt-${QT_VER}.7z
|
||||
7z x qt-${QT_VER}.7z
|
||||
sudo cp -rv $(pwd)/qt-${QT_VER}/* /usr/local/
|
||||
|
||||
# install Vulkan SDK
|
||||
wget https://sdk.lunarg.com/sdk/download/1.3.236.0/mac/vulkansdk-macos-${VULKAN_SDK_VER}.dmg
|
||||
hdiutil attach vulkansdk-macos-${VULKAN_SDK_VER}.dmg
|
||||
sudo /Volumes/vulkansdk-macos-${VULKAN_SDK_VER}/InstallVulkan.app/Contents/MacOS/InstallVulkan install --accept-licenses --confirm-command --default-answer com.lunarg.vulkan.core com.lunarg.vulkan.usr
|
||||
hdiutil detach /Volumes/vulkansdk-macos-${VULKAN_SDK_VER}
|
||||
|
@ -12,20 +12,37 @@ cp build/bin/Release/citra "$REV_NAME"
|
||||
cp -r build/bin/Release/citra-qt.app "$REV_NAME"
|
||||
cp build/bin/Release/citra-room "$REV_NAME"
|
||||
|
||||
# move libs into folder for deployment
|
||||
macpack "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt" -d "../Frameworks"
|
||||
# move qt frameworks into app bundle for deployment
|
||||
macdeployqt "${REV_NAME}/citra-qt.app" -executable="${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt"
|
||||
BUNDLE_PATH="$REV_NAME/citra-qt.app"
|
||||
BUNDLE_CONTENTS_PATH="$BUNDLE_PATH/Contents"
|
||||
BUNDLE_EXECUTABLE_PATH="$BUNDLE_CONTENTS_PATH/MacOS/citra-qt"
|
||||
BUNDLE_FRAMEWORKS_PATH="$BUNDLE_CONTENTS_PATH/Frameworks"
|
||||
BUNDLE_RESOURCES_PATH="$BUNDLE_CONTENTS_PATH/Resources"
|
||||
|
||||
CITRA_STANDALONE_PATH="$REV_NAME/citra"
|
||||
|
||||
# move libs into folder for deployment
|
||||
macpack "${REV_NAME}/citra" -d "libs"
|
||||
macpack $BUNDLE_EXECUTABLE_PATH -d "../Frameworks"
|
||||
# move qt frameworks into app bundle for deployment
|
||||
macdeployqt $BUNDLE_PATH -executable=$BUNDLE_EXECUTABLE_PATH
|
||||
|
||||
# move libs into folder for deployment
|
||||
macpack $CITRA_STANDALONE_PATH -d "libs"
|
||||
|
||||
# bundle MoltenVK
|
||||
VULKAN_SDK_PATH=~/VulkanSDK/*/macOS
|
||||
cp $VULKAN_SDK_PATH/lib/libvulkan.dylib $BUNDLE_FRAMEWORKS_PATH
|
||||
cp $VULKAN_SDK_PATH/lib/libMoltenVK.dylib $BUNDLE_FRAMEWORKS_PATH
|
||||
cp $VULKAN_SDK_PATH/lib/libVkLayer_*.dylib $BUNDLE_FRAMEWORKS_PATH
|
||||
cp -r $VULKAN_SDK_PATH/share/vulkan $BUNDLE_RESOURCES_PATH
|
||||
find $BUNDLE_RESOURCES_PATH/vulkan -type f -name "*.json" -exec sed -i'' -e 's/..\/..\/..\/lib/..\/..\/..\/Frameworks/g' {} \;
|
||||
install_name_tool -add_rpath "@loader_path/../Frameworks/" $BUNDLE_EXECUTABLE_PATH
|
||||
|
||||
# workaround for libc++
|
||||
install_name_tool -change @loader_path/../Frameworks/libc++.1.0.dylib /usr/lib/libc++.1.dylib "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt"
|
||||
install_name_tool -change @loader_path/libs/libc++.1.0.dylib /usr/lib/libc++.1.dylib "${REV_NAME}/citra"
|
||||
install_name_tool -change @loader_path/../Frameworks/libc++.1.0.dylib /usr/lib/libc++.1.dylib $BUNDLE_EXECUTABLE_PATH
|
||||
install_name_tool -change @loader_path/libs/libc++.1.0.dylib /usr/lib/libc++.1.dylib $CITRA_STANDALONE_PATH
|
||||
|
||||
# Make the launching script executable
|
||||
chmod +x ${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt
|
||||
chmod +x $BUNDLE_EXECUTABLE_PATH
|
||||
|
||||
# Verify loader instructions
|
||||
find "$REV_NAME" -type f -exec otool -L {} \;
|
||||
|
21
.github/workflows/ci.yml
vendored
21
.github/workflows/ci.yml
vendored
@ -130,11 +130,11 @@ jobs:
|
||||
run: ./.ci/macos/universal.sh
|
||||
env:
|
||||
ARTIFACTS: macos-x86_64 macos-arm64
|
||||
# - name: Upload
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: macos
|
||||
# path: artifacts/
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macos
|
||||
path: artifacts/
|
||||
- name: Delete intermediate artifacts
|
||||
uses: geekyeggo/delete-artifact@v2
|
||||
with:
|
||||
@ -162,6 +162,14 @@ jobs:
|
||||
shell: bash
|
||||
- name: Set up MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Setup Vulkan SDK
|
||||
uses: humbletim/setup-vulkan-sdk@v1.2.0
|
||||
with:
|
||||
vulkan-query-version: latest
|
||||
vulkan-components: Glslang
|
||||
vulkan-use-cache: true
|
||||
- name: Test glslangValidator
|
||||
run: glslangValidator --version
|
||||
- name: Build
|
||||
run: ./.ci/windows-msvc/build.sh
|
||||
shell: bash
|
||||
@ -197,6 +205,9 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install ccache apksigner -y
|
||||
sudo add-apt-repository -y ppa:savoury1/ffmpeg4
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install --no-install-recommends -y glslang-dev glslang-tools
|
||||
- name: Build
|
||||
run: ./.ci/android/build.sh
|
||||
- name: Copy and sign artifacts
|
||||
|
30
.gitmodules
vendored
30
.gitmodules
vendored
@ -43,9 +43,6 @@
|
||||
[submodule "teakra"]
|
||||
path = externals/teakra
|
||||
url = https://github.com/wwylele/teakra.git
|
||||
[submodule "lodepng"]
|
||||
path = externals/lodepng/lodepng
|
||||
url = https://github.com/lvandeve/lodepng.git
|
||||
[submodule "zstd"]
|
||||
path = externals/zstd
|
||||
url = https://github.com/facebook/zstd.git
|
||||
@ -53,11 +50,26 @@
|
||||
path = externals/libyuv
|
||||
url = https://github.com/lemenkov/libyuv.git
|
||||
[submodule "sdl2"]
|
||||
path = externals/sdl2/SDL
|
||||
url = https://github.com/libsdl-org/SDL
|
||||
path = externals/sdl2/SDL
|
||||
url = https://github.com/libsdl-org/SDL
|
||||
[submodule "cryptopp-cmake"]
|
||||
path = externals/cryptopp-cmake
|
||||
url = https://github.com/abdes/cryptopp-cmake.git
|
||||
path = externals/cryptopp-cmake
|
||||
url = https://github.com/abdes/cryptopp-cmake.git
|
||||
[submodule "cryptopp"]
|
||||
path = externals/cryptopp
|
||||
url = https://github.com/weidai11/cryptopp.git
|
||||
path = externals/cryptopp
|
||||
url = https://github.com/weidai11/cryptopp.git
|
||||
[submodule "vulkan-headers"]
|
||||
path = externals/vulkan-headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers
|
||||
[submodule "glslang"]
|
||||
path = externals/glslang
|
||||
url = https://github.com/KhronosGroup/glslang
|
||||
[submodule "glm"]
|
||||
path = externals/glm
|
||||
url = https://github.com/g-truc/glm
|
||||
[submodule "sirit"]
|
||||
path = externals/sirit
|
||||
url = https://github.com/GPUCode/sirit
|
||||
[submodule "zlib-ng"]
|
||||
path = externals/zlib-ng/zlib-ng
|
||||
url = https://github.com/zlib-ng/zlib-ng
|
||||
|
@ -9,6 +9,7 @@ cmake_policy(SET CMP0069 NEW)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||
include(DownloadExternals)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
project(citra LANGUAGES C CXX ASM)
|
||||
|
14
dist/qt_themes/default/style.qss
vendored
14
dist/qt_themes/default/style.qss
vendored
@ -1,3 +1,17 @@
|
||||
QPushButton#GraphicsAPIStatusBarButton {
|
||||
color: #656565;
|
||||
border: 1px solid transparent;
|
||||
background-color: transparent;
|
||||
padding: 0px 3px 0px 3px;
|
||||
text-align: center;
|
||||
min-width: 60px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QPushButton#GraphicsAPIStatusBarButton:hover {
|
||||
border: 1px solid #76797C;
|
||||
}
|
||||
|
||||
QPushButton#3DOptionStatusBarButton {
|
||||
color: #A5A5A5;
|
||||
font-weight: bold;
|
||||
|
14
dist/qt_themes/qdarkstyle/style.qss
vendored
14
dist/qt_themes/qdarkstyle/style.qss
vendored
@ -1237,6 +1237,20 @@ TouchScreenPreview {
|
||||
qproperty-dotHighlightColor: #3daee9;
|
||||
}
|
||||
|
||||
QPushButton#GraphicsAPIStatusBarButton {
|
||||
color: #656565;
|
||||
border: 1px solid transparent;
|
||||
background-color: transparent;
|
||||
padding: 0px 3px 0px 3px;
|
||||
text-align: center;
|
||||
min-width: 60px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QPushButton#GraphicsAPIStatusBarButton:hover {
|
||||
border: 1px solid #76797C;
|
||||
}
|
||||
|
||||
QPushButton#3DOptionStatusBarButton {
|
||||
color: #A5A5A5;
|
||||
font-weight: bold;
|
||||
|
29
externals/CMakeLists.txt
vendored
29
externals/CMakeLists.txt
vendored
@ -89,6 +89,19 @@ endif()
|
||||
# Glad
|
||||
add_subdirectory(glad)
|
||||
|
||||
# glslang
|
||||
set(SKIP_GLSLANG_INSTALL ON)
|
||||
set(ENABLE_GLSLANG_BINARIES OFF)
|
||||
set(ENABLE_SPVREMAPPER OFF)
|
||||
set(ENABLE_CTEST OFF)
|
||||
add_subdirectory(glslang)
|
||||
|
||||
# Sirit
|
||||
add_subdirectory(sirit)
|
||||
|
||||
# glm
|
||||
add_subdirectory(glm)
|
||||
|
||||
# inih
|
||||
add_subdirectory(inih)
|
||||
|
||||
@ -116,6 +129,9 @@ if (ENABLE_SDL2 AND NOT USE_SYSTEM_SDL2)
|
||||
add_subdirectory(sdl2)
|
||||
endif()
|
||||
|
||||
# Zlib
|
||||
add_subdirectory(zlib-ng)
|
||||
|
||||
# Zstandard
|
||||
set(ZSTD_LEGACY_SUPPORT OFF)
|
||||
set(ZSTD_BUILD_PROGRAMS OFF)
|
||||
@ -174,8 +190,8 @@ if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
|
||||
endif()
|
||||
|
||||
# lodepng
|
||||
add_subdirectory(lodepng)
|
||||
# libspng
|
||||
add_subdirectory(libspng)
|
||||
|
||||
# (xperia64): Only use libyuv on Android b/c of build issues on Windows and mandatory JPEG
|
||||
if(ANDROID)
|
||||
@ -183,3 +199,12 @@ if(ANDROID)
|
||||
add_subdirectory(libyuv)
|
||||
target_include_directories(yuv INTERFACE ./libyuv/include)
|
||||
endif()
|
||||
|
||||
# VMA
|
||||
add_library(vma INTERFACE)
|
||||
target_include_directories(vma INTERFACE ./vma)
|
||||
|
||||
# vulkan-headers
|
||||
add_library(vulkan-headers INTERFACE)
|
||||
target_include_directories(vulkan-headers INTERFACE ./vulkan-headers/include)
|
||||
|
||||
|
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: b3a92ab54d...a179e2f2bb
2
externals/glad/Readme.md
vendored
2
externals/glad/Readme.md
vendored
@ -1,5 +1,5 @@
|
||||
These files were generated by the [glad](https://github.com/Dav1dde/glad) OpenGL loader generator and have been checked in as-is. You can re-generate them using glad with the following command:
|
||||
|
||||
```
|
||||
python -m glad --profile core --out-path glad/ --api "gl=4.6,gles2=3.2" --generator=c
|
||||
python -m glad --profile core --out-path glad/ --api "gl=3.3,gles2=3.2" --generator=c
|
||||
```
|
||||
|
41
externals/glad/include/glad/glad.h
vendored
41
externals/glad/include/glad/glad.h
vendored
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Sun Mar 12 10:25:27 2023.
|
||||
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Tue Feb 21 16:13:52 2023.
|
||||
|
||||
Language/Generator: C/C++
|
||||
Specification: gl
|
||||
@ -8,19 +8,20 @@
|
||||
Profile: core
|
||||
Extensions:
|
||||
GL_ARB_buffer_storage,
|
||||
GL_ARB_clear_texture,
|
||||
GL_ARB_get_texture_sub_image,
|
||||
GL_ARB_direct_state_access,
|
||||
GL_ARB_texture_compression_bptc,
|
||||
GL_EXT_buffer_storage,
|
||||
GL_EXT_clip_cull_distance
|
||||
GL_EXT_clip_cull_distance,
|
||||
GL_EXT_texture_compression_s3tc
|
||||
Loader: True
|
||||
Local files: False
|
||||
Omit khrplatform: False
|
||||
Reproducible: False
|
||||
|
||||
Commandline:
|
||||
--profile="core" --api="gl=4.6,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_clear_texture,GL_ARB_get_texture_sub_image,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance"
|
||||
--profile="core" --api="gl=4.6,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_direct_state_access,GL_ARB_texture_compression_bptc,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_texture_compression_s3tc"
|
||||
Online:
|
||||
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_clear_texture&extensions=GL_ARB_get_texture_sub_image&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance
|
||||
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_direct_state_access&extensions=GL_ARB_texture_compression_bptc&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_texture_compression_s3tc
|
||||
*/
|
||||
|
||||
|
||||
@ -3781,6 +3782,14 @@ typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXPROC)(GLfloat minX, GLfloat min
|
||||
GLAPI PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox;
|
||||
#define glPrimitiveBoundingBox glad_glPrimitiveBoundingBox
|
||||
#endif
|
||||
#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
|
||||
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
|
||||
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
|
||||
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
||||
#define GL_MAP_PERSISTENT_BIT_EXT 0x0040
|
||||
#define GL_MAP_COHERENT_BIT_EXT 0x0080
|
||||
#define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100
|
||||
@ -3803,13 +3812,17 @@ GLAPI PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox;
|
||||
#define GL_ARB_buffer_storage 1
|
||||
GLAPI int GLAD_GL_ARB_buffer_storage;
|
||||
#endif
|
||||
#ifndef GL_ARB_clear_texture
|
||||
#define GL_ARB_clear_texture 1
|
||||
GLAPI int GLAD_GL_ARB_clear_texture;
|
||||
#ifndef GL_ARB_direct_state_access
|
||||
#define GL_ARB_direct_state_access 1
|
||||
GLAPI int GLAD_GL_ARB_direct_state_access;
|
||||
#endif
|
||||
#ifndef GL_ARB_get_texture_sub_image
|
||||
#define GL_ARB_get_texture_sub_image 1
|
||||
GLAPI int GLAD_GL_ARB_get_texture_sub_image;
|
||||
#ifndef GL_ARB_texture_compression_bptc
|
||||
#define GL_ARB_texture_compression_bptc 1
|
||||
GLAPI int GLAD_GL_ARB_texture_compression_bptc;
|
||||
#endif
|
||||
#ifndef GL_EXT_texture_compression_s3tc
|
||||
#define GL_EXT_texture_compression_s3tc 1
|
||||
GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
|
||||
#endif
|
||||
#ifndef GL_EXT_buffer_storage
|
||||
#define GL_EXT_buffer_storage 1
|
||||
@ -3822,6 +3835,10 @@ GLAPI PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT;
|
||||
#define GL_EXT_clip_cull_distance 1
|
||||
GLAPI int GLAD_GL_EXT_clip_cull_distance;
|
||||
#endif
|
||||
#ifndef GL_EXT_texture_compression_s3tc
|
||||
#define GL_EXT_texture_compression_s3tc 1
|
||||
GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
135
externals/glad/src/glad.c
vendored
135
externals/glad/src/glad.c
vendored
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Sun Mar 12 10:25:27 2023.
|
||||
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Tue Feb 21 16:13:52 2023.
|
||||
|
||||
Language/Generator: C/C++
|
||||
Specification: gl
|
||||
@ -8,19 +8,20 @@
|
||||
Profile: core
|
||||
Extensions:
|
||||
GL_ARB_buffer_storage,
|
||||
GL_ARB_clear_texture,
|
||||
GL_ARB_get_texture_sub_image,
|
||||
GL_ARB_direct_state_access,
|
||||
GL_ARB_texture_compression_bptc,
|
||||
GL_EXT_buffer_storage,
|
||||
GL_EXT_clip_cull_distance
|
||||
GL_EXT_clip_cull_distance,
|
||||
GL_EXT_texture_compression_s3tc
|
||||
Loader: True
|
||||
Local files: False
|
||||
Omit khrplatform: False
|
||||
Reproducible: False
|
||||
|
||||
Commandline:
|
||||
--profile="core" --api="gl=4.6,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_clear_texture,GL_ARB_get_texture_sub_image,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance"
|
||||
--profile="core" --api="gl=4.6,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_direct_state_access,GL_ARB_texture_compression_bptc,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_texture_compression_s3tc"
|
||||
Online:
|
||||
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_clear_texture&extensions=GL_ARB_get_texture_sub_image&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance
|
||||
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_direct_state_access&extensions=GL_ARB_texture_compression_bptc&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_texture_compression_s3tc
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -984,10 +985,11 @@ PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
|
||||
PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
|
||||
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
|
||||
int GLAD_GL_ARB_buffer_storage = 0;
|
||||
int GLAD_GL_ARB_clear_texture = 0;
|
||||
int GLAD_GL_ARB_get_texture_sub_image = 0;
|
||||
int GLAD_GL_ARB_direct_state_access = 0;
|
||||
int GLAD_GL_ARB_texture_compression_bptc = 0;
|
||||
int GLAD_GL_EXT_buffer_storage = 0;
|
||||
int GLAD_GL_EXT_clip_cull_distance = 0;
|
||||
int GLAD_GL_EXT_texture_compression_s3tc = 0;
|
||||
PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT = NULL;
|
||||
static void load_GL_VERSION_1_0(GLADloadproc load) {
|
||||
if(!GLAD_GL_VERSION_1_0) return;
|
||||
@ -1753,21 +1755,112 @@ static void load_GL_ARB_buffer_storage(GLADloadproc load) {
|
||||
if(!GLAD_GL_ARB_buffer_storage) return;
|
||||
glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load("glBufferStorage");
|
||||
}
|
||||
static void load_GL_ARB_clear_texture(GLADloadproc load) {
|
||||
if(!GLAD_GL_ARB_clear_texture) return;
|
||||
glad_glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)load("glClearTexImage");
|
||||
glad_glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC)load("glClearTexSubImage");
|
||||
}
|
||||
static void load_GL_ARB_get_texture_sub_image(GLADloadproc load) {
|
||||
if(!GLAD_GL_ARB_get_texture_sub_image) return;
|
||||
glad_glGetTextureSubImage = (PFNGLGETTEXTURESUBIMAGEPROC)load("glGetTextureSubImage");
|
||||
glad_glGetCompressedTextureSubImage = (PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)load("glGetCompressedTextureSubImage");
|
||||
static void load_GL_ARB_direct_state_access(GLADloadproc load) {
|
||||
if(!GLAD_GL_ARB_direct_state_access) return;
|
||||
glad_glCreateTransformFeedbacks = (PFNGLCREATETRANSFORMFEEDBACKSPROC)load("glCreateTransformFeedbacks");
|
||||
glad_glTransformFeedbackBufferBase = (PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)load("glTransformFeedbackBufferBase");
|
||||
glad_glTransformFeedbackBufferRange = (PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)load("glTransformFeedbackBufferRange");
|
||||
glad_glGetTransformFeedbackiv = (PFNGLGETTRANSFORMFEEDBACKIVPROC)load("glGetTransformFeedbackiv");
|
||||
glad_glGetTransformFeedbacki_v = (PFNGLGETTRANSFORMFEEDBACKI_VPROC)load("glGetTransformFeedbacki_v");
|
||||
glad_glGetTransformFeedbacki64_v = (PFNGLGETTRANSFORMFEEDBACKI64_VPROC)load("glGetTransformFeedbacki64_v");
|
||||
glad_glCreateBuffers = (PFNGLCREATEBUFFERSPROC)load("glCreateBuffers");
|
||||
glad_glNamedBufferStorage = (PFNGLNAMEDBUFFERSTORAGEPROC)load("glNamedBufferStorage");
|
||||
glad_glNamedBufferData = (PFNGLNAMEDBUFFERDATAPROC)load("glNamedBufferData");
|
||||
glad_glNamedBufferSubData = (PFNGLNAMEDBUFFERSUBDATAPROC)load("glNamedBufferSubData");
|
||||
glad_glCopyNamedBufferSubData = (PFNGLCOPYNAMEDBUFFERSUBDATAPROC)load("glCopyNamedBufferSubData");
|
||||
glad_glClearNamedBufferData = (PFNGLCLEARNAMEDBUFFERDATAPROC)load("glClearNamedBufferData");
|
||||
glad_glClearNamedBufferSubData = (PFNGLCLEARNAMEDBUFFERSUBDATAPROC)load("glClearNamedBufferSubData");
|
||||
glad_glMapNamedBuffer = (PFNGLMAPNAMEDBUFFERPROC)load("glMapNamedBuffer");
|
||||
glad_glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC)load("glMapNamedBufferRange");
|
||||
glad_glUnmapNamedBuffer = (PFNGLUNMAPNAMEDBUFFERPROC)load("glUnmapNamedBuffer");
|
||||
glad_glFlushMappedNamedBufferRange = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)load("glFlushMappedNamedBufferRange");
|
||||
glad_glGetNamedBufferParameteriv = (PFNGLGETNAMEDBUFFERPARAMETERIVPROC)load("glGetNamedBufferParameteriv");
|
||||
glad_glGetNamedBufferParameteri64v = (PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)load("glGetNamedBufferParameteri64v");
|
||||
glad_glGetNamedBufferPointerv = (PFNGLGETNAMEDBUFFERPOINTERVPROC)load("glGetNamedBufferPointerv");
|
||||
glad_glGetNamedBufferSubData = (PFNGLGETNAMEDBUFFERSUBDATAPROC)load("glGetNamedBufferSubData");
|
||||
glad_glCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC)load("glCreateFramebuffers");
|
||||
glad_glNamedFramebufferRenderbuffer = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)load("glNamedFramebufferRenderbuffer");
|
||||
glad_glNamedFramebufferParameteri = (PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)load("glNamedFramebufferParameteri");
|
||||
glad_glNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)load("glNamedFramebufferTexture");
|
||||
glad_glNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)load("glNamedFramebufferTextureLayer");
|
||||
glad_glNamedFramebufferDrawBuffer = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)load("glNamedFramebufferDrawBuffer");
|
||||
glad_glNamedFramebufferDrawBuffers = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)load("glNamedFramebufferDrawBuffers");
|
||||
glad_glNamedFramebufferReadBuffer = (PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)load("glNamedFramebufferReadBuffer");
|
||||
glad_glInvalidateNamedFramebufferData = (PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)load("glInvalidateNamedFramebufferData");
|
||||
glad_glInvalidateNamedFramebufferSubData = (PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)load("glInvalidateNamedFramebufferSubData");
|
||||
glad_glClearNamedFramebufferiv = (PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)load("glClearNamedFramebufferiv");
|
||||
glad_glClearNamedFramebufferuiv = (PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)load("glClearNamedFramebufferuiv");
|
||||
glad_glClearNamedFramebufferfv = (PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)load("glClearNamedFramebufferfv");
|
||||
glad_glClearNamedFramebufferfi = (PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)load("glClearNamedFramebufferfi");
|
||||
glad_glBlitNamedFramebuffer = (PFNGLBLITNAMEDFRAMEBUFFERPROC)load("glBlitNamedFramebuffer");
|
||||
glad_glCheckNamedFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)load("glCheckNamedFramebufferStatus");
|
||||
glad_glGetNamedFramebufferParameteriv = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)load("glGetNamedFramebufferParameteriv");
|
||||
glad_glGetNamedFramebufferAttachmentParameteriv = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetNamedFramebufferAttachmentParameteriv");
|
||||
glad_glCreateRenderbuffers = (PFNGLCREATERENDERBUFFERSPROC)load("glCreateRenderbuffers");
|
||||
glad_glNamedRenderbufferStorage = (PFNGLNAMEDRENDERBUFFERSTORAGEPROC)load("glNamedRenderbufferStorage");
|
||||
glad_glNamedRenderbufferStorageMultisample = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glNamedRenderbufferStorageMultisample");
|
||||
glad_glGetNamedRenderbufferParameteriv = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)load("glGetNamedRenderbufferParameteriv");
|
||||
glad_glCreateTextures = (PFNGLCREATETEXTURESPROC)load("glCreateTextures");
|
||||
glad_glTextureBuffer = (PFNGLTEXTUREBUFFERPROC)load("glTextureBuffer");
|
||||
glad_glTextureBufferRange = (PFNGLTEXTUREBUFFERRANGEPROC)load("glTextureBufferRange");
|
||||
glad_glTextureStorage1D = (PFNGLTEXTURESTORAGE1DPROC)load("glTextureStorage1D");
|
||||
glad_glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC)load("glTextureStorage2D");
|
||||
glad_glTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC)load("glTextureStorage3D");
|
||||
glad_glTextureStorage2DMultisample = (PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)load("glTextureStorage2DMultisample");
|
||||
glad_glTextureStorage3DMultisample = (PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)load("glTextureStorage3DMultisample");
|
||||
glad_glTextureSubImage1D = (PFNGLTEXTURESUBIMAGE1DPROC)load("glTextureSubImage1D");
|
||||
glad_glTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC)load("glTextureSubImage2D");
|
||||
glad_glTextureSubImage3D = (PFNGLTEXTURESUBIMAGE3DPROC)load("glTextureSubImage3D");
|
||||
glad_glCompressedTextureSubImage1D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)load("glCompressedTextureSubImage1D");
|
||||
glad_glCompressedTextureSubImage2D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)load("glCompressedTextureSubImage2D");
|
||||
glad_glCompressedTextureSubImage3D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)load("glCompressedTextureSubImage3D");
|
||||
glad_glCopyTextureSubImage1D = (PFNGLCOPYTEXTURESUBIMAGE1DPROC)load("glCopyTextureSubImage1D");
|
||||
glad_glCopyTextureSubImage2D = (PFNGLCOPYTEXTURESUBIMAGE2DPROC)load("glCopyTextureSubImage2D");
|
||||
glad_glCopyTextureSubImage3D = (PFNGLCOPYTEXTURESUBIMAGE3DPROC)load("glCopyTextureSubImage3D");
|
||||
glad_glTextureParameterf = (PFNGLTEXTUREPARAMETERFPROC)load("glTextureParameterf");
|
||||
glad_glTextureParameterfv = (PFNGLTEXTUREPARAMETERFVPROC)load("glTextureParameterfv");
|
||||
glad_glTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC)load("glTextureParameteri");
|
||||
glad_glTextureParameterIiv = (PFNGLTEXTUREPARAMETERIIVPROC)load("glTextureParameterIiv");
|
||||
glad_glTextureParameterIuiv = (PFNGLTEXTUREPARAMETERIUIVPROC)load("glTextureParameterIuiv");
|
||||
glad_glTextureParameteriv = (PFNGLTEXTUREPARAMETERIVPROC)load("glTextureParameteriv");
|
||||
glad_glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC)load("glGenerateTextureMipmap");
|
||||
glad_glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC)load("glBindTextureUnit");
|
||||
glad_glGetTextureImage = (PFNGLGETTEXTUREIMAGEPROC)load("glGetTextureImage");
|
||||
glad_glGetCompressedTextureImage = (PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)load("glGetCompressedTextureImage");
|
||||
glad_glGetTextureLevelParameterfv = (PFNGLGETTEXTURELEVELPARAMETERFVPROC)load("glGetTextureLevelParameterfv");
|
||||
glad_glGetTextureLevelParameteriv = (PFNGLGETTEXTURELEVELPARAMETERIVPROC)load("glGetTextureLevelParameteriv");
|
||||
glad_glGetTextureParameterfv = (PFNGLGETTEXTUREPARAMETERFVPROC)load("glGetTextureParameterfv");
|
||||
glad_glGetTextureParameterIiv = (PFNGLGETTEXTUREPARAMETERIIVPROC)load("glGetTextureParameterIiv");
|
||||
glad_glGetTextureParameterIuiv = (PFNGLGETTEXTUREPARAMETERIUIVPROC)load("glGetTextureParameterIuiv");
|
||||
glad_glGetTextureParameteriv = (PFNGLGETTEXTUREPARAMETERIVPROC)load("glGetTextureParameteriv");
|
||||
glad_glCreateVertexArrays = (PFNGLCREATEVERTEXARRAYSPROC)load("glCreateVertexArrays");
|
||||
glad_glDisableVertexArrayAttrib = (PFNGLDISABLEVERTEXARRAYATTRIBPROC)load("glDisableVertexArrayAttrib");
|
||||
glad_glEnableVertexArrayAttrib = (PFNGLENABLEVERTEXARRAYATTRIBPROC)load("glEnableVertexArrayAttrib");
|
||||
glad_glVertexArrayElementBuffer = (PFNGLVERTEXARRAYELEMENTBUFFERPROC)load("glVertexArrayElementBuffer");
|
||||
glad_glVertexArrayVertexBuffer = (PFNGLVERTEXARRAYVERTEXBUFFERPROC)load("glVertexArrayVertexBuffer");
|
||||
glad_glVertexArrayVertexBuffers = (PFNGLVERTEXARRAYVERTEXBUFFERSPROC)load("glVertexArrayVertexBuffers");
|
||||
glad_glVertexArrayAttribBinding = (PFNGLVERTEXARRAYATTRIBBINDINGPROC)load("glVertexArrayAttribBinding");
|
||||
glad_glVertexArrayAttribFormat = (PFNGLVERTEXARRAYATTRIBFORMATPROC)load("glVertexArrayAttribFormat");
|
||||
glad_glVertexArrayAttribIFormat = (PFNGLVERTEXARRAYATTRIBIFORMATPROC)load("glVertexArrayAttribIFormat");
|
||||
glad_glVertexArrayAttribLFormat = (PFNGLVERTEXARRAYATTRIBLFORMATPROC)load("glVertexArrayAttribLFormat");
|
||||
glad_glVertexArrayBindingDivisor = (PFNGLVERTEXARRAYBINDINGDIVISORPROC)load("glVertexArrayBindingDivisor");
|
||||
glad_glGetVertexArrayiv = (PFNGLGETVERTEXARRAYIVPROC)load("glGetVertexArrayiv");
|
||||
glad_glGetVertexArrayIndexediv = (PFNGLGETVERTEXARRAYINDEXEDIVPROC)load("glGetVertexArrayIndexediv");
|
||||
glad_glGetVertexArrayIndexed64iv = (PFNGLGETVERTEXARRAYINDEXED64IVPROC)load("glGetVertexArrayIndexed64iv");
|
||||
glad_glCreateSamplers = (PFNGLCREATESAMPLERSPROC)load("glCreateSamplers");
|
||||
glad_glCreateProgramPipelines = (PFNGLCREATEPROGRAMPIPELINESPROC)load("glCreateProgramPipelines");
|
||||
glad_glCreateQueries = (PFNGLCREATEQUERIESPROC)load("glCreateQueries");
|
||||
glad_glGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECTI64VPROC)load("glGetQueryBufferObjecti64v");
|
||||
glad_glGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECTIVPROC)load("glGetQueryBufferObjectiv");
|
||||
glad_glGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECTUI64VPROC)load("glGetQueryBufferObjectui64v");
|
||||
glad_glGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECTUIVPROC)load("glGetQueryBufferObjectuiv");
|
||||
}
|
||||
static int find_extensionsGL(void) {
|
||||
if (!get_exts()) return 0;
|
||||
GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage");
|
||||
GLAD_GL_ARB_clear_texture = has_ext("GL_ARB_clear_texture");
|
||||
GLAD_GL_ARB_get_texture_sub_image = has_ext("GL_ARB_get_texture_sub_image");
|
||||
GLAD_GL_ARB_direct_state_access = has_ext("GL_ARB_direct_state_access");
|
||||
GLAD_GL_ARB_texture_compression_bptc = has_ext("GL_ARB_texture_compression_bptc");
|
||||
GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
|
||||
free_exts();
|
||||
return 1;
|
||||
}
|
||||
@ -1861,8 +1954,7 @@ int gladLoadGLLoader(GLADloadproc load) {
|
||||
|
||||
if (!find_extensionsGL()) return 0;
|
||||
load_GL_ARB_buffer_storage(load);
|
||||
load_GL_ARB_clear_texture(load);
|
||||
load_GL_ARB_get_texture_sub_image(load);
|
||||
load_GL_ARB_direct_state_access(load);
|
||||
return GLVersion.major != 0 || GLVersion.minor != 0;
|
||||
}
|
||||
|
||||
@ -2244,6 +2336,7 @@ static int find_extensionsGLES2(void) {
|
||||
if (!get_exts()) return 0;
|
||||
GLAD_GL_EXT_buffer_storage = has_ext("GL_EXT_buffer_storage");
|
||||
GLAD_GL_EXT_clip_cull_distance = has_ext("GL_EXT_clip_cull_distance");
|
||||
GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
|
||||
free_exts();
|
||||
return 1;
|
||||
}
|
||||
|
1
externals/glm
vendored
Submodule
1
externals/glm
vendored
Submodule
Submodule externals/glm added at cc98465e35
1
externals/glslang
vendored
Submodule
1
externals/glslang
vendored
Submodule
Submodule externals/glslang added at c0cf8ad876
14
externals/libspng/CMakeLists.txt
vendored
Normal file
14
externals/libspng/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
add_library(spng STATIC spng.h spng.c)
|
||||
target_compile_definitions(spng PUBLIC SPNG_STATIC)
|
||||
target_include_directories(spng PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_link_libraries(spng PRIVATE ZLIB::ZLIB)
|
||||
|
||||
# Enable SSE4.1 on x64
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
target_compile_definitions(spng PRIVATE SPNG_SSE=4)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(spng PRIVATE -msse4.1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(spng::spng ALIAS spng)
|
6979
externals/libspng/spng.c
vendored
Normal file
6979
externals/libspng/spng.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
537
externals/libspng/spng.h
vendored
Normal file
537
externals/libspng/spng.h
vendored
Normal file
@ -0,0 +1,537 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
#ifndef SPNG_H
|
||||
#define SPNG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(SPNG_STATIC)
|
||||
#if defined(SPNG__BUILD)
|
||||
#define SPNG_API __declspec(dllexport)
|
||||
#else
|
||||
#define SPNG_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define SPNG_API
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define SPNG_CDECL __cdecl
|
||||
#else
|
||||
#define SPNG_CDECL
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SPNG_VERSION_MAJOR 0
|
||||
#define SPNG_VERSION_MINOR 7
|
||||
#define SPNG_VERSION_PATCH 3
|
||||
|
||||
enum spng_errno
|
||||
{
|
||||
SPNG_IO_ERROR = -2,
|
||||
SPNG_IO_EOF = -1,
|
||||
SPNG_OK = 0,
|
||||
SPNG_EINVAL,
|
||||
SPNG_EMEM,
|
||||
SPNG_EOVERFLOW,
|
||||
SPNG_ESIGNATURE,
|
||||
SPNG_EWIDTH,
|
||||
SPNG_EHEIGHT,
|
||||
SPNG_EUSER_WIDTH,
|
||||
SPNG_EUSER_HEIGHT,
|
||||
SPNG_EBIT_DEPTH,
|
||||
SPNG_ECOLOR_TYPE,
|
||||
SPNG_ECOMPRESSION_METHOD,
|
||||
SPNG_EFILTER_METHOD,
|
||||
SPNG_EINTERLACE_METHOD,
|
||||
SPNG_EIHDR_SIZE,
|
||||
SPNG_ENOIHDR,
|
||||
SPNG_ECHUNK_POS,
|
||||
SPNG_ECHUNK_SIZE,
|
||||
SPNG_ECHUNK_CRC,
|
||||
SPNG_ECHUNK_TYPE,
|
||||
SPNG_ECHUNK_UNKNOWN_CRITICAL,
|
||||
SPNG_EDUP_PLTE,
|
||||
SPNG_EDUP_CHRM,
|
||||
SPNG_EDUP_GAMA,
|
||||
SPNG_EDUP_ICCP,
|
||||
SPNG_EDUP_SBIT,
|
||||
SPNG_EDUP_SRGB,
|
||||
SPNG_EDUP_BKGD,
|
||||
SPNG_EDUP_HIST,
|
||||
SPNG_EDUP_TRNS,
|
||||
SPNG_EDUP_PHYS,
|
||||
SPNG_EDUP_TIME,
|
||||
SPNG_EDUP_OFFS,
|
||||
SPNG_EDUP_EXIF,
|
||||
SPNG_ECHRM,
|
||||
SPNG_EPLTE_IDX,
|
||||
SPNG_ETRNS_COLOR_TYPE,
|
||||
SPNG_ETRNS_NO_PLTE,
|
||||
SPNG_EGAMA,
|
||||
SPNG_EICCP_NAME,
|
||||
SPNG_EICCP_COMPRESSION_METHOD,
|
||||
SPNG_ESBIT,
|
||||
SPNG_ESRGB,
|
||||
SPNG_ETEXT,
|
||||
SPNG_ETEXT_KEYWORD,
|
||||
SPNG_EZTXT,
|
||||
SPNG_EZTXT_COMPRESSION_METHOD,
|
||||
SPNG_EITXT,
|
||||
SPNG_EITXT_COMPRESSION_FLAG,
|
||||
SPNG_EITXT_COMPRESSION_METHOD,
|
||||
SPNG_EITXT_LANG_TAG,
|
||||
SPNG_EITXT_TRANSLATED_KEY,
|
||||
SPNG_EBKGD_NO_PLTE,
|
||||
SPNG_EBKGD_PLTE_IDX,
|
||||
SPNG_EHIST_NO_PLTE,
|
||||
SPNG_EPHYS,
|
||||
SPNG_ESPLT_NAME,
|
||||
SPNG_ESPLT_DUP_NAME,
|
||||
SPNG_ESPLT_DEPTH,
|
||||
SPNG_ETIME,
|
||||
SPNG_EOFFS,
|
||||
SPNG_EEXIF,
|
||||
SPNG_EIDAT_TOO_SHORT,
|
||||
SPNG_EIDAT_STREAM,
|
||||
SPNG_EZLIB,
|
||||
SPNG_EFILTER,
|
||||
SPNG_EBUFSIZ,
|
||||
SPNG_EIO,
|
||||
SPNG_EOF,
|
||||
SPNG_EBUF_SET,
|
||||
SPNG_EBADSTATE,
|
||||
SPNG_EFMT,
|
||||
SPNG_EFLAGS,
|
||||
SPNG_ECHUNKAVAIL,
|
||||
SPNG_ENCODE_ONLY,
|
||||
SPNG_EOI,
|
||||
SPNG_ENOPLTE,
|
||||
SPNG_ECHUNK_LIMITS,
|
||||
SPNG_EZLIB_INIT,
|
||||
SPNG_ECHUNK_STDLEN,
|
||||
SPNG_EINTERNAL,
|
||||
SPNG_ECTXTYPE,
|
||||
SPNG_ENOSRC,
|
||||
SPNG_ENODST,
|
||||
SPNG_EOPSTATE,
|
||||
SPNG_ENOTFINAL,
|
||||
};
|
||||
|
||||
enum spng_text_type
|
||||
{
|
||||
SPNG_TEXT = 1,
|
||||
SPNG_ZTXT = 2,
|
||||
SPNG_ITXT = 3
|
||||
};
|
||||
|
||||
enum spng_color_type
|
||||
{
|
||||
SPNG_COLOR_TYPE_GRAYSCALE = 0,
|
||||
SPNG_COLOR_TYPE_TRUECOLOR = 2,
|
||||
SPNG_COLOR_TYPE_INDEXED = 3,
|
||||
SPNG_COLOR_TYPE_GRAYSCALE_ALPHA = 4,
|
||||
SPNG_COLOR_TYPE_TRUECOLOR_ALPHA = 6
|
||||
};
|
||||
|
||||
enum spng_filter
|
||||
{
|
||||
SPNG_FILTER_NONE = 0,
|
||||
SPNG_FILTER_SUB = 1,
|
||||
SPNG_FILTER_UP = 2,
|
||||
SPNG_FILTER_AVERAGE = 3,
|
||||
SPNG_FILTER_PAETH = 4
|
||||
};
|
||||
|
||||
enum spng_filter_choice
|
||||
{
|
||||
SPNG_DISABLE_FILTERING = 0,
|
||||
SPNG_FILTER_CHOICE_NONE = 8,
|
||||
SPNG_FILTER_CHOICE_SUB = 16,
|
||||
SPNG_FILTER_CHOICE_UP = 32,
|
||||
SPNG_FILTER_CHOICE_AVG = 64,
|
||||
SPNG_FILTER_CHOICE_PAETH = 128,
|
||||
SPNG_FILTER_CHOICE_ALL = (8|16|32|64|128)
|
||||
};
|
||||
|
||||
enum spng_interlace_method
|
||||
{
|
||||
SPNG_INTERLACE_NONE = 0,
|
||||
SPNG_INTERLACE_ADAM7 = 1
|
||||
};
|
||||
|
||||
/* Channels are always in byte-order */
|
||||
enum spng_format
|
||||
{
|
||||
SPNG_FMT_RGBA8 = 1,
|
||||
SPNG_FMT_RGBA16 = 2,
|
||||
SPNG_FMT_RGB8 = 4,
|
||||
|
||||
/* Partially implemented, see documentation */
|
||||
SPNG_FMT_GA8 = 16,
|
||||
SPNG_FMT_GA16 = 32,
|
||||
SPNG_FMT_G8 = 64,
|
||||
|
||||
/* No conversion or scaling */
|
||||
SPNG_FMT_PNG = 256,
|
||||
SPNG_FMT_RAW = 512 /* big-endian (everything else is host-endian) */
|
||||
};
|
||||
|
||||
enum spng_ctx_flags
|
||||
{
|
||||
SPNG_CTX_IGNORE_ADLER32 = 1, /* Ignore checksum in DEFLATE streams */
|
||||
SPNG_CTX_ENCODER = 2 /* Create an encoder context */
|
||||
};
|
||||
|
||||
enum spng_decode_flags
|
||||
{
|
||||
SPNG_DECODE_USE_TRNS = 1, /* Deprecated */
|
||||
SPNG_DECODE_USE_GAMA = 2, /* Deprecated */
|
||||
SPNG_DECODE_USE_SBIT = 8, /* Undocumented */
|
||||
|
||||
SPNG_DECODE_TRNS = 1, /* Apply transparency */
|
||||
SPNG_DECODE_GAMMA = 2, /* Apply gamma correction */
|
||||
SPNG_DECODE_PROGRESSIVE = 256 /* Initialize for progressive reads */
|
||||
};
|
||||
|
||||
enum spng_crc_action
|
||||
{
|
||||
/* Default for critical chunks */
|
||||
SPNG_CRC_ERROR = 0,
|
||||
|
||||
/* Discard chunk, invalid for critical chunks.
|
||||
Since v0.6.2: default for ancillary chunks */
|
||||
SPNG_CRC_DISCARD = 1,
|
||||
|
||||
/* Ignore and don't calculate checksum.
|
||||
Since v0.6.2: also ignores checksums in DEFLATE streams */
|
||||
SPNG_CRC_USE = 2
|
||||
};
|
||||
|
||||
enum spng_encode_flags
|
||||
{
|
||||
SPNG_ENCODE_PROGRESSIVE = 1, /* Initialize for progressive writes */
|
||||
SPNG_ENCODE_FINALIZE = 2, /* Finalize PNG after encoding image */
|
||||
};
|
||||
|
||||
struct spng_ihdr
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t bit_depth;
|
||||
uint8_t color_type;
|
||||
uint8_t compression_method;
|
||||
uint8_t filter_method;
|
||||
uint8_t interlace_method;
|
||||
};
|
||||
|
||||
struct spng_plte_entry
|
||||
{
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
|
||||
uint8_t alpha; /* Reserved for internal use */
|
||||
};
|
||||
|
||||
struct spng_plte
|
||||
{
|
||||
uint32_t n_entries;
|
||||
struct spng_plte_entry entries[256];
|
||||
};
|
||||
|
||||
struct spng_trns
|
||||
{
|
||||
uint16_t gray;
|
||||
|
||||
uint16_t red;
|
||||
uint16_t green;
|
||||
uint16_t blue;
|
||||
|
||||
uint32_t n_type3_entries;
|
||||
uint8_t type3_alpha[256];
|
||||
};
|
||||
|
||||
struct spng_chrm_int
|
||||
{
|
||||
uint32_t white_point_x;
|
||||
uint32_t white_point_y;
|
||||
uint32_t red_x;
|
||||
uint32_t red_y;
|
||||
uint32_t green_x;
|
||||
uint32_t green_y;
|
||||
uint32_t blue_x;
|
||||
uint32_t blue_y;
|
||||
};
|
||||
|
||||
struct spng_chrm
|
||||
{
|
||||
double white_point_x;
|
||||
double white_point_y;
|
||||
double red_x;
|
||||
double red_y;
|
||||
double green_x;
|
||||
double green_y;
|
||||
double blue_x;
|
||||
double blue_y;
|
||||
};
|
||||
|
||||
struct spng_iccp
|
||||
{
|
||||
char profile_name[80];
|
||||
size_t profile_len;
|
||||
char *profile;
|
||||
};
|
||||
|
||||
struct spng_sbit
|
||||
{
|
||||
uint8_t grayscale_bits;
|
||||
uint8_t red_bits;
|
||||
uint8_t green_bits;
|
||||
uint8_t blue_bits;
|
||||
uint8_t alpha_bits;
|
||||
};
|
||||
|
||||
struct spng_text
|
||||
{
|
||||
char keyword[80];
|
||||
int type;
|
||||
|
||||
size_t length;
|
||||
char *text;
|
||||
|
||||
uint8_t compression_flag; /* iTXt only */
|
||||
uint8_t compression_method; /* iTXt, ztXt only */
|
||||
char *language_tag; /* iTXt only */
|
||||
char *translated_keyword; /* iTXt only */
|
||||
};
|
||||
|
||||
struct spng_bkgd
|
||||
{
|
||||
uint16_t gray; /* Only for gray/gray alpha */
|
||||
uint16_t red;
|
||||
uint16_t green;
|
||||
uint16_t blue;
|
||||
uint16_t plte_index; /* Only for indexed color */
|
||||
};
|
||||
|
||||
struct spng_hist
|
||||
{
|
||||
uint16_t frequency[256];
|
||||
};
|
||||
|
||||
struct spng_phys
|
||||
{
|
||||
uint32_t ppu_x, ppu_y;
|
||||
uint8_t unit_specifier;
|
||||
};
|
||||
|
||||
struct spng_splt_entry
|
||||
{
|
||||
uint16_t red;
|
||||
uint16_t green;
|
||||
uint16_t blue;
|
||||
uint16_t alpha;
|
||||
uint16_t frequency;
|
||||
};
|
||||
|
||||
struct spng_splt
|
||||
{
|
||||
char name[80];
|
||||
uint8_t sample_depth;
|
||||
uint32_t n_entries;
|
||||
struct spng_splt_entry *entries;
|
||||
};
|
||||
|
||||
struct spng_time
|
||||
{
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
};
|
||||
|
||||
struct spng_offs
|
||||
{
|
||||
int32_t x, y;
|
||||
uint8_t unit_specifier;
|
||||
};
|
||||
|
||||
struct spng_exif
|
||||
{
|
||||
size_t length;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct spng_chunk
|
||||
{
|
||||
size_t offset;
|
||||
uint32_t length;
|
||||
uint8_t type[4];
|
||||
uint32_t crc;
|
||||
};
|
||||
|
||||
enum spng_location
|
||||
{
|
||||
SPNG_AFTER_IHDR = 1,
|
||||
SPNG_AFTER_PLTE = 2,
|
||||
SPNG_AFTER_IDAT = 8,
|
||||
};
|
||||
|
||||
struct spng_unknown_chunk
|
||||
{
|
||||
uint8_t type[4];
|
||||
size_t length;
|
||||
void *data;
|
||||
enum spng_location location;
|
||||
};
|
||||
|
||||
enum spng_option
|
||||
{
|
||||
SPNG_KEEP_UNKNOWN_CHUNKS = 1,
|
||||
|
||||
SPNG_IMG_COMPRESSION_LEVEL,
|
||||
SPNG_IMG_WINDOW_BITS,
|
||||
SPNG_IMG_MEM_LEVEL,
|
||||
SPNG_IMG_COMPRESSION_STRATEGY,
|
||||
|
||||
SPNG_TEXT_COMPRESSION_LEVEL,
|
||||
SPNG_TEXT_WINDOW_BITS,
|
||||
SPNG_TEXT_MEM_LEVEL,
|
||||
SPNG_TEXT_COMPRESSION_STRATEGY,
|
||||
|
||||
SPNG_FILTER_CHOICE,
|
||||
SPNG_CHUNK_COUNT_LIMIT,
|
||||
SPNG_ENCODE_TO_BUFFER,
|
||||
};
|
||||
|
||||
typedef void* SPNG_CDECL spng_malloc_fn(size_t size);
|
||||
typedef void* SPNG_CDECL spng_realloc_fn(void* ptr, size_t size);
|
||||
typedef void* SPNG_CDECL spng_calloc_fn(size_t count, size_t size);
|
||||
typedef void SPNG_CDECL spng_free_fn(void* ptr);
|
||||
|
||||
struct spng_alloc
|
||||
{
|
||||
spng_malloc_fn *malloc_fn;
|
||||
spng_realloc_fn *realloc_fn;
|
||||
spng_calloc_fn *calloc_fn;
|
||||
spng_free_fn *free_fn;
|
||||
};
|
||||
|
||||
struct spng_row_info
|
||||
{
|
||||
uint32_t scanline_idx;
|
||||
uint32_t row_num; /* deinterlaced row index */
|
||||
int pass;
|
||||
uint8_t filter;
|
||||
};
|
||||
|
||||
typedef struct spng_ctx spng_ctx;
|
||||
|
||||
typedef int spng_read_fn(spng_ctx *ctx, void *user, void *dest, size_t length);
|
||||
typedef int spng_write_fn(spng_ctx *ctx, void *user, void *src, size_t length);
|
||||
|
||||
typedef int spng_rw_fn(spng_ctx *ctx, void *user, void *dst_src, size_t length);
|
||||
|
||||
SPNG_API spng_ctx *spng_ctx_new(int flags);
|
||||
SPNG_API spng_ctx *spng_ctx_new2(struct spng_alloc *alloc, int flags);
|
||||
SPNG_API void spng_ctx_free(spng_ctx *ctx);
|
||||
|
||||
SPNG_API int spng_set_png_buffer(spng_ctx *ctx, const void *buf, size_t size);
|
||||
SPNG_API int spng_set_png_stream(spng_ctx *ctx, spng_rw_fn *rw_func, void *user);
|
||||
SPNG_API int spng_set_png_file(spng_ctx *ctx, FILE *file);
|
||||
|
||||
SPNG_API void *spng_get_png_buffer(spng_ctx *ctx, size_t *len, int *error);
|
||||
|
||||
SPNG_API int spng_set_image_limits(spng_ctx *ctx, uint32_t width, uint32_t height);
|
||||
SPNG_API int spng_get_image_limits(spng_ctx *ctx, uint32_t *width, uint32_t *height);
|
||||
|
||||
SPNG_API int spng_set_chunk_limits(spng_ctx *ctx, size_t chunk_size, size_t cache_size);
|
||||
SPNG_API int spng_get_chunk_limits(spng_ctx *ctx, size_t *chunk_size, size_t *cache_size);
|
||||
|
||||
SPNG_API int spng_set_crc_action(spng_ctx *ctx, int critical, int ancillary);
|
||||
|
||||
SPNG_API int spng_set_option(spng_ctx *ctx, enum spng_option option, int value);
|
||||
SPNG_API int spng_get_option(spng_ctx *ctx, enum spng_option option, int *value);
|
||||
|
||||
SPNG_API int spng_decoded_image_size(spng_ctx *ctx, int fmt, size_t *len);
|
||||
|
||||
/* Decode */
|
||||
SPNG_API int spng_decode_image(spng_ctx *ctx, void *out, size_t len, int fmt, int flags);
|
||||
|
||||
/* Progressive decode */
|
||||
SPNG_API int spng_decode_scanline(spng_ctx *ctx, void *out, size_t len);
|
||||
SPNG_API int spng_decode_row(spng_ctx *ctx, void *out, size_t len);
|
||||
SPNG_API int spng_decode_chunks(spng_ctx *ctx);
|
||||
|
||||
/* Encode/decode */
|
||||
SPNG_API int spng_get_row_info(spng_ctx *ctx, struct spng_row_info *row_info);
|
||||
|
||||
/* Encode */
|
||||
SPNG_API int spng_encode_image(spng_ctx *ctx, const void *img, size_t len, int fmt, int flags);
|
||||
|
||||
/* Progressive encode */
|
||||
SPNG_API int spng_encode_scanline(spng_ctx *ctx, const void *scanline, size_t len);
|
||||
SPNG_API int spng_encode_row(spng_ctx *ctx, const void *row, size_t len);
|
||||
SPNG_API int spng_encode_chunks(spng_ctx *ctx);
|
||||
|
||||
SPNG_API int spng_get_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr);
|
||||
SPNG_API int spng_get_plte(spng_ctx *ctx, struct spng_plte *plte);
|
||||
SPNG_API int spng_get_trns(spng_ctx *ctx, struct spng_trns *trns);
|
||||
SPNG_API int spng_get_chrm(spng_ctx *ctx, struct spng_chrm *chrm);
|
||||
SPNG_API int spng_get_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int);
|
||||
SPNG_API int spng_get_gama(spng_ctx *ctx, double *gamma);
|
||||
SPNG_API int spng_get_gama_int(spng_ctx *ctx, uint32_t *gama_int);
|
||||
SPNG_API int spng_get_iccp(spng_ctx *ctx, struct spng_iccp *iccp);
|
||||
SPNG_API int spng_get_sbit(spng_ctx *ctx, struct spng_sbit *sbit);
|
||||
SPNG_API int spng_get_srgb(spng_ctx *ctx, uint8_t *rendering_intent);
|
||||
SPNG_API int spng_get_text(spng_ctx *ctx, struct spng_text *text, uint32_t *n_text);
|
||||
SPNG_API int spng_get_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd);
|
||||
SPNG_API int spng_get_hist(spng_ctx *ctx, struct spng_hist *hist);
|
||||
SPNG_API int spng_get_phys(spng_ctx *ctx, struct spng_phys *phys);
|
||||
SPNG_API int spng_get_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t *n_splt);
|
||||
SPNG_API int spng_get_time(spng_ctx *ctx, struct spng_time *time);
|
||||
SPNG_API int spng_get_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t *n_chunks);
|
||||
|
||||
/* Official extensions */
|
||||
SPNG_API int spng_get_offs(spng_ctx *ctx, struct spng_offs *offs);
|
||||
SPNG_API int spng_get_exif(spng_ctx *ctx, struct spng_exif *exif);
|
||||
|
||||
|
||||
SPNG_API int spng_set_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr);
|
||||
SPNG_API int spng_set_plte(spng_ctx *ctx, struct spng_plte *plte);
|
||||
SPNG_API int spng_set_trns(spng_ctx *ctx, struct spng_trns *trns);
|
||||
SPNG_API int spng_set_chrm(spng_ctx *ctx, struct spng_chrm *chrm);
|
||||
SPNG_API int spng_set_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int);
|
||||
SPNG_API int spng_set_gama(spng_ctx *ctx, double gamma);
|
||||
SPNG_API int spng_set_gama_int(spng_ctx *ctx, uint32_t gamma);
|
||||
SPNG_API int spng_set_iccp(spng_ctx *ctx, struct spng_iccp *iccp);
|
||||
SPNG_API int spng_set_sbit(spng_ctx *ctx, struct spng_sbit *sbit);
|
||||
SPNG_API int spng_set_srgb(spng_ctx *ctx, uint8_t rendering_intent);
|
||||
SPNG_API int spng_set_text(spng_ctx *ctx, struct spng_text *text, uint32_t n_text);
|
||||
SPNG_API int spng_set_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd);
|
||||
SPNG_API int spng_set_hist(spng_ctx *ctx, struct spng_hist *hist);
|
||||
SPNG_API int spng_set_phys(spng_ctx *ctx, struct spng_phys *phys);
|
||||
SPNG_API int spng_set_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t n_splt);
|
||||
SPNG_API int spng_set_time(spng_ctx *ctx, struct spng_time *time);
|
||||
SPNG_API int spng_set_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t n_chunks);
|
||||
|
||||
/* Official extensions */
|
||||
SPNG_API int spng_set_offs(spng_ctx *ctx, struct spng_offs *offs);
|
||||
SPNG_API int spng_set_exif(spng_ctx *ctx, struct spng_exif *exif);
|
||||
|
||||
|
||||
SPNG_API const char *spng_strerror(int err);
|
||||
SPNG_API const char *spng_version_string(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SPNG_H */
|
7
externals/lodepng/CMakeLists.txt
vendored
7
externals/lodepng/CMakeLists.txt
vendored
@ -1,7 +0,0 @@
|
||||
add_library(lodepng
|
||||
lodepng/lodepng.cpp
|
||||
lodepng/lodepng.h
|
||||
)
|
||||
|
||||
create_target_directory_groups(lodepng)
|
||||
target_include_directories(lodepng INTERFACE lodepng)
|
1
externals/lodepng/lodepng
vendored
1
externals/lodepng/lodepng
vendored
Submodule externals/lodepng/lodepng deleted from 18964554bc
2
externals/sdl2/CMakeLists.txt
vendored
2
externals/sdl2/CMakeLists.txt
vendored
@ -39,9 +39,9 @@ set(SDL_JOYSTICK ON CACHE BOOL "")
|
||||
set(SDL_HAPTIC OFF CACHE BOOL "")
|
||||
set(SDL_HIDAPI ON CACHE BOOL "")
|
||||
set(SDL_POWER OFF CACHE BOOL "")
|
||||
set(SDL_THREADS ON CACHE BOOL "")
|
||||
set(SDL_TIMERS ON CACHE BOOL "")
|
||||
set(SDL_FILE ON CACHE BOOL "")
|
||||
set(SDL_THREADS ON CACHE BOOL "")
|
||||
set(SDL_LOADSO ON CACHE BOOL "")
|
||||
set(SDL_CPUINFO OFF CACHE BOOL "")
|
||||
set(SDL_FILESYSTEM OFF CACHE BOOL "")
|
||||
|
1
externals/sirit
vendored
Submodule
1
externals/sirit
vendored
Submodule
Submodule externals/sirit added at f0b6bbe55b
19670
externals/vma/vk_mem_alloc.h
vendored
Normal file
19670
externals/vma/vk_mem_alloc.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
externals/vulkan-headers
vendored
Submodule
1
externals/vulkan-headers
vendored
Submodule
Submodule externals/vulkan-headers added at a49166a89a
17
externals/zlib-ng/CMakeLists.txt
vendored
Normal file
17
externals/zlib-ng/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
set(ZLIB_ENABLE_TESTS OFF)
|
||||
set(ZLIBNG_ENABLE_TESTS OFF)
|
||||
set(WITH_GZFILEOP OFF)
|
||||
set(WITH_GTEST OFF)
|
||||
set(ZLIB_COMPAT ON)
|
||||
set(SKIP_INSTALL_ALL ON)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared library" OFF)
|
||||
|
||||
add_subdirectory(zlib-ng)
|
||||
|
||||
# Set ZLIB variables for find_package used by other projects
|
||||
set(ZLIB_INCLUDE_DIR ${CMAKE_BINARY_DIR}/zlib-ng CACHE STRING "Path to zlib include directory")
|
||||
set(ZLIB_LIBRARY ZLIB::ZLIB CACHE STRING "Path to zlib library")
|
||||
|
||||
# Setup zlib alias project so FindZLIB doesn't recreate it
|
||||
add_library(ZLIB::ZLIB ALIAS zlib)
|
1
externals/zlib-ng/zlib-ng
vendored
Submodule
1
externals/zlib-ng/zlib-ng
vendored
Submodule
Submodule externals/zlib-ng/zlib-ng added at c970422caa
@ -122,6 +122,7 @@ else()
|
||||
|
||||
if (MINGW)
|
||||
add_definitions(-DMINGW_HAS_SECURE_API)
|
||||
add_compile_options("-Wa,-mbig-obj")
|
||||
if (COMPILE_WITH_DWARF)
|
||||
add_compile_options("-gdwarf")
|
||||
endif()
|
||||
|
@ -18,15 +18,6 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
// This is important as it will run lint but not abort on error
|
||||
// Lint has some overly obnoxious "errors" that should really be warnings
|
||||
abortOnError false
|
||||
|
||||
//Uncomment disable lines for test builds...
|
||||
//disable 'MissingTranslation'bin
|
||||
//disable 'ExtraTranslation'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO If this is ever modified, change application_id in strings.xml
|
||||
@ -100,6 +91,10 @@ android {
|
||||
path "../../../CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
lint {
|
||||
abortOnError false
|
||||
}
|
||||
namespace 'org.citra.citra_emu'
|
||||
|
||||
defaultConfig {
|
||||
externalNativeBuild {
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.citra.citra_emu">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false"/>
|
||||
@ -39,7 +38,8 @@
|
||||
android:supportsRtl="true"
|
||||
android:isGame="true"
|
||||
android:banner="@mipmap/ic_launcher"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:debuggable="true">
|
||||
|
||||
<activity
|
||||
android:name="org.citra.citra_emu.ui.main.MainActivity"
|
||||
|
@ -496,6 +496,9 @@ public final class NativeLibrary {
|
||||
final int ErrorLoader_ErrorEncrypted = 5;
|
||||
final int ErrorLoader_ErrorInvalidFormat = 6;
|
||||
final int ErrorSystemFiles = 7;
|
||||
final int ErrorVideoCore = 8;
|
||||
final int ErrorVideoCore_ErrorGenericDrivers = 9;
|
||||
final int ErrorVideoCore_ErrorBelowGL33 = 10;
|
||||
final int ShutdownRequested = 11;
|
||||
final int ErrorUnknown = 12;
|
||||
|
||||
|
@ -356,6 +356,8 @@ public final class SettingsFragmentPresenter {
|
||||
|
||||
SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER);
|
||||
Setting graphicsApi = rendererSection.getSetting(SettingsFile.KEY_GRAPHICS_API);
|
||||
Setting spvShaderGen = rendererSection.getSetting(SettingsFile.KEY_SPIRV_SHADER_GEN);
|
||||
Setting asyncShaders = rendererSection.getSetting(SettingsFile.KEY_ASYNC_SHADERS);
|
||||
Setting resolutionFactor = rendererSection.getSetting(SettingsFile.KEY_RESOLUTION_FACTOR);
|
||||
Setting filterMode = rendererSection.getSetting(SettingsFile.KEY_FILTER_MODE);
|
||||
Setting shadersAccurateMul = rendererSection.getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
|
||||
@ -372,7 +374,9 @@ public final class SettingsFragmentPresenter {
|
||||
//Setting preloadTextures = utilitySection.getSetting(SettingsFile.KEY_PRELOAD_TEXTURES);
|
||||
|
||||
sl.add(new HeaderSetting(null, null, R.string.renderer, 0));
|
||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_GRAPHICS_API, Settings.SECTION_RENDERER, R.string.graphics_api, 0, R.array.graphicsApiNames, R.array.graphicsApiValues, 0, graphicsApi));
|
||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_GRAPHICS_API, Settings.SECTION_RENDERER, R.string.graphics_api, 0, R.array.graphicsApiNames, R.array.graphicsApiValues, 2, graphicsApi));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_SPIRV_SHADER_GEN, Settings.SECTION_RENDERER, R.string.spirv_shader_gen, R.string.spirv_shader_gen_description, true, spvShaderGen));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_ASYNC_SHADERS, Settings.SECTION_RENDERER, R.string.async_shaders, R.string.async_shaders_description, false, asyncShaders));
|
||||
sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_FILTER_MODE, Settings.SECTION_RENDERER, R.string.linear_filtering, R.string.linear_filtering_description, true, filterMode));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL, Settings.SECTION_RENDERER, R.string.shaders_accurate_mul, R.string.shaders_accurate_mul_description, false, shadersAccurateMul));
|
||||
@ -411,12 +415,14 @@ public final class SettingsFragmentPresenter {
|
||||
SettingSection coreSection = mSettings.getSection(Settings.SECTION_CORE);
|
||||
SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER);
|
||||
Setting useCpuJit = coreSection.getSetting(SettingsFile.KEY_CPU_JIT);
|
||||
Setting hardwareRenderer = rendererSection.getSetting(SettingsFile.KEY_HW_RENDERER);
|
||||
Setting hardwareShader = rendererSection.getSetting(SettingsFile.KEY_HW_SHADER);
|
||||
Setting vsyncEnable = rendererSection.getSetting(SettingsFile.KEY_USE_VSYNC);
|
||||
Setting rendererDebug = rendererSection.getSetting(SettingsFile.KEY_RENDERER_DEBUG);
|
||||
|
||||
sl.add(new HeaderSetting(null, null, R.string.debug_warning, 0));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, Settings.SECTION_CORE, R.string.cpu_jit, R.string.cpu_jit_description, true, useCpuJit, true, mView));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_RENDERER, Settings.SECTION_RENDERER, R.string.hw_renderer, R.string.hw_renderer_description, true, hardwareRenderer, true, mView));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_SHADER, Settings.SECTION_RENDERER, R.string.hw_shaders, R.string.hw_shaders_description, true, hardwareShader, true, mView));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_VSYNC, Settings.SECTION_RENDERER, R.string.vsync, R.string.vsync_description, true, vsyncEnable));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_RENDERER_DEBUG, Settings.SECTION_RENDERER, R.string.renderer_debug, R.string.renderer_debug_description, false, rendererDebug));
|
||||
|
@ -45,7 +45,10 @@ public final class SettingsFile {
|
||||
public static final String KEY_PREMIUM = "premium";
|
||||
|
||||
public static final String KEY_GRAPHICS_API = "graphics_api";
|
||||
public static final String KEY_SPIRV_SHADER_GEN = "spirv_shader_gen";
|
||||
public static final String KEY_RENDERER_DEBUG = "renderer_debug";
|
||||
public static final String KEY_ASYNC_SHADERS = "async_shader_compilation";
|
||||
public static final String KEY_HW_RENDERER = "use_hw_renderer";
|
||||
public static final String KEY_HW_SHADER = "use_hw_shader";
|
||||
public static final String KEY_SHADERS_ACCURATE_MUL = "shaders_accurate_mul";
|
||||
public static final String KEY_USE_SHADER_JIT = "use_shader_jit";
|
||||
|
@ -125,8 +125,9 @@ public final class GameDatabase extends SQLiteOpenHelper {
|
||||
|
||||
while (fileCursor.moveToNext()) {
|
||||
String gamePath = fileCursor.getString(GAME_COLUMN_PATH);
|
||||
File game = new File(gamePath);
|
||||
|
||||
if (!FileUtil.Exists(mContext, gamePath)) {
|
||||
if (!game.exists()) {
|
||||
Log.error("[GameDatabase] Game file no longer exists. Removing from the library: " +
|
||||
gamePath);
|
||||
database.delete(TABLE_NAME_GAMES,
|
||||
|
@ -19,14 +19,16 @@ add_library(citra-android SHARED
|
||||
default_ini.h
|
||||
emu_window/emu_window.cpp
|
||||
emu_window/emu_window.h
|
||||
emu_window/emu_window_gl.cpp
|
||||
emu_window/emu_window_gl.h
|
||||
emu_window/emu_window_vk.cpp
|
||||
emu_window/emu_window_vk.h
|
||||
game_info.cpp
|
||||
game_info.h
|
||||
game_settings.cpp
|
||||
game_settings.h
|
||||
id_cache.cpp
|
||||
id_cache.h
|
||||
lodepng_image_interface.cpp
|
||||
lodepng_image_interface.h
|
||||
mic.cpp
|
||||
mic.h
|
||||
native.cpp
|
||||
@ -36,6 +38,6 @@ add_library(citra-android SHARED
|
||||
)
|
||||
|
||||
target_link_libraries(citra-android PRIVATE audio_core common core input_common network)
|
||||
target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics lodepng log mediandk yuv)
|
||||
target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics log mediandk yuv)
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android)
|
||||
|
@ -82,30 +82,6 @@ void Config::UpdateCFG() {
|
||||
cfg->UpdateConfigNANDSavegame();
|
||||
}
|
||||
|
||||
template <>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
|
||||
std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
|
||||
if (setting_value.empty()) {
|
||||
setting_value = setting.GetDefault();
|
||||
}
|
||||
setting = std::move(setting_value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
|
||||
setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
||||
}
|
||||
|
||||
template <typename Type, bool ranged>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
|
||||
if constexpr (std::is_floating_point_v<Type>) {
|
||||
setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
|
||||
} else {
|
||||
setting = static_cast<Type>(sdl2_config->GetInteger(
|
||||
group, setting.GetLabel(), static_cast<long>(setting.GetDefault())));
|
||||
}
|
||||
}
|
||||
|
||||
void Config::ReadValues() {
|
||||
// Controls
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
@ -136,32 +112,45 @@ void Config::ReadValues() {
|
||||
InputCommon::CemuhookUDP::DEFAULT_PORT));
|
||||
|
||||
// Core
|
||||
ReadSetting("Core", Settings::values.use_cpu_jit);
|
||||
ReadSetting("Core", Settings::values.cpu_clock_percentage);
|
||||
Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
|
||||
Settings::values.cpu_clock_percentage =
|
||||
static_cast<int>(sdl2_config->GetInteger("Core", "cpu_clock_percentage", 100));
|
||||
|
||||
// Premium
|
||||
ReadSetting("Premium", Settings::values.texture_filter_name);
|
||||
Settings::values.texture_filter_name =
|
||||
sdl2_config->GetString("Premium", "texture_filter_name", "none");
|
||||
|
||||
// Renderer
|
||||
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", true);
|
||||
Settings::values.graphics_api =
|
||||
static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 2));
|
||||
Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "renderer_debug", false);
|
||||
Settings::values.async_shader_compilation =
|
||||
sdl2_config->GetBoolean("Renderer", "async_shader_compilation", true);
|
||||
Settings::values.spirv_shader_gen =
|
||||
sdl2_config->GetBoolean("Renderer", "spirv_shader_gen", true);
|
||||
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
|
||||
Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true);
|
||||
Settings::values.shaders_accurate_mul =
|
||||
sdl2_config->GetBoolean("Renderer", "shaders_accurate_mul", false);
|
||||
ReadSetting("Renderer", Settings::values.graphics_api);
|
||||
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
||||
ReadSetting("Renderer", Settings::values.use_shader_jit);
|
||||
ReadSetting("Renderer", Settings::values.resolution_factor);
|
||||
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
|
||||
ReadSetting("Renderer", Settings::values.use_vsync_new);
|
||||
Settings::values.use_shader_jit = sdl2_config->GetBoolean("Renderer", "use_shader_jit", true);
|
||||
Settings::values.resolution_factor =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Renderer", "resolution_factor", 1));
|
||||
Settings::values.use_disk_shader_cache =
|
||||
sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", true);
|
||||
Settings::values.use_vsync_new = sdl2_config->GetBoolean("Renderer", "use_vsync_new", true);
|
||||
|
||||
// Work around to map Android setting for enabling the frame limiter to the format Citra expects
|
||||
if (sdl2_config->GetBoolean("Renderer", "use_frame_limit", true)) {
|
||||
ReadSetting("Renderer", Settings::values.frame_limit);
|
||||
Settings::values.frame_limit =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100));
|
||||
} else {
|
||||
Settings::values.frame_limit = 0;
|
||||
}
|
||||
|
||||
ReadSetting("Renderer", Settings::values.render_3d);
|
||||
ReadSetting("Renderer", Settings::values.factor_3d);
|
||||
Settings::values.render_3d = static_cast<Settings::StereoRenderOption>(
|
||||
sdl2_config->GetInteger("Renderer", "render_3d", 0));
|
||||
Settings::values.factor_3d =
|
||||
static_cast<u8>(sdl2_config->GetInteger("Renderer", "factor_3d", 0));
|
||||
std::string default_shader = "none (builtin)";
|
||||
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Anaglyph)
|
||||
default_shader = "dubois (builtin)";
|
||||
@ -169,49 +158,70 @@ void Config::ReadValues() {
|
||||
default_shader = "horizontal (builtin)";
|
||||
Settings::values.pp_shader_name =
|
||||
sdl2_config->GetString("Renderer", "pp_shader_name", default_shader);
|
||||
ReadSetting("Renderer", Settings::values.filter_mode);
|
||||
Settings::values.filter_mode = sdl2_config->GetBoolean("Renderer", "filter_mode", true);
|
||||
|
||||
ReadSetting("Renderer", Settings::values.bg_red);
|
||||
ReadSetting("Renderer", Settings::values.bg_green);
|
||||
ReadSetting("Renderer", Settings::values.bg_blue);
|
||||
Settings::values.bg_red = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0));
|
||||
Settings::values.bg_green =
|
||||
static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0));
|
||||
Settings::values.bg_blue = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0));
|
||||
|
||||
// Layout
|
||||
Settings::values.layout_option = static_cast<Settings::LayoutOption>(sdl2_config->GetInteger(
|
||||
"Layout", "layout_option", static_cast<int>(Settings::LayoutOption::MobileLandscape)));
|
||||
ReadSetting("Layout", Settings::values.custom_layout);
|
||||
ReadSetting("Layout", Settings::values.custom_top_left);
|
||||
ReadSetting("Layout", Settings::values.custom_top_top);
|
||||
ReadSetting("Layout", Settings::values.custom_top_right);
|
||||
ReadSetting("Layout", Settings::values.custom_top_bottom);
|
||||
ReadSetting("Layout", Settings::values.custom_bottom_left);
|
||||
ReadSetting("Layout", Settings::values.custom_bottom_top);
|
||||
ReadSetting("Layout", Settings::values.custom_bottom_right);
|
||||
ReadSetting("Layout", Settings::values.custom_bottom_bottom);
|
||||
ReadSetting("Layout", Settings::values.cardboard_screen_size);
|
||||
ReadSetting("Layout", Settings::values.cardboard_x_shift);
|
||||
ReadSetting("Layout", Settings::values.cardboard_y_shift);
|
||||
Settings::values.custom_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false);
|
||||
Settings::values.custom_top_left =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_left", 0));
|
||||
Settings::values.custom_top_top =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_top", 0));
|
||||
Settings::values.custom_top_right =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_right", 400));
|
||||
Settings::values.custom_top_bottom =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_bottom", 240));
|
||||
Settings::values.custom_bottom_left =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_left", 40));
|
||||
Settings::values.custom_bottom_top =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_top", 240));
|
||||
Settings::values.custom_bottom_right =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_right", 360));
|
||||
Settings::values.custom_bottom_bottom =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_bottom", 480));
|
||||
Settings::values.cardboard_screen_size =
|
||||
static_cast<int>(sdl2_config->GetInteger("Layout", "cardboard_screen_size", 85));
|
||||
Settings::values.cardboard_x_shift =
|
||||
static_cast<int>(sdl2_config->GetInteger("Layout", "cardboard_x_shift", 0));
|
||||
Settings::values.cardboard_y_shift =
|
||||
static_cast<int>(sdl2_config->GetInteger("Layout", "cardboard_y_shift", 0));
|
||||
|
||||
// Utility
|
||||
ReadSetting("Utility", Settings::values.dump_textures);
|
||||
ReadSetting("Utility", Settings::values.custom_textures);
|
||||
ReadSetting("Utility", Settings::values.preload_textures);
|
||||
Settings::values.dump_textures = sdl2_config->GetBoolean("Utility", "dump_textures", false);
|
||||
Settings::values.custom_textures = sdl2_config->GetBoolean("Utility", "custom_textures", false);
|
||||
Settings::values.preload_textures =
|
||||
sdl2_config->GetBoolean("Utility", "preload_textures", false);
|
||||
|
||||
// Audio
|
||||
ReadSetting("Audio", Settings::values.audio_emulation);
|
||||
ReadSetting("Audio", Settings::values.sink_id);
|
||||
ReadSetting("Audio", Settings::values.enable_audio_stretching);
|
||||
ReadSetting("Audio", Settings::values.audio_device_id);
|
||||
ReadSetting("Audio", Settings::values.volume);
|
||||
ReadSetting("Audio", Settings::values.mic_input_device);
|
||||
ReadSetting("Audio", Settings::values.mic_input_type);
|
||||
Settings::values.audio_emulation =
|
||||
static_cast<Settings::AudioEmulation>(sdl2_config->GetInteger(
|
||||
"Audio", "audio_emulation", static_cast<int>(Settings::AudioEmulation::HLE)));
|
||||
Settings::values.sink_id = sdl2_config->GetString("Audio", "output_engine", "auto");
|
||||
Settings::values.enable_audio_stretching =
|
||||
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
|
||||
Settings::values.audio_device_id = sdl2_config->GetString("Audio", "output_device", "auto");
|
||||
Settings::values.volume = static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1));
|
||||
Settings::values.mic_input_device =
|
||||
sdl2_config->GetString("Audio", "mic_input_device", "Default");
|
||||
Settings::values.mic_input_type =
|
||||
static_cast<Settings::MicInputType>(sdl2_config->GetInteger("Audio", "mic_input_type", 1));
|
||||
|
||||
// Data Storage
|
||||
ReadSetting("Data Storage", Settings::values.use_virtual_sd);
|
||||
Settings::values.use_virtual_sd =
|
||||
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
|
||||
|
||||
// System
|
||||
ReadSetting("System", Settings::values.is_new_3ds);
|
||||
ReadSetting("System", Settings::values.region_value);
|
||||
ReadSetting("System", Settings::values.init_clock);
|
||||
Settings::values.is_new_3ds = sdl2_config->GetBoolean("System", "is_new_3ds", true);
|
||||
Settings::values.region_value =
|
||||
sdl2_config->GetInteger("System", "region_value", Settings::REGION_VALUE_AUTO_SELECT);
|
||||
Settings::values.init_clock =
|
||||
static_cast<Settings::InitClock>(sdl2_config->GetInteger("System", "init_clock", 0));
|
||||
{
|
||||
std::tm t;
|
||||
t.tm_sec = 1;
|
||||
@ -232,8 +242,10 @@ void Config::ReadValues() {
|
||||
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
ReadSetting("System", Settings::values.plugin_loader_enabled);
|
||||
ReadSetting("System", Settings::values.allow_plugin_loader);
|
||||
Settings::values.plugin_loader_enabled =
|
||||
sdl2_config->GetBoolean("System", "plugin_loader", false);
|
||||
Settings::values.allow_plugin_loader =
|
||||
sdl2_config->GetBoolean("System", "allow_plugin_loader", true);
|
||||
|
||||
// Camera
|
||||
using namespace Service::CAM;
|
||||
@ -257,14 +269,14 @@ void Config::ReadValues() {
|
||||
sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0);
|
||||
|
||||
// Miscellaneous
|
||||
ReadSetting("Miscellaneous", Settings::values.log_filter);
|
||||
Settings::values.log_filter = sdl2_config->GetString("Miscellaneous", "log_filter", "*:Info");
|
||||
|
||||
// Debugging
|
||||
Settings::values.record_frame_times =
|
||||
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
|
||||
ReadSetting("Debugging", Settings::values.renderer_debug);
|
||||
ReadSetting("Debugging", Settings::values.use_gdbstub);
|
||||
ReadSetting("Debugging", Settings::values.gdbstub_port);
|
||||
Settings::values.use_gdbstub = sdl2_config->GetBoolean("Debugging", "use_gdbstub", false);
|
||||
Settings::values.gdbstub_port =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689));
|
||||
|
||||
for (const auto& service_module : Service::service_module_map) {
|
||||
bool use_lle = sdl2_config->GetBoolean("Debugging", "LLE\\" + service_module.name, false);
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "common/settings.h"
|
||||
|
||||
class INIReader;
|
||||
|
||||
@ -24,14 +23,4 @@ public:
|
||||
~Config();
|
||||
|
||||
void Reload();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Applies a value read from the sdl2_config to a Setting.
|
||||
*
|
||||
* @param group The name of the INI group
|
||||
* @param setting The yuzu setting to modify
|
||||
*/
|
||||
template <typename Type, bool ranged>
|
||||
void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
|
||||
};
|
||||
|
@ -98,10 +98,26 @@ use_cpu_jit =
|
||||
cpu_clock_percentage =
|
||||
|
||||
[Renderer]
|
||||
# Whether to render using OpenGL
|
||||
# 1: OpenGLES (default)
|
||||
# Whether to render using OpenGL or Vulkan
|
||||
# 1: OpenGL, 2 (default): Vulkan
|
||||
graphics_api =
|
||||
|
||||
# Whether to emit PICA fragment shader using SPIRV or GLSL
|
||||
# 1: SPIR-V (default), 0: GLSL
|
||||
spirv_shader_gen =
|
||||
|
||||
# Whether to use a worker thread for vulkan command buffer recording
|
||||
# 1: On (default), 0: Off
|
||||
async_command_recording =
|
||||
|
||||
# Whether to enable additional debugging information during emulation
|
||||
# 1: On, 0 (default): Off
|
||||
renderer_debug =
|
||||
|
||||
# Whether to use software or hardware rendering.
|
||||
# 0: Software, 1 (default): Hardware
|
||||
use_hw_renderer =
|
||||
|
||||
# Whether to use hardware shaders to emulate 3DS shaders
|
||||
# 0: Software, 1 (default): Hardware
|
||||
use_hw_shader =
|
||||
@ -114,6 +130,10 @@ separable_shader =
|
||||
# 0: Off (Default. Faster, but causes issues in some games) 1: On (Slower, but correct)
|
||||
shaders_accurate_mul =
|
||||
|
||||
# Enable asynchronous GPU emulation
|
||||
# 0: Off (Slower, but more accurate) 1: On (Default. Faster, but may cause issues in some games)
|
||||
use_asynchronous_gpu_emulation =
|
||||
|
||||
# Whether to use the Just-In-Time (JIT) compiler for shader emulation
|
||||
# 0: Interpreter (slow), 1 (default): JIT (fast)
|
||||
use_shader_jit =
|
||||
@ -317,15 +337,9 @@ log_filter = *:Info
|
||||
[Debugging]
|
||||
# Record frame time data, can be found in the log directory. Boolean value
|
||||
record_frame_times =
|
||||
|
||||
# Whether to enable additional debugging information during emulation
|
||||
# 0 (default): Off, 1: On
|
||||
renderer_debug =
|
||||
|
||||
# Port for listening to GDB connections.
|
||||
use_gdbstub=false
|
||||
gdbstub_port=24689
|
||||
|
||||
# To LLE a service module add "LLE\<module name>=true"
|
||||
|
||||
[WebService]
|
||||
|
@ -6,10 +6,7 @@
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include <android/native_window_jni.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "input_common/main.h"
|
||||
@ -20,52 +17,6 @@
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
static constexpr std::array<EGLint, 15> egl_attribs{EGL_SURFACE_TYPE,
|
||||
EGL_WINDOW_BIT,
|
||||
EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_ES3_BIT_KHR,
|
||||
EGL_BLUE_SIZE,
|
||||
8,
|
||||
EGL_GREEN_SIZE,
|
||||
8,
|
||||
EGL_RED_SIZE,
|
||||
8,
|
||||
EGL_DEPTH_SIZE,
|
||||
0,
|
||||
EGL_STENCIL_SIZE,
|
||||
0,
|
||||
EGL_NONE};
|
||||
static constexpr std::array<EGLint, 5> egl_empty_attribs{EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
|
||||
static constexpr std::array<EGLint, 4> egl_context_attribs{EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
||||
|
||||
SharedContext_Android::SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
|
||||
EGLContext egl_share_context)
|
||||
: egl_display{egl_display}, egl_surface{eglCreatePbufferSurface(egl_display, egl_config,
|
||||
egl_empty_attribs.data())},
|
||||
egl_context{eglCreateContext(egl_display, egl_config, egl_share_context,
|
||||
egl_context_attribs.data())} {
|
||||
ASSERT_MSG(egl_surface, "eglCreatePbufferSurface() failed!");
|
||||
ASSERT_MSG(egl_context, "eglCreateContext() failed!");
|
||||
}
|
||||
|
||||
SharedContext_Android::~SharedContext_Android() {
|
||||
if (!eglDestroySurface(egl_display, egl_surface)) {
|
||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||
}
|
||||
|
||||
if (!eglDestroyContext(egl_display, egl_context)) {
|
||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||
}
|
||||
}
|
||||
|
||||
void SharedContext_Android::MakeCurrent() {
|
||||
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||
}
|
||||
|
||||
void SharedContext_Android::DoneCurrent() {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
static bool IsPortraitMode() {
|
||||
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(
|
||||
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
|
||||
@ -79,6 +30,10 @@ static void UpdateLandscapeScreenLayout() {
|
||||
|
||||
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||
render_window = surface;
|
||||
|
||||
window_info.type = Frontend::WindowSystemType::Android;
|
||||
window_info.render_surface = surface;
|
||||
|
||||
StopPresenting();
|
||||
}
|
||||
|
||||
@ -98,6 +53,7 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) {
|
||||
void EmuWindow_Android::OnFramebufferSizeChanged() {
|
||||
UpdateLandscapeScreenLayout();
|
||||
const bool is_portrait_mode{IsPortraitMode()};
|
||||
|
||||
const int bigger{window_width > window_height ? window_width : window_height};
|
||||
const int smaller{window_width < window_height ? window_width : window_height};
|
||||
if (is_portrait_mode) {
|
||||
@ -107,7 +63,7 @@ void EmuWindow_Android::OnFramebufferSizeChanged() {
|
||||
}
|
||||
}
|
||||
|
||||
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
|
||||
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) : host_window{surface} {
|
||||
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
|
||||
|
||||
if (!surface) {
|
||||
@ -115,108 +71,10 @@ EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
window_width = ANativeWindow_getWidth(surface);
|
||||
window_height = ANativeWindow_getHeight(surface);
|
||||
|
||||
Network::Init();
|
||||
|
||||
host_window = surface;
|
||||
|
||||
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
|
||||
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
|
||||
return;
|
||||
}
|
||||
if (eglInitialize(egl_display, 0, 0) != EGL_TRUE) {
|
||||
LOG_CRITICAL(Frontend, "eglInitialize() failed");
|
||||
return;
|
||||
}
|
||||
if (EGLint egl_num_configs{}; eglChooseConfig(egl_display, egl_attribs.data(), &egl_config, 1,
|
||||
&egl_num_configs) != EGL_TRUE) {
|
||||
LOG_CRITICAL(Frontend, "eglChooseConfig() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
CreateWindowSurface();
|
||||
|
||||
if (eglQuerySurface(egl_display, egl_surface, EGL_WIDTH, &window_width) != EGL_TRUE) {
|
||||
return;
|
||||
}
|
||||
if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data());
|
||||
egl_context == EGL_NO_CONTEXT) {
|
||||
LOG_CRITICAL(Frontend, "eglCreateContext() failed");
|
||||
return;
|
||||
}
|
||||
if (eglSurfaceAttrib(egl_display, egl_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) !=
|
||||
EGL_TRUE) {
|
||||
LOG_CRITICAL(Frontend, "eglSurfaceAttrib() failed");
|
||||
return;
|
||||
}
|
||||
if (core_context = CreateSharedContext(); !core_context) {
|
||||
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
|
||||
return;
|
||||
}
|
||||
if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) != EGL_TRUE) {
|
||||
LOG_CRITICAL(Frontend, "eglMakeCurrent() failed");
|
||||
return;
|
||||
}
|
||||
if (!gladLoadGLES2Loader((GLADloadproc)eglGetProcAddress)) {
|
||||
LOG_CRITICAL(Frontend, "gladLoadGLES2Loader() failed");
|
||||
return;
|
||||
}
|
||||
if (!eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0)) {
|
||||
LOG_CRITICAL(Frontend, "eglSwapInterval() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
OnFramebufferSizeChanged();
|
||||
}
|
||||
|
||||
bool EmuWindow_Android::CreateWindowSurface() {
|
||||
if (!host_window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
EGLint format{};
|
||||
eglGetConfigAttrib(egl_display, egl_config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
|
||||
|
||||
if (egl_surface = eglCreateWindowSurface(egl_display, egl_config, host_window, 0);
|
||||
egl_surface == EGL_NO_SURFACE) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return !!egl_surface;
|
||||
}
|
||||
|
||||
void EmuWindow_Android::DestroyWindowSurface() {
|
||||
if (!egl_surface) {
|
||||
return;
|
||||
}
|
||||
if (eglGetCurrentSurface(EGL_DRAW) == egl_surface) {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
if (!eglDestroySurface(egl_display, egl_surface)) {
|
||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||
}
|
||||
egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
void EmuWindow_Android::DestroyContext() {
|
||||
if (!egl_context) {
|
||||
return;
|
||||
}
|
||||
if (eglGetCurrentContext() == egl_context) {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
if (!eglDestroyContext(egl_display, egl_context)) {
|
||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||
}
|
||||
if (!eglTerminate(egl_display)) {
|
||||
LOG_CRITICAL(Frontend, "eglTerminate() failed");
|
||||
}
|
||||
egl_context = EGL_NO_CONTEXT;
|
||||
egl_display = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
||||
EmuWindow_Android::~EmuWindow_Android() {
|
||||
@ -224,34 +82,6 @@ EmuWindow_Android::~EmuWindow_Android() {
|
||||
DestroyContext();
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android::CreateSharedContext() const {
|
||||
return std::make_unique<SharedContext_Android>(egl_display, egl_config, egl_context);
|
||||
}
|
||||
|
||||
void EmuWindow_Android::StopPresenting() {
|
||||
if (presenting_state == PresentingState::Running) {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
presenting_state = PresentingState::Stopped;
|
||||
}
|
||||
|
||||
void EmuWindow_Android::TryPresenting() {
|
||||
if (presenting_state != PresentingState::Running) {
|
||||
if (presenting_state == PresentingState::Initial) {
|
||||
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
presenting_state = PresentingState::Running;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
|
||||
if (VideoCore::g_renderer) {
|
||||
VideoCore::g_renderer->TryPresent(0);
|
||||
eglSwapBuffers(egl_display, egl_surface);
|
||||
}
|
||||
}
|
||||
|
||||
void EmuWindow_Android::PollEvents() {
|
||||
if (!render_window) {
|
||||
return;
|
||||
|
@ -1,42 +1,17 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Copyright 2022 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "core/frontend/emu_window.h"
|
||||
|
||||
struct ANativeWindow;
|
||||
|
||||
class SharedContext_Android : public Frontend::GraphicsContext {
|
||||
public:
|
||||
SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
|
||||
EGLContext egl_share_context);
|
||||
|
||||
~SharedContext_Android() override;
|
||||
|
||||
void MakeCurrent() override;
|
||||
|
||||
void DoneCurrent() override;
|
||||
|
||||
private:
|
||||
EGLDisplay egl_display{};
|
||||
EGLSurface egl_surface{};
|
||||
EGLContext egl_context{};
|
||||
};
|
||||
|
||||
class EmuWindow_Android : public Frontend::EmuWindow {
|
||||
public:
|
||||
EmuWindow_Android(ANativeWindow* surface);
|
||||
~EmuWindow_Android();
|
||||
|
||||
void Present();
|
||||
|
||||
/// Called by the onSurfaceChanges() method to change the surface
|
||||
void OnSurfaceChanged(ANativeWindow* surface);
|
||||
|
||||
@ -47,31 +22,34 @@ public:
|
||||
void OnTouchMoved(int x, int y);
|
||||
|
||||
void PollEvents() override;
|
||||
|
||||
void MakeCurrent() override;
|
||||
|
||||
void DoneCurrent() override;
|
||||
|
||||
void TryPresenting();
|
||||
void StopPresenting();
|
||||
virtual void TryPresenting() = 0;
|
||||
|
||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||
virtual void StopPresenting() = 0;
|
||||
|
||||
private:
|
||||
protected:
|
||||
void OnFramebufferSizeChanged();
|
||||
bool CreateWindowSurface();
|
||||
void DestroyWindowSurface();
|
||||
void DestroyContext();
|
||||
|
||||
/// Creates the API specific window surface
|
||||
virtual bool CreateWindowSurface() {}
|
||||
|
||||
/// Destroys the API specific window surface
|
||||
virtual void DestroyWindowSurface() {}
|
||||
|
||||
/// Destroys the graphics context
|
||||
virtual void DestroyContext() {}
|
||||
|
||||
protected:
|
||||
ANativeWindow* render_window{};
|
||||
ANativeWindow* host_window{};
|
||||
|
||||
int window_width{};
|
||||
int window_height{};
|
||||
|
||||
EGLConfig egl_config;
|
||||
EGLSurface egl_surface{};
|
||||
EGLContext egl_context{};
|
||||
EGLDisplay egl_display{};
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> core_context;
|
||||
|
||||
enum class PresentingState {
|
||||
|
205
src/android/app/src/main/jni/emu_window/emu_window_gl.cpp
Normal file
205
src/android/app/src/main/jni/emu_window/emu_window_gl.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include <android/native_window_jni.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "input_common/main.h"
|
||||
#include "jni/emu_window/emu_window_gl.h"
|
||||
#include "jni/id_cache.h"
|
||||
#include "jni/input_manager.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
static constexpr std::array<EGLint, 15> egl_attribs{EGL_SURFACE_TYPE,
|
||||
EGL_WINDOW_BIT,
|
||||
EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_ES3_BIT_KHR,
|
||||
EGL_BLUE_SIZE,
|
||||
8,
|
||||
EGL_GREEN_SIZE,
|
||||
8,
|
||||
EGL_RED_SIZE,
|
||||
8,
|
||||
EGL_DEPTH_SIZE,
|
||||
0,
|
||||
EGL_STENCIL_SIZE,
|
||||
0,
|
||||
EGL_NONE};
|
||||
static constexpr std::array<EGLint, 5> egl_empty_attribs{EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
|
||||
static constexpr std::array<EGLint, 4> egl_context_attribs{EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
||||
|
||||
class SharedContext_Android : public Frontend::GraphicsContext {
|
||||
public:
|
||||
SharedContext_Android(EGLDisplay egl_display, EGLConfig egl_config,
|
||||
EGLContext egl_share_context)
|
||||
: egl_display{egl_display}, egl_surface{eglCreatePbufferSurface(egl_display, egl_config,
|
||||
egl_empty_attribs.data())},
|
||||
egl_context{eglCreateContext(egl_display, egl_config, egl_share_context,
|
||||
egl_context_attribs.data())} {
|
||||
ASSERT_MSG(egl_surface, "eglCreatePbufferSurface() failed!");
|
||||
ASSERT_MSG(egl_context, "eglCreateContext() failed!");
|
||||
}
|
||||
|
||||
~SharedContext_Android() override {
|
||||
if (!eglDestroySurface(egl_display, egl_surface)) {
|
||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||
}
|
||||
|
||||
if (!eglDestroyContext(egl_display, egl_context)) {
|
||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||
}
|
||||
}
|
||||
|
||||
void MakeCurrent() {
|
||||
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||
}
|
||||
|
||||
void DoneCurrent() {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
private:
|
||||
EGLDisplay egl_display{};
|
||||
EGLSurface egl_surface{};
|
||||
EGLContext egl_context{};
|
||||
};
|
||||
|
||||
EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(ANativeWindow* surface)
|
||||
: EmuWindow_Android{surface} {
|
||||
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
|
||||
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
|
||||
return;
|
||||
}
|
||||
if (eglInitialize(egl_display, 0, 0) != EGL_TRUE) {
|
||||
LOG_CRITICAL(Frontend, "eglInitialize() failed");
|
||||
return;
|
||||
}
|
||||
if (EGLint egl_num_configs{}; eglChooseConfig(egl_display, egl_attribs.data(), &egl_config, 1,
|
||||
&egl_num_configs) != EGL_TRUE) {
|
||||
LOG_CRITICAL(Frontend, "eglChooseConfig() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
CreateWindowSurface();
|
||||
|
||||
if (eglQuerySurface(egl_display, egl_surface, EGL_WIDTH, &window_width) != EGL_TRUE) {
|
||||
return;
|
||||
}
|
||||
if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data());
|
||||
egl_context == EGL_NO_CONTEXT) {
|
||||
LOG_CRITICAL(Frontend, "eglCreateContext() failed");
|
||||
return;
|
||||
}
|
||||
if (eglSurfaceAttrib(egl_display, egl_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) !=
|
||||
EGL_TRUE) {
|
||||
LOG_CRITICAL(Frontend, "eglSurfaceAttrib() failed");
|
||||
return;
|
||||
}
|
||||
if (core_context = CreateSharedContext(); !core_context) {
|
||||
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
|
||||
return;
|
||||
}
|
||||
if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) != EGL_TRUE) {
|
||||
LOG_CRITICAL(Frontend, "eglMakeCurrent() failed");
|
||||
return;
|
||||
}
|
||||
if (!gladLoadGLES2Loader((GLADloadproc)eglGetProcAddress)) {
|
||||
LOG_CRITICAL(Frontend, "gladLoadGLES2Loader() failed");
|
||||
return;
|
||||
}
|
||||
if (!eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0)) {
|
||||
LOG_CRITICAL(Frontend, "eglSwapInterval() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
OnFramebufferSizeChanged();
|
||||
}
|
||||
|
||||
bool EmuWindow_Android_OpenGL::CreateWindowSurface() {
|
||||
if (!host_window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
EGLint format{};
|
||||
eglGetConfigAttrib(egl_display, egl_config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
|
||||
|
||||
if (egl_surface = eglCreateWindowSurface(egl_display, egl_config, host_window, 0);
|
||||
egl_surface == EGL_NO_SURFACE) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return !!egl_surface;
|
||||
}
|
||||
|
||||
void EmuWindow_Android_OpenGL::DestroyWindowSurface() {
|
||||
if (!egl_surface) {
|
||||
return;
|
||||
}
|
||||
if (eglGetCurrentSurface(EGL_DRAW) == egl_surface) {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
if (!eglDestroySurface(egl_display, egl_surface)) {
|
||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||
}
|
||||
egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
void EmuWindow_Android_OpenGL::DestroyContext() {
|
||||
if (!egl_context) {
|
||||
return;
|
||||
}
|
||||
if (eglGetCurrentContext() == egl_context) {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
if (!eglDestroyContext(egl_display, egl_context)) {
|
||||
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
|
||||
}
|
||||
if (!eglTerminate(egl_display)) {
|
||||
LOG_CRITICAL(Frontend, "eglTerminate() failed");
|
||||
}
|
||||
egl_context = EGL_NO_CONTEXT;
|
||||
egl_display = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_OpenGL::CreateSharedContext() const {
|
||||
return std::make_unique<SharedContext_Android>(egl_display, egl_config, egl_context);
|
||||
}
|
||||
|
||||
void EmuWindow_Android_OpenGL::StopPresenting() {
|
||||
if (presenting_state == PresentingState::Running) {
|
||||
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
presenting_state = PresentingState::Stopped;
|
||||
}
|
||||
|
||||
void EmuWindow_Android_OpenGL::TryPresenting() {
|
||||
if (presenting_state != PresentingState::Running) {
|
||||
if (presenting_state == PresentingState::Initial) {
|
||||
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
presenting_state = PresentingState::Running;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
|
||||
if (VideoCore::g_renderer) {
|
||||
VideoCore::g_renderer->TryPresent(0);
|
||||
eglSwapBuffers(egl_display, egl_surface);
|
||||
}
|
||||
}
|
36
src/android/app/src/main/jni/emu_window/emu_window_gl.h
Normal file
36
src/android/app/src/main/jni/emu_window/emu_window_gl.h
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "jni/emu_window/emu_window.h"
|
||||
|
||||
struct ANativeWindow;
|
||||
|
||||
class EmuWindow_Android_OpenGL : public EmuWindow_Android {
|
||||
public:
|
||||
EmuWindow_Android_OpenGL(ANativeWindow* surface);
|
||||
~EmuWindow_Android_OpenGL() override = default;
|
||||
|
||||
void TryPresenting() override;
|
||||
void StopPresenting() override;
|
||||
|
||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||
|
||||
private:
|
||||
bool CreateWindowSurface() override;
|
||||
void DestroyWindowSurface() override;
|
||||
void DestroyContext() override;
|
||||
|
||||
private:
|
||||
EGLConfig egl_config;
|
||||
EGLSurface egl_surface{};
|
||||
EGLContext egl_context{};
|
||||
EGLDisplay egl_display{};
|
||||
};
|
65
src/android/app/src/main/jni/emu_window/emu_window_vk.cpp
Normal file
65
src/android/app/src/main/jni/emu_window/emu_window_vk.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <android/native_window_jni.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "input_common/main.h"
|
||||
#include "jni/emu_window/emu_window_vk.h"
|
||||
#include "jni/id_cache.h"
|
||||
#include "jni/input_manager.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
class SharedContext_Android : public Frontend::GraphicsContext {};
|
||||
|
||||
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(ANativeWindow* surface)
|
||||
: EmuWindow_Android{surface} {
|
||||
CreateWindowSurface();
|
||||
|
||||
if (core_context = CreateSharedContext(); !core_context) {
|
||||
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
OnFramebufferSizeChanged();
|
||||
}
|
||||
|
||||
bool EmuWindow_Android_Vulkan::CreateWindowSurface() {
|
||||
if (!host_window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
window_info.type = Frontend::WindowSystemType::Android;
|
||||
window_info.render_surface = host_window;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_Vulkan::CreateSharedContext() const {
|
||||
return std::make_unique<SharedContext_Android>();
|
||||
}
|
||||
|
||||
void EmuWindow_Android_Vulkan::StopPresenting() {
|
||||
presenting_state = PresentingState::Stopped;
|
||||
}
|
||||
|
||||
void EmuWindow_Android_Vulkan::TryPresenting() {
|
||||
if (presenting_state != PresentingState::Running) {
|
||||
if (presenting_state == PresentingState::Initial) {
|
||||
presenting_state = PresentingState::Running;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (VideoCore::g_renderer) {
|
||||
VideoCore::g_renderer->TryPresent(0);
|
||||
}
|
||||
}
|
23
src/android/app/src/main/jni/emu_window/emu_window_vk.h
Normal file
23
src/android/app/src/main/jni/emu_window/emu_window_vk.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2022 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jni/emu_window/emu_window.h"
|
||||
|
||||
struct ANativeWindow;
|
||||
|
||||
class EmuWindow_Android_Vulkan : public EmuWindow_Android {
|
||||
public:
|
||||
EmuWindow_Android_Vulkan(ANativeWindow* surface);
|
||||
~EmuWindow_Android_Vulkan() override = default;
|
||||
|
||||
void TryPresenting() override;
|
||||
void StopPresenting() override;
|
||||
|
||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||
|
||||
private:
|
||||
bool CreateWindowSurface() override;
|
||||
};
|
@ -1,44 +0,0 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <lodepng.h>
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "jni/lodepng_image_interface.h"
|
||||
|
||||
bool LodePNGImageInterface::DecodePNG(std::vector<u8>& dst, u32& width, u32& height,
|
||||
const std::string& path) {
|
||||
FileUtil::IOFile file(path, "rb");
|
||||
size_t read_size = file.GetSize();
|
||||
std::vector<u8> in(read_size);
|
||||
if (file.ReadBytes(&in[0], read_size) != read_size) {
|
||||
LOG_CRITICAL(Frontend, "Failed to decode {}", path);
|
||||
}
|
||||
u32 lodepng_ret = lodepng::decode(dst, width, height, in);
|
||||
if (lodepng_ret) {
|
||||
LOG_CRITICAL(Frontend, "Failed to decode {} because {}", path,
|
||||
lodepng_error_text(lodepng_ret));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LodePNGImageInterface::EncodePNG(const std::string& path, const std::vector<u8>& src,
|
||||
u32 width, u32 height) {
|
||||
std::vector<u8> out;
|
||||
u32 lodepng_ret = lodepng::encode(out, src, width, height);
|
||||
if (lodepng_ret) {
|
||||
LOG_CRITICAL(Frontend, "Failed to encode {} because {}", path,
|
||||
lodepng_error_text(lodepng_ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
FileUtil::IOFile file(path, "wb");
|
||||
if (file.WriteBytes(&out[0], out.size()) != out.size()) {
|
||||
LOG_CRITICAL(Frontend, "Failed to save encode to path={}", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/frontend/image_interface.h"
|
||||
|
||||
class LodePNGImageInterface final : public Frontend::ImageInterface {
|
||||
public:
|
||||
bool DecodePNG(std::vector<u8>& dst, u32& width, u32& height, const std::string& path) override;
|
||||
bool EncodePNG(const std::string& path, const std::vector<u8>& src, u32 width,
|
||||
u32 height) override;
|
||||
};
|
@ -34,12 +34,12 @@
|
||||
#include "jni/camera/ndk_camera.h"
|
||||
#include "jni/camera/still_image_camera.h"
|
||||
#include "jni/config.h"
|
||||
#include "jni/emu_window/emu_window.h"
|
||||
#include "jni/emu_window/emu_window_gl.h"
|
||||
#include "jni/emu_window/emu_window_vk.h"
|
||||
#include "jni/game_info.h"
|
||||
#include "jni/game_settings.h"
|
||||
#include "jni/id_cache.h"
|
||||
#include "jni/input_manager.h"
|
||||
#include "jni/lodepng_image_interface.h"
|
||||
#include "jni/mic.h"
|
||||
#include "jni/native.h"
|
||||
#include "jni/ndk_motion.h"
|
||||
@ -149,14 +149,16 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
||||
return Core::System::ResultStatus::ErrorLoader;
|
||||
}
|
||||
|
||||
const auto graphics_api = Settings::values.graphics_api.GetValue();
|
||||
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
|
||||
switch (graphics_api) {
|
||||
case Settings::GraphicsAPI::OpenGL:
|
||||
window = std::make_unique<EmuWindow_Android>(s_surf);
|
||||
case Settings::GraphicsAPI::OpenGLES:
|
||||
window = std::make_unique<EmuWindow_Android_OpenGL>(s_surf);
|
||||
break;
|
||||
case Settings::GraphicsAPI::Vulkan:
|
||||
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf);
|
||||
break;
|
||||
default:
|
||||
LOG_CRITICAL(Frontend, "Unknown graphics API {}, using OpenGL", graphics_api);
|
||||
window = std::make_unique<EmuWindow_Android>(s_surf);
|
||||
UNREACHABLE_MSG("Unknown graphics API {}", graphics_api);
|
||||
}
|
||||
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
@ -185,9 +187,6 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
||||
system.RegisterMiiSelector(std::make_shared<MiiSelector::AndroidMiiSelector>());
|
||||
system.RegisterSoftwareKeyboard(std::make_shared<SoftwareKeyboard::AndroidKeyboard>());
|
||||
|
||||
// Register generic image interface
|
||||
Core::System::GetInstance().RegisterImageInterface(std::make_shared<LodePNGImageInterface>());
|
||||
|
||||
// Register real Mic factory
|
||||
Frontend::Mic::RegisterRealMicFactory(std::make_unique<Mic::AndroidFactory>());
|
||||
|
||||
@ -271,6 +270,9 @@ void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
|
||||
if (window) {
|
||||
window->OnSurfaceChanged(s_surf);
|
||||
}
|
||||
if (VideoCore::g_renderer) {
|
||||
VideoCore::g_renderer->NotifySurfaceChanged();
|
||||
}
|
||||
|
||||
LOG_INFO(Frontend, "Surface changed");
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
src/android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Normal file
BIN
src/android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Normal file
Binary file not shown.
@ -58,6 +58,8 @@
|
||||
<string name="linear_filtering_description">Aktiviert lineare Filterung, welche die Spieletexturen glättet.</string>
|
||||
<string name="texture_filter_name">Texturfilter</string>
|
||||
<string name="texture_filter_description">Verbessert die Grafik von Spielen durch das Anwendung eines Texturfilters. Die unterstützten Filter sind Anime4K Ultrafast, Bicubic, ScaleForce und xBRZ freescale.</string>
|
||||
<string name="hw_renderer">Aktiviere Hardware Renderer</string>
|
||||
<string name="hw_renderer_description">Benutzt Hardware, um die 3DS-Grafik zu emulieren. Wenn aktiviert, wird die Spieleleistung stark verbessert.</string>
|
||||
<string name="hw_shaders">Aktiviere Hardware Shader</string>
|
||||
<string name="hw_shaders_description">Benutzt Hardware, um die 3DS-Shader zu emulieren. Wenn aktiviert, wird die Spieleleistung stark verbessert.</string>
|
||||
<string name="shaders_accurate_mul">Aktiviere genaue Shader-Multiplikation</string>
|
||||
|
@ -62,6 +62,8 @@
|
||||
<string name="linear_filtering_description">Activa el filtro linear, que hace que los gráficos del juego se vean más suaves.</string>
|
||||
<string name="texture_filter_name">Filtro de Texturas</string>
|
||||
<string name="texture_filter_description">Mejora los gráficos visuales de los juegos al aplicar un filtro a las texturas. Los filtros soportados son Anime4K Ultrafast, Bicubic, ScaleForce, y xBRZ freescale.</string>
|
||||
<string name="hw_renderer">Activar renderizador de hardware</string>
|
||||
<string name="hw_renderer_description">Usa el hardware para emular los gráficos de 3DS. Cuando se active, el rendimiento mejorará notablemente.</string>
|
||||
<string name="hw_shaders">Activar sombreador de hardware</string>
|
||||
<string name="hw_shaders_description">Usa el hardware para emular los sombreadores de 3DS. Cuando se active, el rendimiento mejorará notablemente.</string>
|
||||
<string name="shaders_accurate_mul">Activar multiplicación precisa de sombreado</string>
|
||||
|
@ -46,6 +46,8 @@
|
||||
<!-- Graphics settings strings -->
|
||||
<string name="vsync">Aktivoi V-Sync</string>
|
||||
<string name="vsync_description">Synkronoi pelin virkistystaajuus laitteesi virkistystaajuuteen.</string>
|
||||
<string name="hw_renderer">Aktivoi Laitteistorenderöinti</string>
|
||||
<string name="hw_renderer_description">Käyttää laitteistoa emuloidakseen 3DS-grafiikoita. Kun tämä on päällä, pelien suorituskyky on huomattavasti parempi.</string>
|
||||
<string name="hw_shaders">Aktivoi Laitteistovarjostin</string>
|
||||
<string name="hw_shaders_description">Käyttää laitteistoa emuloidakseen 3DS:n varjostimia. Kun tämä on päällä, pelien suorituskyky on huomattavasti parempi.</string>
|
||||
<string name="frame_limit_enable">Aktivoi nopeuden rajoitus</string>
|
||||
|
@ -58,6 +58,8 @@
|
||||
<string name="linear_filtering_description">Active le filtrage linéaire, qui améliorera le lissage graphique du jeu.</string>
|
||||
<string name="texture_filter_name">Filtrage des textures</string>
|
||||
<string name="texture_filter_description">Améliore l\'aspect graphique des jeux en appliquant un filtre aux textures. Les filtres supportés sont Anime4K Ultrafast, Bicubic, ScaleForce, et xBRZ freescale.</string>
|
||||
<string name="hw_renderer">Activer le rendu matériel</string>
|
||||
<string name="hw_renderer_description">Utilise le matériel pour émuler les graphismes de la 3DS. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative.</string>
|
||||
<string name="hw_shaders">Activer le shader (nuanceur) matériel </string>
|
||||
<string name="hw_shaders_description">Utilise le matériel pour émuler les shaders de la 3DS. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative.</string>
|
||||
<string name="shaders_accurate_mul">Activer la multiplication précise dans les shaders</string>
|
||||
|
@ -58,6 +58,8 @@
|
||||
<string name="linear_filtering_description">Abilita il filtro lineare, che fa sembrare più smussata la grafica dei giochi.</string>
|
||||
<string name="texture_filter_name">Filtro Texture</string>
|
||||
<string name="texture_filter_description">Migliora la grafica dei giochi applicando un filtro alle texture. I filtri supportati sono Anime4k Ultrafast, Bicubic, ScaleForce, e xBRZ freescale.</string>
|
||||
<string name="hw_renderer">Abilita renderer hardware</string>
|
||||
<string name="hw_renderer_description">Utilizza l\'hardware per emulare la grafica del 3DS. Se abilitato, le prestazioni dei giochi miglioreranno significativamente.</string>
|
||||
<string name="hw_shaders">Abilita shader hardware</string>
|
||||
<string name="hw_shaders_description">Utilizza l\'hardware per emulare gli shader del 3DS. Se abilitato, le prestazioni dei giochi miglioreranno significativamente.</string>
|
||||
<string name="shaders_accurate_mul">Abilita moltiplicazione shader accurata</string>
|
||||
|
@ -40,6 +40,8 @@
|
||||
<string name="linear_filtering">リニアフィルタリングを有効化</string>
|
||||
<string name="linear_filtering_description">有効にすると、よりなめらかな画質が期待できます。</string>
|
||||
<string name="texture_filter_name">テクスチャフィルタ</string>
|
||||
<string name="hw_renderer">ハードウェアレンダラを有効にする</string>
|
||||
<string name="hw_renderer_description">グラフィックエミュレーションにハードウェアを使用します。有効にすると、パフォーマンスが大幅に向上します。</string>
|
||||
<string name="hw_shaders">ハードウェアシェーダを有効にする</string>
|
||||
<string name="hw_shaders_description">シェーダエミュレーションにハードウェアを使用します。有効にすると、パフォーマンスが大幅に向上します。</string>
|
||||
<string name="shaders_accurate_mul">正確なシェーダ乗算を有効にする</string>
|
||||
|
@ -58,6 +58,8 @@
|
||||
<string name="linear_filtering_description">게임 필터링이 매끄럽게 보이도록 선형 필터링을 활성화합니다.</string>
|
||||
<string name="texture_filter_name">텍스처 필터</string>
|
||||
<string name="texture_filter_description">텍스처에 필터를 적용하여 게임의 시각적 효과를 향상시킵니다. 지원되는 필터는 Anime4K Ultrafast, Bicubic, ScaleForce 및 xBRZ 프리스케일입니다.</string>
|
||||
<string name="hw_renderer">하드웨어 렌더러 사용</string>
|
||||
<string name="hw_renderer_description">하드웨어를 사용하여 3DS 그래픽을 에뮬레이션합니다. 활성화하면 게임 성능이 크게 향상됩니다.</string>
|
||||
<string name="hw_shaders">하드웨어 쉐이더 사용</string>
|
||||
<string name="hw_shaders_description">하드웨어를 사용하여 3DS 쉐이더를 에뮬레이션합니다. 활성화하면 게임 성능이 크게 향상됩니다.</string>
|
||||
<string name="shaders_accurate_mul">정확한 쉐이더 곱셉 사용</string>
|
||||
|
@ -58,6 +58,8 @@
|
||||
<string name="linear_filtering_description">Aktiverer lineær filtrering, noe som får spillvisualer til å vises jevnere.</string>
|
||||
<string name="texture_filter_name">Tekstur Filter</string>
|
||||
<string name="texture_filter_description">Forbedrer det visuelle i spill ved å bruke et filter på teksturer. De støttede filtrene er Anime4K Ultrafast, Bicubic, ScaleForce og xBRZ freescale.</string>
|
||||
<string name="hw_renderer">Aktiver maskinvaregjengivelse</string>
|
||||
<string name="hw_renderer_description">Bruker maskinvare til å emulere 3DS grafikk. Når dette er aktivert, vil spillytelsen bli betydelig forbedret.</string>
|
||||
<string name="hw_shaders">Aktiver maskinvare shader</string>
|
||||
<string name="hw_shaders_description">Bruker maskinvare for å etterligne 3DS shaders. Når dette er aktivert, vil spillytelsen bli betydelig forbedret.</string>
|
||||
<string name="shaders_accurate_mul">Aktiver nøyaktig shader-multiplikasjon</string>
|
||||
|
@ -58,6 +58,8 @@
|
||||
<string name="linear_filtering_description">Ativa a filtragem linear, que suaviza o visual do jogo.</string>
|
||||
<string name="texture_filter_name">Filtro de texturas</string>
|
||||
<string name="texture_filter_description">Aprimora o visual dos jogos ao aplicar filtros às texturas. Os filtros compatíveis são: Anime4K Ultrafast, Bicúbico, ScaleForce e xBRZ Freescale.</string>
|
||||
<string name="hw_renderer">Ativar renderizador por hardware</string>
|
||||
<string name="hw_renderer_description">Utiliza o hardware para emular os gráficos do 3DS. Quando ativado, o desempenho de jogo será consideravelmente melhorado.</string>
|
||||
<string name="hw_shaders">Ativar shaders via hardware</string>
|
||||
<string name="hw_shaders_description">Utiliza o hardware para emular os shaders do 3DS. Quando ativado, o desempenho do jogo será consideravelmente melhorado.</string>
|
||||
<string name="shaders_accurate_mul">Ativar multiplicação precisa de shaders</string>
|
||||
|
@ -58,6 +58,8 @@
|
||||
<string name="linear_filtering_description">开启后,游戏视觉效果会更加平滑。</string>
|
||||
<string name="texture_filter_name">纹理滤镜</string>
|
||||
<string name="texture_filter_description">通过对纹理使用滤镜来增强游戏的视觉效果。支持的滤镜有 Anime4K Ultrafast, Bicubic, ScaleForce 和 xBRZ freescale。</string>
|
||||
<string name="hw_renderer">启用硬件渲染器</string>
|
||||
<string name="hw_renderer_description">使用硬件模拟 3DS 图形。启用后,游戏性能将显著提高。</string>
|
||||
<string name="hw_shaders">启用硬件着色器</string>
|
||||
<string name="hw_shaders_description">使用硬件模拟 3DS 着色器。启用后,游戏性能将显著提高。</string>
|
||||
<string name="shaders_accurate_mul">启用精确乘法运算</string>
|
||||
|
@ -173,10 +173,12 @@
|
||||
</integer-array>
|
||||
|
||||
<string-array name="graphicsApiNames">
|
||||
<item>OpenGLES</item>
|
||||
<item>OpenGL</item>
|
||||
<item>Vulkan</item>
|
||||
</string-array>
|
||||
|
||||
<integer-array name="graphicsApiValues">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
</resources>
|
||||
|
@ -72,15 +72,21 @@
|
||||
|
||||
<!-- Graphics settings strings -->
|
||||
<string name="renderer">Renderer</string>
|
||||
<string name="vsync">Enable V-Sync</string>
|
||||
<string name="graphics_api">Graphics API</string>
|
||||
<string name="spirv_shader_gen">Enable SPIR-V shader generation</string>
|
||||
<string name="spirv_shader_gen_description">Emits the fragment shader used to emulate PICA using SPIR-V instead of GLSL</string>
|
||||
<string name="async_shaders">Enable asynchronous shader compilation</string>
|
||||
<string name="async_shaders_description">Compiles shaders in the background to reduce stuttering during gameplay. When enabled expect temporary graphical glitches</string>
|
||||
<string name="renderer_debug">Enable debug renderer</string>
|
||||
<string name="renderer_debug_description">Log additional graphics related debug information. When enabled, game performance will be significantly reduced</string>
|
||||
<string name="vsync">Enable V-Sync</string>
|
||||
<string name="vsync_description">Synchronizes the game frame rate to the refresh rate of your device.</string>
|
||||
<string name="linear_filtering">Enable linear filtering</string>
|
||||
<string name="linear_filtering_description">Enables linear filtering, which causes game visuals to appear smoother.</string>
|
||||
<string name="texture_filter_name">Texture Filter</string>
|
||||
<string name="texture_filter_description">Enhances the visuals of games by applying a filter to textures. The supported filters are Anime4K Ultrafast, Bicubic, ScaleForce, and xBRZ freescale.</string>
|
||||
<string name="hw_renderer">Enable hardware renderer</string>
|
||||
<string name="hw_renderer_description">Uses hardware to emulate 3DS graphics. When enabled, game performance will be significantly improved.</string>
|
||||
<string name="hw_shaders">Enable hardware shader</string>
|
||||
<string name="hw_shaders_description">Uses hardware to emulate 3DS shaders. When enabled, game performance will be significantly improved.</string>
|
||||
<string name="shaders_accurate_mul">Enable accurate shader multiplication</string>
|
||||
|
@ -7,7 +7,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
||||
classpath 'com.android.tools.build:gradle:7.4.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
@ -8,12 +8,6 @@ add_executable(citra
|
||||
default_ini.h
|
||||
emu_window/emu_window_sdl2.cpp
|
||||
emu_window/emu_window_sdl2.h
|
||||
emu_window/emu_window_sdl2_gl.cpp
|
||||
emu_window/emu_window_sdl2_gl.h
|
||||
emu_window/emu_window_sdl2_sw.cpp
|
||||
emu_window/emu_window_sdl2_sw.h
|
||||
lodepng_image_interface.cpp
|
||||
lodepng_image_interface.h
|
||||
precompiled_headers.h
|
||||
resource.h
|
||||
)
|
||||
@ -21,7 +15,7 @@ add_executable(citra
|
||||
create_target_directory_groups(citra)
|
||||
|
||||
target_link_libraries(citra PRIVATE common core input_common network)
|
||||
target_link_libraries(citra PRIVATE inih glad lodepng)
|
||||
target_link_libraries(citra PRIVATE inih glad)
|
||||
if (MSVC)
|
||||
target_link_libraries(citra PRIVATE getopt)
|
||||
endif()
|
||||
|
@ -7,34 +7,25 @@
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
// This needs to be included before getopt.h because the latter #defines symbols used by it
|
||||
#include "common/microprofile.h"
|
||||
|
||||
#include "citra/config.h"
|
||||
#include "citra/emu_window/emu_window_sdl2.h"
|
||||
#include "citra/emu_window/emu_window_sdl2_gl.h"
|
||||
#include "citra/emu_window/emu_window_sdl2_sw.h"
|
||||
#include "citra/lodepng_image_interface.h"
|
||||
#include "common/common_paths.h"
|
||||
#include "common/detached_tasks.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/dumping/backend.h"
|
||||
#include "core/file_sys/cia_container.h"
|
||||
#include "core/frontend/applets/default_applets.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/cfg/cfg.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/movie.h"
|
||||
#include "input_common/main.h"
|
||||
#include "network/network.h"
|
||||
@ -359,26 +350,13 @@ int main(int argc, char** argv) {
|
||||
// Register frontend applets
|
||||
Frontend::RegisterDefaultApplets();
|
||||
|
||||
// Register generic image interface
|
||||
Core::System::GetInstance().RegisterImageInterface(std::make_shared<LodePNGImageInterface>());
|
||||
|
||||
EmuWindow_SDL2::InitializeSDL2();
|
||||
|
||||
const auto CreateEmuWindow = [](bool fullscreen,
|
||||
bool is_secondary) -> std::unique_ptr<EmuWindow_SDL2> {
|
||||
switch (Settings::values.graphics_api.GetValue()) {
|
||||
case Settings::GraphicsAPI::OpenGL:
|
||||
return std::make_unique<EmuWindow_SDL2_GL>(fullscreen, is_secondary);
|
||||
case Settings::GraphicsAPI::Software:
|
||||
return std::make_unique<EmuWindow_SDL2_SW>(fullscreen, is_secondary);
|
||||
}
|
||||
};
|
||||
|
||||
const auto emu_window{CreateEmuWindow(fullscreen, false)};
|
||||
const bool use_secondary_window{
|
||||
Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows &&
|
||||
Settings::values.graphics_api.GetValue() != Settings::GraphicsAPI::Software};
|
||||
const auto secondary_window = use_secondary_window ? CreateEmuWindow(false, true) : nullptr;
|
||||
const auto emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen, false)};
|
||||
const bool use_secondary_window{Settings::values.layout_option.GetValue() ==
|
||||
Settings::LayoutOption::SeparateWindows};
|
||||
const auto secondary_window =
|
||||
use_secondary_window ? std::make_unique<EmuWindow_SDL2>(false, true) : nullptr;
|
||||
|
||||
const auto scope = emu_window->Acquire();
|
||||
|
||||
@ -412,6 +390,9 @@ int main(int argc, char** argv) {
|
||||
case Core::System::ResultStatus::ErrorSystemMode:
|
||||
LOG_CRITICAL(Frontend, "Failed to determine system mode!");
|
||||
return -1;
|
||||
case Core::System::ResultStatus::ErrorVideoCore:
|
||||
LOG_CRITICAL(Frontend, "VideoCore not initialized");
|
||||
return -1;
|
||||
case Core::System::ResultStatus::Success:
|
||||
break; // Expected case
|
||||
default:
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <SDL.h>
|
||||
#include <inih/cpp/INIReader.h>
|
||||
@ -72,30 +71,6 @@ static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs>
|
||||
},
|
||||
}};
|
||||
|
||||
template <>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
|
||||
std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
|
||||
if (setting_value.empty()) {
|
||||
setting_value = setting.GetDefault();
|
||||
}
|
||||
setting = std::move(setting_value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
|
||||
setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
|
||||
}
|
||||
|
||||
template <typename Type, bool ranged>
|
||||
void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
|
||||
if constexpr (std::is_floating_point_v<Type>) {
|
||||
setting = sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault());
|
||||
} else {
|
||||
setting = static_cast<Type>(sdl2_config->GetInteger(
|
||||
group, setting.GetLabel(), static_cast<long>(setting.GetDefault())));
|
||||
}
|
||||
}
|
||||
|
||||
void Config::ReadValues() {
|
||||
// Controls
|
||||
// TODO: add multiple input profile support
|
||||
@ -129,71 +104,105 @@ void Config::ReadValues() {
|
||||
InputCommon::CemuhookUDP::DEFAULT_PORT));
|
||||
|
||||
// Core
|
||||
ReadSetting("Core", Settings::values.use_cpu_jit);
|
||||
ReadSetting("Core", Settings::values.cpu_clock_percentage);
|
||||
Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
|
||||
Settings::values.cpu_clock_percentage =
|
||||
sdl2_config->GetInteger("Core", "cpu_clock_percentage", 100);
|
||||
|
||||
// Renderer
|
||||
ReadSetting("Renderer", Settings::values.graphics_api);
|
||||
ReadSetting("Renderer", Settings::values.use_gles);
|
||||
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
||||
Settings::values.graphics_api =
|
||||
static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 0));
|
||||
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
|
||||
Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true);
|
||||
#ifdef __APPLE__
|
||||
// Separable shader is broken on macos with Intel GPU thanks to poor drivers.
|
||||
// We still want to provide this option for test/development purposes, but disable it by
|
||||
// default.
|
||||
ReadSetting("Renderer", Settings::values.separable_shader);
|
||||
Settings::values.separable_shader =
|
||||
sdl2_config->GetBoolean("Renderer", "separable_shader", false);
|
||||
#endif
|
||||
ReadSetting("Renderer", Settings::values.shaders_accurate_mul);
|
||||
ReadSetting("Renderer", Settings::values.use_shader_jit);
|
||||
ReadSetting("Renderer", Settings::values.resolution_factor);
|
||||
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
|
||||
ReadSetting("Renderer", Settings::values.frame_limit);
|
||||
ReadSetting("Renderer", Settings::values.use_vsync_new);
|
||||
ReadSetting("Renderer", Settings::values.texture_filter_name);
|
||||
Settings::values.shaders_accurate_mul =
|
||||
sdl2_config->GetBoolean("Renderer", "shaders_accurate_mul", true);
|
||||
Settings::values.use_shader_jit = sdl2_config->GetBoolean("Renderer", "use_shader_jit", true);
|
||||
Settings::values.resolution_factor =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Renderer", "resolution_factor", 1));
|
||||
Settings::values.use_disk_shader_cache =
|
||||
sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", true);
|
||||
Settings::values.frame_limit =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100));
|
||||
Settings::values.use_vsync_new =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync_new", 1));
|
||||
Settings::values.texture_filter_name =
|
||||
sdl2_config->GetString("Renderer", "texture_filter_name", "none");
|
||||
|
||||
ReadSetting("Renderer", Settings::values.mono_render_option);
|
||||
ReadSetting("Renderer", Settings::values.render_3d);
|
||||
ReadSetting("Renderer", Settings::values.factor_3d);
|
||||
ReadSetting("Renderer", Settings::values.pp_shader_name);
|
||||
ReadSetting("Renderer", Settings::values.anaglyph_shader_name);
|
||||
ReadSetting("Renderer", Settings::values.filter_mode);
|
||||
Settings::values.mono_render_option = static_cast<Settings::MonoRenderOption>(
|
||||
sdl2_config->GetInteger("Renderer", "mono_render_option", 0));
|
||||
Settings::values.render_3d = static_cast<Settings::StereoRenderOption>(
|
||||
sdl2_config->GetInteger("Renderer", "render_3d", 0));
|
||||
Settings::values.factor_3d =
|
||||
static_cast<u8>(sdl2_config->GetInteger("Renderer", "factor_3d", 0));
|
||||
Settings::values.pp_shader_name =
|
||||
sdl2_config->GetString("Renderer", "pp_shader_name", "none (builtin)");
|
||||
Settings::values.anaglyph_shader_name =
|
||||
sdl2_config->GetString("Renderer", "anaglyph_shader_name", "dubois (builtin)");
|
||||
Settings::values.filter_mode = sdl2_config->GetBoolean("Renderer", "filter_mode", true);
|
||||
|
||||
ReadSetting("Renderer", Settings::values.bg_red);
|
||||
ReadSetting("Renderer", Settings::values.bg_green);
|
||||
ReadSetting("Renderer", Settings::values.bg_blue);
|
||||
Settings::values.bg_red = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0));
|
||||
Settings::values.bg_green =
|
||||
static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0));
|
||||
Settings::values.bg_blue = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0));
|
||||
|
||||
// Layout
|
||||
ReadSetting("Layout", Settings::values.layout_option);
|
||||
ReadSetting("Layout", Settings::values.swap_screen);
|
||||
ReadSetting("Layout", Settings::values.upright_screen);
|
||||
ReadSetting("Layout", Settings::values.large_screen_proportion);
|
||||
ReadSetting("Layout", Settings::values.custom_layout);
|
||||
ReadSetting("Layout", Settings::values.custom_top_left);
|
||||
ReadSetting("Layout", Settings::values.custom_top_top);
|
||||
ReadSetting("Layout", Settings::values.custom_top_right);
|
||||
ReadSetting("Layout", Settings::values.custom_top_bottom);
|
||||
ReadSetting("Layout", Settings::values.custom_bottom_left);
|
||||
ReadSetting("Layout", Settings::values.custom_bottom_top);
|
||||
ReadSetting("Layout", Settings::values.custom_bottom_right);
|
||||
ReadSetting("Layout", Settings::values.custom_bottom_bottom);
|
||||
ReadSetting("Layout", Settings::values.custom_second_layer_opacity);
|
||||
Settings::values.layout_option =
|
||||
static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0));
|
||||
Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false);
|
||||
Settings::values.upright_screen = sdl2_config->GetBoolean("Layout", "upright_screen", false);
|
||||
Settings::values.large_screen_proportion =
|
||||
sdl2_config->GetReal("Layout", "large_screen_proportion", 4.0);
|
||||
Settings::values.custom_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false);
|
||||
Settings::values.custom_top_left =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_left", 0));
|
||||
Settings::values.custom_top_top =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_top", 0));
|
||||
Settings::values.custom_top_right =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_right", 400));
|
||||
Settings::values.custom_top_bottom =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_bottom", 240));
|
||||
Settings::values.custom_bottom_left =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_left", 40));
|
||||
Settings::values.custom_bottom_top =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_top", 240));
|
||||
Settings::values.custom_bottom_right =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_right", 360));
|
||||
Settings::values.custom_bottom_bottom =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_bottom", 480));
|
||||
Settings::values.custom_second_layer_opacity =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_second_layer_opacity", 100));
|
||||
|
||||
// Utility
|
||||
ReadSetting("Utility", Settings::values.dump_textures);
|
||||
ReadSetting("Utility", Settings::values.custom_textures);
|
||||
ReadSetting("Utility", Settings::values.preload_textures);
|
||||
Settings::values.dump_textures = sdl2_config->GetBoolean("Utility", "dump_textures", false);
|
||||
Settings::values.custom_textures = sdl2_config->GetBoolean("Utility", "custom_textures", false);
|
||||
Settings::values.preload_textures =
|
||||
sdl2_config->GetBoolean("Utility", "preload_textures", false);
|
||||
|
||||
// Audio
|
||||
ReadSetting("Audio", Settings::values.audio_emulation);
|
||||
ReadSetting("Audio", Settings::values.sink_id);
|
||||
ReadSetting("Audio", Settings::values.enable_audio_stretching);
|
||||
ReadSetting("Audio", Settings::values.audio_device_id);
|
||||
ReadSetting("Audio", Settings::values.volume);
|
||||
ReadSetting("Audio", Settings::values.mic_input_device);
|
||||
ReadSetting("Audio", Settings::values.mic_input_type);
|
||||
Settings::values.audio_emulation = static_cast<Settings::AudioEmulation>(
|
||||
sdl2_config->GetInteger("Audio", "audio_emulation", 0));
|
||||
Settings::values.sink_id = sdl2_config->GetString("Audio", "output_engine", "auto");
|
||||
Settings::values.enable_audio_stretching =
|
||||
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
|
||||
Settings::values.audio_device_id = sdl2_config->GetString("Audio", "output_device", "auto");
|
||||
Settings::values.volume = static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1));
|
||||
Settings::values.mic_input_device =
|
||||
sdl2_config->GetString("Audio", "mic_input_device", Frontend::Mic::default_device_name);
|
||||
Settings::values.mic_input_type =
|
||||
static_cast<Settings::MicInputType>(sdl2_config->GetInteger("Audio", "mic_input_type", 0));
|
||||
|
||||
// Data Storage
|
||||
ReadSetting("Data Storage", Settings::values.use_virtual_sd);
|
||||
ReadSetting("Data Storage", Settings::values.use_custom_storage);
|
||||
Settings::values.use_virtual_sd =
|
||||
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
|
||||
|
||||
Settings::values.use_custom_storage =
|
||||
sdl2_config->GetBoolean("Data Storage", "use_custom_storage", false);
|
||||
|
||||
if (Settings::values.use_custom_storage) {
|
||||
FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir,
|
||||
@ -203,9 +212,11 @@ void Config::ReadValues() {
|
||||
}
|
||||
|
||||
// System
|
||||
ReadSetting("System", Settings::values.is_new_3ds);
|
||||
ReadSetting("System", Settings::values.region_value);
|
||||
ReadSetting("System", Settings::values.init_clock);
|
||||
Settings::values.is_new_3ds = sdl2_config->GetBoolean("System", "is_new_3ds", true);
|
||||
Settings::values.region_value =
|
||||
sdl2_config->GetInteger("System", "region_value", Settings::REGION_VALUE_AUTO_SELECT);
|
||||
Settings::values.init_clock =
|
||||
static_cast<Settings::InitClock>(sdl2_config->GetInteger("System", "init_clock", 1));
|
||||
{
|
||||
std::tm t;
|
||||
t.tm_sec = 1;
|
||||
@ -226,8 +237,6 @@ void Config::ReadValues() {
|
||||
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
ReadSetting("System", Settings::values.plugin_loader_enabled);
|
||||
ReadSetting("System", Settings::values.allow_plugin_loader);
|
||||
|
||||
{
|
||||
constexpr const char* default_init_time_offset = "0 00:00:00";
|
||||
@ -303,14 +312,14 @@ void Config::ReadValues() {
|
||||
sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0);
|
||||
|
||||
// Miscellaneous
|
||||
ReadSetting("Miscellaneous", Settings::values.log_filter);
|
||||
Settings::values.log_filter = sdl2_config->GetString("Miscellaneous", "log_filter", "*:Info");
|
||||
|
||||
// Debugging
|
||||
Settings::values.record_frame_times =
|
||||
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
|
||||
ReadSetting("Debugging", Settings::values.renderer_debug);
|
||||
ReadSetting("Debugging", Settings::values.use_gdbstub);
|
||||
ReadSetting("Debugging", Settings::values.gdbstub_port);
|
||||
Settings::values.use_gdbstub = sdl2_config->GetBoolean("Debugging", "use_gdbstub", false);
|
||||
Settings::values.gdbstub_port =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689));
|
||||
|
||||
for (const auto& service_module : Service::service_module_map) {
|
||||
bool use_lle = sdl2_config->GetBoolean("Debugging", "LLE\\" + service_module.name, false);
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "common/settings.h"
|
||||
|
||||
class INIReader;
|
||||
|
||||
@ -22,14 +21,4 @@ public:
|
||||
~Config();
|
||||
|
||||
void Reload();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Applies a value read from the sdl2_config to a Setting.
|
||||
*
|
||||
* @param group The name of the INI group
|
||||
* @param setting The yuzu setting to modify
|
||||
*/
|
||||
template <typename Type, bool ranged>
|
||||
void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
|
||||
};
|
||||
|
@ -98,14 +98,14 @@ use_cpu_jit =
|
||||
cpu_clock_percentage =
|
||||
|
||||
[Renderer]
|
||||
# Whether to render using OpenGL or Software
|
||||
# 0: Software, 1: OpenGL (default)
|
||||
graphics_api =
|
||||
|
||||
# Whether to render using GLES or OpenGL
|
||||
# 0 (default): OpenGL, 1: GLES
|
||||
use_gles =
|
||||
|
||||
# Whether to use software or hardware rendering.
|
||||
# 0: Software, 1 (default): Hardware
|
||||
use_hw_renderer =
|
||||
|
||||
# Whether to use hardware shaders to emulate 3DS shaders
|
||||
# 0: Software, 1 (default): Hardware
|
||||
use_hw_shader =
|
||||
@ -328,15 +328,9 @@ log_filter = *:Info
|
||||
[Debugging]
|
||||
# Record frame time data, can be found in the log directory. Boolean value
|
||||
record_frame_times =
|
||||
|
||||
# Port for listening to GDB connections.
|
||||
use_gdbstub=false
|
||||
gdbstub_port=24689
|
||||
|
||||
# Whether to enable additional debugging information during emulation
|
||||
# 0 (default): Off, 1: On
|
||||
renderer_debug =
|
||||
|
||||
# To LLE a service module add "LLE\<module name>=true"
|
||||
|
||||
[WebService]
|
||||
|
@ -7,14 +7,40 @@
|
||||
#include <string>
|
||||
#define SDL_MAIN_HANDLED
|
||||
#include <SDL.h>
|
||||
#include <fmt/format.h>
|
||||
#include <glad/glad.h>
|
||||
#include "citra/emu_window/emu_window_sdl2.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/3ds.h"
|
||||
#include "core/core.h"
|
||||
#include "input_common/keyboard.h"
|
||||
#include "input_common/main.h"
|
||||
#include "input_common/motion_emu.h"
|
||||
#include "input_common/sdl/sdl.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
SharedContext_SDL2::SharedContext_SDL2() {
|
||||
window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0,
|
||||
SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
|
||||
context = SDL_GL_CreateContext(window);
|
||||
}
|
||||
|
||||
SharedContext_SDL2::~SharedContext_SDL2() {
|
||||
SDL_GL_DeleteContext(context);
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
|
||||
void SharedContext_SDL2::MakeCurrent() {
|
||||
SDL_GL_MakeCurrent(window, context);
|
||||
}
|
||||
|
||||
void SharedContext_SDL2::DoneCurrent() {
|
||||
SDL_GL_MakeCurrent(window, nullptr);
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
|
||||
TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
|
||||
@ -109,9 +135,80 @@ void EmuWindow_SDL2::Fullscreen() {
|
||||
SDL_MaximizeWindow(render_window);
|
||||
}
|
||||
|
||||
EmuWindow_SDL2::EmuWindow_SDL2(bool is_secondary) : EmuWindow(is_secondary) {}
|
||||
EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen, bool is_secondary) : EmuWindow(is_secondary) {
|
||||
// Initialize the window
|
||||
const bool is_opengles =
|
||||
Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::OpenGLES;
|
||||
if (is_opengles) {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
} else {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
}
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
|
||||
// Enable context sharing for the shared context
|
||||
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
|
||||
// Enable vsync
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
std::string window_title = fmt::format("Citra {} | {}-{}", Common::g_build_fullname,
|
||||
Common::g_scm_branch, Common::g_scm_desc);
|
||||
render_window =
|
||||
SDL_CreateWindow(window_title.c_str(),
|
||||
SDL_WINDOWPOS_UNDEFINED, // x position
|
||||
SDL_WINDOWPOS_UNDEFINED, // y position
|
||||
Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
|
||||
if (render_window == nullptr) {
|
||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 window: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dummy_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0,
|
||||
SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
|
||||
|
||||
if (fullscreen) {
|
||||
Fullscreen();
|
||||
}
|
||||
|
||||
window_context = SDL_GL_CreateContext(render_window);
|
||||
core_context = CreateSharedContext();
|
||||
last_saved_context = nullptr;
|
||||
|
||||
if (window_context == nullptr) {
|
||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
if (core_context == nullptr) {
|
||||
LOG_CRITICAL(Frontend, "Failed to create shared SDL2 GL context: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
render_window_id = SDL_GetWindowID(render_window);
|
||||
auto gl_load_func = is_opengles ? gladLoadGLES2Loader : gladLoadGLLoader;
|
||||
|
||||
if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
||||
LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
OnResize();
|
||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||
SDL_PumpEvents();
|
||||
}
|
||||
|
||||
EmuWindow_SDL2::~EmuWindow_SDL2() {
|
||||
core_context.reset();
|
||||
SDL_GL_DeleteContext(window_context);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
@ -127,6 +224,28 @@ void EmuWindow_SDL2::InitializeSDL2() {
|
||||
SDL_SetMainReady();
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_SDL2::CreateSharedContext() const {
|
||||
return std::make_unique<SharedContext_SDL2>();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::SaveContext() {
|
||||
last_saved_context = SDL_GL_GetCurrentContext();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::RestoreContext() {
|
||||
SDL_GL_MakeCurrent(render_window, last_saved_context);
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::Present() {
|
||||
SDL_GL_MakeCurrent(render_window, window_context);
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
while (IsOpen()) {
|
||||
VideoCore::g_renderer->TryPresent(100, is_secondary);
|
||||
SDL_GL_SwapWindow(render_window);
|
||||
}
|
||||
SDL_GL_MakeCurrent(render_window, nullptr);
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::PollEvents() {
|
||||
SDL_Event event;
|
||||
std::vector<SDL_Event> other_window_events;
|
||||
@ -195,6 +314,14 @@ void EmuWindow_SDL2::PollEvents() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::MakeCurrent() {
|
||||
core_context->MakeCurrent();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::DoneCurrent() {
|
||||
core_context->DoneCurrent();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
||||
SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second);
|
||||
}
|
||||
|
@ -10,27 +10,56 @@
|
||||
|
||||
struct SDL_Window;
|
||||
|
||||
class SharedContext_SDL2 : public Frontend::GraphicsContext {
|
||||
public:
|
||||
using SDL_GLContext = void*;
|
||||
|
||||
SharedContext_SDL2();
|
||||
|
||||
~SharedContext_SDL2() override;
|
||||
|
||||
void MakeCurrent() override;
|
||||
|
||||
void DoneCurrent() override;
|
||||
|
||||
private:
|
||||
SDL_GLContext context;
|
||||
SDL_Window* window;
|
||||
};
|
||||
|
||||
class EmuWindow_SDL2 : public Frontend::EmuWindow {
|
||||
public:
|
||||
explicit EmuWindow_SDL2(bool is_secondary);
|
||||
explicit EmuWindow_SDL2(bool fullscreen, bool is_secondary);
|
||||
~EmuWindow_SDL2();
|
||||
|
||||
/// Initializes SDL2
|
||||
static void InitializeSDL2();
|
||||
|
||||
/// Presents the most recent frame from the video backend
|
||||
virtual void Present() {}
|
||||
void Present();
|
||||
|
||||
/// Polls window events
|
||||
void PollEvents() override;
|
||||
|
||||
/// Makes the graphics context current for the caller thread
|
||||
void MakeCurrent() override;
|
||||
|
||||
/// Releases the GL context from the caller thread
|
||||
void DoneCurrent() override;
|
||||
|
||||
/// Whether the window is still open, and a close request hasn't yet been sent
|
||||
bool IsOpen() const;
|
||||
|
||||
/// Close the window.
|
||||
void RequestClose();
|
||||
|
||||
protected:
|
||||
/// Creates a new context that is shared with the current context
|
||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||
|
||||
/// Saves the current context, for the purpose of e.g. creating new shared contexts
|
||||
void SaveContext() override;
|
||||
/// Restores the context previously saved
|
||||
void RestoreContext() override;
|
||||
|
||||
private:
|
||||
/// Called by PollEvents when a key is pressed or released.
|
||||
void OnKeyEvent(int key, u8 state);
|
||||
|
||||
@ -76,6 +105,17 @@ protected:
|
||||
/// Fake hidden window for the core context
|
||||
SDL_Window* dummy_window;
|
||||
|
||||
using SDL_GLContext = void*;
|
||||
|
||||
/// The OpenGL context associated with the window
|
||||
SDL_GLContext window_context;
|
||||
|
||||
/// Used by SaveContext and RestoreContext
|
||||
SDL_GLContext last_saved_context;
|
||||
|
||||
/// The OpenGL context associated with the core
|
||||
std::unique_ptr<Frontend::GraphicsContext> core_context;
|
||||
|
||||
/// Keeps track of how often to update the title bar during gameplay
|
||||
u32 last_time = 0;
|
||||
};
|
||||
|
@ -1,152 +0,0 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#define SDL_MAIN_HANDLED
|
||||
#include <SDL.h>
|
||||
#include <glad/glad.h>
|
||||
#include "citra/emu_window/emu_window_sdl2_gl.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
class SDLGLContext : public Frontend::GraphicsContext {
|
||||
public:
|
||||
using SDL_GLContext = void*;
|
||||
|
||||
SDLGLContext() {
|
||||
window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0,
|
||||
SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
|
||||
context = SDL_GL_CreateContext(window);
|
||||
}
|
||||
|
||||
~SDLGLContext() override {
|
||||
SDL_GL_DeleteContext(context);
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
|
||||
void MakeCurrent() override {
|
||||
SDL_GL_MakeCurrent(window, context);
|
||||
}
|
||||
|
||||
void DoneCurrent() override {
|
||||
SDL_GL_MakeCurrent(window, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
SDL_Window* window;
|
||||
SDL_GLContext context;
|
||||
};
|
||||
|
||||
EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(bool fullscreen, bool is_secondary)
|
||||
: EmuWindow_SDL2{is_secondary} {
|
||||
// Initialize the window
|
||||
if (Settings::values.use_gles) {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
} else {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
}
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
|
||||
// Enable context sharing for the shared context
|
||||
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
|
||||
// Enable vsync
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
// Enable debug context
|
||||
if (Settings::values.renderer_debug) {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
|
||||
}
|
||||
|
||||
std::string window_title = fmt::format("Citra {} | {}-{}", Common::g_build_fullname,
|
||||
Common::g_scm_branch, Common::g_scm_desc);
|
||||
render_window =
|
||||
SDL_CreateWindow(window_title.c_str(),
|
||||
SDL_WINDOWPOS_UNDEFINED, // x position
|
||||
SDL_WINDOWPOS_UNDEFINED, // y position
|
||||
Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
|
||||
if (render_window == nullptr) {
|
||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 window: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dummy_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0,
|
||||
SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
|
||||
|
||||
if (fullscreen) {
|
||||
Fullscreen();
|
||||
}
|
||||
|
||||
window_context = SDL_GL_CreateContext(render_window);
|
||||
core_context = CreateSharedContext();
|
||||
last_saved_context = nullptr;
|
||||
|
||||
if (window_context == nullptr) {
|
||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
if (core_context == nullptr) {
|
||||
LOG_CRITICAL(Frontend, "Failed to create shared SDL2 GL context: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
render_window_id = SDL_GetWindowID(render_window);
|
||||
auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader;
|
||||
|
||||
if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
||||
LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
OnResize();
|
||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||
SDL_PumpEvents();
|
||||
}
|
||||
|
||||
EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() {
|
||||
core_context.reset();
|
||||
SDL_DestroyWindow(render_window);
|
||||
SDL_GL_DeleteContext(window_context);
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const {
|
||||
return std::make_unique<SDLGLContext>();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2_GL::MakeCurrent() {
|
||||
core_context->MakeCurrent();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2_GL::DoneCurrent() {
|
||||
core_context->DoneCurrent();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2_GL::SaveContext() {
|
||||
last_saved_context = SDL_GL_GetCurrentContext();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2_GL::RestoreContext() {
|
||||
SDL_GL_MakeCurrent(render_window, last_saved_context);
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2_GL::Present() {
|
||||
SDL_GL_MakeCurrent(render_window, window_context);
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
while (IsOpen()) {
|
||||
VideoCore::g_renderer->TryPresent(100, is_secondary);
|
||||
SDL_GL_SwapWindow(render_window);
|
||||
}
|
||||
SDL_GL_MakeCurrent(render_window, nullptr);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "citra/emu_window/emu_window_sdl2.h"
|
||||
|
||||
struct SDL_Window;
|
||||
|
||||
class EmuWindow_SDL2_GL : public EmuWindow_SDL2 {
|
||||
public:
|
||||
explicit EmuWindow_SDL2_GL(bool fullscreen, bool is_secondary);
|
||||
~EmuWindow_SDL2_GL();
|
||||
|
||||
void Present() override;
|
||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||
void MakeCurrent() override;
|
||||
void DoneCurrent() override;
|
||||
void SaveContext() override;
|
||||
void RestoreContext() override;
|
||||
|
||||
private:
|
||||
using SDL_GLContext = void*;
|
||||
|
||||
/// The OpenGL context associated with the window
|
||||
SDL_GLContext window_context;
|
||||
|
||||
/// Used by SaveContext and RestoreContext
|
||||
SDL_GLContext last_saved_context;
|
||||
|
||||
/// The OpenGL context associated with the core
|
||||
std::unique_ptr<Frontend::GraphicsContext> core_context;
|
||||
};
|
@ -1,127 +0,0 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#define SDL_MAIN_HANDLED
|
||||
#include <SDL.h>
|
||||
#include <SDL_rect.h>
|
||||
#include "citra/emu_window/emu_window_sdl2_sw.h"
|
||||
#include "common/color.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hw/gpu.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
class DummyContext : public Frontend::GraphicsContext {};
|
||||
|
||||
EmuWindow_SDL2_SW::EmuWindow_SDL2_SW(bool fullscreen, bool is_secondary)
|
||||
: EmuWindow_SDL2{is_secondary} {
|
||||
std::string window_title = fmt::format("Citra {} | {}-{}", Common::g_build_fullname,
|
||||
Common::g_scm_branch, Common::g_scm_desc);
|
||||
render_window =
|
||||
SDL_CreateWindow(window_title.c_str(),
|
||||
SDL_WINDOWPOS_UNDEFINED, // x position
|
||||
SDL_WINDOWPOS_UNDEFINED, // y position
|
||||
Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight,
|
||||
SDL_WINDOW_SHOWN);
|
||||
|
||||
if (render_window == nullptr) {
|
||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 window: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
window_surface = SDL_GetWindowSurface(render_window);
|
||||
renderer = SDL_CreateSoftwareRenderer(window_surface);
|
||||
|
||||
if (fullscreen) {
|
||||
Fullscreen();
|
||||
}
|
||||
|
||||
render_window_id = SDL_GetWindowID(render_window);
|
||||
|
||||
OnResize();
|
||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||
SDL_PumpEvents();
|
||||
}
|
||||
|
||||
EmuWindow_SDL2_SW::~EmuWindow_SDL2_SW() {
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(render_window);
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_SDL2_SW::CreateSharedContext() const {
|
||||
return std::make_unique<DummyContext>();
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2_SW::Present() {
|
||||
const auto layout{Layout::DefaultFrameLayout(
|
||||
Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight, false, false)};
|
||||
|
||||
while (IsOpen()) {
|
||||
SDL_SetRenderDrawColor(renderer, Settings::values.bg_red.GetValue() * 255,
|
||||
Settings::values.bg_green.GetValue() * 255,
|
||||
Settings::values.bg_blue.GetValue() * 255, 0xFF);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
const auto draw_screen = [&](int fb_id) {
|
||||
const auto dst_rect = fb_id == 0 ? layout.top_screen : layout.bottom_screen;
|
||||
SDL_Rect sdl_rect{static_cast<int>(dst_rect.left), static_cast<int>(dst_rect.top),
|
||||
static_cast<int>(dst_rect.GetWidth()),
|
||||
static_cast<int>(dst_rect.GetHeight())};
|
||||
SDL_Surface* screen = LoadFramebuffer(fb_id);
|
||||
SDL_BlitSurface(screen, nullptr, window_surface, &sdl_rect);
|
||||
SDL_FreeSurface(screen);
|
||||
};
|
||||
|
||||
draw_screen(0);
|
||||
draw_screen(1);
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
SDL_UpdateWindowSurface(render_window);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Surface* EmuWindow_SDL2_SW::LoadFramebuffer(int fb_id) {
|
||||
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
|
||||
const PAddr framebuffer_addr =
|
||||
framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2;
|
||||
|
||||
Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
|
||||
const u8* framebuffer_data = VideoCore::g_memory->GetPhysicalPointer(framebuffer_addr);
|
||||
|
||||
const int width = framebuffer.height;
|
||||
const int height = framebuffer.width;
|
||||
const int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
|
||||
|
||||
SDL_Surface* surface =
|
||||
SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, SDL_PIXELFORMAT_ABGR8888);
|
||||
SDL_LockSurface(surface);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
const u8* pixel = framebuffer_data + (x * height + height - y) * bpp;
|
||||
const Common::Vec4 color = [&] {
|
||||
switch (framebuffer.color_format) {
|
||||
case GPU::Regs::PixelFormat::RGBA8:
|
||||
return Common::Color::DecodeRGBA8(pixel);
|
||||
case GPU::Regs::PixelFormat::RGB8:
|
||||
return Common::Color::DecodeRGB8(pixel);
|
||||
case GPU::Regs::PixelFormat::RGB565:
|
||||
return Common::Color::DecodeRGB565(pixel);
|
||||
case GPU::Regs::PixelFormat::RGB5A1:
|
||||
return Common::Color::DecodeRGB5A1(pixel);
|
||||
case GPU::Regs::PixelFormat::RGBA4:
|
||||
return Common::Color::DecodeRGBA4(pixel);
|
||||
}
|
||||
}();
|
||||
|
||||
u8* dst_pixel = reinterpret_cast<u8*>(surface->pixels) + (y * width + x) * 4;
|
||||
std::memcpy(dst_pixel, color.AsArray(), sizeof(color));
|
||||
}
|
||||
}
|
||||
SDL_UnlockSurface(surface);
|
||||
return surface;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "citra/emu_window/emu_window_sdl2.h"
|
||||
|
||||
struct SDL_Renderer;
|
||||
struct SDL_Surface;
|
||||
|
||||
class EmuWindow_SDL2_SW : public EmuWindow_SDL2 {
|
||||
public:
|
||||
explicit EmuWindow_SDL2_SW(bool fullscreen, bool is_secondary);
|
||||
~EmuWindow_SDL2_SW();
|
||||
|
||||
void Present() override;
|
||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||
void MakeCurrent() override {}
|
||||
void DoneCurrent() override {}
|
||||
|
||||
private:
|
||||
/// Loads a framebuffer to an SDL surface
|
||||
SDL_Surface* LoadFramebuffer(int fb_id);
|
||||
|
||||
/// The SDL software renderer
|
||||
SDL_Renderer* renderer;
|
||||
|
||||
/// The window surface
|
||||
SDL_Surface* window_surface;
|
||||
};
|
@ -1,29 +0,0 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <lodepng.h>
|
||||
#include "citra/lodepng_image_interface.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
bool LodePNGImageInterface::DecodePNG(std::vector<u8>& dst, u32& width, u32& height,
|
||||
const std::string& path) {
|
||||
u32 lodepng_ret = lodepng::decode(dst, width, height, path);
|
||||
if (lodepng_ret) {
|
||||
LOG_CRITICAL(Frontend, "Failed to decode {} because {}", path,
|
||||
lodepng_error_text(lodepng_ret));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LodePNGImageInterface::EncodePNG(const std::string& path, const std::vector<u8>& src,
|
||||
u32 width, u32 height) {
|
||||
u32 lodepng_ret = lodepng::encode(path, src, width, height);
|
||||
if (lodepng_ret) {
|
||||
LOG_CRITICAL(Frontend, "Failed to encode {} because {}", path,
|
||||
lodepng_error_text(lodepng_ret));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/frontend/image_interface.h"
|
||||
|
||||
class LodePNGImageInterface final : public Frontend::ImageInterface {
|
||||
public:
|
||||
bool DecodePNG(std::vector<u8>& dst, u32& width, u32& height, const std::string& path) override;
|
||||
bool EncodePNG(const std::string& path, const std::vector<u8>& src, u32 width,
|
||||
u32 height) override;
|
||||
};
|
@ -167,8 +167,6 @@ add_executable(citra-qt
|
||||
precompiled_headers.h
|
||||
uisettings.cpp
|
||||
uisettings.h
|
||||
qt_image_interface.cpp
|
||||
qt_image_interface.h
|
||||
updater/updater.cpp
|
||||
updater/updater.h
|
||||
updater/updater_p.h
|
||||
@ -266,7 +264,7 @@ endif()
|
||||
create_target_directory_groups(citra-qt)
|
||||
|
||||
target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
|
||||
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia Qt5::Concurrent)
|
||||
target_link_libraries(citra-qt PRIVATE Boost::boost glad vma vulkan-headers nihstro-headers Qt5::Widgets Qt5::Multimedia Qt5::Concurrent)
|
||||
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||
|
||||
if (NOT WIN32)
|
||||
@ -329,10 +327,6 @@ if (MSVC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT APPLE)
|
||||
target_compile_definitions(citra-qt PRIVATE HAS_OPENGL)
|
||||
endif()
|
||||
|
||||
if (CITRA_USE_PRECOMPILED_HEADERS)
|
||||
target_precompile_headers(citra-qt PRIVATE precompiled_headers.h)
|
||||
endif()
|
||||
|
@ -2,36 +2,28 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <fmt/format.h>
|
||||
#include "citra_qt/bootmanager.h"
|
||||
#include "citra_qt/main.h"
|
||||
#include "common/color.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/3ds.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
#include "core/perf_stats.h"
|
||||
#include "input_common/keyboard.h"
|
||||
#include "input_common/main.h"
|
||||
#include "input_common/motion_emu.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
#ifdef HAS_OPENGL
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <objc/message.h>
|
||||
#include <objc/objc.h>
|
||||
@ -128,14 +120,13 @@ void EmuThread::run() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAS_OPENGL
|
||||
class OpenGLSharedContext : public Frontend::GraphicsContext {
|
||||
public:
|
||||
/// Create the original context that should be shared from
|
||||
explicit OpenGLSharedContext() {
|
||||
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
|
||||
QSurfaceFormat format;
|
||||
|
||||
format.setVersion(4, 3);
|
||||
format.setVersion(4, 4);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
|
||||
if (Settings::values.renderer_debug) {
|
||||
@ -151,15 +142,10 @@ public:
|
||||
if (!context->create()) {
|
||||
LOG_ERROR(Frontend, "Unable to create main openGL context");
|
||||
}
|
||||
|
||||
offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
|
||||
offscreen_surface->setFormat(format);
|
||||
offscreen_surface->create();
|
||||
surface = offscreen_surface.get();
|
||||
}
|
||||
|
||||
/// Create the shared contexts for rendering and presentation
|
||||
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface) {
|
||||
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface = nullptr) {
|
||||
|
||||
// disable vsync for any shared contexts
|
||||
auto format = share_context->format();
|
||||
@ -172,7 +158,14 @@ public:
|
||||
LOG_ERROR(Frontend, "Unable to create shared openGL context");
|
||||
}
|
||||
|
||||
surface = main_surface;
|
||||
if (!main_surface) {
|
||||
offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
|
||||
offscreen_surface->setFormat(format);
|
||||
offscreen_surface->create();
|
||||
surface = offscreen_surface.get();
|
||||
} else {
|
||||
surface = main_surface;
|
||||
}
|
||||
}
|
||||
|
||||
~OpenGLSharedContext() {
|
||||
@ -210,14 +203,14 @@ private:
|
||||
std::unique_ptr<QOffscreenSurface> offscreen_surface{};
|
||||
QSurface* surface;
|
||||
};
|
||||
#endif
|
||||
|
||||
class DummyContext : public Frontend::GraphicsContext {};
|
||||
|
||||
class RenderWidget : public QWidget {
|
||||
public:
|
||||
RenderWidget(GRenderWindow* parent) : QWidget(parent) {
|
||||
setMouseTracking(true);
|
||||
RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
setAttribute(Qt::WA_PaintOnScreen);
|
||||
}
|
||||
|
||||
virtual ~RenderWidget() = default;
|
||||
@ -229,22 +222,72 @@ public:
|
||||
update();
|
||||
}
|
||||
|
||||
void resizeEvent(QResizeEvent* ev) override {
|
||||
render_window->resize(ev->size());
|
||||
render_window->OnFramebufferSizeChanged();
|
||||
}
|
||||
|
||||
void keyPressEvent(QKeyEvent* event) override {
|
||||
InputCommon::GetKeyboard()->PressKey(event->key());
|
||||
}
|
||||
|
||||
void keyReleaseEvent(QKeyEvent* event) override {
|
||||
InputCommon::GetKeyboard()->ReleaseKey(event->key());
|
||||
}
|
||||
|
||||
void mousePressEvent(QMouseEvent* event) override {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchBeginEvent
|
||||
|
||||
const auto pos{event->pos()};
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
const auto [x, y] = render_window->ScaleTouch(pos);
|
||||
render_window->TouchPressed(x, y);
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
|
||||
}
|
||||
}
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event) override {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchUpdateEvent
|
||||
|
||||
const auto pos{event->pos()};
|
||||
const auto [x, y] = render_window->ScaleTouch(pos);
|
||||
render_window->TouchMoved(x, y);
|
||||
InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
void mouseReleaseEvent(QMouseEvent* event) override {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchEndEvent
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
render_window->TouchReleased();
|
||||
else if (event->button() == Qt::RightButton)
|
||||
InputCommon::GetMotionEmu()->EndTilt();
|
||||
}
|
||||
|
||||
std::pair<unsigned, unsigned> GetSize() const {
|
||||
return std::make_pair(width(), height());
|
||||
}
|
||||
|
||||
QPaintEngine* paintEngine() const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
GRenderWindow* render_window;
|
||||
};
|
||||
|
||||
#ifdef HAS_OPENGL
|
||||
class OpenGLRenderWidget : public RenderWidget {
|
||||
public:
|
||||
explicit OpenGLRenderWidget(GRenderWindow* parent, bool is_secondary)
|
||||
: RenderWidget(parent), is_secondary(is_secondary) {
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
setAttribute(Qt::WA_PaintOnScreen);
|
||||
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
|
||||
}
|
||||
|
||||
void SetContext(std::unique_ptr<Frontend::GraphicsContext>&& context_) {
|
||||
void SetContext(std::unique_ptr<OpenGLSharedContext>&& context_) {
|
||||
context = std::move(context_);
|
||||
}
|
||||
|
||||
@ -256,92 +299,28 @@ public:
|
||||
return;
|
||||
}
|
||||
context->MakeCurrent();
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
const auto f = context->GetShareContext()->extraFunctions();
|
||||
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
VideoCore::g_renderer->TryPresent(100, is_secondary);
|
||||
context->SwapBuffers();
|
||||
glFinish();
|
||||
}
|
||||
|
||||
QPaintEngine* paintEngine() const override {
|
||||
return nullptr;
|
||||
f->glFinish();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Frontend::GraphicsContext> context{};
|
||||
std::unique_ptr<OpenGLSharedContext> context{};
|
||||
bool is_secondary;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct SoftwareRenderWidget : public RenderWidget {
|
||||
explicit SoftwareRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {}
|
||||
|
||||
void Present() override {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
if (!Core::System::GetInstance().IsPoweredOn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto layout{Layout::DefaultFrameLayout(width(), height(), false, false)};
|
||||
QPainter painter(this);
|
||||
|
||||
const auto draw_screen = [&](int fb_id) {
|
||||
const auto rect = fb_id == 0 ? layout.top_screen : layout.bottom_screen;
|
||||
const QImage screen = LoadFramebuffer(fb_id);
|
||||
painter.drawImage(rect.left, rect.top, screen);
|
||||
};
|
||||
|
||||
painter.fillRect(rect(), qRgb(Settings::values.bg_red.GetValue() * 255,
|
||||
Settings::values.bg_green.GetValue() * 255,
|
||||
Settings::values.bg_blue.GetValue() * 255));
|
||||
draw_screen(0);
|
||||
draw_screen(1);
|
||||
|
||||
painter.end();
|
||||
}
|
||||
|
||||
QImage LoadFramebuffer(int fb_id) {
|
||||
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
|
||||
const PAddr framebuffer_addr =
|
||||
framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2;
|
||||
|
||||
Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
|
||||
const u8* framebuffer_data = VideoCore::g_memory->GetPhysicalPointer(framebuffer_addr);
|
||||
|
||||
const int width = framebuffer.height;
|
||||
const int height = framebuffer.width;
|
||||
const int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
|
||||
|
||||
QImage image{width, height, QImage::Format_RGBA8888};
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
const u8* pixel = framebuffer_data + (x * height + height - y) * bpp;
|
||||
const Common::Vec4 color = [&] {
|
||||
switch (framebuffer.color_format) {
|
||||
case GPU::Regs::PixelFormat::RGBA8:
|
||||
return Common::Color::DecodeRGBA8(pixel);
|
||||
case GPU::Regs::PixelFormat::RGB8:
|
||||
return Common::Color::DecodeRGB8(pixel);
|
||||
case GPU::Regs::PixelFormat::RGB565:
|
||||
return Common::Color::DecodeRGB565(pixel);
|
||||
case GPU::Regs::PixelFormat::RGB5A1:
|
||||
return Common::Color::DecodeRGB5A1(pixel);
|
||||
case GPU::Regs::PixelFormat::RGBA4:
|
||||
return Common::Color::DecodeRGBA4(pixel);
|
||||
}
|
||||
}();
|
||||
|
||||
image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
|
||||
}
|
||||
}
|
||||
return image;
|
||||
class VulkanRenderWidget : public RenderWidget {
|
||||
public:
|
||||
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
|
||||
}
|
||||
};
|
||||
|
||||
static Frontend::WindowSystemType GetWindowSystemType() {
|
||||
// Determine WSI type based on Qt platform.
|
||||
const QString platform_name = QGuiApplication::platformName();
|
||||
QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("windows"))
|
||||
return Frontend::WindowSystemType::Windows;
|
||||
else if (platform_name == QStringLiteral("xcb"))
|
||||
@ -383,8 +362,6 @@ static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window
|
||||
return wsi;
|
||||
}
|
||||
|
||||
std::shared_ptr<Frontend::GraphicsContext> GRenderWindow::main_context;
|
||||
|
||||
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread, bool is_secondary_)
|
||||
: QWidget(parent_), EmuWindow(is_secondary_), emu_thread(emu_thread) {
|
||||
|
||||
@ -483,9 +460,8 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
|
||||
}
|
||||
|
||||
void GRenderWindow::mousePressEvent(QMouseEvent* event) {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchBeginEvent
|
||||
}
|
||||
|
||||
auto pos = event->pos();
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
@ -498,9 +474,8 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
|
||||
}
|
||||
|
||||
void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchUpdateEvent
|
||||
}
|
||||
|
||||
auto pos = event->pos();
|
||||
const auto [x, y] = ScaleTouch(pos);
|
||||
@ -510,9 +485,8 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
|
||||
}
|
||||
|
||||
void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchEndEvent
|
||||
}
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
this->TouchReleased();
|
||||
@ -584,7 +558,23 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
|
||||
OnFramebufferSizeChanged();
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
||||
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
|
||||
if (graphics_api == Settings::GraphicsAPI::OpenGL ||
|
||||
graphics_api == Settings::GraphicsAPI::OpenGLES) {
|
||||
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
|
||||
// Bind the shared contexts to the main surface in case the backend wants to take over
|
||||
// presentation
|
||||
return std::make_unique<OpenGLSharedContext>(c->GetShareContext(),
|
||||
child_widget->windowHandle());
|
||||
}
|
||||
|
||||
return std::make_unique<DummyContext>();
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitRenderTarget() {
|
||||
ReleaseRenderTarget();
|
||||
|
||||
{
|
||||
// Create a dummy render widget so that Qt
|
||||
// places the render window at the correct position.
|
||||
@ -593,13 +583,16 @@ bool GRenderWindow::InitRenderTarget() {
|
||||
|
||||
first_frame = false;
|
||||
|
||||
const auto graphics_api = Settings::values.graphics_api.GetValue();
|
||||
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
|
||||
switch (graphics_api) {
|
||||
case Settings::GraphicsAPI::Software:
|
||||
InitializeSoftware();
|
||||
break;
|
||||
case Settings::GraphicsAPI::OpenGL:
|
||||
if (!InitializeOpenGL() || !LoadOpenGL()) {
|
||||
case Settings::GraphicsAPI::OpenGLES:
|
||||
if (!InitializeOpenGL()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Settings::GraphicsAPI::Vulkan:
|
||||
if (!InitializeVulkan()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@ -656,54 +649,24 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitializeOpenGL() {
|
||||
#ifdef HAS_OPENGL
|
||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
||||
auto child = new OpenGLRenderWidget(this, is_secondary);
|
||||
child_widget = child;
|
||||
child_widget->windowHandle()->create();
|
||||
|
||||
if (!main_context) {
|
||||
main_context = std::make_shared<OpenGLSharedContext>();
|
||||
}
|
||||
|
||||
auto child_context = CreateSharedContext();
|
||||
child->SetContext(std::move(child_context));
|
||||
auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle());
|
||||
main_context = context;
|
||||
child->SetContext(
|
||||
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
|
||||
|
||||
return true;
|
||||
#else
|
||||
QMessageBox::warning(this, tr("OpenGL not available!"),
|
||||
tr("Citra has not been compiled with OpenGL support."));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GRenderWindow::InitializeSoftware() {
|
||||
child_widget = new SoftwareRenderWidget(this);
|
||||
bool GRenderWindow::InitializeVulkan() {
|
||||
auto child = new VulkanRenderWidget(this);
|
||||
child_widget = child;
|
||||
child_widget->windowHandle()->create();
|
||||
main_context = std::make_unique<DummyContext>();
|
||||
}
|
||||
|
||||
bool GRenderWindow::LoadOpenGL() {
|
||||
auto context = CreateSharedContext();
|
||||
auto scope = context->Acquire();
|
||||
if (!gladLoadGL()) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Error while initializing OpenGL!"),
|
||||
tr("Your GPU may not support OpenGL, or you do not have the latest graphics driver."));
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString renderer =
|
||||
QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
|
||||
|
||||
if (!GLAD_GL_VERSION_4_3) {
|
||||
LOG_ERROR(Frontend, "GPU does not support OpenGL 4.3: {}", renderer.toStdString());
|
||||
QMessageBox::warning(this, tr("Error while initializing OpenGL 4.3!"),
|
||||
tr("Your GPU may not support OpenGL 4.3, or you do not have the "
|
||||
"latest graphics driver.<br><br>GL Renderer:<br>%1")
|
||||
.arg(renderer));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -719,17 +682,3 @@ void GRenderWindow::OnEmulationStopping() {
|
||||
void GRenderWindow::showEvent(QShowEvent* event) {
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
||||
#ifdef HAS_OPENGL
|
||||
const auto graphics_api = Settings::values.graphics_api.GetValue();
|
||||
if (graphics_api == Settings::GraphicsAPI::OpenGL) {
|
||||
auto gl_context = static_cast<OpenGLSharedContext*>(main_context.get());
|
||||
// Bind the shared contexts to the main surface in case the backend wants to take over
|
||||
// presentation
|
||||
return std::make_unique<OpenGLSharedContext>(gl_context->GetShareContext(),
|
||||
child_widget->windowHandle());
|
||||
}
|
||||
#endif
|
||||
return std::make_unique<DummyContext>();
|
||||
}
|
||||
|
@ -187,21 +187,22 @@ private:
|
||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||
|
||||
bool InitializeOpenGL();
|
||||
void InitializeSoftware();
|
||||
bool LoadOpenGL();
|
||||
|
||||
QWidget* child_widget = nullptr;
|
||||
bool InitializeVulkan();
|
||||
|
||||
EmuThread* emu_thread;
|
||||
|
||||
/// Main context that will be shared with all other contexts that are requested.
|
||||
/// If this is used in a shared context setting, then this should not be used directly, but
|
||||
/// should instead be shared from
|
||||
static std::shared_ptr<Frontend::GraphicsContext> main_context;
|
||||
// Main context that will be shared with all other contexts that are requested.
|
||||
// If this is used in a shared context setting, then this should not be used directly, but
|
||||
// should instead be shared from
|
||||
std::shared_ptr<Frontend::GraphicsContext> main_context;
|
||||
|
||||
/// Temporary storage of the screenshot taken
|
||||
QImage screenshot_image;
|
||||
|
||||
QByteArray geometry;
|
||||
|
||||
QWidget* child_widget = nullptr;
|
||||
|
||||
bool first_frame = false;
|
||||
bool has_focus = false;
|
||||
|
||||
|
@ -447,7 +447,6 @@ void Config::ReadCoreValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Core"));
|
||||
|
||||
ReadGlobalSetting(Settings::values.cpu_clock_percentage);
|
||||
ReadGlobalSetting(Settings::values.refresh_rate);
|
||||
|
||||
if (global) {
|
||||
ReadBasicSetting(Settings::values.use_cpu_jit);
|
||||
@ -484,6 +483,7 @@ void Config::ReadDebuggingValues() {
|
||||
ReadBasicSetting(Settings::values.use_gdbstub);
|
||||
ReadBasicSetting(Settings::values.gdbstub_port);
|
||||
ReadBasicSetting(Settings::values.renderer_debug);
|
||||
ReadBasicSetting(Settings::values.dump_command_buffers);
|
||||
|
||||
qt_config->beginGroup(QStringLiteral("LLE"));
|
||||
for (const auto& service_module : Service::service_module_map) {
|
||||
@ -627,7 +627,11 @@ void Config::ReadPathValues() {
|
||||
void Config::ReadRendererValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||
|
||||
ReadGlobalSetting(Settings::values.physical_device);
|
||||
ReadGlobalSetting(Settings::values.async_shader_compilation);
|
||||
ReadGlobalSetting(Settings::values.spirv_shader_gen);
|
||||
ReadGlobalSetting(Settings::values.graphics_api);
|
||||
ReadGlobalSetting(Settings::values.use_hw_renderer);
|
||||
ReadGlobalSetting(Settings::values.use_hw_shader);
|
||||
#ifdef __APPLE__
|
||||
// Hardware shader is broken on macos with Intel GPUs thanks to poor drivers.
|
||||
@ -964,7 +968,6 @@ void Config::SaveCoreValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Core"));
|
||||
|
||||
WriteGlobalSetting(Settings::values.cpu_clock_percentage);
|
||||
WriteGlobalSetting(Settings::values.refresh_rate);
|
||||
|
||||
if (global) {
|
||||
WriteBasicSetting(Settings::values.use_cpu_jit);
|
||||
@ -996,6 +999,7 @@ void Config::SaveDebuggingValues() {
|
||||
WriteBasicSetting(Settings::values.use_gdbstub);
|
||||
WriteBasicSetting(Settings::values.gdbstub_port);
|
||||
WriteBasicSetting(Settings::values.renderer_debug);
|
||||
WriteBasicSetting(Settings::values.dump_command_buffers);
|
||||
|
||||
qt_config->beginGroup(QStringLiteral("LLE"));
|
||||
for (const auto& service_module : Settings::values.lle_modules) {
|
||||
@ -1108,6 +1112,10 @@ void Config::SaveRendererValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||
|
||||
WriteGlobalSetting(Settings::values.graphics_api);
|
||||
WriteGlobalSetting(Settings::values.physical_device);
|
||||
WriteGlobalSetting(Settings::values.async_shader_compilation);
|
||||
WriteGlobalSetting(Settings::values.spirv_shader_gen);
|
||||
WriteGlobalSetting(Settings::values.use_hw_renderer);
|
||||
WriteGlobalSetting(Settings::values.use_hw_shader);
|
||||
#ifdef __APPLE__
|
||||
// Hardware shader is broken on macos thanks to poor drivers.
|
||||
|
@ -83,21 +83,6 @@ template <>
|
||||
void SetPerGameSetting(QComboBox* combobox,
|
||||
const Settings::SwitchableSetting<std::string>* setting);
|
||||
|
||||
/// Given an index of a combobox setting extracts the setting taking into
|
||||
/// account per-game status
|
||||
template <typename Type, bool ranged>
|
||||
Type GetComboboxSetting(int index, const Settings::SwitchableSetting<Type, ranged>* setting) {
|
||||
if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
|
||||
return static_cast<Type>(index);
|
||||
} else if (!Settings::IsConfiguringGlobal()) {
|
||||
if (index == 0) {
|
||||
return setting->GetValue();
|
||||
} else {
|
||||
return static_cast<Type>(index - ConfigurationShared::USE_GLOBAL_OFFSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a Qt widget sets the background color to indicate whether the setting
|
||||
/// is per-game overriden (highlighted) or global (non-highlighted)
|
||||
void SetHighlight(QWidget* widget, bool highlighted);
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QUrl>
|
||||
#include "citra_qt/configuration/configuration_shared.h"
|
||||
#include "citra_qt/configuration/configure_debug.h"
|
||||
@ -12,7 +13,9 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "qcheckbox.h"
|
||||
#include "ui_configure_debug.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
||||
// The QSlider doesn't have an easy way to set a custom step amount,
|
||||
// so we can just convert from the sliders range (0 - 79) to the expected
|
||||
@ -35,28 +38,51 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||
});
|
||||
|
||||
connect(ui->toggle_renderer_debug, &QCheckBox::clicked, this, [this](bool checked) {
|
||||
if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) {
|
||||
try {
|
||||
Vulkan::Instance debug_inst{true};
|
||||
} catch (vk::LayerNotPresentError&) {
|
||||
ui->toggle_renderer_debug->toggle();
|
||||
QMessageBox::warning(this, tr("Validation layer not available"),
|
||||
tr("Unable to enable debug renderer because the layer "
|
||||
"<strong>VK_LAYER_KHRONOS_validation</strong> is missing. "
|
||||
"Please install the Vulkan SDK or the appropriate package "
|
||||
"of your distribution"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->toggle_dump_command_buffers, &QCheckBox::clicked, this, [this](bool checked) {
|
||||
if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) {
|
||||
try {
|
||||
Vulkan::Instance debug_inst{false, true};
|
||||
} catch (vk::LayerNotPresentError&) {
|
||||
ui->toggle_dump_command_buffers->toggle();
|
||||
QMessageBox::warning(this, tr("Command buffer dumping not available"),
|
||||
tr("Unable to enable command buffer dumping because the layer "
|
||||
"<strong>VK_LAYER_LUNARG_api_dump</strong> is missing. "
|
||||
"Please install the Vulkan SDK or the appropriate package "
|
||||
"of your distribution"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
|
||||
ui->toggle_cpu_jit->setEnabled(!is_powered_on);
|
||||
ui->toggle_renderer_debug->setEnabled(!is_powered_on);
|
||||
ui->toggle_dump_command_buffers->setEnabled(!is_powered_on);
|
||||
|
||||
// Set a minimum width for the label to prevent the slider from changing size.
|
||||
// This scales across DPIs. (This value should be enough for "xxx%")
|
||||
ui->clock_display_label->setMinimumWidth(40);
|
||||
ui->refresh_display_label->setMinimumWidth(40);
|
||||
|
||||
connect(ui->slider_clock_speed, &QSlider::valueChanged, this, [&](int value) {
|
||||
ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value)));
|
||||
});
|
||||
|
||||
connect(ui->slider_refresh_rate, &QSlider::valueChanged, this, [&](int value) {
|
||||
ui->refresh_display_label->setText(QStringLiteral("%1Hz").arg(value));
|
||||
});
|
||||
|
||||
const bool is_global = Settings::IsConfiguringGlobal();
|
||||
ui->clock_speed_label->setVisible(is_global);
|
||||
ui->refresh_rate_label->setVisible(is_global);
|
||||
ui->clock_speed_combo->setVisible(!is_global);
|
||||
ui->refresh_rate_combo->setVisible(!is_global);
|
||||
ui->clock_speed_label->setVisible(Settings::IsConfiguringGlobal());
|
||||
ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
|
||||
|
||||
SetupPerGameUI();
|
||||
}
|
||||
@ -72,6 +98,7 @@ void ConfigureDebug::SetConfiguration() {
|
||||
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
|
||||
ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit.GetValue());
|
||||
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug.GetValue());
|
||||
ui->toggle_dump_command_buffers->setChecked(Settings::values.dump_command_buffers.GetValue());
|
||||
|
||||
if (!Settings::IsConfiguringGlobal()) {
|
||||
if (Settings::values.cpu_clock_percentage.UsingGlobal()) {
|
||||
@ -81,26 +108,14 @@ void ConfigureDebug::SetConfiguration() {
|
||||
ui->clock_speed_combo->setCurrentIndex(1);
|
||||
ui->slider_clock_speed->setEnabled(true);
|
||||
}
|
||||
if (Settings::values.refresh_rate.UsingGlobal()) {
|
||||
ui->refresh_rate_combo->setCurrentIndex(0);
|
||||
ui->slider_refresh_rate->setEnabled(false);
|
||||
} else {
|
||||
ui->refresh_rate_combo->setCurrentIndex(1);
|
||||
ui->slider_refresh_rate->setEnabled(true);
|
||||
}
|
||||
ConfigurationShared::SetHighlight(ui->clock_speed_widget,
|
||||
!Settings::values.cpu_clock_percentage.UsingGlobal());
|
||||
ConfigurationShared::SetHighlight(ui->refresh_rate_widget,
|
||||
!Settings::values.refresh_rate.UsingGlobal());
|
||||
}
|
||||
|
||||
ui->slider_clock_speed->setValue(
|
||||
SettingsToSlider(Settings::values.cpu_clock_percentage.GetValue()));
|
||||
ui->clock_display_label->setText(
|
||||
QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage.GetValue()));
|
||||
ui->slider_refresh_rate->setValue(Settings::values.refresh_rate.GetValue());
|
||||
ui->refresh_display_label->setText(
|
||||
QStringLiteral("%1Hz").arg(Settings::values.refresh_rate.GetValue()));
|
||||
}
|
||||
|
||||
void ConfigureDebug::ApplyConfiguration() {
|
||||
@ -114,39 +129,28 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||
Log::SetGlobalFilter(filter);
|
||||
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
|
||||
Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked();
|
||||
Settings::values.dump_command_buffers = ui->toggle_dump_command_buffers->isChecked();
|
||||
|
||||
ConfigurationShared::ApplyPerGameSetting(
|
||||
&Settings::values.cpu_clock_percentage, ui->clock_speed_combo,
|
||||
[this](s32) { return SliderToSettings(ui->slider_clock_speed->value()); });
|
||||
|
||||
ConfigurationShared::ApplyPerGameSetting(
|
||||
&Settings::values.refresh_rate, ui->refresh_rate_combo,
|
||||
[this](s32) { return ui->slider_refresh_rate->value(); });
|
||||
}
|
||||
|
||||
void ConfigureDebug::SetupPerGameUI() {
|
||||
// Block the global settings if a game is currently running that overrides them
|
||||
if (Settings::IsConfiguringGlobal()) {
|
||||
ui->slider_clock_speed->setEnabled(Settings::values.cpu_clock_percentage.UsingGlobal());
|
||||
ui->slider_refresh_rate->setEnabled(Settings::values.refresh_rate.UsingGlobal());
|
||||
ui->refresh_rate_widget->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
connect(ui->refresh_rate_combo, qOverload<int>(&QComboBox::activated), this, [this](int index) {
|
||||
ui->slider_refresh_rate->setEnabled(index == 1);
|
||||
ConfigurationShared::SetHighlight(ui->refresh_rate_widget, index == 1);
|
||||
});
|
||||
|
||||
connect(ui->clock_speed_combo, qOverload<int>(&QComboBox::activated), this, [this](int index) {
|
||||
ui->slider_clock_speed->setEnabled(index == 1);
|
||||
ConfigurationShared::SetHighlight(ui->clock_speed_widget, index == 1);
|
||||
});
|
||||
|
||||
ui->gdb_group->setVisible(false);
|
||||
ui->logging_group->setVisible(false);
|
||||
ui->groupBox->setVisible(false);
|
||||
ui->groupBox_2->setVisible(false);
|
||||
ui->toggle_cpu_jit->setVisible(false);
|
||||
ui->refresh_rate_widget->setVisible(true);
|
||||
}
|
||||
|
||||
void ConfigureDebug::RetranslateUI() {
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>523</width>
|
||||
<height>495</height>
|
||||
<height>491</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -17,7 +17,7 @@
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gdb_group">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>GDB</string>
|
||||
</property>
|
||||
@ -66,7 +66,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="logging_group">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Logging</string>
|
||||
</property>
|
||||
@ -107,23 +107,16 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="cpu_group">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>CPU</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="toggle_renderer_debug">
|
||||
<property name="text">
|
||||
<string>Enable debug renderer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QWidget" name="clock_speed_widget" native="true">
|
||||
<layout class="QHBoxLayout" name="clock_speed_layout">
|
||||
<property name="spacing">
|
||||
<number>7</number>
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
@ -209,72 +202,18 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QWidget" name="refresh_rate_widget" native="true">
|
||||
<layout class="QHBoxLayout" name="refresh_rate_widget_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="refresh_rate_combo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Use global refresh rate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Set refresh rate:</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="refresh_rate_label">
|
||||
<property name="text">
|
||||
<string>Refresh rate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_refresh_rate">
|
||||
<property name="minimum">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>360</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>60</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="refresh_display_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="toggle_dump_command_buffers">
|
||||
<property name="text">
|
||||
<string>Dump command buffers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="toggle_renderer_debug">
|
||||
<property name="text">
|
||||
<string>Enable debug renderer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -22,9 +22,7 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
|
||||
|
||||
ui->layout_group->setEnabled(!Settings::values.custom_layout);
|
||||
|
||||
const auto graphics_api = Settings::values.graphics_api.GetValue();
|
||||
const bool res_scale_enabled = graphics_api != Settings::GraphicsAPI::Software;
|
||||
ui->resolution_factor_combobox->setEnabled(res_scale_enabled);
|
||||
ui->resolution_factor_combobox->setEnabled(Settings::values.use_hw_renderer.GetValue());
|
||||
|
||||
connect(ui->render_3d_combobox,
|
||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||
|
@ -11,25 +11,35 @@
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "ui_configure_graphics.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
||||
ConfigureGraphics::ConfigureGraphics(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureGraphics>()) {
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->toggle_vsync_new->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
// Set the index to -1 to ensure the below lambda is called with setCurrentIndex
|
||||
DiscoverPhysicalDevices();
|
||||
SetupPerGameUI();
|
||||
|
||||
const bool not_running = !Core::System::GetInstance().IsPoweredOn();
|
||||
const bool hw_renderer_enabled = ui->toggle_hw_renderer->isChecked();
|
||||
ui->toggle_hw_renderer->setEnabled(not_running);
|
||||
ui->hw_renderer_group->setEnabled(hw_renderer_enabled && not_running);
|
||||
ui->graphics_api_combo->setEnabled(not_running);
|
||||
ui->toggle_shader_jit->setEnabled(not_running);
|
||||
ui->toggle_disk_shader_cache->setEnabled(hw_renderer_enabled && not_running);
|
||||
ui->physical_device_combo->setEnabled(not_running);
|
||||
ui->toggle_async_shaders->setEnabled(not_running);
|
||||
ui->graphics_api_combo->setCurrentIndex(-1);
|
||||
|
||||
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
[this](int index) {
|
||||
const auto graphics_api =
|
||||
ConfigurationShared::GetComboboxSetting(index, &Settings::values.graphics_api);
|
||||
const bool is_software = graphics_api == Settings::GraphicsAPI::Software;
|
||||
connect(ui->toggle_hw_renderer, &QCheckBox::toggled, this, [this] {
|
||||
const bool checked = ui->toggle_hw_renderer->isChecked();
|
||||
ui->hw_renderer_group->setEnabled(checked);
|
||||
ui->toggle_disk_shader_cache->setEnabled(checked && ui->toggle_hw_shader->isChecked());
|
||||
});
|
||||
|
||||
ui->hw_renderer_group->setEnabled(!is_software);
|
||||
ui->toggle_disk_shader_cache->setEnabled(!is_software &&
|
||||
ui->toggle_hw_shader->isChecked());
|
||||
});
|
||||
ui->hw_shader_group->setEnabled(ui->toggle_hw_shader->isChecked());
|
||||
ui->toggle_disk_shader_cache->setEnabled(ui->toggle_hw_renderer->isChecked() &&
|
||||
ui->toggle_hw_shader->isChecked());
|
||||
|
||||
connect(ui->toggle_hw_shader, &QCheckBox::toggled, this, [this] {
|
||||
const bool checked = ui->toggle_hw_shader->isChecked();
|
||||
@ -59,7 +69,9 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
|
||||
ui->toggle_separable_shader->setVisible(false);
|
||||
#endif
|
||||
|
||||
SetupPerGameUI();
|
||||
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
&ConfigureGraphics::SetPhysicalDeviceComboVisibility);
|
||||
|
||||
SetConfiguration();
|
||||
}
|
||||
|
||||
@ -67,20 +79,29 @@ ConfigureGraphics::~ConfigureGraphics() = default;
|
||||
|
||||
void ConfigureGraphics::SetConfiguration() {
|
||||
if (!Settings::IsConfiguringGlobal()) {
|
||||
ConfigurationShared::SetHighlight(ui->physical_device_group,
|
||||
!Settings::values.physical_device.UsingGlobal());
|
||||
ConfigurationShared::SetPerGameSetting(ui->physical_device_combo,
|
||||
&Settings::values.physical_device);
|
||||
ConfigurationShared::SetHighlight(ui->graphics_api_group,
|
||||
!Settings::values.graphics_api.UsingGlobal());
|
||||
ConfigurationShared::SetPerGameSetting(ui->graphics_api_combo,
|
||||
&Settings::values.graphics_api);
|
||||
} else {
|
||||
ui->physical_device_combo->setCurrentIndex(
|
||||
static_cast<int>(Settings::values.physical_device.GetValue()));
|
||||
ui->graphics_api_combo->setCurrentIndex(
|
||||
static_cast<int>(Settings::values.graphics_api.GetValue()));
|
||||
}
|
||||
|
||||
ui->toggle_hw_renderer->setChecked(Settings::values.use_hw_renderer.GetValue());
|
||||
ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader.GetValue());
|
||||
ui->toggle_separable_shader->setChecked(Settings::values.separable_shader.GetValue());
|
||||
ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul.GetValue());
|
||||
ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
|
||||
ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new.GetValue());
|
||||
ui->spirv_shader_gen->setChecked(Settings::values.spirv_shader_gen.GetValue());
|
||||
ui->toggle_async_shaders->setChecked(Settings::values.async_shader_compilation.GetValue());
|
||||
|
||||
if (Settings::IsConfiguringGlobal()) {
|
||||
ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit.GetValue());
|
||||
@ -88,8 +109,8 @@ void ConfigureGraphics::SetConfiguration() {
|
||||
}
|
||||
|
||||
void ConfigureGraphics::ApplyConfiguration() {
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api,
|
||||
ui->graphics_api_combo);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_hw_renderer,
|
||||
ui->toggle_hw_renderer, use_hw_renderer);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_hw_shader, ui->toggle_hw_shader,
|
||||
use_hw_shader);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.separable_shader,
|
||||
@ -100,6 +121,14 @@ void ConfigureGraphics::ApplyConfiguration() {
|
||||
ui->toggle_disk_shader_cache, use_disk_shader_cache);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new,
|
||||
use_vsync_new);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api,
|
||||
ui->graphics_api_combo);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.physical_device,
|
||||
ui->physical_device_combo);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_shader_compilation,
|
||||
ui->toggle_async_shaders, async_shader_compilation);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.spirv_shader_gen,
|
||||
ui->spirv_shader_gen, spirv_shader_gen);
|
||||
|
||||
if (Settings::IsConfiguringGlobal()) {
|
||||
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();
|
||||
@ -113,13 +142,17 @@ void ConfigureGraphics::RetranslateUI() {
|
||||
void ConfigureGraphics::SetupPerGameUI() {
|
||||
// Block the global settings if a game is currently running that overrides them
|
||||
if (Settings::IsConfiguringGlobal()) {
|
||||
ui->graphics_api_group->setEnabled(Settings::values.graphics_api.UsingGlobal());
|
||||
ui->toggle_hw_renderer->setEnabled(Settings::values.use_hw_renderer.UsingGlobal());
|
||||
ui->toggle_hw_shader->setEnabled(Settings::values.use_hw_shader.UsingGlobal());
|
||||
ui->toggle_separable_shader->setEnabled(Settings::values.separable_shader.UsingGlobal());
|
||||
ui->toggle_accurate_mul->setEnabled(Settings::values.shaders_accurate_mul.UsingGlobal());
|
||||
ui->toggle_disk_shader_cache->setEnabled(
|
||||
Settings::values.use_disk_shader_cache.UsingGlobal());
|
||||
ui->toggle_vsync_new->setEnabled(Settings::values.use_vsync_new.UsingGlobal());
|
||||
ui->toggle_async_shaders->setEnabled(
|
||||
Settings::values.async_shader_compilation.UsingGlobal());
|
||||
ui->graphics_api_combo->setEnabled(Settings::values.graphics_api.UsingGlobal());
|
||||
ui->physical_device_combo->setEnabled(Settings::values.physical_device.UsingGlobal());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -129,6 +162,12 @@ void ConfigureGraphics::SetupPerGameUI() {
|
||||
ui->graphics_api_combo, ui->graphics_api_group,
|
||||
static_cast<u32>(Settings::values.graphics_api.GetValue(true)));
|
||||
|
||||
ConfigurationShared::SetColoredComboBox(
|
||||
ui->physical_device_combo, ui->physical_device_group,
|
||||
static_cast<u32>(Settings::values.physical_device.GetValue(true)));
|
||||
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_hw_renderer,
|
||||
Settings::values.use_hw_renderer, use_hw_renderer);
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_hw_shader, Settings::values.use_hw_shader,
|
||||
use_hw_shader);
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_separable_shader,
|
||||
@ -140,4 +179,48 @@ void ConfigureGraphics::SetupPerGameUI() {
|
||||
use_disk_shader_cache);
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_vsync_new, Settings::values.use_vsync_new,
|
||||
use_vsync_new);
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_async_shaders,
|
||||
Settings::values.async_shader_compilation,
|
||||
async_shader_compilation);
|
||||
ConfigurationShared::SetColoredTristate(ui->spirv_shader_gen, Settings::values.spirv_shader_gen,
|
||||
spirv_shader_gen);
|
||||
}
|
||||
|
||||
void ConfigureGraphics::DiscoverPhysicalDevices() {
|
||||
if (physical_devices_discovered) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vulkan::Instance instance{};
|
||||
const auto physical_devices = instance.GetPhysicalDevices();
|
||||
|
||||
for (const vk::PhysicalDevice& physical_device : physical_devices) {
|
||||
const QString name = QString::fromLocal8Bit(physical_device.getProperties().deviceName);
|
||||
ui->physical_device_combo->addItem(name);
|
||||
}
|
||||
|
||||
physical_devices_discovered = true;
|
||||
}
|
||||
|
||||
void ConfigureGraphics::SetPhysicalDeviceComboVisibility(int index) {
|
||||
bool is_visible{false};
|
||||
|
||||
// When configuring per-game the physical device combo should be
|
||||
// shown either when the global api is used and that is vulkan or
|
||||
// vulkan is set as the per-game api.
|
||||
if (!Settings::IsConfiguringGlobal()) {
|
||||
const auto global_graphics_api = Settings::values.graphics_api.GetValue(true);
|
||||
const bool using_global = index == 0;
|
||||
if (!using_global) {
|
||||
index -= ConfigurationShared::USE_GLOBAL_OFFSET;
|
||||
}
|
||||
const auto graphics_api = static_cast<Settings::GraphicsAPI>(index);
|
||||
is_visible = (using_global && global_graphics_api == Settings::GraphicsAPI::Vulkan) ||
|
||||
graphics_api == Settings::GraphicsAPI::Vulkan;
|
||||
} else {
|
||||
const auto graphics_api = static_cast<Settings::GraphicsAPI>(index);
|
||||
is_visible = graphics_api == Settings::GraphicsAPI::Vulkan;
|
||||
}
|
||||
ui->physical_device_group->setVisible(is_visible);
|
||||
ui->spirv_shader_gen->setVisible(is_visible);
|
||||
}
|
||||
|
@ -28,14 +28,21 @@ public:
|
||||
|
||||
void UpdateBackgroundColorButton(const QColor& color);
|
||||
|
||||
private:
|
||||
void SetupPerGameUI();
|
||||
|
||||
private:
|
||||
void DiscoverPhysicalDevices();
|
||||
void SetPhysicalDeviceComboVisibility(int index);
|
||||
|
||||
ConfigurationShared::CheckState use_hw_renderer;
|
||||
ConfigurationShared::CheckState use_hw_shader;
|
||||
ConfigurationShared::CheckState separable_shader;
|
||||
ConfigurationShared::CheckState shaders_accurate_mul;
|
||||
ConfigurationShared::CheckState use_disk_shader_cache;
|
||||
ConfigurationShared::CheckState use_vsync_new;
|
||||
ConfigurationShared::CheckState async_shader_compilation;
|
||||
ConfigurationShared::CheckState spirv_shader_gen;
|
||||
std::unique_ptr<Ui::ConfigureGraphics> ui;
|
||||
QColor bg_color;
|
||||
bool physical_devices_discovered = false;
|
||||
};
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>443</height>
|
||||
<width>454</width>
|
||||
<height>579</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
@ -29,6 +29,9 @@
|
||||
<item>
|
||||
<widget class="QWidget" name="graphics_api_group" native="true">
|
||||
<layout class="QHBoxLayout" name="graphics_api_group_2">
|
||||
<property name="spacing">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -52,12 +55,17 @@
|
||||
<widget class="QComboBox" name="graphics_api_combo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Software</string>
|
||||
<string>OpenGL</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>OpenGL</string>
|
||||
<string>OpenGLES</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Vulkan</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
@ -65,6 +73,41 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="physical_device_group" native="true">
|
||||
<layout class="QHBoxLayout" name="physical_device_group_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="physical_device_label">
|
||||
<property name="text">
|
||||
<string>Physical device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="physical_device_combo"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="spirv_shader_gen">
|
||||
<property name="text">
|
||||
<string>SPIR-V Shader Generation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -74,11 +117,21 @@
|
||||
<string>Renderer</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_hw_renderer">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Use OpenGL to accelerate rendering.</p><p>Disable to debug graphics-related problem.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Hardware Renderer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="hw_renderer_group" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
@ -156,6 +209,13 @@
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_async_shaders">
|
||||
<property name="text">
|
||||
<string>Async Shader Compilation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_disk_shader_cache">
|
||||
<property name="toolTip">
|
||||
@ -195,6 +255,8 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>toggle_hw_renderer</tabstop>
|
||||
<tabstop>toggle_hw_shader</tabstop>
|
||||
<tabstop>toggle_separable_shader</tabstop>
|
||||
<tabstop>toggle_accurate_mul</tabstop>
|
||||
<tabstop>toggle_shader_jit</tabstop>
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "citra_qt/util/spinbox.h"
|
||||
#include "common/color.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hw/gpu.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/pica_state.h"
|
||||
#include "video_core/regs_framebuffer.h"
|
||||
|
@ -90,4 +90,4 @@ bool CheckAuthorizationForMicrophone() {
|
||||
return authorized_microphone;
|
||||
}
|
||||
|
||||
} // AppleAuthorization
|
||||
} // namespace AppleAuthorization
|
||||
|
@ -12,22 +12,12 @@
|
||||
#include <QFutureWatcher>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QOpenGLFunctions_4_3_Core>
|
||||
#include <QSysInfo>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include <QtGui>
|
||||
#include <QtWidgets>
|
||||
#include <fmt/format.h>
|
||||
#ifdef __APPLE__
|
||||
#include <unistd.h> // for chdir
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef __unix__
|
||||
#include <QVariant>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QtDBus>
|
||||
#endif
|
||||
#include "citra_qt/aboutdialog.h"
|
||||
#include "citra_qt/applets/mii_selector.h"
|
||||
#include "citra_qt/applets/swkbd.h"
|
||||
@ -60,7 +50,6 @@
|
||||
#include "citra_qt/movie/movie_play_dialog.h"
|
||||
#include "citra_qt/movie/movie_record_dialog.h"
|
||||
#include "citra_qt/multiplayer/state.h"
|
||||
#include "citra_qt/qt_image_interface.h"
|
||||
#include "citra_qt/uisettings.h"
|
||||
#include "citra_qt/updater/updater.h"
|
||||
#include "citra_qt/util/clickable_label.h"
|
||||
@ -70,9 +59,7 @@
|
||||
#include "common/file_util.h"
|
||||
#include "common/literals.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/logging/text_formatter.h"
|
||||
#include "common/memory_detect.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scm_rev.h"
|
||||
@ -87,7 +74,6 @@
|
||||
#include "core/file_sys/archive_extsavedata.h"
|
||||
#include "core/file_sys/archive_source_sd_savedata.h"
|
||||
#include "core/frontend/applets/default_applets.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/service/cfg/cfg.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/hle/service/nfc/nfc.h"
|
||||
@ -98,9 +84,20 @@
|
||||
#include "input_common/main.h"
|
||||
#include "network/network_settings.h"
|
||||
#include "ui_main.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <unistd.h> // for chdir
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef __unix__
|
||||
#include <QVariant>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QtDBus>
|
||||
#endif
|
||||
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
#include "citra_qt/discord_impl.h"
|
||||
#endif
|
||||
@ -354,6 +351,22 @@ void GMainWindow::InitializeWidgets() {
|
||||
statusBar()->addPermanentWidget(label);
|
||||
}
|
||||
|
||||
// Setup Graphics API button
|
||||
graphics_api_button = new QPushButton();
|
||||
graphics_api_button->setObjectName(QStringLiteral("GraphicsAPIStatusBarButton"));
|
||||
graphics_api_button->setFocusPolicy(Qt::NoFocus);
|
||||
UpdateAPIIndicator(false);
|
||||
|
||||
connect(graphics_api_button, &QPushButton::clicked, this, [this] {
|
||||
if (emulation_running) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAPIIndicator(true);
|
||||
});
|
||||
|
||||
statusBar()->insertPermanentWidget(0, graphics_api_button);
|
||||
|
||||
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText());
|
||||
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon());
|
||||
|
||||
@ -577,6 +590,8 @@ void GMainWindow::InitializeHotkeys() {
|
||||
});
|
||||
connect_shortcut(QStringLiteral("Toggle Texture Dumping"),
|
||||
[&] { Settings::values.dump_textures = !Settings::values.dump_textures; });
|
||||
connect_shortcut(QStringLiteral("Toggle Custom Textures"),
|
||||
[&] { Settings::values.custom_textures = !Settings::values.custom_textures; });
|
||||
// We use "static" here in order to avoid capturing by lambda due to a MSVC bug, which makes
|
||||
// the variable hold a garbage value after this function exits
|
||||
static constexpr u16 SPEED_LIMIT_STEP = 5;
|
||||
@ -1080,6 +1095,24 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
tr("GBA Virtual Console ROMs are not supported by Citra."));
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorVideoCore:
|
||||
QMessageBox::critical(
|
||||
this, tr("Video Core Error"),
|
||||
tr("An error has occurred during intialization of the video backend. Please <a "
|
||||
"href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see "
|
||||
"the "
|
||||
"log</a> for more details. "
|
||||
"Ensure that you have the latest graphics drivers for your GPU."));
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorVideoCore_ErrorGenericDrivers:
|
||||
QMessageBox::critical(
|
||||
this, tr("Video Core Error"),
|
||||
tr("You are running default Windows drivers "
|
||||
"for your GPU. You need to install the "
|
||||
"proper drivers for your graphics card from the manufacturer's website."));
|
||||
break;
|
||||
|
||||
default:
|
||||
QMessageBox::critical(
|
||||
this, tr("Error while loading ROM!"),
|
||||
@ -1137,6 +1170,9 @@ void GMainWindow::BootGame(const QString& filename) {
|
||||
|
||||
LOG_INFO(Frontend, "Using per game config file for title id {}", config_file_name);
|
||||
Settings::LogSettings();
|
||||
|
||||
// Update API indicator to reflect the per-game graphics API, if set.
|
||||
UpdateAPIIndicator(false);
|
||||
}
|
||||
|
||||
// Save configurations
|
||||
@ -1222,10 +1258,6 @@ void GMainWindow::BootGame(const QString& filename) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
// show and hide the render_window to create the context
|
||||
render_window->show();
|
||||
render_window->hide();
|
||||
|
||||
loading_screen->Prepare(Core::System::GetInstance().GetAppLoader());
|
||||
loading_screen->show();
|
||||
|
||||
@ -1775,6 +1807,9 @@ void GMainWindow::OnPauseContinueGame() {
|
||||
void GMainWindow::OnStopGame() {
|
||||
ShutdownGame();
|
||||
Settings::RestoreGlobalState(false);
|
||||
|
||||
// If a per-game graphics API was set we should reset to the global option
|
||||
UpdateAPIIndicator(false);
|
||||
}
|
||||
|
||||
void GMainWindow::OnLoadComplete() {
|
||||
@ -1997,6 +2032,7 @@ void GMainWindow::OnConfigure() {
|
||||
setMouseTracking(false);
|
||||
}
|
||||
UpdateSecondaryWindowVisibility();
|
||||
UpdateAPIIndicator(false);
|
||||
UpdateBootHomeMenuState();
|
||||
} else {
|
||||
Settings::values.input_profiles = old_input_profiles;
|
||||
@ -2319,6 +2355,26 @@ void GMainWindow::ShowMouseCursor() {
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateAPIIndicator(bool override) {
|
||||
static std::array graphics_apis = {QStringLiteral("OPENGL"), QStringLiteral("OPENGLES"),
|
||||
QStringLiteral("VULKAN")};
|
||||
|
||||
static std::array graphics_api_colors = {QStringLiteral("#00ccdd"), QStringLiteral("#ba2a8d"),
|
||||
QStringLiteral("#91242a")};
|
||||
|
||||
u32 api_index = static_cast<u32>(Settings::values.graphics_api.GetValue());
|
||||
if (override) {
|
||||
api_index = (api_index + 1) % graphics_apis.size();
|
||||
Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(api_index);
|
||||
}
|
||||
|
||||
const QString style_sheet = QStringLiteral("QPushButton { font-weight: bold; color: %0; }")
|
||||
.arg(graphics_api_colors[api_index]);
|
||||
|
||||
graphics_api_button->setText(graphics_apis[api_index]);
|
||||
graphics_api_button->setStyleSheet(style_sheet);
|
||||
}
|
||||
|
||||
void GMainWindow::OnMouseActivity() {
|
||||
ShowMouseCursor();
|
||||
}
|
||||
@ -2785,9 +2841,6 @@ int main(int argc, char* argv[]) {
|
||||
system.RegisterMiiSelector(std::make_shared<QtMiiSelector>(main_window));
|
||||
system.RegisterSoftwareKeyboard(std::make_shared<QtKeyboard>(main_window));
|
||||
|
||||
// Register Qt image interface
|
||||
system.RegisterImageInterface(std::make_shared<QtImageInterface>());
|
||||
|
||||
main_window.show();
|
||||
|
||||
QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window,
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <QMainWindow>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include <QTranslator>
|
||||
#include "citra_qt/compatibility_list.h"
|
||||
@ -252,6 +253,7 @@ private:
|
||||
void HideMouseCursor();
|
||||
void ShowMouseCursor();
|
||||
void OpenPerGameConfiguration(u64 title_id, const QString& file_name);
|
||||
void UpdateAPIIndicator(bool override);
|
||||
|
||||
std::unique_ptr<Ui::MainWindow> ui;
|
||||
|
||||
@ -267,6 +269,7 @@ private:
|
||||
QLabel* emu_speed_label = nullptr;
|
||||
QLabel* game_fps_label = nullptr;
|
||||
QLabel* emu_frametime_label = nullptr;
|
||||
QPushButton* graphics_api_button = nullptr;
|
||||
QTimer status_bar_update_timer;
|
||||
bool message_label_used_for_movie = false;
|
||||
|
||||
|
@ -1,38 +0,0 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QImage>
|
||||
#include <QString>
|
||||
#include "citra_qt/qt_image_interface.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
bool QtImageInterface::DecodePNG(std::vector<u8>& dst, u32& width, u32& height,
|
||||
const std::string& path) {
|
||||
QImage image(QString::fromStdString(path));
|
||||
|
||||
if (image.isNull()) {
|
||||
LOG_ERROR(Frontend, "Failed to open {} for decoding", path);
|
||||
return false;
|
||||
}
|
||||
width = image.width();
|
||||
height = image.height();
|
||||
|
||||
image = image.convertToFormat(QImage::Format_RGBA8888);
|
||||
|
||||
// Write RGBA8 to vector
|
||||
dst = std::vector<u8>(image.constBits(), image.constBits() + (width * height * 4));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QtImageInterface::EncodePNG(const std::string& path, const std::vector<u8>& src, u32 width,
|
||||
u32 height) {
|
||||
QImage image(src.data(), width, height, QImage::Format_RGBA8888);
|
||||
|
||||
if (!image.save(QString::fromStdString(path), "PNG")) {
|
||||
LOG_ERROR(Frontend, "Failed to save {}", path);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/frontend/image_interface.h"
|
||||
|
||||
class QtImageInterface final : public Frontend::ImageInterface {
|
||||
public:
|
||||
bool DecodePNG(std::vector<u8>& dst, u32& width, u32& height, const std::string& path) override;
|
||||
bool EncodePNG(const std::string& path, const std::vector<u8>& src, u32 width,
|
||||
u32 height) override;
|
||||
};
|
@ -63,11 +63,13 @@ add_library(common STATIC
|
||||
arch.h
|
||||
archives.h
|
||||
assert.h
|
||||
async_handle.h
|
||||
atomic_ops.h
|
||||
detached_tasks.cpp
|
||||
detached_tasks.h
|
||||
bit_field.h
|
||||
bit_set.h
|
||||
bit_util.h
|
||||
cityhash.cpp
|
||||
cityhash.h
|
||||
color.h
|
||||
@ -76,9 +78,14 @@ add_library(common STATIC
|
||||
common_precompiled_headers.h
|
||||
common_types.h
|
||||
construct.h
|
||||
dds-ktx.h
|
||||
error.cpp
|
||||
error.h
|
||||
file_util.cpp
|
||||
file_util.h
|
||||
hash.h
|
||||
image_util.cpp
|
||||
image_util.h
|
||||
linear_disk_cache.h
|
||||
literals.h
|
||||
logging/backend.cpp
|
||||
@ -100,12 +107,14 @@ add_library(common STATIC
|
||||
misc.cpp
|
||||
param_package.cpp
|
||||
param_package.h
|
||||
polyfill_thread.h
|
||||
precompiled_headers.h
|
||||
quaternion.h
|
||||
ring_buffer.h
|
||||
scm_rev.cpp
|
||||
scm_rev.h
|
||||
scope_exit.h
|
||||
scratch_buffer.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
serialization/atomic.h
|
||||
@ -124,9 +133,11 @@ add_library(common STATIC
|
||||
thread.cpp
|
||||
thread.h
|
||||
thread_queue_list.h
|
||||
thread_worker.h
|
||||
threadsafe_queue.h
|
||||
timer.cpp
|
||||
timer.h
|
||||
unique_function.h
|
||||
vector_math.h
|
||||
web_result.h
|
||||
x64/cpu_detect.cpp
|
||||
@ -140,7 +151,7 @@ add_library(common STATIC
|
||||
create_target_directory_groups(common)
|
||||
|
||||
target_link_libraries(common PUBLIC fmt::fmt microprofile Boost::boost Boost::serialization Boost::iostreams)
|
||||
target_link_libraries(common PRIVATE libzstd_static)
|
||||
target_link_libraries(common PRIVATE libzstd_static spng::spng)
|
||||
set_target_properties(common PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
|
||||
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
|
39
src/common/async_handle.h
Normal file
39
src/common/async_handle.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common {
|
||||
|
||||
struct AsyncHandle {
|
||||
public:
|
||||
AsyncHandle(bool is_done_ = false) : is_done{is_done_} {}
|
||||
|
||||
[[nodiscard]] bool IsDone() noexcept {
|
||||
return is_done.load(std::memory_order::relaxed);
|
||||
}
|
||||
|
||||
void WaitDone() noexcept {
|
||||
std::unique_lock lock{mutex};
|
||||
condvar.wait(lock, [this] { return is_done.load(std::memory_order::relaxed); });
|
||||
}
|
||||
|
||||
void MarkDone(bool done = true) noexcept {
|
||||
std::scoped_lock lock{mutex};
|
||||
is_done = done;
|
||||
condvar.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
std::condition_variable condvar;
|
||||
std::mutex mutex;
|
||||
std::atomic_bool is_done{false};
|
||||
};
|
||||
|
||||
} // namespace Common
|
66
src/common/bit_util.h
Normal file
66
src/common/bit_util.h
Normal file
@ -0,0 +1,66 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <bit>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
/// Gets the size of a specified type T in bits.
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr std::size_t BitSize() {
|
||||
return sizeof(T) * CHAR_BIT;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 MostSignificantBit32(const u32 value) {
|
||||
return 31U - static_cast<u32>(std::countl_zero(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 MostSignificantBit64(const u64 value) {
|
||||
return 63U - static_cast<u32>(std::countl_zero(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 Log2Floor32(const u32 value) {
|
||||
return MostSignificantBit32(value);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 Log2Floor64(const u64 value) {
|
||||
return MostSignificantBit64(value);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 Log2Ceil32(const u32 value) {
|
||||
const u32 log2_f = Log2Floor32(value);
|
||||
return log2_f + static_cast<u32>((value ^ (1U << log2_f)) != 0U);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 Log2Ceil64(const u64 value) {
|
||||
const u64 log2_f = Log2Floor64(value);
|
||||
return static_cast<u32>(log2_f + static_cast<u64>((value ^ (1ULL << log2_f)) != 0ULL));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::is_unsigned_v<T>
|
||||
[[nodiscard]] constexpr bool IsPow2(T value) {
|
||||
return value != 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::is_integral_v<T>
|
||||
[[nodiscard]] T NextPow2(T value) {
|
||||
return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
|
||||
}
|
||||
|
||||
template <size_t bit_index, typename T>
|
||||
requires std::is_integral_v<T>
|
||||
[[nodiscard]] constexpr bool Bit(const T value) {
|
||||
static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T");
|
||||
return ((value >> bit_index) & T(1)) == T(1);
|
||||
}
|
||||
|
||||
} // namespace Common
|
@ -52,6 +52,11 @@ namespace Common::Color {
|
||||
return value >> 2;
|
||||
}
|
||||
|
||||
/// Averages the RGB components of a color
|
||||
[[nodiscard]] constexpr u8 AverageRgbComponents(const Common::Vec4<u8>& color) {
|
||||
return (static_cast<u32>(color.r()) + color.g() + color.b()) / 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a color stored in RGBA8 format
|
||||
* @param bytes Pointer to encoded source color
|
||||
@ -115,6 +120,44 @@ namespace Common::Color {
|
||||
Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a color stored in IA8 format
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeIA8(const u8* bytes) {
|
||||
return {bytes[1], bytes[1], bytes[1], bytes[0]};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a color stored in I8 format
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeI8(const u8* bytes) {
|
||||
return {bytes[0], bytes[0], bytes[0], 255};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a color stored in A8 format
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeA8(const u8* bytes) {
|
||||
return {0, 0, 0, bytes[0]};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a color stored in IA4 format
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeIA4(const u8* bytes) {
|
||||
u8 i = Common::Color::Convert4To8((bytes[0] & 0xF0) >> 4);
|
||||
u8 a = Common::Color::Convert4To8(bytes[0] & 0x0F);
|
||||
return {i, i, i, a};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a depth value stored in D16 format
|
||||
* @param bytes Pointer to encoded source value
|
||||
@ -176,6 +219,7 @@ inline void EncodeRG8(const Common::Vec4<u8>& color, u8* bytes) {
|
||||
bytes[1] = color.r();
|
||||
bytes[0] = color.g();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a color as RGB565 format
|
||||
* @param color Source color to encode
|
||||
@ -212,6 +256,43 @@ inline void EncodeRGBA4(const Common::Vec4<u8>& color, u8* bytes) {
|
||||
std::memcpy(bytes, &data, sizeof(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a color as IA8 format
|
||||
* @param color Source color to encode
|
||||
* @param bytes Destination pointer to store encoded color
|
||||
*/
|
||||
inline void EncodeIA8(const Common::Vec4<u8>& color, u8* bytes) {
|
||||
bytes[1] = AverageRgbComponents(color);
|
||||
bytes[0] = color.a();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a color as I8 format
|
||||
* @param color Source color to encode
|
||||
* @param bytes Destination pointer to store encoded color
|
||||
*/
|
||||
inline void EncodeI8(const Common::Vec4<u8>& color, u8* bytes) {
|
||||
bytes[0] = AverageRgbComponents(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a color as A8 format
|
||||
* @param color Source color to encode
|
||||
* @param bytes Destination pointer to store encoded color
|
||||
*/
|
||||
inline void EncodeA8(const Common::Vec4<u8>& color, u8* bytes) {
|
||||
bytes[0] = color.a();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a color as IA4 format
|
||||
* @param color Source color to encode
|
||||
* @param bytes Destination pointer to store encoded color
|
||||
*/
|
||||
inline void EncodeIA4(const Common::Vec4<u8>& color, u8* bytes) {
|
||||
bytes[0] = (Convert8To4(AverageRgbComponents(color)) << 4) | Convert8To4(color.a());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a 16 bit depth value as D16 format
|
||||
* @param value 16 bit source depth value to encode
|
||||
|
1465
src/common/dds-ktx.h
Normal file
1465
src/common/dds-ktx.h
Normal file
File diff suppressed because it is too large
Load Diff
57
src/common/error.cpp
Normal file
57
src/common/error.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstddef>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
std::string NativeErrorToString(int e) {
|
||||
#ifdef _WIN32
|
||||
LPSTR err_str;
|
||||
|
||||
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
|
||||
if (!res) {
|
||||
return "(FormatMessageA failed to format error)";
|
||||
}
|
||||
std::string ret(err_str);
|
||||
LocalFree(err_str);
|
||||
return ret;
|
||||
#else
|
||||
char err_str[255];
|
||||
#if (defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))) || \
|
||||
defined(ANDROID)
|
||||
// Thread safe (GNU-specific)
|
||||
const char* str = strerror_r(e, err_str, sizeof(err_str));
|
||||
return std::string(str);
|
||||
#else
|
||||
// Thread safe (XSI-compliant)
|
||||
int second_err = strerror_r(e, err_str, sizeof(err_str));
|
||||
if (second_err != 0) {
|
||||
return "(strerror_r failed to format error)";
|
||||
}
|
||||
return std::string(err_str);
|
||||
#endif // GLIBC etc.
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
std::string GetLastErrorMsg() {
|
||||
#ifdef _WIN32
|
||||
return NativeErrorToString(GetLastError());
|
||||
#else
|
||||
return NativeErrorToString(errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Common
|
21
src/common/error.h
Normal file
21
src/common/error.h
Normal file
@ -0,0 +1,21 @@
|
||||
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Common {
|
||||
|
||||
// Generic function to get last error message.
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
// Defined in error.cpp.
|
||||
[[nodiscard]] std::string GetLastErrorMsg();
|
||||
|
||||
// Like GetLastErrorMsg(), but passing an explicit error code.
|
||||
// Defined in error.cpp.
|
||||
[[nodiscard]] std::string NativeErrorToString(int e);
|
||||
|
||||
} // namespace Common
|
@ -348,6 +348,9 @@ public:
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return IsGood();
|
||||
}
|
||||
[[nodiscard]] std::FILE* Handle() {
|
||||
return m_file;
|
||||
}
|
||||
|
||||
bool Seek(s64 off, int origin);
|
||||
[[nodiscard]] u64 Tell() const;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include "common/cityhash.h"
|
||||
@ -37,10 +38,17 @@ static inline u64 ComputeStructHash64(const T& data) noexcept {
|
||||
* Combines the seed parameter with the provided hash, producing a new unique hash
|
||||
* Implementation from: http://boost.sourceforge.net/doc/html/boost/hash_combine.html
|
||||
*/
|
||||
inline u64 HashCombine(std::size_t& seed, const u64 hash) {
|
||||
inline u64 HashCombine(std::size_t seed, const u64 hash) {
|
||||
return seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct IdentityHash {
|
||||
T operator()(const T& value) const {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
|
||||
template <typename T>
|
||||
struct HashableStruct {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user