Compare commits
123 Commits
tev-jit
...
vulkan-but
Author | SHA1 | Date | |
---|---|---|---|
dcc51d5526 | |||
164d85709c | |||
eb6ef052d5 | |||
868dc0c11f | |||
f17f127f46 | |||
5c3f6e3b72 | |||
da891af113 | |||
ba89673d77 | |||
cc9768963a | |||
37f5d66c10 | |||
6bfe1daac7 | |||
bcbce50120 | |||
a608e33593 | |||
ff10decc2c | |||
78050813c4 | |||
b758dd214a | |||
8267da3874 | |||
9e7ae03b6c | |||
631c777983 | |||
622c20761c | |||
d22d556d30 | |||
c281c1a5cc | |||
fd38e33fb2 | |||
66c5f59627 | |||
faf6b36f3b | |||
dd71859818 | |||
fe724600ab | |||
a12b01105d | |||
8c05a52a65 | |||
e5ba2abd1c | |||
8421be7ebf | |||
ba9f1f8ae9 | |||
6c391971c6 | |||
85dd604a7e | |||
edd8de29ae | |||
89226eea2a | |||
59549a2eb6 | |||
a8d590ae80 | |||
6b51afaf1f | |||
a67bfe544d | |||
bbb47cd753 | |||
0b0d3a4ac3 | |||
6aa31d6ec2 | |||
3e254d01ee | |||
928f352c94 | |||
e2d8eef5fa | |||
9e898bca06 | |||
cab0ad50f0 | |||
5ad58e0605 | |||
1159e4d928 | |||
93c7c6a995 | |||
81a5e2355a | |||
d2260bafef | |||
d1f600601d | |||
8b218e1b7d | |||
04aeecabcf | |||
df57012c50 | |||
61cf550d0c | |||
f2e0748a22 | |||
edf157200d | |||
a94297922b | |||
894c1c85a5 | |||
e129f07047 | |||
cf54210f42 | |||
b2092de871 | |||
6ddf4b241f | |||
f3d92dd3b8 | |||
1a6860f35c | |||
bc0bf4d3d2 | |||
1d3bf64f13 | |||
c3609785ff | |||
66404a669f | |||
6a1fd38063 | |||
a27971e723 | |||
eb8d2941c9 | |||
af78268dd5 | |||
baca2bfc6b | |||
33a2113b71 | |||
1f07ab8643 | |||
b739bd2632 | |||
f76165d848 | |||
ac78b74c45 | |||
a478bedb12 | |||
6d0cd5b00e | |||
5b52849f90 | |||
20f4677f80 | |||
0048e61fc7 | |||
aaeba6759e | |||
ebac2e4978 | |||
5b9f4d4129 | |||
b1b6f08926 | |||
7e6a761f07 | |||
6f7612f73d | |||
88ea66053e | |||
970f2284d8 | |||
baf3ea4beb | |||
35e208b447 | |||
f8b8b6e53c | |||
a955f02771 | |||
3fedc68230 | |||
335fb78c5c | |||
22c4eb86d7 | |||
964f9ee3cf | |||
bb364d9bc0 | |||
51996c54f0 | |||
539a1a0b6e | |||
8b21b902f2 | |||
19107cec4b | |||
a537f56766 | |||
b5e1a27a7e | |||
a9e390b1b1 | |||
71582a72a4 | |||
e783b0d4a9 | |||
700c00f021 | |||
9cb14044ec | |||
8b6b58a364 | |||
e043caac27 | |||
0bedb28bdc | |||
c10ffda91f | |||
5e8ae4fa8a | |||
7a7f485640 | |||
bbf833bceb | |||
8eebb83c2c |
@ -7,13 +7,6 @@ REV_NAME="citra-${OS}-${TARGET}-${GITDATE}-${GITREV}"
|
|||||||
# Find out what release we are building
|
# Find out what release we are building
|
||||||
if [[ "$GITHUB_REF_NAME" =~ ^canary- ]] || [[ "$GITHUB_REF_NAME" =~ ^nightly- ]]; then
|
if [[ "$GITHUB_REF_NAME" =~ ^canary- ]] || [[ "$GITHUB_REF_NAME" =~ ^nightly- ]]; then
|
||||||
RELEASE_NAME=$(echo $GITHUB_REF_NAME | cut -d- -f1)
|
RELEASE_NAME=$(echo $GITHUB_REF_NAME | cut -d- -f1)
|
||||||
# For compatibility with existing installs, use mingw/osx in the archive and target names.
|
|
||||||
if [ "$TARGET" = "msys2" ]; then
|
|
||||||
REV_NAME="citra-${OS}-mingw-${GITDATE}-${GITREV}"
|
|
||||||
RELEASE_NAME="${RELEASE_NAME}-mingw"
|
|
||||||
elif [ "$OS" = "macos" ]; then
|
|
||||||
REV_NAME="citra-osx-${TARGET}-${GITDATE}-${GITREV}"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
RELEASE_NAME=head
|
RELEASE_NAME=head
|
||||||
fi
|
fi
|
||||||
|
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
@ -158,12 +158,24 @@ jobs:
|
|||||||
key: ${{ runner.os }}-${{ matrix.target }}-${{ github.sha }}
|
key: ${{ runner.os }}-${{ matrix.target }}-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-${{ matrix.target }}-
|
${{ runner.os }}-${{ matrix.target }}-
|
||||||
|
- name: Increase Pagefile size
|
||||||
|
uses: al-cheb/configure-pagefile-action@v1.2
|
||||||
|
with:
|
||||||
|
minimum-size: 2GB
|
||||||
|
maximum-size: 6GB
|
||||||
- name: Set up MSVC
|
- name: Set up MSVC
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
if: ${{ matrix.target == 'msvc' }}
|
if: ${{ matrix.target == 'msvc' }}
|
||||||
- name: Install MSVC extra tools
|
- name: Install extra tools (MSVC)
|
||||||
run: choco install ccache ninja wget
|
run: choco install ccache ninja wget
|
||||||
if: ${{ matrix.target == 'msvc' }}
|
if: ${{ matrix.target == 'msvc' }}
|
||||||
|
- name: Set up Vulkan SDK (MSVC)
|
||||||
|
uses: humbletim/setup-vulkan-sdk@v1.2.0
|
||||||
|
if: ${{ matrix.target == 'msvc' }}
|
||||||
|
with:
|
||||||
|
vulkan-query-version: latest
|
||||||
|
vulkan-components: Glslang
|
||||||
|
vulkan-use-cache: true
|
||||||
- name: Set up MSYS2
|
- name: Set up MSYS2
|
||||||
uses: msys2/setup-msys2@v2
|
uses: msys2/setup-msys2@v2
|
||||||
if: ${{ matrix.target == 'msys2' }}
|
if: ${{ matrix.target == 'msys2' }}
|
||||||
@ -172,16 +184,10 @@ jobs:
|
|||||||
update: true
|
update: true
|
||||||
install: git make p7zip
|
install: git make p7zip
|
||||||
pacboy: >-
|
pacboy: >-
|
||||||
toolchain:p ccache:p cmake:p ninja:p
|
toolchain:p ccache:p cmake:p ninja:p glslang:p
|
||||||
qt6-base:p qt6-multimedia:p qt6-multimedia-wmf:p qt6-tools:p qt6-translations:p
|
qt6-base:p qt6-multimedia:p qt6-multimedia-wmf:p qt6-tools:p qt6-translations:p
|
||||||
- name: Setup Vulkan SDK
|
- name: Test glslang
|
||||||
uses: humbletim/setup-vulkan-sdk@v1.2.0
|
run: glslang --version || glslangValidator --version
|
||||||
with:
|
|
||||||
vulkan-query-version: latest
|
|
||||||
vulkan-components: Glslang
|
|
||||||
vulkan-use-cache: true
|
|
||||||
- name: Test glslangValidator
|
|
||||||
run: glslangValidator --version
|
|
||||||
- name: Disable line ending translation
|
- name: Disable line ending translation
|
||||||
run: git config --global core.autocrlf input
|
run: git config --global core.autocrlf input
|
||||||
- name: Build
|
- name: Build
|
||||||
|
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
|
||||||
|
@ -40,8 +40,10 @@ 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()
|
endif()
|
||||||
|
|
||||||
option(ENABLE_SDL2 "Enable using SDL2" ON)
|
option(ENABLE_SDL2 "Enable using SDL2" ON)
|
||||||
@ -57,6 +59,7 @@ CMAKE_DEPENDENT_OPTION(ENABLE_TESTS "Enable generating tests executable" ON "NOT
|
|||||||
CMAKE_DEPENDENT_OPTION(ENABLE_DEDICATED_ROOM "Enable generating dedicated room executable" ON "NOT ANDROID AND NOT IOS" OFF)
|
CMAKE_DEPENDENT_OPTION(ENABLE_DEDICATED_ROOM "Enable generating dedicated room executable" ON "NOT ANDROID AND NOT IOS" OFF)
|
||||||
|
|
||||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||||
|
option(ENABLE_SCRIPTING "Enable RPC server for scripting" ON)
|
||||||
|
|
||||||
CMAKE_DEPENDENT_OPTION(ENABLE_CUBEB "Enables the cubeb audio backend" ON "NOT IOS" OFF)
|
CMAKE_DEPENDENT_OPTION(ENABLE_CUBEB "Enables the cubeb audio backend" ON "NOT IOS" OFF)
|
||||||
option(ENABLE_OPENAL "Enables the OpenAL audio backend" ON)
|
option(ENABLE_OPENAL "Enables the OpenAL audio backend" ON)
|
||||||
@ -68,9 +71,11 @@ option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
|||||||
CMAKE_DEPENDENT_OPTION(ENABLE_MF "Use Media Foundation decoder (preferred over FFmpeg)" ON "WIN32" OFF)
|
CMAKE_DEPENDENT_OPTION(ENABLE_MF "Use Media Foundation decoder (preferred over FFmpeg)" ON "WIN32" OFF)
|
||||||
CMAKE_DEPENDENT_OPTION(ENABLE_AUDIOTOOLBOX "Use AudioToolbox decoder (preferred over FFmpeg)" ON "APPLE" OFF)
|
CMAKE_DEPENDENT_OPTION(ENABLE_AUDIOTOOLBOX "Use AudioToolbox decoder (preferred over FFmpeg)" ON "APPLE" OFF)
|
||||||
|
|
||||||
|
CMAKE_DEPENDENT_OPTION(CITRA_ENABLE_BUNDLE_TARGET "Enable the distribution bundling target." ON "NOT ANDROID AND NOT IOS" OFF)
|
||||||
|
|
||||||
# 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" ${IS_RELEASE_BUILD})
|
||||||
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)
|
||||||
|
|
||||||
@ -219,7 +224,7 @@ find_package(Threads REQUIRED)
|
|||||||
|
|
||||||
if (ENABLE_QT)
|
if (ENABLE_QT)
|
||||||
if (NOT USE_SYSTEM_QT)
|
if (NOT USE_SYSTEM_QT)
|
||||||
download_qt(6.5.0)
|
download_qt(6.5.1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent)
|
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent)
|
||||||
@ -341,13 +346,6 @@ function(get_timestamp _var)
|
|||||||
set(${_var} "${timestamp}" PARENT_SCOPE)
|
set(${_var} "${timestamp}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Prevent boost from linking against libs when building
|
|
||||||
add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY
|
|
||||||
-DBOOST_SYSTEM_NO_LIB
|
|
||||||
-DBOOST_DATE_TIME_NO_LIB
|
|
||||||
-DBOOST_REGEX_NO_LIB
|
|
||||||
)
|
|
||||||
|
|
||||||
# generate git/build information
|
# generate git/build information
|
||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||||
@ -355,17 +353,23 @@ git_describe(GIT_DESC --always --long --dirty)
|
|||||||
git_branch_name(GIT_BRANCH)
|
git_branch_name(GIT_BRANCH)
|
||||||
get_timestamp(BUILD_DATE)
|
get_timestamp(BUILD_DATE)
|
||||||
|
|
||||||
if (NOT USE_SYSTEM_BOOST)
|
# Boost
|
||||||
add_definitions( -DBOOST_ALL_NO_LIB )
|
# Prevent boost from linking against libs when building
|
||||||
|
add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY
|
||||||
|
-DBOOST_SYSTEM_NO_LIB
|
||||||
|
-DBOOST_DATE_TIME_NO_LIB
|
||||||
|
-DBOOST_REGEX_NO_LIB
|
||||||
|
)
|
||||||
|
if (USE_SYSTEM_BOOST)
|
||||||
|
find_package(Boost 1.70.0 COMPONENTS container locale serialization iostreams REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(externals)
|
add_subdirectory(externals)
|
||||||
|
|
||||||
# Boost
|
# Boost (bundled)
|
||||||
if (USE_SYSTEM_BOOST)
|
if (NOT USE_SYSTEM_BOOST)
|
||||||
find_package(Boost 1.70.0 COMPONENTS serialization iostreams REQUIRED)
|
add_definitions( -DBOOST_ALL_NO_LIB )
|
||||||
else()
|
|
||||||
add_library(Boost::boost ALIAS boost)
|
add_library(Boost::boost ALIAS boost)
|
||||||
add_library(Boost::serialization ALIAS boost_serialization)
|
add_library(Boost::serialization ALIAS boost_serialization)
|
||||||
add_library(Boost::iostreams ALIAS boost_iostreams)
|
add_library(Boost::iostreams ALIAS boost_iostreams)
|
||||||
@ -397,7 +401,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Create target for outputting distributable bundles.
|
# Create target for outputting distributable bundles.
|
||||||
if (NOT ANDROID AND NOT IOS)
|
if (CITRA_ENABLE_BUNDLE_TARGET)
|
||||||
include(BundleTarget)
|
include(BundleTarget)
|
||||||
if (ENABLE_SDL2_FRONTEND)
|
if (ENABLE_SDL2_FRONTEND)
|
||||||
bundle_target(citra)
|
bundle_target(citra)
|
||||||
|
@ -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*")
|
||||||
|
@ -189,6 +189,12 @@ else()
|
|||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET bundle
|
TARGET bundle
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/")
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/")
|
||||||
|
add_custom_command(
|
||||||
|
TARGET bundle
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/dist/")
|
||||||
|
add_custom_command(
|
||||||
|
TARGET bundle
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/dist/icon.png" "${CMAKE_BINARY_DIR}/bundle/dist/citra.png")
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET bundle
|
TARGET bundle
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/license.txt" "${CMAKE_BINARY_DIR}/bundle/")
|
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/license.txt" "${CMAKE_BINARY_DIR}/bundle/")
|
||||||
|
@ -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}")
|
||||||
@ -54,7 +61,8 @@ function(download_qt target)
|
|||||||
set(host_flag "--autodesktop")
|
set(host_flag "--autodesktop")
|
||||||
set(host_prefix "${base_path}/${target}/${host_arch_path}")
|
set(host_prefix "${base_path}/${target}/${host_arch_path}")
|
||||||
endif()
|
endif()
|
||||||
set(install_args install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} ${host_flag} -m qtmultimedia)
|
set(install_args install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} ${host_flag}
|
||||||
|
-m qtmultimedia --archives qttranslations qttools qtsvg qtbase)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT EXISTS "${prefix}")
|
if (NOT EXISTS "${prefix}")
|
||||||
@ -62,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})
|
||||||
|
@ -57,9 +57,7 @@ if (DEFINED ENV{CI})
|
|||||||
set(BUILD_VERSION ${CMAKE_MATCH_1})
|
set(BUILD_VERSION ${CMAKE_MATCH_1})
|
||||||
endif()
|
endif()
|
||||||
if (BUILD_VERSION)
|
if (BUILD_VERSION)
|
||||||
# This leaves a trailing space on the last word, but we actually want that
|
set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION}")
|
||||||
# because of how it's styled in the title bar.
|
|
||||||
set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ")
|
|
||||||
else()
|
else()
|
||||||
set(BUILD_FULLNAME "")
|
set(BUILD_FULLNAME "")
|
||||||
endif()
|
endif()
|
||||||
|
@ -12,8 +12,16 @@ set(HASH_FILES
|
|||||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_gen.h"
|
"${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.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
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
5
dist/qt_themes/qdarkstyle/style.qss
vendored
5
dist/qt_themes/qdarkstyle/style.qss
vendored
@ -298,6 +298,11 @@ QAbstractItemView:read-only {
|
|||||||
alternate-background-color: #232629;
|
alternate-background-color: #232629;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Workaround for https://bugreports.qt.io/browse/QTBUG-115529 */
|
||||||
|
QAbstractItemView:item {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
QWidget:focus {
|
QWidget:focus {
|
||||||
border: 1px solid #3daee9;
|
border: 1px solid #3daee9;
|
||||||
}
|
}
|
||||||
|
@ -481,6 +481,11 @@ QAbstractItemView QLineEdit {
|
|||||||
padding: 2px;
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Workaround for https://bugreports.qt.io/browse/QTBUG-115529 */
|
||||||
|
QAbstractItemView:item {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
/* QAbstractScrollArea ----------------------------------------------------
|
/* QAbstractScrollArea ----------------------------------------------------
|
||||||
|
|
||||||
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea
|
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea
|
||||||
@ -1067,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
|
||||||
|
109
externals/CMakeLists.txt
vendored
109
externals/CMakeLists.txt
vendored
@ -12,27 +12,29 @@ include(DownloadExternals)
|
|||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
|
|
||||||
# Boost
|
# Boost
|
||||||
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
|
if (NOT USE_SYSTEM_BOOST)
|
||||||
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
|
message(STATUS "Including vendored Boost library")
|
||||||
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
|
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
|
||||||
add_library(boost INTERFACE)
|
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
|
||||||
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
|
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
|
||||||
|
add_library(boost INTERFACE)
|
||||||
|
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
|
||||||
|
|
||||||
# Boost::serialization
|
# Boost::serialization
|
||||||
file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp")
|
file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp")
|
||||||
add_library(boost_serialization STATIC ${boost_serialization_SRC})
|
add_library(boost_serialization STATIC ${boost_serialization_SRC})
|
||||||
target_link_libraries(boost_serialization PUBLIC boost)
|
target_link_libraries(boost_serialization PUBLIC boost)
|
||||||
|
|
||||||
# Boost::iostreams
|
|
||||||
add_library(
|
|
||||||
boost_iostreams
|
|
||||||
STATIC
|
|
||||||
${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/file_descriptor.cpp
|
|
||||||
${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp
|
|
||||||
)
|
|
||||||
target_link_libraries(boost_iostreams PUBLIC boost)
|
|
||||||
|
|
||||||
|
# Boost::iostreams
|
||||||
|
add_library(
|
||||||
|
boost_iostreams
|
||||||
|
STATIC
|
||||||
|
${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/file_descriptor.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(boost_iostreams PUBLIC boost)
|
||||||
# Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
|
# Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
|
||||||
|
endif()
|
||||||
|
|
||||||
# Catch2
|
# Catch2
|
||||||
set(CATCH_INSTALL_DOCS OFF CACHE BOOL "")
|
set(CATCH_INSTALL_DOCS OFF CACHE BOOL "")
|
||||||
@ -95,6 +97,7 @@ set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "")
|
|||||||
set(ENABLE_SPVREMAPPER OFF CACHE BOOL "")
|
set(ENABLE_SPVREMAPPER OFF CACHE BOOL "")
|
||||||
set(ENABLE_CTEST OFF CACHE BOOL "")
|
set(ENABLE_CTEST OFF CACHE BOOL "")
|
||||||
set(ENABLE_HLSL OFF CACHE BOOL "")
|
set(ENABLE_HLSL OFF CACHE BOOL "")
|
||||||
|
set(BUILD_EXTERNAL OFF CACHE BOOL "")
|
||||||
add_subdirectory(glslang)
|
add_subdirectory(glslang)
|
||||||
|
|
||||||
# inih
|
# inih
|
||||||
@ -171,37 +174,39 @@ endif()
|
|||||||
add_library(json-headers INTERFACE)
|
add_library(json-headers INTERFACE)
|
||||||
target_include_directories(json-headers INTERFACE ./json)
|
target_include_directories(json-headers INTERFACE ./json)
|
||||||
|
|
||||||
|
# OpenSSL
|
||||||
|
if (USE_SYSTEM_OPENSSL)
|
||||||
|
find_package(OpenSSL 1.1)
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT OPENSSL_FOUND)
|
||||||
|
# LibreSSL
|
||||||
|
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
|
||||||
|
set(OPENSSLDIR "/etc/ssl/")
|
||||||
|
add_subdirectory(libressl EXCLUDE_FROM_ALL)
|
||||||
|
target_include_directories(ssl INTERFACE ./libressl/include)
|
||||||
|
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
|
||||||
|
get_directory_property(OPENSSL_LIBRARIES
|
||||||
|
DIRECTORY libressl
|
||||||
|
DEFINITION OPENSSL_LIBS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# httplib
|
||||||
|
add_library(httplib INTERFACE)
|
||||||
|
target_include_directories(httplib INTERFACE ./httplib)
|
||||||
|
target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||||
|
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
add_subdirectory(android-ifaddrs)
|
||||||
|
target_link_libraries(httplib INTERFACE ifaddrs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# cpp-jwt
|
||||||
if (ENABLE_WEB_SERVICE)
|
if (ENABLE_WEB_SERVICE)
|
||||||
if (USE_SYSTEM_OPENSSL)
|
|
||||||
find_package(OpenSSL 1.1)
|
|
||||||
if (OPENSSL_FOUND)
|
|
||||||
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT OPENSSL_FOUND)
|
|
||||||
# LibreSSL
|
|
||||||
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
|
|
||||||
set(OPENSSLDIR "/etc/ssl/")
|
|
||||||
add_subdirectory(libressl EXCLUDE_FROM_ALL)
|
|
||||||
target_include_directories(ssl INTERFACE ./libressl/include)
|
|
||||||
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
|
|
||||||
get_directory_property(OPENSSL_LIBRARIES
|
|
||||||
DIRECTORY libressl
|
|
||||||
DEFINITION OPENSSL_LIBS)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(ANDROID)
|
|
||||||
add_subdirectory(android-ifaddrs)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# httplib
|
|
||||||
add_library(httplib INTERFACE)
|
|
||||||
target_include_directories(httplib INTERFACE ./httplib)
|
|
||||||
target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
|
||||||
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
|
|
||||||
|
|
||||||
# cpp-jwt
|
|
||||||
add_library(cpp-jwt INTERFACE)
|
add_library(cpp-jwt INTERFACE)
|
||||||
target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
|
target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
|
||||||
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
|
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
|
||||||
@ -237,3 +242,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()
|
||||||
|
2
externals/boost
vendored
2
externals/boost
vendored
Submodule externals/boost updated: 700ae2eff3...3c27c785ad
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
Submodule externals/libadrenotools added at deec5f75ee
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
Submodule externals/vulkan-headers updated: bae9700cd9...85c2334e92
@ -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)
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="org.citra.citra_emu.CitraApplication"
|
android:name="org.citra.citra_emu.CitraApplication"
|
||||||
|
@ -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";
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package org.citra.citra_emu.ui.main;
|
package org.citra.citra_emu.ui.main;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@ -13,6 +16,7 @@ import androidx.activity.result.contract.ActivityResultContracts;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.splashscreen.SplashScreen;
|
import androidx.core.splashscreen.SplashScreen;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -124,6 +128,9 @@ public final class MainActivity extends AppCompatActivity implements MainView {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<String> requestNotificationPermissionLauncher =
|
||||||
|
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> { });
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
|
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
|
||||||
@ -165,6 +172,12 @@ public final class MainActivity extends AppCompatActivity implements MainView {
|
|||||||
EmulationActivity.tryDismissRunningNotification(this);
|
EmulationActivity.tryDismissRunningNotification(this);
|
||||||
|
|
||||||
setInsets();
|
setInsets();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
requestNotificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -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)
|
||||||
|
@ -53,7 +53,7 @@ void AndroidMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) {
|
|||||||
const u32 return_code = static_cast<u32>(
|
const u32 return_code = static_cast<u32>(
|
||||||
env->GetLongField(data, env->GetFieldID(s_mii_selector_data_class, "return_code", "J")));
|
env->GetLongField(data, env->GetFieldID(s_mii_selector_data_class, "return_code", "J")));
|
||||||
if (return_code == 1) {
|
if (return_code == 1) {
|
||||||
Finalize(return_code, HLE::Applets::MiiData{});
|
Finalize(return_code, Mii::MiiData{});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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"
|
||||||
@ -26,13 +29,15 @@
|
|||||||
#include "core/hle/service/nfc/nfc.h"
|
#include "core/hle/service/nfc/nfc.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/savestate.h"
|
#include "core/savestate.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "jni/android_common/android_common.h"
|
#include "jni/android_common/android_common.h"
|
||||||
#include "jni/applets/mii_selector.h"
|
#include "jni/applets/mii_selector.h"
|
||||||
#include "jni/applets/swkbd.h"
|
#include "jni/applets/swkbd.h"
|
||||||
#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"
|
||||||
@ -41,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};
|
||||||
@ -122,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()};
|
||||||
@ -156,7 +169,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
system.RegisterSoftwareKeyboard(std::make_shared<SoftwareKeyboard::AndroidKeyboard>());
|
system.RegisterSoftwareKeyboard(std::make_shared<SoftwareKeyboard::AndroidKeyboard>());
|
||||||
|
|
||||||
// Register microphone permission check
|
// Register microphone permission check
|
||||||
Core::System::GetInstance().RegisterMicPermissionCheck(&CheckMicPermission);
|
system.RegisterMicPermissionCheck(&CheckMicPermission);
|
||||||
|
|
||||||
InputManager::Init();
|
InputManager::Init();
|
||||||
|
|
||||||
@ -166,7 +179,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
return load_result;
|
return load_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& telemetry_session = Core::System::GetInstance().TelemetrySession();
|
auto& telemetry_session = system.TelemetrySession();
|
||||||
telemetry_session.AddField(Common::Telemetry::FieldType::App, "Frontend", "Android");
|
telemetry_session.AddField(Common::Telemetry::FieldType::App, "Frontend", "Android");
|
||||||
|
|
||||||
stop_run = false;
|
stop_run = false;
|
||||||
@ -187,8 +200,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
audio_stretching_event =
|
audio_stretching_event =
|
||||||
system.CoreTiming().RegisterEvent("AudioStretchingEvent", [&](u64, s64 cycles_late) {
|
system.CoreTiming().RegisterEvent("AudioStretchingEvent", [&](u64, s64 cycles_late) {
|
||||||
if (Settings::values.enable_audio_stretching) {
|
if (Settings::values.enable_audio_stretching) {
|
||||||
Core::DSP().EnableStretching(
|
system.DSP().EnableStretching(system.GetAndResetPerfStats().emulation_speed < 0.95);
|
||||||
Core::System::GetInstance().GetAndResetPerfStats().emulation_speed < 0.95);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
system.CoreTiming().ScheduleEvent(audio_stretching_ticks - cycles_late,
|
system.CoreTiming().ScheduleEvent(audio_stretching_ticks - cycles_late,
|
||||||
@ -219,7 +231,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
SCOPE_EXIT({ Settings::values.volume = volume; });
|
SCOPE_EXIT({ Settings::values.volume = volume; });
|
||||||
Settings::values.volume = 0;
|
Settings::values.volume = 0;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> pause_lock(paused_mutex);
|
std::unique_lock pause_lock{paused_mutex};
|
||||||
running_cv.wait(pause_lock, [] { return !pause_emulation || stop_run; });
|
running_cv.wait(pause_lock, [] { return !pause_emulation || stop_run; });
|
||||||
window->PollEvents();
|
window->PollEvents();
|
||||||
}
|
}
|
||||||
@ -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,
|
||||||
@ -621,7 +676,7 @@ jobjectArray Java_org_citra_citra_1emu_NativeLibrary_GetSavestateInfo(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto savestates = Core::ListSaveStates(title_id);
|
const auto savestates = Core::ListSaveStates(title_id, system.Movie().GetCurrentMovieID());
|
||||||
const jobjectArray array =
|
const jobjectArray array =
|
||||||
env->NewObjectArray(static_cast<jsize>(savestates.size()), savestate_info_class, nullptr);
|
env->NewObjectArray(static_cast<jsize>(savestates.size()), savestate_info_class, nullptr);
|
||||||
for (std::size_t i = 0; i < savestates.size(); ++i) {
|
for (std::size_t i = 0; i < savestates.size(); ++i) {
|
||||||
|
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>
|
||||||
|
@ -47,9 +47,8 @@ add_library(audio_core STATIC
|
|||||||
|
|
||||||
create_target_directory_groups(audio_core)
|
create_target_directory_groups(audio_core)
|
||||||
|
|
||||||
target_link_libraries(audio_core PUBLIC citra_common)
|
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)
|
add_definitions(-DSOUNDTOUCH_INTEGER_SAMPLES)
|
||||||
|
|
||||||
if(ENABLE_MF)
|
if(ENABLE_MF)
|
||||||
|
@ -5,20 +5,24 @@
|
|||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace AudioCore {
|
||||||
|
|
||||||
struct ADTSData {
|
struct ADTSData {
|
||||||
u8 header_length;
|
u8 header_length = 0;
|
||||||
bool MPEG2;
|
bool mpeg2 = false;
|
||||||
u8 profile;
|
u8 profile = 0;
|
||||||
u8 channels;
|
u8 channels = 0;
|
||||||
u8 channel_idx;
|
u8 channel_idx = 0;
|
||||||
u8 framecount;
|
u8 framecount = 0;
|
||||||
u8 samplerate_idx;
|
u8 samplerate_idx = 0;
|
||||||
u32 length;
|
u32 length = 0;
|
||||||
u32 samplerate;
|
u32 samplerate = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
ADTSData ParseADTS(const char* buffer);
|
ADTSData ParseADTS(const u8* buffer);
|
||||||
|
|
||||||
// last two bytes of MF AAC decoder user data
|
// last two bytes of MF AAC decoder user data
|
||||||
// see https://docs.microsoft.com/en-us/windows/desktop/medfound/aac-decoder#example-media-types
|
// see https://docs.microsoft.com/en-us/windows/desktop/medfound/aac-decoder#example-media-types
|
||||||
u16 MFGetAACTag(const ADTSData& input);
|
u16 MFGetAACTag(const ADTSData& input);
|
||||||
|
|
||||||
|
} // namespace AudioCore
|
||||||
|
@ -3,44 +3,59 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "adts.h"
|
#include "adts.h"
|
||||||
|
#include "common/bit_field.h"
|
||||||
|
|
||||||
|
namespace AudioCore {
|
||||||
constexpr std::array<u32, 16> freq_table = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
|
constexpr std::array<u32, 16> freq_table = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
|
||||||
16000, 12000, 11025, 8000, 7350, 0, 0, 0};
|
16000, 12000, 11025, 8000, 7350, 0, 0, 0};
|
||||||
constexpr std::array<u8, 8> channel_table = {0, 1, 2, 3, 4, 5, 6, 8};
|
constexpr std::array<u8, 8> channel_table = {0, 1, 2, 3, 4, 5, 6, 8};
|
||||||
|
|
||||||
ADTSData ParseADTS(const char* buffer) {
|
struct ADTSHeader {
|
||||||
u32 tmp = 0;
|
union {
|
||||||
ADTSData out;
|
std::array<u8, 7> raw{};
|
||||||
|
BitFieldBE<52, 12, u64> sync_word;
|
||||||
|
BitFieldBE<51, 1, u64> mpeg2;
|
||||||
|
BitFieldBE<49, 2, u64> layer;
|
||||||
|
BitFieldBE<48, 1, u64> protection_absent;
|
||||||
|
BitFieldBE<46, 2, u64> profile;
|
||||||
|
BitFieldBE<42, 4, u64> samplerate_idx;
|
||||||
|
BitFieldBE<41, 1, u64> private_bit;
|
||||||
|
BitFieldBE<38, 3, u64> channel_idx;
|
||||||
|
BitFieldBE<37, 1, u64> originality;
|
||||||
|
BitFieldBE<36, 1, u64> home;
|
||||||
|
BitFieldBE<35, 1, u64> copyright_id;
|
||||||
|
BitFieldBE<34, 1, u64> copyright_id_start;
|
||||||
|
BitFieldBE<21, 13, u64> frame_length;
|
||||||
|
BitFieldBE<10, 11, u64> buffer_fullness;
|
||||||
|
BitFieldBE<8, 2, u64> frame_count;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ADTSData ParseADTS(const u8* buffer) {
|
||||||
|
ADTSHeader header;
|
||||||
|
memcpy(header.raw.data(), buffer, sizeof(header.raw));
|
||||||
|
|
||||||
// sync word 0xfff
|
// sync word 0xfff
|
||||||
tmp = (buffer[0] << 8) | (buffer[1] & 0xf0);
|
if (header.sync_word != 0xfff) {
|
||||||
if ((tmp & 0xffff) != 0xfff0) {
|
return {};
|
||||||
out.length = 0;
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ADTSData out{};
|
||||||
// bit 16 = no CRC
|
// bit 16 = no CRC
|
||||||
out.header_length = (buffer[1] & 0x1) ? 7 : 9;
|
out.header_length = header.protection_absent ? 7 : 9;
|
||||||
out.MPEG2 = (buffer[1] >> 3) & 0x1;
|
out.mpeg2 = static_cast<bool>(header.mpeg2);
|
||||||
// bit 17 to 18
|
// bit 17 to 18
|
||||||
out.profile = (buffer[2] >> 6) + 1;
|
out.profile = static_cast<u8>(header.profile) + 1;
|
||||||
// bit 19 to 22
|
// bit 19 to 22
|
||||||
tmp = (buffer[2] >> 2) & 0xf;
|
out.samplerate_idx = static_cast<u8>(header.samplerate_idx);
|
||||||
out.samplerate_idx = tmp;
|
out.samplerate = header.samplerate_idx > 15 ? 0 : freq_table[header.samplerate_idx];
|
||||||
out.samplerate = (tmp > 15) ? 0 : freq_table[tmp];
|
|
||||||
// bit 24 to 26
|
// bit 24 to 26
|
||||||
tmp = ((buffer[2] & 0x1) << 2) | ((buffer[3] >> 6) & 0x3);
|
out.channel_idx = static_cast<u8>(header.channel_idx);
|
||||||
out.channel_idx = tmp;
|
out.channels = (header.channel_idx > 7) ? 0 : channel_table[header.channel_idx];
|
||||||
out.channels = (tmp > 7) ? 0 : channel_table[tmp];
|
|
||||||
|
|
||||||
// bit 55 to 56
|
// bit 55 to 56
|
||||||
out.framecount = (buffer[6] & 0x3) + 1;
|
out.framecount = static_cast<u8>(header.frame_count + 1);
|
||||||
|
|
||||||
// bit 31 to 43
|
// bit 31 to 43
|
||||||
tmp = (buffer[3] & 0x3) << 11;
|
out.length = static_cast<u32>(header.frame_length);
|
||||||
tmp |= (buffer[4] << 3) & 0x7f8;
|
|
||||||
tmp |= (buffer[5] >> 5) & 0x7;
|
|
||||||
|
|
||||||
out.length = tmp;
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -61,3 +76,4 @@ u16 MFGetAACTag(const ADTSData& input) {
|
|||||||
|
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
} // namespace AudioCore
|
||||||
|
@ -24,7 +24,7 @@ private:
|
|||||||
std::optional<BinaryMessage> Decode(const BinaryMessage& request);
|
std::optional<BinaryMessage> Decode(const BinaryMessage& request);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
bool InitializeDecoder(ADTSData& adts_header);
|
bool InitializeDecoder(AudioCore::ADTSData& adts_header);
|
||||||
|
|
||||||
static OSStatus DataFunc(AudioConverterRef in_audio_converter, u32* io_number_data_packets,
|
static OSStatus DataFunc(AudioConverterRef in_audio_converter, u32* io_number_data_packets,
|
||||||
AudioBufferList* io_data,
|
AudioBufferList* io_data,
|
||||||
@ -33,7 +33,7 @@ private:
|
|||||||
|
|
||||||
Memory::MemorySystem& memory;
|
Memory::MemorySystem& memory;
|
||||||
|
|
||||||
ADTSData adts_config;
|
AudioCore::ADTSData adts_config;
|
||||||
AudioStreamBasicDescription output_format = {};
|
AudioStreamBasicDescription output_format = {};
|
||||||
AudioConverterRef converter = nullptr;
|
AudioConverterRef converter = nullptr;
|
||||||
|
|
||||||
@ -85,7 +85,11 @@ std::optional<BinaryMessage> AudioToolboxDecoder::Impl::ProcessRequest(
|
|||||||
case DecoderCommand::EncodeDecode: {
|
case DecoderCommand::EncodeDecode: {
|
||||||
return Decode(request);
|
return Decode(request);
|
||||||
}
|
}
|
||||||
case DecoderCommand::Unknown: {
|
case DecoderCommand::Shutdown:
|
||||||
|
case DecoderCommand::SaveState:
|
||||||
|
case DecoderCommand::LoadState: {
|
||||||
|
LOG_WARNING(Audio_DSP, "Got unimplemented binary request: {}",
|
||||||
|
static_cast<u16>(request.header.cmd));
|
||||||
BinaryMessage response = request;
|
BinaryMessage response = request;
|
||||||
response.header.result = ResultStatus::Success;
|
response.header.result = ResultStatus::Success;
|
||||||
return response;
|
return response;
|
||||||
@ -97,7 +101,7 @@ std::optional<BinaryMessage> AudioToolboxDecoder::Impl::ProcessRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioToolboxDecoder::Impl::InitializeDecoder(ADTSData& adts_header) {
|
bool AudioToolboxDecoder::Impl::InitializeDecoder(AudioCore::ADTSData& adts_header) {
|
||||||
if (converter) {
|
if (converter) {
|
||||||
if (adts_config.channels == adts_header.channels &&
|
if (adts_config.channels == adts_header.channels &&
|
||||||
adts_config.samplerate == adts_header.samplerate) {
|
adts_config.samplerate == adts_header.samplerate) {
|
||||||
@ -179,8 +183,9 @@ std::optional<BinaryMessage> AudioToolboxDecoder::Impl::Decode(const BinaryMessa
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
|
const auto data =
|
||||||
auto adts_header = ParseADTS(reinterpret_cast<const char*>(data));
|
memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
|
||||||
|
auto adts_header = AudioCore::ParseADTS(data);
|
||||||
curr_data = data + adts_header.header_length;
|
curr_data = data + adts_header.header_length;
|
||||||
curr_data_len = request.decode_aac_request.size - adts_header.header_length;
|
curr_data_len = request.decode_aac_request.size - adts_header.header_length;
|
||||||
|
|
||||||
|
@ -42,7 +42,9 @@ std::optional<BinaryMessage> NullDecoder::ProcessRequest(const BinaryMessage& re
|
|||||||
BinaryMessage response{};
|
BinaryMessage response{};
|
||||||
switch (request.header.cmd) {
|
switch (request.header.cmd) {
|
||||||
case DecoderCommand::Init:
|
case DecoderCommand::Init:
|
||||||
case DecoderCommand::Unknown:
|
case DecoderCommand::Shutdown:
|
||||||
|
case DecoderCommand::SaveState:
|
||||||
|
case DecoderCommand::LoadState:
|
||||||
response = request;
|
response = request;
|
||||||
response.header.result = ResultStatus::Success;
|
response.header.result = ResultStatus::Success;
|
||||||
return response;
|
return response;
|
||||||
|
@ -14,9 +14,16 @@
|
|||||||
namespace AudioCore::HLE {
|
namespace AudioCore::HLE {
|
||||||
|
|
||||||
enum class DecoderCommand : u16 {
|
enum class DecoderCommand : u16 {
|
||||||
|
/// Initializes the decoder.
|
||||||
Init = 0,
|
Init = 0,
|
||||||
|
/// Decodes/encodes a data frame.
|
||||||
EncodeDecode = 1,
|
EncodeDecode = 1,
|
||||||
Unknown = 2, // Probably UnInit
|
/// Shuts down the decoder.
|
||||||
|
Shutdown = 2,
|
||||||
|
/// Loads the saved decoder state. Used for DSP wake.
|
||||||
|
LoadState = 3,
|
||||||
|
/// Saves the decoder state. Used for DSP sleep.
|
||||||
|
SaveState = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DecoderCodec : u16 {
|
enum class DecoderCodec : u16 {
|
||||||
|
@ -111,7 +111,11 @@ std::optional<BinaryMessage> FDKDecoder::Impl::ProcessRequest(const BinaryMessag
|
|||||||
case DecoderCommand::EncodeDecode: {
|
case DecoderCommand::EncodeDecode: {
|
||||||
return Decode(request);
|
return Decode(request);
|
||||||
}
|
}
|
||||||
case DecoderCommand::Unknown: {
|
case DecoderCommand::Shutdown:
|
||||||
|
case DecoderCommand::SaveState:
|
||||||
|
case DecoderCommand::LoadState: {
|
||||||
|
LOG_WARNING(Audio_DSP, "Got unimplemented binary request: {}",
|
||||||
|
static_cast<u16>(request.header.cmd));
|
||||||
BinaryMessage response = request;
|
BinaryMessage response = request;
|
||||||
response.header.result = ResultStatus::Success;
|
response.header.result = ResultStatus::Success;
|
||||||
return response;
|
return response;
|
||||||
|
@ -80,7 +80,11 @@ std::optional<BinaryMessage> FFMPEGDecoder::Impl::ProcessRequest(const BinaryMes
|
|||||||
case DecoderCommand::EncodeDecode: {
|
case DecoderCommand::EncodeDecode: {
|
||||||
return Decode(request);
|
return Decode(request);
|
||||||
}
|
}
|
||||||
case DecoderCommand::Unknown: {
|
case DecoderCommand::Shutdown:
|
||||||
|
case DecoderCommand::SaveState:
|
||||||
|
case DecoderCommand::LoadState: {
|
||||||
|
LOG_WARNING(Audio_DSP, "Got unimplemented binary request: {}",
|
||||||
|
static_cast<u16>(request.header.cmd));
|
||||||
BinaryMessage response = request;
|
BinaryMessage response = request;
|
||||||
response.header.result = ResultStatus::Success;
|
response.header.result = ResultStatus::Success;
|
||||||
return response;
|
return response;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <boost/serialization/vector.hpp>
|
#include <boost/serialization/vector.hpp>
|
||||||
#include <boost/serialization/weak_ptr.hpp>
|
#include <boost/serialization/weak_ptr.hpp>
|
||||||
#include "audio_core/audio_types.h"
|
#include "audio_core/audio_types.h"
|
||||||
|
#include "common/archives.h"
|
||||||
#ifdef HAVE_MF
|
#ifdef HAVE_MF
|
||||||
#include "audio_core/hle/wmf_decoder.h"
|
#include "audio_core/hle/wmf_decoder.h"
|
||||||
#elif HAVE_AUDIOTOOLBOX
|
#elif HAVE_AUDIOTOOLBOX
|
||||||
@ -319,6 +320,10 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) {
|
|||||||
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(value));
|
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(value));
|
||||||
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &value, sizeof(value));
|
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &value, sizeof(value));
|
||||||
}
|
}
|
||||||
|
auto dsp = dsp_dsp.lock();
|
||||||
|
if (dsp) {
|
||||||
|
dsp->SignalInterrupt(InterruptType::Pipe, DspPipe::Binary);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -461,8 +466,6 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) {
|
|||||||
// TODO(merry): Signal all the other interrupts as appropriate.
|
// TODO(merry): Signal all the other interrupts as appropriate.
|
||||||
if (auto service = dsp_dsp.lock()) {
|
if (auto service = dsp_dsp.lock()) {
|
||||||
service->SignalInterrupt(InterruptType::Pipe, DspPipe::Audio);
|
service->SignalInterrupt(InterruptType::Pipe, DspPipe::Audio);
|
||||||
// HACK(merry): Added to prevent regressions. Will remove soon.
|
|
||||||
service->SignalInterrupt(InterruptType::Pipe, DspPipe::Binary);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ public:
|
|||||||
~Impl();
|
~Impl();
|
||||||
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request);
|
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request);
|
||||||
|
|
||||||
bool SetMediaType(const ADTSData& adts_data);
|
bool SetMediaType(const AudioCore::ADTSData& adts_data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<BinaryMessage> Initalize(const BinaryMessage& request);
|
std::optional<BinaryMessage> Initalize(const BinaryMessage& request);
|
||||||
@ -36,8 +36,8 @@ private:
|
|||||||
Memory::MemorySystem& memory;
|
Memory::MemorySystem& memory;
|
||||||
std::unique_ptr<AMediaCodec, AMediaCodecRelease> decoder;
|
std::unique_ptr<AMediaCodec, AMediaCodecRelease> decoder;
|
||||||
// default: 2 channles, 48000 samplerate
|
// default: 2 channles, 48000 samplerate
|
||||||
ADTSData mADTSData{
|
AudioCore::ADTSData mADTSData{
|
||||||
/*header_length*/ 7, /*MPEG2*/ false, /*profile*/ 2,
|
/*header_length*/ 7, /*mpeg2*/ false, /*profile*/ 2,
|
||||||
/*channels*/ 2, /*channel_idx*/ 2, /*framecount*/ 0,
|
/*channels*/ 2, /*channel_idx*/ 2, /*framecount*/ 0,
|
||||||
/*samplerate_idx*/ 3, /*length*/ 0, /*samplerate*/ 48000};
|
/*samplerate_idx*/ 3, /*length*/ 0, /*samplerate*/ 48000};
|
||||||
};
|
};
|
||||||
@ -54,7 +54,7 @@ std::optional<BinaryMessage> MediaNDKDecoder::Impl::Initalize(const BinaryMessag
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaNDKDecoder::Impl::SetMediaType(const ADTSData& adts_data) {
|
bool MediaNDKDecoder::Impl::SetMediaType(const AudioCore::ADTSData& adts_data) {
|
||||||
const char* mime = "audio/mp4a-latm";
|
const char* mime = "audio/mp4a-latm";
|
||||||
if (decoder && mADTSData.profile == adts_data.profile &&
|
if (decoder && mADTSData.profile == adts_data.profile &&
|
||||||
mADTSData.channel_idx == adts_data.channel_idx &&
|
mADTSData.channel_idx == adts_data.channel_idx &&
|
||||||
@ -110,7 +110,11 @@ std::optional<BinaryMessage> MediaNDKDecoder::Impl::ProcessRequest(const BinaryM
|
|||||||
case DecoderCommand::EncodeDecode: {
|
case DecoderCommand::EncodeDecode: {
|
||||||
return Decode(request);
|
return Decode(request);
|
||||||
}
|
}
|
||||||
case DecoderCommand::Unknown: {
|
case DecoderCommand::Shutdown:
|
||||||
|
case DecoderCommand::SaveState:
|
||||||
|
case DecoderCommand::LoadState: {
|
||||||
|
LOG_WARNING(Audio_DSP, "Got unimplemented binary request: {}",
|
||||||
|
static_cast<u16>(request.header.cmd));
|
||||||
BinaryMessage response = request;
|
BinaryMessage response = request;
|
||||||
response.header.result = ResultStatus::Success;
|
response.header.result = ResultStatus::Success;
|
||||||
return response;
|
return response;
|
||||||
@ -137,8 +141,9 @@ std::optional<BinaryMessage> MediaNDKDecoder::Impl::Decode(const BinaryMessage&
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
|
const u8* data =
|
||||||
ADTSData adts_data = ParseADTS(reinterpret_cast<const char*>(data));
|
memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
|
||||||
|
ADTSData adts_data = AudioCore::ParseADTS(data);
|
||||||
SetMediaType(adts_data);
|
SetMediaType(adts_data);
|
||||||
response.decode_aac_response.sample_rate = GetSampleRateEnum(adts_data.samplerate);
|
response.decode_aac_response.sample_rate = GetSampleRateEnum(adts_data.samplerate);
|
||||||
response.decode_aac_response.num_channels = adts_data.channels;
|
response.decode_aac_response.num_channels = adts_data.channels;
|
||||||
|
@ -23,7 +23,8 @@ private:
|
|||||||
|
|
||||||
std::optional<BinaryMessage> Decode(const BinaryMessage& request);
|
std::optional<BinaryMessage> Decode(const BinaryMessage& request);
|
||||||
|
|
||||||
MFOutputState DecodingLoop(ADTSData adts_header, std::array<std::vector<u8>, 2>& out_streams);
|
MFOutputState DecodingLoop(AudioCore::ADTSData adts_header,
|
||||||
|
std::array<std::vector<u8>, 2>& out_streams);
|
||||||
|
|
||||||
bool transform_initialized = false;
|
bool transform_initialized = false;
|
||||||
bool format_selected = false;
|
bool format_selected = false;
|
||||||
@ -115,7 +116,11 @@ std::optional<BinaryMessage> WMFDecoder::Impl::ProcessRequest(const BinaryMessag
|
|||||||
case DecoderCommand::EncodeDecode: {
|
case DecoderCommand::EncodeDecode: {
|
||||||
return Decode(request);
|
return Decode(request);
|
||||||
}
|
}
|
||||||
case DecoderCommand::Unknown: {
|
case DecoderCommand::Shutdown:
|
||||||
|
case DecoderCommand::SaveState:
|
||||||
|
case DecoderCommand::LoadState: {
|
||||||
|
LOG_WARNING(Audio_DSP, "Got unimplemented binary request: {}",
|
||||||
|
static_cast<u16>(request.header.cmd));
|
||||||
BinaryMessage response = request;
|
BinaryMessage response = request;
|
||||||
response.header.result = ResultStatus::Success;
|
response.header.result = ResultStatus::Success;
|
||||||
return response;
|
return response;
|
||||||
@ -135,7 +140,7 @@ std::optional<BinaryMessage> WMFDecoder::Impl::Initalize(const BinaryMessage& re
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
MFOutputState WMFDecoder::Impl::DecodingLoop(ADTSData adts_header,
|
MFOutputState WMFDecoder::Impl::DecodingLoop(AudioCore::ADTSData adts_header,
|
||||||
std::array<std::vector<u8>, 2>& out_streams) {
|
std::array<std::vector<u8>, 2>& out_streams) {
|
||||||
std::optional<std::vector<f32>> output_buffer;
|
std::optional<std::vector<f32>> output_buffer;
|
||||||
|
|
||||||
@ -206,14 +211,14 @@ std::optional<BinaryMessage> WMFDecoder::Impl::Decode(const BinaryMessage& reque
|
|||||||
request.decode_aac_request.src_addr);
|
request.decode_aac_request.src_addr);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
|
const u8* data =
|
||||||
|
memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
|
||||||
|
|
||||||
std::array<std::vector<u8>, 2> out_streams;
|
std::array<std::vector<u8>, 2> out_streams;
|
||||||
unique_mfptr<IMFSample> sample;
|
unique_mfptr<IMFSample> sample;
|
||||||
MFInputState input_status = MFInputState::OK;
|
MFInputState input_status = MFInputState::OK;
|
||||||
MFOutputState output_status = MFOutputState::OK;
|
MFOutputState output_status = MFOutputState::OK;
|
||||||
std::optional<ADTSMeta> adts_meta =
|
std::optional<ADTSMeta> adts_meta = DetectMediaType(data, request.decode_aac_request.size);
|
||||||
DetectMediaType((char*)data, request.decode_aac_request.size);
|
|
||||||
|
|
||||||
if (!adts_meta) {
|
if (!adts_meta) {
|
||||||
LOG_ERROR(Audio_DSP, "Unable to deduce decoding parameters from ADTS stream");
|
LOG_ERROR(Audio_DSP, "Unable to deduce decoding parameters from ADTS stream");
|
||||||
|
@ -110,8 +110,9 @@ unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignmen
|
|||||||
return sample;
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSData& adts,
|
bool SelectInputMediaType(IMFTransform* transform, int in_stream_id,
|
||||||
const UINT8* user_data, UINT32 user_data_len, GUID audio_format) {
|
const AudioCore::ADTSData& adts, const UINT8* user_data,
|
||||||
|
UINT32 user_data_len, GUID audio_format) {
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
unique_mfptr<IMFMediaType> t;
|
unique_mfptr<IMFMediaType> t;
|
||||||
|
|
||||||
@ -190,12 +191,12 @@ bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, GUID audi
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ADTSMeta> DetectMediaType(char* buffer, std::size_t len) {
|
std::optional<ADTSMeta> DetectMediaType(const u8* buffer, std::size_t len) {
|
||||||
if (len < 7) {
|
if (len < 7) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADTSData tmp;
|
AudioCore::ADTSData tmp;
|
||||||
ADTSMeta result;
|
ADTSMeta result;
|
||||||
// see https://docs.microsoft.com/en-us/windows/desktop/api/mmreg/ns-mmreg-heaacwaveinfo_tag
|
// see https://docs.microsoft.com/en-us/windows/desktop/api/mmreg/ns-mmreg-heaacwaveinfo_tag
|
||||||
// for the meaning of the byte array below
|
// for the meaning of the byte array below
|
||||||
@ -207,7 +208,7 @@ std::optional<ADTSMeta> DetectMediaType(char* buffer, std::size_t len) {
|
|||||||
UINT8 aac_tmp[] = {0x01, 0x00, 0xfe, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x00, 0x00};
|
UINT8 aac_tmp[] = {0x01, 0x00, 0xfe, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x00, 0x00};
|
||||||
uint16_t tag = 0;
|
uint16_t tag = 0;
|
||||||
|
|
||||||
tmp = ParseADTS(buffer);
|
tmp = AudioCore::ParseADTS(buffer);
|
||||||
if (tmp.length == 0) {
|
if (tmp.length == 0) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -215,7 +216,7 @@ std::optional<ADTSMeta> DetectMediaType(char* buffer, std::size_t len) {
|
|||||||
tag = MFGetAACTag(tmp);
|
tag = MFGetAACTag(tmp);
|
||||||
aac_tmp[12] |= (tag & 0xff00) >> 8;
|
aac_tmp[12] |= (tag & 0xff00) >> 8;
|
||||||
aac_tmp[13] |= (tag & 0x00ff);
|
aac_tmp[13] |= (tag & 0x00ff);
|
||||||
std::memcpy(&(result.ADTSHeader), &tmp, sizeof(ADTSData));
|
std::memcpy(&(result.ADTSHeader), &tmp, sizeof(AudioCore::ADTSData));
|
||||||
std::memcpy(&(result.AACTag), aac_tmp, 14);
|
std::memcpy(&(result.AACTag), aac_tmp, 14);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ void ReportError(std::string msg, HRESULT hr);
|
|||||||
|
|
||||||
// data type for transferring ADTS metadata between functions
|
// data type for transferring ADTS metadata between functions
|
||||||
struct ADTSMeta {
|
struct ADTSMeta {
|
||||||
ADTSData ADTSHeader;
|
AudioCore::ADTSData ADTSHeader;
|
||||||
u8 AACTag[14];
|
u8 AACTag[14];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -110,10 +110,10 @@ bool InitMFDLL();
|
|||||||
unique_mfptr<IMFTransform> MFDecoderInit(GUID audio_format = MFAudioFormat_AAC);
|
unique_mfptr<IMFTransform> MFDecoderInit(GUID audio_format = MFAudioFormat_AAC);
|
||||||
unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignment = 1,
|
unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignment = 1,
|
||||||
LONGLONG duration = 0);
|
LONGLONG duration = 0);
|
||||||
bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSData& adts,
|
bool SelectInputMediaType(IMFTransform* transform, int in_stream_id,
|
||||||
const UINT8* user_data, UINT32 user_data_len,
|
const AudioCore::ADTSData& adts, const UINT8* user_data,
|
||||||
GUID audio_format = MFAudioFormat_AAC);
|
UINT32 user_data_len, GUID audio_format = MFAudioFormat_AAC);
|
||||||
std::optional<ADTSMeta> DetectMediaType(char* buffer, std::size_t len);
|
std::optional<ADTSMeta> DetectMediaType(const u8* buffer, std::size_t len);
|
||||||
bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id,
|
bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id,
|
||||||
GUID audio_format = MFAudioFormat_PCM);
|
GUID audio_format = MFAudioFormat_PCM);
|
||||||
void MFFlush(IMFTransform* transform);
|
void MFFlush(IMFTransform* transform);
|
||||||
|
@ -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,11 +15,11 @@
|
|||||||
#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"
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/logging/filter.h"
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
@ -28,18 +28,15 @@
|
|||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/dumping/backend.h"
|
#include "core/dumping/backend.h"
|
||||||
#include "core/dumping/ffmpeg_backend.h"
|
#include "core/dumping/ffmpeg_backend.h"
|
||||||
#include "core/file_sys/cia_container.h"
|
|
||||||
#include "core/frontend/applets/default_applets.h"
|
#include "core/frontend/applets/default_applets.h"
|
||||||
#include "core/frontend/framebuffer_layout.h"
|
#include "core/frontend/framebuffer_layout.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/cfg/cfg.h"
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/loader/loader.h"
|
|
||||||
#include "core/movie.h"
|
#include "core/movie.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/video_core.h"
|
|
||||||
|
|
||||||
#undef _UNICODE
|
#undef _UNICODE
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -331,7 +328,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& movie = Core::Movie::GetInstance();
|
auto& movie = system.Movie();
|
||||||
|
|
||||||
if (!movie_record.empty()) {
|
if (!movie_record.empty()) {
|
||||||
movie.PrepareForRecording();
|
movie.PrepareForRecording();
|
||||||
@ -355,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
|
||||||
|
@ -128,16 +128,54 @@ void EmuWindow_SDL2::InitializeSDL2() {
|
|||||||
SDL_SetMainReady();
|
SDL_SetMainReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 EmuWindow_SDL2::GetEventWindowId(const SDL_Event& event) const {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
return event.window.windowID;
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
case SDL_KEYUP:
|
||||||
|
return event.key.windowID;
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
return event.motion.windowID;
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
return event.button.windowID;
|
||||||
|
case SDL_MOUSEWHEEL:
|
||||||
|
return event.wheel.windowID;
|
||||||
|
case SDL_FINGERDOWN:
|
||||||
|
case SDL_FINGERMOTION:
|
||||||
|
case SDL_FINGERUP:
|
||||||
|
return event.tfinger.windowID;
|
||||||
|
case SDL_TEXTEDITING:
|
||||||
|
return event.edit.windowID;
|
||||||
|
case SDL_TEXTEDITING_EXT:
|
||||||
|
return event.editExt.windowID;
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
return event.text.windowID;
|
||||||
|
case SDL_DROPBEGIN:
|
||||||
|
case SDL_DROPFILE:
|
||||||
|
case SDL_DROPTEXT:
|
||||||
|
case SDL_DROPCOMPLETE:
|
||||||
|
return event.drop.windowID;
|
||||||
|
case SDL_USEREVENT:
|
||||||
|
return event.user.windowID;
|
||||||
|
default:
|
||||||
|
// Event is not for any particular window, so we can just pretend it's for this one.
|
||||||
|
return render_window_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::PollEvents() {
|
void EmuWindow_SDL2::PollEvents() {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
std::vector<SDL_Event> other_window_events;
|
std::vector<SDL_Event> other_window_events;
|
||||||
|
|
||||||
// SDL_PollEvent returns 0 when there are no more events in the event queue
|
// SDL_PollEvent returns 0 when there are no more events in the event queue
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
if (event.window.windowID != render_window_id) {
|
if (GetEventWindowId(event) != render_window_id) {
|
||||||
other_window_events.push_back(event);
|
other_window_events.push_back(event);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
switch (event.window.event) {
|
switch (event.window.event) {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
|
|
||||||
|
union SDL_Event;
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -35,6 +36,9 @@ public:
|
|||||||
void RequestClose();
|
void RequestClose();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// Gets the ID of the window an event originated from.
|
||||||
|
u32 GetEventWindowId(const SDL_Event& event) const;
|
||||||
|
|
||||||
/// Called by PollEvents when a key is pressed or released.
|
/// Called by PollEvents when a key is pressed or released.
|
||||||
void OnKeyEvent(int key, u8 state);
|
void OnKeyEvent(int key, u8 state);
|
||||||
|
|
||||||
|
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
|
||||||
@ -342,7 +344,7 @@ if (USE_DISCORD_PRESENCE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_WEB_SERVICE)
|
if (ENABLE_WEB_SERVICE)
|
||||||
target_compile_definitions(citra-qt PRIVATE -DENABLE_WEB_SERVICE)
|
target_link_libraries(citra-qt PRIVATE web_service)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
|
@ -67,6 +67,5 @@ void QtMiiSelector::OpenDialog() {
|
|||||||
dialog.return_code, index);
|
dialog.return_code, index);
|
||||||
|
|
||||||
const auto mii_data = dialog.miis.at(index);
|
const auto mii_data = dialog.miis.at(index);
|
||||||
Finalize(dialog.return_code,
|
Finalize(dialog.return_code, dialog.return_code == 0 ? std::move(mii_data) : Mii::MiiData{});
|
||||||
dialog.return_code == 0 ? std::move(mii_data) : HLE::Applets::MiiData{});
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ private:
|
|||||||
QVBoxLayout* layout;
|
QVBoxLayout* layout;
|
||||||
QtMiiSelector* mii_selector;
|
QtMiiSelector* mii_selector;
|
||||||
u32 return_code = 0;
|
u32 return_code = 0;
|
||||||
std::vector<HLE::Applets::MiiData> miis;
|
std::vector<Mii::MiiData> miis;
|
||||||
|
|
||||||
friend class QtMiiSelector;
|
friend class QtMiiSelector;
|
||||||
};
|
};
|
||||||
|
@ -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,27 @@ 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);
|
||||||
|
}
|
||||||
|
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 +334,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);
|
||||||
@ -387,10 +403,6 @@ GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread_, Core::Sys
|
|||||||
bool is_secondary_)
|
bool is_secondary_)
|
||||||
: QWidget(parent_), EmuWindow(is_secondary_), emu_thread(emu_thread_), system{system_} {
|
: QWidget(parent_), EmuWindow(is_secondary_), emu_thread(emu_thread_), system{system_} {
|
||||||
|
|
||||||
setWindowTitle(QStringLiteral("Citra %1 | %2-%3")
|
|
||||||
.arg(QString::fromUtf8(Common::g_build_name),
|
|
||||||
QString::fromUtf8(Common::g_scm_branch),
|
|
||||||
QString::fromUtf8(Common::g_scm_desc)));
|
|
||||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||||
auto layout = new QHBoxLayout(this);
|
auto layout = new QHBoxLayout(this);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
@ -605,6 +617,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
|
||||||
@ -690,6 +705,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();
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "citra_qt/compatdb.h"
|
#include "citra_qt/compatdb.h"
|
||||||
#include "common/telemetry.h"
|
#include "common/telemetry.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "ui_compatdb.h"
|
#include "ui_compatdb.h"
|
||||||
|
|
||||||
CompatDB::CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent)
|
CompatDB::CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent)
|
||||||
|
@ -29,7 +29,7 @@ Config::~Config() {
|
|||||||
const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
|
const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
|
||||||
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G,
|
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G,
|
||||||
Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N,
|
Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N,
|
||||||
Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B,
|
Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_V,
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
|
const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
|
||||||
@ -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);
|
||||||
@ -772,6 +777,11 @@ void Config::ReadUIGameListValues() {
|
|||||||
ReadBasicSetting(UISettings::values.game_list_hide_no_icon);
|
ReadBasicSetting(UISettings::values.game_list_hide_no_icon);
|
||||||
ReadBasicSetting(UISettings::values.game_list_single_line_mode);
|
ReadBasicSetting(UISettings::values.game_list_single_line_mode);
|
||||||
|
|
||||||
|
ReadBasicSetting(UISettings::values.show_compat_column);
|
||||||
|
ReadBasicSetting(UISettings::values.show_region_column);
|
||||||
|
ReadBasicSetting(UISettings::values.show_type_column);
|
||||||
|
ReadBasicSetting(UISettings::values.show_size_column);
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1102,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);
|
||||||
@ -1230,6 +1244,11 @@ void Config::SaveUIGameListValues() {
|
|||||||
WriteBasicSetting(UISettings::values.game_list_hide_no_icon);
|
WriteBasicSetting(UISettings::values.game_list_hide_no_icon);
|
||||||
WriteBasicSetting(UISettings::values.game_list_single_line_mode);
|
WriteBasicSetting(UISettings::values.game_list_single_line_mode);
|
||||||
|
|
||||||
|
WriteBasicSetting(UISettings::values.show_compat_column);
|
||||||
|
WriteBasicSetting(UISettings::values.show_region_column);
|
||||||
|
WriteBasicSetting(UISettings::values.show_type_column);
|
||||||
|
WriteBasicSetting(UISettings::values.show_size_column);
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,68 +21,8 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>-1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="ConfigureGeneral" name="generalTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>General</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureSystem" name="systemTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>System</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureInput" name="inputTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Input</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureHotkeys" name="hotkeysTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Hotkeys</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureGraphics" name="graphicsTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Graphics</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureEnhancements" name="enhancementsTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Enhancements</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureAudio" name="audioTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Audio</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureCamera" name="cameraTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Camera</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureDebug" name="debugTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Debug</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureStorage" name="storageTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Storage</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureWeb" name="webTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Web</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
<widget class="ConfigureUi" name="uiTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>UI</string>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -10,14 +10,13 @@
|
|||||||
#include "citra_qt/configuration/configuration_shared.h"
|
#include "citra_qt/configuration/configuration_shared.h"
|
||||||
#include "citra_qt/configuration/configure_audio.h"
|
#include "citra_qt/configuration/configure_audio.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
|
||||||
#include "ui_configure_audio.h"
|
#include "ui_configure_audio.h"
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include "common/apple_authorization.h"
|
#include "common/apple_authorization.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ConfigureAudio::ConfigureAudio(QWidget* parent)
|
ConfigureAudio::ConfigureAudio(bool is_powered_on, QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@ -27,8 +26,7 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
|
|||||||
AudioCore::GetSinkName(static_cast<AudioCore::SinkType>(type)).data()));
|
AudioCore::GetSinkName(static_cast<AudioCore::SinkType>(type)).data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool is_running = Core::System::GetInstance().IsPoweredOn();
|
ui->emulation_combo_box->setEnabled(!is_powered_on);
|
||||||
ui->emulation_combo_box->setEnabled(!is_running);
|
|
||||||
|
|
||||||
connect(ui->volume_slider, &QSlider::valueChanged, this,
|
connect(ui->volume_slider, &QSlider::valueChanged, this,
|
||||||
&ConfigureAudio::SetVolumeIndicatorText);
|
&ConfigureAudio::SetVolumeIndicatorText);
|
||||||
|
@ -19,7 +19,7 @@ class ConfigureAudio : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureAudio(QWidget* parent = nullptr);
|
explicit ConfigureAudio(bool is_powered_on, QWidget* parent = nullptr);
|
||||||
~ConfigureAudio() override;
|
~ConfigureAudio() override;
|
||||||
|
|
||||||
void ApplyConfiguration();
|
void ApplyConfiguration();
|
||||||
|
@ -47,8 +47,7 @@ ConfigureCamera::~ConfigureCamera() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureCamera::ConnectEvents() {
|
void ConfigureCamera::ConnectEvents() {
|
||||||
connect(ui->image_source,
|
connect(ui->image_source, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
|
||||||
[this](int index) {
|
[this](int index) {
|
||||||
StopPreviewing();
|
StopPreviewing();
|
||||||
UpdateImageSourceUI();
|
UpdateImageSourceUI();
|
||||||
@ -58,36 +57,33 @@ void ConfigureCamera::ConnectEvents() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
connect(ui->camera_selection,
|
connect(ui->camera_selection, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this] {
|
StopPreviewing();
|
||||||
StopPreviewing();
|
if (GetCameraSelection() != current_selected) {
|
||||||
if (GetCameraSelection() != current_selected) {
|
RecordConfig();
|
||||||
RecordConfig();
|
}
|
||||||
}
|
if (ui->camera_selection->currentIndex() == 1) {
|
||||||
if (ui->camera_selection->currentIndex() == 1) {
|
ui->camera_mode->setCurrentIndex(1); // Double
|
||||||
ui->camera_mode->setCurrentIndex(1); // Double
|
if (camera_name[0] == camera_name[2] && camera_config[0] == camera_config[2]) {
|
||||||
if (camera_name[0] == camera_name[2] && camera_config[0] == camera_config[2]) {
|
ui->camera_mode->setCurrentIndex(0); // Single
|
||||||
ui->camera_mode->setCurrentIndex(0); // Single
|
}
|
||||||
}
|
}
|
||||||
}
|
UpdateCameraMode();
|
||||||
UpdateCameraMode();
|
SetConfiguration();
|
||||||
SetConfiguration();
|
});
|
||||||
});
|
connect(ui->camera_mode, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
|
||||||
connect(ui->camera_mode, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
StopPreviewing();
|
||||||
this, [this] {
|
ui->camera_position_label->setVisible(ui->camera_mode->currentIndex() == 1);
|
||||||
StopPreviewing();
|
ui->camera_position->setVisible(ui->camera_mode->currentIndex() == 1);
|
||||||
ui->camera_position_label->setVisible(ui->camera_mode->currentIndex() == 1);
|
current_selected = GetCameraSelection();
|
||||||
ui->camera_position->setVisible(ui->camera_mode->currentIndex() == 1);
|
});
|
||||||
current_selected = GetCameraSelection();
|
connect(ui->camera_position, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
|
||||||
});
|
StopPreviewing();
|
||||||
connect(ui->camera_position,
|
if (GetCameraSelection() != current_selected) {
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this] {
|
RecordConfig();
|
||||||
StopPreviewing();
|
}
|
||||||
if (GetCameraSelection() != current_selected) {
|
SetConfiguration();
|
||||||
RecordConfig();
|
});
|
||||||
}
|
|
||||||
SetConfiguration();
|
|
||||||
});
|
|
||||||
connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked);
|
connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked);
|
||||||
connect(ui->preview_button, &QPushButton::clicked, this, [this] { StartPreviewing(); });
|
connect(ui->preview_button, &QPushButton::clicked, this, [this] { StartPreviewing(); });
|
||||||
connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) {
|
connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) {
|
||||||
|
@ -9,11 +9,9 @@
|
|||||||
#include "core/cheats/cheat_base.h"
|
#include "core/cheats/cheat_base.h"
|
||||||
#include "core/cheats/cheats.h"
|
#include "core/cheats/cheats.h"
|
||||||
#include "core/cheats/gateway_cheat.h"
|
#include "core/cheats/gateway_cheat.h"
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/hle/kernel/process.h"
|
|
||||||
#include "ui_configure_cheats.h"
|
#include "ui_configure_cheats.h"
|
||||||
|
|
||||||
ConfigureCheats::ConfigureCheats(u64 title_id_, QWidget* parent)
|
ConfigureCheats::ConfigureCheats(Core::System& system, u64 title_id_, QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureCheats>()), title_id{title_id_} {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureCheats>()), title_id{title_id_} {
|
||||||
// Setup gui control settings
|
// Setup gui control settings
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
@ -36,7 +34,7 @@ ConfigureCheats::ConfigureCheats(u64 title_id_, QWidget* parent)
|
|||||||
[this] { SaveCheat(ui->tableCheats->currentRow()); });
|
[this] { SaveCheat(ui->tableCheats->currentRow()); });
|
||||||
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureCheats::OnDeleteCheat);
|
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureCheats::OnDeleteCheat);
|
||||||
|
|
||||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, Core::System::GetInstance());
|
cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, system);
|
||||||
|
|
||||||
LoadCheats();
|
LoadCheats();
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <QWidget>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Cheats {
|
namespace Cheats {
|
||||||
@ -12,6 +13,10 @@ class CheatBase;
|
|||||||
class CheatEngine;
|
class CheatEngine;
|
||||||
} // namespace Cheats
|
} // namespace Cheats
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ConfigureCheats;
|
class ConfigureCheats;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
@ -20,7 +25,7 @@ class ConfigureCheats : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureCheats(u64 title_id_, QWidget* parent = nullptr);
|
explicit ConfigureCheats(Core::System& system, u64 title_id, QWidget* parent = nullptr);
|
||||||
~ConfigureCheats();
|
~ConfigureCheats();
|
||||||
bool ApplyConfiguration();
|
bool ApplyConfiguration();
|
||||||
|
|
||||||
|
@ -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"
|
||||||
@ -11,8 +12,8 @@
|
|||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.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
|
||||||
@ -25,8 +26,8 @@ static constexpr int SettingsToSlider(int value) {
|
|||||||
return (value - 5) / 5;
|
return (value - 5) / 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureDebug::ConfigureDebug(QWidget* parent)
|
ConfigureDebug::ConfigureDebug(bool is_powered_on_, QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureDebug>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureDebug>()), is_powered_on{is_powered_on_} {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
|
|
||||||
@ -35,9 +36,39 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
|
|||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||||
});
|
});
|
||||||
|
|
||||||
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
|
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%")
|
||||||
@ -59,11 +90,12 @@ void ConfigureDebug::SetConfiguration() {
|
|||||||
ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub.GetValue());
|
ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub.GetValue());
|
||||||
ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub.GetValue());
|
ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub.GetValue());
|
||||||
ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port.GetValue());
|
ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port.GetValue());
|
||||||
ui->toggle_console->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
ui->toggle_console->setEnabled(!is_powered_on);
|
||||||
ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
|
ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
|
||||||
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()) {
|
||||||
@ -94,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,
|
||||||
|
@ -15,7 +15,7 @@ class ConfigureDebug : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureDebug(QWidget* parent = nullptr);
|
explicit ConfigureDebug(bool is_powered_on, QWidget* parent = nullptr);
|
||||||
~ConfigureDebug() override;
|
~ConfigureDebug() override;
|
||||||
|
|
||||||
void ApplyConfiguration();
|
void ApplyConfiguration();
|
||||||
@ -25,4 +25,5 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::ConfigureDebug> ui;
|
std::unique_ptr<Ui::ConfigureDebug> ui;
|
||||||
|
bool is_powered_on;
|
||||||
};
|
};
|
||||||
|
@ -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>
|
||||||
|
@ -4,26 +4,62 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <QListWidgetItem>
|
#include <QListWidgetItem>
|
||||||
#include "citra_qt/configuration/config.h"
|
#include "citra_qt/configuration/configure_audio.h"
|
||||||
|
#include "citra_qt/configuration/configure_camera.h"
|
||||||
|
#include "citra_qt/configuration/configure_debug.h"
|
||||||
#include "citra_qt/configuration/configure_dialog.h"
|
#include "citra_qt/configuration/configure_dialog.h"
|
||||||
|
#include "citra_qt/configuration/configure_enhancements.h"
|
||||||
|
#include "citra_qt/configuration/configure_general.h"
|
||||||
|
#include "citra_qt/configuration/configure_graphics.h"
|
||||||
|
#include "citra_qt/configuration/configure_hotkeys.h"
|
||||||
|
#include "citra_qt/configuration/configure_input.h"
|
||||||
|
#include "citra_qt/configuration/configure_storage.h"
|
||||||
|
#include "citra_qt/configuration/configure_system.h"
|
||||||
|
#include "citra_qt/configuration/configure_ui.h"
|
||||||
|
#include "citra_qt/configuration/configure_web.h"
|
||||||
#include "citra_qt/hotkeys.h"
|
#include "citra_qt/hotkeys.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#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_} {
|
system{system_}, is_powered_on{system.IsPoweredOn()},
|
||||||
|
general_tab{std::make_unique<ConfigureGeneral>(this)},
|
||||||
|
system_tab{std::make_unique<ConfigureSystem>(system, this)},
|
||||||
|
input_tab{std::make_unique<ConfigureInput>(this)},
|
||||||
|
hotkeys_tab{std::make_unique<ConfigureHotkeys>(this)},
|
||||||
|
graphics_tab{std::make_unique<ConfigureGraphics>(physical_devices, is_powered_on, this)},
|
||||||
|
enhancements_tab{std::make_unique<ConfigureEnhancements>(this)},
|
||||||
|
audio_tab{std::make_unique<ConfigureAudio>(is_powered_on, this)},
|
||||||
|
camera_tab{std::make_unique<ConfigureCamera>(this)},
|
||||||
|
debug_tab{std::make_unique<ConfigureDebug>(is_powered_on, this)},
|
||||||
|
storage_tab{std::make_unique<ConfigureStorage>(is_powered_on, this)},
|
||||||
|
web_tab{std::make_unique<ConfigureWeb>(this)}, ui_tab{std::make_unique<ConfigureUi>(this)} {
|
||||||
Settings::SetConfiguringGlobal(true);
|
Settings::SetConfiguringGlobal(true);
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->hotkeysTab->Populate(registry);
|
|
||||||
ui->webTab->SetWebServiceConfigEnabled(enable_web_config);
|
ui->tabWidget->addTab(general_tab.get(), tr("General"));
|
||||||
|
ui->tabWidget->addTab(system_tab.get(), tr("System"));
|
||||||
|
ui->tabWidget->addTab(input_tab.get(), tr("Input"));
|
||||||
|
ui->tabWidget->addTab(hotkeys_tab.get(), tr("Hotkeys"));
|
||||||
|
ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics"));
|
||||||
|
ui->tabWidget->addTab(enhancements_tab.get(), tr("Enhancements"));
|
||||||
|
ui->tabWidget->addTab(audio_tab.get(), tr("Audio"));
|
||||||
|
ui->tabWidget->addTab(camera_tab.get(), tr("Camera"));
|
||||||
|
ui->tabWidget->addTab(debug_tab.get(), tr("Debug"));
|
||||||
|
ui->tabWidget->addTab(storage_tab.get(), tr("Storage"));
|
||||||
|
ui->tabWidget->addTab(web_tab.get(), tr("Web"));
|
||||||
|
ui->tabWidget->addTab(ui_tab.get(), tr("UI"));
|
||||||
|
|
||||||
|
hotkeys_tab->Populate(registry);
|
||||||
|
web_tab->SetWebServiceConfigEnabled(enable_web_config);
|
||||||
|
|
||||||
PopulateSelectionList();
|
PopulateSelectionList();
|
||||||
|
|
||||||
connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
|
connect(ui_tab.get(), &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
|
||||||
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
|
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
|
||||||
&ConfigureDialog::UpdateVisibleTabs);
|
&ConfigureDialog::UpdateVisibleTabs);
|
||||||
|
|
||||||
@ -31,46 +67,46 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Cor
|
|||||||
ui->selectorList->setCurrentRow(0);
|
ui->selectorList->setCurrentRow(0);
|
||||||
|
|
||||||
// Set up used key list synchronisation
|
// Set up used key list synchronisation
|
||||||
connect(ui->inputTab, &ConfigureInput::InputKeysChanged, ui->hotkeysTab,
|
connect(input_tab.get(), &ConfigureInput::InputKeysChanged, hotkeys_tab.get(),
|
||||||
&ConfigureHotkeys::OnInputKeysChanged);
|
&ConfigureHotkeys::OnInputKeysChanged);
|
||||||
connect(ui->hotkeysTab, &ConfigureHotkeys::HotkeysChanged, ui->inputTab,
|
connect(hotkeys_tab.get(), &ConfigureHotkeys::HotkeysChanged, input_tab.get(),
|
||||||
&ConfigureInput::OnHotkeysChanged);
|
&ConfigureInput::OnHotkeysChanged);
|
||||||
|
|
||||||
// Synchronise lists upon initialisation
|
// Synchronise lists upon initialisation
|
||||||
ui->inputTab->EmitInputKeysChanged();
|
input_tab->EmitInputKeysChanged();
|
||||||
ui->hotkeysTab->EmitHotkeysChanged();
|
hotkeys_tab->EmitHotkeysChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureDialog::~ConfigureDialog() = default;
|
ConfigureDialog::~ConfigureDialog() = default;
|
||||||
|
|
||||||
void ConfigureDialog::SetConfiguration() {
|
void ConfigureDialog::SetConfiguration() {
|
||||||
ui->generalTab->SetConfiguration();
|
general_tab->SetConfiguration();
|
||||||
ui->systemTab->SetConfiguration();
|
system_tab->SetConfiguration();
|
||||||
ui->inputTab->LoadConfiguration();
|
input_tab->LoadConfiguration();
|
||||||
ui->graphicsTab->SetConfiguration();
|
graphics_tab->SetConfiguration();
|
||||||
ui->enhancementsTab->SetConfiguration();
|
enhancements_tab->SetConfiguration();
|
||||||
ui->audioTab->SetConfiguration();
|
audio_tab->SetConfiguration();
|
||||||
ui->cameraTab->SetConfiguration();
|
camera_tab->SetConfiguration();
|
||||||
ui->debugTab->SetConfiguration();
|
debug_tab->SetConfiguration();
|
||||||
ui->webTab->SetConfiguration();
|
web_tab->SetConfiguration();
|
||||||
ui->uiTab->SetConfiguration();
|
ui_tab->SetConfiguration();
|
||||||
ui->storageTab->SetConfiguration();
|
storage_tab->SetConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureDialog::ApplyConfiguration() {
|
void ConfigureDialog::ApplyConfiguration() {
|
||||||
ui->generalTab->ApplyConfiguration();
|
general_tab->ApplyConfiguration();
|
||||||
ui->systemTab->ApplyConfiguration();
|
system_tab->ApplyConfiguration();
|
||||||
ui->inputTab->ApplyConfiguration();
|
input_tab->ApplyConfiguration();
|
||||||
ui->inputTab->ApplyProfile();
|
input_tab->ApplyProfile();
|
||||||
ui->hotkeysTab->ApplyConfiguration(registry);
|
hotkeys_tab->ApplyConfiguration(registry);
|
||||||
ui->graphicsTab->ApplyConfiguration();
|
graphics_tab->ApplyConfiguration();
|
||||||
ui->enhancementsTab->ApplyConfiguration();
|
enhancements_tab->ApplyConfiguration();
|
||||||
ui->audioTab->ApplyConfiguration();
|
audio_tab->ApplyConfiguration();
|
||||||
ui->cameraTab->ApplyConfiguration();
|
camera_tab->ApplyConfiguration();
|
||||||
ui->debugTab->ApplyConfiguration();
|
debug_tab->ApplyConfiguration();
|
||||||
ui->webTab->ApplyConfiguration();
|
web_tab->ApplyConfiguration();
|
||||||
ui->uiTab->ApplyConfiguration();
|
ui_tab->ApplyConfiguration();
|
||||||
ui->storageTab->ApplyConfiguration();
|
storage_tab->ApplyConfiguration();
|
||||||
system.ApplySettings();
|
system.ApplySettings();
|
||||||
Settings::LogSettings();
|
Settings::LogSettings();
|
||||||
}
|
}
|
||||||
@ -81,11 +117,11 @@ void ConfigureDialog::PopulateSelectionList() {
|
|||||||
ui->selectorList->clear();
|
ui->selectorList->clear();
|
||||||
|
|
||||||
const std::array<std::pair<QString, QList<QWidget*>>, 5> items{
|
const std::array<std::pair<QString, QList<QWidget*>>, 5> items{
|
||||||
{{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}},
|
{{tr("General"), {general_tab.get(), web_tab.get(), debug_tab.get(), ui_tab.get()}},
|
||||||
{tr("System"), {ui->systemTab, ui->cameraTab, ui->storageTab}},
|
{tr("System"), {system_tab.get(), camera_tab.get(), storage_tab.get()}},
|
||||||
{tr("Graphics"), {ui->enhancementsTab, ui->graphicsTab}},
|
{tr("Graphics"), {enhancements_tab.get(), graphics_tab.get()}},
|
||||||
{tr("Audio"), {ui->audioTab}},
|
{tr("Audio"), {audio_tab.get()}},
|
||||||
{tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}};
|
{tr("Controls"), {input_tab.get(), hotkeys_tab.get()}}}};
|
||||||
|
|
||||||
for (const auto& entry : items) {
|
for (const auto& entry : items) {
|
||||||
auto* const item = new QListWidgetItem(entry.first);
|
auto* const item = new QListWidgetItem(entry.first);
|
||||||
@ -112,18 +148,18 @@ void ConfigureDialog::RetranslateUI() {
|
|||||||
ui->selectorList->setCurrentRow(old_row);
|
ui->selectorList->setCurrentRow(old_row);
|
||||||
ui->tabWidget->setCurrentIndex(old_index);
|
ui->tabWidget->setCurrentIndex(old_index);
|
||||||
|
|
||||||
ui->generalTab->RetranslateUI();
|
general_tab->RetranslateUI();
|
||||||
ui->systemTab->RetranslateUI();
|
system_tab->RetranslateUI();
|
||||||
ui->inputTab->RetranslateUI();
|
input_tab->RetranslateUI();
|
||||||
ui->hotkeysTab->RetranslateUI();
|
hotkeys_tab->RetranslateUI();
|
||||||
ui->graphicsTab->RetranslateUI();
|
graphics_tab->RetranslateUI();
|
||||||
ui->enhancementsTab->RetranslateUI();
|
enhancements_tab->RetranslateUI();
|
||||||
ui->audioTab->RetranslateUI();
|
audio_tab->RetranslateUI();
|
||||||
ui->cameraTab->RetranslateUI();
|
camera_tab->RetranslateUI();
|
||||||
ui->debugTab->RetranslateUI();
|
debug_tab->RetranslateUI();
|
||||||
ui->webTab->RetranslateUI();
|
web_tab->RetranslateUI();
|
||||||
ui->uiTab->RetranslateUI();
|
ui_tab->RetranslateUI();
|
||||||
ui->storageTab->RetranslateUI();
|
storage_tab->RetranslateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureDialog::UpdateVisibleTabs() {
|
void ConfigureDialog::UpdateVisibleTabs() {
|
||||||
@ -131,18 +167,18 @@ void ConfigureDialog::UpdateVisibleTabs() {
|
|||||||
if (items.isEmpty())
|
if (items.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::map<QWidget*, QString> widgets = {{ui->generalTab, tr("General")},
|
const std::map<QWidget*, QString> widgets = {{general_tab.get(), tr("General")},
|
||||||
{ui->systemTab, tr("System")},
|
{system_tab.get(), tr("System")},
|
||||||
{ui->inputTab, tr("Input")},
|
{input_tab.get(), tr("Input")},
|
||||||
{ui->hotkeysTab, tr("Hotkeys")},
|
{hotkeys_tab.get(), tr("Hotkeys")},
|
||||||
{ui->enhancementsTab, tr("Enhancements")},
|
{enhancements_tab.get(), tr("Enhancements")},
|
||||||
{ui->graphicsTab, tr("Advanced")},
|
{graphics_tab.get(), tr("Advanced")},
|
||||||
{ui->audioTab, tr("Audio")},
|
{audio_tab.get(), tr("Audio")},
|
||||||
{ui->cameraTab, tr("Camera")},
|
{camera_tab.get(), tr("Camera")},
|
||||||
{ui->debugTab, tr("Debug")},
|
{debug_tab.get(), tr("Debug")},
|
||||||
{ui->storageTab, tr("Storage")},
|
{storage_tab.get(), tr("Storage")},
|
||||||
{ui->webTab, tr("Web")},
|
{web_tab.get(), tr("Web")},
|
||||||
{ui->uiTab, tr("UI")}};
|
{ui_tab.get(), tr("UI")}};
|
||||||
|
|
||||||
ui->tabWidget->clear();
|
ui->tabWidget->clear();
|
||||||
|
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class HotkeyRegistry;
|
class HotkeyRegistry;
|
||||||
|
|
||||||
@ -17,11 +19,25 @@ namespace Core {
|
|||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConfigureGeneral;
|
||||||
|
class ConfigureSystem;
|
||||||
|
class ConfigureInput;
|
||||||
|
class ConfigureHotkeys;
|
||||||
|
class ConfigureGraphics;
|
||||||
|
class ConfigureEnhancements;
|
||||||
|
class ConfigureAudio;
|
||||||
|
class ConfigureCamera;
|
||||||
|
class ConfigureDebug;
|
||||||
|
class ConfigureStorage;
|
||||||
|
class ConfigureWeb;
|
||||||
|
class ConfigureUi;
|
||||||
|
|
||||||
class ConfigureDialog : public QDialog {
|
class ConfigureDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -42,4 +58,18 @@ private:
|
|||||||
std::unique_ptr<Ui::ConfigureDialog> ui;
|
std::unique_ptr<Ui::ConfigureDialog> ui;
|
||||||
HotkeyRegistry& registry;
|
HotkeyRegistry& registry;
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
bool is_powered_on;
|
||||||
|
|
||||||
|
std::unique_ptr<ConfigureGeneral> general_tab;
|
||||||
|
std::unique_ptr<ConfigureSystem> system_tab;
|
||||||
|
std::unique_ptr<ConfigureInput> input_tab;
|
||||||
|
std::unique_ptr<ConfigureHotkeys> hotkeys_tab;
|
||||||
|
std::unique_ptr<ConfigureGraphics> graphics_tab;
|
||||||
|
std::unique_ptr<ConfigureEnhancements> enhancements_tab;
|
||||||
|
std::unique_ptr<ConfigureAudio> audio_tab;
|
||||||
|
std::unique_ptr<ConfigureCamera> camera_tab;
|
||||||
|
std::unique_ptr<ConfigureDebug> debug_tab;
|
||||||
|
std::unique_ptr<ConfigureStorage> storage_tab;
|
||||||
|
std::unique_ptr<ConfigureWeb> web_tab;
|
||||||
|
std::unique_ptr<ConfigureUi> ui_tab;
|
||||||
};
|
};
|
||||||
|
@ -22,8 +22,7 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
|
|||||||
const bool res_scale_enabled = graphics_api != Settings::GraphicsAPI::Software;
|
const bool res_scale_enabled = graphics_api != Settings::GraphicsAPI::Software;
|
||||||
ui->resolution_factor_combobox->setEnabled(res_scale_enabled);
|
ui->resolution_factor_combobox->setEnabled(res_scale_enabled);
|
||||||
|
|
||||||
connect(ui->render_3d_combobox,
|
connect(ui->render_3d_combobox, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
|
||||||
[this](int currentIndex) {
|
[this](int currentIndex) {
|
||||||
updateShaders(static_cast<Settings::StereoRenderOption>(currentIndex));
|
updateShaders(static_cast<Settings::StereoRenderOption>(currentIndex));
|
||||||
});
|
});
|
||||||
|
@ -6,17 +6,35 @@
|
|||||||
#include "citra_qt/configuration/configuration_shared.h"
|
#include "citra_qt/configuration/configuration_shared.h"
|
||||||
#include "citra_qt/configuration/configure_graphics.h"
|
#include "citra_qt/configuration/configure_graphics.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
|
||||||
#include "ui_configure_graphics.h"
|
#include "ui_configure_graphics.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||||
|
|
||||||
ConfigureGraphics::ConfigureGraphics(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);
|
||||||
|
|
||||||
ui->toggle_vsync_new->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
SetupPerGameUI();
|
||||||
|
|
||||||
|
for (const QString& name : physical_devices) {
|
||||||
|
ui->physical_device_combo->addItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->toggle_vsync_new->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 =
|
||||||
@ -29,12 +47,15 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
|
|||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->toggle_hw_shader, &QCheckBox::toggled, this, [this] {
|
connect(ui->toggle_hw_shader, &QCheckBox::toggled, this, [this] {
|
||||||
|
const bool enabled = ui->toggle_hw_shader->isEnabled();
|
||||||
const bool checked = ui->toggle_hw_shader->isChecked();
|
const bool checked = ui->toggle_hw_shader->isChecked();
|
||||||
ui->hw_shader_group->setEnabled(checked);
|
ui->hw_shader_group->setEnabled(checked && enabled);
|
||||||
ui->toggle_disk_shader_cache->setEnabled(checked);
|
ui->toggle_disk_shader_cache->setEnabled(checked && enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
SetupPerGameUI();
|
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
|
&ConfigureGraphics::SetPhysicalDeviceComboVisibility);
|
||||||
|
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,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());
|
||||||
@ -64,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,
|
||||||
@ -92,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,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(
|
||||||
@ -110,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(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">
|
||||||
@ -19,6 +19,9 @@
|
|||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="accessibleName">
|
||||||
|
<string>Graphics</string>
|
||||||
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="apiBox">
|
<widget class="QGroupBox" name="apiBox">
|
||||||
@ -60,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>
|
||||||
@ -92,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>
|
||||||
@ -140,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>
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "citra_qt/configuration/configure_hotkeys.h"
|
#include "citra_qt/configuration/configure_hotkeys.h"
|
||||||
#include "citra_qt/hotkeys.h"
|
#include "citra_qt/hotkeys.h"
|
||||||
#include "citra_qt/util/sequence_dialog/sequence_dialog.h"
|
#include "citra_qt/util/sequence_dialog/sequence_dialog.h"
|
||||||
#include "common/settings.h"
|
|
||||||
#include "ui_configure_hotkeys.h"
|
#include "ui_configure_hotkeys.h"
|
||||||
|
|
||||||
constexpr int name_column = 0;
|
constexpr int name_column = 0;
|
||||||
@ -189,9 +188,9 @@ void ConfigureHotkeys::PopupContextMenu(const QPoint& menu_location) {
|
|||||||
QAction* clear = context_menu.addAction(tr("Clear"));
|
QAction* clear = context_menu.addAction(tr("Clear"));
|
||||||
|
|
||||||
const auto hotkey_index = index.sibling(index.row(), hotkey_column);
|
const auto hotkey_index = index.sibling(index.row(), hotkey_column);
|
||||||
connect(restore_default, &QAction::triggered,
|
connect(restore_default, &QAction::triggered, this,
|
||||||
[this, hotkey_index] { RestoreHotkey(hotkey_index); });
|
[this, hotkey_index] { RestoreHotkey(hotkey_index); });
|
||||||
connect(clear, &QAction::triggered,
|
connect(clear, &QAction::triggered, this,
|
||||||
[this, hotkey_index] { model->setData(hotkey_index, QString{}); });
|
[this, hotkey_index] { model->setData(hotkey_index, QString{}); });
|
||||||
|
|
||||||
context_menu.exec(ui->hotkey_list->viewport()->mapToGlobal(menu_location));
|
context_menu.exec(ui->hotkey_list->viewport()->mapToGlobal(menu_location));
|
||||||
|
@ -162,7 +162,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
|||||||
ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight,
|
ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight,
|
||||||
ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect,
|
ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect,
|
||||||
ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR,
|
ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR,
|
||||||
ui->buttonHome,
|
ui->buttonHome, ui->buttonPower,
|
||||||
};
|
};
|
||||||
|
|
||||||
analog_map_buttons = {{
|
analog_map_buttons = {{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,19 +24,21 @@
|
|||||||
#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 ? filename : fmt::format("{:016X}", title_id);
|
const auto config_file_name = title_id == 0 ? std::string(FileUtil::GetFilename(filename))
|
||||||
|
: fmt::format("{:016X}", title_id);
|
||||||
game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
|
game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
|
||||||
|
|
||||||
audio_tab = std::make_unique<ConfigureAudio>(this);
|
const bool is_powered_on = system.IsPoweredOn();
|
||||||
|
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>(this);
|
graphics_tab = std::make_unique<ConfigureGraphics>(physical_devices, is_powered_on, this);
|
||||||
system_tab = std::make_unique<ConfigureSystem>(this);
|
system_tab = std::make_unique<ConfigureSystem>(system, this);
|
||||||
debug_tab = std::make_unique<ConfigureDebug>(this);
|
debug_tab = std::make_unique<ConfigureDebug>(is_powered_on, this);
|
||||||
cheat_tab = std::make_unique<ConfigureCheats>(title_id, this);
|
cheat_tab = std::make_unique<ConfigureCheats>(system, title_id, this);
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(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
|
||||||
|
@ -6,12 +6,12 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include "citra_qt/configuration/configure_storage.h"
|
#include "citra_qt/configuration/configure_storage.h"
|
||||||
|
#include "common/file_util.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
|
||||||
#include "ui_configure_storage.h"
|
#include "ui_configure_storage.h"
|
||||||
|
|
||||||
ConfigureStorage::ConfigureStorage(QWidget* parent)
|
ConfigureStorage::ConfigureStorage(bool is_powered_on_, QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureStorage>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureStorage>()), is_powered_on{is_powered_on_} {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ void ConfigureStorage::SetConfiguration() {
|
|||||||
ui->toggle_virtual_sd->setChecked(Settings::values.use_virtual_sd.GetValue());
|
ui->toggle_virtual_sd->setChecked(Settings::values.use_virtual_sd.GetValue());
|
||||||
ui->toggle_custom_storage->setChecked(Settings::values.use_custom_storage.GetValue());
|
ui->toggle_custom_storage->setChecked(Settings::values.use_custom_storage.GetValue());
|
||||||
|
|
||||||
ui->storage_group->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
ui->storage_group->setEnabled(!is_powered_on);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureStorage::ApplyConfiguration() {
|
void ConfigureStorage::ApplyConfiguration() {
|
||||||
|
@ -15,7 +15,7 @@ class ConfigureStorage : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureStorage(QWidget* parent = nullptr);
|
explicit ConfigureStorage(bool is_powered_on, QWidget* parent = nullptr);
|
||||||
~ConfigureStorage() override;
|
~ConfigureStorage() override;
|
||||||
|
|
||||||
void ApplyConfiguration();
|
void ApplyConfiguration();
|
||||||
@ -23,4 +23,5 @@ public:
|
|||||||
void SetConfiguration();
|
void SetConfiguration();
|
||||||
|
|
||||||
std::unique_ptr<Ui::ConfigureStorage> ui;
|
std::unique_ptr<Ui::ConfigureStorage> ui;
|
||||||
|
bool is_powered_on;
|
||||||
};
|
};
|
||||||
|
@ -223,14 +223,12 @@ static const std::array<const char*, 187> country_names = {
|
|||||||
QT_TRANSLATE_NOOP("ConfigureSystem", "Bermuda"), // 180-186
|
QT_TRANSLATE_NOOP("ConfigureSystem", "Bermuda"), // 180-186
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigureSystem::ConfigureSystem(QWidget* parent)
|
ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureSystem>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureSystem>()), system{system_} {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
connect(ui->combo_birthmonth,
|
connect(ui->combo_birthmonth, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
|
||||||
&ConfigureSystem::UpdateBirthdayComboBox);
|
&ConfigureSystem::UpdateBirthdayComboBox);
|
||||||
connect(ui->combo_init_clock,
|
connect(ui->combo_init_clock, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
|
||||||
&ConfigureSystem::UpdateInitTime);
|
&ConfigureSystem::UpdateInitTime);
|
||||||
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
|
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
|
||||||
&ConfigureSystem::RefreshConsoleID);
|
&ConfigureSystem::RefreshConsoleID);
|
||||||
@ -280,7 +278,7 @@ ConfigureSystem::ConfigureSystem(QWidget* parent)
|
|||||||
ConfigureSystem::~ConfigureSystem() = default;
|
ConfigureSystem::~ConfigureSystem() = default;
|
||||||
|
|
||||||
void ConfigureSystem::SetConfiguration() {
|
void ConfigureSystem::SetConfiguration() {
|
||||||
enabled = !Core::System::GetInstance().IsPoweredOn();
|
enabled = !system.IsPoweredOn();
|
||||||
|
|
||||||
ui->combo_init_clock->setCurrentIndex(static_cast<u8>(Settings::values.init_clock.GetValue()));
|
ui->combo_init_clock->setCurrentIndex(static_cast<u8>(Settings::values.init_clock.GetValue()));
|
||||||
QDateTime date_time;
|
QDateTime date_time;
|
||||||
@ -296,7 +294,7 @@ void ConfigureSystem::SetConfiguration() {
|
|||||||
ui->edit_init_time_offset_time->setTime(time);
|
ui->edit_init_time_offset_time->setTime(time);
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
cfg = Service::CFG::GetModule(Core::System::GetInstance());
|
cfg = Service::CFG::GetModule(system);
|
||||||
ASSERT_MSG(cfg, "CFG Module missing!");
|
ASSERT_MSG(cfg, "CFG Module missing!");
|
||||||
ReadSystemSettings();
|
ReadSystemSettings();
|
||||||
ui->group_system_settings->setEnabled(false);
|
ui->group_system_settings->setEnabled(false);
|
||||||
@ -553,7 +551,6 @@ void ConfigureSystem::SetupPerGameUI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureSystem::DownloadFromNUS() {
|
void ConfigureSystem::DownloadFromNUS() {
|
||||||
#ifdef ENABLE_WEB_SERVICE
|
|
||||||
ui->button_start_download->setEnabled(false);
|
ui->button_start_download->setEnabled(false);
|
||||||
|
|
||||||
const auto mode =
|
const auto mode =
|
||||||
@ -592,5 +589,4 @@ void ConfigureSystem::DownloadFromNUS() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->button_start_download->setEnabled(true);
|
ui->button_start_download->setEnabled(true);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,10 @@ namespace ConfigurationShared {
|
|||||||
enum class CheckState;
|
enum class CheckState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace CFG {
|
namespace CFG {
|
||||||
class Module;
|
class Module;
|
||||||
@ -26,7 +30,7 @@ class ConfigureSystem : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureSystem(QWidget* parent = nullptr);
|
explicit ConfigureSystem(Core::System& system, QWidget* parent = nullptr);
|
||||||
~ConfigureSystem() override;
|
~ConfigureSystem() override;
|
||||||
|
|
||||||
void ApplyConfiguration();
|
void ApplyConfiguration();
|
||||||
@ -45,8 +49,10 @@ private:
|
|||||||
|
|
||||||
void DownloadFromNUS();
|
void DownloadFromNUS();
|
||||||
|
|
||||||
ConfigurationShared::CheckState is_new_3ds;
|
private:
|
||||||
std::unique_ptr<Ui::ConfigureSystem> ui;
|
std::unique_ptr<Ui::ConfigureSystem> ui;
|
||||||
|
Core::System& system;
|
||||||
|
ConfigurationShared::CheckState is_new_3ds;
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
|
|
||||||
std::shared_ptr<Service::CFG::Module> cfg;
|
std::shared_ptr<Service::CFG::Module> cfg;
|
||||||
|
@ -64,15 +64,22 @@ void GPUCommandStreamItemModel::OnGXCommandFinishedInternal(int total_command_co
|
|||||||
}
|
}
|
||||||
|
|
||||||
GPUCommandStreamWidget::GPUCommandStreamWidget(QWidget* parent)
|
GPUCommandStreamWidget::GPUCommandStreamWidget(QWidget* parent)
|
||||||
: QDockWidget(tr("Graphics Debugger"), parent) {
|
: QDockWidget(tr("Graphics Debugger"), parent), model(this) {
|
||||||
setObjectName(QStringLiteral("GraphicsDebugger"));
|
setObjectName(QStringLiteral("GraphicsDebugger"));
|
||||||
|
|
||||||
GPUCommandStreamItemModel* command_model = new GPUCommandStreamItemModel(this);
|
auto* command_list = new QListView;
|
||||||
g_debugger.RegisterObserver(command_model);
|
command_list->setModel(&model);
|
||||||
|
|
||||||
QListView* command_list = new QListView;
|
|
||||||
command_list->setModel(command_model);
|
|
||||||
command_list->setFont(GetMonospaceFont());
|
command_list->setFont(GetMonospaceFont());
|
||||||
|
|
||||||
setWidget(command_list);
|
setWidget(command_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPUCommandStreamWidget::showEvent(QShowEvent* event) {
|
||||||
|
g_debugger.RegisterObserver(&model);
|
||||||
|
QDockWidget::showEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPUCommandStreamWidget::hideEvent(QHideEvent* event) {
|
||||||
|
g_debugger.UnregisterObserver(&model);
|
||||||
|
QDockWidget::hideEvent(event);
|
||||||
|
}
|
||||||
|
@ -37,5 +37,10 @@ class GPUCommandStreamWidget : public QDockWidget {
|
|||||||
public:
|
public:
|
||||||
GPUCommandStreamWidget(QWidget* parent = nullptr);
|
GPUCommandStreamWidget(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent* event) override;
|
||||||
|
void hideEvent(QHideEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
GPUCommandStreamItemModel model;
|
||||||
};
|
};
|
||||||
|
@ -167,8 +167,7 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
|
|||||||
const auto format = texture.format;
|
const auto format = texture.format;
|
||||||
|
|
||||||
const auto info = Pica::Texture::TextureInfo::FromPicaRegister(config, format);
|
const auto info = Pica::Texture::TextureInfo::FromPicaRegister(config, format);
|
||||||
const u8* src =
|
const u8* src = system.Memory().GetPhysicalPointer(config.GetPhysicalAddress());
|
||||||
Core::System::GetInstance().Memory().GetPhysicalPointer(config.GetPhysicalAddress());
|
|
||||||
new_info_widget = new TextureInfoWidget(src, info);
|
new_info_widget = new TextureInfoWidget(src, info);
|
||||||
}
|
}
|
||||||
if (command_info_widget) {
|
if (command_info_widget) {
|
||||||
@ -182,8 +181,8 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
|
|||||||
}
|
}
|
||||||
#undef COMMAND_IN_RANGE
|
#undef COMMAND_IN_RANGE
|
||||||
|
|
||||||
GPUCommandListWidget::GPUCommandListWidget(QWidget* parent)
|
GPUCommandListWidget::GPUCommandListWidget(Core::System& system_, QWidget* parent)
|
||||||
: QDockWidget(tr("Pica Command List"), parent) {
|
: QDockWidget(tr("Pica Command List"), parent), system{system_} {
|
||||||
setObjectName(QStringLiteral("Pica Command List"));
|
setObjectName(QStringLiteral("Pica Command List"));
|
||||||
GPUCommandListModel* model = new GPUCommandListModel(this);
|
GPUCommandListModel* model = new GPUCommandListModel(this);
|
||||||
|
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/gpu_debugger.h"
|
|
||||||
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QTreeView;
|
class QTreeView;
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
class GPUCommandListModel : public QAbstractListModel {
|
class GPUCommandListModel : public QAbstractListModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -39,7 +42,7 @@ class GPUCommandListWidget : public QDockWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GPUCommandListWidget(QWidget* parent = nullptr);
|
explicit GPUCommandListWidget(Core::System& system, QWidget* parent = nullptr);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnToggleTracing();
|
void OnToggleTracing();
|
||||||
@ -54,7 +57,7 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Pica::DebugUtils::PicaTrace> pica_trace;
|
std::unique_ptr<Pica::DebugUtils::PicaTrace> pica_trace;
|
||||||
|
Core::System& system;
|
||||||
QTreeView* list_widget;
|
QTreeView* list_widget;
|
||||||
QWidget* command_info_widget;
|
QWidget* command_info_widget;
|
||||||
QPushButton* toggle_tracing;
|
QPushButton* toggle_tracing;
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
#include "citra_qt/debugger/graphics/graphics_surface.h"
|
#include "citra_qt/debugger/graphics/graphics_surface.h"
|
||||||
#include "citra_qt/util/spinbox.h"
|
#include "citra_qt/util/spinbox.h"
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/hw/gpu.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/regs_framebuffer.h"
|
#include "video_core/regs_framebuffer.h"
|
||||||
@ -51,9 +49,10 @@ void SurfacePicture::mouseMoveEvent(QMouseEvent* event) {
|
|||||||
mousePressEvent(event);
|
mousePressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context,
|
GraphicsSurfaceWidget::GraphicsSurfaceWidget(Memory::MemorySystem& memory_,
|
||||||
|
std::shared_ptr<Pica::DebugContext> debug_context,
|
||||||
QWidget* parent)
|
QWidget* parent)
|
||||||
: BreakPointObserverDock(debug_context, tr("Pica Surface Viewer"), parent),
|
: BreakPointObserverDock(debug_context, tr("Pica Surface Viewer"), parent), memory{memory_},
|
||||||
surface_source(Source::ColorBuffer) {
|
surface_source(Source::ColorBuffer) {
|
||||||
setObjectName(QStringLiteral("PicaSurface"));
|
setObjectName(QStringLiteral("PicaSurface"));
|
||||||
|
|
||||||
@ -290,57 +289,57 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* buffer = Core::System::GetInstance().Memory().GetPhysicalPointer(surface_address);
|
const u8* buffer = memory.GetPhysicalPointer(surface_address);
|
||||||
if (buffer == nullptr) {
|
if (!buffer) {
|
||||||
surface_info_label->setText(tr("(unable to access pixel data)"));
|
surface_info_label->setText(tr("(unable to access pixel data)"));
|
||||||
surface_info_label->setAlignment(Qt::AlignCenter);
|
surface_info_label->setAlignment(Qt::AlignCenter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned nibbles_per_pixel = GraphicsSurfaceWidget::NibblesPerPixel(surface_format);
|
const u32 nibbles_per_pixel = GraphicsSurfaceWidget::NibblesPerPixel(surface_format);
|
||||||
unsigned stride = nibbles_per_pixel * surface_width / 2;
|
const u32 stride = nibbles_per_pixel * surface_width / 2;
|
||||||
|
const bool nibble_mode = (nibbles_per_pixel == 1);
|
||||||
unsigned bytes_per_pixel;
|
const u32 bytes_per_pixel = [&] {
|
||||||
bool nibble_mode = (nibbles_per_pixel == 1);
|
if (nibble_mode) {
|
||||||
if (nibble_mode) {
|
// As nibbles are contained in a byte we still need to access one byte per nibble
|
||||||
// As nibbles are contained in a byte we still need to access one byte per nibble
|
return 1u;
|
||||||
bytes_per_pixel = 1;
|
} else {
|
||||||
} else {
|
return nibbles_per_pixel / 2;
|
||||||
bytes_per_pixel = nibbles_per_pixel / 2;
|
}
|
||||||
}
|
}();
|
||||||
|
|
||||||
const u32 coarse_y = y & ~7;
|
const u32 coarse_y = y & ~7;
|
||||||
u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
const u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
||||||
const u8* pixel = buffer + (nibble_mode ? (offset / 2) : offset);
|
const u8* pixel = buffer + (nibble_mode ? (offset / 2) : offset);
|
||||||
|
|
||||||
auto GetText = [offset](Format format, const u8* pixel) {
|
const auto get_text = [offset](Format format, const u8* pixel) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case Format::RGBA8: {
|
case Format::RGBA8: {
|
||||||
auto value = Common::Color::DecodeRGBA8(pixel) / 255.0f;
|
const auto value = Common::Color::DecodeRGBA8(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||||
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::RGB8: {
|
case Format::RGB8: {
|
||||||
auto value = Common::Color::DecodeRGB8(pixel) / 255.0f;
|
const auto value = Common::Color::DecodeRGB8(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
||||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||||
QString::number(value.b(), 'f', 2));
|
QString::number(value.b(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::RGB5A1: {
|
case Format::RGB5A1: {
|
||||||
auto value = Common::Color::DecodeRGB5A1(pixel) / 255.0f;
|
const auto value = Common::Color::DecodeRGB5A1(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||||
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::RGB565: {
|
case Format::RGB565: {
|
||||||
auto value = Common::Color::DecodeRGB565(pixel) / 255.0f;
|
const auto value = Common::Color::DecodeRGB565(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
||||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||||
QString::number(value.b(), 'f', 2));
|
QString::number(value.b(), 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::RGBA4: {
|
case Format::RGBA4: {
|
||||||
auto value = Common::Color::DecodeRGBA4(pixel) / 255.0f;
|
const auto value = Common::Color::DecodeRGBA4(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||||
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
||||||
@ -348,7 +347,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
case Format::IA8:
|
case Format::IA8:
|
||||||
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]);
|
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]);
|
||||||
case Format::RG8: {
|
case Format::RG8: {
|
||||||
auto value = Common::Color::DecodeRG8(pixel) / 255.0f;
|
const auto value = Common::Color::DecodeRG8(pixel) / 255.0f;
|
||||||
return QStringLiteral("Red: %1, Green: %2")
|
return QStringLiteral("Red: %1, Green: %2")
|
||||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2));
|
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2));
|
||||||
}
|
}
|
||||||
@ -359,11 +358,11 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
case Format::IA4:
|
case Format::IA4:
|
||||||
return QStringLiteral("Index: %1, Alpha: %2").arg(*pixel & 0xF, (*pixel & 0xF0) >> 4);
|
return QStringLiteral("Index: %1, Alpha: %2").arg(*pixel & 0xF, (*pixel & 0xF0) >> 4);
|
||||||
case Format::I4: {
|
case Format::I4: {
|
||||||
u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
|
const u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
|
||||||
return QStringLiteral("Index: %1").arg(i);
|
return QStringLiteral("Index: %1").arg(i);
|
||||||
}
|
}
|
||||||
case Format::A4: {
|
case Format::A4: {
|
||||||
u8 a = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
|
const u8 a = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
|
||||||
return QStringLiteral("Alpha: %1").arg(QString::number(a / 15.0f, 'f', 2));
|
return QStringLiteral("Alpha: %1").arg(QString::number(a / 15.0f, 'f', 2));
|
||||||
}
|
}
|
||||||
case Format::ETC1:
|
case Format::ETC1:
|
||||||
@ -371,17 +370,17 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
// TODO: Display block information or channel values?
|
// TODO: Display block information or channel values?
|
||||||
return QStringLiteral("Compressed data");
|
return QStringLiteral("Compressed data");
|
||||||
case Format::D16: {
|
case Format::D16: {
|
||||||
auto value = Common::Color::DecodeD16(pixel);
|
const auto value = Common::Color::DecodeD16(pixel);
|
||||||
return QStringLiteral("Depth: %1").arg(QString::number(value / (float)0xFFFF, 'f', 4));
|
return QStringLiteral("Depth: %1").arg(QString::number(value / (float)0xFFFF, 'f', 4));
|
||||||
}
|
}
|
||||||
case Format::D24: {
|
case Format::D24: {
|
||||||
auto value = Common::Color::DecodeD24(pixel);
|
const auto value = Common::Color::DecodeD24(pixel);
|
||||||
return QStringLiteral("Depth: %1")
|
return QStringLiteral("Depth: %1")
|
||||||
.arg(QString::number(value / (float)0xFFFFFF, 'f', 4));
|
.arg(QString::number(value / (float)0xFFFFFF, 'f', 4));
|
||||||
}
|
}
|
||||||
case Format::D24X8:
|
case Format::D24X8:
|
||||||
case Format::X24S8: {
|
case Format::X24S8: {
|
||||||
auto values = Common::Color::DecodeD24S8(pixel);
|
const auto values = Common::Color::DecodeD24S8(pixel);
|
||||||
return QStringLiteral("Depth: %1, Stencil: %2")
|
return QStringLiteral("Depth: %1, Stencil: %2")
|
||||||
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]);
|
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]);
|
||||||
}
|
}
|
||||||
@ -398,13 +397,13 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
|||||||
if (nibble_mode) {
|
if (nibble_mode) {
|
||||||
nibble_index += (offset % 2) ? 0 : 1;
|
nibble_index += (offset % 2) ? 0 : 1;
|
||||||
}
|
}
|
||||||
u8 byte = pixel[nibble_index / 2];
|
const u8 byte = pixel[nibble_index / 2];
|
||||||
u8 nibble = (byte >> ((nibble_index % 2) ? 0 : 4)) & 0xF;
|
const u8 nibble = (byte >> ((nibble_index % 2) ? 0 : 4)) & 0xF;
|
||||||
nibbles.append(QString::number(nibble, 16).toUpper());
|
nibbles.append(QString::number(nibble, 16).toUpper());
|
||||||
}
|
}
|
||||||
|
|
||||||
surface_info_label->setText(
|
surface_info_label->setText(
|
||||||
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles, GetText(surface_format, pixel)));
|
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles, get_text(surface_format, pixel)));
|
||||||
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,9 +545,9 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
|||||||
// TODO: Implement a good way to visualize alpha components!
|
// TODO: Implement a good way to visualize alpha components!
|
||||||
|
|
||||||
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
|
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
|
||||||
u8* buffer = Core::System::GetInstance().Memory().GetPhysicalPointer(surface_address);
|
const u8* buffer = memory.GetPhysicalPointer(surface_address);
|
||||||
|
|
||||||
if (buffer == nullptr) {
|
if (!buffer) {
|
||||||
surface_picture_label->hide();
|
surface_picture_label->hide();
|
||||||
surface_info_label->setText(tr("(invalid surface address)"));
|
surface_info_label->setText(tr("(invalid surface address)"));
|
||||||
surface_info_label->setAlignment(Qt::AlignCenter);
|
surface_info_label->setAlignment(Qt::AlignCenter);
|
||||||
@ -682,9 +681,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
|
|||||||
tr("Failed to save surface data to file '%1'").arg(filename));
|
tr("Failed to save surface data to file '%1'").arg(filename));
|
||||||
}
|
}
|
||||||
} else if (selected_filter == bin_filter) {
|
} else if (selected_filter == bin_filter) {
|
||||||
const u8* const buffer =
|
const u8* const buffer = memory.GetPhysicalPointer(surface_address);
|
||||||
Core::System::GetInstance().Memory().GetPhysicalPointer(surface_address);
|
ASSERT_MSG(buffer, "Memory not accessible");
|
||||||
ASSERT_MSG(buffer != nullptr, "Memory not accessible");
|
|
||||||
|
|
||||||
QFile file{filename};
|
QFile file{filename};
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
|
@ -14,6 +14,10 @@ class CSpinBox;
|
|||||||
|
|
||||||
class GraphicsSurfaceWidget;
|
class GraphicsSurfaceWidget;
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
class SurfacePicture : public QLabel {
|
class SurfacePicture : public QLabel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -72,7 +76,8 @@ class GraphicsSurfaceWidget : public BreakPointObserverDock {
|
|||||||
static unsigned int NibblesPerPixel(Format format);
|
static unsigned int NibblesPerPixel(Format format);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context,
|
explicit GraphicsSurfaceWidget(Memory::MemorySystem& memory,
|
||||||
|
std::shared_ptr<Pica::DebugContext> debug_context,
|
||||||
QWidget* parent = nullptr);
|
QWidget* parent = nullptr);
|
||||||
void Pick(int x, int y);
|
void Pick(int x, int y);
|
||||||
|
|
||||||
@ -95,6 +100,7 @@ private:
|
|||||||
|
|
||||||
void SaveSurface();
|
void SaveSurface();
|
||||||
|
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
QComboBox* surface_source_list;
|
QComboBox* surface_source_list;
|
||||||
CSpinBox* surface_address_control;
|
CSpinBox* surface_address_control;
|
||||||
QSpinBox* surface_width_control;
|
QSpinBox* surface_width_control;
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
#include "ui_recorder.h"
|
#include "ui_recorder.h"
|
||||||
|
|
||||||
IPCRecorderWidget::IPCRecorderWidget(QWidget* parent)
|
IPCRecorderWidget::IPCRecorderWidget(Core::System& system_, QWidget* parent)
|
||||||
: QDockWidget(parent), ui(std::make_unique<Ui::IPCRecorder>()) {
|
: QDockWidget(parent), ui(std::make_unique<Ui::IPCRecorder>()), system{system_} {
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
qRegisterMetaType<IPCDebugger::RequestRecord>();
|
qRegisterMetaType<IPCDebugger::RequestRecord>();
|
||||||
|
|
||||||
connect(ui->enabled, &QCheckBox::stateChanged,
|
connect(ui->enabled, &QCheckBox::stateChanged, this,
|
||||||
[this](int new_state) { SetEnabled(new_state == Qt::Checked); });
|
[this](int new_state) { SetEnabled(new_state == Qt::Checked); });
|
||||||
connect(ui->clearButton, &QPushButton::clicked, this, &IPCRecorderWidget::Clear);
|
connect(ui->clearButton, &QPushButton::clicked, this, &IPCRecorderWidget::Clear);
|
||||||
connect(ui->filter, &QLineEdit::textChanged, this, &IPCRecorderWidget::ApplyFilterToAll);
|
connect(ui->filter, &QLineEdit::textChanged, this, &IPCRecorderWidget::ApplyFilterToAll);
|
||||||
@ -90,7 +90,7 @@ void IPCRecorderWidget::OnEntryUpdated(IPCDebugger::RequestRecord record) {
|
|||||||
(record.status == IPCDebugger::RequestStatus::Handled &&
|
(record.status == IPCDebugger::RequestStatus::Handled &&
|
||||||
record.translated_reply_cmdbuf[1] != RESULT_SUCCESS.raw)) { // Unimplemented / Error
|
record.translated_reply_cmdbuf[1] != RESULT_SUCCESS.raw)) { // Unimplemented / Error
|
||||||
|
|
||||||
auto* item = ui->main->invisibleRootItem()->child(row_id);
|
auto item = ui->main->invisibleRootItem()->child(row_id);
|
||||||
for (int column = 0; column < item->columnCount(); ++column) {
|
for (int column = 0; column < item->columnCount(); ++column) {
|
||||||
item->setBackground(column, QBrush(QColor::fromRgb(255, 0, 0)));
|
item->setBackground(column, QBrush(QColor::fromRgb(255, 0, 0)));
|
||||||
}
|
}
|
||||||
@ -100,11 +100,11 @@ void IPCRecorderWidget::OnEntryUpdated(IPCDebugger::RequestRecord record) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IPCRecorderWidget::SetEnabled(bool enabled) {
|
void IPCRecorderWidget::SetEnabled(bool enabled) {
|
||||||
if (!Core::System::GetInstance().IsPoweredOn()) {
|
if (!system.IsPoweredOn()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& ipc_recorder = Core::System::GetInstance().Kernel().GetIPCRecorder();
|
auto& ipc_recorder = system.Kernel().GetIPCRecorder();
|
||||||
ipc_recorder.SetEnabled(enabled);
|
ipc_recorder.SetEnabled(enabled);
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@ -123,10 +123,10 @@ void IPCRecorderWidget::Clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString IPCRecorderWidget::GetServiceName(const IPCDebugger::RequestRecord& record) const {
|
QString IPCRecorderWidget::GetServiceName(const IPCDebugger::RequestRecord& record) const {
|
||||||
if (Core::System::GetInstance().IsPoweredOn() && record.client_port.id != -1) {
|
if (system.IsPoweredOn() && record.client_port.id != -1) {
|
||||||
const auto service_name =
|
const Service::SM::ServiceManager& sm = system.ServiceManager();
|
||||||
Core::System::GetInstance().ServiceManager().GetServiceNameByPortId(
|
const u32 port_id = static_cast<u32>(record.client_port.id);
|
||||||
static_cast<u32>(record.client_port.id));
|
const auto service_name = sm.GetServiceNameByPortId(port_id);
|
||||||
|
|
||||||
if (!service_name.empty()) {
|
if (!service_name.empty()) {
|
||||||
return QString::fromStdString(service_name);
|
return QString::fromStdString(service_name);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user