mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-15 13:16:43 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1fa72e7bc5 | |||
| 666593a3b2 | |||
| 91058d7383 | |||
| 048d02e5b4 | |||
| 17e2be173c | |||
| bd6dd7ecec | |||
| 72ae613176 | |||
| 26ce96297c | |||
| b3cc8723c1 |
@@ -3,6 +3,8 @@ name: Check Strings
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
check-strings:
|
||||
@@ -10,7 +12,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Find Unused Strings
|
||||
run: ./tools/unused-strings.sh
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
|
||||
index eb4e69e..3155805 100644
|
||||
--- a/external/CMakeLists.txt
|
||||
+++ b/external/CMakeLists.txt
|
||||
@@ -72,7 +72,8 @@ if (SPIRV_TOOLS_USE_MIMALLOC)
|
||||
pop_variable(MI_BUILD_TESTS)
|
||||
endif()
|
||||
|
||||
-if (DEFINED SPIRV-Headers_SOURCE_DIR)
|
||||
+# NetBSD doesn't have SPIRV-Headers readily available on system
|
||||
+if (DEFINED SPIRV-Headers_SOURCE_DIR AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
|
||||
# This allows flexible position of the SPIRV-Headers repo.
|
||||
set(SPIRV_HEADER_DIR ${SPIRV-Headers_SOURCE_DIR})
|
||||
else()
|
||||
@@ -1,287 +0,0 @@
|
||||
From 67bf3d1381b1faf59e87001d6156ba4e21cada14 Mon Sep 17 00:00:00 2001
|
||||
From: crueter <crueter@eden-emu.dev>
|
||||
Date: Mon, 29 Dec 2025 21:22:36 -0500
|
||||
Subject: [PATCH] [cmake] refactor: shared/static handling
|
||||
|
||||
This significantly redoes the way shared and static libraries are
|
||||
handled. Now, it's controlled by two options: `SPIRV_TOOLS_BUILD_STATIC`
|
||||
and `SPIRV_TOOLS_BUILD_SHARED`.
|
||||
|
||||
The default configuration (no `BUILD_SHARED_LIBS` set, options left at
|
||||
default) is to build shared ONLY if this is the master project, or
|
||||
static ONLY if this is a subproject (e.g. FetchContent, CPM.cmake). Also
|
||||
I should note that static-only (i.e. no shared) is now a supported
|
||||
target, this is done because projects including it as a submodule e.g.
|
||||
on Android or Windows may prefer this.
|
||||
|
||||
Now the shared/static handling:
|
||||
- static ON, shared OFF: Only generates `.a` libraries.
|
||||
- static ON, shared ON: Generates `.a` libraries, but also
|
||||
`libSPIRV-Tools.so`
|
||||
- static OFF, shared ON: Only generates `.so` libraries.
|
||||
|
||||
Notable TODOs:
|
||||
- SPIRV-Tools-shared.pc seems redundant--how should we handle which one
|
||||
to use in the case of distributions that distribute both types (MSYS2
|
||||
for instance)?
|
||||
* *Note: pkgconfig sucks at this and usually just leaves it up to the
|
||||
user, so the optimal solution may indeed be doing absolutely
|
||||
nothing.* CMake is unaffected :)
|
||||
- use namespaces in the CMake config files pleaaaaase
|
||||
|
||||
This is going to change things a good bit for package maintainers, but
|
||||
cest la vie. It's for the greater good, I promise.
|
||||
|
||||
Signed-off-by: crueter <crueter@eden-emu.dev>
|
||||
---
|
||||
CMakeLists.txt | 108 +++++++++++++++++++++++++-----------------
|
||||
source/CMakeLists.txt | 62 ++++++++++++------------
|
||||
2 files changed, 94 insertions(+), 76 deletions(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 4d843b4d2f..07201f690f 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -14,6 +14,15 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
+# master project detection--useful for FetchContent/submodule inclusion
|
||||
+set(master_project OFF)
|
||||
+set(subproject ON)
|
||||
+
|
||||
+if (NOT DEFINED PROJECT_NAME)
|
||||
+ set(master_project ON)
|
||||
+ set(subproject OFF)
|
||||
+endif()
|
||||
+
|
||||
project(spirv-tools)
|
||||
|
||||
# Avoid a bug in CMake 3.22.1. By default it will set -std=c++11 for
|
||||
@@ -135,46 +144,49 @@ if (DEFINED SPIRV_TOOLS_EXTRA_DEFINITIONS)
|
||||
add_definitions(${SPIRV_TOOLS_EXTRA_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
-# Library build setting definitions:
|
||||
-#
|
||||
-# * SPIRV_TOOLS_BUILD_STATIC - ON or OFF - Defaults to ON.
|
||||
-# If enabled the following targets will be created:
|
||||
-# ${SPIRV_TOOLS}-static - STATIC library.
|
||||
-# Has full public symbol visibility.
|
||||
-# ${SPIRV_TOOLS}-shared - SHARED library.
|
||||
-# Has default-hidden symbol visibility.
|
||||
-# ${SPIRV_TOOLS} - will alias to one of above, based on BUILD_SHARED_LIBS.
|
||||
-# If disabled the following targets will be created:
|
||||
-# ${SPIRV_TOOLS} - either STATIC or SHARED based on SPIRV_TOOLS_LIBRARY_TYPE.
|
||||
-# Has full public symbol visibility.
|
||||
-# ${SPIRV_TOOLS}-shared - SHARED library.
|
||||
-# Has default-hidden symbol visibility.
|
||||
-#
|
||||
-# * SPIRV_TOOLS_LIBRARY_TYPE - SHARED or STATIC.
|
||||
-# Specifies the library type used for building SPIRV-Tools libraries.
|
||||
-# Defaults to SHARED when BUILD_SHARED_LIBS=1, otherwise STATIC.
|
||||
-#
|
||||
-# * SPIRV_TOOLS_FULL_VISIBILITY - "${SPIRV_TOOLS}-static" or "${SPIRV_TOOLS}"
|
||||
-# Evaluates to the SPIRV_TOOLS target library name that has no hidden symbols.
|
||||
-# This is used by internal targets for accessing symbols that are non-public.
|
||||
-# Note this target provides no API stability guarantees.
|
||||
-#
|
||||
-# Ideally, all of these will go away - see https://github.com/KhronosGroup/SPIRV-Tools/issues/3909.
|
||||
-option(ENABLE_EXCEPTIONS_ON_MSVC "Build SPIRV-TOOLS with c++ exceptions enabled in MSVC" ON)
|
||||
-option(SPIRV_TOOLS_BUILD_STATIC "Build ${SPIRV_TOOLS}-static target. ${SPIRV_TOOLS} will alias to ${SPIRV_TOOLS}-static or ${SPIRV_TOOLS}-shared based on BUILD_SHARED_LIBS" ON)
|
||||
-if(SPIRV_TOOLS_BUILD_STATIC)
|
||||
- set(SPIRV_TOOLS_FULL_VISIBILITY ${SPIRV_TOOLS}-static)
|
||||
+# If BUILD_SHARED_LIBS is undefined, set it based on whether we are
|
||||
+# the master project or a subproject
|
||||
+if (NOT DEFINED BUILD_SHARED_LIBS)
|
||||
+ set(BUILD_SHARED_LIBS ${master_project})
|
||||
+endif()
|
||||
+
|
||||
+if (BUILD_SHARED_LIBS)
|
||||
+ set(static_default OFF)
|
||||
+else()
|
||||
+ set(static_default ON)
|
||||
+endif()
|
||||
+
|
||||
+option(SPIRV_TOOLS_BUILD_SHARED "Build ${SPIRV_TOOLS} as a shared library"
|
||||
+ ${BUILD_SHARED_LIBS})
|
||||
+option(SPIRV_TOOLS_BUILD_STATIC "Build ${SPIRV_TOOLS} as a static library"
|
||||
+ ${static_default})
|
||||
+
|
||||
+# Avoid conflict between the dll import library and
|
||||
+# the static library (thanks microsoft)
|
||||
+if(CMAKE_STATIC_LIBRARY_PREFIX STREQUAL "" AND
|
||||
+ CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL ".lib")
|
||||
+ set(SPIRV_TOOLS_STATIC_LIBNAME "${SPIRV_TOOLS}-static")
|
||||
+else()
|
||||
+ set(SPIRV_TOOLS_STATIC_LIBNAME "${SPIRV_TOOLS}")
|
||||
+endif()
|
||||
+
|
||||
+if (SPIRV_TOOLS_BUILD_STATIC)
|
||||
+ # If building a static library at all, always build other libraries as static,
|
||||
+ # and link to the static SPIRV-Tools library.
|
||||
set(SPIRV_TOOLS_LIBRARY_TYPE "STATIC")
|
||||
-else(SPIRV_TOOLS_BUILD_STATIC)
|
||||
- set(SPIRV_TOOLS_FULL_VISIBILITY ${SPIRV_TOOLS})
|
||||
- if (NOT DEFINED SPIRV_TOOLS_LIBRARY_TYPE)
|
||||
- if(BUILD_SHARED_LIBS)
|
||||
- set(SPIRV_TOOLS_LIBRARY_TYPE "SHARED")
|
||||
- else()
|
||||
- set(SPIRV_TOOLS_LIBRARY_TYPE "STATIC")
|
||||
- endif()
|
||||
- endif()
|
||||
-endif(SPIRV_TOOLS_BUILD_STATIC)
|
||||
+ set(SPIRV_TOOLS_FULL_VISIBILITY ${SPIRV_TOOLS}-static)
|
||||
+elseif (SPIRV_TOOLS_BUILD_SHARED)
|
||||
+ # If only building a shared library, link other libraries to the
|
||||
+ # shared library. Also, other libraries should be shared
|
||||
+ set(SPIRV_TOOLS_LIBRARY_TYPE "SHARED")
|
||||
+ set(SPIRV_TOOLS_FULL_VISIBILITY ${SPIRV_TOOLS}-shared)
|
||||
+else()
|
||||
+ message(FATAL_ERROR "You must set one of "
|
||||
+ "SPIRV_TOOLS_BUILD_STATIC or SPIRV_TOOLS_BUILD_SHARED!")
|
||||
+endif()
|
||||
+
|
||||
+option(ENABLE_EXCEPTIONS_ON_MSVC
|
||||
+ "Build SPIRV-TOOLS with C++ exceptions enabled in MSVC" ON)
|
||||
|
||||
function(spvtools_default_compile_options TARGET)
|
||||
target_compile_options(${TARGET} PRIVATE ${SPIRV_WARNINGS})
|
||||
@@ -372,7 +384,7 @@ if (NOT "${SPIRV_SKIP_TESTS}")
|
||||
endif()
|
||||
|
||||
set(SPIRV_LIBRARIES "-lSPIRV-Tools-opt -lSPIRV-Tools -lSPIRV-Tools-link")
|
||||
-set(SPIRV_SHARED_LIBRARIES "-lSPIRV-Tools-shared")
|
||||
+set(SPIRV_SHARED_LIBRARIES "-lSPIRV-Tools")
|
||||
|
||||
# Build pkg-config file
|
||||
# Use a first-class target so it's regenerated when relevant files are updated.
|
||||
@@ -388,7 +400,12 @@ add_custom_command(
|
||||
-DSPIRV_LIBRARIES=${SPIRV_LIBRARIES}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake
|
||||
DEPENDS "CHANGES" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools.pc.in" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake")
|
||||
-add_custom_command(
|
||||
+
|
||||
+set(pc_files ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc)
|
||||
+
|
||||
+# TODO(crueter): remove?
|
||||
+if (SPIRV_TOOLS_BUILD_SHARED)
|
||||
+ add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES
|
||||
@@ -400,9 +417,12 @@ add_custom_command(
|
||||
-DSPIRV_SHARED_LIBRARIES=${SPIRV_SHARED_LIBRARIES}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake
|
||||
DEPENDS "CHANGES" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools-shared.pc.in" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake")
|
||||
-add_custom_target(spirv-tools-pkg-config
|
||||
- ALL
|
||||
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc)
|
||||
+ set(pc_files ${pc_files} ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc)
|
||||
+endif()
|
||||
+
|
||||
+add_custom_target(spirv-tools-pkg-config
|
||||
+ ALL
|
||||
+ DEPENDS ${pc_files})
|
||||
|
||||
# Install pkg-config file
|
||||
if (ENABLE_SPIRV_TOOLS_INSTALL)
|
||||
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
|
||||
index bfa1e661bc..fd3712c70c 100644
|
||||
--- a/source/CMakeLists.txt
|
||||
+++ b/source/CMakeLists.txt
|
||||
@@ -337,49 +337,44 @@ function(spirv_tools_default_target_options target)
|
||||
)
|
||||
set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools libraries")
|
||||
spvtools_check_symbol_exports(${target})
|
||||
- add_dependencies(${target} spirv-tools-build-version core_tables extinst_tables)
|
||||
+ add_dependencies(${target}
|
||||
+ spirv-tools-build-version core_tables extinst_tables)
|
||||
endfunction()
|
||||
|
||||
-# Always build ${SPIRV_TOOLS}-shared. This is expected distro packages, and
|
||||
-# unlike the other SPIRV_TOOLS target, defaults to hidden symbol visibility.
|
||||
-add_library(${SPIRV_TOOLS}-shared SHARED ${SPIRV_SOURCES})
|
||||
-if (SPIRV_TOOLS_USE_MIMALLOC)
|
||||
- target_link_libraries(${SPIRV_TOOLS}-shared PRIVATE mimalloc-static)
|
||||
+if (SPIRV_TOOLS_BUILD_SHARED)
|
||||
+ add_library(${SPIRV_TOOLS}-shared SHARED ${SPIRV_SOURCES})
|
||||
+ if (SPIRV_TOOLS_USE_MIMALLOC)
|
||||
+ target_link_libraries(${SPIRV_TOOLS}-shared PRIVATE mimalloc-static)
|
||||
+ endif()
|
||||
+
|
||||
+ set_target_properties(${SPIRV_TOOLS}-shared PROPERTIES
|
||||
+ OUTPUT_NAME "${SPIRV_TOOLS}")
|
||||
+ spirv_tools_default_target_options(${SPIRV_TOOLS}-shared)
|
||||
+
|
||||
+ target_compile_definitions(${SPIRV_TOOLS}-shared
|
||||
+ PRIVATE SPIRV_TOOLS_IMPLEMENTATION
|
||||
+ PUBLIC SPIRV_TOOLS_SHAREDLIB)
|
||||
+
|
||||
+ list(APPEND SPIRV_TOOLS_TARGETS ${SPIRV_TOOLS}-shared)
|
||||
endif()
|
||||
-spirv_tools_default_target_options(${SPIRV_TOOLS}-shared)
|
||||
-set_target_properties(${SPIRV_TOOLS}-shared PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
-target_compile_definitions(${SPIRV_TOOLS}-shared
|
||||
- PRIVATE SPIRV_TOOLS_IMPLEMENTATION
|
||||
- PUBLIC SPIRV_TOOLS_SHAREDLIB
|
||||
-)
|
||||
|
||||
if(SPIRV_TOOLS_BUILD_STATIC)
|
||||
add_library(${SPIRV_TOOLS}-static STATIC ${SPIRV_SOURCES})
|
||||
if (SPIRV_TOOLS_USE_MIMALLOC AND SPIRV_TOOLS_USE_MIMALLOC_IN_STATIC_BUILD)
|
||||
target_link_libraries(${SPIRV_TOOLS}-shared PRIVATE mimalloc-static)
|
||||
endif()
|
||||
+
|
||||
spirv_tools_default_target_options(${SPIRV_TOOLS}-static)
|
||||
- # The static target does not have the '-static' suffix.
|
||||
- set_target_properties(${SPIRV_TOOLS}-static PROPERTIES OUTPUT_NAME "${SPIRV_TOOLS}")
|
||||
-
|
||||
- # Create the "${SPIRV_TOOLS}" target as an alias to either "${SPIRV_TOOLS}-static"
|
||||
- # or "${SPIRV_TOOLS}-shared" depending on the value of BUILD_SHARED_LIBS.
|
||||
- if(BUILD_SHARED_LIBS)
|
||||
- add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-shared)
|
||||
- else()
|
||||
- add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS}-static)
|
||||
- endif()
|
||||
+ set_target_properties(${SPIRV_TOOLS}-static PROPERTIES
|
||||
+ OUTPUT_NAME "${SPIRV_TOOLS_STATIC_LIBNAME}")
|
||||
|
||||
- set(SPIRV_TOOLS_TARGETS ${SPIRV_TOOLS}-static ${SPIRV_TOOLS}-shared)
|
||||
-else()
|
||||
- add_library(${SPIRV_TOOLS} ${SPIRV_TOOLS_LIBRARY_TYPE} ${SPIRV_SOURCES})
|
||||
- if (SPIRV_TOOLS_USE_MIMALLOC)
|
||||
- target_link_libraries(${SPIRV_TOOLS} PRIVATE mimalloc-static)
|
||||
- endif()
|
||||
- spirv_tools_default_target_options(${SPIRV_TOOLS})
|
||||
- set(SPIRV_TOOLS_TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared)
|
||||
+ list(APPEND SPIRV_TOOLS_TARGETS ${SPIRV_TOOLS}-static)
|
||||
endif()
|
||||
|
||||
+# Create the "SPIRV-Tools" target as an alias to either "SPIRV-Tools-static"
|
||||
+# or "SPIRV-Tools-shared" depending on the value of SPIRV_TOOLS_BUILD_SHARED.
|
||||
+add_library(${SPIRV_TOOLS} ALIAS ${SPIRV_TOOLS_FULL_VISIBILITY})
|
||||
+
|
||||
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
find_library(LIBRT rt)
|
||||
if(LIBRT)
|
||||
@@ -390,14 +385,17 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
endif()
|
||||
|
||||
if(ENABLE_SPIRV_TOOLS_INSTALL)
|
||||
- if (SPIRV_TOOLS_USE_MIMALLOC AND (NOT SPIRV_TOOLS_BUILD_STATIC OR SPIRV_TOOLS_USE_MIMALLOC_IN_STATIC_BUILD))
|
||||
+ if (SPIRV_TOOLS_USE_MIMALLOC AND
|
||||
+ (NOT SPIRV_TOOLS_BUILD_STATIC OR SPIRV_TOOLS_USE_MIMALLOC_IN_STATIC_BUILD))
|
||||
list(APPEND SPIRV_TOOLS_TARGETS mimalloc-static)
|
||||
endif()
|
||||
install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets)
|
||||
export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake)
|
||||
|
||||
spvtools_config_package_dir(${SPIRV_TOOLS} PACKAGE_DIR)
|
||||
- install(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake DESTINATION ${PACKAGE_DIR})
|
||||
+ install(EXPORT ${SPIRV_TOOLS}Targets
|
||||
+ FILE ${SPIRV_TOOLS}Target.cmake
|
||||
+ DESTINATION ${PACKAGE_DIR})
|
||||
|
||||
# Special config file for root library compared to other libs.
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake
|
||||
@@ -130,7 +130,6 @@ if (YUZU_STATIC_BUILD)
|
||||
|
||||
# these libs do not properly provide static libs/let you do it with cmake
|
||||
set(fmt_FORCE_BUNDLED ON)
|
||||
set(SPIRV-Tools_FORCE_BUNDLED ON)
|
||||
set(SPIRV-Headers_FORCE_BUNDLED ON)
|
||||
set(zstd_FORCE_BUNDLED ON)
|
||||
endif()
|
||||
@@ -523,7 +522,6 @@ if (NOT YUZU_STATIC_ROOM)
|
||||
find_package(VulkanMemoryAllocator)
|
||||
find_package(VulkanUtilityLibraries)
|
||||
find_package(SimpleIni)
|
||||
find_package(SPIRV-Tools)
|
||||
find_package(sirit)
|
||||
find_package(gamemode)
|
||||
find_package(frozen)
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(SPIRV-Tools QUIET IMPORTED_TARGET SPIRV-Tools)
|
||||
find_package_handle_standard_args(SPIRV-Tools
|
||||
REQUIRED_VARS SPIRV-Tools_LINK_LIBRARIES
|
||||
VERSION_VAR SPIRV-Tools_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
FixMsysPath(PkgConfig::SPIRV-Tools)
|
||||
endif()
|
||||
|
||||
if (SPIRV-Tools_FOUND AND NOT TARGET SPIRV-Tools::SPIRV-Tools)
|
||||
if (TARGET SPIRV-Tools)
|
||||
add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools)
|
||||
else()
|
||||
add_library(SPIRV-Tools::SPIRV-Tools ALIAS PkgConfig::SPIRV-Tools)
|
||||
endif()
|
||||
endif()
|
||||
@@ -35,17 +35,17 @@ set(GIT_DESC ${BUILD_VERSION})
|
||||
# Generate cpp with Git revision from template
|
||||
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
|
||||
|
||||
# Auto-updater metadata! Must somewhat mirror GitHub API endpoint
|
||||
# Auto-updater metadata! Must somewhat mirror GitHub/Forgejo API endpoint
|
||||
|
||||
set(BUILD_AUTO_UPDATE_API_PATH "/latest/release.json")
|
||||
if (NIGHTLY_BUILD)
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_API "git.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_API_PATH "/api/v1/repos/")
|
||||
set(BUILD_AUTO_UPDATE_API "nightly.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_REPO "eden-ci/nightly")
|
||||
set(REPO_NAME "Eden Nightly")
|
||||
else()
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_API "git.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_API_PATH "/api/v1/repos/")
|
||||
set(BUILD_AUTO_UPDATE_API "stable.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_REPO "eden-emu/eden")
|
||||
set(REPO_NAME "Eden")
|
||||
endif()
|
||||
|
||||
Vendored
+36
-36
@@ -239,7 +239,7 @@ Esto vetará su nombre de usuario del foro y su dirección IP.</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/compatdb.ui" line="36"/>
|
||||
<source><html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://eden-emulator.github.io/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">eden Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of eden you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected eden account</li></ul></body></html></source>
|
||||
<translation><html><head/><body><p><span style=" font-size:10pt;">Si elijes entregar un caso de prueba a la </span><a href="https://eden-emulator.github.io/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">lista de compatibilidad de Eden</span></a><span style=" font-size:10pt;">, Se recopilará y mostrará la siguiente información en el sito:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Información del hardware (Procesador / Tarjeta gráfica / Sistema operativo)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qué version de Eden estás usando</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">La cuenta de eden que está conectada </li></ul></body></html></translation>
|
||||
<translation><html><head/><body><p><span style=" font-size:10pt;">Si elijes entregar un caso de prueba a la </span><a href="https://eden-emulator.github.io/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">lista de compatibilidad de Eden</span></a><span style=" font-size:10pt;">, Se recopilará y mostrará la siguiente información en el sito:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Información del hardware (CPU / GPU / Sistema operativo)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qué version de Eden estás usando</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">La cuenta de eden que está conectada </li></ul></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/compatdb.ui" line="77"/>
|
||||
@@ -492,14 +492,14 @@ Esto vetará su nombre de usuario del foro y su dirección IP.</translation>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="63"/>
|
||||
<source>Multicore CPU Emulation</source>
|
||||
<translation>Emulación del procesador multinúcleo </translation>
|
||||
<translation>Emulación de la CPU multinúcleo </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="64"/>
|
||||
<source>This option increases CPU emulation thread use from 1 to the maximum of 4.
|
||||
This is mainly a debug option and shouldn't be disabled.</source>
|
||||
<translation>Esta opción aumenta el uso de hilos de emulación del procesador de 1 a un máximo de 4.
|
||||
Principalmente es una opción de depuración y no debería desactivarse.</translation>
|
||||
<translation>Esta opción aumenta el uso de hilos de emulación de la CPU de 1 a un máximo de 4.
|
||||
Esta es una opción principalmente de depuración y no debería desactivarse.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="66"/>
|
||||
@@ -556,7 +556,7 @@ Desactivarlo hará que el juego se renderice lo más rápido posible según tu o
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="86"/>
|
||||
<source>Synchronizes CPU core speed with the game's maximum rendering speed to boost FPS without affecting game speed (animations, physics, etc.).
|
||||
Can help reduce stuttering at lower framerates.</source>
|
||||
<translation>Sincroniza la velocidad del núcleo del procesador con la velocidad máxima de renderizado del juego para aumentar los fotogramas por segundo sin afectar la velocidad del juego (animaciones, físicas, etc.).
|
||||
<translation>Sincroniza la velocidad del núcleo de la CPU con la velocidad máxima de renderizado del juego para aumentar los fotogramas por segundo sin afectar la velocidad del juego (animaciones, físicas, etc.).
|
||||
Puede ayudar a reducir los tirones o parpadeos en tasas de fotogramas bajas.</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -567,7 +567,7 @@ Puede ayudar a reducir los tirones o parpadeos en tasas de fotogramas bajas.</tr
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="92"/>
|
||||
<source>Change the accuracy of the emulated CPU (for debugging only).</source>
|
||||
<translation>Cambia la precisión del procesador emulado (solo para depuración)</translation>
|
||||
<translation>Cambia la precisión de la CPU emulada (solo para depuración)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="93"/>
|
||||
@@ -578,7 +578,7 @@ Puede ayudar a reducir los tirones o parpadeos en tasas de fotogramas bajas.</tr
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="95"/>
|
||||
<source>CPU Overclock</source>
|
||||
<translation>Overclock del procesador</translation>
|
||||
<translation>Overclock de la CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="96"/>
|
||||
@@ -806,7 +806,7 @@ Esta función es experimental.</translation>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="173"/>
|
||||
<source>Uses an extra CPU thread for rendering.
|
||||
This option should always remain enabled.</source>
|
||||
<translation>Usa un hilo adicional del procesador para el renderizado.
|
||||
<translation>Usa un hilo adicional de la CPU para el renderizado.
|
||||
Esta opción siempre debe permanecer activada.</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -836,9 +836,9 @@ GPU: Use the GPU's compute shaders to decode ASTC textures (recommended).
|
||||
CPU Asynchronously: Use the CPU to decode ASTC textures on demand. EliminatesASTC decoding
|
||||
stuttering but may present artifacts.</source>
|
||||
<translation>Esta opción controla cómo deben descodificarse las texturas ASTC.
|
||||
CPU: utiliza el procesador para la descodificación.
|
||||
GPU: utiliza los sombreadores computables de la tarjeta gráfica para descodificar las texturas ASTC (recomendado).
|
||||
CPU asíncrono: usa el procesador para descodificar las texturas ASTC bajo demanda. Elimina los tirones causados por la descodificación ASTC, pero puede generar errores visuales.</translation>
|
||||
CPU: utiliza la CPU para la descodificación.
|
||||
GPU: utiliza los sombreadores computables de la GPU para descodificar las texturas ASTC (recomendado).
|
||||
CPU asíncrona: usa la CPU para descodificar las texturas ASTC bajo demanda. Elimina los tirones causados por la descodificación ASTC, pero puede generar errores visuales.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="184"/>
|
||||
@@ -1354,7 +1354,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="393"/>
|
||||
<source>CPU</source>
|
||||
<translation>Procesador</translation>
|
||||
<translation>CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="394"/>
|
||||
@@ -1364,7 +1364,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="395"/>
|
||||
<source>CPU Asynchronous</source>
|
||||
<translation>Procesador asíncrono</translation>
|
||||
<translation>CPU asíncrona</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="400"/>
|
||||
@@ -1517,7 +1517,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="460"/>
|
||||
<source>CPU Video Decoding</source>
|
||||
<translation>Decodificación de vídeo en el procesador</translation>
|
||||
<translation>Decodificación de vídeo en la CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/qt_common/config/shared_translation.cpp" line="461"/>
|
||||
@@ -2367,7 +2367,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="17"/>
|
||||
<source>CPU</source>
|
||||
<translation>Procesador</translation>
|
||||
<translation>CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="28"/>
|
||||
@@ -2382,12 +2382,12 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="68"/>
|
||||
<source>CPU Backend</source>
|
||||
<translation>Motor del procesador</translation>
|
||||
<translation>Motor de la CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="95"/>
|
||||
<source>Unsafe CPU Optimization Settings</source>
|
||||
<translation>Ajustes de optimización del procesador inseguro</translation>
|
||||
<translation>Ajustes inseguros de la optimización de la CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="101"/>
|
||||
@@ -2405,12 +2405,12 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="17"/>
|
||||
<source>CPU</source>
|
||||
<translation>Procesador</translation>
|
||||
<translation>CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="25"/>
|
||||
<source>Toggle CPU Optimizations</source>
|
||||
<translation>Cambiar las optimizaciones del procesador</translation>
|
||||
<translation>Cambiar las optimizaciones de la CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
|
||||
@@ -2606,7 +2606,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="212"/>
|
||||
<source>CPU settings are available only when game is not running.</source>
|
||||
<translation>Los ajustes del procesador solo están disponibles cuando no se esté ejecutando ningún juego.</translation>
|
||||
<translation>Los ajustes de la CPU solo están disponibles cuando no se esté ejecutando ningún juego.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2644,17 +2644,17 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="209"/>
|
||||
<source>Enable Extended Logging**</source>
|
||||
<translation>Habilitar registro extendido**</translation>
|
||||
<translation>Habilitar el registro extendido**</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="216"/>
|
||||
<source>Show Log in Console</source>
|
||||
<translation>Ver registro en consola</translation>
|
||||
<translation>Ver el registro en la consola</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="223"/>
|
||||
<source>Open Log Location</source>
|
||||
<translation>Abrir ubicación del archivo de registro</translation>
|
||||
<translation>Abrir la ubicación del archivo de registro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="235"/>
|
||||
@@ -2689,7 +2689,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="282"/>
|
||||
<source>Dump Maxwell Macros</source>
|
||||
<translation>Volcar Macros Maxwell</translation>
|
||||
<translation>Volcar macros Maxwell</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="289"/>
|
||||
@@ -2734,7 +2734,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="338"/>
|
||||
<source>Disable Macro HLE</source>
|
||||
<translation>Desactivar Macro HLE</translation>
|
||||
<translation>Desactivar macro HLE</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="348"/>
|
||||
@@ -2844,7 +2844,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="538"/>
|
||||
<source>Debug Knobs: </source>
|
||||
<translation>perillas de depuración:</translation>
|
||||
<translation>Interruptores de depuración:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="572"/>
|
||||
@@ -2864,7 +2864,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="611"/>
|
||||
<source>Flush log output on each line</source>
|
||||
<translation>Limpia lg salida en cada linea</translation>
|
||||
<translation>Limpia el registro de salida en cada línea</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="618"/>
|
||||
@@ -2879,7 +2879,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="632"/>
|
||||
<source>Censor username in logs</source>
|
||||
<translation>Censura nombre de usario en logs</translation>
|
||||
<translation>Censura del nombre de usuario en los archivos de registro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="668"/>
|
||||
@@ -2921,7 +2921,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug_tab.cpp" line="17"/>
|
||||
<source>CPU</source>
|
||||
<translation>Procesador</translation>
|
||||
<translation>CPU</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2951,7 +2951,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="71"/>
|
||||
<location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="180"/>
|
||||
<source>CPU</source>
|
||||
<translation>Procesador</translation>
|
||||
<translation>CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="72"/>
|
||||
@@ -2978,7 +2978,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="76"/>
|
||||
<source>GraphicsAdvanced</source>
|
||||
<translation>Gráficosavanzados</translation>
|
||||
<translation>GráficosAvanzados</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="77"/>
|
||||
@@ -3063,7 +3063,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="65"/>
|
||||
<source>Save Data</source>
|
||||
<translation>Datos guardados</translation>
|
||||
<translation>Datos de guardado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="101"/>
|
||||
@@ -3169,7 +3169,7 @@ Cuando un programa intenta abrir el applet del controlador, se cierra inmediatam
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="151"/>
|
||||
<source>Set Custom Path</source>
|
||||
<translation>Configure ruta personalizado</translation>
|
||||
<translation>Configura una ruta personalizado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="152"/>
|
||||
@@ -4812,7 +4812,7 @@ Los valores actuales son %1% y %2% respectivamente.</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="79"/>
|
||||
<source>CPU</source>
|
||||
<translation>Procesador</translation>
|
||||
<translation>CPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="80"/>
|
||||
@@ -5814,12 +5814,12 @@ Arrastre los puntos para cambiar de posición, o haga doble clic en las celdas d
|
||||
<message>
|
||||
<location filename="../../src/yuzu/data_dialog.cpp" line="32"/>
|
||||
<source>User NAND</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>NAND del usuario</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/data_dialog.cpp" line="33"/>
|
||||
<source>System NAND</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>NAND del sistema</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/data_dialog.cpp" line="34"/>
|
||||
|
||||
Vendored
+621
-614
File diff suppressed because it is too large
Load Diff
Vendored
+2
-2
@@ -5819,12 +5819,12 @@ Drag points to change position, or double-click table cells to edit values.</sou
|
||||
<message>
|
||||
<location filename="../../src/yuzu/data_dialog.cpp" line="32"/>
|
||||
<source>User NAND</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>NAND користувача</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/data_dialog.cpp" line="33"/>
|
||||
<source>System NAND</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>NAND системи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/data_dialog.cpp" line="34"/>
|
||||
|
||||
Vendored
-8
@@ -192,14 +192,6 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# SPIRV Tools
|
||||
AddJsonPackage(spirv-tools)
|
||||
|
||||
if (SPIRV-Tools_ADDED)
|
||||
add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static)
|
||||
target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link)
|
||||
endif()
|
||||
|
||||
# Catch2
|
||||
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
||||
AddJsonPackage(catch2)
|
||||
|
||||
Vendored
-14
@@ -102,20 +102,6 @@
|
||||
"git_version": "1.3.18",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"spirv-tools": {
|
||||
"package": "SPIRV-Tools",
|
||||
"repo": "KhronosGroup/SPIRV-Tools",
|
||||
"sha": "0a7e28689a",
|
||||
"hash": "eadfcceb82f4b414528d99962335e4f806101168474028f3cf7691ac40c37f323decf2a42c525e2d5bfa6f14ff132d6c5cf9b87c151490efad01f5e13ade1520",
|
||||
"git_version": "2025.4",
|
||||
"options": [
|
||||
"SPIRV_SKIP_EXECUTABLES ON"
|
||||
],
|
||||
"patches": [
|
||||
"0001-netbsd-fix.patch",
|
||||
"0002-allow-static-only.patch"
|
||||
]
|
||||
},
|
||||
"spirv-headers": {
|
||||
"package": "SPIRV-Headers",
|
||||
"repo": "KhronosGroup/SPIRV-Headers",
|
||||
|
||||
Vendored
+2
-2
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
||||
@@ -254,7 +254,7 @@ else()
|
||||
OUTPUT
|
||||
${FFmpeg_BUILD_LIBRARIES}
|
||||
COMMAND
|
||||
make ${FFmpeg_MAKE_ARGS}
|
||||
gmake ${FFmpeg_MAKE_ARGS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
+5
@@ -17,6 +17,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
|
||||
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
|
||||
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
|
||||
EMULATE_BGR565("emulate_bgr565"),
|
||||
CPUOPT_UNSAFE_HOST_MMU("cpuopt_unsafe_host_mmu"),
|
||||
USE_DOCKED_MODE("use_docked_mode"),
|
||||
USE_AUTO_STUB("use_auto_stub"),
|
||||
@@ -33,6 +34,10 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
RENDERER_DEBUG("debug"),
|
||||
RENDERER_PATCH_OLD_QCOM_DRIVERS("patch_old_qcom_drivers"),
|
||||
RENDERER_VERTEX_INPUT_DYNAMIC_STATE("vertex_input_dynamic_state"),
|
||||
FORCE_IDENTITY_SWIZZLE("force_identity_swizzle"),
|
||||
FORCE_LDR_TO_SRGB("force_ldr_to_srgb"),
|
||||
RENDERER_PROVOKING_VERTEX("provoking_vertex"),
|
||||
RENDERER_DESCRIPTOR_INDEXING("descriptor_indexing"),
|
||||
RENDERER_SAMPLE_SHADING("sample_shading"),
|
||||
GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"),
|
||||
PICTURE_IN_PICTURE("picture_in_picture"),
|
||||
|
||||
+2
-1
@@ -17,6 +17,8 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
RENDERER_VRAM_USAGE_MODE("vram_usage_mode"),
|
||||
RENDERER_NVDEC_EMULATION("nvdec_emulation"),
|
||||
RENDERER_ASTC_DECODE_METHOD("accelerate_astc"),
|
||||
RENDERER_ASTC_RECOMPRESSION("astc_recompression"),
|
||||
RENDERER_FORMAT_REINTERPRETATION("format_reinterpretation"),
|
||||
RENDERER_ACCURACY("gpu_accuracy"),
|
||||
RENDERER_RESOLUTION("resolution_setup"),
|
||||
RENDERER_VSYNC("use_vsync"),
|
||||
@@ -24,7 +26,6 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
RENDERER_ANTI_ALIASING("anti_aliasing"),
|
||||
RENDERER_SCREEN_LAYOUT("screen_layout"),
|
||||
RENDERER_ASPECT_RATIO("aspect_ratio"),
|
||||
RENDERER_OPTIMIZE_SPIRV_OUTPUT("optimize_spirv_output"),
|
||||
|
||||
RENDERER_DYNA_STATE("dyna_state"),
|
||||
DMA_ACCURACY("dma_accuracy"),
|
||||
|
||||
+52
-9
@@ -148,6 +148,34 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.vertex_input_dynamic_state_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.FORCE_IDENTITY_SWIZZLE,
|
||||
titleId = R.string.force_identity_swizzle,
|
||||
descriptionId = R.string.force_identity_swizzle_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.FORCE_LDR_TO_SRGB,
|
||||
titleId = R.string.force_ldr_to_srgb,
|
||||
descriptionId = R.string.force_ldr_to_srgb_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.RENDERER_DESCRIPTOR_INDEXING,
|
||||
titleId = R.string.descriptor_indexing,
|
||||
descriptionId = R.string.descriptor_indexing_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.RENDERER_SAMPLE_SHADING,
|
||||
titleId = R.string.sample_shading,
|
||||
descriptionId = R.string.sample_shading_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SliderSetting(
|
||||
IntSetting.RENDERER_SAMPLE_SHADING,
|
||||
@@ -335,6 +363,23 @@ abstract class SettingsItem(
|
||||
valuesId = R.array.astcDecodingMethodValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.RENDERER_ASTC_RECOMPRESSION,
|
||||
titleId = R.string.astc_recompression,
|
||||
descriptionId = R.string.astc_recompression_description,
|
||||
choicesId = R.array.astcRecompressionMethodNames,
|
||||
valuesId = R.array.astcRecompressionMethodValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.RENDERER_FORMAT_REINTERPRETATION,
|
||||
titleId = R.string.format_reinterpretation,
|
||||
choicesId = R.array.formatReinterpretationNames,
|
||||
valuesId = R.array.formatReinterpretationValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.RENDERER_VRAM_USAGE_MODE,
|
||||
@@ -643,15 +688,6 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.renderer_async_presentation_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.RENDERER_OPTIMIZE_SPIRV_OUTPUT,
|
||||
titleId = R.string.renderer_optimize_spirv_output,
|
||||
descriptionId = R.string.renderer_optimize_spirv_output_description,
|
||||
choicesId = R.array.optimizeSpirvOutputEntries,
|
||||
valuesId = R.array.optimizeSpirvOutputValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.DMA_ACCURACY,
|
||||
@@ -756,6 +792,13 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.fix_bloom_effects_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.EMULATE_BGR565,
|
||||
titleId = R.string.emulate_bgr565,
|
||||
descriptionId = R.string.emulate_bgr565_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.CPUOPT_UNSAFE_HOST_MMU,
|
||||
|
||||
+1
-1
@@ -271,7 +271,6 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.FSR_SHARPENING_SLIDER.key)
|
||||
}
|
||||
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
||||
add(IntSetting.RENDERER_OPTIMIZE_SPIRV_OUTPUT.key)
|
||||
|
||||
add(HeaderSetting(R.string.advanced))
|
||||
|
||||
@@ -293,6 +292,7 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.FAST_GPU_TIME.key)
|
||||
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
||||
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
||||
add(BooleanSetting.EMULATE_BGR565.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key)
|
||||
add(BooleanSetting.RENDERER_ASYNC_PRESENTATION.key)
|
||||
|
||||
@@ -1726,9 +1726,8 @@ JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_getUpdateUrl(
|
||||
jobject obj,
|
||||
jstring version) {
|
||||
const char* version_str = env->GetStringUTFChars(version, nullptr);
|
||||
const std::string url = fmt::format("{}/{}/releases/tag/{}",
|
||||
std::string{Common::g_build_auto_update_website},
|
||||
std::string{Common::g_build_auto_update_repo},
|
||||
const std::string url = fmt::format("{}/{}",
|
||||
std::string{Common::g_build_auto_update_api},
|
||||
version_str);
|
||||
env->ReleaseStringUTFChars(version, version_str);
|
||||
return env->NewStringUTF(url.c_str());
|
||||
@@ -1760,11 +1759,10 @@ JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_getUpdateApkUrl(
|
||||
}
|
||||
|
||||
const std::string apk_filename = fmt::format("Eden-Android-{}-{}.apk", artifact_str, variant);
|
||||
const std::string url = fmt::format("{}/{}/releases/download/{}/{}",
|
||||
std::string{Common::g_build_auto_update_website},
|
||||
std::string{Common::g_build_auto_update_repo},
|
||||
version_str,
|
||||
apk_filename);
|
||||
|
||||
const std::string url = fmt::format("{}/{}/{}",
|
||||
std::string{Common::g_build_auto_update_api},
|
||||
version_str, apk_filename);
|
||||
|
||||
env->ReleaseStringUTFChars(tag, version_str);
|
||||
env->ReleaseStringUTFChars(artifact, artifact_str);
|
||||
|
||||
@@ -463,8 +463,6 @@
|
||||
<string name="fsr_sharpness">حدة FSR</string>
|
||||
<string name="fsr_sharpness_description">يحدد مدى وضوح الصورة عند استخدام التباين الديناميكي لـ FSR</string>
|
||||
<string name="renderer_anti_aliasing">طريقة مضاد التعرج</string>
|
||||
<string name="renderer_optimize_spirv_output">تحسين مخرجات SPIRV</string>
|
||||
<string name="renderer_optimize_spirv_output_description">يعمل على تحسين أداء برامج التظليل المجمعة لتحسين كفاءة وحدة معالجة الرسومات، ولكنه قد يؤدي إلى زيادة وقت التحميل وإبطاء السرعة في البداية.</string>
|
||||
|
||||
|
||||
<string name="advanced">متقدم</string>
|
||||
@@ -495,7 +493,7 @@
|
||||
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
|
||||
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
|
||||
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
|
||||
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Turnip من Mesa 26.0 أو أحدث. قد يتعطل على برامج التشغيل الأقدم.</string>
|
||||
<string name="use_optimized_vertex_buffers_description">يتيح ربط مخزن الرؤوس المُحسّن لتحسين الأداء. يتطلب برامج تشغيل Turnip/QCOM من إصدار Mesa 26.0 أو أحدث. سيؤدي إلى تعطل النظام عند استخدام برامج تشغيل Turnip الأقدم.</string>
|
||||
|
||||
<string name="hacks">اختراقات</string>
|
||||
|
||||
@@ -504,7 +502,9 @@
|
||||
<string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
|
||||
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
|
||||
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno 700)، ويزيل التوهج في Burnout. تحذير: قد يسبب ظهور خلل رسومي في ألعاب أخرى.</string>
|
||||
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
|
||||
<string name="emulate_bgr565">محاكاة BGR565</string>
|
||||
<string name="emulate_bgr565_description">يُصلح مشاكل انعكاس الألوان في الألعاب أو ظهور تشوهات غريبة أو ظلال غريبة.</string>
|
||||
<string name="renderer_asynchronous_shaders">استخدم تظليل غير متزامن</string>
|
||||
<string name="renderer_asynchronous_shaders_description">يقوم بتجميع التظليل بشكل غير متزامن. قد يقلل ذلك من التقطعات ولكنه قد يؤدي أيضًا إلى حدوث أخطاء.</string>
|
||||
<string name="gpu_unswizzle_settings">إعدادات إلغاء ترتيب بيانات وحدة معالجة الرسومات</string>
|
||||
|
||||
@@ -332,7 +332,6 @@
|
||||
<string name="fsr_sharpness">تیژی FSR</string>
|
||||
<string name="fsr_sharpness_description">دیاریکردنی تیژی وێنە لە کاتی بەکارهێنانی FSR</string>
|
||||
<string name="renderer_anti_aliasing">شێوازی دژە-خاوڕۆیی</string>
|
||||
<string name="renderer_optimize_spirv_output_description">شێیدەرە کۆمپایلکراوەکان باش دەکات بۆ باشترکردنی کارایی GPU.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">وردیی DMA</string>
|
||||
|
||||
@@ -442,8 +442,6 @@
|
||||
<string name="fsr_sharpness">Ostrost FSR</string>
|
||||
<string name="fsr_sharpness_description">Určuje jak ostře bude obraz vypadat při použití dynamického kontrastu FSR.</string>
|
||||
<string name="renderer_anti_aliasing">Metoda anti-aliasingu</string>
|
||||
<string name="renderer_optimize_spirv_output">Optimalizovat výstup SPIRV</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Optimalizuje kompilované shadery pro zlepšení efektivity GPU, ale mohou se objevit delší nahrávací časy a zpomalení v úvodu.</string>
|
||||
|
||||
|
||||
<string name="advanced">Pokročilé</string>
|
||||
|
||||
@@ -442,8 +442,6 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die
|
||||
<string name="fsr_sharpness">FSR-Schärfe</string>
|
||||
<string name="fsr_sharpness_description">Bestimmt die Schärfe bei FSR-Nutzung.</string>
|
||||
<string name="renderer_anti_aliasing">Kantenglättung</string>
|
||||
<string name="renderer_optimize_spirv_output">Optimiere SPIRV-Ausgabe</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Optimiert den kompilierten Shader, um die GPU-Effizienz zu verbessern.</string>
|
||||
|
||||
|
||||
<string name="advanced">Erweitert</string>
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
<string name="general_information">Información general</string>
|
||||
<string name="hardware">Hardware</string>
|
||||
<string name="supported_abis">ABIs soportadas</string>
|
||||
<string name="cpu_info">Información del procesador</string>
|
||||
<string name="cpu_info">Información de la CPU</string>
|
||||
<string name="gpu_information">Información de la GPU</string>
|
||||
<string name="vulkan_driver_version">Versión del controlador de Vulkan</string>
|
||||
<string name="error_getting_emulator_info">Error al obtener la información del emulador</string>
|
||||
@@ -416,8 +416,8 @@
|
||||
<string name="turbo_speed_limit_description">Cuando el modo turbo esté activado, la emulación se ejecutará a esta velocidad.</string>
|
||||
<string name="slow_speed_limit">Velocidad lenta</string>
|
||||
<string name="slow_speed_limit_description">Cuando el modo lento esté activado, la emulación se ejecutará a esta velocidad.</string>
|
||||
<string name="cpu_backend">Motor del procesador</string>
|
||||
<string name="cpu_accuracy">Precisión del procesador</string>
|
||||
<string name="cpu_backend">Motor de la CPU</string>
|
||||
<string name="cpu_accuracy">Precisión de la CPU</string>
|
||||
<string name="value_with_units">%1$s%2$s</string>
|
||||
|
||||
<!-- System settings strings -->
|
||||
@@ -433,7 +433,7 @@
|
||||
<string name="set_custom_rtc">Configurar RTC personalizado</string>
|
||||
|
||||
<!-- CPU -->
|
||||
<string name="fast_cpu_time">Overclock del procesador</string>
|
||||
<string name="fast_cpu_time">Overclock de la CPU</string>
|
||||
<string name="fast_cpu_time_description">Fuerza a la CPU emulada a ejecutarser a una velocidad de reloj más alta, lo cual reduce ciertos limitadores de fotogramas por segundo. Usa Boost (1700 MHz) para ejecutar a la velocidad de reloj nativa más alta de la Switch, o Fast (2000 MHz) para ejecutar a una velocidad doble de reloj.</string>
|
||||
<string name="custom_cpu_ticks">Ticks de CPU personalizados</string>
|
||||
<string name="custom_cpu_ticks_description">Establezca un valor personalizado de los ciclos de la CPU. Los valores más altos pueden aumentar el rendimiento, pero también pueden hacer que el juego se congele. Se recomienda un rango de 77–21000.</string>
|
||||
@@ -457,8 +457,6 @@
|
||||
<string name="fsr_sharpness">Nitidez FSR</string>
|
||||
<string name="fsr_sharpness_description">Ajusta la intensidad del filtro de enfoque al usar el contraste dinámico de FSR.</string>
|
||||
<string name="renderer_anti_aliasing">Método de suavizado de bordes</string>
|
||||
<string name="renderer_optimize_spirv_output">Optimizar la salida de SPIRV</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Optimiza los sombreadores compilados para mejorar la eficiencia de la GPU.</string>
|
||||
|
||||
|
||||
<string name="advanced">Avanzado</string>
|
||||
@@ -489,7 +487,7 @@
|
||||
<string name="enable_buffer_history">Activar el historial del búfer</string>
|
||||
<string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string>
|
||||
<string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Permite la vinculación optimizada del búfer de vértices para un mejor rendimiento. Requiere controladores de Mesa 26.0+ Turnip. Se producirán fallos en controladores más antiguos.</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Causará fallos con controladores Turnip más antiguos.</string>
|
||||
|
||||
<string name="hacks">Hacks</string>
|
||||
|
||||
@@ -498,7 +496,9 @@
|
||||
<string name="skip_cpu_inner_invalidation">Omitir invalidación interna de la CPU</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">Omite ciertas invalidaciones de caché de la CPU durante las actualizaciones de memoria, lo que reduce el uso de la CPU y mejora su rendimiento. Esto puede causar fallos o bloqueos en algunos juegos.</string>
|
||||
<string name="fix_bloom_effects">Arreglar los efectos de resplandor</string>
|
||||
<string name="fix_bloom_effects_description">Reduce el efecto de resplandor en LA/EOW (Adreno 700), elimina el resplandor en Burnout. Advertencia: puede causar artefactos gráficos en otros juegos.</string>
|
||||
<string name="fix_bloom_effects_description">Reduce el efecto de resplandor en LA/EOW (Adreno A6XX - A7XX/ Turnip), elimina el resplandor en Burnout. Advertencia: puede causar artefactos gráficos en otros juegos.</string>
|
||||
<string name="emulate_bgr565">Emular BGR565</string>
|
||||
<string name="emulate_bgr565_description">Soluciona problemas con colores invertidos en juegos, artefactos o sombras extrañas.</string>
|
||||
<string name="renderer_asynchronous_shaders">Usar sombreadores asíncronos</string>
|
||||
<string name="renderer_asynchronous_shaders_description">Compila los sombreadores de forma asíncrona. Esto puede reducir los tirones, pero también puede introducir errores gráficos.</string>
|
||||
<string name="gpu_unswizzle_settings">Ajustes de desentrelazado de la GPU</string>
|
||||
@@ -536,7 +536,7 @@
|
||||
<string name="warning_resolution">Escalar la resolución a 2x o más puede causar problemas y ralentizar significativamente su dispositivo.</string>
|
||||
|
||||
<!-- Debug settings strings -->
|
||||
<string name="cpu">Procesador</string>
|
||||
<string name="cpu">CPU</string>
|
||||
<string name="use_auto_stub">Usar Auto Stub</string>
|
||||
<string name="use_auto_stub_description">Rellena automáticamente servicios y funciones ausentes. Puede mejorar la compatibilidad pero puede causar cierres inesperados.</string>
|
||||
|
||||
|
||||
@@ -125,8 +125,6 @@
|
||||
<string name="nvdec_emulation_none">هیچکدام</string>
|
||||
|
||||
<!-- Optimize Spir-V output -->
|
||||
<string name="renderer_optimize_spirv_output">بهینهسازی خروجی Spir-V</string>
|
||||
<string name="renderer_optimize_spirv_output_description">شیدر کامپایل شده را برای بهبود کارایی GPU بهینهسازی میکند.</string>
|
||||
<string name="never">هرگز</string>
|
||||
<string name="on_load">در هنگام بارگذاری</string>
|
||||
<string name="always">همیشه</string>
|
||||
|
||||
@@ -455,7 +455,6 @@
|
||||
<string name="fsr_sharpness">Netteté FSR</string>
|
||||
<string name="fsr_sharpness_description">Détermine à quel point l\'image sera affinée lors de l\'utilisation du contraste dynamique FSR.</string>
|
||||
<string name="renderer_anti_aliasing">Méthode d\'anticrénelage</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Optimise le shader compilé pour améliorer l\'efficacité du GPU.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">Précision DMA</string>
|
||||
|
||||
@@ -362,7 +362,6 @@
|
||||
<string name="fsr_sharpness">חדות FSR</string>
|
||||
<string name="fsr_sharpness_description">קובע את מידת החדות בעת שימוש ב-FSR.</string>
|
||||
<string name="renderer_anti_aliasing">שיטת Anti-aliasing</string>
|
||||
<string name="renderer_optimize_spirv_output_description">משפר את השאדר המהודר כדי להגביר את יעילות ה-GPU.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">דיוק DMA</string>
|
||||
|
||||
@@ -351,7 +351,6 @@
|
||||
<string name="fsr_sharpness">FSR élesség</string>
|
||||
<string name="fsr_sharpness_description">Meghatározza, milyen éles lesz a kép az FSR dinamikus kontraszt használata közben.</string>
|
||||
<string name="renderer_anti_aliasing">Élsimítási módszer</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Optimalizálja a lefordított shadert a GPU hatékonyságának javításáért.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">DMA pontosság</string>
|
||||
|
||||
@@ -383,7 +383,6 @@
|
||||
<string name="fsr_sharpness">Ketajaman FSR</string>
|
||||
<string name="fsr_sharpness_description">Menentukan seberapa tajam gambar akan terlihat saat menggunakan kontras dinamis FSR</string>
|
||||
<string name="renderer_anti_aliasing">Metode anti-aliasing</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Mengoptimalkan shader yang dikompilasi untuk meningkatkan efisiensi GPU.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">Akurasi DMA</string>
|
||||
|
||||
@@ -390,7 +390,6 @@
|
||||
<string name="fsr_sharpness">Nitidezza FSR</string>
|
||||
<string name="fsr_sharpness_description">Determina quanto sarà nitida l\'immagine utilizzando il contrasto dinamico di FSR</string>
|
||||
<string name="renderer_anti_aliasing">Metodo di anti-aliasing</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Ottimizza lo shader compilato per migliorare l\'efficienza della GPU.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">Precisione DMA</string>
|
||||
|
||||
@@ -349,7 +349,6 @@
|
||||
<string name="renderer_vsync">垂直同期モード</string>
|
||||
<string name="renderer_scaling_filter">ウィンドウ適応フィルター</string>
|
||||
<string name="renderer_anti_aliasing">アンチエイリアス方式</string>
|
||||
<string name="renderer_optimize_spirv_output_description">コンパイル済みシェーダーを最適化し、GPUの効率を向上させます。</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">DMA精度</string>
|
||||
|
||||
@@ -349,7 +349,6 @@
|
||||
<string name="renderer_vsync">수직동기화 모드</string>
|
||||
<string name="renderer_scaling_filter">윈도우 적응 필터</string>
|
||||
<string name="renderer_anti_aliasing">안티에일리어싱 방법</string>
|
||||
<string name="renderer_optimize_spirv_output_description">컴파일된 셰이더를 최적화하여 GPU 효율성을 향상시킵니다.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">DMA 정확도</string>
|
||||
|
||||
@@ -332,7 +332,6 @@
|
||||
<string name="fsr_sharpness">FSR-skarphet</string>
|
||||
<string name="fsr_sharpness_description">Bestemmer bildekvalitet med FSR</string>
|
||||
<string name="renderer_anti_aliasing">Anti-aliasing-metode</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Optimaliserer den kompilerte shaderen for å forbedre GPU-effektiviteten.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">DMA-nøyaktighet</string>
|
||||
|
||||
@@ -442,8 +442,6 @@
|
||||
<string name="fsr_sharpness">Ostrość FSR</string>
|
||||
<string name="fsr_sharpness_description">Kontroluje ostrość obrazu w FSR.</string>
|
||||
<string name="renderer_anti_aliasing">Metoda wygładzania krawędzi</string>
|
||||
<string name="renderer_optimize_spirv_output">Optymalizuj wyjście SPIRV</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Optymalizuje skompilowany shader w celu poprawy wydajności GPU.</string>
|
||||
|
||||
|
||||
<string name="advanced">Zaawansowane</string>
|
||||
|
||||
@@ -433,7 +433,6 @@
|
||||
<string name="fsr_sharpness">Nitidez do FSR</string>
|
||||
<string name="fsr_sharpness_description">Determina a nitidez da imagem ao utilizar o contraste dinâmico do FSR</string>
|
||||
<string name="renderer_anti_aliasing">Método de Anti-aliasing</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Otimiza o shader compilado para melhorar a eficiência da GPU.</string>
|
||||
|
||||
|
||||
<string name="advanced">Avançado</string>
|
||||
|
||||
@@ -355,7 +355,6 @@
|
||||
<string name="fsr_sharpness">Nitidez do FSR</string>
|
||||
<string name="fsr_sharpness_description">Determina a nitidez da imagem ao usar contraste dinâmico do FSR</string>
|
||||
<string name="renderer_anti_aliasing">Método de Anti-Serrilhado</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Otimiza o shader compilado para melhorar a eficiência da GPU.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">Precisão da DMA</string>
|
||||
|
||||
@@ -459,8 +459,6 @@
|
||||
<string name="fsr_sharpness">Резкость FSR</string>
|
||||
<string name="fsr_sharpness_description">Определяет, насколько чётким будет изображение при использовании динамического контраста FSR.</string>
|
||||
<string name="renderer_anti_aliasing">Метод сглаживания</string>
|
||||
<string name="renderer_optimize_spirv_output">Оптимизация вывода SPIRV</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Оптимизирует скомпилированный шейдер для повышения эффективности ГПУ.</string>
|
||||
|
||||
|
||||
<string name="advanced">Расширенные</string>
|
||||
@@ -491,8 +489,6 @@
|
||||
<string name="enable_buffer_history">Включить историю буфера</string>
|
||||
<string name="enable_buffer_history_description">Позволяет обращаться к предыдущим состояниям буфера. Эта опция может повысить качество рендеринга и стабильность производительности в некоторых играх.</string>
|
||||
<string name="use_optimized_vertex_buffers">Оптимизированные вершинные буферы</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Активирует оптимизированную привязку вершинных буферов для улучшения производительности. Требуются Mesa Turnip драйвера версией не ниже 26.0, на более старых драйверах будут происходить сбои и краши</string>
|
||||
|
||||
<string name="hacks">Хаки</string>
|
||||
|
||||
<string name="fast_gpu_time">Быстрое время ГПУ</string>
|
||||
@@ -500,7 +496,6 @@
|
||||
<string name="skip_cpu_inner_invalidation">Пропустить внутреннюю инвалидацию ЦП</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх.</string>
|
||||
<string name="fix_bloom_effects">Исправить эффекты размытия</string>
|
||||
<string name="fix_bloom_effects_description">Частично убирает размытие в LA/EOW (Adreno 700), полностью отключает его в Burnout. Внимание: может вызывать графические артефакты в других играх.</string>
|
||||
<string name="renderer_asynchronous_shaders">Использовать асинхронные шейдеры</string>
|
||||
<string name="renderer_asynchronous_shaders_description">Компилирует шейдеры асинхронно. Это может уменьшить подтормаживания, но также может вызвать графические артефакты.</string>
|
||||
<string name="gpu_unswizzle_settings">Настройки распаковки текстур (Unswizzle)</string>
|
||||
|
||||
@@ -354,7 +354,6 @@
|
||||
<string name="fsr_sharpness">ФСР оштрина</string>
|
||||
<string name="fsr_sharpness_description">Одређује колико ће се слика наоштрен трајати док користи \"ФСР\" динамички контраст</string>
|
||||
<string name="renderer_anti_aliasing">Метода против алиасирања</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Оптимизира састављена схадер за побољшање ефикасности ГПУ-а.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">DMA тачност</string>
|
||||
|
||||
@@ -459,8 +459,6 @@
|
||||
<string name="fsr_sharpness">Різкість FSR</string>
|
||||
<string name="fsr_sharpness_description">Визначає різкість зображення при використанні FSR.</string>
|
||||
<string name="renderer_anti_aliasing">Згладжування</string>
|
||||
<string name="renderer_optimize_spirv_output">Оптимізовувати виведення SPIRV</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Оптимізує скомпільований шейдер для покращення ефективності GPU.</string>
|
||||
|
||||
|
||||
<string name="advanced">Додаткові</string>
|
||||
@@ -491,7 +489,7 @@
|
||||
<string name="enable_buffer_history">Увімкнути історію буфера</string>
|
||||
<string name="enable_buffer_history_description">Вмикає доступ до попередніх станів буфера. Цей параметр може покращити якість візуалізації та стабільну продуктивність у деяких іграх.</string>
|
||||
<string name="use_optimized_vertex_buffers">Оптимізовані буфери вершин</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Застосовує оптимізований буфер вершин, щоб покращити продуктивність. Потребує драйверів Mesa 26.0+ Turnip. На старіших драйверах виникатиме збій.</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Застосовує оптимізований буфер вершин, щоб покращити продуктивність. Потребує драйверів Mesa 26.0+ Turnip / QCOM. На старіших драйверах Turnip виникатиме збій.</string>
|
||||
|
||||
<string name="hacks">Обхідні рішення</string>
|
||||
|
||||
@@ -500,7 +498,9 @@
|
||||
<string name="skip_cpu_inner_invalidation">Пропустити внутрішнє інвалідування CPU</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">Пропускає деякі інвалідації кешу на стороні CPU під час оновлення пам\'яті, зменшуючи навантаження на процесор і покращуючи продуктивність. Може спричинити збої в деяких іграх.</string>
|
||||
<string name="fix_bloom_effects">Виправити ефекти світіння</string>
|
||||
<string name="fix_bloom_effects_description">Зменшує розмиття світіння в LA/EOW (Adreno 700), прибирає світіння в Burnout. Увага: може спричинити графічні артефакти в інших іграх.</string>
|
||||
<string name="fix_bloom_effects_description">Зменшує розмиття світіння в LA/EOW (Adreno A6XX–A7XX / Turnip), прибирає світіння в Burnout. Увага: може спричинити графічні артефакти в інших іграх.</string>
|
||||
<string name="emulate_bgr565">Емулювати BGR565</string>
|
||||
<string name="emulate_bgr565_description">Виправляє проблеми з інвертованими кольорами в іграх або дивними артефактами чи тінями.</string>
|
||||
<string name="renderer_asynchronous_shaders">Асинхронні шейдери</string>
|
||||
<string name="renderer_asynchronous_shaders_description">Компілює шейдери асинхронно. Це може зменшити затримки, але також може спричинити графічні баги.</string>
|
||||
<string name="gpu_unswizzle_settings">Налаштування розпакування за допомогою ГП</string>
|
||||
|
||||
@@ -330,7 +330,6 @@
|
||||
<string name="fsr_sharpness">Độ sắc nét FSR</string>
|
||||
<string name="fsr_sharpness_description">Độ sắc nét khi dùng FSR</string>
|
||||
<string name="renderer_anti_aliasing">Phương pháp khử răng cưa</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Tối ưu hóa shader đã biên dịch để cải thiện hiệu suất GPU.</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">Độ chính xác DMA</string>
|
||||
|
||||
@@ -453,8 +453,6 @@
|
||||
<string name="fsr_sharpness">FSR 锐化度</string>
|
||||
<string name="fsr_sharpness_description">指定使用 FSR 时图像的锐化程度</string>
|
||||
<string name="renderer_anti_aliasing">抗锯齿方式</string>
|
||||
<string name="renderer_optimize_spirv_output">优化 SPIRV 输出</string>
|
||||
<string name="renderer_optimize_spirv_output_description">优化编译后的着色器以提高GPU效率。</string>
|
||||
|
||||
|
||||
<string name="advanced">高级</string>
|
||||
@@ -485,8 +483,6 @@
|
||||
<string name="enable_buffer_history">启用缓冲区历史</string>
|
||||
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
|
||||
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
|
||||
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 驱动程序。在旧版驱动程序上会导致程序崩溃。</string>
|
||||
|
||||
<string name="hacks">Hacks</string>
|
||||
|
||||
<string name="fast_gpu_time">GPU 超频频率</string>
|
||||
@@ -494,7 +490,6 @@
|
||||
<string name="skip_cpu_inner_invalidation">跳过CPU内部无效化</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">在内存更新期间跳过某些CPU端缓存无效化,减少CPU使用率并提高其性能。可能会导致某些游戏出现故障或崩溃。</string>
|
||||
<string name="fix_bloom_effects">修复 Bloom 效果</string>
|
||||
<string name="fix_bloom_effects_description">减少《塞尔达传说:智慧的再现》(Adreno 700)中的 bloom 模糊,并移除《Burnout》中的 bloom 效果。警告:可能会导致在其他游戏中出现画面显示问题。</string>
|
||||
<string name="renderer_asynchronous_shaders">使用异步着色器</string>
|
||||
<string name="renderer_asynchronous_shaders_description">异步编译着色器。这可能会减少卡顿,但也可能会导致图形错误。</string>
|
||||
<string name="gpu_unswizzle_settings">GPU 还原设置</string>
|
||||
|
||||
@@ -440,7 +440,6 @@
|
||||
<string name="fsr_sharpness">FSR 銳化度</string>
|
||||
<string name="fsr_sharpness_description">使用 FSR 時圖片的銳化程度</string>
|
||||
<string name="renderer_anti_aliasing">抗鋸齒</string>
|
||||
<string name="renderer_optimize_spirv_output_description">最佳化編譯後的著色器以提高GPU效率。</string>
|
||||
|
||||
|
||||
<string name="dma_accuracy">DMA 準確度</string>
|
||||
|
||||
@@ -469,8 +469,6 @@
|
||||
<string name="fsr_sharpness">FSR sharpness</string>
|
||||
<string name="fsr_sharpness_description">Determines how sharpened the image will look while using FSR\'s dynamic contrast</string>
|
||||
<string name="renderer_anti_aliasing">Anti-aliasing method</string>
|
||||
<string name="renderer_optimize_spirv_output">Optimize SPIRV output</string>
|
||||
<string name="renderer_optimize_spirv_output_description">Optimizes compiled shaders to improve GPU efficiency, but may introduce longer loading times and initial slowdowns.</string>
|
||||
|
||||
|
||||
<string name="advanced">Advanced</string>
|
||||
@@ -501,7 +499,7 @@
|
||||
<string name="enable_buffer_history">Enable buffer history</string>
|
||||
<string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string>
|
||||
<string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers. Will crash on older drivers.</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers.</string>
|
||||
|
||||
<string name="hacks">Hacks</string>
|
||||
|
||||
@@ -510,7 +508,9 @@
|
||||
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
||||
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
||||
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
||||
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
||||
<string name="emulate_bgr565">Emulate BGR565</string>
|
||||
<string name="emulate_bgr565_description">Fixes problems with inverted colors in games or strange artifacts or strange shadows.</string>
|
||||
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
||||
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
||||
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
|
||||
|
||||
@@ -693,7 +693,9 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(host_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
if (impl && virtual_base) {
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
}
|
||||
ASSERT(host_offset + length <= backing_size);
|
||||
if (length == 0 || !virtual_base || !impl) {
|
||||
return;
|
||||
@@ -704,7 +706,9 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
if (impl && virtual_base) {
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
}
|
||||
if (length == 0 || !virtual_base || !impl) {
|
||||
return;
|
||||
}
|
||||
@@ -714,7 +718,9 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap)
|
||||
void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) {
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
if (impl && virtual_base) {
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
}
|
||||
if (length == 0 || !virtual_base || !impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ SWITCHABLE(AstcRecompression, true);
|
||||
SWITCHABLE(AudioMode, true);
|
||||
SWITCHABLE(CpuBackend, true);
|
||||
SWITCHABLE(CpuAccuracy, true);
|
||||
SWITCHABLE(FormatReinterpretation, true);
|
||||
SWITCHABLE(FullscreenMode, true);
|
||||
SWITCHABLE(GpuAccuracy, true);
|
||||
SWITCHABLE(GpuLogLevel, true);
|
||||
|
||||
+67
-6
@@ -69,6 +69,7 @@ SWITCHABLE(AstcRecompression, true);
|
||||
SWITCHABLE(AudioMode, true);
|
||||
SWITCHABLE(CpuBackend, true);
|
||||
SWITCHABLE(CpuAccuracy, true);
|
||||
SWITCHABLE(FormatReinterpretation, true);
|
||||
SWITCHABLE(FullscreenMode, true);
|
||||
SWITCHABLE(GpuAccuracy, true);
|
||||
SWITCHABLE(Language, true);
|
||||
@@ -388,10 +389,6 @@ struct Values {
|
||||
true,
|
||||
true};
|
||||
|
||||
SwitchableSetting<SpirvOptimizeMode, true> optimize_spirv_output{linkage,
|
||||
SpirvOptimizeMode::Never,
|
||||
"optimize_spirv_output",
|
||||
Category::Renderer};
|
||||
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
|
||||
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
|
||||
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||
@@ -473,7 +470,11 @@ struct Values {
|
||||
"astc_recompression",
|
||||
Category::RendererAdvanced};
|
||||
|
||||
|
||||
SwitchableSetting<FormatReinterpretation, true> format_reinterpretation{
|
||||
linkage,
|
||||
FormatReinterpretation::Disabled,
|
||||
"format_reinterpretation",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> sync_memory_operations{linkage,
|
||||
false,
|
||||
"sync_memory_operations",
|
||||
@@ -482,6 +483,9 @@ struct Values {
|
||||
true,
|
||||
true};
|
||||
|
||||
SwitchableSetting<bool> force_identity_swizzle{linkage, false, "force_identity_swizzle",
|
||||
Category::RendererAdvanced};
|
||||
|
||||
SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
|
||||
Category::RendererAdvanced};
|
||||
|
||||
@@ -555,6 +559,9 @@ struct Values {
|
||||
SwitchableSetting<bool> fix_bloom_effects{linkage, false, "fix_bloom_effects",
|
||||
Category::RendererHacks};
|
||||
|
||||
SwitchableSetting<bool> emulate_bgr565{linkage, false, "emulate_bgr565",
|
||||
Category::RendererHacks};
|
||||
|
||||
SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack",
|
||||
Category::RendererHacks};
|
||||
|
||||
@@ -584,7 +591,7 @@ struct Values {
|
||||
|
||||
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
|
||||
#if defined(ANDROID)
|
||||
ExtendedDynamicState::EDS1,
|
||||
ExtendedDynamicState::Disabled,
|
||||
#elif defined(__APPLE__)
|
||||
ExtendedDynamicState::Disabled,
|
||||
#else
|
||||
@@ -609,6 +616,60 @@ struct Values {
|
||||
#endif
|
||||
"vertex_input_dynamic_state", Category::RendererExtensions};
|
||||
|
||||
#ifdef ANDROID
|
||||
// Shader Float Controls (Android only) - Eden Veil / Extensions
|
||||
// Force enable VK_KHR_shader_float_controls even if driver has known issues
|
||||
// Allows fine-tuning float behavior to match Switch/Maxwell or optimize performance
|
||||
SwitchableSetting<bool> shader_float_controls_force_enable{linkage,
|
||||
false,
|
||||
"shader_float_controls_force_enable",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Paired};
|
||||
|
||||
// Individual float behavior controls (visible only when force_enable is true)
|
||||
// Multiple can be active simultaneously EXCEPT FTZ and DenormPreserve (mutually exclusive)
|
||||
//
|
||||
// Recommended configurations:
|
||||
// Switch-native: FTZ=ON, RTE=ON, SignedZero=ON (matches Maxwell behavior)
|
||||
// Performance: FTZ=ON only (fastest)
|
||||
// Accuracy: DenormPreserve=ON, RTE=ON, SignedZero=ON (slowest, highest precision)
|
||||
SwitchableSetting<bool> shader_float_ftz{linkage,
|
||||
false,
|
||||
"shader_float_ftz",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Default,
|
||||
true,
|
||||
false,
|
||||
&shader_float_controls_force_enable};
|
||||
|
||||
SwitchableSetting<bool> shader_float_denorm_preserve{linkage,
|
||||
false,
|
||||
"shader_float_denorm_preserve",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Default,
|
||||
true,
|
||||
false,
|
||||
&shader_float_controls_force_enable};
|
||||
|
||||
SwitchableSetting<bool> shader_float_rte{linkage,
|
||||
false,
|
||||
"shader_float_rte",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Default,
|
||||
true,
|
||||
false,
|
||||
&shader_float_controls_force_enable};
|
||||
|
||||
SwitchableSetting<bool> shader_float_signed_zero_inf_nan{linkage,
|
||||
false,
|
||||
"shader_float_signed_zero_inf_nan",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Default,
|
||||
true,
|
||||
false,
|
||||
&shader_float_controls_force_enable};
|
||||
#endif
|
||||
|
||||
Setting<bool> renderer_debug{linkage, false, "debug", Category::RendererDebug};
|
||||
Setting<bool> renderer_shader_feedback{linkage, false, "shader_feedback",
|
||||
Category::RendererDebug};
|
||||
|
||||
@@ -158,6 +158,17 @@ ENUM(ExtendedDynamicState, Disabled, EDS1, EDS2, EDS3);
|
||||
ENUM(GpuLogLevel, Off, Errors, Standard, Verbose, All)
|
||||
ENUM(GameListMode, TreeView, GridView);
|
||||
ENUM(SpeedMode, Standard, Turbo, Slow);
|
||||
ENUM(FormatReinterpretation, Disabled, R32UintToR32Sfloat, R32SintToR32Uint, R32SfloatToR32Sint)
|
||||
|
||||
// Shader Float Controls behavior modes
|
||||
// These control how floating-point denormals and special values are handled in shaders
|
||||
ENUM(ShaderFloatBehavior,
|
||||
DriverDefault, // Let driver choose (safest, may not match Switch behavior)
|
||||
SwitchNative, // Emulate Switch/Maxwell behavior (FTZ + RTE + SignedZero)
|
||||
FlushToZero, // FTZ only - flush denorms to zero (fastest, some precision loss)
|
||||
PreserveDenorms, // Preserve denorms (slowest, highest precision)
|
||||
RoundToEven, // RTE rounding mode (IEEE 754 compliant)
|
||||
SignedZeroInfNan); // Preserve signed zero, inf, nan (accuracy for edge cases)
|
||||
|
||||
template <typename Type>
|
||||
inline std::string_view CanonicalizeEnum(Type id) {
|
||||
|
||||
@@ -396,6 +396,24 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
|
||||
const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size()};
|
||||
const std::size_t buffer_size{GetWriteBufferSize(buffer_index)};
|
||||
|
||||
// Defensive check: if client didn't provide output buffer, log detailed error but don't crash
|
||||
if (buffer_size == 0) {
|
||||
LOG_ERROR(Core,
|
||||
"WriteBuffer called but client provided NO output buffer! "
|
||||
"Requested size: 0x{:X}, buffer_index: {}, is_buffer_b: {}, "
|
||||
"BufferB count: {}, BufferC count: {}",
|
||||
size, buffer_index, is_buffer_b, BufferDescriptorB().size(),
|
||||
BufferDescriptorC().size());
|
||||
|
||||
// Log command context for debugging
|
||||
LOG_ERROR(Core, "IPC Command: 0x{:X}, Type: {}", GetCommand(),
|
||||
static_cast<u32>(GetCommandType()));
|
||||
|
||||
// Return 0 instead of crashing - let service handle error
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size > buffer_size) {
|
||||
LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
|
||||
buffer_size);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <fmt/format.h>
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/fs_types.h"
|
||||
@@ -25,7 +26,10 @@ std::vector<std::filesystem::path> GetModFolder(const std::string& root) {
|
||||
"romfslite"};
|
||||
|
||||
if (std::ranges::find(valid_names, name) != valid_names.end()) {
|
||||
paths.emplace_back(entry.path().parent_path());
|
||||
const auto parent = entry.path().parent_path();
|
||||
if (std::ranges::find(paths, parent) == paths.end()) {
|
||||
paths.emplace_back(parent);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -80,55 +80,24 @@ std::optional<std::string> UpdateChecker::GetResponse(std::string url, std::stri
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<UpdateChecker::Update> UpdateChecker::GetLatestRelease(bool include_prereleases) {
|
||||
std::optional<UpdateChecker::Update> UpdateChecker::GetLatestRelease() {
|
||||
#ifdef YUZU_BUNDLED_OPENSSL
|
||||
const auto update_check_url = fmt::format("https://{}", Common::g_build_auto_update_api);
|
||||
#else
|
||||
const auto update_check_url = std::string{Common::g_build_auto_update_api};
|
||||
#endif
|
||||
|
||||
auto update_check_path = fmt::format("{}{}", std::string{Common::g_build_auto_update_api_path},
|
||||
std::string{Common::g_build_auto_update_repo});
|
||||
auto update_check_path = std::string{Common::g_build_auto_update_api_path};
|
||||
try {
|
||||
if (include_prereleases) { // This can return either a prerelease or a stable release,
|
||||
// whichever is more recent.
|
||||
const auto update_check_tags_path = update_check_path + "/tags";
|
||||
const auto update_check_releases_path = update_check_path + "/releases";
|
||||
const auto response = UpdateChecker::GetResponse(update_check_url, update_check_path);
|
||||
|
||||
const auto tags_response = UpdateChecker::GetResponse(update_check_url, update_check_tags_path);
|
||||
const auto releases_response = UpdateChecker::GetResponse(update_check_url, update_check_releases_path);
|
||||
if (!response)
|
||||
return {};
|
||||
|
||||
if (!tags_response || !releases_response)
|
||||
return {};
|
||||
|
||||
const std::string latest_tag
|
||||
= nlohmann::json::parse(tags_response.value()).at(0).at("name");
|
||||
const std::string latest_name =
|
||||
nlohmann::json::parse(releases_response.value()).at(0).at("name");
|
||||
|
||||
const bool latest_tag_has_release = releases_response.value().find(
|
||||
fmt::format("\"{}\"", latest_tag))
|
||||
!= std::string::npos;
|
||||
|
||||
// If there is a newer tag, but that tag has no associated release, don't prompt the
|
||||
// user to update.
|
||||
if (!latest_tag_has_release)
|
||||
return {};
|
||||
|
||||
return Update{latest_tag, latest_name};
|
||||
} else { // This is a stable release, only check for other stable releases.
|
||||
update_check_path += "/releases/latest";
|
||||
const auto response = UpdateChecker::GetResponse(update_check_url, update_check_path);
|
||||
|
||||
if (!response)
|
||||
return {};
|
||||
|
||||
const std::string latest_tag = nlohmann::json::parse(response.value()).at("tag_name");
|
||||
const std::string latest_name = nlohmann::json::parse(response.value()).at("name");
|
||||
|
||||
return Update{latest_tag, latest_name};
|
||||
}
|
||||
const std::string latest_tag = nlohmann::json::parse(response.value()).at("tag_name");
|
||||
const std::string latest_name = nlohmann::json::parse(response.value()).at("name");
|
||||
|
||||
return Update{latest_tag, latest_name};
|
||||
} catch (nlohmann::detail::out_of_range&) {
|
||||
LOG_ERROR(Frontend,
|
||||
"Parsing JSON response from {}{} failed during update check: "
|
||||
@@ -147,12 +116,8 @@ std::optional<UpdateChecker::Update> UpdateChecker::GetLatestRelease(bool includ
|
||||
}
|
||||
|
||||
std::optional<UpdateChecker::Update> UpdateChecker::GetUpdate() {
|
||||
const bool is_prerelease = ((strstr(Common::g_build_version, "pre-alpha") != NULL) ||
|
||||
(strstr(Common::g_build_version, "alpha") != NULL) ||
|
||||
(strstr(Common::g_build_version, "beta") != NULL) ||
|
||||
(strstr(Common::g_build_version, "rc") != NULL));
|
||||
const std::optional<UpdateChecker::Update> latest_release_tag =
|
||||
UpdateChecker::GetLatestRelease(is_prerelease);
|
||||
UpdateChecker::GetLatestRelease();
|
||||
|
||||
if (!latest_release_tag)
|
||||
goto empty;
|
||||
|
||||
@@ -18,6 +18,6 @@ typedef struct {
|
||||
} Update;
|
||||
|
||||
std::optional<std::string> GetResponse(std::string url, std::string path);
|
||||
std::optional<Update> GetLatestRelease(bool include_prereleases);
|
||||
std::optional<Update> GetLatestRelease();
|
||||
std::optional<Update> GetUpdate();
|
||||
} // namespace UpdateChecker
|
||||
|
||||
@@ -162,13 +162,21 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
||||
tr("Stretches the renderer to fit the specified aspect ratio.\nMost games only support "
|
||||
"16:9, so modifications are required to get other ratios.\nAlso controls the "
|
||||
"aspect ratio of captured screenshots."));
|
||||
INSERT(Settings, use_disk_shader_cache, tr("Use persistent pipeline cache"),
|
||||
INSERT(Settings,
|
||||
format_reinterpretation,
|
||||
tr("Format Reinterpretation:"),
|
||||
tr("Reinterprets certain texture formats for accuracy rendering.\nMay cause "
|
||||
"graphical issues in some games."));
|
||||
INSERT(Settings,
|
||||
force_identity_swizzle,
|
||||
tr("Force Identity Swizzle"),
|
||||
tr("Forces identity component swizzle for storage and input attachment images. "
|
||||
"Required by Vulkan spec. Disable only for debugging driver issues."));
|
||||
INSERT(Settings,
|
||||
use_disk_shader_cache,
|
||||
tr("Use persistent pipeline cache"),
|
||||
tr("Allows saving shaders to storage for faster loading on following game "
|
||||
"boots.\nDisabling it is only intended for debugging."));
|
||||
INSERT(Settings, optimize_spirv_output, tr("Optimize SPIRV output"),
|
||||
tr("Runs an additional optimization pass over generated SPIRV shaders.\n"
|
||||
"Will increase time required for shader compilation.\nMay slightly improve "
|
||||
"performance.\nThis feature is experimental."));
|
||||
INSERT(Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"),
|
||||
tr("Uses an extra CPU thread for rendering.\nThis option should always remain enabled."));
|
||||
INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"),
|
||||
@@ -684,6 +692,13 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
|
||||
PAIR(GameListMode, TreeView, tr("Tree View")),
|
||||
PAIR(GameListMode, GridView, tr("Grid View")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::FormatReinterpretation>::Index(),
|
||||
{
|
||||
PAIR(FormatReinterpretation, Disabled, tr("Disabled")),
|
||||
PAIR(FormatReinterpretation, R32UintToR32Sfloat, tr("R32 Uint to R32 Float")),
|
||||
PAIR(FormatReinterpretation, R32SintToR32Uint, tr("R32 Sint to R32 Uint")),
|
||||
PAIR(FormatReinterpretation, R32SfloatToR32Sint, tr("R32 Float to R32 Sint")),
|
||||
}});
|
||||
|
||||
#undef PAIR
|
||||
#undef CTX_PAIR
|
||||
|
||||
@@ -55,6 +55,17 @@ static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map
|
||||
{Settings::ScalingFilter::Mmpx, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "MMPX"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::FormatReinterpretation, QString> format_reinterpretation_texts_map = {
|
||||
{Settings::FormatReinterpretation::Disabled,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Disabled"))},
|
||||
{Settings::FormatReinterpretation::R32UintToR32Sfloat,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "R32 Uint to R32 Float"))},
|
||||
{Settings::FormatReinterpretation::R32SintToR32Uint,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "R32 Sint to R32 Uint"))},
|
||||
{Settings::FormatReinterpretation::R32SfloatToR32Sint,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "R32 Float to R32 Sint"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = {
|
||||
{Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Docked"))},
|
||||
{Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Handheld"))},
|
||||
|
||||
@@ -101,8 +101,10 @@ QStringList GetModFolders(const QString& root, const QString& fallbackName) {
|
||||
} else {
|
||||
// Rename the existing mod folder.
|
||||
const auto new_path = std_path.parent_path() / name.toStdString();
|
||||
fs::remove_all(new_path);
|
||||
fs::rename(std_path, new_path);
|
||||
if (new_path != std_path) {
|
||||
fs::remove_all(new_path);
|
||||
fs::rename(std_path, new_path);
|
||||
}
|
||||
std_path = new_path;
|
||||
}
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ add_library(shader_recompiler STATIC
|
||||
|
||||
)
|
||||
|
||||
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit::sirit SPIRV-Tools::SPIRV-Tools)
|
||||
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit::sirit)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(shader_recompiler PRIVATE
|
||||
|
||||
@@ -382,13 +382,14 @@ void EmitContext::SetupExtensions() {
|
||||
if (info.uses_int64 && profile.support_int64) {
|
||||
header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
|
||||
}
|
||||
if (info.uses_int64_bit_atomics) {
|
||||
if (info.uses_int64_bit_atomics && profile.support_gl_shader_atomic_int64) {
|
||||
header += "#extension GL_NV_shader_atomic_int64 : enable\n";
|
||||
}
|
||||
if (info.uses_atomic_f32_add) {
|
||||
if (info.uses_atomic_f32_add && profile.support_gl_shader_atomic_float) {
|
||||
header += "#extension GL_NV_shader_atomic_float : enable\n";
|
||||
}
|
||||
if (info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) {
|
||||
if ((info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) &&
|
||||
profile.support_gl_shader_atomic_fp16_vector) {
|
||||
header += "#extension GL_NV_shader_atomic_fp16_vector : enable\n";
|
||||
}
|
||||
if (info.uses_fp16) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <spirv-tools/optimizer.hpp>
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
@@ -22,15 +21,7 @@ namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
template <class Func>
|
||||
struct FuncTraits {};
|
||||
thread_local std::unique_ptr<spvtools::Optimizer> thread_optimizer;
|
||||
|
||||
spvtools::Optimizer& GetThreadOptimizer() {
|
||||
if (!thread_optimizer) {
|
||||
thread_optimizer = std::make_unique<spvtools::Optimizer>(SPV_ENV_VULKAN_1_3);
|
||||
thread_optimizer->RegisterPerformancePasses();
|
||||
}
|
||||
return *thread_optimizer;
|
||||
}
|
||||
template <class ReturnType_, class... Args>
|
||||
struct FuncTraits<ReturnType_ (*)(Args...)> {
|
||||
using ReturnType = ReturnType_;
|
||||
@@ -341,19 +332,35 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
||||
void SetupDenormControl(const Profile& profile, const IR::Program& program, EmitContext& ctx,
|
||||
Id main_func) {
|
||||
const Info& info{program.info};
|
||||
|
||||
// User-forced behavior overrides (Android Eden Veil/Extensions)
|
||||
// When force flags are active, they take precedence over shader-declared behavior
|
||||
const bool force_flush = profile.force_fp32_denorm_flush;
|
||||
const bool force_preserve = profile.force_fp32_denorm_preserve;
|
||||
|
||||
if (force_flush && force_preserve) {
|
||||
LOG_WARNING(Shader_SPIRV, "Both FTZ and Preserve forced simultaneously - FTZ takes precedence");
|
||||
}
|
||||
|
||||
if (info.uses_fp32_denorms_flush && info.uses_fp32_denorms_preserve) {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 denorm flush and preserve on the same shader");
|
||||
} else if (info.uses_fp32_denorms_flush) {
|
||||
} else if (force_flush || info.uses_fp32_denorms_flush) {
|
||||
if (profile.support_fp32_denorm_flush) {
|
||||
ctx.AddCapability(spv::Capability::DenormFlushToZero);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormFlushToZero, 32U);
|
||||
if (force_flush) {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 DenormFlushToZero FORCED by user setting");
|
||||
}
|
||||
} else {
|
||||
// Drivers will most likely flush denorms by default, no need to warn
|
||||
}
|
||||
} else if (info.uses_fp32_denorms_preserve) {
|
||||
} else if (force_preserve || info.uses_fp32_denorms_preserve) {
|
||||
if (profile.support_fp32_denorm_preserve) {
|
||||
ctx.AddCapability(spv::Capability::DenormPreserve);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 32U);
|
||||
if (force_preserve) {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 DenormPreserve FORCED by user setting");
|
||||
}
|
||||
} else {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 denorm preserve used in shader without host support");
|
||||
}
|
||||
@@ -386,13 +393,24 @@ void SetupSignedNanCapabilities(const Profile& profile, const IR::Program& progr
|
||||
if (profile.has_broken_fp16_float_controls && program.info.uses_fp16) {
|
||||
return;
|
||||
}
|
||||
|
||||
// User-forced behavior (Android Eden Veil/Extensions)
|
||||
const bool force_signed_zero_inf_nan = profile.force_fp32_signed_zero_inf_nan;
|
||||
|
||||
if (program.info.uses_fp16 && profile.support_fp16_signed_zero_nan_preserve) {
|
||||
ctx.AddCapability(spv::Capability::SignedZeroInfNanPreserve);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::SignedZeroInfNanPreserve, 16U);
|
||||
}
|
||||
if (profile.support_fp32_signed_zero_nan_preserve) {
|
||||
ctx.AddCapability(spv::Capability::SignedZeroInfNanPreserve);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::SignedZeroInfNanPreserve, 32U);
|
||||
if (force_signed_zero_inf_nan || profile.support_fp32_signed_zero_nan_preserve) {
|
||||
if (profile.support_fp32_signed_zero_nan_preserve) {
|
||||
ctx.AddCapability(spv::Capability::SignedZeroInfNanPreserve);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::SignedZeroInfNanPreserve, 32U);
|
||||
if (force_signed_zero_inf_nan) {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 SignedZeroInfNanPreserve FORCED by user setting");
|
||||
}
|
||||
} else if (force_signed_zero_inf_nan) {
|
||||
LOG_WARNING(Shader_SPIRV, "SignedZeroInfNanPreserve forced but driver doesn't support it");
|
||||
}
|
||||
}
|
||||
if (program.info.uses_fp64 && profile.support_fp64_signed_zero_nan_preserve) {
|
||||
ctx.AddCapability(spv::Capability::SignedZeroInfNanPreserve);
|
||||
@@ -501,8 +519,7 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
|
||||
IR::Program& program, Bindings& bindings, bool optimize) {
|
||||
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, Bindings& bindings) {
|
||||
EmitContext ctx{profile, runtime_info, program, bindings};
|
||||
const Id main{DefineMain(ctx, program)};
|
||||
DefineEntryPoint(program, ctx, main);
|
||||
@@ -514,29 +531,7 @@ std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in
|
||||
SetupCapabilities(profile, program.info, ctx);
|
||||
SetupTransformFeedbackCapabilities(ctx, main);
|
||||
PatchPhiNodes(program, ctx);
|
||||
|
||||
if (!optimize) {
|
||||
return ctx.Assemble();
|
||||
} else {
|
||||
std::vector<u32> spirv = ctx.Assemble();
|
||||
|
||||
// Use thread-local optimizer instead of creating a new one
|
||||
auto& spv_opt = GetThreadOptimizer();
|
||||
spv_opt.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
|
||||
LOG_ERROR(HW_GPU, "spirv-opt: {}", m);
|
||||
});
|
||||
|
||||
spvtools::OptimizerOptions opt_options;
|
||||
opt_options.set_run_validator(false);
|
||||
|
||||
std::vector<u32> result;
|
||||
if (!spv_opt.Run(spirv.data(), spirv.size(), &result, opt_options)) {
|
||||
LOG_ERROR(HW_GPU,
|
||||
"Failed to optimize SPIRV shader output, continuing without optimization");
|
||||
result = std::move(spirv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return ctx.Assemble();
|
||||
}
|
||||
|
||||
Id EmitPhi(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -33,13 +33,10 @@ constexpr u32 RESCALING_LAYOUT_WORDS_OFFSET = offsetof(RescalingLayout, rescalin
|
||||
constexpr u32 RESCALING_LAYOUT_DOWN_FACTOR_OFFSET = offsetof(RescalingLayout, down_factor);
|
||||
constexpr u32 RENDERAREA_LAYOUT_OFFSET = offsetof(RenderAreaLayout, render_area);
|
||||
|
||||
[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
|
||||
IR::Program& program, Bindings& bindings, bool optimize);
|
||||
|
||||
[[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program,
|
||||
bool optimize) {
|
||||
[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, Bindings& bindings);
|
||||
[[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program) {
|
||||
Bindings binding;
|
||||
return EmitSPIRV(profile, {}, program, binding, optimize);
|
||||
return EmitSPIRV(profile, {}, program, binding);
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
||||
@@ -332,13 +332,23 @@ void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, I
|
||||
return;
|
||||
}
|
||||
|
||||
// Mobile GPUs: 1D textures emulated as 2D with height=1
|
||||
const bool emulate_1d = ctx.profile.needs_1d_texture_emulation;
|
||||
|
||||
Id result_type{};
|
||||
switch (info.type) {
|
||||
case TextureType::Buffer:
|
||||
case TextureType::Color1D: {
|
||||
result_type = ctx.U32[1];
|
||||
break;
|
||||
}
|
||||
case TextureType::Color1D:
|
||||
if (emulate_1d) {
|
||||
// Treat as 2D: offset needs Y component
|
||||
offset = ctx.OpCompositeConstruct(ctx.U32[2], offset, ctx.u32_zero_value);
|
||||
result_type = ctx.U32[2];
|
||||
} else {
|
||||
result_type = ctx.U32[1];
|
||||
}
|
||||
break;
|
||||
case TextureType::ColorArray1D:
|
||||
offset = ctx.OpCompositeConstruct(ctx.U32[2], offset, ctx.u32_zero_value);
|
||||
[[fallthrough]];
|
||||
@@ -362,6 +372,40 @@ void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, I
|
||||
}
|
||||
coords = ctx.OpIAdd(result_type, coords, offset);
|
||||
}
|
||||
|
||||
// Helper: Convert 1D coordinates to 2D when emulating 1D textures on mobile GPUs
|
||||
[[nodiscard]] Id AdjustCoordinatesForEmulation(EmitContext& ctx, const IR::TextureInstInfo& info,
|
||||
Id coords) {
|
||||
if (!ctx.profile.needs_1d_texture_emulation) {
|
||||
return coords;
|
||||
}
|
||||
|
||||
switch (info.type) {
|
||||
case TextureType::Color1D: {
|
||||
// Convert scalar → vec2(x, 0.0)
|
||||
return ctx.OpCompositeConstruct(ctx.F32[2], coords, ctx.f32_zero_value);
|
||||
}
|
||||
case TextureType::ColorArray1D: {
|
||||
// Convert vec2(x, layer) → vec3(x, 0.0, layer)
|
||||
// ColorArray1D coords are always vec2 in IR
|
||||
const Id x = ctx.OpCompositeExtract(ctx.F32[1], coords, 0);
|
||||
const Id layer = ctx.OpCompositeExtract(ctx.F32[1], coords, 1);
|
||||
return ctx.OpCompositeConstruct(ctx.F32[3], x, ctx.f32_zero_value, layer);
|
||||
}
|
||||
case TextureType::Color2D:
|
||||
case TextureType::ColorArray2D:
|
||||
case TextureType::Color3D:
|
||||
case TextureType::ColorCube:
|
||||
case TextureType::ColorArrayCube:
|
||||
case TextureType::Buffer:
|
||||
case TextureType::Color2DRect:
|
||||
// No adjustment needed for non-1D textures
|
||||
return coords;
|
||||
}
|
||||
|
||||
return coords; // Unreachable, but silences -Werror=return-type
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
|
||||
@@ -463,6 +507,7 @@ Id EmitBoundImageWrite(EmitContext&) {
|
||||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id bias_lc, const IR::Value& offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
if (ctx.stage == Stage::Fragment) {
|
||||
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0,
|
||||
bias_lc, offset);
|
||||
@@ -484,6 +529,7 @@ Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value&
|
||||
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id lod, const IR::Value& offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
const ImageOperands operands(ctx, false, true, false, lod, offset);
|
||||
|
||||
Id result = Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
@@ -500,6 +546,7 @@ Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value&
|
||||
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
Id coords, Id dref, Id bias_lc, const IR::Value& offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
if (ctx.stage == Stage::Fragment) {
|
||||
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0,
|
||||
bias_lc, offset);
|
||||
@@ -521,6 +568,7 @@ Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va
|
||||
Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
Id coords, Id dref, Id lod, const IR::Value& offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
const ImageOperands operands(ctx, false, true, false, lod, offset);
|
||||
return Emit(&EmitContext::OpImageSparseSampleDrefExplicitLod,
|
||||
&EmitContext::OpImageSampleDrefExplicitLod, ctx, inst, ctx.F32[1],
|
||||
@@ -530,6 +578,7 @@ Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va
|
||||
Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
const IR::Value& offset, const IR::Value& offset2) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
const ImageOperands operands(ctx, offset, offset2);
|
||||
if (ctx.profile.need_gather_subpixel_offset) {
|
||||
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords);
|
||||
@@ -542,6 +591,7 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id
|
||||
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
const IR::Value& offset, const IR::Value& offset2, Id dref) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
const ImageOperands operands(ctx, offset, offset2);
|
||||
if (ctx.profile.need_gather_subpixel_offset) {
|
||||
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords);
|
||||
@@ -554,6 +604,7 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
|
||||
Id lod, Id ms) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
AddOffsetToCoordinates(ctx, info, coords, offset);
|
||||
if (info.type == TextureType::Buffer) {
|
||||
lod = Id{};
|
||||
@@ -580,9 +631,20 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
|
||||
return uses_lod ? ctx.OpImageQuerySizeLod(type, image, lod)
|
||||
: ctx.OpImageQuerySize(type, image);
|
||||
}};
|
||||
|
||||
// Mobile GPUs: 1D textures emulated as 2D, query returns vec2 instead of scalar
|
||||
const bool emulate_1d = ctx.profile.needs_1d_texture_emulation;
|
||||
|
||||
switch (info.type) {
|
||||
case TextureType::Color1D:
|
||||
return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips());
|
||||
if (emulate_1d) {
|
||||
// Query as 2D, extract only X component for 1D size
|
||||
const Id size_2d = query(ctx.U32[2]);
|
||||
const Id width = ctx.OpCompositeExtract(ctx.U32[1], size_2d, 0);
|
||||
return ctx.OpCompositeConstruct(ctx.U32[4], width, zero, zero, mips());
|
||||
} else {
|
||||
return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips());
|
||||
}
|
||||
case TextureType::ColorArray1D:
|
||||
case TextureType::Color2D:
|
||||
case TextureType::ColorCube:
|
||||
@@ -600,6 +662,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
|
||||
|
||||
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
const Id zero{ctx.f32_zero_value};
|
||||
const Id sampler{Texture(ctx, info, index)};
|
||||
return ctx.OpCompositeConstruct(ctx.F32[4], ctx.OpImageQueryLod(ctx.F32[2], sampler, coords),
|
||||
@@ -609,6 +672,7 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
|
||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id derivatives, const IR::Value& offset, Id lod_clamp) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
const auto operands = info.num_derivatives == 3
|
||||
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
|
||||
ctx.Def(offset), {}, lod_clamp)
|
||||
@@ -621,6 +685,7 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
|
||||
|
||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
if (info.image_format == ImageFormat::Typeless && !ctx.profile.support_typeless_image_loads) {
|
||||
LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host");
|
||||
return ctx.ConstantNull(ctx.U32[4]);
|
||||
@@ -637,6 +702,7 @@ Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id co
|
||||
|
||||
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
coords = AdjustCoordinatesForEmulation(ctx, info, coords);
|
||||
const auto [image, is_integer] = Image(ctx, index, info);
|
||||
if (!is_integer) {
|
||||
color = ctx.OpBitcast(ctx.F32[4], color);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
||||
@@ -33,11 +33,24 @@ Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
|
||||
const Id type{ctx.F32[1]};
|
||||
const bool depth{desc.is_depth};
|
||||
const bool ms{desc.is_multisample};
|
||||
|
||||
// Mobile GPUs lack Sampled1D SPIR-V capability - emulate 1D as 2D with array layer
|
||||
const bool emulate_1d = ctx.profile.needs_1d_texture_emulation;
|
||||
|
||||
// Debug log for 1D emulation
|
||||
if (desc.type == TextureType::Color1D || desc.type == TextureType::ColorArray1D) {
|
||||
LOG_WARNING(Shader_SPIRV, "ImageType(texture): Creating {} texture, emulate_1d={}",
|
||||
desc.type == TextureType::Color1D ? "Color1D" : "ColorArray1D",
|
||||
emulate_1d);
|
||||
}
|
||||
|
||||
switch (desc.type) {
|
||||
case TextureType::Color1D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format);
|
||||
return emulate_1d ? ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, false, 1, format)
|
||||
: ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format);
|
||||
case TextureType::ColorArray1D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format);
|
||||
return emulate_1d ? ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, false, 1, format)
|
||||
: ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format);
|
||||
case TextureType::Color2D:
|
||||
case TextureType::Color2DRect:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, ms, 1, format);
|
||||
@@ -79,11 +92,22 @@ spv::ImageFormat GetImageFormat(ImageFormat format) {
|
||||
|
||||
Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) {
|
||||
const spv::ImageFormat format{GetImageFormat(desc.format)};
|
||||
const bool emulate_1d = ctx.profile.needs_1d_texture_emulation;
|
||||
|
||||
// Debug log for 1D emulation
|
||||
if (desc.type == TextureType::Color1D || desc.type == TextureType::ColorArray1D) {
|
||||
LOG_WARNING(Shader_SPIRV, "ImageType: Creating {} image, emulate_1d={}",
|
||||
desc.type == TextureType::Color1D ? "Color1D" : "ColorArray1D",
|
||||
emulate_1d);
|
||||
}
|
||||
|
||||
switch (desc.type) {
|
||||
case TextureType::Color1D:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, 2, format);
|
||||
return emulate_1d ? ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, 2, format)
|
||||
: ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, 2, format);
|
||||
case TextureType::ColorArray1D:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, true, false, 2, format);
|
||||
return emulate_1d ? ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, true, false, 2, format)
|
||||
: ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, true, false, 2, format);
|
||||
case TextureType::Color2D:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, 2, format);
|
||||
case TextureType::ColorArray2D:
|
||||
@@ -178,6 +202,9 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invo
|
||||
ctx.Decorate(id, spv::Decoration::XfbBuffer, xfb_varying->buffer);
|
||||
ctx.Decorate(id, spv::Decoration::XfbStride, xfb_varying->stride);
|
||||
ctx.Decorate(id, spv::Decoration::Offset, xfb_varying->offset);
|
||||
if (ctx.stage == Stage::Geometry && xfb_varying->stream != 0) {
|
||||
ctx.Decorate(id, spv::Decoration::Stream, xfb_varying->stream);
|
||||
}
|
||||
}
|
||||
if (num_components < 4 || element > 0) {
|
||||
const std::string_view subswizzle{swizzle.substr(element, num_components)};
|
||||
@@ -1441,6 +1468,8 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
||||
subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR);
|
||||
subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR);
|
||||
subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR);
|
||||
|
||||
// Vulkan spec: Fragment shader Input variables with integer/float type must have Flat decoration
|
||||
if (stage == Stage::Fragment) {
|
||||
Decorate(subgroup_mask_eq, spv::Decoration::Flat);
|
||||
Decorate(subgroup_mask_lt, spv::Decoration::Flat);
|
||||
|
||||
@@ -979,7 +979,7 @@ private:
|
||||
Environment& env;
|
||||
IR::AbstractSyntaxList& syntax_list;
|
||||
bool uses_demote_to_helper{};
|
||||
const Flow::Block dummy_flow_block;
|
||||
const Flow::Block dummy_flow_block{};
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -293,6 +296,14 @@ std::optional<LowAddrInfo> TrackLowAddress(IR::Inst* inst) {
|
||||
}
|
||||
// This address is expected to either be a PackUint2x32, a IAdd64, or a CompositeConstructU32x2
|
||||
IR::Inst* addr_inst{addr.InstRecursive()};
|
||||
// Unwrap Identity ops introduced by lowerings (e.g., PackUint2x32 -> Identity)
|
||||
while (addr_inst->GetOpcode() == IR::Opcode::Identity) {
|
||||
const IR::Value id_arg{addr_inst->Arg(0)};
|
||||
if (id_arg.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = id_arg.InstRecursive();
|
||||
}
|
||||
s32 imm_offset{0};
|
||||
if (addr_inst->GetOpcode() == IR::Opcode::IAdd64) {
|
||||
// If it's an IAdd64, get the immediate offset it is applying and grab the address
|
||||
@@ -308,6 +319,14 @@ std::optional<LowAddrInfo> TrackLowAddress(IR::Inst* inst) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = iadd_addr.InstRecursive();
|
||||
// Unwrap Identity again if present after folding IAdd64
|
||||
while (addr_inst->GetOpcode() == IR::Opcode::Identity) {
|
||||
const IR::Value id_arg{addr_inst->Arg(0)};
|
||||
if (id_arg.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = id_arg.InstRecursive();
|
||||
}
|
||||
}
|
||||
// With IAdd64 handled, now PackUint2x32 is expected
|
||||
if (addr_inst->GetOpcode() == IR::Opcode::PackUint2x32) {
|
||||
@@ -317,6 +336,14 @@ std::optional<LowAddrInfo> TrackLowAddress(IR::Inst* inst) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = vector.InstRecursive();
|
||||
// Unwrap Identity that may replace PackUint2x32
|
||||
while (addr_inst->GetOpcode() == IR::Opcode::Identity) {
|
||||
const IR::Value id_arg{addr_inst->Arg(0)};
|
||||
if (id_arg.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = id_arg.InstRecursive();
|
||||
}
|
||||
}
|
||||
// The vector is expected to be a CompositeConstructU32x2
|
||||
if (addr_inst->GetOpcode() != IR::Opcode::CompositeConstructU32x2) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -25,6 +28,14 @@ struct Profile {
|
||||
bool support_fp16_signed_zero_nan_preserve{};
|
||||
bool support_fp32_signed_zero_nan_preserve{};
|
||||
bool support_fp64_signed_zero_nan_preserve{};
|
||||
|
||||
// User-forced float behavior overrides (Android Eden Veil/Extensions)
|
||||
// When shader_float_controls_force_enable is true, these override shader-declared behavior
|
||||
bool force_fp32_denorm_flush{}; // Force FTZ for all FP32 ops
|
||||
bool force_fp32_denorm_preserve{}; // Force denorm preservation for all FP32 ops
|
||||
bool force_fp32_rte_rounding{}; // Force Round-To-Even for all FP32 ops
|
||||
bool force_fp32_signed_zero_inf_nan{}; // Force signed zero/inf/nan preservation
|
||||
|
||||
bool support_explicit_workgroup_layout{};
|
||||
bool support_vote{};
|
||||
bool support_viewport_index_layer_non_geometry{};
|
||||
@@ -38,6 +49,9 @@ struct Profile {
|
||||
bool support_gl_nv_gpu_shader_5{};
|
||||
bool support_gl_amd_gpu_shader_half_float{};
|
||||
bool support_gl_texture_shadow_lod{};
|
||||
bool support_gl_shader_atomic_float{};
|
||||
bool support_gl_shader_atomic_fp16_vector{};
|
||||
bool support_gl_shader_atomic_int64{};
|
||||
bool support_gl_warp_intrinsics{};
|
||||
bool support_gl_variable_aoffi{};
|
||||
bool support_gl_sparse_textures{};
|
||||
@@ -81,6 +95,8 @@ struct Profile {
|
||||
bool ignore_nan_fp_comparisons{};
|
||||
/// Some drivers have broken support for OpVectorExtractDynamic on subgroup mask inputs
|
||||
bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{};
|
||||
/// Mobile GPUs lack Sampled1D capability - need to emulate 1D textures as 2D with height=1
|
||||
bool needs_1d_texture_emulation{};
|
||||
|
||||
u32 gl_max_compute_smem_size{};
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ enum class TessSpacing {
|
||||
|
||||
struct TransformFeedbackVarying {
|
||||
u32 buffer{};
|
||||
u32 stream{};
|
||||
u32 stride{};
|
||||
u32 offset{};
|
||||
u32 components{};
|
||||
|
||||
@@ -133,7 +133,7 @@ enum class TexturePixelFormat {
|
||||
ASTC_2D_8X6_SRGB,
|
||||
ASTC_2D_6X5_UNORM,
|
||||
ASTC_2D_6X5_SRGB,
|
||||
E5B9G9R9_FLOAT,
|
||||
|
||||
D32_FLOAT,
|
||||
D16_UNORM,
|
||||
X8_D24_UNORM,
|
||||
|
||||
@@ -1067,26 +1067,29 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
|
||||
HostBindings<typename P::Buffer> host_bindings;
|
||||
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
|
||||
const Binding& binding = channel_state->transform_feedback_buffers[index];
|
||||
if (maxwell3d->regs.transform_feedback.controls[index].varying_count == 0 &&
|
||||
maxwell3d->regs.transform_feedback.controls[index].stride == 0) {
|
||||
break;
|
||||
const auto& control = maxwell3d->regs.transform_feedback.controls[index];
|
||||
const bool has_layout = control.varying_count != 0 || control.stride != 0;
|
||||
|
||||
Buffer* host_buffer = &slot_buffers[NULL_BUFFER_ID];
|
||||
u32 offset = 0;
|
||||
u32 size = 0;
|
||||
|
||||
if (has_layout && binding.buffer_id != NULL_BUFFER_ID && binding.size != 0) {
|
||||
Buffer& buffer = slot_buffers[binding.buffer_id];
|
||||
TouchBuffer(buffer, binding.buffer_id);
|
||||
size = binding.size;
|
||||
SynchronizeBuffer(buffer, binding.device_addr, size);
|
||||
MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
|
||||
offset = buffer.Offset(binding.device_addr);
|
||||
buffer.MarkUsage(offset, size);
|
||||
host_buffer = &buffer;
|
||||
}
|
||||
Buffer& buffer = slot_buffers[binding.buffer_id];
|
||||
TouchBuffer(buffer, binding.buffer_id);
|
||||
const u32 size = binding.size;
|
||||
SynchronizeBuffer(buffer, binding.device_addr, size);
|
||||
|
||||
MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
|
||||
|
||||
const u32 offset = buffer.Offset(binding.device_addr);
|
||||
buffer.MarkUsage(offset, size);
|
||||
host_bindings.buffers.push_back(&buffer);
|
||||
host_bindings.buffers.push_back(host_buffer);
|
||||
host_bindings.offsets.push_back(offset);
|
||||
host_bindings.sizes.push_back(size);
|
||||
}
|
||||
if (host_bindings.buffers.size() > 0) {
|
||||
runtime.BindTransformFeedbackBuffers(host_bindings);
|
||||
}
|
||||
runtime.BindTransformFeedbackBuffers(host_bindings);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -42,7 +45,7 @@ constexpr std::array VIEW_CLASS_32_BITS{
|
||||
PixelFormat::A2B10G10R10_UNORM, PixelFormat::R16G16_UINT, PixelFormat::R32_UINT,
|
||||
PixelFormat::R16G16_SINT, PixelFormat::R32_SINT, PixelFormat::A8B8G8R8_UNORM,
|
||||
PixelFormat::R16G16_UNORM, PixelFormat::A8B8G8R8_SNORM, PixelFormat::R16G16_SNORM,
|
||||
PixelFormat::A8B8G8R8_SRGB, PixelFormat::E5B9G9R9_FLOAT, PixelFormat::B8G8R8A8_UNORM,
|
||||
PixelFormat::A8B8G8R8_SRGB, PixelFormat::B8G8R8A8_UNORM,
|
||||
PixelFormat::B8G8R8A8_SRGB, PixelFormat::A8B8G8R8_UINT, PixelFormat::A8B8G8R8_SINT,
|
||||
PixelFormat::A2B10G10R10_UINT,
|
||||
};
|
||||
@@ -52,7 +55,7 @@ constexpr std::array VIEW_CLASS_32_BITS_NO_BGR{
|
||||
PixelFormat::A2B10G10R10_UNORM, PixelFormat::R16G16_UINT, PixelFormat::R32_UINT,
|
||||
PixelFormat::R16G16_SINT, PixelFormat::R32_SINT, PixelFormat::A8B8G8R8_UNORM,
|
||||
PixelFormat::R16G16_UNORM, PixelFormat::A8B8G8R8_SNORM, PixelFormat::R16G16_SNORM,
|
||||
PixelFormat::A8B8G8R8_SRGB, PixelFormat::E5B9G9R9_FLOAT, PixelFormat::A8B8G8R8_UINT,
|
||||
PixelFormat::A8B8G8R8_SRGB, PixelFormat::A8B8G8R8_UINT,
|
||||
PixelFormat::A8B8G8R8_SINT, PixelFormat::A2B10G10R10_UINT,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -92,7 +92,16 @@ void ThreadManager::InvalidateRegion(DAddr addr, u64 size) {
|
||||
}
|
||||
|
||||
void ThreadManager::FlushAndInvalidateRegion(DAddr addr, u64 size) {
|
||||
// Skip flush on asynch mode, as FlushAndInvalidateRegion is not used for anything too important
|
||||
if (Settings::IsGPULevelHigh()) {
|
||||
if (!is_async) {
|
||||
PushCommand(FlushRegionCommand(addr, size));
|
||||
} else {
|
||||
auto& gpu = system.GPU();
|
||||
const u64 fence = gpu.RequestFlush(addr, size);
|
||||
TickGPU();
|
||||
gpu.WaitForSyncOperation(fence);
|
||||
}
|
||||
}
|
||||
rasterizer->OnCacheInvalidation(addr, size);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -5,16 +8,22 @@
|
||||
|
||||
layout(local_size_x = 1) in;
|
||||
|
||||
layout(std430, binding = 0) buffer Query {
|
||||
uvec2 initial;
|
||||
uvec2 unknown;
|
||||
uvec2 current;
|
||||
layout(std430, binding = 0) readonly buffer Query {
|
||||
uint data[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) buffer Result {
|
||||
layout(std430, binding = 1) writeonly buffer Result {
|
||||
uint result;
|
||||
};
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
uint compare_to_zero;
|
||||
};
|
||||
|
||||
void main() {
|
||||
result = all(equal(initial, current)) ? 1 : 0;
|
||||
if (compare_to_zero != 0u) {
|
||||
result = (data[0] != 0u && data[1] != 0u) ? 1u : 0u;
|
||||
} else {
|
||||
result = (data[0] == data[4] && data[1] == data[5]) ? 1u : 0u;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#version 450
|
||||
|
||||
// VK_QCOM_render_pass_shader_resolve fragment shader
|
||||
// Resolves MSAA attachment to single-sample within render pass
|
||||
// Requires VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM in subpass flags
|
||||
|
||||
// Use combined image sampler for MSAA texture instead of input attachment
|
||||
// This allows us to sample MSAA textures from previous rendering
|
||||
layout(set = 0, binding = 0) uniform sampler2DMS msaa_texture;
|
||||
|
||||
layout(location = 0) out vec4 color_output;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec2 tex_scale;
|
||||
vec2 tex_offset;
|
||||
} push_constants;
|
||||
|
||||
// Custom MSAA resolve using box filter (simple average)
|
||||
// Assumes 4x MSAA (can be extended with push constant for dynamic sample count)
|
||||
void main() {
|
||||
ivec2 coord = ivec2(gl_FragCoord.xy);
|
||||
ivec2 tex_size = textureSize(msaa_texture);
|
||||
|
||||
// Clamp coordinates to texture bounds
|
||||
coord = clamp(coord, ivec2(0), tex_size - ivec2(1));
|
||||
|
||||
vec4 accumulated_color = vec4(0.0);
|
||||
int sample_count = 4; // Adreno typically uses 4x MSAA max
|
||||
|
||||
// Box filter: simple average of all MSAA samples
|
||||
for (int i = 0; i < sample_count; i++) {
|
||||
accumulated_color += texelFetch(msaa_texture, coord, i);
|
||||
}
|
||||
|
||||
color_output = accumulated_color / float(sample_count);
|
||||
}
|
||||
@@ -285,11 +285,11 @@ void HLE_MultiDrawIndexedIndirectCount::Fallback(Engines::Maxwell3D& maxwell3d,
|
||||
}
|
||||
void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
|
||||
const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback();
|
||||
auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[0] & 0xFFFFU);
|
||||
if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) {
|
||||
if (!force) {
|
||||
Fallback(maxwell3d, parameters);
|
||||
return;
|
||||
}
|
||||
auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[0] & 0xFFFFU);
|
||||
auto& params = maxwell3d.draw_manager->GetIndirectParams();
|
||||
params.is_byte_count = true;
|
||||
params.is_indexed = false;
|
||||
|
||||
@@ -412,6 +412,7 @@ bool QueryCacheBase<Traits>::AccelerateHostConditionalRendering() {
|
||||
.found_query = nullptr,
|
||||
};
|
||||
}
|
||||
it_current = it_current_2;
|
||||
}
|
||||
auto* query = impl->ObtainQuery(it_current->second);
|
||||
qc_dirty |= True(query->flags & QueryFlagBits::IsHostManaged) &&
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -75,7 +78,7 @@ public:
|
||||
}
|
||||
|
||||
u64 GetDependentMask() const {
|
||||
return dependence_mask;
|
||||
return dependent_mask;
|
||||
}
|
||||
|
||||
u64 GetAmendValue() const {
|
||||
|
||||
@@ -225,6 +225,9 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
|
||||
has_amd_shader_half_float = GLAD_GL_AMD_gpu_shader_half_float;
|
||||
has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2;
|
||||
has_draw_texture = GLAD_GL_NV_draw_texture;
|
||||
has_shader_atomic_float = GLAD_GL_NV_shader_atomic_float;
|
||||
has_shader_atomic_fp16_vector = GLAD_GL_NV_shader_atomic_fp16_vector;
|
||||
has_shader_atomic_int64 = GLAD_GL_NV_shader_atomic_int64;
|
||||
warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel;
|
||||
need_fastmath_off = is_nvidia;
|
||||
can_report_memory = GLAD_GL_NVX_gpu_memory_info;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -151,6 +151,18 @@ public:
|
||||
return has_draw_texture;
|
||||
}
|
||||
|
||||
bool HasShaderAtomicFloat() const {
|
||||
return has_shader_atomic_float;
|
||||
}
|
||||
|
||||
bool HasShaderAtomicFp16Vector() const {
|
||||
return has_shader_atomic_fp16_vector;
|
||||
}
|
||||
|
||||
bool HasShaderAtomicInt64() const {
|
||||
return has_shader_atomic_int64;
|
||||
}
|
||||
|
||||
bool IsWarpSizePotentiallyLargerThanGuest() const {
|
||||
return warp_size_potentially_larger_than_guest;
|
||||
}
|
||||
@@ -228,6 +240,9 @@ private:
|
||||
bool has_amd_shader_half_float{};
|
||||
bool has_sparse_texture_2{};
|
||||
bool has_draw_texture{};
|
||||
bool has_shader_atomic_float{};
|
||||
bool has_shader_atomic_fp16_vector{};
|
||||
bool has_shader_atomic_int64{};
|
||||
bool warp_size_potentially_larger_than_guest{};
|
||||
bool need_fastmath_off{};
|
||||
bool has_cbuf_ftou_bug{};
|
||||
|
||||
@@ -629,6 +629,9 @@ void RasterizerOpenGL::ReleaseFences(bool force) {
|
||||
|
||||
void RasterizerOpenGL::FlushAndInvalidateRegion(DAddr addr, u64 size,
|
||||
VideoCommon::CacheType which) {
|
||||
if (Settings::IsGPULevelHigh()) {
|
||||
FlushRegion(addr, size, which);
|
||||
}
|
||||
InvalidateRegion(addr, size, which);
|
||||
}
|
||||
|
||||
|
||||
@@ -181,7 +181,6 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
state_tracker{state_tracker_}, shader_notify{shader_notify_},
|
||||
use_asynchronous_shaders{device.UseAsynchronousShaders()},
|
||||
strict_context_required{device.StrictContextRequired()},
|
||||
optimize_spirv_output{Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Never},
|
||||
profile{
|
||||
.supported_spirv = 0x00010000,
|
||||
|
||||
@@ -215,6 +214,9 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
.support_gl_nv_gpu_shader_5 = device.HasNvGpuShader5(),
|
||||
.support_gl_amd_gpu_shader_half_float = device.HasAmdShaderHalfFloat(),
|
||||
.support_gl_texture_shadow_lod = device.HasTextureShadowLod(),
|
||||
.support_gl_shader_atomic_float = device.HasShaderAtomicFloat(),
|
||||
.support_gl_shader_atomic_fp16_vector = device.HasShaderAtomicFp16Vector(),
|
||||
.support_gl_shader_atomic_int64 = device.HasShaderAtomicInt64(),
|
||||
.support_gl_warp_intrinsics = false,
|
||||
.support_gl_variable_aoffi = device.HasVariableAoffi(),
|
||||
.support_gl_sparse_textures = device.HasSparseTexture2(),
|
||||
@@ -348,10 +350,6 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
|
||||
if (!use_asynchronous_shaders) {
|
||||
workers.reset();
|
||||
}
|
||||
|
||||
if (Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Always) {
|
||||
this->optimize_spirv_output = false;
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() {
|
||||
@@ -537,7 +535,7 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||
break;
|
||||
case Settings::RendererBackend::OpenGL_SPIRV:
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output);
|
||||
sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@@ -598,7 +596,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||
code = EmitGLASM(profile, info, program);
|
||||
break;
|
||||
case Settings::RendererBackend::OpenGL_SPIRV:
|
||||
code_spirv = EmitSPIRV(profile, program, this->optimize_spirv_output);
|
||||
code_spirv = EmitSPIRV(profile, program);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
||||
@@ -76,7 +76,6 @@ private:
|
||||
VideoCore::ShaderNotify& shader_notify;
|
||||
const bool use_asynchronous_shaders;
|
||||
const bool strict_context_required;
|
||||
bool optimize_spirv_output{};
|
||||
|
||||
GraphicsPipelineKey graphics_key{};
|
||||
GraphicsPipeline* current_pipeline{};
|
||||
|
||||
@@ -100,6 +100,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CanDownloadMSAA() const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
|
||||
|
||||
void CopyImageMSAA(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
|
||||
|
||||
@@ -190,9 +190,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!extended_dynamic_state_3_enables) {
|
||||
dynamic_state.Refresh3(regs);
|
||||
}
|
||||
dynamic_state.Refresh3(regs, features);
|
||||
if (xfb_enabled) {
|
||||
RefreshXfbState(xfb_state, regs);
|
||||
}
|
||||
@@ -295,16 +293,22 @@ void FixedPipelineState::DynamicState::Refresh2(const Maxwell& regs,
|
||||
depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
void FixedPipelineState::DynamicState::Refresh3(const Maxwell& regs) {
|
||||
logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
|
||||
depth_clamp_disabled.Assign(regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::Passthrough ||
|
||||
regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::FrustumXYZ ||
|
||||
regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::FrustumZ);
|
||||
|
||||
line_stipple_enable.Assign(regs.line_stipple_enable);
|
||||
void FixedPipelineState::DynamicState::Refresh3(const Maxwell& regs,
|
||||
const DynamicFeatures& features) {
|
||||
if (!features.has_dynamic_state3_logic_op_enable) {
|
||||
logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
|
||||
}
|
||||
if (!features.has_dynamic_state3_depth_clamp_enable) {
|
||||
depth_clamp_disabled.Assign(regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::Passthrough ||
|
||||
regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::FrustumXYZ ||
|
||||
regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::FrustumZ);
|
||||
}
|
||||
if (!features.has_dynamic_state3_line_stipple_enable) {
|
||||
line_stipple_enable.Assign(regs.line_stipple_enable);
|
||||
}
|
||||
}
|
||||
|
||||
size_t FixedPipelineState::Hash() const noexcept {
|
||||
|
||||
@@ -27,6 +27,9 @@ struct DynamicFeatures {
|
||||
bool has_extended_dynamic_state_2_patch_control_points;
|
||||
bool has_extended_dynamic_state_3_blend;
|
||||
bool has_extended_dynamic_state_3_enables;
|
||||
bool has_dynamic_state3_depth_clamp_enable;
|
||||
bool has_dynamic_state3_logic_op_enable;
|
||||
bool has_dynamic_state3_line_stipple_enable;
|
||||
bool has_dynamic_vertex_input;
|
||||
bool has_provoking_vertex;
|
||||
bool has_provoking_vertex_first_mode;
|
||||
@@ -175,7 +178,7 @@ struct FixedPipelineState {
|
||||
void Refresh(const Maxwell& regs);
|
||||
void Refresh2(const Maxwell& regs, Maxwell::PrimitiveTopology topology,
|
||||
bool base_features_supported);
|
||||
void Refresh3(const Maxwell& regs);
|
||||
void Refresh3(const Maxwell& regs, const DynamicFeatures& features);
|
||||
|
||||
Maxwell::ComparisonOp DepthTestFunc() const noexcept {
|
||||
return UnpackComparisonOp(depth_test_func);
|
||||
@@ -192,7 +195,10 @@ struct FixedPipelineState {
|
||||
|
||||
union {
|
||||
u32 raw1;
|
||||
// EDS1 - Bit 0
|
||||
BitField<0, 1, u32> extended_dynamic_state;
|
||||
|
||||
// EDS2 - Bits 1-3
|
||||
BitField<1, 1, u32> extended_dynamic_state_2;
|
||||
BitField<2, 1, u32> extended_dynamic_state_2_logic_op;
|
||||
BitField<3, 1, u32> extended_dynamic_state_3_blend;
|
||||
@@ -206,9 +212,32 @@ struct FixedPipelineState {
|
||||
BitField<14, 1, u32> tessellation_clockwise;
|
||||
BitField<15, 5, u32> patch_control_points_minus_one;
|
||||
|
||||
// Topology and MSAA - Bits 24-31
|
||||
BitField<24, 4, Maxwell::PrimitiveTopology> topology;
|
||||
BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode;
|
||||
};
|
||||
|
||||
union {
|
||||
u32 raw1_eds3_extended;
|
||||
// EDS3 Additional Features - Bits 0-15
|
||||
BitField<0, 1, u32> extended_dynamic_state_3_depth_clamp;
|
||||
BitField<1, 1, u32> extended_dynamic_state_3_logic_op_enable;
|
||||
BitField<2, 1, u32> extended_dynamic_state_3_tessellation_domain_origin;
|
||||
BitField<3, 1, u32> extended_dynamic_state_3_polygon_mode;
|
||||
BitField<4, 1, u32> extended_dynamic_state_3_rasterization_samples;
|
||||
BitField<5, 1, u32> extended_dynamic_state_3_sample_mask;
|
||||
BitField<6, 1, u32> extended_dynamic_state_3_alpha_to_coverage_enable;
|
||||
BitField<7, 1, u32> extended_dynamic_state_3_alpha_to_one_enable;
|
||||
BitField<8, 1, u32> extended_dynamic_state_3_depth_clip_enable;
|
||||
BitField<9, 1, u32> extended_dynamic_state_3_depth_clip_negative_one_to_one;
|
||||
BitField<10, 1, u32> extended_dynamic_state_3_line_rasterization_mode;
|
||||
BitField<11, 1, u32> extended_dynamic_state_3_line_stipple_enable;
|
||||
BitField<12, 1, u32> extended_dynamic_state_3_provoking_vertex_mode;
|
||||
BitField<13, 1, u32> extended_dynamic_state_3_conservative_rasterization_mode;
|
||||
BitField<14, 1, u32> extended_dynamic_state_3_sample_locations_enable;
|
||||
BitField<15, 1, u32> extended_dynamic_state_3_rasterization_stream;
|
||||
};
|
||||
|
||||
union {
|
||||
u32 raw2;
|
||||
BitField<1, 3, u32> alpha_test_func;
|
||||
@@ -223,12 +252,15 @@ struct FixedPipelineState {
|
||||
BitField<16, 1, u32> alpha_to_one_enabled;
|
||||
BitField<17, 3, Tegra::Engines::Maxwell3D::EngineHint> app_stage;
|
||||
};
|
||||
std::array<u8, Maxwell::NumRenderTargets> color_formats;
|
||||
|
||||
u32 alpha_test_ref;
|
||||
u32 point_size;
|
||||
|
||||
std::array<u8, Maxwell::NumRenderTargets> color_formats;
|
||||
std::array<u16, Maxwell::NumViewports> viewport_swizzles;
|
||||
|
||||
u32 pad_align_u64;
|
||||
|
||||
union {
|
||||
u64 attribute_types; // Used with VK_EXT_vertex_input_dynamic_state
|
||||
u64 enabled_divisors;
|
||||
@@ -265,8 +297,7 @@ struct FixedPipelineState {
|
||||
return sizeof(*this);
|
||||
}
|
||||
if (dynamic_vertex_input && extended_dynamic_state_3_blend) {
|
||||
// Exclude dynamic state and attributes
|
||||
return offsetof(FixedPipelineState, dynamic_state);
|
||||
return offsetof(FixedPipelineState, attachments);
|
||||
}
|
||||
if (dynamic_vertex_input) {
|
||||
// Exclude dynamic state
|
||||
|
||||
@@ -27,8 +27,13 @@ public:
|
||||
DescriptorLayoutBuilder(const Device& device_) : device{&device_} {}
|
||||
|
||||
bool CanUsePushDescriptor() const noexcept {
|
||||
return device->IsKhrPushDescriptorSupported() &&
|
||||
num_descriptors <= device->MaxPushDescriptors();
|
||||
if (!device->IsKhrPushDescriptorSupported()) {
|
||||
return false;
|
||||
}
|
||||
if (num_descriptors > device->MaxPushDescriptors()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(crueter): utilize layout binding flags
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include <ranges>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include "video_core/vulkan_common/vulkan.h"
|
||||
#include "video_core/renderer_vulkan/present/util.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -171,7 +172,11 @@ try
|
||||
|
||||
RendererVulkan::~RendererVulkan() {
|
||||
scheduler.RegisterOnSubmit([] {});
|
||||
void(device.GetLogical().WaitIdle());
|
||||
scheduler.Finish();
|
||||
{
|
||||
std::scoped_lock lock{scheduler.submit_mutex};
|
||||
void(device.GetLogical().WaitIdle());
|
||||
}
|
||||
}
|
||||
|
||||
void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebuffers) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <mutex>
|
||||
#include "video_core/framebuffer_config.h"
|
||||
#include "video_core/present.h"
|
||||
#include "video_core/renderer_vulkan/present/filters.h"
|
||||
@@ -31,7 +32,10 @@ BlitScreen::~BlitScreen() = default;
|
||||
void BlitScreen::WaitIdle() {
|
||||
present_manager.WaitPresent();
|
||||
scheduler.Finish();
|
||||
device.GetLogical().WaitIdle();
|
||||
{
|
||||
std::scoped_lock lock{scheduler.submit_mutex};
|
||||
device.GetLogical().WaitIdle();
|
||||
}
|
||||
}
|
||||
|
||||
void BlitScreen::SetWindowAdaptPass() {
|
||||
|
||||
@@ -637,12 +637,10 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<
|
||||
for (u32 i = 0; i < bindings.buffers.size(); ++i) {
|
||||
auto handle = bindings.buffers[i]->Handle();
|
||||
if (handle == VK_NULL_HANDLE) {
|
||||
ReserveNullBuffer();
|
||||
handle = *null_buffer;
|
||||
bindings.offsets[i] = 0;
|
||||
bindings.sizes[i] = VK_WHOLE_SIZE;
|
||||
if (!device.HasNullDescriptor()) {
|
||||
ReserveNullBuffer();
|
||||
handle = *null_buffer;
|
||||
}
|
||||
bindings.sizes[i] = 0;
|
||||
}
|
||||
buffer_handles[i] = handle;
|
||||
}
|
||||
|
||||
@@ -228,6 +228,10 @@ struct QueriesPrefixScanPushConstants {
|
||||
u32 accumulation_limit;
|
||||
u32 buffer_offset;
|
||||
};
|
||||
|
||||
struct ConditionalRenderingResolvePushConstants {
|
||||
u32 compare_to_zero;
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool,
|
||||
@@ -413,7 +417,8 @@ ConditionalRenderingResolvePass::ConditionalRenderingResolvePass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||
: ComputePass(device_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
|
||||
INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, nullptr,
|
||||
INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(ConditionalRenderingResolvePushConstants)>,
|
||||
RESOLVE_CONDITIONAL_RENDER_COMP_SPV),
|
||||
scheduler{scheduler_}, compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||
|
||||
@@ -430,7 +435,7 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
|
||||
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([this, descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([this, descriptor_data, compare_to_zero](vk::CommandBuffer cmdbuf) {
|
||||
static constexpr VkMemoryBarrier read_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
@@ -443,6 +448,9 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT,
|
||||
};
|
||||
const ConditionalRenderingResolvePushConstants uniforms{
|
||||
.compare_to_zero = compare_to_zero ? 1U : 0U,
|
||||
};
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
|
||||
@@ -450,9 +458,11 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
|
||||
cmdbuf.Dispatch(1, 1, 1);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
|
||||
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT, 0,
|
||||
write_barrier);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -520,7 +530,7 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
|
||||
@@ -467,6 +467,10 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
bind_stage_info(4);
|
||||
}
|
||||
|
||||
if (regs.transform_feedback_enabled != 0) {
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
}
|
||||
|
||||
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
||||
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
||||
|
||||
@@ -844,13 +848,38 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
.pAttachments = cb_attachments.data(),
|
||||
.blendConstants = {}
|
||||
};
|
||||
static_vector<VkDynamicState, 34> dynamic_states{
|
||||
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
|
||||
VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
|
||||
VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
|
||||
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE,
|
||||
VK_DYNAMIC_STATE_LINE_WIDTH,
|
||||
};
|
||||
// Base Vulkan Dynamic States - Always active (independent of EDS)
|
||||
// Granular fallback: Each state added only if device supports it (protection against broken drivers)
|
||||
static_vector<VkDynamicState, 34> dynamic_states;
|
||||
if (device.SupportsDynamicViewport()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT);
|
||||
}
|
||||
if (device.SupportsDynamicScissor()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
|
||||
}
|
||||
if (device.SupportsDynamicLineWidth()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
|
||||
}
|
||||
if (device.SupportsDynamicDepthBias()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
|
||||
}
|
||||
if (device.SupportsDynamicBlendConstants()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
|
||||
}
|
||||
if (device.SupportsDynamicDepthBounds()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
|
||||
}
|
||||
if (device.SupportsDynamicStencilCompareMask()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
|
||||
}
|
||||
if (device.SupportsDynamicStencilWriteMask()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
|
||||
}
|
||||
if (device.SupportsDynamicStencilReference()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
|
||||
}
|
||||
|
||||
// EDS1 - Extended Dynamic State
|
||||
if (key.state.extended_dynamic_state) {
|
||||
static constexpr std::array extended{
|
||||
VK_DYNAMIC_STATE_CULL_MODE_EXT,
|
||||
|
||||
@@ -369,7 +369,6 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
texture_cache{texture_cache_}, shader_notify{shader_notify_},
|
||||
use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
|
||||
use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()},
|
||||
optimize_spirv_output{Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Never},
|
||||
workers(device.HasBrokenParallelShaderCompiling() ? 1ULL : GetTotalPipelineWorkers(),
|
||||
"VkPipelineBuilder"),
|
||||
serialization_thread(1, "VkPipelineSerialization") {
|
||||
@@ -398,6 +397,17 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
float_control.shaderSignedZeroInfNanPreserveFloat32 != VK_FALSE,
|
||||
.support_fp64_signed_zero_nan_preserve =
|
||||
float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
|
||||
|
||||
// Switch/Maxwell native float behavior - ONLY for Turnip Mesa (Stock Qualcomm broken)
|
||||
// Stock Adreno drivers have broken float controls disabled in vulkan_device.cpp
|
||||
.force_fp32_denorm_flush = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY &&
|
||||
device.IsKhrShaderFloatControlsSupported(), // false on Stock, true on Turnip
|
||||
.force_fp32_denorm_preserve = false, // FTZ dominates
|
||||
.force_fp32_rte_rounding = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY &&
|
||||
device.IsKhrShaderFloatControlsSupported(), // false on Stock, true on Turnip
|
||||
.force_fp32_signed_zero_inf_nan = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY &&
|
||||
device.IsKhrShaderFloatControlsSupported(), // false on Stock, true on Turnip
|
||||
|
||||
.support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
|
||||
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
|
||||
.support_viewport_index_layer_non_geometry =
|
||||
@@ -428,10 +438,17 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
.has_broken_spirv_position_input = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
|
||||
.has_broken_unsigned_image_offsets = false,
|
||||
.has_broken_signed_operations = false,
|
||||
.has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,
|
||||
.has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
|
||||
.ignore_nan_fp_comparisons = false,
|
||||
.has_broken_spirv_subgroup_mask_vector_extract_dynamic =
|
||||
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
|
||||
.needs_1d_texture_emulation =
|
||||
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_MESA_TURNIP ||
|
||||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_BROADCOM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_IMAGINATION_PROPRIETARY,
|
||||
.has_broken_robust =
|
||||
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal,
|
||||
.min_ssbo_alignment = device.GetStorageBufferAlignment(),
|
||||
@@ -485,6 +502,12 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
device.IsExtExtendedDynamicState3BlendingSupported();
|
||||
dynamic_features.has_extended_dynamic_state_3_enables =
|
||||
device.IsExtExtendedDynamicState3EnablesSupported();
|
||||
dynamic_features.has_dynamic_state3_depth_clamp_enable =
|
||||
device.SupportsDynamicState3DepthClampEnable();
|
||||
dynamic_features.has_dynamic_state3_logic_op_enable =
|
||||
device.SupportsDynamicState3LogicOpEnable();
|
||||
dynamic_features.has_dynamic_state3_line_stipple_enable =
|
||||
device.SupportsDynamicState3LineStippleEnable();
|
||||
|
||||
// VIDS: Independent toggle (not affected by dyna_state levels)
|
||||
dynamic_features.has_dynamic_vertex_input =
|
||||
@@ -663,10 +686,6 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
|
||||
if (state.statistics) {
|
||||
state.statistics->Report();
|
||||
}
|
||||
|
||||
if (Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Always) {
|
||||
this->optimize_spirv_output = false;
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() {
|
||||
@@ -771,7 +790,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
|
||||
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage, device)};
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output)};
|
||||
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)};
|
||||
device.SaveShader(code);
|
||||
modules[stage_index] = BuildShader(device, code);
|
||||
|
||||
@@ -889,7 +908,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
max_shared_memory / 1024);
|
||||
program.shared_memory_size = max_shared_memory;
|
||||
}
|
||||
const std::vector<u32> code{EmitSPIRV(profile, program, this->optimize_spirv_output)};
|
||||
const std::vector<u32> code{EmitSPIRV(profile, program)};
|
||||
device.SaveShader(code);
|
||||
vk::ShaderModule spv_module{BuildShader(device, code)};
|
||||
|
||||
|
||||
@@ -116,6 +116,10 @@ public:
|
||||
void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback);
|
||||
|
||||
[[nodiscard]] const DynamicFeatures& GetDynamicFeatures() const noexcept {
|
||||
return dynamic_features;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] GraphicsPipeline* CurrentGraphicsPipelineSlowPath();
|
||||
|
||||
@@ -153,7 +157,6 @@ private:
|
||||
VideoCore::ShaderNotify& shader_notify;
|
||||
bool use_asynchronous_shaders{};
|
||||
bool use_vulkan_pipeline_cache{};
|
||||
bool optimize_spirv_output{};
|
||||
|
||||
GraphicsPipelineCacheKey graphics_key{};
|
||||
GraphicsPipeline* current_pipeline{};
|
||||
|
||||
@@ -189,7 +189,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat
|
||||
frame->image = memory_allocator.CreateImage({
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
|
||||
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = swapchain.GetImageFormat(),
|
||||
.extent =
|
||||
|
||||
@@ -157,8 +157,9 @@ public:
|
||||
ReserveHostQuery();
|
||||
|
||||
scheduler.Record([query_pool = current_query_pool,
|
||||
query_index = current_bank_slot](vk::CommandBuffer cmdbuf) {
|
||||
query_index = current_bank_slot](vk::CommandBuffer cmdbuf) {
|
||||
const bool use_precise = Settings::IsGPULevelHigh();
|
||||
cmdbuf.ResetQueryPool(query_pool, static_cast<u32>(query_index), 1);
|
||||
cmdbuf.BeginQuery(query_pool, static_cast<u32>(query_index),
|
||||
use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0);
|
||||
});
|
||||
@@ -220,8 +221,7 @@ public:
|
||||
}
|
||||
PauseCounter();
|
||||
const auto driver_id = device.GetDriverID();
|
||||
if (driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) {
|
||||
if (driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) {
|
||||
pending_sync.clear();
|
||||
sync_values_stash.clear();
|
||||
return;
|
||||
@@ -666,13 +666,18 @@ public:
|
||||
offsets.fill(0);
|
||||
last_queries.fill(0);
|
||||
last_queries_stride.fill(1);
|
||||
stream_to_slot.fill(INVALID_SLOT);
|
||||
VkBufferUsageFlags counter_buffer_usage =
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
if (device.IsExtTransformFeedbackSupported()) {
|
||||
counter_buffer_usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT;
|
||||
}
|
||||
const VkBufferCreateInfo buffer_ci = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.size = TFBQueryBank::QUERY_SIZE * NUM_STREAMS,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT,
|
||||
.usage = counter_buffer_usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
@@ -692,6 +697,9 @@ public:
|
||||
~TFBCounterStreamer() = default;
|
||||
|
||||
void StartCounter() override {
|
||||
if (!device.IsExtTransformFeedbackSupported()) {
|
||||
return;
|
||||
}
|
||||
FlushBeginTFB();
|
||||
has_started = true;
|
||||
}
|
||||
@@ -706,7 +714,9 @@ public:
|
||||
|
||||
void CloseCounter() override {
|
||||
if (has_flushed_end_pending) {
|
||||
FlushEndTFB();
|
||||
if (scheduler.IsRenderPassActive()) {
|
||||
FlushEndTFB();
|
||||
}
|
||||
}
|
||||
runtime.View3DRegs([this](Maxwell3D& maxwell3d) {
|
||||
if (maxwell3d.regs.transform_feedback_enabled == 0) {
|
||||
@@ -756,18 +766,33 @@ public:
|
||||
if (has_timestamp) {
|
||||
new_query->flags |= VideoCommon::QueryFlagBits::HasTimestamp;
|
||||
}
|
||||
if (!device.IsExtTransformFeedbackSupported()) {
|
||||
new_query->flags |= VideoCommon::QueryFlagBits::IsFinalValueSynced;
|
||||
return index;
|
||||
}
|
||||
if (!subreport_) {
|
||||
new_query->flags |= VideoCommon::QueryFlagBits::IsFinalValueSynced;
|
||||
return index;
|
||||
}
|
||||
const size_t subreport = static_cast<size_t>(*subreport_);
|
||||
if (subreport >= NUM_STREAMS) {
|
||||
new_query->flags |= VideoCommon::QueryFlagBits::IsFinalValueSynced;
|
||||
return index;
|
||||
}
|
||||
last_queries[subreport] = address;
|
||||
if ((streams_mask & (1ULL << subreport)) == 0) {
|
||||
new_query->flags |= VideoCommon::QueryFlagBits::IsFinalValueSynced;
|
||||
return index;
|
||||
}
|
||||
const size_t slot = stream_to_slot[subreport];
|
||||
if (slot >= NUM_STREAMS) {
|
||||
new_query->flags |= VideoCommon::QueryFlagBits::IsFinalValueSynced;
|
||||
return index;
|
||||
}
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
CloseCounter();
|
||||
auto [bank_slot, data_slot] = ProduceCounterBuffer(subreport);
|
||||
auto [bank_slot, data_slot] = ProduceCounterBuffer(slot);
|
||||
new_query->start_bank_id = static_cast<u32>(bank_slot);
|
||||
new_query->size_banks = 1;
|
||||
new_query->start_slot = static_cast<u32>(data_slot);
|
||||
@@ -778,6 +803,9 @@ public:
|
||||
}
|
||||
|
||||
std::optional<std::pair<DAddr, size_t>> GetLastQueryStream(size_t stream) {
|
||||
if (stream >= NUM_STREAMS) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (last_queries[stream] != 0) {
|
||||
std::pair<DAddr, size_t> result(last_queries[stream], last_queries_stride[stream]);
|
||||
return result;
|
||||
@@ -789,6 +817,10 @@ public:
|
||||
return out_topology;
|
||||
}
|
||||
|
||||
u32 GetPatchVertices() const {
|
||||
return patch_vertices;
|
||||
}
|
||||
|
||||
bool HasUnsyncedQueries() const override {
|
||||
return !pending_flush_queries.empty();
|
||||
}
|
||||
@@ -855,6 +887,9 @@ public:
|
||||
|
||||
private:
|
||||
void FlushBeginTFB() {
|
||||
if (!device.IsExtTransformFeedbackSupported()) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
if (has_flushed_end_pending) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
@@ -868,12 +903,24 @@ private:
|
||||
});
|
||||
return;
|
||||
}
|
||||
static constexpr VkMemoryBarrier COUNTER_RESUME_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,
|
||||
};
|
||||
scheduler.Record([this, total = static_cast<u32>(buffers_count)](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
|
||||
VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, 0,
|
||||
COUNTER_RESUME_BARRIER);
|
||||
cmdbuf.BeginTransformFeedbackEXT(0, total, counter_buffers.data(), offsets.data());
|
||||
});
|
||||
}
|
||||
|
||||
void FlushEndTFB() {
|
||||
if (!device.IsExtTransformFeedbackSupported()) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
if (!has_flushed_end_pending) [[unlikely]] {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
@@ -899,28 +946,48 @@ private:
|
||||
void UpdateBuffers() {
|
||||
last_queries.fill(0);
|
||||
last_queries_stride.fill(1);
|
||||
stream_to_slot.fill(INVALID_SLOT);
|
||||
streams_mask = 0; // reset previously recorded streams
|
||||
runtime.View3DRegs([this](Maxwell3D& maxwell3d) {
|
||||
buffers_count = 0;
|
||||
out_topology = maxwell3d.draw_manager->GetDrawState().topology;
|
||||
patch_vertices = std::max(maxwell3d.regs.patch_vertices, 1U);
|
||||
if (out_topology == Maxwell3D::Regs::PrimitiveTopology::Patches) {
|
||||
switch (maxwell3d.regs.tessellation.params.output_primitives.Value()) {
|
||||
case Maxwell3D::Regs::Tessellation::OutputPrimitives::Points:
|
||||
out_topology = Maxwell3D::Regs::PrimitiveTopology::Points;
|
||||
break;
|
||||
case Maxwell3D::Regs::Tessellation::OutputPrimitives::Lines:
|
||||
out_topology = Maxwell3D::Regs::PrimitiveTopology::LineStrip;
|
||||
break;
|
||||
case Maxwell3D::Regs::Tessellation::OutputPrimitives::Triangles_CW:
|
||||
case Maxwell3D::Regs::Tessellation::OutputPrimitives::Triangles_CCW:
|
||||
out_topology = Maxwell3D::Regs::PrimitiveTopology::TriangleStrip;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < Maxwell3D::Regs::NumTransformFeedbackBuffers; i++) {
|
||||
const auto& tf = maxwell3d.regs.transform_feedback;
|
||||
if (tf.buffers[i].enable == 0) {
|
||||
continue;
|
||||
}
|
||||
buffers_count = std::max<size_t>(buffers_count, i + 1);
|
||||
const size_t stream = tf.controls[i].stream;
|
||||
if (stream >= last_queries_stride.size()) {
|
||||
LOG_WARNING(Render_Vulkan, "TransformFeedback stream {} out of range", stream);
|
||||
continue;
|
||||
}
|
||||
if ((streams_mask & (1ULL << stream)) != 0) {
|
||||
continue;
|
||||
}
|
||||
last_queries_stride[stream] = tf.controls[i].stride;
|
||||
stream_to_slot[stream] = i;
|
||||
streams_mask |= 1ULL << stream;
|
||||
buffers_count = std::max<size_t>(buffers_count, stream + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::pair<size_t, size_t> ProduceCounterBuffer(size_t stream) {
|
||||
std::pair<size_t, size_t> ProduceCounterBuffer(size_t slot_index) {
|
||||
if (current_bank == nullptr || current_bank->IsClosed()) {
|
||||
current_bank_id =
|
||||
bank_pool.ReserveBank([this](std::deque<TFBQueryBank>& queue, size_t index) {
|
||||
@@ -946,7 +1013,8 @@ private:
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([dst_buffer = current_bank->GetBuffer(),
|
||||
src_buffer = counter_buffers[stream], src_offset = offsets[stream],
|
||||
src_buffer = counter_buffers[slot_index],
|
||||
src_offset = offsets[slot_index],
|
||||
slot](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
|
||||
@@ -965,6 +1033,7 @@ private:
|
||||
friend class PrimitivesSucceededStreamer;
|
||||
|
||||
static constexpr size_t NUM_STREAMS = 4;
|
||||
static constexpr size_t INVALID_SLOT = NUM_STREAMS;
|
||||
|
||||
QueryCacheRuntime& runtime;
|
||||
const Device& device;
|
||||
@@ -994,7 +1063,9 @@ private:
|
||||
std::array<VkDeviceSize, NUM_STREAMS> offsets{};
|
||||
std::array<DAddr, NUM_STREAMS> last_queries;
|
||||
std::array<size_t, NUM_STREAMS> last_queries_stride;
|
||||
std::array<size_t, NUM_STREAMS> stream_to_slot;
|
||||
Maxwell3D::Regs::PrimitiveTopology out_topology;
|
||||
u32 patch_vertices{1};
|
||||
u64 streams_mask;
|
||||
};
|
||||
|
||||
@@ -1015,6 +1086,7 @@ public:
|
||||
u64 stride{};
|
||||
DAddr dependant_address{};
|
||||
Maxwell3D::Regs::PrimitiveTopology topology{Maxwell3D::Regs::PrimitiveTopology::Points};
|
||||
u32 patch_vertices{1};
|
||||
size_t dependant_index{};
|
||||
bool dependant_manage{};
|
||||
};
|
||||
@@ -1031,6 +1103,10 @@ public:
|
||||
|
||||
~PrimitivesSucceededStreamer() = default;
|
||||
|
||||
void ResetCounter() override {
|
||||
tfb_streamer.ResetCounter();
|
||||
}
|
||||
|
||||
size_t WriteCounter(DAddr address, bool has_timestamp, u32 value,
|
||||
std::optional<u32> subreport_) override {
|
||||
auto index = BuildQuery();
|
||||
@@ -1048,6 +1124,7 @@ public:
|
||||
auto dependant_address_opt = tfb_streamer.GetLastQueryStream(subreport);
|
||||
bool must_manage_dependance = false;
|
||||
new_query->topology = tfb_streamer.GetOutputTopology();
|
||||
new_query->patch_vertices = tfb_streamer.GetPatchVertices();
|
||||
if (dependant_address_opt) {
|
||||
auto [dep_address, stride] = *dependant_address_opt;
|
||||
new_query->dependant_address = dep_address;
|
||||
@@ -1068,6 +1145,7 @@ public:
|
||||
}
|
||||
new_query->stride = 1;
|
||||
runtime.View3DRegs([new_query, subreport](Maxwell3D& maxwell3d) {
|
||||
new_query->patch_vertices = std::max(maxwell3d.regs.patch_vertices, 1U);
|
||||
for (size_t i = 0; i < Maxwell3D::Regs::NumTransformFeedbackBuffers; i++) {
|
||||
const auto& tf = maxwell3d.regs.transform_feedback;
|
||||
if (tf.buffers[i].enable == 0) {
|
||||
@@ -1131,27 +1209,39 @@ public:
|
||||
}
|
||||
}
|
||||
query->value = [&]() -> u64 {
|
||||
const auto saturating_subtract = [](u64 value, u64 amount) {
|
||||
return value > amount ? value - amount : 0;
|
||||
};
|
||||
switch (query->topology) {
|
||||
case Maxwell3D::Regs::PrimitiveTopology::Points:
|
||||
return num_vertices;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::Lines:
|
||||
return num_vertices / 2;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::LineLoop:
|
||||
return (num_vertices / 2) + 1;
|
||||
return num_vertices > 1 ? num_vertices : 0;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::LineStrip:
|
||||
return num_vertices - 1;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::Patches:
|
||||
return saturating_subtract(num_vertices, 1);
|
||||
case Maxwell3D::Regs::PrimitiveTopology::LinesAdjacency:
|
||||
return num_vertices / 4;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::LineStripAdjacency:
|
||||
return saturating_subtract(num_vertices, 3);
|
||||
case Maxwell3D::Regs::PrimitiveTopology::Triangles:
|
||||
case Maxwell3D::Regs::PrimitiveTopology::TrianglesAdjacency:
|
||||
return num_vertices / 3;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::TrianglesAdjacency:
|
||||
return num_vertices / 6;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::TriangleFan:
|
||||
case Maxwell3D::Regs::PrimitiveTopology::TriangleStrip:
|
||||
return saturating_subtract(num_vertices, 2);
|
||||
case Maxwell3D::Regs::PrimitiveTopology::TriangleStripAdjacency:
|
||||
return num_vertices - 2;
|
||||
return num_vertices > 4 ? (num_vertices - 4) / 2 : 0;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::Quads:
|
||||
return num_vertices / 4;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::QuadStrip:
|
||||
return num_vertices > 2 ? (num_vertices - 2) / 2 : 0;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::Polygon:
|
||||
return 1U;
|
||||
return num_vertices >= 3 ? 1U : 0U;
|
||||
case Maxwell3D::Regs::PrimitiveTopology::Patches:
|
||||
return num_vertices / std::max<u64>(query->patch_vertices, 1U);
|
||||
default:
|
||||
return num_vertices;
|
||||
}
|
||||
@@ -1202,16 +1292,24 @@ struct QueryCacheRuntimeImpl {
|
||||
hcr_setup.pNext = nullptr;
|
||||
hcr_setup.flags = 0;
|
||||
|
||||
conditional_resolve_pass = std::make_unique<ConditionalRenderingResolvePass>(
|
||||
device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
|
||||
const bool has_conditional_rendering = device.IsExtConditionalRendering();
|
||||
if (has_conditional_rendering) {
|
||||
conditional_resolve_pass = std::make_unique<ConditionalRenderingResolvePass>(
|
||||
device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
|
||||
}
|
||||
|
||||
VkBufferUsageFlags hcr_buffer_usage =
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
if (has_conditional_rendering) {
|
||||
hcr_buffer_usage |= VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT;
|
||||
}
|
||||
|
||||
const VkBufferCreateInfo buffer_ci = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.size = sizeof(u32),
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT,
|
||||
.usage = hcr_buffer_usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
@@ -1338,15 +1436,17 @@ void QueryCacheRuntime::HostConditionalRenderingCompareValueImpl(VideoCommon::Lo
|
||||
}
|
||||
}
|
||||
|
||||
void QueryCacheRuntime::HostConditionalRenderingCompareBCImpl(DAddr address, bool is_equal) {
|
||||
void QueryCacheRuntime::HostConditionalRenderingCompareBCImpl(DAddr address, bool is_equal,
|
||||
bool compare_to_zero) {
|
||||
VkBuffer to_resolve;
|
||||
u32 to_resolve_offset;
|
||||
const u32 resolve_size = compare_to_zero ? 8 : 24;
|
||||
{
|
||||
std::scoped_lock lk(impl->buffer_cache.mutex);
|
||||
static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::NoSynchronize;
|
||||
const auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize;
|
||||
const auto post_op = VideoCommon::ObtainBufferOperation::DoNothing;
|
||||
const auto [buffer, offset] =
|
||||
impl->buffer_cache.ObtainCPUBuffer(address, 24, sync_info, post_op);
|
||||
impl->buffer_cache.ObtainCPUBuffer(address, resolve_size, sync_info, post_op);
|
||||
to_resolve = buffer->Handle();
|
||||
to_resolve_offset = static_cast<u32>(offset);
|
||||
}
|
||||
@@ -1355,7 +1455,7 @@ void QueryCacheRuntime::HostConditionalRenderingCompareBCImpl(DAddr address, boo
|
||||
PauseHostConditionalRendering();
|
||||
}
|
||||
impl->conditional_resolve_pass->Resolve(*impl->hcr_resolve_buffer, to_resolve,
|
||||
to_resolve_offset, false);
|
||||
to_resolve_offset, compare_to_zero);
|
||||
impl->hcr_setup.buffer = *impl->hcr_resolve_buffer;
|
||||
impl->hcr_setup.offset = 0;
|
||||
impl->hcr_setup.flags = is_equal ? 0 : VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT;
|
||||
@@ -1371,7 +1471,7 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValue(VideoCommon::Lookup
|
||||
if (!impl->device.IsExtConditionalRendering()) {
|
||||
return false;
|
||||
}
|
||||
HostConditionalRenderingCompareValueImpl(object_1, false);
|
||||
HostConditionalRenderingCompareBCImpl(object_1.address, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1420,7 +1520,8 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
|
||||
auto driver_id = impl->device.GetDriverID();
|
||||
const bool is_gpu_high = Settings::IsGPULevelHigh();
|
||||
|
||||
if ((!is_gpu_high && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) || driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) {
|
||||
if ((!is_gpu_high && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) || driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) {
|
||||
EndHostConditionalRendering();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1437,10 +1538,12 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
|
||||
}
|
||||
|
||||
if (!is_gpu_high) {
|
||||
EndHostConditionalRendering();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_in_bc[0] && !is_in_bc[1]) {
|
||||
EndHostConditionalRendering();
|
||||
return true;
|
||||
}
|
||||
HostConditionalRenderingCompareBCImpl(object_1.address, equal_check);
|
||||
|
||||
@@ -63,7 +63,8 @@ public:
|
||||
|
||||
private:
|
||||
void HostConditionalRenderingCompareValueImpl(VideoCommon::LookupData object, bool is_equal);
|
||||
void HostConditionalRenderingCompareBCImpl(DAddr address, bool is_equal);
|
||||
void HostConditionalRenderingCompareBCImpl(DAddr address, bool is_equal,
|
||||
bool compare_to_zero = false);
|
||||
friend struct QueryCacheRuntimeImpl;
|
||||
std::unique_ptr<QueryCacheRuntimeImpl> impl;
|
||||
};
|
||||
|
||||
@@ -173,6 +173,28 @@ DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances,
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
bool SupportsPrimitiveRestart(VkPrimitiveTopology topology) {
|
||||
switch (topology) {
|
||||
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
|
||||
case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
|
||||
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
|
||||
case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
|
||||
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
|
||||
case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsPrimitiveRestartSupported(const Device& device, VkPrimitiveTopology topology) {
|
||||
return ((topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
|
||||
device.IsTopologyListPrimitiveRestartSupported()) ||
|
||||
SupportsPrimitiveRestart(topology) ||
|
||||
(topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
|
||||
device.IsPatchListPrimitiveRestartSupported()));
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
|
||||
@@ -225,6 +247,7 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
||||
|
||||
UpdateDynamicStates();
|
||||
|
||||
query_cache.NotifySegment(true);
|
||||
HandleTransformFeedback();
|
||||
query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64,
|
||||
maxwell3d->regs.zpass_pixel_count_enable);
|
||||
@@ -336,6 +359,7 @@ void RasterizerVulkan::DrawTexture() {
|
||||
|
||||
UpdateDynamicStates();
|
||||
|
||||
query_cache.NotifySegment(true);
|
||||
query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64,
|
||||
maxwell3d->regs.zpass_pixel_count_enable);
|
||||
const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState();
|
||||
@@ -575,11 +599,17 @@ void RasterizerVulkan::DispatchCompute() {
|
||||
}
|
||||
|
||||
void RasterizerVulkan::ResetCounter(VideoCommon::QueryType type) {
|
||||
if (type != VideoCommon::QueryType::ZPassPixelCount64) {
|
||||
switch (type) {
|
||||
case VideoCommon::QueryType::ZPassPixelCount64:
|
||||
case VideoCommon::QueryType::StreamingByteCount:
|
||||
case VideoCommon::QueryType::StreamingPrimitivesSucceeded:
|
||||
case VideoCommon::QueryType::VtgPrimitivesOut:
|
||||
query_cache.CounterReset(type);
|
||||
return;
|
||||
default:
|
||||
LOG_DEBUG(Render_Vulkan, "Unimplemented counter reset={}", type);
|
||||
return;
|
||||
}
|
||||
query_cache.CounterReset(type);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::Query(GPUVAddr gpu_addr, VideoCommon::QueryType type,
|
||||
@@ -766,6 +796,9 @@ void RasterizerVulkan::ReleaseFences(bool force) {
|
||||
|
||||
void RasterizerVulkan::FlushAndInvalidateRegion(DAddr addr, u64 size,
|
||||
VideoCommon::CacheType which) {
|
||||
if (Settings::IsGPULevelHigh()) {
|
||||
FlushRegion(addr, size, which);
|
||||
}
|
||||
InvalidateRegion(addr, size, which);
|
||||
}
|
||||
|
||||
@@ -830,6 +863,10 @@ bool RasterizerVulkan::AccelerateConditionalRendering() {
|
||||
return query_cache.AccelerateHostConditionalRendering();
|
||||
}
|
||||
|
||||
bool RasterizerVulkan::HasDrawTransformFeedback() {
|
||||
return device.IsTransformFeedbackDrawSupported();
|
||||
}
|
||||
|
||||
bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
|
||||
const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
const Tegra::Engines::Fermi2D::Config& copy_config) {
|
||||
@@ -976,6 +1013,12 @@ bool AccelerateDMA::BufferToImage(const Tegra::DMA::ImageCopy& copy_info,
|
||||
|
||||
void RasterizerVulkan::UpdateDynamicStates() {
|
||||
auto& regs = maxwell3d->regs;
|
||||
auto& flags = maxwell3d->dirty.flags;
|
||||
const auto topology = maxwell3d->draw_manager->GetDrawState().topology;
|
||||
if (state_tracker.ChangePrimitiveTopology(topology)) {
|
||||
flags[Dirty::DepthBiasEnable] = true;
|
||||
flags[Dirty::PrimitiveRestartEnable] = true;
|
||||
}
|
||||
|
||||
// Core Dynamic States (Vulkan 1.0) - Always active regardless of dyna_state setting
|
||||
UpdateViewportsState(regs);
|
||||
@@ -1084,6 +1127,9 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
|
||||
if (!state_tracker.TouchViewports()) {
|
||||
return;
|
||||
}
|
||||
|
||||
maxwell3d->dirty.flags[Dirty::Scissors] = true;
|
||||
|
||||
if (!regs.viewport_scale_offset_enabled) {
|
||||
float x = static_cast<float>(regs.surface_clip.x);
|
||||
float y = static_cast<float>(regs.surface_clip.y);
|
||||
@@ -1101,8 +1147,12 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f,
|
||||
};
|
||||
scheduler.Record([viewport](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetViewport(0, viewport);
|
||||
scheduler.Record([this, viewport](vk::CommandBuffer cmdbuf) {
|
||||
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
|
||||
std::array<VkViewport, Maxwell::NumViewports> viewport_list{};
|
||||
viewport_list.fill(viewport);
|
||||
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
|
||||
cmdbuf.SetViewport(0, viewports);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -1142,8 +1192,12 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
|
||||
scissor.offset.y = static_cast<int32_t>(y);
|
||||
scissor.extent.width = width;
|
||||
scissor.extent.height = height;
|
||||
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetScissor(0, scissor);
|
||||
scheduler.Record([this, scissor](vk::CommandBuffer cmdbuf) {
|
||||
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
|
||||
std::array<VkRect2D, Maxwell::NumViewports> scissor_list{};
|
||||
scissor_list.fill(scissor);
|
||||
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
|
||||
cmdbuf.SetScissor(0, scissors);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -1388,7 +1442,17 @@ void RasterizerVulkan::UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::R
|
||||
if (!state_tracker.TouchPrimitiveRestartEnable()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([enable = regs.primitive_restart.enabled](vk::CommandBuffer cmdbuf) {
|
||||
|
||||
bool enable = regs.primitive_restart.enabled != 0;
|
||||
if (device.IsMoltenVK()) {
|
||||
enable = true;
|
||||
} else if (enable) {
|
||||
const auto topology =
|
||||
MaxwellToVK::PrimitiveTopology(device, maxwell3d->draw_manager->GetDrawState().topology);
|
||||
enable = IsPrimitiveRestartSupported(device, topology);
|
||||
}
|
||||
|
||||
scheduler.Record([enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetPrimitiveRestartEnableEXT(enable);
|
||||
});
|
||||
}
|
||||
@@ -1727,7 +1791,9 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs&
|
||||
|
||||
void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
auto& dirty{maxwell3d->dirty.flags};
|
||||
if (!dirty[Dirty::VertexInput]) {
|
||||
const bool vertex_input_dirty = dirty[Dirty::VertexInput];
|
||||
const bool vertex_buffers_dirty = dirty[VideoCommon::Dirty::VertexBuffers];
|
||||
if (!vertex_input_dirty && !vertex_buffers_dirty) {
|
||||
return;
|
||||
}
|
||||
dirty[Dirty::VertexInput] = false;
|
||||
@@ -1735,38 +1801,31 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
boost::container::static_vector<VkVertexInputBindingDescription2EXT, 32> bindings;
|
||||
boost::container::static_vector<VkVertexInputAttributeDescription2EXT, 32> attributes;
|
||||
|
||||
// There seems to be a bug on Nvidia's driver where updating only higher attributes ends up
|
||||
// generating dirty state. Track the highest dirty attribute and update all attributes until
|
||||
// that one.
|
||||
size_t highest_dirty_attr{};
|
||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||
if (dirty[Dirty::VertexAttribute0 + index]) {
|
||||
highest_dirty_attr = index;
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < highest_dirty_attr; ++index) {
|
||||
const u32 max_attributes =
|
||||
static_cast<u32>(std::min<size_t>(Maxwell::NumVertexAttributes,
|
||||
device.GetMaxVertexInputAttributes()));
|
||||
const u32 max_bindings =
|
||||
static_cast<u32>(std::min<size_t>(Maxwell::NumVertexArrays,
|
||||
device.GetMaxVertexInputBindings()));
|
||||
|
||||
|
||||
for (u32 index = 0; index < max_attributes; ++index) {
|
||||
const Maxwell::VertexAttribute attribute{regs.vertex_attrib_format[index]};
|
||||
const u32 binding{attribute.buffer};
|
||||
dirty[Dirty::VertexAttribute0 + index] = false;
|
||||
dirty[Dirty::VertexBinding0 + static_cast<size_t>(binding)] = true;
|
||||
if (!attribute.constant) {
|
||||
attributes.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
|
||||
.pNext = nullptr,
|
||||
.location = static_cast<u32>(index),
|
||||
.binding = binding,
|
||||
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
|
||||
.offset = attribute.offset,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||
if (!dirty[Dirty::VertexBinding0 + index]) {
|
||||
if (attribute.constant || binding >= max_bindings) {
|
||||
continue;
|
||||
}
|
||||
dirty[Dirty::VertexBinding0 + index] = false;
|
||||
attributes.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
|
||||
.pNext = nullptr,
|
||||
.location = index,
|
||||
.binding = binding,
|
||||
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
|
||||
.offset = attribute.offset,
|
||||
});
|
||||
}
|
||||
|
||||
const u32 binding{static_cast<u32>(index)};
|
||||
for (u32 binding = 0; binding < max_bindings; ++binding) {
|
||||
const auto& input_binding{regs.vertex_streams[binding]};
|
||||
const bool is_instanced{regs.vertex_stream_instances.IsInstancingEnabled(binding)};
|
||||
bindings.push_back({
|
||||
@@ -1778,6 +1837,14 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
.divisor = is_instanced ? input_binding.frequency : 1,
|
||||
});
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||
dirty[Dirty::VertexAttribute0 + index] = false;
|
||||
}
|
||||
for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
|
||||
dirty[Dirty::VertexBinding0 + index] = false;
|
||||
}
|
||||
|
||||
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetVertexInputEXT(bindings, attributes);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -122,6 +122,7 @@ public:
|
||||
void FlushCommands() override;
|
||||
void TickFrame() override;
|
||||
bool AccelerateConditionalRendering() override;
|
||||
bool HasDrawTransformFeedback() override;
|
||||
bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
|
||||
const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
const Tegra::Engines::Fermi2D::Config& copy_config) override;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_render_pass_cache.h"
|
||||
#include "video_core/surface.h"
|
||||
@@ -19,6 +20,23 @@ namespace {
|
||||
using VideoCore::Surface::PixelFormat;
|
||||
using VideoCore::Surface::SurfaceType;
|
||||
|
||||
// Check if the driver uses tile-based deferred rendering (TBDR) architecture
|
||||
// These GPUs benefit from optimized load/store operations to keep data on-chip
|
||||
//
|
||||
// TBDR GPUs supported in Eden:
|
||||
// - Qualcomm Adreno (Snapdragon): Most Android flagship/midrange devices
|
||||
// - ARM Mali: Android devices (Samsung Exynos, MediaTek, etc.)
|
||||
// - Imagination PowerVR: Older iOS devices, some Android tablets
|
||||
// - Samsung Xclipse: Galaxy S22+ (AMD RDNA2-based, but uses TBDR mode)
|
||||
// - Broadcom VideoCore: Raspberry Pi
|
||||
[[nodiscard]] constexpr bool IsTBDRGPU(VkDriverId driver_id) {
|
||||
return driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_IMAGINATION_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_SAMSUNG_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_BROADCOM_PROPRIETARY;
|
||||
}
|
||||
|
||||
constexpr SurfaceType GetSurfaceType(PixelFormat format) {
|
||||
switch (format) {
|
||||
// Depth formats
|
||||
@@ -44,23 +62,57 @@ using VideoCore::Surface::SurfaceType;
|
||||
}
|
||||
|
||||
VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat format,
|
||||
VkSampleCountFlagBits samples) {
|
||||
VkSampleCountFlagBits samples,
|
||||
bool tbdr_will_clear,
|
||||
bool tbdr_discard_after,
|
||||
bool tbdr_read_only = false) {
|
||||
using MaxwellToVK::SurfaceFormat;
|
||||
|
||||
const SurfaceType surface_type = GetSurfaceType(format);
|
||||
const bool has_stencil = surface_type == SurfaceType::DepthStencil ||
|
||||
surface_type == SurfaceType::Stencil;
|
||||
|
||||
// TBDR optimization: Apply hints only on tile-based GPUs
|
||||
// Desktop GPUs (NVIDIA/AMD/Intel) ignore these hints and use standard behavior
|
||||
const bool is_tbdr = IsTBDRGPU(device.GetDriverID());
|
||||
|
||||
// On TBDR: Use DONT_CARE if clear is guaranteed (avoids loading from main memory)
|
||||
// On Desktop: Always LOAD to preserve existing content (safer default)
|
||||
VkAttachmentLoadOp load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
if (is_tbdr && tbdr_will_clear) {
|
||||
load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
|
||||
// On TBDR: Use DONT_CARE if content won't be read (avoids storing to main memory)
|
||||
// On Desktop: Always STORE (safer default)
|
||||
// VK_QCOM_render_pass_store_ops: Use NONE_QCOM for read-only attachments (preserves outside render area)
|
||||
VkAttachmentStoreOp store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
if (is_tbdr && tbdr_discard_after) {
|
||||
store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
} else if (is_tbdr && tbdr_read_only && device.IsQcomRenderPassStoreOpsSupported()) {
|
||||
store_op = static_cast<VkAttachmentStoreOp>(1000301000); // VK_ATTACHMENT_STORE_OP_NONE_QCOM
|
||||
}
|
||||
|
||||
// Stencil operations follow same logic
|
||||
VkAttachmentLoadOp stencil_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
VkAttachmentStoreOp stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
if (has_stencil && tbdr_read_only && device.IsQcomRenderPassStoreOpsSupported()) {
|
||||
stencil_store_op = static_cast<VkAttachmentStoreOp>(1000301000); // VK_ATTACHMENT_STORE_OP_NONE_QCOM
|
||||
} else if (has_stencil) {
|
||||
stencil_load_op = (is_tbdr && tbdr_will_clear) ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
|
||||
: VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
stencil_store_op = (is_tbdr && tbdr_discard_after) ? VK_ATTACHMENT_STORE_OP_DONT_CARE
|
||||
: VK_ATTACHMENT_STORE_OP_STORE;
|
||||
}
|
||||
|
||||
return {
|
||||
.flags = {},
|
||||
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
|
||||
.samples = samples,
|
||||
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
.stencilLoadOp = has_stencil ? VK_ATTACHMENT_LOAD_OP_LOAD
|
||||
: VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.stencilStoreOp = has_stencil ? VK_ATTACHMENT_STORE_OP_STORE
|
||||
: VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
.loadOp = load_op,
|
||||
.storeOp = store_op,
|
||||
.stencilLoadOp = stencil_load_op,
|
||||
.stencilStoreOp = stencil_store_op,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
};
|
||||
@@ -75,6 +127,13 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
if (!is_new) {
|
||||
return *pair->second;
|
||||
}
|
||||
|
||||
const bool is_tbdr = IsTBDRGPU(device->GetDriverID());
|
||||
if (is_tbdr && (key.tbdr_will_clear || key.tbdr_discard_after)) {
|
||||
LOG_DEBUG(Render_Vulkan, "Creating TBDR-optimized render pass (driver={}, clear={}, discard={})",
|
||||
static_cast<u32>(device->GetDriverID()), key.tbdr_will_clear, key.tbdr_discard_after);
|
||||
}
|
||||
|
||||
boost::container::static_vector<VkAttachmentDescription, 9> descriptions;
|
||||
std::array<VkAttachmentReference, 8> references{};
|
||||
u32 num_attachments{};
|
||||
@@ -87,7 +146,8 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
};
|
||||
if (is_valid) {
|
||||
descriptions.push_back(AttachmentDescription(*device, format, key.samples));
|
||||
descriptions.push_back(AttachmentDescription(*device, format, key.samples,
|
||||
key.tbdr_will_clear, key.tbdr_discard_after));
|
||||
num_attachments = static_cast<u32>(index + 1);
|
||||
++num_colors;
|
||||
}
|
||||
@@ -99,10 +159,19 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
.attachment = num_colors,
|
||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
};
|
||||
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples));
|
||||
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples,
|
||||
key.tbdr_will_clear, key.tbdr_discard_after, key.tbdr_read_only));
|
||||
}
|
||||
VkSubpassDescriptionFlags subpass_flags = 0;
|
||||
if (key.qcom_shader_resolve) {
|
||||
// VK_QCOM_render_pass_shader_resolve: enables custom shader resolve in fragment shader
|
||||
// This flag allows using a programmable fragment shader for MSAA resolve instead of
|
||||
// fixed-function hardware resolve, enabling better quality and HDR format support
|
||||
subpass_flags |= 0x00000004; // VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM
|
||||
}
|
||||
|
||||
const VkSubpassDescription subpass{
|
||||
.flags = 0,
|
||||
.flags = subpass_flags,
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.inputAttachmentCount = 0,
|
||||
.pInputAttachments = nullptr,
|
||||
|
||||
@@ -20,6 +20,15 @@ struct RenderPassKey {
|
||||
std::array<VideoCore::Surface::PixelFormat, 8> color_formats;
|
||||
VideoCore::Surface::PixelFormat depth_format;
|
||||
VkSampleCountFlagBits samples;
|
||||
|
||||
// TBDR optimization hints - only affect tile-based GPUs (Qualcomm, ARM, Imagination)
|
||||
// These flags indicate the expected usage pattern to optimize load/store operations
|
||||
bool tbdr_will_clear{false}; // Attachment will be cleared with vkCmdClearAttachments
|
||||
bool tbdr_discard_after{false}; // Attachment won't be read after render pass
|
||||
bool tbdr_read_only{false}; // Attachment is read-only (input attachment, depth test without writes)
|
||||
|
||||
// VK_QCOM_render_pass_shader_resolve support
|
||||
bool qcom_shader_resolve{false}; // Use shader resolve instead of fixed-function (last subpass)
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
@@ -30,6 +39,8 @@ struct hash<Vulkan::RenderPassKey> {
|
||||
[[nodiscard]] size_t operator()(const Vulkan::RenderPassKey& key) const noexcept {
|
||||
size_t value = static_cast<size_t>(key.depth_format) << 48;
|
||||
value ^= static_cast<size_t>(key.samples) << 52;
|
||||
value ^= (static_cast<size_t>(key.tbdr_will_clear) << 56);
|
||||
value ^= (static_cast<size_t>(key.tbdr_discard_after) << 57);
|
||||
for (size_t i = 0; i < key.color_formats.size(); ++i) {
|
||||
value ^= static_cast<size_t>(key.color_formats[i]) << (i * 6);
|
||||
}
|
||||
|
||||
@@ -324,6 +324,8 @@ void Scheduler::EndRenderPass()
|
||||
return;
|
||||
}
|
||||
|
||||
query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount);
|
||||
|
||||
// Log render pass end
|
||||
if (Settings::values.gpu_logging_enabled.GetValue() &&
|
||||
Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||
|
||||
@@ -63,6 +63,11 @@ public:
|
||||
/// of a renderpass.
|
||||
void RequestOutsideRenderPassOperationContext();
|
||||
|
||||
/// Returns true when a render pass is currently active in the scheduler state.
|
||||
bool IsRenderPassActive() const {
|
||||
return state.renderpass != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
/// Update the pipeline to the current execution context.
|
||||
bool UpdateGraphicsPipeline(GraphicsPipeline* pipeline);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
@@ -87,6 +87,7 @@ Flags MakeInvalidationFlags() {
|
||||
void SetupDirtyViewports(Tables& tables) {
|
||||
FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports);
|
||||
FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports);
|
||||
FillBlock(tables[1], OFF(surface_clip), NUM(surface_clip), Viewports);
|
||||
tables[0][OFF(viewport_scale_offset_enabled)] = Viewports;
|
||||
tables[1][OFF(window_origin)] = Viewports;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user