Compare commits

..

4 Commits

Author SHA1 Message Date
94a46c4b82 citra_qt: Hide refresh rate dialog on global configure 2023-04-06 22:54:49 +03:00
ce115869c9 citra_qt: Add option to adjust screen refresh rate 2023-03-30 00:05:29 +03:00
b5d6f645bd Prepare frontend for multiple graphics APIs (#6347)
* externals: Update dynarmic

* settings: Introduce GraphicsAPI enum

* For now it's OpenGL only but will be expanded upon later

* citra_qt: Introduce backend agnostic context management

* Mostly a direct port from yuzu

* core: Simplify context acquire

* settings: Add option to create debug contexts

* renderer_opengl: Abstract initialization to Driver

* This commit also updates glad and adds some useful extensions which we will use in part 2

* Rasterizer construction is moved to the specific renderer instead of RendererBase.
  Software rendering has been disable to achieve this but will be brought back in the next commit.

* video_core: Remove Init/Shutdown methods from renderer

* The constructor and destructor can do the same job

* In addition move opengl function loading to Qt since SDL already does this. Also remove ErrorVideoCore which is never reached

* citra_qt: Decouple software renderer from opengl part 1

* citra: Decouple software renderer from opengl part 2

* android: Decouple software renderer from opengl part 3

* swrasterizer: Decouple software renderer from opengl part 4

* This commit simply enforces the renderer naming conventions in the software renderer

* video_core: Move RendererBase to VideoCore

* video_core: De-globalize screenshot state

* video_core: Pass system to the renderers

* video_core: Commonize shader uniform data

* video_core: Abstract backend agnostic rasterizer operations

* bootmanager: Remove references to OpenGL for macOS

OpenGL macOS headers definitions clash heavily with each other

* citra_qt: Proper title for api settings

* video_core: Reduce boost usage

* bootmanager: Fix hide mouse option

Remove event handlers from RenderWidget for events that are
already handled by the parent GRenderWindow.
Also enable mouse tracking on the RenderWidget.

* android: Remove software from graphics api list

* code: Address review comments

* citra: Port per-game settings read

* Having to update the default value for all backends is a pain so lets centralize it

* android: Rename to OpenGLES

---------

Co-authored-by: MerryMage <MerryMage@users.noreply.github.com>
Co-authored-by: Vitor Kiguchi <vitor-kiguchi@hotmail.com>
2023-03-27 14:29:17 +03:00
9ef42040af GameDatabase.java: Fix file exists check on SAF (#6374)
Doesn't really do much other than reduce log spam
2023-03-26 21:24:44 +03:00
295 changed files with 6508 additions and 53045 deletions

View File

@ -5,7 +5,6 @@ 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/
@ -19,9 +18,3 @@ 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}

View File

@ -12,37 +12,20 @@ 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"
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 $BUNDLE_EXECUTABLE_PATH -d "../Frameworks"
macpack "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt" -d "../Frameworks"
# move qt frameworks into app bundle for deployment
macdeployqt $BUNDLE_PATH -executable=$BUNDLE_EXECUTABLE_PATH
macdeployqt "${REV_NAME}/citra-qt.app" -executable="${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt"
# 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
macpack "${REV_NAME}/citra" -d "libs"
# workaround for libc++
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
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"
# Make the launching script executable
chmod +x $BUNDLE_EXECUTABLE_PATH
chmod +x ${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt
# Verify loader instructions
find "$REV_NAME" -type f -exec otool -L {} \;

View File

@ -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,14 +162,6 @@ 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
@ -205,9 +197,6 @@ 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
View File

@ -43,6 +43,9 @@
[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
@ -50,26 +53,11 @@
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
[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
path = externals/cryptopp
url = https://github.com/weidai11/cryptopp.git

View File

@ -9,7 +9,6 @@ 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)

View File

@ -1,17 +1,3 @@
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;

View File

@ -1237,20 +1237,6 @@ 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;

View File

@ -89,19 +89,6 @@ 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)
@ -129,9 +116,6 @@ 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)
@ -190,8 +174,8 @@ if (ENABLE_WEB_SERVICE)
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
endif()
# libspng
add_subdirectory(libspng)
# lodepng
add_subdirectory(lodepng)
# (xperia64): Only use libyuv on Android b/c of build issues on Windows and mandatory JPEG
if(ANDROID)
@ -199,12 +183,3 @@ 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)

View File

