Merge branch 'master' into online
This commit is contained in:
commit
ffb9a443cd
@ -7,7 +7,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Default clang-format points to default 3.5 version one
|
# Default clang-format points to default 3.5 version one
|
||||||
CLANG_FORMAT=clang-format-12
|
CLANG_FORMAT=clang-format-15
|
||||||
$CLANG_FORMAT --version
|
$CLANG_FORMAT --version
|
||||||
|
|
||||||
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
|
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
|
||||||
|
15
.ci/ios.sh
Executable file
15
.ci/ios.sh
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash -ex
|
||||||
|
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake .. -GNinja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_SYSTEM_NAME=iOS \
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DENABLE_QT_TRANSLATION=ON \
|
||||||
|
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
|
||||||
|
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON
|
||||||
|
ninja
|
||||||
|
|
||||||
|
ccache -s
|
@ -1,4 +1,4 @@
|
|||||||
name: citra-ci
|
name: citra-build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@ -8,19 +8,6 @@ on:
|
|||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
clang-format:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: citraemu/build-environments:linux-fresh
|
|
||||||
options: -u 1001
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Build
|
|
||||||
env:
|
|
||||||
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
|
|
||||||
run: ./.ci/clang-format.sh
|
|
||||||
source:
|
source:
|
||||||
if: ${{ !github.head_ref }}
|
if: ${{ !github.head_ref }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -130,11 +117,11 @@ jobs:
|
|||||||
ARTIFACTS: ${{ env.OS }}-x86_64 ${{ env.OS }}-arm64
|
ARTIFACTS: ${{ env.OS }}-x86_64 ${{ env.OS }}-arm64
|
||||||
- name: Pack
|
- name: Pack
|
||||||
run: ./.ci/pack.sh
|
run: ./.ci/pack.sh
|
||||||
# - name: Upload
|
- name: Upload
|
||||||
# uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
# with:
|
with:
|
||||||
# name: ${{ env.OS }}-${{ env.TARGET }}
|
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||||
# path: artifacts/
|
path: artifacts/
|
||||||
windows:
|
windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
@ -240,19 +227,30 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: ${{ env.OS }}-${{ env.TARGET }}
|
name: ${{ env.OS }}-${{ env.TARGET }}
|
||||||
path: src/android/app/artifacts/
|
path: src/android/app/artifacts/
|
||||||
transifex:
|
ios:
|
||||||
runs-on: ubuntu-latest
|
runs-on: macos-latest
|
||||||
container: citraemu/build-environments:linux-fresh
|
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||||
if: ${{ github.repository == 'citra-emu/citra' && !github.head_ref }}
|
env:
|
||||||
|
CCACHE_CPP2: yes
|
||||||
|
CCACHE_SLOPPINESS: time_macros
|
||||||
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||||
|
OS: ios
|
||||||
|
TARGET: arm64
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
fetch-depth: 0
|
- name: Set up cache
|
||||||
- name: Update Translation
|
uses: actions/cache@v3
|
||||||
run: ./.ci/transifex.sh
|
with:
|
||||||
env:
|
path: ${{ env.CCACHE_DIR }}
|
||||||
TX_TOKEN: ${{ secrets.TRANSIFEX_API_TOKEN }}
|
key: ${{ runner.os }}-ios-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-ios-
|
||||||
|
- name: Install tools
|
||||||
|
run: brew install ccache glslang ninja
|
||||||
|
- name: Build
|
||||||
|
run: ./.ci/ios.sh
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [windows, linux, macos-universal, android, source]
|
needs: [windows, linux, macos-universal, android, source]
|
22
.github/workflows/format.yml
vendored
Normal file
22
.github/workflows/format.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
name: citra-format
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "*" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: citraemu/build-environments:linux-fresh
|
||||||
|
options: -u 1001
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Build
|
||||||
|
env:
|
||||||
|
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
|
||||||
|
run: ./.ci/clang-format.sh
|
20
.github/workflows/transifex.yml
vendored
Normal file
20
.github/workflows/transifex.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: citra-transifex
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
transifex:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: citraemu/build-environments:linux-fresh
|
||||||
|
if: ${{ github.repository == 'citra-emu/citra' }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Update Translation
|
||||||
|
run: ./.ci/transifex.sh
|
||||||
|
env:
|
||||||
|
TX_TOKEN: ${{ secrets.TRANSIFEX_API_TOKEN }}
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,10 +9,12 @@ src/common/scm_rev.cpp
|
|||||||
|
|
||||||
# Project/editor files
|
# Project/editor files
|
||||||
*.swp
|
*.swp
|
||||||
|
*.kdev4
|
||||||
.idea/
|
.idea/
|
||||||
.vs/
|
.vs/
|
||||||
.vscode/
|
.vscode/
|
||||||
.cache/
|
.cache/
|
||||||
|
.kdev4/
|
||||||
cmake-build-debug/
|
cmake-build-debug/
|
||||||
cmake-build-release/
|
cmake-build-release/
|
||||||
CMakeLists.txt.user*
|
CMakeLists.txt.user*
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -82,3 +82,6 @@
|
|||||||
[submodule "library-headers"]
|
[submodule "library-headers"]
|
||||||
path = externals/library-headers/library-headers
|
path = externals/library-headers/library-headers
|
||||||
url = https://github.com/citra-emu/ext-library-headers.git
|
url = https://github.com/citra-emu/ext-library-headers.git
|
||||||
|
[submodule "libadrenotools"]
|
||||||
|
path = externals/libadrenotools
|
||||||
|
url = https://github.com/bylaws/libadrenotools
|
||||||
|
13
.lgtm.yml
13
.lgtm.yml
@ -1,13 +0,0 @@
|
|||||||
path_classifiers:
|
|
||||||
library: "externals"
|
|
||||||
extraction:
|
|
||||||
cpp:
|
|
||||||
prepare:
|
|
||||||
packages:
|
|
||||||
- "libsdl2-dev"
|
|
||||||
- "qtmultimedia5-dev"
|
|
||||||
- "clang-format-6.0"
|
|
||||||
- "libtbb-dev"
|
|
||||||
- "libjack-jackd2-dev"
|
|
||||||
- "doxygen"
|
|
||||||
- "graphviz"
|
|
@ -40,8 +40,17 @@ endif()
|
|||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL Debug)
|
if (CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||||
set(IS_DEBUG_BUILD ON)
|
set(IS_DEBUG_BUILD ON)
|
||||||
|
set(IS_RELEASE_BUILD OFF)
|
||||||
else()
|
else()
|
||||||
set(IS_DEBUG_BUILD OFF)
|
set(IS_DEBUG_BUILD OFF)
|
||||||
|
set(IS_RELEASE_BUILD ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# LTO takes too much memory and time using MSVC.
|
||||||
|
if (NOT MSVC AND IS_RELEASE_BUILD)
|
||||||
|
set(DEFAULT_ENABLE_LTO ON)
|
||||||
|
else()
|
||||||
|
set(DEFAULT_ENABLE_LTO OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(ENABLE_SDL2 "Enable using SDL2" ON)
|
option(ENABLE_SDL2 "Enable using SDL2" ON)
|
||||||
@ -73,7 +82,7 @@ CMAKE_DEPENDENT_OPTION(CITRA_ENABLE_BUNDLE_TARGET "Enable the distribution bundl
|
|||||||
|
|
||||||
# Compile options
|
# Compile options
|
||||||
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ${IS_DEBUG_BUILD} "MINGW" OFF)
|
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ${IS_DEBUG_BUILD} "MINGW" OFF)
|
||||||
option(ENABLE_LTO "Enable link time optimization" OFF)
|
option(ENABLE_LTO "Enable link time optimization" ${DEFAULT_ENABLE_LTO})
|
||||||
option(CITRA_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
option(CITRA_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
||||||
option(CITRA_WARNINGS_AS_ERRORS "Enable warnings as errors" ON)
|
option(CITRA_WARNINGS_AS_ERRORS "Enable warnings as errors" ON)
|
||||||
|
|
||||||
@ -84,6 +93,8 @@ option(USE_SYSTEM_SDL2 "Use the system SDL2 lib (instead of the bundled one)" OF
|
|||||||
option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)" OFF)
|
option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)" OFF)
|
||||||
option(USE_SYSTEM_OPENSSL "Use the system OpenSSL libs (instead of the bundled LibreSSL)" OFF)
|
option(USE_SYSTEM_OPENSSL "Use the system OpenSSL libs (instead of the bundled LibreSSL)" OFF)
|
||||||
option(USE_SYSTEM_LIBUSB "Use the system libusb (instead of the bundled libusb)" OFF)
|
option(USE_SYSTEM_LIBUSB "Use the system libusb (instead of the bundled libusb)" OFF)
|
||||||
|
option(USE_SYSTEM_CPP_JWT "Use the system cpp-jwt (instead of the bundled one)" OFF)
|
||||||
|
option(USE_SYSTEM_SOUNDTOUCH "Use the system SoundTouch (instead of the bundled one)" OFF)
|
||||||
|
|
||||||
if (CITRA_USE_PRECOMPILED_HEADERS)
|
if (CITRA_USE_PRECOMPILED_HEADERS)
|
||||||
message(STATUS "Using Precompiled Headers.")
|
message(STATUS "Using Precompiled Headers.")
|
||||||
@ -271,7 +282,7 @@ endif()
|
|||||||
# against all the src files. This should be used before making a pull request.
|
# against all the src files. This should be used before making a pull request.
|
||||||
# =======================================================================
|
# =======================================================================
|
||||||
|
|
||||||
set(CLANG_FORMAT_POSTFIX "-12")
|
set(CLANG_FORMAT_POSTFIX "-15")
|
||||||
find_program(CLANG_FORMAT
|
find_program(CLANG_FORMAT
|
||||||
NAMES clang-format${CLANG_FORMAT_POSTFIX}
|
NAMES clang-format${CLANG_FORMAT_POSTFIX}
|
||||||
clang-format
|
clang-format
|
||||||
@ -387,6 +398,14 @@ if (ENABLE_LIBUSB AND USE_SYSTEM_LIBUSB)
|
|||||||
find_package(LibUSB)
|
find_package(LibUSB)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (USE_SYSTEM_SOUNDTOUCH)
|
||||||
|
include(FindPkgConfig)
|
||||||
|
find_package(SoundTouch REQUIRED)
|
||||||
|
add_library(SoundTouch INTERFACE)
|
||||||
|
target_link_libraries(SoundTouch INTERFACE "${SOUNDTOUCH_LIBRARIES}")
|
||||||
|
target_include_directories(SoundTouch INTERFACE "${SOUNDTOUCH_INCLUDE_DIRS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(dist/installer)
|
add_subdirectory(dist/installer)
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# To use this as a script, make sure you pass in the variables BASE_DIR, SRC_DIR, BUILD_DIR, and TARGET_FILE
|
# To use this as a script, make sure you pass in the variables BASE_DIR, SRC_DIR, BUILD_DIR, and TARGET_FILE
|
||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(PLATFORM "windows")
|
set(PLATFORM "windows")
|
||||||
@ -12,7 +13,8 @@ endif()
|
|||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${BASE_DIR}/CMakeModules")
|
list(APPEND CMAKE_MODULE_PATH "${BASE_DIR}/CMakeModules")
|
||||||
include(DownloadExternals)
|
include(DownloadExternals)
|
||||||
download_qt(tools_ifw QT_PREFIX)
|
download_qt(tools_ifw)
|
||||||
|
get_external_prefix(qt QT_PREFIX)
|
||||||
|
|
||||||
file(GLOB_RECURSE INSTALLER_BASE "${QT_PREFIX}/**/installerbase*")
|
file(GLOB_RECURSE INSTALLER_BASE "${QT_PREFIX}/**/installerbase*")
|
||||||
file(GLOB_RECURSE BINARY_CREATOR "${QT_PREFIX}/**/binarycreator*")
|
file(GLOB_RECURSE BINARY_CREATOR "${QT_PREFIX}/**/binarycreator*")
|
||||||
|
@ -1,31 +1,38 @@
|
|||||||
|
|
||||||
# This function downloads Qt using aqt.
|
# This function downloads Qt using aqt. The path of the downloaded content will be added to the CMAKE_PREFIX_PATH.
|
||||||
# Params:
|
# Params:
|
||||||
# target: Qt dependency to install. Specify a version number to download Qt, or "tools_(name)" for a specific build tool.
|
# target: Qt dependency to install. Specify a version number to download Qt, or "tools_(name)" for a specific build tool.
|
||||||
# prefix_var: Name of a variable which will be set with the path to the extracted contents.
|
|
||||||
function(download_qt target)
|
function(download_qt target)
|
||||||
|
if (target MATCHES "tools_.*")
|
||||||
|
set(DOWNLOAD_QT_TOOL ON)
|
||||||
|
else()
|
||||||
|
set(DOWNLOAD_QT_TOOL OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Determine installation parameters for OS, architecture, and compiler
|
# Determine installation parameters for OS, architecture, and compiler
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(host "windows")
|
set(host "windows")
|
||||||
set(type "desktop")
|
set(type "desktop")
|
||||||
if (MINGW)
|
if (NOT DOWNLOAD_QT_TOOL)
|
||||||
set(arch "win64_mingw")
|
if (MINGW)
|
||||||
set(arch_path "mingw_64")
|
set(arch "win64_mingw")
|
||||||
elseif (MSVC)
|
set(arch_path "mingw_64")
|
||||||
if ("arm64" IN_LIST ARCHITECTURE)
|
elseif (MSVC)
|
||||||
set(arch_path "msvc2019_arm64")
|
if ("arm64" IN_LIST ARCHITECTURE)
|
||||||
elseif ("x86_64" IN_LIST ARCHITECTURE)
|
set(arch_path "msvc2019_arm64")
|
||||||
set(arch_path "msvc2019_64")
|
elseif ("x86_64" IN_LIST ARCHITECTURE)
|
||||||
|
set(arch_path "msvc2019_64")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.")
|
||||||
|
endif()
|
||||||
|
set(arch "win64_${arch_path}")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.")
|
message(FATAL_ERROR "Unsupported bundled Qt toolchain. Enable USE_SYSTEM_QT and provide your own.")
|
||||||
endif()
|
endif()
|
||||||
set(arch "win64_${arch_path}")
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "Unsupported bundled Qt toolchain. Enable USE_SYSTEM_QT and provide your own.")
|
|
||||||
endif()
|
endif()
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
set(host "mac")
|
set(host "mac")
|
||||||
if (IOS)
|
if (IOS AND NOT DOWNLOAD_QT_TOOL)
|
||||||
set(type "ios")
|
set(type "ios")
|
||||||
set(arch "ios")
|
set(arch "ios")
|
||||||
set(arch_path "ios")
|
set(arch_path "ios")
|
||||||
@ -45,8 +52,8 @@ function(download_qt target)
|
|||||||
get_external_prefix(qt base_path)
|
get_external_prefix(qt base_path)
|
||||||
file(MAKE_DIRECTORY "${base_path}")
|
file(MAKE_DIRECTORY "${base_path}")
|
||||||
|
|
||||||
if (target MATCHES "tools_.*")
|
if (DOWNLOAD_QT_TOOL)
|
||||||
set(prefix "${base_path}")
|
set(prefix "${base_path}/Tools")
|
||||||
set(install_args install-tool --outputdir ${base_path} ${host} desktop ${target})
|
set(install_args install-tool --outputdir ${base_path} ${host} desktop ${target})
|
||||||
else()
|
else()
|
||||||
set(prefix "${base_path}/${target}/${arch_path}")
|
set(prefix "${base_path}/${target}/${arch_path}")
|
||||||
@ -63,7 +70,7 @@ function(download_qt target)
|
|||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(aqt_path "${base_path}/aqt.exe")
|
set(aqt_path "${base_path}/aqt.exe")
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
https://github.com/miurahr/aqtinstall/releases/download/v3.1.4/aqt.exe
|
https://github.com/miurahr/aqtinstall/releases/download/v3.1.7/aqt.exe
|
||||||
${aqt_path} SHOW_PROGRESS)
|
${aqt_path} SHOW_PROGRESS)
|
||||||
execute_process(COMMAND ${aqt_path} ${install_args}
|
execute_process(COMMAND ${aqt_path} ${install_args}
|
||||||
WORKING_DIRECTORY ${base_path})
|
WORKING_DIRECTORY ${base_path})
|
||||||
|
@ -4,24 +4,24 @@ include(GenerateBuildInfo)
|
|||||||
# The variable SRC_DIR must be passed into the script (since it uses the current build directory for all values of CMAKE_*_DIR)
|
# The variable SRC_DIR must be passed into the script (since it uses the current build directory for all values of CMAKE_*_DIR)
|
||||||
set(VIDEO_CORE "${SRC_DIR}/src/video_core")
|
set(VIDEO_CORE "${SRC_DIR}/src/video_core")
|
||||||
set(HASH_FILES
|
set(HASH_FILES
|
||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.cpp"
|
|
||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.h"
|
|
||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp"
|
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp"
|
||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h"
|
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h"
|
||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_gen.cpp"
|
|
||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_gen.h"
|
|
||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.cpp"
|
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.cpp"
|
||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.h"
|
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.h"
|
||||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_gen.cpp"
|
|
||||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_gen.h"
|
|
||||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_gen_spv.cpp"
|
|
||||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_gen_spv.h"
|
|
||||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_util.cpp"
|
"${VIDEO_CORE}/renderer_vulkan/vk_shader_util.cpp"
|
||||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_util.h"
|
"${VIDEO_CORE}/renderer_vulkan/vk_shader_util.h"
|
||||||
|
"${VIDEO_CORE}/shader/generator/glsl_shader_decompiler.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/generator/glsl_shader_decompiler.h"
|
||||||
|
"${VIDEO_CORE}/shader/generator/glsl_shader_gen.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/generator/glsl_shader_gen.h"
|
||||||
|
"${VIDEO_CORE}/shader/generator/shader_gen.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/generator/shader_gen.h"
|
||||||
|
"${VIDEO_CORE}/shader/generator/shader_uniforms.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/generator/shader_uniforms.h"
|
||||||
|
"${VIDEO_CORE}/shader/generator/spv_shader_gen.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/generator/spv_shader_gen.h"
|
||||||
"${VIDEO_CORE}/shader/shader.cpp"
|
"${VIDEO_CORE}/shader/shader.cpp"
|
||||||
"${VIDEO_CORE}/shader/shader.h"
|
"${VIDEO_CORE}/shader/shader.h"
|
||||||
"${VIDEO_CORE}/shader/shader_uniforms.cpp"
|
|
||||||
"${VIDEO_CORE}/shader/shader_uniforms.h"
|
|
||||||
"${VIDEO_CORE}/pica.cpp"
|
"${VIDEO_CORE}/pica.cpp"
|
||||||
"${VIDEO_CORE}/pica.h"
|
"${VIDEO_CORE}/pica.h"
|
||||||
"${VIDEO_CORE}/regs_framebuffer.h"
|
"${VIDEO_CORE}/regs_framebuffer.h"
|
||||||
|
2
dist/installer/CMakeLists.txt
vendored
2
dist/installer/CMakeLists.txt
vendored
@ -13,6 +13,8 @@ set(BUILD_DIR "${CMAKE_BINARY_DIR}/installer")
|
|||||||
set(DIST_DIR "${BUILD_DIR}/dist")
|
set(DIST_DIR "${BUILD_DIR}/dist")
|
||||||
set(TARGET_FILE "${DIST_DIR}/citra-setup-${PLATFORM}")
|
set(TARGET_FILE "${DIST_DIR}/citra-setup-${PLATFORM}")
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${BUILD_DIR}" "${DIST_DIR}")
|
||||||
|
|
||||||
# Adds a custom target that will run the BuildInstaller.cmake file
|
# Adds a custom target that will run the BuildInstaller.cmake file
|
||||||
# CMake can't just run a cmake function as a custom command, so this is a way around it.
|
# CMake can't just run a cmake function as a custom command, so this is a way around it.
|
||||||
# Calls the cmake command and runs a cmake file in "scripting" mode passing in variables with -D
|
# Calls the cmake command and runs a cmake file in "scripting" mode passing in variables with -D
|
||||||
|
3314
dist/languages/da_DK.ts
vendored
3314
dist/languages/da_DK.ts
vendored
File diff suppressed because it is too large
Load Diff
3255
dist/languages/de.ts
vendored
3255
dist/languages/de.ts
vendored
File diff suppressed because it is too large
Load Diff
3332
dist/languages/el.ts
vendored
3332
dist/languages/el.ts
vendored
File diff suppressed because it is too large
Load Diff
3380
dist/languages/es_ES.ts
vendored
3380
dist/languages/es_ES.ts
vendored
File diff suppressed because it is too large
Load Diff
3315
dist/languages/fi.ts
vendored
3315
dist/languages/fi.ts
vendored
File diff suppressed because it is too large
Load Diff
3463
dist/languages/fr.ts
vendored
3463
dist/languages/fr.ts
vendored
File diff suppressed because it is too large
Load Diff
3238
dist/languages/id.ts
vendored
3238
dist/languages/id.ts
vendored
File diff suppressed because it is too large
Load Diff
3259
dist/languages/it.ts
vendored
3259
dist/languages/it.ts
vendored
File diff suppressed because it is too large
Load Diff
3309
dist/languages/ja_JP.ts
vendored
3309
dist/languages/ja_JP.ts
vendored
File diff suppressed because it is too large
Load Diff
3449
dist/languages/ko_KR.ts
vendored
3449
dist/languages/ko_KR.ts
vendored
File diff suppressed because it is too large
Load Diff
3308
dist/languages/lt_LT.ts
vendored
3308
dist/languages/lt_LT.ts
vendored
File diff suppressed because it is too large
Load Diff
3254
dist/languages/nb.ts
vendored
3254
dist/languages/nb.ts
vendored
File diff suppressed because it is too large
Load Diff
4126
dist/languages/nl.ts
vendored
4126
dist/languages/nl.ts
vendored
File diff suppressed because it is too large
Load Diff
3315
dist/languages/pl_PL.ts
vendored
3315
dist/languages/pl_PL.ts
vendored
File diff suppressed because it is too large
Load Diff
3324
dist/languages/pt_BR.ts
vendored
3324
dist/languages/pt_BR.ts
vendored
File diff suppressed because it is too large
Load Diff
3336
dist/languages/ro_RO.ts
vendored
3336
dist/languages/ro_RO.ts
vendored
File diff suppressed because it is too large
Load Diff
3256
dist/languages/ru_RU.ts
vendored
3256
dist/languages/ru_RU.ts
vendored
File diff suppressed because it is too large
Load Diff
3265
dist/languages/tr_TR.ts
vendored
3265
dist/languages/tr_TR.ts
vendored
File diff suppressed because it is too large
Load Diff
3478
dist/languages/vi_VN.ts
vendored
3478
dist/languages/vi_VN.ts
vendored
File diff suppressed because it is too large
Load Diff
3237
dist/languages/zh_CN.ts
vendored
3237
dist/languages/zh_CN.ts
vendored
File diff suppressed because it is too large
Load Diff
3542
dist/languages/zh_TW.ts
vendored
3542
dist/languages/zh_TW.ts
vendored
File diff suppressed because it is too large
Load Diff
5
dist/qt_themes/default/style.qss
vendored
5
dist/qt_themes/default/style.qss
vendored
@ -26,3 +26,8 @@ QPushButton#3DOptionStatusBarButton {
|
|||||||
QPushButton#3DOptionStatusBarButton:hover {
|
QPushButton#3DOptionStatusBarButton:hover {
|
||||||
border: 1px solid #76797C;
|
border: 1px solid #76797C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton#button_reset_defaults {
|
||||||
|
min-width: 57px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
@ -1072,6 +1072,10 @@ QPushButton:focus {
|
|||||||
border: 1px solid #1464A0;
|
border: 1px solid #1464A0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton#button_reset_defaults {
|
||||||
|
padding: 3px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
/* QToolButton ------------------------------------------------------------
|
/* QToolButton ------------------------------------------------------------
|
||||||
|
|
||||||
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton
|
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton
|
||||||
|
31
externals/CMakeLists.txt
vendored
31
externals/CMakeLists.txt
vendored
@ -122,10 +122,13 @@ add_subdirectory(open_source_archives)
|
|||||||
add_subdirectory(library-headers EXCLUDE_FROM_ALL)
|
add_subdirectory(library-headers EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
# SoundTouch
|
# SoundTouch
|
||||||
set(INTEGER_SAMPLES ON CACHE BOOL "")
|
if(NOT USE_SYSTEM_SOUNDTOUCH)
|
||||||
set(SOUNDSTRETCH OFF CACHE BOOL "")
|
set(INTEGER_SAMPLES ON CACHE BOOL "")
|
||||||
set(SOUNDTOUCH_DLL OFF CACHE BOOL "")
|
set(SOUNDSTRETCH OFF CACHE BOOL "")
|
||||||
add_subdirectory(soundtouch EXCLUDE_FROM_ALL)
|
set(SOUNDTOUCH_DLL OFF CACHE BOOL "")
|
||||||
|
add_subdirectory(soundtouch EXCLUDE_FROM_ALL)
|
||||||
|
target_compile_definitions(SoundTouch PUBLIC SOUNDTOUCH_INTEGER_SAMPLES)
|
||||||
|
endif()
|
||||||
|
|
||||||
# sirit
|
# sirit
|
||||||
add_subdirectory(sirit EXCLUDE_FROM_ALL)
|
add_subdirectory(sirit EXCLUDE_FROM_ALL)
|
||||||
@ -207,9 +210,15 @@ endif()
|
|||||||
|
|
||||||
# cpp-jwt
|
# cpp-jwt
|
||||||
if (ENABLE_WEB_SERVICE)
|
if (ENABLE_WEB_SERVICE)
|
||||||
add_library(cpp-jwt INTERFACE)
|
if (USE_SYSTEM_CPP_JWT)
|
||||||
target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
|
find_package(cpp-jwt REQUIRED)
|
||||||
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
|
add_library(cpp-jwt INTERFACE)
|
||||||
|
target_link_libraries(cpp-jwt INTERFACE cpp-jwt::cpp-jwt)
|
||||||
|
else()
|
||||||
|
add_library(cpp-jwt INTERFACE)
|
||||||
|
target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
|
||||||
|
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# lodepng
|
# lodepng
|
||||||
@ -242,3 +251,11 @@ target_include_directories(vma SYSTEM INTERFACE ./vma/include)
|
|||||||
# vulkan-headers
|
# vulkan-headers
|
||||||
add_library(vulkan-headers INTERFACE)
|
add_library(vulkan-headers INTERFACE)
|
||||||
target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include)
|
target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include)
|
||||||
|
if (APPLE)
|
||||||
|
target_include_directories(vulkan-headers SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# adrenotools
|
||||||
|
if (ANDROID)
|
||||||
|
add_subdirectory(libadrenotools)
|
||||||
|
endif()
|
||||||
|
27
externals/cmake-modules/FindSoundTouch.cmake
vendored
Normal file
27
externals/cmake-modules/FindSoundTouch.cmake
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
if(NOT SOUNDTOUCH_FOUND)
|
||||||
|
pkg_check_modules(SOUNDTOUCH_TMP soundtouch)
|
||||||
|
|
||||||
|
find_path(SOUNDTOUCH_INCLUDE_DIRS NAMES SoundTouch.h
|
||||||
|
PATHS
|
||||||
|
${SOUNDTOUCH_TMP_INCLUDE_DIRS}
|
||||||
|
/usr/include/soundtouch
|
||||||
|
/usr/include
|
||||||
|
/usr/local/include/soundtouch
|
||||||
|
/usr/local/include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(SOUNDTOUCH_LIBRARIES NAMES SoundTouch
|
||||||
|
PATHS
|
||||||
|
${SOUNDTOUCH_TMP_LIBRARY_DIRS}
|
||||||
|
/usr/lib
|
||||||
|
/usr/local/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
if(SOUNDTOUCH_INCLUDE_DIRS AND SOUNDTOUCH_LIBRARIES)
|
||||||
|
set(SOUNDTOUCH_FOUND TRUE CACHE INTERNAL "SoundTouch found")
|
||||||
|
message(STATUS "Found SoundTouch: ${SOUNDTOUCH_INCLUDE_DIRS}, ${SOUNDTOUCH_LIBRARIES}")
|
||||||
|
else()
|
||||||
|
set(SOUNDTOUCH_FOUND FALSE CACHE INTERNAL "SoundTouch found")
|
||||||
|
message(STATUS "SoundTouch not found.")
|
||||||
|
endif()
|
||||||
|
endif()
|
2
externals/fmt
vendored
2
externals/fmt
vendored
@ -1 +1 @@
|
|||||||
Subproject commit a33701196adfad74917046096bf5a2aa0ab0bb50
|
Subproject commit 2dd4fa8742fdac36468f8d8ea3e06e78215551f8
|
41
externals/glad/include/glad/glad.h
vendored
41
externals/glad/include/glad/glad.h
vendored
@ -1,28 +1,32 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Sat Apr 1 20:34:42 2023.
|
OpenGL, OpenGL ES loader generated by glad 0.1.34 on Sat Aug 26 18:38:43 2023.
|
||||||
|
|
||||||
Language/Generator: C/C++
|
Language/Generator: C/C++
|
||||||
Specification: gl
|
Specification: gl
|
||||||
APIs: gl=4.3, gles2=3.2
|
APIs: gl=4.3, gles2=3.2
|
||||||
Profile: core
|
Profile: core
|
||||||
Extensions:
|
Extensions:
|
||||||
|
GL_AMD_blend_minmax_factor,
|
||||||
GL_ARB_buffer_storage,
|
GL_ARB_buffer_storage,
|
||||||
GL_ARB_clear_texture,
|
GL_ARB_clear_texture,
|
||||||
GL_ARB_get_texture_sub_image,
|
GL_ARB_get_texture_sub_image,
|
||||||
GL_ARB_texture_compression_bptc,
|
GL_ARB_texture_compression_bptc,
|
||||||
|
GL_ARM_shader_framebuffer_fetch,
|
||||||
GL_EXT_buffer_storage,
|
GL_EXT_buffer_storage,
|
||||||
GL_EXT_clip_cull_distance,
|
GL_EXT_clip_cull_distance,
|
||||||
GL_EXT_texture_compression_s3tc
|
GL_EXT_shader_framebuffer_fetch,
|
||||||
|
GL_EXT_texture_compression_s3tc,
|
||||||
|
GL_NV_blend_minmax_factor
|
||||||
Loader: True
|
Loader: True
|
||||||
Local files: False
|
Local files: False
|
||||||
Omit khrplatform: False
|
Omit khrplatform: False
|
||||||
Reproducible: False
|
Reproducible: False
|
||||||
|
|
||||||
Commandline:
|
Commandline:
|
||||||
--profile="core" --api="gl=4.3,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_clear_texture,GL_ARB_get_texture_sub_image,GL_ARB_texture_compression_bptc,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_texture_compression_s3tc"
|
--profile="core" --api="gl=4.3,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_AMD_blend_minmax_factor,GL_ARB_buffer_storage,GL_ARB_clear_texture,GL_ARB_get_texture_sub_image,GL_ARB_texture_compression_bptc,GL_ARM_shader_framebuffer_fetch,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_shader_framebuffer_fetch,GL_EXT_texture_compression_s3tc,GL_NV_blend_minmax_factor"
|
||||||
Online:
|
Online:
|
||||||
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.3&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_clear_texture&extensions=GL_ARB_get_texture_sub_image&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.3&api=gles2%3D3.2&extensions=GL_AMD_blend_minmax_factor&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_clear_texture&extensions=GL_ARB_get_texture_sub_image&extensions=GL_ARB_texture_compression_bptc&extensions=GL_ARM_shader_framebuffer_fetch&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_shader_framebuffer_fetch&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_NV_blend_minmax_factor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -3320,6 +3324,8 @@ typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC)(GLuint program, GLint location,
|
|||||||
GLAPI PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
|
GLAPI PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
|
||||||
#define glGetnUniformuiv glad_glGetnUniformuiv
|
#define glGetnUniformuiv glad_glGetnUniformuiv
|
||||||
#endif
|
#endif
|
||||||
|
#define GL_FACTOR_MIN_AMD 0x901C
|
||||||
|
#define GL_FACTOR_MAX_AMD 0x901D
|
||||||
#define GL_MAP_PERSISTENT_BIT 0x0040
|
#define GL_MAP_PERSISTENT_BIT 0x0040
|
||||||
#define GL_MAP_COHERENT_BIT 0x0080
|
#define GL_MAP_COHERENT_BIT 0x0080
|
||||||
#define GL_DYNAMIC_STORAGE_BIT 0x0100
|
#define GL_DYNAMIC_STORAGE_BIT 0x0100
|
||||||
@ -3332,10 +3338,13 @@ GLAPI PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
|
|||||||
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
|
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
|
||||||
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
|
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
|
||||||
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
|
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
|
||||||
|
#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52
|
||||||
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
|
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
|
||||||
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
||||||
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
|
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
|
||||||
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
||||||
|
#define GL_FETCH_PER_SAMPLE_ARM 0x8F65
|
||||||
|
#define GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM 0x8F66
|
||||||
#define GL_MAP_PERSISTENT_BIT_EXT 0x0040
|
#define GL_MAP_PERSISTENT_BIT_EXT 0x0040
|
||||||
#define GL_MAP_COHERENT_BIT_EXT 0x0080
|
#define GL_MAP_COHERENT_BIT_EXT 0x0080
|
||||||
#define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100
|
#define GL_DYNAMIC_STORAGE_BIT_EXT 0x0100
|
||||||
@ -3354,6 +3363,10 @@ GLAPI PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
|
|||||||
#define GL_CLIP_DISTANCE5_EXT 0x3005
|
#define GL_CLIP_DISTANCE5_EXT 0x3005
|
||||||
#define GL_CLIP_DISTANCE6_EXT 0x3006
|
#define GL_CLIP_DISTANCE6_EXT 0x3006
|
||||||
#define GL_CLIP_DISTANCE7_EXT 0x3007
|
#define GL_CLIP_DISTANCE7_EXT 0x3007
|
||||||
|
#ifndef GL_AMD_blend_minmax_factor
|
||||||
|
#define GL_AMD_blend_minmax_factor 1
|
||||||
|
GLAPI int GLAD_GL_AMD_blend_minmax_factor;
|
||||||
|
#endif
|
||||||
#ifndef GL_ARB_buffer_storage
|
#ifndef GL_ARB_buffer_storage
|
||||||
#define GL_ARB_buffer_storage 1
|
#define GL_ARB_buffer_storage 1
|
||||||
GLAPI int GLAD_GL_ARB_buffer_storage;
|
GLAPI int GLAD_GL_ARB_buffer_storage;
|
||||||
@ -3385,10 +3398,22 @@ GLAPI PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage;
|
|||||||
#define GL_ARB_texture_compression_bptc 1
|
#define GL_ARB_texture_compression_bptc 1
|
||||||
GLAPI int GLAD_GL_ARB_texture_compression_bptc;
|
GLAPI int GLAD_GL_ARB_texture_compression_bptc;
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef GL_EXT_shader_framebuffer_fetch
|
||||||
|
#define GL_EXT_shader_framebuffer_fetch 1
|
||||||
|
GLAPI int GLAD_GL_EXT_shader_framebuffer_fetch;
|
||||||
|
#endif
|
||||||
#ifndef GL_EXT_texture_compression_s3tc
|
#ifndef GL_EXT_texture_compression_s3tc
|
||||||
#define GL_EXT_texture_compression_s3tc 1
|
#define GL_EXT_texture_compression_s3tc 1
|
||||||
GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
|
GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef GL_NV_blend_minmax_factor
|
||||||
|
#define GL_NV_blend_minmax_factor 1
|
||||||
|
GLAPI int GLAD_GL_NV_blend_minmax_factor;
|
||||||
|
#endif
|
||||||
|
#ifndef GL_ARM_shader_framebuffer_fetch
|
||||||
|
#define GL_ARM_shader_framebuffer_fetch 1
|
||||||
|
GLAPI int GLAD_GL_ARM_shader_framebuffer_fetch;
|
||||||
|
#endif
|
||||||
#ifndef GL_EXT_buffer_storage
|
#ifndef GL_EXT_buffer_storage
|
||||||
#define GL_EXT_buffer_storage 1
|
#define GL_EXT_buffer_storage 1
|
||||||
GLAPI int GLAD_GL_EXT_buffer_storage;
|
GLAPI int GLAD_GL_EXT_buffer_storage;
|
||||||
@ -3400,10 +3425,18 @@ GLAPI PFNGLBUFFERSTORAGEEXTPROC glad_glBufferStorageEXT;
|
|||||||
#define GL_EXT_clip_cull_distance 1
|
#define GL_EXT_clip_cull_distance 1
|
||||||
GLAPI int GLAD_GL_EXT_clip_cull_distance;
|
GLAPI int GLAD_GL_EXT_clip_cull_distance;
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef GL_EXT_shader_framebuffer_fetch
|
||||||
|
#define GL_EXT_shader_framebuffer_fetch 1
|
||||||
|
GLAPI int GLAD_GL_EXT_shader_framebuffer_fetch;
|
||||||
|
#endif
|
||||||
#ifndef GL_EXT_texture_compression_s3tc
|
#ifndef GL_EXT_texture_compression_s3tc
|
||||||
#define GL_EXT_texture_compression_s3tc 1
|
#define GL_EXT_texture_compression_s3tc 1
|
||||||
GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
|
GLAPI int GLAD_GL_EXT_texture_compression_s3tc;
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef GL_NV_blend_minmax_factor
|
||||||
|
#define GL_NV_blend_minmax_factor 1
|
||||||
|
GLAPI int GLAD_GL_NV_blend_minmax_factor;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
22
externals/glad/src/glad.c
vendored
22
externals/glad/src/glad.c
vendored
@ -1,28 +1,32 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
OpenGL, OpenGL ES loader generated by glad 0.1.36 on Sat Apr 1 20:34:42 2023.
|
OpenGL, OpenGL ES loader generated by glad 0.1.34 on Sat Aug 26 18:38:43 2023.
|
||||||
|
|
||||||
Language/Generator: C/C++
|
Language/Generator: C/C++
|
||||||
Specification: gl
|
Specification: gl
|
||||||
APIs: gl=4.3, gles2=3.2
|
APIs: gl=4.3, gles2=3.2
|
||||||
Profile: core
|
Profile: core
|
||||||
Extensions:
|
Extensions:
|
||||||
|
GL_AMD_blend_minmax_factor,
|
||||||
GL_ARB_buffer_storage,
|
GL_ARB_buffer_storage,
|
||||||
GL_ARB_clear_texture,
|
GL_ARB_clear_texture,
|
||||||
GL_ARB_get_texture_sub_image,
|
GL_ARB_get_texture_sub_image,
|
||||||
GL_ARB_texture_compression_bptc,
|
GL_ARB_texture_compression_bptc,
|
||||||
|
GL_ARM_shader_framebuffer_fetch,
|
||||||
GL_EXT_buffer_storage,
|
GL_EXT_buffer_storage,
|
||||||
GL_EXT_clip_cull_distance,
|
GL_EXT_clip_cull_distance,
|
||||||
GL_EXT_texture_compression_s3tc
|
GL_EXT_shader_framebuffer_fetch,
|
||||||
|
GL_EXT_texture_compression_s3tc,
|
||||||
|
GL_NV_blend_minmax_factor
|
||||||
Loader: True
|
Loader: True
|
||||||
Local files: False
|
Local files: False
|
||||||
Omit khrplatform: False
|
Omit khrplatform: False
|
||||||
Reproducible: False
|
Reproducible: False
|
||||||
|
|
||||||
Commandline:
|
Commandline:
|
||||||
--profile="core" --api="gl=4.3,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_clear_texture,GL_ARB_get_texture_sub_image,GL_ARB_texture_compression_bptc,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_texture_compression_s3tc"
|
--profile="core" --api="gl=4.3,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_AMD_blend_minmax_factor,GL_ARB_buffer_storage,GL_ARB_clear_texture,GL_ARB_get_texture_sub_image,GL_ARB_texture_compression_bptc,GL_ARM_shader_framebuffer_fetch,GL_EXT_buffer_storage,GL_EXT_clip_cull_distance,GL_EXT_shader_framebuffer_fetch,GL_EXT_texture_compression_s3tc,GL_NV_blend_minmax_factor"
|
||||||
Online:
|
Online:
|
||||||
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D4.3&api=gles2%3D3.2&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_clear_texture&extensions=GL_ARB_get_texture_sub_image&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.3&api=gles2%3D3.2&extensions=GL_AMD_blend_minmax_factor&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_clear_texture&extensions=GL_ARB_get_texture_sub_image&extensions=GL_ARB_texture_compression_bptc&extensions=GL_ARM_shader_framebuffer_fetch&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_shader_framebuffer_fetch&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_NV_blend_minmax_factor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -853,13 +857,17 @@ PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL;
|
|||||||
PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
|
PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
|
||||||
PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
|
PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
|
||||||
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
|
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
|
||||||
|
int GLAD_GL_AMD_blend_minmax_factor = 0;
|
||||||
int GLAD_GL_ARB_buffer_storage = 0;
|
int GLAD_GL_ARB_buffer_storage = 0;
|
||||||
int GLAD_GL_ARB_clear_texture = 0;
|
int GLAD_GL_ARB_clear_texture = 0;
|
||||||
int GLAD_GL_ARB_get_texture_sub_image = 0;
|
int GLAD_GL_ARB_get_texture_sub_image = 0;
|
||||||
int GLAD_GL_ARB_texture_compression_bptc = 0;
|
int GLAD_GL_ARB_texture_compression_bptc = 0;
|
||||||
|
int GLAD_GL_ARM_shader_framebuffer_fetch = 0;
|
||||||
int GLAD_GL_EXT_buffer_storage = 0;
|
int GLAD_GL_EXT_buffer_storage = 0;
|
||||||
int GLAD_GL_EXT_clip_cull_distance = 0;
|
int GLAD_GL_EXT_clip_cull_distance = 0;
|
||||||
|
int GLAD_GL_EXT_shader_framebuffer_fetch = 0;
|
||||||
int GLAD_GL_EXT_texture_compression_s3tc = 0;
|
int GLAD_GL_EXT_texture_compression_s3tc = 0;
|
||||||
|
int GLAD_GL_NV_blend_minmax_factor = 0;
|
||||||
PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;
|
PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;
|
||||||
PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL;
|
PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL;
|
||||||
PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL;
|
PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL;
|
||||||
@ -1498,11 +1506,14 @@ static void load_GL_ARB_get_texture_sub_image(GLADloadproc load) {
|
|||||||
}
|
}
|
||||||
static int find_extensionsGL(void) {
|
static int find_extensionsGL(void) {
|
||||||
if (!get_exts()) return 0;
|
if (!get_exts()) return 0;
|
||||||
|
GLAD_GL_AMD_blend_minmax_factor = has_ext("GL_AMD_blend_minmax_factor");
|
||||||
GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage");
|
GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage");
|
||||||
GLAD_GL_ARB_clear_texture = has_ext("GL_ARB_clear_texture");
|
GLAD_GL_ARB_clear_texture = has_ext("GL_ARB_clear_texture");
|
||||||
GLAD_GL_ARB_get_texture_sub_image = has_ext("GL_ARB_get_texture_sub_image");
|
GLAD_GL_ARB_get_texture_sub_image = has_ext("GL_ARB_get_texture_sub_image");
|
||||||
GLAD_GL_ARB_texture_compression_bptc = has_ext("GL_ARB_texture_compression_bptc");
|
GLAD_GL_ARB_texture_compression_bptc = has_ext("GL_ARB_texture_compression_bptc");
|
||||||
|
GLAD_GL_EXT_shader_framebuffer_fetch = has_ext("GL_EXT_shader_framebuffer_fetch");
|
||||||
GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
|
GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
|
||||||
|
GLAD_GL_NV_blend_minmax_factor = has_ext("GL_NV_blend_minmax_factor");
|
||||||
free_exts();
|
free_exts();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1971,9 +1982,12 @@ static void load_GL_EXT_buffer_storage(GLADloadproc load) {
|
|||||||
}
|
}
|
||||||
static int find_extensionsGLES2(void) {
|
static int find_extensionsGLES2(void) {
|
||||||
if (!get_exts()) return 0;
|
if (!get_exts()) return 0;
|
||||||
|
GLAD_GL_ARM_shader_framebuffer_fetch = has_ext("GL_ARM_shader_framebuffer_fetch");
|
||||||
GLAD_GL_EXT_buffer_storage = has_ext("GL_EXT_buffer_storage");
|
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_clip_cull_distance = has_ext("GL_EXT_clip_cull_distance");
|
||||||
|
GLAD_GL_EXT_shader_framebuffer_fetch = has_ext("GL_EXT_shader_framebuffer_fetch");
|
||||||
GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
|
GLAD_GL_EXT_texture_compression_s3tc = has_ext("GL_EXT_texture_compression_s3tc");
|
||||||
|
GLAD_GL_NV_blend_minmax_factor = has_ext("GL_NV_blend_minmax_factor");
|
||||||
free_exts();
|
free_exts();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
1
externals/libadrenotools
vendored
Submodule
1
externals/libadrenotools
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit deec5f75ee1a8ccbe32c8780b1d17284fc87b0f1
|
1071
externals/moltenvk/mvk_config.h
vendored
Normal file
1071
externals/moltenvk/mvk_config.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
externals/vulkan-headers
vendored
2
externals/vulkan-headers
vendored
@ -1 +1 @@
|
|||||||
Subproject commit bae9700cd9425541a0f6029957f005e5ad3ef660
|
Subproject commit 85c2334e92e215cce34e8e0ed8b2dce4700f4a50
|
@ -5,6 +5,10 @@ include_directories(.)
|
|||||||
set_property(DIRECTORY APPEND PROPERTY
|
set_property(DIRECTORY APPEND PROPERTY
|
||||||
COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
|
COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
|
||||||
|
|
||||||
|
if (ENABLE_LTO)
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Set compilation flags
|
# Set compilation flags
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE)
|
set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE)
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.citra.citra_emu.activities.EmulationActivity"
|
android:name="org.citra.citra_emu.activities.EmulationActivity"
|
||||||
|
android:exported="true"
|
||||||
android:resizeableActivity="false"
|
android:resizeableActivity="false"
|
||||||
android:theme="@style/Theme.Citra.Main"
|
android:theme="@style/Theme.Citra.Main"
|
||||||
android:launchMode="singleTop"/>
|
android:launchMode="singleTop"/>
|
||||||
|
@ -359,6 +359,8 @@ public final class SettingsFragmentPresenter {
|
|||||||
|
|
||||||
SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER);
|
SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER);
|
||||||
Setting graphicsApi = rendererSection.getSetting(SettingsFile.KEY_GRAPHICS_API);
|
Setting graphicsApi = rendererSection.getSetting(SettingsFile.KEY_GRAPHICS_API);
|
||||||
|
Setting spirvShaderGen = rendererSection.getSetting(SettingsFile.KEY_SPIRV_SHADER_GEN);
|
||||||
|
Setting asyncShaders = rendererSection.getSetting(SettingsFile.KEY_ASYNC_SHADERS);
|
||||||
Setting resolutionFactor = rendererSection.getSetting(SettingsFile.KEY_RESOLUTION_FACTOR);
|
Setting resolutionFactor = rendererSection.getSetting(SettingsFile.KEY_RESOLUTION_FACTOR);
|
||||||
Setting filterMode = rendererSection.getSetting(SettingsFile.KEY_FILTER_MODE);
|
Setting filterMode = rendererSection.getSetting(SettingsFile.KEY_FILTER_MODE);
|
||||||
Setting shadersAccurateMul = rendererSection.getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
|
Setting shadersAccurateMul = rendererSection.getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
|
||||||
@ -377,6 +379,8 @@ public final class SettingsFragmentPresenter {
|
|||||||
|
|
||||||
sl.add(new HeaderSetting(null, null, R.string.renderer, 0));
|
sl.add(new HeaderSetting(null, null, R.string.renderer, 0));
|
||||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_GRAPHICS_API, Settings.SECTION_RENDERER, R.string.graphics_api, 0, R.array.graphicsApiNames, R.array.graphicsApiValues, 0, graphicsApi));
|
sl.add(new SingleChoiceSetting(SettingsFile.KEY_GRAPHICS_API, Settings.SECTION_RENDERER, R.string.graphics_api, 0, R.array.graphicsApiNames, R.array.graphicsApiValues, 0, 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, spirvShaderGen));
|
||||||
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_ASYNC_SHADERS, Settings.SECTION_RENDERER, R.string.async_shaders, R.string.async_shaders_description, false, asyncShaders));
|
||||||
sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor));
|
sl.add(new 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_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));
|
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));
|
||||||
@ -424,6 +428,6 @@ public final class SettingsFragmentPresenter {
|
|||||||
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_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_SHADER, Settings.SECTION_RENDERER, R.string.hw_shaders, R.string.hw_shaders_description, true, hardwareShader, 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_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));
|
sl.add(new CheckBoxSetting(SettingsFile.KEY_RENDERER_DEBUG, Settings.SECTION_DEBUG, R.string.renderer_debug, R.string.renderer_debug_description, false, rendererDebug));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@ public final class SettingsFile {
|
|||||||
public static final String KEY_PREMIUM = "premium";
|
public static final String KEY_PREMIUM = "premium";
|
||||||
|
|
||||||
public static final String KEY_GRAPHICS_API = "graphics_api";
|
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_ASYNC_SHADERS = "async_shader_compilation";
|
||||||
public static final String KEY_RENDERER_DEBUG = "renderer_debug";
|
public static final String KEY_RENDERER_DEBUG = "renderer_debug";
|
||||||
public static final String KEY_HW_SHADER = "use_hw_shader";
|
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_SHADERS_ACCURATE_MUL = "shaders_accurate_mul";
|
||||||
|
@ -19,6 +19,10 @@ add_library(citra-android SHARED
|
|||||||
default_ini.h
|
default_ini.h
|
||||||
emu_window/emu_window.cpp
|
emu_window/emu_window.cpp
|
||||||
emu_window/emu_window.h
|
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.cpp
|
||||||
game_settings.cpp
|
game_settings.cpp
|
||||||
game_settings.h
|
game_settings.h
|
||||||
@ -30,7 +34,7 @@ add_library(citra-android SHARED
|
|||||||
ndk_motion.h
|
ndk_motion.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(citra-android PRIVATE audio_core citra_common citra_core input_common network)
|
target_link_libraries(citra-android PRIVATE audio_core citra_common citra_core input_common network adrenotools)
|
||||||
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 log mediandk yuv)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android)
|
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android)
|
||||||
|
@ -42,9 +42,7 @@ struct CaptureSession final {
|
|||||||
|
|
||||||
#define MEMBER(type, name, func) \
|
#define MEMBER(type, name, func) \
|
||||||
struct type##Deleter { \
|
struct type##Deleter { \
|
||||||
void operator()(type* ptr) { \
|
void operator()(type* ptr) { type##_##func(ptr); } \
|
||||||
type##_##func(ptr); \
|
|
||||||
} \
|
|
||||||
}; \
|
}; \
|
||||||
std::unique_ptr<type, type##Deleter> name
|
std::unique_ptr<type, type##Deleter> name
|
||||||
|
|
||||||
|
@ -147,6 +147,9 @@ void Config::ReadValues() {
|
|||||||
Settings::values.shaders_accurate_mul =
|
Settings::values.shaders_accurate_mul =
|
||||||
sdl2_config->GetBoolean("Renderer", "shaders_accurate_mul", false);
|
sdl2_config->GetBoolean("Renderer", "shaders_accurate_mul", false);
|
||||||
ReadSetting("Renderer", Settings::values.graphics_api);
|
ReadSetting("Renderer", Settings::values.graphics_api);
|
||||||
|
ReadSetting("Renderer", Settings::values.async_presentation);
|
||||||
|
ReadSetting("Renderer", Settings::values.async_shader_compilation);
|
||||||
|
ReadSetting("Renderer", Settings::values.spirv_shader_gen);
|
||||||
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
||||||
ReadSetting("Renderer", Settings::values.use_shader_jit);
|
ReadSetting("Renderer", Settings::values.use_shader_jit);
|
||||||
ReadSetting("Renderer", Settings::values.resolution_factor);
|
ReadSetting("Renderer", Settings::values.resolution_factor);
|
||||||
|
@ -99,9 +99,17 @@ cpu_clock_percentage =
|
|||||||
|
|
||||||
[Renderer]
|
[Renderer]
|
||||||
# Whether to render using OpenGL
|
# Whether to render using OpenGL
|
||||||
# 1: OpenGLES (default)
|
# 1: OpenGL ES (default), 2: Vulkan
|
||||||
graphics_api =
|
graphics_api =
|
||||||
|
|
||||||
|
# Whether to compile shaders on multiple worker threads (Vulkan only)
|
||||||
|
# 0: Off, 1: On (default)
|
||||||
|
async_shader_compilation =
|
||||||
|
|
||||||
|
# Whether to emit PICA fragment shader using SPIRV or GLSL (Vulkan only)
|
||||||
|
# 0: GLSL, 1: SPIR-V (default)
|
||||||
|
spirv_shader_gen =
|
||||||
|
|
||||||
# Whether to use hardware shaders to emulate 3DS shaders
|
# Whether to use hardware shaders to emulate 3DS shaders
|
||||||
# 0: Software, 1 (default): Hardware
|
# 0: Software, 1 (default): Hardware
|
||||||
use_hw_shader =
|
use_hw_shader =
|
||||||
|
@ -6,10 +6,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <android/native_window_jni.h>
|
#include <android/native_window_jni.h>
|
||||||
#include <glad/glad.h>
|
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
@ -20,52 +17,6 @@
|
|||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/video_core.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() {
|
static bool IsPortraitMode() {
|
||||||
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(
|
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(
|
||||||
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
|
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
|
||||||
@ -79,7 +30,12 @@ static void UpdateLandscapeScreenLayout() {
|
|||||||
|
|
||||||
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||||
render_window = surface;
|
render_window = surface;
|
||||||
|
|
||||||
|
window_info.type = Frontend::WindowSystemType::Android;
|
||||||
|
window_info.render_surface = surface;
|
||||||
|
|
||||||
StopPresenting();
|
StopPresenting();
|
||||||
|
OnFramebufferSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuWindow_Android::OnTouchEvent(int x, int y, bool pressed) {
|
bool EmuWindow_Android::OnTouchEvent(int x, int y, bool pressed) {
|
||||||
@ -98,6 +54,7 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) {
|
|||||||
void EmuWindow_Android::OnFramebufferSizeChanged() {
|
void EmuWindow_Android::OnFramebufferSizeChanged() {
|
||||||
UpdateLandscapeScreenLayout();
|
UpdateLandscapeScreenLayout();
|
||||||
const bool is_portrait_mode{IsPortraitMode()};
|
const bool is_portrait_mode{IsPortraitMode()};
|
||||||
|
|
||||||
const int bigger{window_width > window_height ? window_width : window_height};
|
const int bigger{window_width > window_height ? window_width : window_height};
|
||||||
const int smaller{window_width < window_height ? window_width : window_height};
|
const int smaller{window_width < window_height ? window_width : window_height};
|
||||||
if (is_portrait_mode) {
|
if (is_portrait_mode) {
|
||||||
@ -107,7 +64,7 @@ void EmuWindow_Android::OnFramebufferSizeChanged() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
|
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) : host_window{surface} {
|
||||||
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
|
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
|
||||||
|
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
@ -115,108 +72,10 @@ EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window_width = ANativeWindow_getWidth(surface);
|
||||||
|
window_height = ANativeWindow_getHeight(surface);
|
||||||
|
|
||||||
Network::Init();
|
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() {
|
EmuWindow_Android::~EmuWindow_Android() {
|
||||||
@ -224,48 +83,6 @@ EmuWindow_Android::~EmuWindow_Android() {
|
|||||||
DestroyContext();
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
host_window = render_window;
|
|
||||||
render_window = nullptr;
|
|
||||||
|
|
||||||
DestroyWindowSurface();
|
|
||||||
CreateWindowSurface();
|
|
||||||
OnFramebufferSizeChanged();
|
|
||||||
presenting_state = PresentingState::Initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuWindow_Android::MakeCurrent() {
|
void EmuWindow_Android::MakeCurrent() {
|
||||||
core_context->MakeCurrent();
|
core_context->MakeCurrent();
|
||||||
}
|
}
|
||||||
|
@ -5,38 +5,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
|
||||||
#include <EGL/eglext.h>
|
|
||||||
|
|
||||||
#include "core/frontend/emu_window.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 {
|
class EmuWindow_Android : public Frontend::EmuWindow {
|
||||||
public:
|
public:
|
||||||
EmuWindow_Android(ANativeWindow* surface);
|
EmuWindow_Android(ANativeWindow* surface);
|
||||||
~EmuWindow_Android();
|
~EmuWindow_Android();
|
||||||
|
|
||||||
void Present();
|
|
||||||
|
|
||||||
/// Called by the onSurfaceChanges() method to change the surface
|
/// Called by the onSurfaceChanges() method to change the surface
|
||||||
void OnSurfaceChanged(ANativeWindow* surface);
|
void OnSurfaceChanged(ANativeWindow* surface);
|
||||||
|
|
||||||
@ -46,38 +21,34 @@ public:
|
|||||||
/// Handles movement of touch pointer
|
/// Handles movement of touch pointer
|
||||||
void OnTouchMoved(int x, int y);
|
void OnTouchMoved(int x, int y);
|
||||||
|
|
||||||
void PollEvents() override;
|
|
||||||
void MakeCurrent() override;
|
void MakeCurrent() override;
|
||||||
|
|
||||||
void DoneCurrent() override;
|
void DoneCurrent() override;
|
||||||
|
|
||||||
void TryPresenting();
|
virtual void TryPresenting() {}
|
||||||
void StopPresenting();
|
|
||||||
|
|
||||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
virtual void StopPresenting() {}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void OnFramebufferSizeChanged();
|
void OnFramebufferSizeChanged();
|
||||||
bool CreateWindowSurface();
|
|
||||||
void DestroyWindowSurface();
|
|
||||||
void DestroyContext();
|
|
||||||
|
|
||||||
|
/// Creates the API specific window surface
|
||||||
|
virtual bool CreateWindowSurface() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys the API specific window surface
|
||||||
|
virtual void DestroyWindowSurface() {}
|
||||||
|
|
||||||
|
/// Destroys the graphics context
|
||||||
|
virtual void DestroyContext() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
ANativeWindow* render_window{};
|
ANativeWindow* render_window{};
|
||||||
ANativeWindow* host_window{};
|
ANativeWindow* host_window{};
|
||||||
|
|
||||||
int window_width{};
|
int window_width{};
|
||||||
int window_height{};
|
int window_height{};
|
||||||
|
|
||||||
EGLConfig egl_config;
|
|
||||||
EGLSurface egl_surface{};
|
|
||||||
EGLContext egl_context{};
|
|
||||||
EGLDisplay egl_display{};
|
|
||||||
|
|
||||||
std::unique_ptr<Frontend::GraphicsContext> core_context;
|
std::unique_ptr<Frontend::GraphicsContext> core_context;
|
||||||
|
|
||||||
enum class PresentingState {
|
|
||||||
Initial,
|
|
||||||
Running,
|
|
||||||
Stopped,
|
|
||||||
};
|
|
||||||
PresentingState presenting_state{};
|
|
||||||
};
|
};
|
||||||
|
215
src/android/app/src/main/jni/emu_window/emu_window_gl.cpp
Normal file
215
src/android/app/src/main/jni/emu_window/emu_window_gl.cpp
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
// 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 "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() override {
|
||||||
|
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoneCurrent() override {
|
||||||
|
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::PollEvents() {
|
||||||
|
if (!render_window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
host_window = render_window;
|
||||||
|
render_window = nullptr;
|
||||||
|
|
||||||
|
DestroyWindowSurface();
|
||||||
|
CreateWindowSurface();
|
||||||
|
OnFramebufferSizeChanged();
|
||||||
|
presenting_state = PresentingState::Initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
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::Initial) [[unlikely]] {
|
||||||
|
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
presenting_state = PresentingState::Running;
|
||||||
|
}
|
||||||
|
if (presenting_state != PresentingState::Running) [[unlikely]] {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
44
src/android/app/src/main/jni/emu_window/emu_window_gl.h
Normal file
44
src/android/app/src/main/jni/emu_window/emu_window_gl.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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;
|
||||||
|
void PollEvents() 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{};
|
||||||
|
|
||||||
|
enum class PresentingState {
|
||||||
|
Initial,
|
||||||
|
Running,
|
||||||
|
Stopped,
|
||||||
|
};
|
||||||
|
PresentingState presenting_state{};
|
||||||
|
};
|
53
src/android/app/src/main/jni/emu_window/emu_window_vk.cpp
Normal file
53
src/android/app/src/main/jni/emu_window/emu_window_vk.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <android/native_window_jni.h>
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "jni/emu_window/emu_window_vk.h"
|
||||||
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
|
class GraphicsContext_Android final : public Frontend::GraphicsContext {
|
||||||
|
public:
|
||||||
|
explicit GraphicsContext_Android(std::shared_ptr<Common::DynamicLibrary> driver_library_)
|
||||||
|
: driver_library{driver_library_} {}
|
||||||
|
|
||||||
|
~GraphicsContext_Android() = default;
|
||||||
|
|
||||||
|
std::shared_ptr<Common::DynamicLibrary> GetDriverLibrary() override {
|
||||||
|
return driver_library;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Common::DynamicLibrary> driver_library;
|
||||||
|
};
|
||||||
|
|
||||||
|
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(
|
||||||
|
ANativeWindow* surface, std::shared_ptr<Common::DynamicLibrary> driver_library_)
|
||||||
|
: EmuWindow_Android{surface}, driver_library{driver_library_} {
|
||||||
|
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<GraphicsContext_Android>(driver_library);
|
||||||
|
}
|
26
src/android/app/src/main/jni/emu_window/emu_window_vk.h
Normal file
26
src/android/app/src/main/jni/emu_window/emu_window_vk.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 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,
|
||||||
|
std::shared_ptr<Common::DynamicLibrary> driver_library);
|
||||||
|
~EmuWindow_Android_Vulkan() override = default;
|
||||||
|
|
||||||
|
void PollEvents() override {}
|
||||||
|
|
||||||
|
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool CreateWindowSurface() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Common::DynamicLibrary> driver_library;
|
||||||
|
};
|
@ -4,13 +4,16 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#include <android/api-level.h>
|
#include <android/api-level.h>
|
||||||
#include <android/native_window_jni.h>
|
#include <android/native_window_jni.h>
|
||||||
|
|
||||||
#include "audio_core/dsp_interface.h"
|
#include "audio_core/dsp_interface.h"
|
||||||
#include "common/aarch64/cpu_detect.h"
|
#include "common/aarch64/cpu_detect.h"
|
||||||
|
#include "common/arch.h"
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
|
#include "common/dynamic_library/dynamic_library.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
@ -33,7 +36,8 @@
|
|||||||
#include "jni/camera/ndk_camera.h"
|
#include "jni/camera/ndk_camera.h"
|
||||||
#include "jni/camera/still_image_camera.h"
|
#include "jni/camera/still_image_camera.h"
|
||||||
#include "jni/config.h"
|
#include "jni/config.h"
|
||||||
#include "jni/emu_window/emu_window.h"
|
#include "jni/emu_window/emu_window_gl.h"
|
||||||
|
#include "jni/emu_window/emu_window_vk.h"
|
||||||
#include "jni/game_settings.h"
|
#include "jni/game_settings.h"
|
||||||
#include "jni/id_cache.h"
|
#include "jni/id_cache.h"
|
||||||
#include "jni/input_manager.h"
|
#include "jni/input_manager.h"
|
||||||
@ -42,10 +46,15 @@
|
|||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
|
#if CITRA_ARCH(arm64)
|
||||||
|
#include <adrenotools/driver.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
ANativeWindow* s_surf;
|
ANativeWindow* s_surf;
|
||||||
|
|
||||||
|
std::shared_ptr<Common::DynamicLibrary> vulkan_library{};
|
||||||
std::unique_ptr<EmuWindow_Android> window;
|
std::unique_ptr<EmuWindow_Android> window;
|
||||||
|
|
||||||
std::atomic<bool> stop_run{true};
|
std::atomic<bool> stop_run{true};
|
||||||
@ -123,11 +132,14 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
const auto graphics_api = Settings::values.graphics_api.GetValue();
|
const auto graphics_api = Settings::values.graphics_api.GetValue();
|
||||||
switch (graphics_api) {
|
switch (graphics_api) {
|
||||||
case Settings::GraphicsAPI::OpenGL:
|
case Settings::GraphicsAPI::OpenGL:
|
||||||
window = std::make_unique<EmuWindow_Android>(s_surf);
|
window = std::make_unique<EmuWindow_Android_OpenGL>(s_surf);
|
||||||
|
break;
|
||||||
|
case Settings::GraphicsAPI::Vulkan:
|
||||||
|
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(Frontend, "Unknown graphics API {}, using OpenGL", graphics_api);
|
LOG_CRITICAL(Frontend, "Unknown graphics API {}, using Vulkan", graphics_api);
|
||||||
window = std::make_unique<EmuWindow_Android>(s_surf);
|
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::System& system{Core::System::GetInstance()};
|
Core::System& system{Core::System::GetInstance()};
|
||||||
@ -228,6 +240,37 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
return Core::System::ResultStatus::Success;
|
return Core::System::ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
|
||||||
|
const std::string& custom_driver_name,
|
||||||
|
const std::string& file_redirect_dir) {
|
||||||
|
#if CITRA_ARCH(arm64)
|
||||||
|
void* handle{};
|
||||||
|
const char* file_redirect_dir_{};
|
||||||
|
int featureFlags{};
|
||||||
|
|
||||||
|
// Enable driver file redirection when renderer debugging is enabled.
|
||||||
|
if (Settings::values.renderer_debug && file_redirect_dir.size()) {
|
||||||
|
featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT;
|
||||||
|
file_redirect_dir_ = file_redirect_dir.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load a custom driver.
|
||||||
|
if (custom_driver_name.size()) {
|
||||||
|
handle = adrenotools_open_libvulkan(
|
||||||
|
RTLD_NOW, featureFlags | ADRENOTOOLS_DRIVER_CUSTOM, nullptr, hook_lib_dir.c_str(),
|
||||||
|
custom_driver_dir.c_str(), custom_driver_name.c_str(), file_redirect_dir_, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load the system driver.
|
||||||
|
if (!handle) {
|
||||||
|
handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
|
||||||
|
nullptr, nullptr, file_redirect_dir_, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
vulkan_library = std::make_shared<Common::DynamicLibrary>(handle);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
|
void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
|
||||||
@ -238,6 +281,9 @@ void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
|
|||||||
if (window) {
|
if (window) {
|
||||||
window->OnSurfaceChanged(s_surf);
|
window->OnSurfaceChanged(s_surf);
|
||||||
}
|
}
|
||||||
|
if (VideoCore::g_renderer) {
|
||||||
|
VideoCore::g_renderer->NotifySurfaceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
LOG_INFO(Frontend, "Surface changed");
|
LOG_INFO(Frontend, "Surface changed");
|
||||||
}
|
}
|
||||||
@ -258,6 +304,15 @@ void Java_org_citra_citra_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused
|
|||||||
window->TryPresenting();
|
window->TryPresenting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* env, jclass clazz,
|
||||||
|
jstring hook_lib_dir,
|
||||||
|
jstring custom_driver_dir,
|
||||||
|
jstring custom_driver_name,
|
||||||
|
jstring file_redirect_dir) {
|
||||||
|
InitializeGpuDriver(GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
|
||||||
|
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
|
||||||
|
}
|
||||||
|
|
||||||
void Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env,
|
void Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jint layout_option,
|
jint layout_option,
|
||||||
|
Binary file not shown.
BIN
src/android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Normal file
BIN
src/android/app/src/main/jniLibs/arm64-v8a/libc++_shared.so
Normal file
Binary file not shown.
@ -177,11 +177,13 @@
|
|||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="graphicsApiNames">
|
<string-array name="graphicsApiNames">
|
||||||
<item>OpenGLES</item>
|
<item>OpenGL ES</item>
|
||||||
|
<item>Vulkan</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<integer-array name="graphicsApiValues">
|
<integer-array name="graphicsApiValues">
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="textureFilterNames">
|
<string-array name="textureFilterNames">
|
||||||
|
@ -74,6 +74,10 @@
|
|||||||
<!-- Graphics settings strings -->
|
<!-- Graphics settings strings -->
|
||||||
<string name="renderer">Renderer</string>
|
<string name="renderer">Renderer</string>
|
||||||
<string name="graphics_api">Graphics API</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">Debug Renderer</string>
|
<string name="renderer_debug">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="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">Enable V-Sync</string>
|
||||||
|
@ -49,8 +49,6 @@ create_target_directory_groups(audio_core)
|
|||||||
|
|
||||||
target_link_libraries(audio_core PUBLIC citra_common citra_core)
|
target_link_libraries(audio_core PUBLIC citra_common citra_core)
|
||||||
target_link_libraries(audio_core PRIVATE SoundTouch teakra)
|
target_link_libraries(audio_core PRIVATE SoundTouch teakra)
|
||||||
set_target_properties(audio_core PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
|
|
||||||
add_definitions(-DSOUNDTOUCH_INTEGER_SAMPLES)
|
|
||||||
|
|
||||||
if(ENABLE_MF)
|
if(ENABLE_MF)
|
||||||
target_sources(audio_core PRIVATE
|
target_sources(audio_core PRIVATE
|
||||||
|
@ -33,34 +33,34 @@ void Mixers::ParseConfig(DspConfiguration& config) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.mixer1_enabled_dirty) {
|
if (config.aux_bus_enable[0]) {
|
||||||
config.mixer1_enabled_dirty.Assign(0);
|
config.aux_bus_enable_0_dirty.Assign(0);
|
||||||
state.mixer1_enabled = config.mixer1_enabled != 0;
|
state.aux_bus_enable[0] = config.aux_bus_enable[0] != 0;
|
||||||
LOG_TRACE(Audio_DSP, "mixers mixer1_enabled = {}", config.mixer1_enabled);
|
LOG_TRACE(Audio_DSP, "mixers aux_bus_enable[0] = {}", config.aux_bus_enable[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.mixer2_enabled_dirty) {
|
if (config.aux_bus_enable[1]) {
|
||||||
config.mixer2_enabled_dirty.Assign(0);
|
config.aux_bus_enable_1_dirty.Assign(0);
|
||||||
state.mixer2_enabled = config.mixer2_enabled != 0;
|
state.aux_bus_enable[1] = config.aux_bus_enable[1] != 0;
|
||||||
LOG_TRACE(Audio_DSP, "mixers mixer2_enabled = {}", config.mixer2_enabled);
|
LOG_TRACE(Audio_DSP, "mixers aux_bus_enable[1] = {}", config.aux_bus_enable[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.volume_0_dirty) {
|
if (config.master_volume) {
|
||||||
config.volume_0_dirty.Assign(0);
|
config.master_volume_dirty.Assign(0);
|
||||||
state.intermediate_mixer_volume[0] = config.volume[0];
|
state.intermediate_mixer_volume[0] = config.master_volume;
|
||||||
LOG_TRACE(Audio_DSP, "mixers volume[0] = {}", config.volume[0]);
|
LOG_TRACE(Audio_DSP, "mixers master_volume = {}", config.master_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.volume_1_dirty) {
|
if (config.aux_return_volume[0]) {
|
||||||
config.volume_1_dirty.Assign(0);
|
config.aux_return_volume_0_dirty.Assign(0);
|
||||||
state.intermediate_mixer_volume[1] = config.volume[1];
|
state.intermediate_mixer_volume[1] = config.aux_return_volume[0];
|
||||||
LOG_TRACE(Audio_DSP, "mixers volume[1] = {}", config.volume[1]);
|
LOG_TRACE(Audio_DSP, "mixers aux_return_volume[0] = {}", config.aux_return_volume[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.volume_2_dirty) {
|
if (config.aux_return_volume[1]) {
|
||||||
config.volume_2_dirty.Assign(0);
|
config.aux_return_volume_1_dirty.Assign(0);
|
||||||
state.intermediate_mixer_volume[2] = config.volume[2];
|
state.intermediate_mixer_volume[2] = config.aux_return_volume[1];
|
||||||
LOG_TRACE(Audio_DSP, "mixers volume[2] = {}", config.volume[2]);
|
LOG_TRACE(Audio_DSP, "mixers aux_return_volume[1] = {}", config.aux_return_volume[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.output_format_dirty) {
|
if (config.output_format_dirty) {
|
||||||
@ -137,7 +137,7 @@ void Mixers::AuxReturn(const IntermediateMixSamples& read_samples) {
|
|||||||
// NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to
|
// NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to
|
||||||
// QuadFrame32.
|
// QuadFrame32.
|
||||||
|
|
||||||
if (state.mixer1_enabled) {
|
if (state.aux_bus_enable[0]) {
|
||||||
for (std::size_t sample = 0; sample < samples_per_frame; sample++) {
|
for (std::size_t sample = 0; sample < samples_per_frame; sample++) {
|
||||||
for (std::size_t channel = 0; channel < 4; channel++) {
|
for (std::size_t channel = 0; channel < 4; channel++) {
|
||||||
state.intermediate_mix_buffer[1][sample][channel] =
|
state.intermediate_mix_buffer[1][sample][channel] =
|
||||||
@ -146,7 +146,7 @@ void Mixers::AuxReturn(const IntermediateMixSamples& read_samples) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.mixer2_enabled) {
|
if (state.aux_bus_enable[1]) {
|
||||||
for (std::size_t sample = 0; sample < samples_per_frame; sample++) {
|
for (std::size_t sample = 0; sample < samples_per_frame; sample++) {
|
||||||
for (std::size_t channel = 0; channel < 4; channel++) {
|
for (std::size_t channel = 0; channel < 4; channel++) {
|
||||||
state.intermediate_mix_buffer[2][sample][channel] =
|
state.intermediate_mix_buffer[2][sample][channel] =
|
||||||
@ -163,7 +163,7 @@ void Mixers::AuxSend(IntermediateMixSamples& write_samples,
|
|||||||
|
|
||||||
state.intermediate_mix_buffer[0] = input[0];
|
state.intermediate_mix_buffer[0] = input[0];
|
||||||
|
|
||||||
if (state.mixer1_enabled) {
|
if (state.aux_bus_enable[0]) {
|
||||||
for (std::size_t sample = 0; sample < samples_per_frame; sample++) {
|
for (std::size_t sample = 0; sample < samples_per_frame; sample++) {
|
||||||
for (std::size_t channel = 0; channel < 4; channel++) {
|
for (std::size_t channel = 0; channel < 4; channel++) {
|
||||||
write_samples.mix1.pcm32[channel][sample] = input[1][sample][channel];
|
write_samples.mix1.pcm32[channel][sample] = input[1][sample][channel];
|
||||||
@ -173,7 +173,7 @@ void Mixers::AuxSend(IntermediateMixSamples& write_samples,
|
|||||||
state.intermediate_mix_buffer[1] = input[1];
|
state.intermediate_mix_buffer[1] = input[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.mixer2_enabled) {
|
if (state.aux_bus_enable[1]) {
|
||||||
for (std::size_t sample = 0; sample < samples_per_frame; sample++) {
|
for (std::size_t sample = 0; sample < samples_per_frame; sample++) {
|
||||||
for (std::size_t channel = 0; channel < 4; channel++) {
|
for (std::size_t channel = 0; channel < 4; channel++) {
|
||||||
write_samples.mix2.pcm32[channel][sample] = input[2][sample][channel];
|
write_samples.mix2.pcm32[channel][sample] = input[2][sample][channel];
|
||||||
@ -187,6 +187,8 @@ void Mixers::AuxSend(IntermediateMixSamples& write_samples,
|
|||||||
void Mixers::MixCurrentFrame() {
|
void Mixers::MixCurrentFrame() {
|
||||||
current_frame.fill({});
|
current_frame.fill({});
|
||||||
|
|
||||||
|
// TODO(SachinV): This is probably not accurate, based on symbols from FE:Fates,
|
||||||
|
// state.intermediate_mixer_volume[0] represents the master volume
|
||||||
for (std::size_t mix = 0; mix < 3; mix++) {
|
for (std::size_t mix = 0; mix < 3; mix++) {
|
||||||
DownmixAndMixIntoCurrentFrame(state.intermediate_mixer_volume[mix],
|
DownmixAndMixIntoCurrentFrame(state.intermediate_mixer_volume[mix],
|
||||||
state.intermediate_mix_buffer[mix]);
|
state.intermediate_mix_buffer[mix]);
|
||||||
|
@ -34,8 +34,7 @@ private:
|
|||||||
struct {
|
struct {
|
||||||
std::array<float, 3> intermediate_mixer_volume = {};
|
std::array<float, 3> intermediate_mixer_volume = {};
|
||||||
|
|
||||||
bool mixer1_enabled = false;
|
std::array<bool, 2> aux_bus_enable = {};
|
||||||
bool mixer2_enabled = false;
|
|
||||||
std::array<QuadFrame32, 3> intermediate_mix_buffer = {};
|
std::array<QuadFrame32, 3> intermediate_mix_buffer = {};
|
||||||
|
|
||||||
OutputFormat output_format = OutputFormat::Stereo;
|
OutputFormat output_format = OutputFormat::Stereo;
|
||||||
@ -60,8 +59,7 @@ private:
|
|||||||
void serialize(Archive& ar, const unsigned int) {
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
ar& current_frame;
|
ar& current_frame;
|
||||||
ar& state.intermediate_mixer_volume;
|
ar& state.intermediate_mixer_volume;
|
||||||
ar& state.mixer1_enabled;
|
ar& state.aux_bus_enable;
|
||||||
ar& state.mixer2_enabled;
|
|
||||||
ar& state.intermediate_mix_buffer;
|
ar& state.intermediate_mix_buffer;
|
||||||
ar& state.output_format;
|
ar& state.output_format;
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ struct SourceConfiguration {
|
|||||||
BitField<25, 1, u32> gain_0_dirty;
|
BitField<25, 1, u32> gain_0_dirty;
|
||||||
BitField<26, 1, u32> gain_1_dirty;
|
BitField<26, 1, u32> gain_1_dirty;
|
||||||
BitField<27, 1, u32> gain_2_dirty;
|
BitField<27, 1, u32> gain_2_dirty;
|
||||||
BitField<28, 1, u32> sync_dirty;
|
BitField<28, 1, u32> sync_count_dirty;
|
||||||
BitField<29, 1, u32> reset_flag;
|
BitField<29, 1, u32> reset_flag;
|
||||||
BitField<30, 1, u32> embedded_buffer_dirty;
|
BitField<30, 1, u32> embedded_buffer_dirty;
|
||||||
};
|
};
|
||||||
@ -251,7 +251,7 @@ struct SourceConfiguration {
|
|||||||
u32_dsp loop_related;
|
u32_dsp loop_related;
|
||||||
u8 enable;
|
u8 enable;
|
||||||
INSERT_PADDING_BYTES(1);
|
INSERT_PADDING_BYTES(1);
|
||||||
u16_le sync; ///< Application-side sync (See also: SourceStatus::sync)
|
u16_le sync_count; ///< Application-side sync count (See also: SourceStatus::sync_count)
|
||||||
u32_dsp play_position; ///< Position. (Units: number of samples)
|
u32_dsp play_position; ///< Position. (Units: number of samples)
|
||||||
INSERT_PADDING_DSPWORDS(2);
|
INSERT_PADDING_DSPWORDS(2);
|
||||||
|
|
||||||
@ -313,9 +313,9 @@ struct SourceStatus {
|
|||||||
struct Status {
|
struct Status {
|
||||||
u8 is_enabled; ///< Is this channel enabled? (Doesn't have to be playing anything.)
|
u8 is_enabled; ///< Is this channel enabled? (Doesn't have to be playing anything.)
|
||||||
u8 current_buffer_id_dirty; ///< Non-zero when current_buffer_id changes
|
u8 current_buffer_id_dirty; ///< Non-zero when current_buffer_id changes
|
||||||
u16_le sync; ///< Is set by the DSP to the value of SourceConfiguration::sync
|
u16_le sync_count; ///< Is set by the DSP to the value of SourceConfiguration::sync_count
|
||||||
u32_dsp buffer_position; ///< Number of samples into the current buffer
|
u32_dsp buffer_position; ///< Number of samples into the current buffer
|
||||||
u16_le current_buffer_id; ///< Updated when a buffer finishes playing
|
u16_le current_buffer_id; ///< Updated when a buffer finishes playing
|
||||||
INSERT_PADDING_DSPWORDS(1);
|
INSERT_PADDING_DSPWORDS(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -329,27 +329,35 @@ struct DspConfiguration {
|
|||||||
union {
|
union {
|
||||||
u32_le dirty_raw;
|
u32_le dirty_raw;
|
||||||
|
|
||||||
BitField<8, 1, u32> mixer1_enabled_dirty;
|
BitField<6, 1, u32> aux_front_bypass_0_dirty;
|
||||||
BitField<9, 1, u32> mixer2_enabled_dirty;
|
BitField<7, 1, u32> aux_front_bypass_1_dirty;
|
||||||
|
BitField<8, 1, u32> aux_bus_enable_0_dirty;
|
||||||
|
BitField<9, 1, u32> aux_bus_enable_1_dirty;
|
||||||
BitField<10, 1, u32> delay_effect_0_dirty;
|
BitField<10, 1, u32> delay_effect_0_dirty;
|
||||||
BitField<11, 1, u32> delay_effect_1_dirty;
|
BitField<11, 1, u32> delay_effect_1_dirty;
|
||||||
BitField<12, 1, u32> reverb_effect_0_dirty;
|
BitField<12, 1, u32> reverb_effect_0_dirty;
|
||||||
BitField<13, 1, u32> reverb_effect_1_dirty;
|
BitField<13, 1, u32> reverb_effect_1_dirty;
|
||||||
|
|
||||||
BitField<16, 1, u32> volume_0_dirty;
|
BitField<15, 1, u32> output_buffer_count_dirty;
|
||||||
|
BitField<16, 1, u32> master_volume_dirty;
|
||||||
|
|
||||||
BitField<24, 1, u32> volume_1_dirty;
|
BitField<24, 1, u32> aux_return_volume_0_dirty;
|
||||||
BitField<25, 1, u32> volume_2_dirty;
|
BitField<25, 1, u32> aux_return_volume_1_dirty;
|
||||||
BitField<26, 1, u32> output_format_dirty;
|
BitField<26, 1, u32> output_format_dirty;
|
||||||
BitField<27, 1, u32> limiter_enabled_dirty;
|
BitField<27, 1, u32> clipping_mode_dirty;
|
||||||
BitField<28, 1, u32> headphones_connected_dirty;
|
BitField<28, 1, u32> headphones_connected_dirty;
|
||||||
|
BitField<29, 1, u32> surround_depth_dirty;
|
||||||
|
BitField<30, 1, u32> surround_speaker_position_dirty;
|
||||||
|
BitField<31, 1, u32> rear_ratio_dirty;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for
|
/// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for
|
||||||
/// each at the final mixer.
|
/// each at the final mixer.
|
||||||
float_le volume[3];
|
float_le master_volume;
|
||||||
|
std::array<float_le, 2> aux_return_volume;
|
||||||
|
|
||||||
INSERT_PADDING_DSPWORDS(3);
|
u16_le output_buffer_count;
|
||||||
|
INSERT_PADDING_DSPWORDS(2);
|
||||||
|
|
||||||
enum class OutputFormat : u16_le {
|
enum class OutputFormat : u16_le {
|
||||||
Mono = 0,
|
Mono = 0,
|
||||||
@ -359,12 +367,15 @@ struct DspConfiguration {
|
|||||||
|
|
||||||
OutputFormat output_format;
|
OutputFormat output_format;
|
||||||
|
|
||||||
u16_le limiter_enabled; ///< Not sure of the exact gain equation for the limiter.
|
u16_le clipping_mode; ///< Not sure of the exact gain equation for the limiter.
|
||||||
u16_le headphones_connected; ///< Application updates the DSP on headphone status.
|
u16_le headphones_connected; ///< Application updates the DSP on headphone status.
|
||||||
INSERT_PADDING_DSPWORDS(4); ///< TODO: Surround sound related
|
|
||||||
INSERT_PADDING_DSPWORDS(2); ///< TODO: Intermediate mixer 1/2 related
|
u16_le surround_depth;
|
||||||
u16_le mixer1_enabled;
|
u16_le surround_speaker_position;
|
||||||
u16_le mixer2_enabled;
|
INSERT_PADDING_DSPWORDS(1); ///< TODO: Surround sound related
|
||||||
|
u16_le rear_ratio;
|
||||||
|
std::array<u16_le, 2> aux_front_bypass;
|
||||||
|
std::array<u16_le, 2> aux_bus_enable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is delay with feedback.
|
* This is delay with feedback.
|
||||||
@ -406,11 +417,19 @@ struct DspConfiguration {
|
|||||||
|
|
||||||
ReverbEffect reverb_effect[2];
|
ReverbEffect reverb_effect[2];
|
||||||
|
|
||||||
INSERT_PADDING_DSPWORDS(4);
|
u16_le sync_mode;
|
||||||
|
INSERT_PADDING_DSPWORDS(1);
|
||||||
|
union {
|
||||||
|
u32_le dirty2_raw;
|
||||||
|
|
||||||
|
BitField<16, 1, u32> sync_mode_dirty;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
ASSERT_DSP_STRUCT(DspConfiguration, 196);
|
ASSERT_DSP_STRUCT(DspConfiguration, 196);
|
||||||
ASSERT_DSP_STRUCT(DspConfiguration::DelayEffect, 20);
|
ASSERT_DSP_STRUCT(DspConfiguration::DelayEffect, 20);
|
||||||
ASSERT_DSP_STRUCT(DspConfiguration::ReverbEffect, 52);
|
ASSERT_DSP_STRUCT(DspConfiguration::ReverbEffect, 52);
|
||||||
|
static_assert(offsetof(DspConfiguration, sync_mode) == 0xBC);
|
||||||
|
static_assert(offsetof(DspConfiguration, dirty2_raw) == 0xC0);
|
||||||
|
|
||||||
struct AdpcmCoefficients {
|
struct AdpcmCoefficients {
|
||||||
/// Coefficients are signed fixed point with 11 fractional bits.
|
/// Coefficients are signed fixed point with 11 fractional bits.
|
||||||
|
@ -72,10 +72,10 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
|||||||
LOG_TRACE(Audio_DSP, "source_id={} enable={}", source_id, state.enabled);
|
LOG_TRACE(Audio_DSP, "source_id={} enable={}", source_id, state.enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.sync_dirty) {
|
if (config.sync_count_dirty) {
|
||||||
config.sync_dirty.Assign(0);
|
config.sync_count_dirty.Assign(0);
|
||||||
state.sync = config.sync;
|
state.sync_count = config.sync_count;
|
||||||
LOG_TRACE(Audio_DSP, "source_id={} sync={}", source_id, state.sync);
|
LOG_TRACE(Audio_DSP, "source_id={} sync={}", source_id, state.sync_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.rate_multiplier_dirty) {
|
if (config.rate_multiplier_dirty) {
|
||||||
@ -231,7 +231,8 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_TRACE(Audio_DSP, "partially updating embedded buffer addr={:#010x} len={} id={}",
|
LOG_TRACE(Audio_DSP, "partially updating embedded buffer addr={:#010x} len={} id={}",
|
||||||
state.current_buffer_physical_address, config.length, config.buffer_id);
|
state.current_buffer_physical_address, static_cast<u32>(config.length),
|
||||||
|
config.buffer_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.embedded_buffer_dirty) {
|
if (config.embedded_buffer_dirty) {
|
||||||
@ -248,7 +249,7 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
|||||||
LOG_ERROR(Audio_DSP,
|
LOG_ERROR(Audio_DSP,
|
||||||
"Skipping embedded buffer sample! Game passed in improper value for length. "
|
"Skipping embedded buffer sample! Game passed in improper value for length. "
|
||||||
"addr {:X} length {:X}",
|
"addr {:X} length {:X}",
|
||||||
config.physical_address, config.length);
|
static_cast<u32>(config.physical_address), static_cast<u32>(config.length));
|
||||||
} else {
|
} else {
|
||||||
state.input_queue.emplace(Buffer{
|
state.input_queue.emplace(Buffer{
|
||||||
config.physical_address,
|
config.physical_address,
|
||||||
@ -266,8 +267,8 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
LOG_TRACE(Audio_DSP, "enqueuing embedded addr={:#010x} len={} id={} start={}",
|
LOG_TRACE(Audio_DSP, "enqueuing embedded addr={:#010x} len={} id={} start={}",
|
||||||
config.physical_address, config.length, config.buffer_id,
|
static_cast<u32>(config.physical_address), static_cast<u32>(config.length),
|
||||||
static_cast<u32>(config.play_position));
|
config.buffer_id, static_cast<u32>(config.play_position));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.loop_related_dirty && config.loop_related != 0) {
|
if (config.loop_related_dirty && config.loop_related != 0) {
|
||||||
@ -285,7 +286,7 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
|||||||
LOG_ERROR(Audio_DSP,
|
LOG_ERROR(Audio_DSP,
|
||||||
"Skipping buffer queue sample! Game passed in improper value for "
|
"Skipping buffer queue sample! Game passed in improper value for "
|
||||||
"length. addr {:X} length {:X}",
|
"length. addr {:X} length {:X}",
|
||||||
b.physical_address, b.length);
|
static_cast<u32>(b.physical_address), static_cast<u32>(b.length));
|
||||||
} else {
|
} else {
|
||||||
state.input_queue.emplace(Buffer{
|
state.input_queue.emplace(Buffer{
|
||||||
b.physical_address,
|
b.physical_address,
|
||||||
@ -303,7 +304,8 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
LOG_TRACE(Audio_DSP, "enqueuing queued {} addr={:#010x} len={} id={}", i,
|
LOG_TRACE(Audio_DSP, "enqueuing queued {} addr={:#010x} len={} id={}", i,
|
||||||
b.physical_address, b.length, b.buffer_id);
|
static_cast<u32>(b.physical_address), static_cast<u32>(b.length),
|
||||||
|
b.buffer_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config.buffers_dirty = 0;
|
config.buffers_dirty = 0;
|
||||||
@ -432,7 +434,7 @@ SourceStatus::Status Source::GetCurrentStatus() {
|
|||||||
state.buffer_update = false;
|
state.buffer_update = false;
|
||||||
ret.current_buffer_id = state.current_buffer_id;
|
ret.current_buffer_id = state.current_buffer_id;
|
||||||
ret.buffer_position = state.current_sample_number;
|
ret.buffer_position = state.current_sample_number;
|
||||||
ret.sync = state.sync;
|
ret.sync_count = state.sync_count;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ private:
|
|||||||
// State variables
|
// State variables
|
||||||
|
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
u16 sync = 0;
|
u16 sync_count = 0;
|
||||||
|
|
||||||
// Mixing
|
// Mixing
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ private:
|
|||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& ar, const unsigned int) {
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
ar& enabled;
|
ar& enabled;
|
||||||
ar& sync;
|
ar& sync_count;
|
||||||
ar& gain;
|
ar& gain;
|
||||||
ar& input_queue;
|
ar& input_queue;
|
||||||
ar& mono_or_stereo;
|
ar& mono_or_stereo;
|
||||||
|
@ -5,10 +5,15 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
#include <SoundTouch.h>
|
#include <SoundTouch.h>
|
||||||
|
|
||||||
#include "audio_core/audio_types.h"
|
#include "audio_core/audio_types.h"
|
||||||
#include "audio_core/time_stretch.h"
|
#include "audio_core/time_stretch.h"
|
||||||
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
@ -62,8 +67,44 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
|
|||||||
LOG_TRACE(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, stretch_ratio,
|
LOG_TRACE(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, stretch_ratio,
|
||||||
backlog_fullness);
|
backlog_fullness);
|
||||||
|
|
||||||
sound_touch->putSamples(in, static_cast<u32>(num_in));
|
if constexpr (std::is_floating_point<soundtouch::SAMPLETYPE>()) {
|
||||||
return sound_touch->receiveSamples(out, static_cast<u32>(num_out));
|
// The SoundTouch library on most systems expects float samples
|
||||||
|
// use this vector to store input if soundtouch::SAMPLETYPE is a float
|
||||||
|
std::vector<soundtouch::SAMPLETYPE> float_in(2 * num_in);
|
||||||
|
std::vector<soundtouch::SAMPLETYPE> float_out(2 * num_out);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < (2 * num_in); i++) {
|
||||||
|
// Conventional integer PCM uses a range of -32768 to 32767,
|
||||||
|
// but float samples use -1 to 1
|
||||||
|
// As a result we need to scale sample values during conversion
|
||||||
|
const float temp = static_cast<float>(in[i]) / std::numeric_limits<s16>::max();
|
||||||
|
float_in[i] = static_cast<soundtouch::SAMPLETYPE>(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
sound_touch->putSamples(float_in.data(), static_cast<u32>(num_in));
|
||||||
|
|
||||||
|
const std::size_t samples_received =
|
||||||
|
sound_touch->receiveSamples(float_out.data(), static_cast<u32>(num_out));
|
||||||
|
|
||||||
|
// Converting output samples back to shorts so we can use them
|
||||||
|
for (std::size_t i = 0; i < (2 * num_out); i++) {
|
||||||
|
const s16 temp = static_cast<s16>(float_out[i] * std::numeric_limits<s16>::max());
|
||||||
|
out[i] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples_received;
|
||||||
|
} else if (std::is_same<soundtouch::SAMPLETYPE, s16>()) {
|
||||||
|
// Use reinterpret_cast to workaround compile error when SAMPLETYPE is float.
|
||||||
|
sound_touch->putSamples(reinterpret_cast<const soundtouch::SAMPLETYPE*>(in),
|
||||||
|
static_cast<u32>(num_in));
|
||||||
|
return sound_touch->receiveSamples(reinterpret_cast<soundtouch::SAMPLETYPE*>(out),
|
||||||
|
static_cast<u32>(num_out));
|
||||||
|
} else {
|
||||||
|
static_assert(std::is_floating_point<soundtouch::SAMPLETYPE>() ||
|
||||||
|
std::is_same<soundtouch::SAMPLETYPE, s16>());
|
||||||
|
UNREACHABLE_MSG("Invalid SAMPLETYPE {}", typeid(soundtouch::SAMPLETYPE).name());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeStretcher::Clear() {
|
void TimeStretcher::Clear() {
|
||||||
|
@ -12,6 +12,8 @@ add_executable(citra
|
|||||||
emu_window/emu_window_sdl2_gl.h
|
emu_window/emu_window_sdl2_gl.h
|
||||||
emu_window/emu_window_sdl2_sw.cpp
|
emu_window/emu_window_sdl2_sw.cpp
|
||||||
emu_window/emu_window_sdl2_sw.h
|
emu_window/emu_window_sdl2_sw.h
|
||||||
|
emu_window/emu_window_sdl2_vk.cpp
|
||||||
|
emu_window/emu_window_sdl2_vk.h
|
||||||
precompiled_headers.h
|
precompiled_headers.h
|
||||||
resource.h
|
resource.h
|
||||||
)
|
)
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "citra/emu_window/emu_window_sdl2.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_gl.h"
|
||||||
#include "citra/emu_window/emu_window_sdl2_sw.h"
|
#include "citra/emu_window/emu_window_sdl2_sw.h"
|
||||||
|
#include "citra/emu_window/emu_window_sdl2_vk.h"
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
#include "common/detached_tasks.h"
|
#include "common/detached_tasks.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
@ -351,6 +352,8 @@ int main(int argc, char** argv) {
|
|||||||
switch (Settings::values.graphics_api.GetValue()) {
|
switch (Settings::values.graphics_api.GetValue()) {
|
||||||
case Settings::GraphicsAPI::OpenGL:
|
case Settings::GraphicsAPI::OpenGL:
|
||||||
return std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, is_secondary);
|
return std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, is_secondary);
|
||||||
|
case Settings::GraphicsAPI::Vulkan:
|
||||||
|
return std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen, is_secondary);
|
||||||
case Settings::GraphicsAPI::Software:
|
case Settings::GraphicsAPI::Software:
|
||||||
return std::make_unique<EmuWindow_SDL2_SW>(system, fullscreen, is_secondary);
|
return std::make_unique<EmuWindow_SDL2_SW>(system, fullscreen, is_secondary);
|
||||||
}
|
}
|
||||||
|
@ -133,6 +133,10 @@ void Config::ReadValues() {
|
|||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
ReadSetting("Renderer", Settings::values.graphics_api);
|
ReadSetting("Renderer", Settings::values.graphics_api);
|
||||||
|
ReadSetting("Renderer", Settings::values.physical_device);
|
||||||
|
ReadSetting("Renderer", Settings::values.spirv_shader_gen);
|
||||||
|
ReadSetting("Renderer", Settings::values.async_shader_compilation);
|
||||||
|
ReadSetting("Renderer", Settings::values.async_presentation);
|
||||||
ReadSetting("Renderer", Settings::values.use_gles);
|
ReadSetting("Renderer", Settings::values.use_gles);
|
||||||
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
ReadSetting("Renderer", Settings::values.use_hw_shader);
|
||||||
ReadSetting("Renderer", Settings::values.shaders_accurate_mul);
|
ReadSetting("Renderer", Settings::values.shaders_accurate_mul);
|
||||||
|
@ -99,7 +99,7 @@ cpu_clock_percentage =
|
|||||||
|
|
||||||
[Renderer]
|
[Renderer]
|
||||||
# Whether to render using OpenGL or Software
|
# Whether to render using OpenGL or Software
|
||||||
# 0: Software, 1: OpenGL (default)
|
# 0: Software, 1: OpenGL (default), 2: Vulkan
|
||||||
graphics_api =
|
graphics_api =
|
||||||
|
|
||||||
# Whether to render using GLES or OpenGL
|
# Whether to render using GLES or OpenGL
|
||||||
|
90
src/citra/emu_window/emu_window_sdl2_vk.cpp
Normal file
90
src/citra/emu_window/emu_window_sdl2_vk.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2023 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_syswm.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include "citra/emu_window/emu_window_sdl2_vk.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/scm_rev.h"
|
||||||
|
#include "core/frontend/emu_window.h"
|
||||||
|
|
||||||
|
class DummyContext : public Frontend::GraphicsContext {};
|
||||||
|
|
||||||
|
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen, bool is_secondary)
|
||||||
|
: EmuWindow_SDL2{system, is_secondary} {
|
||||||
|
const 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);
|
||||||
|
SDL_SysWMinfo wm;
|
||||||
|
SDL_VERSION(&wm.version);
|
||||||
|
if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) {
|
||||||
|
LOG_CRITICAL(Frontend, "Failed to get information from the window manager");
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullscreen) {
|
||||||
|
Fullscreen();
|
||||||
|
SDL_ShowCursor(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (wm.subsystem) {
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
|
||||||
|
window_info.type = Frontend::WindowSystemType::Windows;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_X11
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
||||||
|
window_info.type = Frontend::WindowSystemType::X11;
|
||||||
|
window_info.display_connection = wm.info.x11.display;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
||||||
|
window_info.type = Frontend::WindowSystemType::Wayland;
|
||||||
|
window_info.display_connection = wm.info.wl.display;
|
||||||
|
window_info.render_surface = wm.info.wl.surface;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_COCOA
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA:
|
||||||
|
window_info.type = Frontend::WindowSystemType::MacOS;
|
||||||
|
window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(render_window));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID:
|
||||||
|
window_info.type = Frontend::WindowSystemType::Android;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.android.window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem);
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
render_window_id = SDL_GetWindowID(render_window);
|
||||||
|
|
||||||
|
OnResize();
|
||||||
|
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||||
|
SDL_PumpEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const {
|
||||||
|
return std::make_unique<DummyContext>();
|
||||||
|
}
|
24
src/citra/emu_window/emu_window_sdl2_vk.h
Normal file
24
src/citra/emu_window/emu_window_sdl2_vk.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
namespace Frontend {
|
||||||
|
class GraphicsContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
|
||||||
|
public:
|
||||||
|
explicit EmuWindow_SDL2_VK(Core::System& system_, bool fullscreen, bool is_secondary);
|
||||||
|
~EmuWindow_SDL2_VK() override;
|
||||||
|
|
||||||
|
std::unique_ptr<Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||||
|
};
|
@ -185,6 +185,8 @@ add_executable(citra-qt
|
|||||||
util/spinbox.h
|
util/spinbox.h
|
||||||
util/util.cpp
|
util/util.cpp
|
||||||
util/util.h
|
util/util.h
|
||||||
|
util/vk_device_info.cpp
|
||||||
|
util/vk_device_info.h
|
||||||
)
|
)
|
||||||
|
|
||||||
file(GLOB COMPAT_LIST
|
file(GLOB COMPAT_LIST
|
||||||
|
@ -229,20 +229,10 @@ class RenderWidget : public QWidget {
|
|||||||
public:
|
public:
|
||||||
RenderWidget(GRenderWindow* parent) : QWidget(parent) {
|
RenderWidget(GRenderWindow* parent) : QWidget(parent) {
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~RenderWidget() = default;
|
|
||||||
|
|
||||||
virtual void Present() {}
|
|
||||||
|
|
||||||
void paintEvent(QPaintEvent* event) override {
|
|
||||||
Present();
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<unsigned, unsigned> GetSize() const {
|
virtual ~RenderWidget() = default;
|
||||||
return std::make_pair(width(), height());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAS_OPENGL
|
#ifdef HAS_OPENGL
|
||||||
@ -262,7 +252,7 @@ public:
|
|||||||
context = std::move(context_);
|
context = std::move(context_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Present() override {
|
void Present() {
|
||||||
if (!isVisible()) {
|
if (!isVisible()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -278,6 +268,11 @@ public:
|
|||||||
glFinish();
|
glFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* event) override {
|
||||||
|
Present();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
QPaintEngine* paintEngine() const override {
|
QPaintEngine* paintEngine() const override {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -289,11 +284,31 @@ private:
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class VulkanRenderWidget : public RenderWidget {
|
||||||
|
public:
|
||||||
|
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||||
|
setAttribute(Qt::WA_NativeWindow);
|
||||||
|
setAttribute(Qt::WA_PaintOnScreen);
|
||||||
|
if (GetWindowSystemType() == Frontend::WindowSystemType::Wayland) {
|
||||||
|
setAttribute(Qt::WA_DontCreateNativeAncestors);
|
||||||
|
}
|
||||||
|
#ifdef __APPLE__
|
||||||
|
windowHandle()->setSurfaceType(QWindow::MetalSurface);
|
||||||
|
#else
|
||||||
|
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QPaintEngine* paintEngine() const override {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct SoftwareRenderWidget : public RenderWidget {
|
struct SoftwareRenderWidget : public RenderWidget {
|
||||||
explicit SoftwareRenderWidget(GRenderWindow* parent, Core::System& system_)
|
explicit SoftwareRenderWidget(GRenderWindow* parent, Core::System& system_)
|
||||||
: RenderWidget(parent), system(system_) {}
|
: RenderWidget(parent), system(system_) {}
|
||||||
|
|
||||||
void Present() override {
|
void Present() {
|
||||||
if (!isVisible()) {
|
if (!isVisible()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -323,6 +338,11 @@ struct SoftwareRenderWidget : public RenderWidget {
|
|||||||
painter.end();
|
painter.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* event) override {
|
||||||
|
Present();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
QImage LoadFramebuffer(VideoCore::ScreenId screen_id) {
|
QImage LoadFramebuffer(VideoCore::ScreenId screen_id) {
|
||||||
const auto& renderer = static_cast<SwRenderer::RendererSoftware&>(system.Renderer());
|
const auto& renderer = static_cast<SwRenderer::RendererSoftware&>(system.Renderer());
|
||||||
const auto& info = renderer.Screen(screen_id);
|
const auto& info = renderer.Screen(screen_id);
|
||||||
@ -601,6 +621,9 @@ bool GRenderWindow::InitRenderTarget() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Settings::GraphicsAPI::Vulkan:
|
||||||
|
InitializeVulkan();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the Window System information with the new render target
|
// Update the Window System information with the new render target
|
||||||
@ -686,6 +709,13 @@ bool GRenderWindow::InitializeOpenGL() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GRenderWindow::InitializeVulkan() {
|
||||||
|
auto child = new VulkanRenderWidget(this);
|
||||||
|
child_widget = child;
|
||||||
|
child_widget->windowHandle()->create();
|
||||||
|
main_context = std::make_unique<DummyContext>();
|
||||||
|
}
|
||||||
|
|
||||||
void GRenderWindow::InitializeSoftware() {
|
void GRenderWindow::InitializeSoftware() {
|
||||||
child_widget = new SoftwareRenderWidget(this, system);
|
child_widget = new SoftwareRenderWidget(this, system);
|
||||||
main_context = std::make_unique<DummyContext>();
|
main_context = std::make_unique<DummyContext>();
|
||||||
|
@ -187,6 +187,7 @@ private:
|
|||||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||||
|
|
||||||
bool InitializeOpenGL();
|
bool InitializeOpenGL();
|
||||||
|
void InitializeVulkan();
|
||||||
void InitializeSoftware();
|
void InitializeSoftware();
|
||||||
bool LoadOpenGL();
|
bool LoadOpenGL();
|
||||||
|
|
||||||
|
@ -483,6 +483,7 @@ void Config::ReadDebuggingValues() {
|
|||||||
ReadBasicSetting(Settings::values.use_gdbstub);
|
ReadBasicSetting(Settings::values.use_gdbstub);
|
||||||
ReadBasicSetting(Settings::values.gdbstub_port);
|
ReadBasicSetting(Settings::values.gdbstub_port);
|
||||||
ReadBasicSetting(Settings::values.renderer_debug);
|
ReadBasicSetting(Settings::values.renderer_debug);
|
||||||
|
ReadBasicSetting(Settings::values.dump_command_buffers);
|
||||||
|
|
||||||
qt_config->beginGroup(QStringLiteral("LLE"));
|
qt_config->beginGroup(QStringLiteral("LLE"));
|
||||||
for (const auto& service_module : Service::service_module_map) {
|
for (const auto& service_module : Service::service_module_map) {
|
||||||
@ -627,6 +628,10 @@ void Config::ReadRendererValues() {
|
|||||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||||
|
|
||||||
ReadGlobalSetting(Settings::values.graphics_api);
|
ReadGlobalSetting(Settings::values.graphics_api);
|
||||||
|
ReadGlobalSetting(Settings::values.physical_device);
|
||||||
|
ReadGlobalSetting(Settings::values.spirv_shader_gen);
|
||||||
|
ReadGlobalSetting(Settings::values.async_shader_compilation);
|
||||||
|
ReadGlobalSetting(Settings::values.async_presentation);
|
||||||
ReadGlobalSetting(Settings::values.use_hw_shader);
|
ReadGlobalSetting(Settings::values.use_hw_shader);
|
||||||
ReadGlobalSetting(Settings::values.shaders_accurate_mul);
|
ReadGlobalSetting(Settings::values.shaders_accurate_mul);
|
||||||
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
|
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
|
||||||
@ -1107,6 +1112,10 @@ void Config::SaveRendererValues() {
|
|||||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||||
|
|
||||||
WriteGlobalSetting(Settings::values.graphics_api);
|
WriteGlobalSetting(Settings::values.graphics_api);
|
||||||
|
WriteGlobalSetting(Settings::values.physical_device);
|
||||||
|
WriteGlobalSetting(Settings::values.spirv_shader_gen);
|
||||||
|
WriteGlobalSetting(Settings::values.async_shader_compilation);
|
||||||
|
WriteGlobalSetting(Settings::values.async_presentation);
|
||||||
WriteGlobalSetting(Settings::values.use_hw_shader);
|
WriteGlobalSetting(Settings::values.use_hw_shader);
|
||||||
WriteGlobalSetting(Settings::values.shaders_accurate_mul);
|
WriteGlobalSetting(Settings::values.shaders_accurate_mul);
|
||||||
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
|
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
|
||||||
@ -1269,7 +1278,7 @@ void Config::SaveUpdaterValues() {
|
|||||||
void Config::SaveWebServiceValues() {
|
void Config::SaveWebServiceValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("WebService"));
|
qt_config->beginGroup(QStringLiteral("WebService"));
|
||||||
|
|
||||||
WriteSetting(QStringLiteral("enable_telemetry"), NetSettings::values.enable_telemetry, true);
|
WriteSetting(QStringLiteral("enable_telemetry"), NetSettings::values.enable_telemetry, false);
|
||||||
WriteSetting(QStringLiteral("web_api_url"),
|
WriteSetting(QStringLiteral("web_api_url"),
|
||||||
QString::fromStdString(NetSettings::values.web_api_url),
|
QString::fromStdString(NetSettings::values.web_api_url),
|
||||||
QStringLiteral("https://api.citra-emu.org"));
|
QStringLiteral("https://api.citra-emu.org"));
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include "citra_qt/configuration/configuration_shared.h"
|
#include "citra_qt/configuration/configuration_shared.h"
|
||||||
#include "citra_qt/configuration/configure_debug.h"
|
#include "citra_qt/configuration/configure_debug.h"
|
||||||
@ -12,6 +13,7 @@
|
|||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "ui_configure_debug.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,
|
// 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
|
// so we can just convert from the sliders range (0 - 79) to the expected
|
||||||
@ -34,8 +36,39 @@ ConfigureDebug::ConfigureDebug(bool is_powered_on_, QWidget* parent)
|
|||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ui->toggle_cpu_jit->setEnabled(!is_powered_on);
|
ui->toggle_cpu_jit->setEnabled(!is_powered_on);
|
||||||
ui->toggle_renderer_debug->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.
|
// 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%")
|
// This scales across DPIs. (This value should be enough for "xxx%")
|
||||||
@ -62,6 +95,7 @@ void ConfigureDebug::SetConfiguration() {
|
|||||||
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
|
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_cpu_jit->setChecked(Settings::values.use_cpu_jit.GetValue());
|
||||||
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug.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::IsConfiguringGlobal()) {
|
||||||
if (Settings::values.cpu_clock_percentage.UsingGlobal()) {
|
if (Settings::values.cpu_clock_percentage.UsingGlobal()) {
|
||||||
@ -92,6 +126,7 @@ void ConfigureDebug::ApplyConfiguration() {
|
|||||||
Common::Log::SetGlobalFilter(filter);
|
Common::Log::SetGlobalFilter(filter);
|
||||||
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
|
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
|
||||||
Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked();
|
Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked();
|
||||||
|
Settings::values.dump_command_buffers = ui->toggle_dump_command_buffers->isChecked();
|
||||||
|
|
||||||
ConfigurationShared::ApplyPerGameSetting(
|
ConfigurationShared::ApplyPerGameSetting(
|
||||||
&Settings::values.cpu_clock_percentage, ui->clock_speed_combo,
|
&Settings::values.cpu_clock_percentage, ui->clock_speed_combo,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>523</width>
|
<width>523</width>
|
||||||
<height>447</height>
|
<height>458</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -112,16 +112,6 @@
|
|||||||
<string>CPU</string>
|
<string>CPU</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QCheckBox" name="toggle_cpu_jit">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p>Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Enable CPU JIT</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QWidget" name="clock_speed_widget" native="true">
|
<widget class="QWidget" name="clock_speed_widget" native="true">
|
||||||
<layout class="QHBoxLayout" name="clock_speed_layout">
|
<layout class="QHBoxLayout" name="clock_speed_layout">
|
||||||
@ -202,6 +192,16 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="toggle_cpu_jit">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable CPU JIT</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QCheckBox" name="toggle_renderer_debug">
|
<widget class="QCheckBox" name="toggle_renderer_debug">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -209,6 +209,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QCheckBox" name="toggle_dump_command_buffers">
|
||||||
|
<property name="text">
|
||||||
|
<string>Dump command buffers</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -23,14 +23,14 @@
|
|||||||
#include "ui_configure.h"
|
#include "ui_configure.h"
|
||||||
|
|
||||||
ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Core::System& system_,
|
ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Core::System& system_,
|
||||||
bool enable_web_config)
|
std::span<const QString> physical_devices, bool enable_web_config)
|
||||||
: QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()}, registry{registry_},
|
: QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()}, registry{registry_},
|
||||||
system{system_}, is_powered_on{system.IsPoweredOn()},
|
system{system_}, is_powered_on{system.IsPoweredOn()},
|
||||||
general_tab{std::make_unique<ConfigureGeneral>(this)},
|
general_tab{std::make_unique<ConfigureGeneral>(this)},
|
||||||
system_tab{std::make_unique<ConfigureSystem>(system, this)},
|
system_tab{std::make_unique<ConfigureSystem>(system, this)},
|
||||||
input_tab{std::make_unique<ConfigureInput>(this)},
|
input_tab{std::make_unique<ConfigureInput>(this)},
|
||||||
hotkeys_tab{std::make_unique<ConfigureHotkeys>(this)},
|
hotkeys_tab{std::make_unique<ConfigureHotkeys>(this)},
|
||||||
graphics_tab{std::make_unique<ConfigureGraphics>(is_powered_on, this)},
|
graphics_tab{std::make_unique<ConfigureGraphics>(physical_devices, is_powered_on, this)},
|
||||||
enhancements_tab{std::make_unique<ConfigureEnhancements>(this)},
|
enhancements_tab{std::make_unique<ConfigureEnhancements>(this)},
|
||||||
audio_tab{std::make_unique<ConfigureAudio>(is_powered_on, this)},
|
audio_tab{std::make_unique<ConfigureAudio>(is_powered_on, this)},
|
||||||
camera_tab{std::make_unique<ConfigureCamera>(this)},
|
camera_tab{std::make_unique<ConfigureCamera>(this)},
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class HotkeyRegistry;
|
class HotkeyRegistry;
|
||||||
|
|
||||||
@ -35,6 +37,7 @@ class ConfigureDialog : public QDialog {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, Core::System& system,
|
explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, Core::System& system,
|
||||||
|
std::span<const QString> physical_devices,
|
||||||
bool enable_web_config = true);
|
bool enable_web_config = true);
|
||||||
~ConfigureDialog() override;
|
~ConfigureDialog() override;
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
|
|||||||
|
|
||||||
// Set a minimum width for the label to prevent the slider from changing size.
|
// Set a minimum width for the label to prevent the slider from changing size.
|
||||||
// This scales across DPIs, and is acceptable for uncapitalized strings.
|
// This scales across DPIs, and is acceptable for uncapitalized strings.
|
||||||
ui->emulation_speed_display_label->setMinimumWidth(tr("unthrottled").size() * 6);
|
const auto width = static_cast<int>(tr("unthrottled").size() * 6);
|
||||||
|
ui->emulation_speed_display_label->setMinimumWidth(width);
|
||||||
ui->emulation_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
|
ui->emulation_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
|
||||||
ui->screenshot_combo->setVisible(!Settings::IsConfiguringGlobal());
|
ui->screenshot_combo->setVisible(!Settings::IsConfiguringGlobal());
|
||||||
ui->updateBox->setVisible(UISettings::values.updater_found);
|
ui->updateBox->setVisible(UISettings::values.updater_found);
|
||||||
|
@ -7,16 +7,34 @@
|
|||||||
#include "citra_qt/configuration/configure_graphics.h"
|
#include "citra_qt/configuration/configure_graphics.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "ui_configure_graphics.h"
|
#include "ui_configure_graphics.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||||
|
|
||||||
ConfigureGraphics::ConfigureGraphics(bool is_powered_on, QWidget* parent)
|
ConfigureGraphics::ConfigureGraphics(std::span<const QString> physical_devices, bool is_powered_on,
|
||||||
|
QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureGraphics>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureGraphics>()) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
SetupPerGameUI();
|
||||||
|
|
||||||
|
for (const QString& name : physical_devices) {
|
||||||
|
ui->physical_device_combo->addItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
ui->toggle_vsync_new->setEnabled(!is_powered_on);
|
ui->toggle_vsync_new->setEnabled(!is_powered_on);
|
||||||
ui->graphics_api_combo->setEnabled(!is_powered_on);
|
ui->graphics_api_combo->setEnabled(!is_powered_on);
|
||||||
|
ui->physical_device_combo->setEnabled(!is_powered_on);
|
||||||
|
ui->toggle_async_shaders->setEnabled(!is_powered_on);
|
||||||
|
ui->toggle_async_present->setEnabled(!is_powered_on);
|
||||||
// Set the index to -1 to ensure the below lambda is called with setCurrentIndex
|
// Set the index to -1 to ensure the below lambda is called with setCurrentIndex
|
||||||
ui->graphics_api_combo->setCurrentIndex(-1);
|
ui->graphics_api_combo->setCurrentIndex(-1);
|
||||||
|
|
||||||
|
if (physical_devices.empty()) {
|
||||||
|
const u32 index = static_cast<u32>(Settings::GraphicsAPI::Vulkan);
|
||||||
|
ui->graphics_api_combo->removeItem(index);
|
||||||
|
ui->physical_device_combo->setVisible(false);
|
||||||
|
ui->spirv_shader_gen->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
[this](int index) {
|
[this](int index) {
|
||||||
const auto graphics_api =
|
const auto graphics_api =
|
||||||
@ -35,7 +53,9 @@ ConfigureGraphics::ConfigureGraphics(bool is_powered_on, QWidget* parent)
|
|||||||
ui->toggle_disk_shader_cache->setEnabled(checked && enabled);
|
ui->toggle_disk_shader_cache->setEnabled(checked && enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
SetupPerGameUI();
|
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
|
&ConfigureGraphics::SetPhysicalDeviceComboVisibility);
|
||||||
|
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,15 +67,24 @@ void ConfigureGraphics::SetConfiguration() {
|
|||||||
!Settings::values.graphics_api.UsingGlobal());
|
!Settings::values.graphics_api.UsingGlobal());
|
||||||
ConfigurationShared::SetPerGameSetting(ui->graphics_api_combo,
|
ConfigurationShared::SetPerGameSetting(ui->graphics_api_combo,
|
||||||
&Settings::values.graphics_api);
|
&Settings::values.graphics_api);
|
||||||
|
ConfigurationShared::SetHighlight(ui->physical_device_group,
|
||||||
|
!Settings::values.physical_device.UsingGlobal());
|
||||||
|
ConfigurationShared::SetPerGameSetting(ui->physical_device_combo,
|
||||||
|
&Settings::values.physical_device);
|
||||||
} else {
|
} else {
|
||||||
ui->graphics_api_combo->setCurrentIndex(
|
ui->graphics_api_combo->setCurrentIndex(
|
||||||
static_cast<int>(Settings::values.graphics_api.GetValue()));
|
static_cast<int>(Settings::values.graphics_api.GetValue()));
|
||||||
|
ui->physical_device_combo->setCurrentIndex(
|
||||||
|
static_cast<int>(Settings::values.physical_device.GetValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader.GetValue());
|
ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader.GetValue());
|
||||||
ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul.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_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
|
||||||
ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new.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());
|
||||||
|
ui->toggle_async_present->setChecked(Settings::values.async_presentation.GetValue());
|
||||||
|
|
||||||
if (Settings::IsConfiguringGlobal()) {
|
if (Settings::IsConfiguringGlobal()) {
|
||||||
ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit.GetValue());
|
ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit.GetValue());
|
||||||
@ -65,6 +94,14 @@ void ConfigureGraphics::SetConfiguration() {
|
|||||||
void ConfigureGraphics::ApplyConfiguration() {
|
void ConfigureGraphics::ApplyConfiguration() {
|
||||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api,
|
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api,
|
||||||
ui->graphics_api_combo);
|
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.async_presentation,
|
||||||
|
ui->toggle_async_present, async_presentation);
|
||||||
|
ConfigurationShared::ApplyPerGameSetting(&Settings::values.spirv_shader_gen,
|
||||||
|
ui->spirv_shader_gen, spirv_shader_gen);
|
||||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_hw_shader, ui->toggle_hw_shader,
|
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_hw_shader, ui->toggle_hw_shader,
|
||||||
use_hw_shader);
|
use_hw_shader);
|
||||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.shaders_accurate_mul,
|
ConfigurationShared::ApplyPerGameSetting(&Settings::values.shaders_accurate_mul,
|
||||||
@ -93,6 +130,11 @@ void ConfigureGraphics::SetupPerGameUI() {
|
|||||||
Settings::values.use_disk_shader_cache.UsingGlobal());
|
Settings::values.use_disk_shader_cache.UsingGlobal());
|
||||||
ui->toggle_vsync_new->setEnabled(ui->toggle_vsync_new->isEnabled() &&
|
ui->toggle_vsync_new->setEnabled(ui->toggle_vsync_new->isEnabled() &&
|
||||||
Settings::values.use_vsync_new.UsingGlobal());
|
Settings::values.use_vsync_new.UsingGlobal());
|
||||||
|
ui->toggle_async_shaders->setEnabled(
|
||||||
|
Settings::values.async_shader_compilation.UsingGlobal());
|
||||||
|
ui->toggle_async_present->setEnabled(Settings::values.async_presentation.UsingGlobal());
|
||||||
|
ui->graphics_api_combo->setEnabled(Settings::values.graphics_api.UsingGlobal());
|
||||||
|
ui->physical_device_combo->setEnabled(Settings::values.physical_device.UsingGlobal());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +144,10 @@ void ConfigureGraphics::SetupPerGameUI() {
|
|||||||
ui->graphics_api_combo, ui->graphics_api_group,
|
ui->graphics_api_combo, ui->graphics_api_group,
|
||||||
static_cast<u32>(Settings::values.graphics_api.GetValue(true)));
|
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_shader, Settings::values.use_hw_shader,
|
ConfigurationShared::SetColoredTristate(ui->toggle_hw_shader, Settings::values.use_hw_shader,
|
||||||
use_hw_shader);
|
use_hw_shader);
|
||||||
ConfigurationShared::SetColoredTristate(
|
ConfigurationShared::SetColoredTristate(
|
||||||
@ -111,4 +157,34 @@ void ConfigureGraphics::SetupPerGameUI() {
|
|||||||
use_disk_shader_cache);
|
use_disk_shader_cache);
|
||||||
ConfigurationShared::SetColoredTristate(ui->toggle_vsync_new, Settings::values.use_vsync_new,
|
ConfigurationShared::SetColoredTristate(ui->toggle_vsync_new, Settings::values.use_vsync_new,
|
||||||
use_vsync_new);
|
use_vsync_new);
|
||||||
|
ConfigurationShared::SetColoredTristate(ui->toggle_async_shaders,
|
||||||
|
Settings::values.async_shader_compilation,
|
||||||
|
async_shader_compilation);
|
||||||
|
ConfigurationShared::SetColoredTristate(
|
||||||
|
ui->toggle_async_present, Settings::values.async_presentation, async_presentation);
|
||||||
|
ConfigurationShared::SetColoredTristate(ui->spirv_shader_gen, Settings::values.spirv_shader_gen,
|
||||||
|
spirv_shader_gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureGraphics::SetPhysicalDeviceComboVisibility(int index) {
|
||||||
|
bool is_visible{};
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
#include <QString>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@ -19,7 +21,8 @@ class ConfigureGraphics : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureGraphics(bool is_powered_on, QWidget* parent = nullptr);
|
explicit ConfigureGraphics(std::span<const QString> physical_devices, bool is_powered_on,
|
||||||
|
QWidget* parent = nullptr);
|
||||||
~ConfigureGraphics() override;
|
~ConfigureGraphics() override;
|
||||||
|
|
||||||
void ApplyConfiguration();
|
void ApplyConfiguration();
|
||||||
@ -30,11 +33,15 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void SetupPerGameUI();
|
void SetupPerGameUI();
|
||||||
|
void SetPhysicalDeviceComboVisibility(int index);
|
||||||
|
|
||||||
ConfigurationShared::CheckState use_hw_shader;
|
ConfigurationShared::CheckState use_hw_shader;
|
||||||
ConfigurationShared::CheckState shaders_accurate_mul;
|
ConfigurationShared::CheckState shaders_accurate_mul;
|
||||||
ConfigurationShared::CheckState use_disk_shader_cache;
|
ConfigurationShared::CheckState use_disk_shader_cache;
|
||||||
ConfigurationShared::CheckState use_vsync_new;
|
ConfigurationShared::CheckState use_vsync_new;
|
||||||
|
ConfigurationShared::CheckState async_shader_compilation;
|
||||||
|
ConfigurationShared::CheckState async_presentation;
|
||||||
|
ConfigurationShared::CheckState spirv_shader_gen;
|
||||||
std::unique_ptr<Ui::ConfigureGraphics> ui;
|
std::unique_ptr<Ui::ConfigureGraphics> ui;
|
||||||
QColor bg_color;
|
QColor bg_color;
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
<height>443</height>
|
<height>509</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
@ -63,11 +63,51 @@
|
|||||||
<string>OpenGL</string>
|
<string>OpenGL</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Vulkan</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -95,7 +135,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="toggle_hw_shader">
|
<widget class="QCheckBox" name="toggle_hw_shader">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Use OpenGL to accelerate shader emulation.</p><p>Requires a relatively powerful GPU for better performance.</p></body></html></string>
|
<string><html><head/><body><p>Use the selected graphics API to accelerate shader emulation.</p><p>Requires a relatively powerful GPU for better performance.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Enable Hardware Shader</string>
|
<string>Enable Hardware Shader</string>
|
||||||
@ -143,6 +183,26 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="toggle_async_shaders">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Compile shaders using background threads to avoid shader compilation stutter. Expect temporary graphical glitches</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Async Shader Compilation</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="toggle_async_present">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Perform presentation on separate threads. Improves performance when using Vulkan in most games.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Async Presentation</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#include "ui_configure_per_game.h"
|
#include "ui_configure_per_game.h"
|
||||||
|
|
||||||
ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString& file_name,
|
ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString& file_name,
|
||||||
Core::System& system_)
|
std::span<const QString> physical_devices, Core::System& system_)
|
||||||
: QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()),
|
: QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()),
|
||||||
filename{file_name.toStdString()}, title_id{title_id_}, system{system_} {
|
filename{file_name.toStdString()}, title_id{title_id_}, system{system_} {
|
||||||
const auto config_file_name = title_id == 0 ? std::string(FileUtil::GetFilename(filename))
|
const auto config_file_name = title_id == 0 ? std::string(FileUtil::GetFilename(filename))
|
||||||
@ -35,7 +35,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString
|
|||||||
audio_tab = std::make_unique<ConfigureAudio>(is_powered_on, this);
|
audio_tab = std::make_unique<ConfigureAudio>(is_powered_on, this);
|
||||||
general_tab = std::make_unique<ConfigureGeneral>(this);
|
general_tab = std::make_unique<ConfigureGeneral>(this);
|
||||||
enhancements_tab = std::make_unique<ConfigureEnhancements>(this);
|
enhancements_tab = std::make_unique<ConfigureEnhancements>(this);
|
||||||
graphics_tab = std::make_unique<ConfigureGraphics>(is_powered_on, this);
|
graphics_tab = std::make_unique<ConfigureGraphics>(physical_devices, is_powered_on, this);
|
||||||
system_tab = std::make_unique<ConfigureSystem>(system, this);
|
system_tab = std::make_unique<ConfigureSystem>(system, this);
|
||||||
debug_tab = std::make_unique<ConfigureDebug>(is_powered_on, this);
|
debug_tab = std::make_unique<ConfigureDebug>(is_powered_on, this);
|
||||||
cheat_tab = std::make_unique<ConfigureCheats>(system, title_id, this);
|
cheat_tab = std::make_unique<ConfigureCheats>(system, title_id, this);
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
#include "citra_qt/configuration/config.h"
|
#include "citra_qt/configuration/config.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -35,9 +37,8 @@ class ConfigurePerGame : public QDialog {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263
|
|
||||||
explicit ConfigurePerGame(QWidget* parent, u64 title_id_, const QString& file_name,
|
explicit ConfigurePerGame(QWidget* parent, u64 title_id_, const QString& file_name,
|
||||||
Core::System& system_);
|
std::span<const QString> physical_devices, Core::System& system_);
|
||||||
~ConfigurePerGame() override;
|
~ConfigurePerGame() override;
|
||||||
|
|
||||||
/// Loads all button configurations to settings file
|
/// Loads all button configurations to settings file
|
||||||
|
@ -285,12 +285,12 @@ void ConfigureSystem::SetConfiguration() {
|
|||||||
date_time.setSecsSinceEpoch(Settings::values.init_time.GetValue());
|
date_time.setSecsSinceEpoch(Settings::values.init_time.GetValue());
|
||||||
ui->edit_init_time->setDateTime(date_time);
|
ui->edit_init_time->setDateTime(date_time);
|
||||||
|
|
||||||
long long init_time_offset = Settings::values.init_time_offset.GetValue();
|
s64 init_time_offset = Settings::values.init_time_offset.GetValue();
|
||||||
long long days_offset = init_time_offset / 86400;
|
int days_offset = static_cast<int>(init_time_offset / 86400);
|
||||||
ui->edit_init_time_offset_days->setValue(days_offset);
|
ui->edit_init_time_offset_days->setValue(days_offset);
|
||||||
|
|
||||||
unsigned long long time_offset = std::abs(init_time_offset) - std::abs(days_offset * 86400);
|
u64 time_offset = std::abs(init_time_offset) - std::abs(days_offset * 86400);
|
||||||
QTime time = QTime::fromMSecsSinceStartOfDay(time_offset * 1000);
|
QTime time = QTime::fromMSecsSinceStartOfDay(static_cast<int>(time_offset * 1000));
|
||||||
ui->edit_init_time_offset_time->setTime(time);
|
ui->edit_init_time_offset_time->setTime(time);
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
|
@ -180,9 +180,10 @@ void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size
|
|||||||
}
|
}
|
||||||
const auto eta_mseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
|
const auto eta_mseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
rolling_average * (total - value));
|
rolling_average * (total - value));
|
||||||
|
const auto limited_mseconds = std::max<long>(eta_mseconds.count(), 1000);
|
||||||
estimate = tr("Estimated Time %1")
|
estimate = tr("Estimated Time %1")
|
||||||
.arg(QTime(0, 0, 0, 0)
|
.arg(QTime(0, 0, 0, 0)
|
||||||
.addMSecs(std::max<long>(eta_mseconds.count(), 1000))
|
.addMSecs(static_cast<int>(limited_mseconds))
|
||||||
.toString(QStringLiteral("mm:ss")));
|
.toString(QStringLiteral("mm:ss")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
#include "citra_qt/uisettings.h"
|
#include "citra_qt/uisettings.h"
|
||||||
#include "citra_qt/updater/updater.h"
|
#include "citra_qt/updater/updater.h"
|
||||||
#include "citra_qt/util/clickable_label.h"
|
#include "citra_qt/util/clickable_label.h"
|
||||||
|
#include "citra_qt/util/vk_device_info.h"
|
||||||
#include "common/arch.h"
|
#include "common/arch.h"
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
#include "common/detached_tasks.h"
|
#include "common/detached_tasks.h"
|
||||||
@ -263,6 +264,14 @@ GMainWindow::GMainWindow(Core::System& system_)
|
|||||||
connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor);
|
connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor);
|
||||||
connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::OnMouseActivity);
|
connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::OnMouseActivity);
|
||||||
|
|
||||||
|
physical_devices = GetVulkanPhysicalDevices();
|
||||||
|
if (physical_devices.empty()) {
|
||||||
|
QMessageBox::warning(this, tr("No Suitable Vulkan Devices Detected"),
|
||||||
|
tr("Vulkan initialization failed during boot.<br/>"
|
||||||
|
"Your GPU may not support Vulkan 1.1, or you do not "
|
||||||
|
"have the latest graphics driver."));
|
||||||
|
}
|
||||||
|
|
||||||
#if ENABLE_QT_UPDATER
|
#if ENABLE_QT_UPDATER
|
||||||
if (UISettings::values.check_for_update_on_start) {
|
if (UISettings::values.check_for_update_on_start) {
|
||||||
CheckForUpdates();
|
CheckForUpdates();
|
||||||
@ -2010,7 +2019,7 @@ void GMainWindow::OnLoadState() {
|
|||||||
void GMainWindow::OnConfigure() {
|
void GMainWindow::OnConfigure() {
|
||||||
game_list->SetDirectoryWatcherEnabled(false);
|
game_list->SetDirectoryWatcherEnabled(false);
|
||||||
Settings::SetConfiguringGlobal(true);
|
Settings::SetConfiguringGlobal(true);
|
||||||
ConfigureDialog configureDialog(this, hotkey_registry, system,
|
ConfigureDialog configureDialog(this, hotkey_registry, system, physical_devices,
|
||||||
!multiplayer_state->IsHostingPublicRoom());
|
!multiplayer_state->IsHostingPublicRoom());
|
||||||
connect(&configureDialog, &ConfigureDialog::LanguageChanged, this,
|
connect(&configureDialog, &ConfigureDialog::LanguageChanged, this,
|
||||||
&GMainWindow::OnLanguageChanged);
|
&GMainWindow::OnLanguageChanged);
|
||||||
@ -2470,9 +2479,11 @@ void GMainWindow::ShowMouseCursor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::UpdateAPIIndicator(bool update) {
|
void GMainWindow::UpdateAPIIndicator(bool update) {
|
||||||
static std::array graphics_apis = {QStringLiteral("SOFTWARE"), QStringLiteral("OPENGL")};
|
static std::array graphics_apis = {QStringLiteral("SOFTWARE"), QStringLiteral("OPENGL"),
|
||||||
|
QStringLiteral("VULKAN")};
|
||||||
|
|
||||||
static std::array graphics_api_colors = {QStringLiteral("#3ae400"), QStringLiteral("#00ccdd")};
|
static std::array graphics_api_colors = {QStringLiteral("#3ae400"), QStringLiteral("#00ccdd"),
|
||||||
|
QStringLiteral("#91242a")};
|
||||||
|
|
||||||
u32 api_index = static_cast<u32>(Settings::values.graphics_api.GetValue());
|
u32 api_index = static_cast<u32>(Settings::values.graphics_api.GetValue());
|
||||||
if (update) {
|
if (update) {
|
||||||
@ -2764,7 +2775,7 @@ void GMainWindow::OnConfigurePerGame() {
|
|||||||
|
|
||||||
void GMainWindow::OpenPerGameConfiguration(u64 title_id, const QString& file_name) {
|
void GMainWindow::OpenPerGameConfiguration(u64 title_id, const QString& file_name) {
|
||||||
Settings::SetConfiguringGlobal(false);
|
Settings::SetConfiguringGlobal(false);
|
||||||
ConfigurePerGame dialog(this, title_id, file_name, system);
|
ConfigurePerGame dialog(this, title_id, file_name, physical_devices, system);
|
||||||
const auto result = dialog.exec();
|
const auto result = dialog.exec();
|
||||||
|
|
||||||
if (result != QDialog::Accepted) {
|
if (result != QDialog::Accepted) {
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QString>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
#include "citra_qt/compatibility_list.h"
|
#include "citra_qt/compatibility_list.h"
|
||||||
@ -326,6 +328,8 @@ private:
|
|||||||
// Whether game was paused due to stopping video dumping
|
// Whether game was paused due to stopping video dumping
|
||||||
bool game_paused_for_dumping = false;
|
bool game_paused_for_dumping = false;
|
||||||
|
|
||||||
|
std::vector<QString> physical_devices;
|
||||||
|
|
||||||
// Debugger panes
|
// Debugger panes
|
||||||
ProfilerWidget* profilerWidget;
|
ProfilerWidget* profilerWidget;
|
||||||
MicroProfileDialog* microProfileDialog;
|
MicroProfileDialog* microProfileDialog;
|
||||||
|
@ -125,8 +125,8 @@ void MoviePlayDialog::UpdateUIDisplay() {
|
|||||||
} else {
|
} else {
|
||||||
const u64 msecs = Service::HID::Module::pad_update_ticks * metadata.input_count * 1000 /
|
const u64 msecs = Service::HID::Module::pad_update_ticks * metadata.input_count * 1000 /
|
||||||
BASE_CLOCK_RATE_ARM11;
|
BASE_CLOCK_RATE_ARM11;
|
||||||
ui->lengthLineEdit->setText(
|
ui->lengthLineEdit->setText(QTime::fromMSecsSinceStartOfDay(static_cast<int>(msecs))
|
||||||
QTime::fromMSecsSinceStartOfDay(msecs).toString(QStringLiteral("hh:mm:ss.zzz")));
|
.toString(QStringLiteral("hh:mm:ss.zzz")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,7 +284,7 @@ bool LobbyFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
|
|||||||
// filter by empty rooms
|
// filter by empty rooms
|
||||||
if (filter_empty) {
|
if (filter_empty) {
|
||||||
QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent);
|
QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent);
|
||||||
const int player_count =
|
const qsizetype player_count =
|
||||||
sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size();
|
sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size();
|
||||||
if (player_count == 0) {
|
if (player_count == 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -294,7 +294,7 @@ bool LobbyFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
|
|||||||
// filter by filled rooms
|
// filter by filled rooms
|
||||||
if (filter_full) {
|
if (filter_full) {
|
||||||
QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent);
|
QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent);
|
||||||
const int player_count =
|
const qsizetype player_count =
|
||||||
sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size();
|
sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size();
|
||||||
const int max_players =
|
const int max_players =
|
||||||
sourceModel()->data(member_list, LobbyItemMemberList::MaxPlayerRole).toInt();
|
sourceModel()->data(member_list, LobbyItemMemberList::MaxPlayerRole).toInt();
|
||||||
|
@ -198,8 +198,8 @@ public:
|
|||||||
|
|
||||||
bool operator<(const QStandardItem& other) const override {
|
bool operator<(const QStandardItem& other) const override {
|
||||||
// sort by rooms that have the most players
|
// sort by rooms that have the most players
|
||||||
int left_members = data(MemberListRole).toList().size();
|
qsizetype left_members = data(MemberListRole).toList().size();
|
||||||
int right_members = other.data(MemberListRole).toList().size();
|
qsizetype right_members = other.data(MemberListRole).toList().size();
|
||||||
return left_members < right_members;
|
return left_members < right_members;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "citra_qt/uisettings.h"
|
#include "citra_qt/uisettings.h"
|
||||||
#include "citra_qt/updater/updater.h"
|
#include "citra_qt/updater/updater.h"
|
||||||
#include "citra_qt/updater/updater_p.h"
|
#include "citra_qt/updater/updater_p.h"
|
||||||
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
|
||||||
#ifdef Q_OS_OSX
|
#ifdef Q_OS_OSX
|
||||||
@ -110,9 +111,22 @@ QString UpdaterPrivate::ToSystemExe(QString base_path) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFileInfo UpdaterPrivate::GetMaintenanceTool() const {
|
||||||
|
#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
|
||||||
|
const auto appimage_path = QProcessEnvironment::systemEnvironment()
|
||||||
|
.value(QStringLiteral("APPIMAGE"), {})
|
||||||
|
.toStdString();
|
||||||
|
if (!appimage_path.empty()) {
|
||||||
|
const auto appimage_dir = FileUtil::GetParentPath(appimage_path);
|
||||||
|
LOG_DEBUG(Frontend, "Detected app image directory: {}", appimage_dir);
|
||||||
|
return QFileInfo(QString::fromStdString(std::string(appimage_dir)), tool_path);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return QFileInfo(QCoreApplication::applicationDirPath(), tool_path);
|
||||||
|
}
|
||||||
|
|
||||||
bool UpdaterPrivate::HasUpdater() const {
|
bool UpdaterPrivate::HasUpdater() const {
|
||||||
QFileInfo tool_info(QCoreApplication::applicationDirPath(), tool_path);
|
return GetMaintenanceTool().exists();
|
||||||
return tool_info.exists();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdaterPrivate::StartUpdateCheck() {
|
bool UpdaterPrivate::StartUpdateCheck() {
|
||||||
@ -125,10 +139,9 @@ bool UpdaterPrivate::StartUpdateCheck() {
|
|||||||
last_error_code = EXIT_SUCCESS;
|
last_error_code = EXIT_SUCCESS;
|
||||||
last_error_log.clear();
|
last_error_log.clear();
|
||||||
|
|
||||||
QFileInfo tool_info(QCoreApplication::applicationDirPath(), tool_path);
|
|
||||||
main_process = new QProcess(this);
|
main_process = new QProcess(this);
|
||||||
main_process->setProgram(tool_info.absoluteFilePath());
|
main_process->setProgram(GetMaintenanceTool().absoluteFilePath());
|
||||||
main_process->setArguments({QStringLiteral("--checkupdates"), QStringLiteral("-v")});
|
main_process->setArguments({QStringLiteral("--checkupdates")});
|
||||||
|
|
||||||
connect(main_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
connect(main_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
||||||
&UpdaterPrivate::UpdaterReady, Qt::QueuedConnection);
|
&UpdaterPrivate::UpdaterReady, Qt::QueuedConnection);
|
||||||
@ -271,7 +284,7 @@ void UpdaterPrivate::LaunchWithArguments(const QStringList& args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileInfo tool_info(QCoreApplication::applicationDirPath(), tool_path);
|
QFileInfo tool_info = GetMaintenanceTool();
|
||||||
|
|
||||||
if (!QProcess::startDetached(tool_info.absoluteFilePath(), args, tool_info.absolutePath())) {
|
if (!QProcess::startDetached(tool_info.absoluteFilePath(), args, tool_info.absolutePath())) {
|
||||||
LOG_WARNING(Frontend, "Unable to start program {}",
|
LOG_WARNING(Frontend, "Unable to start program {}",
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
|
|
||||||
static QString ToSystemExe(QString base_path);
|
static QString ToSystemExe(QString base_path);
|
||||||
|
|
||||||
|
QFileInfo GetMaintenanceTool() const;
|
||||||
bool HasUpdater() const;
|
bool HasUpdater() const;
|
||||||
|
|
||||||
bool StartUpdateCheck();
|
bool StartUpdateCheck();
|
||||||
|
@ -194,7 +194,7 @@ QString CSpinBox::TextFromValue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
qint64 CSpinBox::ValueFromText() {
|
qint64 CSpinBox::ValueFromText() {
|
||||||
unsigned strpos = prefix.length();
|
qsizetype strpos = prefix.length();
|
||||||
|
|
||||||
QString num_string = text().mid(strpos, text().length() - strpos - suffix.length());
|
QString num_string = text().mid(strpos, text().length() - strpos - suffix.length());
|
||||||
return num_string.toLongLong(nullptr, base);
|
return num_string.toLongLong(nullptr, base);
|
||||||
@ -216,7 +216,7 @@ QValidator::State CSpinBox::validate(QString& input, int& pos) const {
|
|||||||
if (!prefix.isEmpty() && input.left(prefix.length()) != prefix)
|
if (!prefix.isEmpty() && input.left(prefix.length()) != prefix)
|
||||||
return QValidator::Invalid;
|
return QValidator::Invalid;
|
||||||
|
|
||||||
int strpos = prefix.length();
|
qsizetype strpos = prefix.length();
|
||||||
|
|
||||||
// Empty "numbers" allowed as intermediate values
|
// Empty "numbers" allowed as intermediate values
|
||||||
if (strpos >= input.length() - HasSign() - suffix.length())
|
if (strpos >= input.length() - HasSign() - suffix.length())
|
||||||
@ -245,7 +245,7 @@ QValidator::State CSpinBox::validate(QString& input, int& pos) const {
|
|||||||
|
|
||||||
// Match string
|
// Match string
|
||||||
QRegularExpression num_regexp(QRegularExpression::anchoredPattern(regexp));
|
QRegularExpression num_regexp(QRegularExpression::anchoredPattern(regexp));
|
||||||
int num_pos = strpos;
|
qsizetype num_pos = strpos;
|
||||||
QString sub_input = input.mid(strpos, input.length() - strpos - suffix.length());
|
QString sub_input = input.mid(strpos, input.length() - strpos - suffix.length());
|
||||||
|
|
||||||
auto match = num_regexp.match(sub_input);
|
auto match = num_regexp.match(sub_input);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user