@ -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=3.3,gles2=3.2" --generator=c
python -m glad --profile core --out-path glad/ --api "gl=4.6,gles2=3.2" --generator=c
```

View File

@ -1,6 +1,6 @@
/*
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Tue Feb 21 16:13:52 2023.
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Sun Mar 12 10:25:27 2023.
Language/Generator: C/C++
Specification: gl
@ -8,20 +8,19 @@
Profile: core
Extensions:
GL_ARB_buffer_storage,
GL_ARB_direct_state_access,
GL_ARB_texture_compression_bptc,
GL_ARB_clear_texture,
GL_ARB_get_texture_sub_image,
GL_EXT_buffer_storage,
GL_EXT_clip_cull_distance,
GL_EXT_texture_compression_s3tc
GL_EXT_clip_cull_distance
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_direct_state_access,GL_ARB_texture_compression_bptc,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_texture_compression_s3tc"
--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"
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_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
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
*/
@ -3782,14 +3781,6 @@ 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
@ -3812,17 +3803,13 @@ GLAPI PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox;
#define GL_ARB_buffer_storage 1
GLAPI int GLAD_GL_ARB_buffer_storage;
#endif
#ifndef GL_ARB_direct_state_access
#define GL_ARB_direct_state_access 1
GLAPI int GLAD_GL_ARB_direct_state_access;
#ifndef GL_ARB_clear_texture
#define GL_ARB_clear_texture 1
GLAPI int GLAD_GL_ARB_clear_texture;
#endif
#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;
#ifndef GL_ARB_get_texture_sub_image
#define GL_ARB_get_texture_sub_image 1
GLAPI int GLAD_GL_ARB_get_texture_sub_image;
#endif
#ifndef GL_EXT_buffer_storage
#define GL_EXT_buffer_storage 1
@ -3835,10 +3822,6 @@ 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
}

View File

@ -1,6 +1,6 @@
/*
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Tue Feb 21 16:13:52 2023.
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Sun Mar 12 10:25:27 2023.
Language/Generator: C/C++
Specification: gl
@ -8,20 +8,19 @@
Profile: core
Extensions:
GL_ARB_buffer_storage,
GL_ARB_direct_state_access,
GL_ARB_texture_compression_bptc,
GL_ARB_clear_texture,
GL_ARB_get_texture_sub_image,
GL_EXT_buffer_storage,
GL_EXT_clip_cull_distance,
GL_EXT_texture_compression_s3tc
GL_EXT_clip_cull_distance
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_direct_state_access,GL_ARB_texture_compression_bptc,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_texture_compression_s3tc"
--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"
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_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
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
*/
#include <stdio.h>
@ -985,11 +984,10 @@ PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
int GLAD_GL_ARB_buffer_storage = 0;
int GLAD_GL_ARB_direct_state_access = 0;
int GLAD_GL_ARB_texture_compression_bptc = 0;
int GLAD_GL_ARB_clear_texture = 0;
int GLAD_GL_ARB_get_texture_sub_image = 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;
@ -1755,112 +1753,21 @@ 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_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 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 int find_extensionsGL(void) {
if (!get_exts()) return 0;
GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage");
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");
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");
free_exts();
return 1;
}
@ -1954,7 +1861,8 @@ int gladLoadGLLoader(GLADloadproc load) {
if (!find_extensionsGL()) return 0;
load_GL_ARB_buffer_storage(load);
load_GL_ARB_direct_state_access(load);
load_GL_ARB_clear_texture(load);
load_GL_ARB_get_texture_sub_image(load);
return GLVersion.major != 0 || GLVersion.minor != 0;
}
@ -2336,7 +2244,6 @@ 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 externals/glm deleted from cc98465e35

1
externals/glslang vendored

Submodule externals/glslang deleted from c0cf8ad876

View File

@ -1,14 +0,0 @@
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

File diff suppressed because it is too large Load Diff

View File

@ -1,537 +0,0 @@
/* 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 Normal file
View File

@ -0,0 +1,7 @@
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 Submodule

View File

@ -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 externals/sirit deleted from f0b6bbe55b

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
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)

View File

@ -122,7 +122,6 @@ else()
if (MINGW)
add_definitions(-DMINGW_HAS_SECURE_API)
add_compile_options("-Wa,-mbig-obj")
if (COMPILE_WITH_DWARF)
add_compile_options("-gdwarf")
endif()

View File

@ -18,6 +18,15 @@ 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
@ -91,10 +100,6 @@ android {
path "../../../CMakeLists.txt"
}
}
lint {
abortOnError false
}
namespace 'org.citra.citra_emu'
defaultConfig {
externalNativeBuild {

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.citra.citra_emu">
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false"/>
@ -38,8 +39,7 @@
android:supportsRtl="true"
android:isGame="true"
android:banner="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true"
android:debuggable="true">
android:requestLegacyExternalStorage="true">
<activity
android:name="org.citra.citra_emu.ui.main.MainActivity"

View File

@ -496,9 +496,6 @@ 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;

View File

@ -356,8 +356,6 @@ 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);
@ -374,9 +372,7 @@ 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, 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 SingleChoiceSetting(SettingsFile.KEY_GRAPHICS_API, Settings.SECTION_RENDERER, R.string.graphics_api, 0, R.array.graphicsApiNames, R.array.graphicsApiValues, 0, graphicsApi));
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));
@ -415,14 +411,12 @@ 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));

View File

@ -45,10 +45,7 @@ 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";

View File

@ -125,9 +125,8 @@ public final class GameDatabase extends SQLiteOpenHelper {
while (fileCursor.moveToNext()) {
String gamePath = fileCursor.getString(GAME_COLUMN_PATH);
File game = new File(gamePath);
if (!game.exists()) {
if (!FileUtil.Exists(mContext, gamePath)) {
Log.error("[GameDatabase] Game file no longer exists. Removing from the library: " +
gamePath);
database.delete(TABLE_NAME_GAMES,

View File

@ -19,16 +19,14 @@ 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
@ -38,6 +36,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 log mediandk yuv)
target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics lodepng log mediandk yuv)
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android)

View File

@ -82,6 +82,30 @@ 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) {
@ -112,45 +136,32 @@ void Config::ReadValues() {
InputCommon::CemuhookUDP::DEFAULT_PORT));
// Core
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));
ReadSetting("Core", Settings::values.use_cpu_jit);
ReadSetting("Core", Settings::values.cpu_clock_percentage);
// Premium
Settings::values.texture_filter_name =
sdl2_config->GetString("Premium", "texture_filter_name", "none");
ReadSetting("Premium", Settings::values.texture_filter_name);
// Renderer
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.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", true);
Settings::values.shaders_accurate_mul =
sdl2_config->GetBoolean("Renderer", "shaders_accurate_mul", false);
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);
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);
// 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)) {
Settings::values.frame_limit =
static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100));
ReadSetting("Renderer", Settings::values.frame_limit);
} else {
Settings::values.frame_limit = 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));
ReadSetting("Renderer", Settings::values.render_3d);
ReadSetting("Renderer", Settings::values.factor_3d);
std::string default_shader = "none (builtin)";
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Anaglyph)
default_shader = "dubois (builtin)";
@ -158,70 +169,49 @@ void Config::ReadValues() {
default_shader = "horizontal (builtin)";
Settings::values.pp_shader_name =
sdl2_config->GetString("Renderer", "pp_shader_name", default_shader);
Settings::values.filter_mode = sdl2_config->GetBoolean("Renderer", "filter_mode", true);
ReadSetting("Renderer", Settings::values.filter_mode);
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));
ReadSetting("Renderer", Settings::values.bg_red);
ReadSetting("Renderer", Settings::values.bg_green);
ReadSetting("Renderer", Settings::values.bg_blue);
// Layout
Settings::values.layout_option = static_cast<Settings::LayoutOption>(sdl2_config->GetInteger(
"Layout", "layout_option", static_cast<int>(Settings::LayoutOption::MobileLandscape)));
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));
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);
// Utility
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);
ReadSetting("Utility", Settings::values.dump_textures);
ReadSetting("Utility", Settings::values.custom_textures);
ReadSetting("Utility", Settings::values.preload_textures);
// Audio
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));
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);
// Data Storage
Settings::values.use_virtual_sd =
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
ReadSetting("Data Storage", Settings::values.use_virtual_sd);
// System
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));
ReadSetting("System", Settings::values.is_new_3ds);
ReadSetting("System", Settings::values.region_value);
ReadSetting("System", Settings::values.init_clock);
{
std::tm t;
t.tm_sec = 1;
@ -242,10 +232,8 @@ void Config::ReadValues() {
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch())
.count();
}
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);
ReadSetting("System", Settings::values.plugin_loader_enabled);
ReadSetting("System", Settings::values.allow_plugin_loader);
// Camera
using namespace Service::CAM;
@ -269,14 +257,14 @@ void Config::ReadValues() {
sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0);
// Miscellaneous
Settings::values.log_filter = sdl2_config->GetString("Miscellaneous", "log_filter", "*:Info");
ReadSetting("Miscellaneous", Settings::values.log_filter);
// Debugging
Settings::values.record_frame_times =
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
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));
ReadSetting("Debugging", Settings::values.renderer_debug);
ReadSetting("Debugging", Settings::values.use_gdbstub);
ReadSetting("Debugging", Settings::values.gdbstub_port);
for (const auto& service_module : Service::service_module_map) {
bool use_lle = sdl2_config->GetBoolean("Debugging", "LLE\\" + service_module.name, false);

View File

@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include "common/settings.h"
class INIReader;
@ -23,4 +24,14 @@ 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);
};

View File

@ -98,26 +98,10 @@ use_cpu_jit =
cpu_clock_percentage =
[Renderer]
# Whether to render using OpenGL or Vulkan
# 1: OpenGL, 2 (default): Vulkan
# Whether to render using OpenGL
# 1: OpenGLES (default)
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 =
@ -130,10 +114,6 @@ 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 =
@ -337,9 +317,15 @@ 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]

View File

@ -6,7 +6,10 @@
#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"
@ -17,6 +20,52 @@
#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());
@ -30,10 +79,6 @@ static void UpdateLandscapeScreenLayout() {
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
render_window = surface;
window_info.type = Frontend::WindowSystemType::Android;
window_info.render_surface = surface;
StopPresenting();
}
@ -53,7 +98,6 @@ 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) {
@ -63,7 +107,7 @@ void EmuWindow_Android::OnFramebufferSizeChanged() {
}
}
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) : host_window{surface} {
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
if (!surface) {
@ -71,10 +115,108 @@ EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) : host_window{surfa
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() {
@ -82,6 +224,34 @@ 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;

View File

@ -1,17 +1,42 @@
// Copyright 2022 Citra Emulator Project
// 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 "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);
@ -22,34 +47,31 @@ public:
void OnTouchMoved(int x, int y);
void PollEvents() override;
void MakeCurrent() override;
void DoneCurrent() override;
virtual void TryPresenting() = 0;
void TryPresenting();
void StopPresenting();
virtual void StopPresenting() = 0;
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
protected:
private:
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 {

View File

@ -1,205 +0,0 @@
// 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);
}
}

View File

@ -1,36 +0,0 @@
// 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{};
};

View File

@ -1,65 +0,0 @@
// 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);
}
}

View File

@ -1,23 +0,0 @@
// 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;
};

View File

@ -0,0 +1,44 @@
// 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;
}

View File

@ -0,0 +1,14 @@
// 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;
};

View File

@ -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_gl.h"
#include "jni/emu_window/emu_window_vk.h"
#include "jni/emu_window/emu_window.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,16 +149,14 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
return Core::System::ResultStatus::ErrorLoader;
}
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
const auto graphics_api = Settings::values.graphics_api.GetValue();
switch (graphics_api) {
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);
case Settings::GraphicsAPI::OpenGL:
window = std::make_unique<EmuWindow_Android>(s_surf);
break;
default:
UNREACHABLE_MSG("Unknown graphics API {}", graphics_api);
LOG_CRITICAL(Frontend, "Unknown graphics API {}, using OpenGL", graphics_api);
window = std::make_unique<EmuWindow_Android>(s_surf);
}
Core::System& system{Core::System::GetInstance()};
@ -187,6 +185,9 @@ 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>());
@ -270,9 +271,6 @@ 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");
}

View File

@ -58,8 +58,6 @@
<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>

View File

@ -62,8 +62,6 @@
<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>

View File

@ -46,8 +46,6 @@
<!-- 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>

View File

@ -58,8 +58,6 @@
<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>

View File

@ -58,8 +58,6 @@
<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>

View File

@ -40,8 +40,6 @@
<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>

View File

@ -58,8 +58,6 @@
<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>

View File

@ -58,8 +58,6 @@
<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>

View File

@ -58,8 +58,6 @@
<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>

View File

@ -58,8 +58,6 @@
<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>

View File

@ -173,12 +173,10 @@
</integer-array>
<string-array name="graphicsApiNames">
<item>OpenGL</item>
<item>Vulkan</item>
<item>OpenGLES</item>
</string-array>
<integer-array name="graphicsApiValues">
<item>1</item>
<item>2</item>
</integer-array>
</resources>

View File

@ -72,21 +72,15 @@
<!-- 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>

View File

@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.0'
classpath 'com.android.tools.build:gradle:7.2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@ -8,6 +8,12 @@ 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
)
@ -15,7 +21,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)
target_link_libraries(citra PRIVATE inih glad lodepng)
if (MSVC)
target_link_libraries(citra PRIVATE getopt)
endif()

View File

@ -7,25 +7,34 @@
#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"
@ -350,13 +359,26 @@ 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 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 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 scope = emu_window->Acquire();
@ -390,9 +412,6 @@ 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:

View File

@ -5,6 +5,7 @@
#include <iomanip>
#include <memory>
#include <sstream>
#include <type_traits>
#include <unordered_map>
#include <SDL.h>
#include <inih/cpp/INIReader.h>
@ -71,6 +72,30 @@ 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
@ -104,105 +129,71 @@ void Config::ReadValues() {
InputCommon::CemuhookUDP::DEFAULT_PORT));
// Core
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);
ReadSetting("Core", Settings::values.use_cpu_jit);
ReadSetting("Core", Settings::values.cpu_clock_percentage);
// Renderer
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);
ReadSetting("Renderer", Settings::values.graphics_api);
ReadSetting("Renderer", Settings::values.use_gles);
ReadSetting("Renderer", Settings::values.use_hw_shader);
#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.
Settings::values.separable_shader =
sdl2_config->GetBoolean("Renderer", "separable_shader", false);
ReadSetting("Renderer", Settings::values.separable_shader);
#endif
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.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.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.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.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));
ReadSetting("Renderer", Settings::values.bg_red);
ReadSetting("Renderer", Settings::values.bg_green);
ReadSetting("Renderer", Settings::values.bg_blue);
// Layout
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));
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);
// Utility
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);
ReadSetting("Utility", Settings::values.dump_textures);
ReadSetting("Utility", Settings::values.custom_textures);
ReadSetting("Utility", Settings::values.preload_textures);
// Audio
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));
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);
// Data 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);
ReadSetting("Data Storage", Settings::values.use_virtual_sd);
ReadSetting("Data Storage", Settings::values.use_custom_storage);
if (Settings::values.use_custom_storage) {
FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir,
@ -212,11 +203,9 @@ void Config::ReadValues() {
}
// System
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));
ReadSetting("System", Settings::values.is_new_3ds);
ReadSetting("System", Settings::values.region_value);
ReadSetting("System", Settings::values.init_clock);
{
std::tm t;
t.tm_sec = 1;
@ -237,6 +226,8 @@ 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";
@ -312,14 +303,14 @@ void Config::ReadValues() {
sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0);
// Miscellaneous
Settings::values.log_filter = sdl2_config->GetString("Miscellaneous", "log_filter", "*:Info");
ReadSetting("Miscellaneous", Settings::values.log_filter);
// Debugging
Settings::values.record_frame_times =
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
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));
ReadSetting("Debugging", Settings::values.renderer_debug);
ReadSetting("Debugging", Settings::values.use_gdbstub);
ReadSetting("Debugging", Settings::values.gdbstub_port);
for (const auto& service_module : Service::service_module_map) {
bool use_lle = sdl2_config->GetBoolean("Debugging", "LLE\\" + service_module.name, false);

View File

@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include "common/settings.h"
class INIReader;
@ -21,4 +22,14 @@ 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);
};

View File

@ -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,9 +328,15 @@ 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]

View File

@ -7,40 +7,14 @@
#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));
@ -135,80 +109,9 @@ void EmuWindow_SDL2::Fullscreen() {
SDL_MaximizeWindow(render_window);
}
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(bool is_secondary) : EmuWindow(is_secondary) {}
EmuWindow_SDL2::~EmuWindow_SDL2() {
core_context.reset();
SDL_GL_DeleteContext(window_context);
SDL_Quit();
}
@ -224,28 +127,6 @@ 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;
@ -314,14 +195,6 @@ 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);
}

View File

@ -10,56 +10,27 @@
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 fullscreen, bool is_secondary);
explicit EmuWindow_SDL2(bool is_secondary);
~EmuWindow_SDL2();
/// Initializes SDL2
static void InitializeSDL2();
void Present();
/// Presents the most recent frame from the video backend
virtual 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();
/// 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:
protected:
/// Called by PollEvents when a key is pressed or released.
void OnKeyEvent(int key, u8 state);
@ -105,17 +76,6 @@ private:
/// 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;
};

View File

@ -0,0 +1,152 @@
// 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);
}

View File

@ -0,0 +1,35 @@
// 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;
};

View File

@ -0,0 +1,127 @@
// 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;
}

View File

@ -0,0 +1,32 @@
// 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;
};

View File

@ -0,0 +1,29 @@
// 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;
}

View File

@ -0,0 +1,14 @@
// 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;
};

View File

@ -167,6 +167,8 @@ 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
@ -264,7 +266,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 vma vulkan-headers nihstro-headers Qt5::Widgets Qt5::Multimedia Qt5::Concurrent)
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia Qt5::Concurrent)
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (NOT WIN32)
@ -327,6 +329,10 @@ 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()

View File

@ -2,28 +2,36 @@
// 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 <QOffscreenSurface>
#include <QOpenGLContext>
#include <QOpenGLExtraFunctions>
#include <QPainter>
#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>
@ -120,13 +128,14 @@ void EmuThread::run() {
#endif
}
#ifdef HAS_OPENGL
class OpenGLSharedContext : public Frontend::GraphicsContext {
public:
/// Create the original context that should be shared from
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
explicit OpenGLSharedContext() {
QSurfaceFormat format;
format.setVersion(4, 4);
format.setVersion(4, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
if (Settings::values.renderer_debug) {
@ -142,10 +151,15 @@ 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 = nullptr) {
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface) {
// disable vsync for any shared contexts
auto format = share_context->format();
@ -158,14 +172,7 @@ public:
LOG_ERROR(Frontend, "Unable to create shared openGL context");
}
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;
}
surface = main_surface;
}
~OpenGLSharedContext() {
@ -203,14 +210,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), render_window(parent) {
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
RenderWidget(GRenderWindow* parent) : QWidget(parent) {
setMouseTracking(true);
}
virtual ~RenderWidget() = default;
@ -222,72 +229,22 @@ 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<OpenGLSharedContext>&& context_) {
void SetContext(std::unique_ptr<Frontend::GraphicsContext>&& context_) {
context = std::move(context_);
}
@ -299,28 +256,92 @@ public:
return;
}
context->MakeCurrent();
const auto f = context->GetShareContext()->extraFunctions();
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
VideoCore::g_renderer->TryPresent(100, is_secondary);
context->SwapBuffers();
f->glFinish();
glFinish();
}
QPaintEngine* paintEngine() const override {
return nullptr;
}
private:
std::unique_ptr<OpenGLSharedContext> context{};
std::unique_ptr<Frontend::GraphicsContext> context{};
bool is_secondary;
};
#endif
class VulkanRenderWidget : public RenderWidget {
public:
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
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;
}
};
static Frontend::WindowSystemType GetWindowSystemType() {
// Determine WSI type based on Qt platform.
QString platform_name = QGuiApplication::platformName();
const QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("windows"))
return Frontend::WindowSystemType::Windows;
else if (platform_name == QStringLiteral("xcb"))
@ -362,6 +383,8 @@ 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) {
@ -460,8 +483,9 @@ 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) {
@ -474,8 +498,9 @@ 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);
@ -485,8 +510,9 @@ 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();
@ -558,23 +584,7 @@ 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.
@ -583,16 +593,13 @@ bool GRenderWindow::InitRenderTarget() {
first_frame = false;
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
const auto graphics_api = Settings::values.graphics_api.GetValue();
switch (graphics_api) {
case Settings::GraphicsAPI::OpenGL:
case Settings::GraphicsAPI::OpenGLES:
if (!InitializeOpenGL()) {
return false;
}
case Settings::GraphicsAPI::Software:
InitializeSoftware();
break;
case Settings::GraphicsAPI::Vulkan:
if (!InitializeVulkan()) {
case Settings::GraphicsAPI::OpenGL:
if (!InitializeOpenGL() || !LoadOpenGL()) {
return false;
}
break;
@ -649,24 +656,54 @@ 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();
auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle());
main_context = context;
child->SetContext(
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
if (!main_context) {
main_context = std::make_shared<OpenGLSharedContext>();
}
auto child_context = CreateSharedContext();
child->SetContext(std::move(child_context));
return true;
#else
QMessageBox::warning(this, tr("OpenGL not available!"),
tr("Citra has not been compiled with OpenGL support."));
return false;
#endif
}
bool GRenderWindow::InitializeVulkan() {
auto child = new VulkanRenderWidget(this);
child_widget = child;
child_widget->windowHandle()->create();
void GRenderWindow::InitializeSoftware() {
child_widget = new SoftwareRenderWidget(this);
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;
}
@ -682,3 +719,17 @@ 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>();
}

View File

@ -187,22 +187,21 @@ private:
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
bool InitializeOpenGL();
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
std::shared_ptr<Frontend::GraphicsContext> main_context;
/// Temporary storage of the screenshot taken
QImage screenshot_image;
QByteArray geometry;
void InitializeSoftware();
bool LoadOpenGL();
QWidget* child_widget = nullptr;
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;
/// Temporary storage of the screenshot taken
QImage screenshot_image;
QByteArray geometry;
bool first_frame = false;
bool has_focus = false;

View File

@ -447,6 +447,7 @@ 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);
@ -483,7 +484,6 @@ 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,11 +627,7 @@ 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.
@ -968,6 +964,7 @@ 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);
@ -999,7 +996,6 @@ 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) {
@ -1112,10 +1108,6 @@ 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.

View File

@ -83,6 +83,21 @@ 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);

View File

@ -3,7 +3,6 @@
// 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"
@ -13,9 +12,7 @@
#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
@ -38,51 +35,28 @@ 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)));
});
ui->clock_speed_label->setVisible(Settings::IsConfiguringGlobal());
ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
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);
SetupPerGameUI();
}
@ -98,7 +72,6 @@ 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()) {
@ -108,14 +81,26 @@ 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() {
@ -129,28 +114,39 @@ 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->groupBox->setVisible(false);
ui->groupBox_2->setVisible(false);
ui->gdb_group->setVisible(false);
ui->logging_group->setVisible(false);
ui->toggle_cpu_jit->setVisible(false);
ui->refresh_rate_widget->setVisible(true);
}
void ConfigureDebug::RetranslateUI() {

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>523</width>
<height>491</height>
<height>495</height>
</rect>
</property>
<property name="windowTitle">
@ -17,7 +17,7 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<widget class="QGroupBox" name="gdb_group">
<property name="title">
<string>GDB</string>
</property>
@ -66,7 +66,7 @@
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<widget class="QGroupBox" name="logging_group">
<property name="title">
<string>Logging</string>
</property>
@ -107,16 +107,23 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<widget class="QGroupBox" name="cpu_group">
<property name="title">
<string>CPU</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<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">
<widget class="QWidget" name="clock_speed_widget" native="true">
<layout class="QHBoxLayout" name="clock_speed_layout">
<property name="spacing">
<number>11</number>
<number>7</number>
</property>
<property name="leftMargin">
<number>0</number>
@ -202,18 +209,72 @@
</property>
</widget>
</item>
<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>
<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>
</widget>
</item>
</layout>

View File

@ -22,7 +22,9 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
ui->layout_group->setEnabled(!Settings::values.custom_layout);
ui->resolution_factor_combobox->setEnabled(Settings::values.use_hw_renderer.GetValue());
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);
connect(ui->render_3d_combobox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,

View File

@ -11,35 +11,25 @@
#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);
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->toggle_vsync_new->setEnabled(!Core::System::GetInstance().IsPoweredOn());
// Set the index to -1 to ensure the below lambda is called with setCurrentIndex
ui->graphics_api_combo->setCurrentIndex(-1);
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());
});
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;
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());
ui->hw_renderer_group->setEnabled(!is_software);
ui->toggle_disk_shader_cache->setEnabled(!is_software &&
ui->toggle_hw_shader->isChecked());
});
connect(ui->toggle_hw_shader, &QCheckBox::toggled, this, [this] {
const bool checked = ui->toggle_hw_shader->isChecked();
@ -69,9 +59,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
ui->toggle_separable_shader->setVisible(false);
#endif
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureGraphics::SetPhysicalDeviceComboVisibility);
SetupPerGameUI();
SetConfiguration();
}
@ -79,29 +67,20 @@ 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());
@ -109,8 +88,8 @@ void ConfigureGraphics::SetConfiguration() {
}
void ConfigureGraphics::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_hw_renderer,
ui->toggle_hw_renderer, use_hw_renderer);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api,
ui->graphics_api_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_hw_shader, ui->toggle_hw_shader,
use_hw_shader);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.separable_shader,
@ -121,14 +100,6 @@ 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();
@ -142,17 +113,13 @@ void ConfigureGraphics::RetranslateUI() {
void ConfigureGraphics::SetupPerGameUI() {
// Block the global settings if a game is currently running that overrides them
if (Settings::IsConfiguringGlobal()) {
ui->toggle_hw_renderer->setEnabled(Settings::values.use_hw_renderer.UsingGlobal());
ui->graphics_api_group->setEnabled(Settings::values.graphics_api.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;
}
@ -162,12 +129,6 @@ 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,
@ -179,48 +140,4 @@ 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);
}

View File

@ -28,21 +28,14 @@ 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;
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>454</width>
<height>579</height>
<width>400</width>
<height>443</height>
</rect>
</property>
<property name="minimumSize">
@ -29,9 +29,6 @@
<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>
@ -53,61 +50,21 @@
</item>
<item>
<widget class="QComboBox" name="graphics_api_combo">
<item>
<property name="text">
<string>Software</string>
</property>
</item>
<item>
<property name="text">
<string>OpenGL</string>
</property>
</item>
<item>
<property name="text">
<string>OpenGLES</string>
</property>
</item>
<item>
<property name="text">
<string>Vulkan</string>
</property>
</item>
</widget>
</item>
</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>
@ -117,21 +74,11 @@
<string>Renderer</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="toggle_hw_renderer">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use OpenGL to accelerate rendering.&lt;/p&gt;&lt;p&gt;Disable to debug graphics-related problem.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>16</number>
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
@ -209,13 +156,6 @@
<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">
@ -255,8 +195,6 @@
</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>

View File

@ -16,6 +16,7 @@
#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"

View File

@ -90,4 +90,4 @@ bool CheckAuthorizationForMicrophone() {
return authorized_microphone;
}
} // namespace AppleAuthorization
} // AppleAuthorization

View File

@ -12,12 +12,22 @@
#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"
@ -50,6 +60,7 @@
#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"
@ -59,7 +70,9 @@
#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"
@ -74,6 +87,7 @@
#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"
@ -84,20 +98,9 @@
#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
@ -351,22 +354,6 @@ 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());
@ -590,8 +577,6 @@ 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;
@ -1095,24 +1080,6 @@ 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!"),
@ -1170,9 +1137,6 @@ 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
@ -1258,6 +1222,10 @@ 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();
@ -1807,9 +1775,6 @@ 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() {
@ -2032,7 +1997,6 @@ void GMainWindow::OnConfigure() {
setMouseTracking(false);
}
UpdateSecondaryWindowVisibility();
UpdateAPIIndicator(false);
UpdateBootHomeMenuState();
} else {
Settings::values.input_profiles = old_input_profiles;
@ -2355,26 +2319,6 @@ 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();
}
@ -2841,6 +2785,9 @@ 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,

View File

@ -7,7 +7,6 @@
#include <array>
#include <memory>
#include <QMainWindow>
#include <QPushButton>
#include <QTimer>
#include <QTranslator>
#include "citra_qt/compatibility_list.h"
@ -253,7 +252,6 @@ private:
void HideMouseCursor();
void ShowMouseCursor();
void OpenPerGameConfiguration(u64 title_id, const QString& file_name);
void UpdateAPIIndicator(bool override);
std::unique_ptr<Ui::MainWindow> ui;
@ -269,7 +267,6 @@ 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;

View File

@ -0,0 +1,38 @@
// 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;
}

View File

@ -0,0 +1,14 @@
// 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;
};

View File

@ -63,13 +63,11 @@ 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
@ -78,14 +76,9 @@ 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
@ -107,14 +100,12 @@ 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
@ -133,11 +124,9 @@ 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
@ -151,7 +140,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 spng::spng)
target_link_libraries(common PRIVATE libzstd_static)
set_target_properties(common PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
if ("x86_64" IN_LIST ARCHITECTURE)

View File

@ -1,39 +0,0 @@
// 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

View File

@ -1,66 +0,0 @@
// 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

View File

@ -52,11 +52,6 @@ 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
@ -120,44 +115,6 @@ 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
@ -219,7 +176,6 @@ 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
@ -256,43 +212,6 @@ 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

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +0,0 @@
// 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

View File

@ -1,21 +0,0 @@
// 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

View File

@ -348,9 +348,6 @@ 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;

View File

@ -4,7 +4,6 @@
#pragma once
#include <concepts>
#include <cstddef>
#include <cstring>
#include "common/cityhash.h"
@ -38,17 +37,10 @@ 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