mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-24 16:30:44 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 213a9a7813 | |||
| 48ba1f3f24 | |||
| d59fcf01bf | |||
| b8456394f1 | |||
| a467dd1ba6 | |||
| c156f4760f | |||
| 13f11ebf49 | |||
| 6065e9aa09 |
+4
-4
@@ -178,7 +178,9 @@ endif()
|
|||||||
|
|
||||||
# Disable Warnings as Errors for MSVC
|
# Disable Warnings as Errors for MSVC
|
||||||
if (MSVC AND NOT CXX_CLANG)
|
if (MSVC AND NOT CXX_CLANG)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-")
|
# This was dripping into spirv, being overriden, and causing cl flag override warning
|
||||||
|
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-")
|
||||||
|
set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /W3 /WX-")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set bundled sdl2/qt as dependent options.
|
# Set bundled sdl2/qt as dependent options.
|
||||||
@@ -587,6 +589,7 @@ if (NOT YUZU_STATIC_ROOM)
|
|||||||
find_package(sirit)
|
find_package(sirit)
|
||||||
find_package(gamemode)
|
find_package(gamemode)
|
||||||
find_package(mcl)
|
find_package(mcl)
|
||||||
|
find_package(frozen)
|
||||||
|
|
||||||
if (ARCHITECTURE_riscv64)
|
if (ARCHITECTURE_riscv64)
|
||||||
find_package(biscuit)
|
find_package(biscuit)
|
||||||
@@ -698,9 +701,6 @@ if (ENABLE_QT)
|
|||||||
|
|
||||||
# QuaZip
|
# QuaZip
|
||||||
AddJsonPackage(quazip)
|
AddJsonPackage(quazip)
|
||||||
|
|
||||||
# frozen
|
|
||||||
AddJsonPackage(frozen)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT YUZU_STATIC_ROOM AND NOT (YUZU_USE_BUNDLED_FFMPEG OR YUZU_USE_EXTERNAL_FFMPEG))
|
if (NOT YUZU_STATIC_ROOM AND NOT (YUZU_USE_BUNDLED_FFMPEG OR YUZU_USE_EXTERNAL_FFMPEG))
|
||||||
|
|||||||
+192
-125
@@ -41,6 +41,11 @@ function(cpm_utils_message level name message)
|
|||||||
message(${level} "[CPMUtil] ${name}: ${message}")
|
message(${level} "[CPMUtil] ${name}: ${message}")
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# propagate a variable to parent scope
|
||||||
|
macro(Propagate var)
|
||||||
|
set(${var} ${${var}} PARENT_SCOPE)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
function(array_to_list array length out)
|
function(array_to_list array length out)
|
||||||
math(EXPR range "${length} - 1")
|
math(EXPR range "${length} - 1")
|
||||||
|
|
||||||
@@ -72,6 +77,159 @@ function(get_json_element object out member default)
|
|||||||
set("${out}" "${outvar}" PARENT_SCOPE)
|
set("${out}" "${outvar}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# Determine whether or not a package has a viable system candidate.
|
||||||
|
function(SystemPackageViable JSON_NAME)
|
||||||
|
string(JSON object GET "${CPMFILE_CONTENT}" "${JSON_NAME}")
|
||||||
|
|
||||||
|
parse_object(${object})
|
||||||
|
|
||||||
|
string(REPLACE " " ";" find_args "${find_args}")
|
||||||
|
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
|
||||||
|
|
||||||
|
set(${pkg}_VIABLE ${${package}_FOUND} PARENT_SCOPE)
|
||||||
|
set(${pkg}_PACKAGE ${package} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Add several packages such that if one is bundled,
|
||||||
|
# all the rest must also be bundled.
|
||||||
|
function(AddDependentPackages)
|
||||||
|
set(_some_system OFF)
|
||||||
|
set(_some_bundled OFF)
|
||||||
|
|
||||||
|
foreach(pkg ${ARGN})
|
||||||
|
SystemPackageViable(${pkg})
|
||||||
|
|
||||||
|
if (${pkg}_VIABLE)
|
||||||
|
set(_some_system ON)
|
||||||
|
list(APPEND _system_pkgs ${${pkg}_PACKAGE})
|
||||||
|
else()
|
||||||
|
set(_some_bundled ON)
|
||||||
|
list(APPEND _bundled_pkgs ${${pkg}_PACKAGE})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if (_some_system AND _some_bundled)
|
||||||
|
foreach(pkg ${ARGN})
|
||||||
|
list(APPEND package_names ${${pkg}_PACKAGE})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
string(REPLACE ";" ", " package_names "${package_names}")
|
||||||
|
string(REPLACE ";" ", " bundled_names "${_bundled_pkgs}")
|
||||||
|
foreach(sys ${_system_pkgs})
|
||||||
|
list(APPEND system_names ${sys}_FORCE_BUNDLED)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
string(REPLACE ";" ", " system_names "${system_names}")
|
||||||
|
|
||||||
|
message(FATAL_ERROR "Partial dependency installation detected "
|
||||||
|
"for the following packages:\n${package_names}\n"
|
||||||
|
"You can solve this in one of two ways:\n"
|
||||||
|
"1. Install the following packages to your system if available:"
|
||||||
|
"\n\t${bundled_names}\n"
|
||||||
|
"2. Set the following variables to ON:"
|
||||||
|
"\n\t${system_names}\n"
|
||||||
|
"This may also be caused by a version mismatch, "
|
||||||
|
"such as one package being newer than the other.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(pkg ${ARGN})
|
||||||
|
AddJsonPackage(${pkg})
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# json util
|
||||||
|
macro(parse_object object)
|
||||||
|
get_json_element("${object}" package package ${JSON_NAME})
|
||||||
|
get_json_element("${object}" repo repo "")
|
||||||
|
get_json_element("${object}" ci ci OFF)
|
||||||
|
get_json_element("${object}" version version "")
|
||||||
|
|
||||||
|
if(ci)
|
||||||
|
get_json_element("${object}" name name "${JSON_NAME}")
|
||||||
|
get_json_element("${object}" extension extension "tar.zst")
|
||||||
|
get_json_element("${object}" min_version min_version "")
|
||||||
|
get_json_element("${object}" raw_disabled disabled_platforms "")
|
||||||
|
|
||||||
|
if(raw_disabled)
|
||||||
|
array_to_list("${raw_disabled}"
|
||||||
|
${raw_disabled_LENGTH} disabled_platforms)
|
||||||
|
else()
|
||||||
|
set(disabled_platforms "")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
get_json_element("${object}" hash hash "")
|
||||||
|
get_json_element("${object}" hash_suffix hash_suffix "")
|
||||||
|
get_json_element("${object}" sha sha "")
|
||||||
|
get_json_element("${object}" url url "")
|
||||||
|
get_json_element("${object}" key key "")
|
||||||
|
get_json_element("${object}" tag tag "")
|
||||||
|
get_json_element("${object}" artifact artifact "")
|
||||||
|
get_json_element("${object}" git_version git_version "")
|
||||||
|
get_json_element("${object}" git_host git_host "")
|
||||||
|
get_json_element("${object}" source_subdir source_subdir "")
|
||||||
|
get_json_element("${object}" bundled bundled "unset")
|
||||||
|
get_json_element("${object}" find_args find_args "")
|
||||||
|
get_json_element("${object}" raw_patches patches "")
|
||||||
|
|
||||||
|
# okay here comes the fun part: REPLACEMENTS!
|
||||||
|
# first: tag gets %VERSION% replaced if applicable,
|
||||||
|
# with either git_version (preferred) or version
|
||||||
|
# second: artifact gets %VERSION% and %TAG% replaced
|
||||||
|
# accordingly (same rules for VERSION)
|
||||||
|
|
||||||
|
if(git_version)
|
||||||
|
set(version_replace ${git_version})
|
||||||
|
else()
|
||||||
|
set(version_replace ${version})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# TODO(crueter): fmt module for cmake
|
||||||
|
if(tag)
|
||||||
|
string(REPLACE "%VERSION%" "${version_replace}" tag ${tag})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(artifact)
|
||||||
|
string(REPLACE "%VERSION%" "${version_replace}"
|
||||||
|
artifact ${artifact})
|
||||||
|
string(REPLACE "%TAG%" "${tag}" artifact ${artifact})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# format patchdir
|
||||||
|
if(raw_patches)
|
||||||
|
math(EXPR range "${raw_patches_LENGTH} - 1")
|
||||||
|
|
||||||
|
foreach(IDX RANGE ${range})
|
||||||
|
string(JSON _patch GET "${raw_patches}" "${IDX}")
|
||||||
|
|
||||||
|
set(full_patch
|
||||||
|
"${PROJECT_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}")
|
||||||
|
if(NOT EXISTS ${full_patch})
|
||||||
|
cpm_utils_message(FATAL_ERROR ${JSON_NAME}
|
||||||
|
"specifies patch ${full_patch} which does not exist")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND patches "${full_patch}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
# end format patchdir
|
||||||
|
|
||||||
|
# options
|
||||||
|
get_json_element("${object}" raw_options options "")
|
||||||
|
|
||||||
|
if(raw_options)
|
||||||
|
array_to_list("${raw_options}" ${raw_options_LENGTH} options)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(options ${options} ${JSON_OPTIONS})
|
||||||
|
# end options
|
||||||
|
|
||||||
|
# system/bundled
|
||||||
|
if(bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
|
||||||
|
set(bundled ${JSON_BUNDLED_PACKAGE})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
# The preferred usage
|
# The preferred usage
|
||||||
function(AddJsonPackage)
|
function(AddJsonPackage)
|
||||||
set(oneValueArgs
|
set(oneValueArgs
|
||||||
@@ -80,7 +238,8 @@ function(AddJsonPackage)
|
|||||||
# these are overrides that can be generated at runtime,
|
# these are overrides that can be generated at runtime,
|
||||||
# so can be defined separately from the json
|
# so can be defined separately from the json
|
||||||
DOWNLOAD_ONLY
|
DOWNLOAD_ONLY
|
||||||
BUNDLED_PACKAGE)
|
BUNDLED_PACKAGE
|
||||||
|
FORCE_BUNDLED_PACKAGE)
|
||||||
|
|
||||||
set(multiValueArgs OPTIONS)
|
set(multiValueArgs OPTIONS)
|
||||||
|
|
||||||
@@ -111,24 +270,9 @@ function(AddJsonPackage)
|
|||||||
cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile")
|
cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
get_json_element("${object}" package package ${JSON_NAME})
|
parse_object(${object})
|
||||||
get_json_element("${object}" repo repo "")
|
|
||||||
get_json_element("${object}" ci ci OFF)
|
|
||||||
get_json_element("${object}" version version "")
|
|
||||||
|
|
||||||
if(ci)
|
if(ci)
|
||||||
get_json_element("${object}" name name "${JSON_NAME}")
|
|
||||||
get_json_element("${object}" extension extension "tar.zst")
|
|
||||||
get_json_element("${object}" min_version min_version "")
|
|
||||||
get_json_element("${object}" raw_disabled disabled_platforms "")
|
|
||||||
|
|
||||||
if(raw_disabled)
|
|
||||||
array_to_list("${raw_disabled}"
|
|
||||||
${raw_disabled_LENGTH} disabled_platforms)
|
|
||||||
else()
|
|
||||||
set(disabled_platforms "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
AddCIPackage(
|
AddCIPackage(
|
||||||
VERSION ${version}
|
VERSION ${version}
|
||||||
NAME ${name}
|
NAME ${name}
|
||||||
@@ -138,116 +282,38 @@ function(AddJsonPackage)
|
|||||||
MIN_VERSION ${min_version}
|
MIN_VERSION ${min_version}
|
||||||
DISABLED_PLATFORMS ${disabled_platforms})
|
DISABLED_PLATFORMS ${disabled_platforms})
|
||||||
|
|
||||||
# pass stuff to parent scope
|
|
||||||
set(${package}_ADDED "${${package}_ADDED}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
set(${package}_SOURCE_DIR "${${package}_SOURCE_DIR}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
set(${package}_BINARY_DIR "${${package}_BINARY_DIR}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
get_json_element("${object}" hash hash "")
|
|
||||||
get_json_element("${object}" hash_suffix hash_suffix "")
|
|
||||||
get_json_element("${object}" sha sha "")
|
|
||||||
get_json_element("${object}" url url "")
|
|
||||||
get_json_element("${object}" key key "")
|
|
||||||
get_json_element("${object}" tag tag "")
|
|
||||||
get_json_element("${object}" artifact artifact "")
|
|
||||||
get_json_element("${object}" git_version git_version "")
|
|
||||||
get_json_element("${object}" git_host git_host "")
|
|
||||||
get_json_element("${object}" source_subdir source_subdir "")
|
|
||||||
get_json_element("${object}" bundled bundled "unset")
|
|
||||||
get_json_element("${object}" find_args find_args "")
|
|
||||||
get_json_element("${object}" raw_patches patches "")
|
|
||||||
|
|
||||||
# okay here comes the fun part: REPLACEMENTS!
|
|
||||||
# first: tag gets %VERSION% replaced if applicable,
|
|
||||||
# with either git_version (preferred) or version
|
|
||||||
# second: artifact gets %VERSION% and %TAG% replaced
|
|
||||||
# accordingly (same rules for VERSION)
|
|
||||||
|
|
||||||
if(git_version)
|
|
||||||
set(version_replace ${git_version})
|
|
||||||
else()
|
else()
|
||||||
set(version_replace ${version})
|
if (NOT DEFINED JSON_FORCE_BUNDLED_PACKAGE)
|
||||||
|
set(JSON_FORCE_BUNDLED_PACKAGE OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
AddPackage(
|
||||||
|
NAME "${package}"
|
||||||
|
VERSION "${version}"
|
||||||
|
URL "${url}"
|
||||||
|
HASH "${hash}"
|
||||||
|
HASH_SUFFIX "${hash_suffix}"
|
||||||
|
SHA "${sha}"
|
||||||
|
REPO "${repo}"
|
||||||
|
KEY "${key}"
|
||||||
|
PATCHES "${patches}"
|
||||||
|
OPTIONS "${options}"
|
||||||
|
FIND_PACKAGE_ARGUMENTS "${find_args}"
|
||||||
|
BUNDLED_PACKAGE "${bundled}"
|
||||||
|
FORCE_BUNDLED_PACKAGE "${JSON_FORCE_BUNDLED_PACKAGE}"
|
||||||
|
SOURCE_SUBDIR "${source_subdir}"
|
||||||
|
|
||||||
|
GIT_VERSION ${git_version}
|
||||||
|
GIT_HOST ${git_host}
|
||||||
|
|
||||||
|
ARTIFACT ${artifact}
|
||||||
|
TAG ${tag})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# TODO(crueter): fmt module for cmake
|
|
||||||
if(tag)
|
|
||||||
string(REPLACE "%VERSION%" "${version_replace}" tag ${tag})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(artifact)
|
|
||||||
string(REPLACE "%VERSION%" "${version_replace}" artifact ${artifact})
|
|
||||||
string(REPLACE "%TAG%" "${tag}" artifact ${artifact})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# format patchdir
|
|
||||||
if(raw_patches)
|
|
||||||
math(EXPR range "${raw_patches_LENGTH} - 1")
|
|
||||||
|
|
||||||
foreach(IDX RANGE ${range})
|
|
||||||
string(JSON _patch GET "${raw_patches}" "${IDX}")
|
|
||||||
|
|
||||||
set(full_patch
|
|
||||||
"${PROJECT_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}")
|
|
||||||
if(NOT EXISTS ${full_patch})
|
|
||||||
cpm_utils_message(FATAL_ERROR ${JSON_NAME}
|
|
||||||
"specifies patch ${full_patch} which does not exist")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND patches "${full_patch}")
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
# end format patchdir
|
|
||||||
|
|
||||||
# options
|
|
||||||
get_json_element("${object}" raw_options options "")
|
|
||||||
|
|
||||||
if(raw_options)
|
|
||||||
array_to_list("${raw_options}" ${raw_options_LENGTH} options)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(options ${options} ${JSON_OPTIONS})
|
|
||||||
# end options
|
|
||||||
|
|
||||||
# system/bundled
|
|
||||||
if(bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
|
|
||||||
set(bundled ${JSON_BUNDLED_PACKAGE})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
AddPackage(
|
|
||||||
NAME "${package}"
|
|
||||||
VERSION "${version}"
|
|
||||||
URL "${url}"
|
|
||||||
HASH "${hash}"
|
|
||||||
HASH_SUFFIX "${hash_suffix}"
|
|
||||||
SHA "${sha}"
|
|
||||||
REPO "${repo}"
|
|
||||||
KEY "${key}"
|
|
||||||
PATCHES "${patches}"
|
|
||||||
OPTIONS "${options}"
|
|
||||||
FIND_PACKAGE_ARGUMENTS "${find_args}"
|
|
||||||
BUNDLED_PACKAGE "${bundled}"
|
|
||||||
SOURCE_SUBDIR "${source_subdir}"
|
|
||||||
|
|
||||||
GIT_VERSION ${git_version}
|
|
||||||
GIT_HOST ${git_host}
|
|
||||||
|
|
||||||
ARTIFACT ${artifact}
|
|
||||||
TAG ${tag})
|
|
||||||
|
|
||||||
# pass stuff to parent scope
|
# pass stuff to parent scope
|
||||||
set(${package}_ADDED "${${package}_ADDED}"
|
Propagate(${package}_ADDED)
|
||||||
PARENT_SCOPE)
|
Propagate(${package}_SOURCE_DIR)
|
||||||
set(${package}_SOURCE_DIR "${${package}_SOURCE_DIR}"
|
Propagate(${package}_BINARY_DIR)
|
||||||
PARENT_SCOPE)
|
|
||||||
set(${package}_BINARY_DIR "${${package}_BINARY_DIR}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(AddPackage)
|
function(AddPackage)
|
||||||
@@ -343,7 +409,7 @@ function(AddPackage)
|
|||||||
|
|
||||||
if(DEFINED PKG_ARGS_ARTIFACT)
|
if(DEFINED PKG_ARGS_ARTIFACT)
|
||||||
set(pkg_url
|
set(pkg_url
|
||||||
${pkg_git_url}/releases/download/${PKG_ARGS_TAG}/${PKG_ARGS_ARTIFACT})
|
"${pkg_git_url}/releases/download/${PKG_ARGS_TAG}/${PKG_ARGS_ARTIFACT}")
|
||||||
else()
|
else()
|
||||||
set(pkg_url
|
set(pkg_url
|
||||||
${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz)
|
${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz)
|
||||||
@@ -625,7 +691,8 @@ function(AddCIPackage)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (DEFINED pkgname AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS)
|
if (DEFINED pkgname AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS)
|
||||||
set(ARTIFACT "${ARTIFACT_NAME}-${pkgname}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}")
|
set(ARTIFACT
|
||||||
|
"${ARTIFACT_NAME}-${pkgname}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}")
|
||||||
|
|
||||||
AddPackage(
|
AddPackage(
|
||||||
NAME ${ARTIFACT_PACKAGE}
|
NAME ${ARTIFACT_PACKAGE}
|
||||||
|
|||||||
@@ -114,11 +114,5 @@
|
|||||||
"QUAZIP_INSTALL OFF",
|
"QUAZIP_INSTALL OFF",
|
||||||
"QUAZIP_ENABLE_QTEXTCODEC OFF"
|
"QUAZIP_ENABLE_QTEXTCODEC OFF"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"frozen": {
|
|
||||||
"package": "frozen",
|
|
||||||
"repo": "serge-sans-paille/frozen",
|
|
||||||
"sha": "61dce5ae18",
|
|
||||||
"hash": "b8dfe741c82bc178dfc9749d4ab5a130cee718d9ee7b71d9b547cf5f7f23027ed0152ad250012a8546399fcc1e12187efc68d89d6731256c4d2df7d04eef8d5c"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
src/web_service @AleksandrPopovich
|
src/web_service @AleksandrPopovich
|
||||||
src/dynarmic @Lizzie
|
src/dynarmic @Lizzie
|
||||||
src/core @Lizzie @Maufeat @PavelBARABANOV @MrPurple666 @JPikachu
|
src/core @Lizzie @Maufeat @PavelBARABANOV @MrPurple666 @JPikachu
|
||||||
src/core/hle @Maufeat @PavelBARABANOV @SDK-Chan
|
src/core/hle @Maufeat @PavelBARABANOV
|
||||||
src/core/arm @Lizzie @MrPurple666
|
src/core/arm @Lizzie @MrPurple666
|
||||||
src/*_room @AleksandrPopovich
|
src/*_room @AleksandrPopovich
|
||||||
src/video_core @CamilleLaVey @MaranBr @Wildcard @weakboson
|
src/video_core @CamilleLaVey @MaranBr @Wildcard @weakboson
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# AddDependentPackage
|
||||||
|
|
||||||
|
Use `AddDependentPackage` when you have multiple packages that are required to all be from the system, OR bundled. This is useful in cases where e.g. versions must absolutely match.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
Versioning must be handled by the package itself.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Vulkan
|
||||||
|
|
||||||
|
`cpmfile.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"vulkan-headers": {
|
||||||
|
"repo": "KhronosGroup/Vulkan-Headers",
|
||||||
|
"package": "VulkanHeaders",
|
||||||
|
"version": "1.4.317",
|
||||||
|
"hash": "26e0ad8fa34ab65a91ca62ddc54cc4410d209a94f64f2817dcdb8061dc621539a4262eab6387e9b9aa421db3dbf2cf8e2a4b041b696d0d03746bae1f25191272",
|
||||||
|
"git_version": "1.4.342",
|
||||||
|
"tag": "v%VERSION%"
|
||||||
|
},
|
||||||
|
"vulkan-utility-libraries": {
|
||||||
|
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
|
||||||
|
"package": "VulkanUtilityLibraries",
|
||||||
|
"hash": "8147370f964fd82c315d6bb89adeda30186098427bf3efaa641d36282d42a263f31e96e4586bfd7ae0410ff015379c19aa4512ba160630444d3d8553afd1ec14",
|
||||||
|
"git_version": "1.4.342",
|
||||||
|
"tag": "v%VERSION%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`CMakeLists.txt`:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
AddDependentPackages(vulkan-headers vulkan-utility-libraries)
|
||||||
|
```
|
||||||
|
|
||||||
|
If Vulkan Headers are installed, but NOT Vulkan Utility Libraries, then CPMUtil will throw an error.
|
||||||
@@ -31,6 +31,10 @@ The core of CPMUtil is the [`AddPackage`](./AddPackage.md) function. [`AddPackag
|
|||||||
|
|
||||||
[`AddJsonPackage`](./AddJsonPackage.md) is the recommended method of usage for CPMUtil.
|
[`AddJsonPackage`](./AddJsonPackage.md) is the recommended method of usage for CPMUtil.
|
||||||
|
|
||||||
|
## AddDependentPackage
|
||||||
|
|
||||||
|
[`AddDependentPackage`](./AddDependentPackage.md) allows you to add multiple packages such that all of them must be from the system OR bundled.
|
||||||
|
|
||||||
## AddQt
|
## AddQt
|
||||||
|
|
||||||
[`AddQt`](./AddQt.md) adds a specific version of Qt to your project.
|
[`AddQt`](./AddQt.md) adds a specific version of Qt to your project.
|
||||||
|
|||||||
Vendored
+3
-6
@@ -84,13 +84,10 @@ endif()
|
|||||||
AddJsonPackage(mcl)
|
AddJsonPackage(mcl)
|
||||||
|
|
||||||
# Vulkan stuff
|
# Vulkan stuff
|
||||||
AddJsonPackage(vulkan-headers)
|
AddDependentPackages(vulkan-headers vulkan-utility-libraries)
|
||||||
AddJsonPackage(vulkan-utility-libraries)
|
|
||||||
|
|
||||||
# small hack
|
# frozen
|
||||||
if (NOT VulkanUtilityLibraries_ADDED)
|
AddJsonPackage(frozen)
|
||||||
find_package(VulkanHeaders 1.3.274 REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# DiscordRPC
|
# DiscordRPC
|
||||||
if (USE_DISCORD_PRESENCE)
|
if (USE_DISCORD_PRESENCE)
|
||||||
|
|||||||
Vendored
+7
-1
@@ -276,7 +276,7 @@
|
|||||||
"vulkan-headers": {
|
"vulkan-headers": {
|
||||||
"repo": "KhronosGroup/Vulkan-Headers",
|
"repo": "KhronosGroup/Vulkan-Headers",
|
||||||
"package": "VulkanHeaders",
|
"package": "VulkanHeaders",
|
||||||
"version": "1.3.274",
|
"version": "1.4.317",
|
||||||
"hash": "26e0ad8fa34ab65a91ca62ddc54cc4410d209a94f64f2817dcdb8061dc621539a4262eab6387e9b9aa421db3dbf2cf8e2a4b041b696d0d03746bae1f25191272",
|
"hash": "26e0ad8fa34ab65a91ca62ddc54cc4410d209a94f64f2817dcdb8061dc621539a4262eab6387e9b9aa421db3dbf2cf8e2a4b041b696d0d03746bae1f25191272",
|
||||||
"git_version": "1.4.342",
|
"git_version": "1.4.342",
|
||||||
"tag": "v%VERSION%"
|
"tag": "v%VERSION%"
|
||||||
@@ -287,5 +287,11 @@
|
|||||||
"hash": "8147370f964fd82c315d6bb89adeda30186098427bf3efaa641d36282d42a263f31e96e4586bfd7ae0410ff015379c19aa4512ba160630444d3d8553afd1ec14",
|
"hash": "8147370f964fd82c315d6bb89adeda30186098427bf3efaa641d36282d42a263f31e96e4586bfd7ae0410ff015379c19aa4512ba160630444d3d8553afd1ec14",
|
||||||
"git_version": "1.4.342",
|
"git_version": "1.4.342",
|
||||||
"tag": "v%VERSION%"
|
"tag": "v%VERSION%"
|
||||||
|
},
|
||||||
|
"frozen": {
|
||||||
|
"package": "frozen",
|
||||||
|
"repo": "serge-sans-paille/frozen",
|
||||||
|
"sha": "61dce5ae18",
|
||||||
|
"hash": "b8dfe741c82bc178dfc9749d4ab5a130cee718d9ee7b71d9b547cf5f7f23027ed0152ad250012a8546399fcc1e12187efc68d89d6731256c4d2df7d04eef8d5c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -24,6 +24,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
|
RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
|
||||||
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
|
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
|
||||||
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
||||||
|
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
|
||||||
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
|
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
|
||||||
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
|
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
|
||||||
RENDERER_DEBUG("debug"),
|
RENDERER_DEBUG("debug"),
|
||||||
|
|||||||
+7
@@ -745,6 +745,13 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.renderer_reactive_flushing_description
|
descriptionId = R.string.renderer_reactive_flushing_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
SwitchSetting(
|
||||||
|
BooleanSetting.ENABLE_BUFFER_HISTORY,
|
||||||
|
titleId = R.string.enable_buffer_history,
|
||||||
|
descriptionId = R.string.enable_buffer_history_description
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.SYNC_MEMORY_OPERATIONS,
|
BooleanSetting.SYNC_MEMORY_OPERATIONS,
|
||||||
|
|||||||
+1
@@ -275,6 +275,7 @@ class SettingsFragmentPresenter(
|
|||||||
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
||||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||||
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
||||||
|
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
|
||||||
|
|
||||||
add(HeaderSetting(R.string.hacks))
|
add(HeaderSetting(R.string.hacks))
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <common/fs/path_util.h>
|
|
||||||
|
|
||||||
#include "android_config.h"
|
#include "android_config.h"
|
||||||
#include "android_settings.h"
|
#include "android_settings.h"
|
||||||
#include "common/android/android_common.h"
|
#include "common/android/android_common.h"
|
||||||
#include "common/android/id_cache.h"
|
#include "common/android/id_cache.h"
|
||||||
|
#include "common/fs/path_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "frontend_common/config.h"
|
#include "frontend_common/config.h"
|
||||||
|
#include "frontend_common/settings_generator.h"
|
||||||
#include "native.h"
|
#include "native.h"
|
||||||
|
|
||||||
std::unique_ptr<AndroidConfig> global_config;
|
std::unique_ptr<AndroidConfig> global_config;
|
||||||
@@ -37,6 +38,7 @@ extern "C" {
|
|||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
global_config = std::make_unique<AndroidConfig>();
|
global_config = std::make_unique<AndroidConfig>();
|
||||||
|
FrontendCommon::GenerateSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
|
|||||||
@@ -493,6 +493,8 @@
|
|||||||
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
|
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
|
||||||
<string name="renderer_reactive_flushing">Use reactive flushing</string>
|
<string name="renderer_reactive_flushing">Use reactive flushing</string>
|
||||||
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
||||||
|
<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="hacks">Hacks</string>
|
<string name="hacks">Hacks</string>
|
||||||
|
|||||||
@@ -481,6 +481,14 @@ struct Values {
|
|||||||
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
|
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> enable_buffer_history{linkage,
|
||||||
|
false,
|
||||||
|
"enable_buffer_history",
|
||||||
|
Category::RendererAdvanced,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
// Renderer Hacks //
|
// Renderer Hacks //
|
||||||
SwitchableSetting<GpuOverclock> fast_gpu_time{linkage,
|
SwitchableSetting<GpuOverclock> fast_gpu_time{linkage,
|
||||||
GpuOverclock::Medium,
|
GpuOverclock::Medium,
|
||||||
@@ -778,7 +786,7 @@ struct Values {
|
|||||||
Category::WebService};
|
Category::WebService};
|
||||||
Setting<std::string> eden_username{linkage, "Eden", "eden_username",
|
Setting<std::string> eden_username{linkage, "Eden", "eden_username",
|
||||||
Category::WebService};
|
Category::WebService};
|
||||||
Setting<std::string> eden_token{linkage, "njausoolxygtpvraofqunuufhmupriifnpfggjxefntlyglr",
|
Setting<std::string> eden_token{linkage, "",
|
||||||
"eden_token", Category::WebService};
|
"eden_token", Category::WebService};
|
||||||
|
|
||||||
// Add-Ons
|
// Add-Ons
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -99,11 +99,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
|
|||||||
slots[slot].acquire_called = true;
|
slots[slot].acquire_called = true;
|
||||||
slots[slot].needs_cleanup_on_release = false;
|
slots[slot].needs_cleanup_on_release = false;
|
||||||
slots[slot].buffer_state = BufferState::Acquired;
|
slots[slot].buffer_state = BufferState::Acquired;
|
||||||
|
|
||||||
// TODO: for now, avoid resetting the fence, so that when we next return this
|
|
||||||
// slot to the producer, it will wait for the fence to pass. We should fix this
|
|
||||||
// by properly waiting for the fence in the BufferItemConsumer.
|
|
||||||
// slots[slot].fence = Fence::NoFence();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to
|
// If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -17,6 +17,39 @@ BufferQueueCore::BufferQueueCore() = default;
|
|||||||
|
|
||||||
BufferQueueCore::~BufferQueueCore() = default;
|
BufferQueueCore::~BufferQueueCore() = default;
|
||||||
|
|
||||||
|
void BufferQueueCore::PushHistory(u64 frame_number, s64 queue_time, s64 presentation_time, BufferState state) {
|
||||||
|
std::lock_guard lk(buffer_history_mutex);
|
||||||
|
|
||||||
|
auto it = buffer_history_map.find(frame_number);
|
||||||
|
if (it != buffer_history_map.end()) {
|
||||||
|
it->second.state = state;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_history_map.emplace(frame_number, BufferHistoryInfo{
|
||||||
|
frame_number,
|
||||||
|
queue_time,
|
||||||
|
presentation_time,
|
||||||
|
state
|
||||||
|
});
|
||||||
|
buffer_history_order.push_back(frame_number);
|
||||||
|
|
||||||
|
if (buffer_history_order.size() > BUFFER_HISTORY_SIZE) {
|
||||||
|
u64 oldest_frame = buffer_history_order.front();
|
||||||
|
buffer_history_order.pop_front();
|
||||||
|
buffer_history_map.erase(oldest_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferQueueCore::UpdateHistory(u64 frame_number, BufferState state) {
|
||||||
|
std::lock_guard lk(buffer_history_mutex);
|
||||||
|
|
||||||
|
auto it = buffer_history_map.find(frame_number);
|
||||||
|
if (it != buffer_history_map.end()) {
|
||||||
|
it->second.state = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BufferQueueCore::SignalDequeueCondition() {
|
void BufferQueueCore::SignalDequeueCondition() {
|
||||||
dequeue_possible.store(true);
|
dequeue_possible.store(true);
|
||||||
dequeue_condition.notify_all();
|
dequeue_condition.notify_all();
|
||||||
@@ -30,7 +63,6 @@ bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const {
|
s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const {
|
||||||
// If DequeueBuffer is allowed to error out, we don't have to add an extra buffer.
|
|
||||||
if (!use_async_buffer) {
|
if (!use_async_buffer) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -55,8 +87,6 @@ s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const {
|
|||||||
return override_max_buffer_count;
|
return override_max_buffer_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed
|
|
||||||
// need to have their slots preserved.
|
|
||||||
for (s32 slot = max_buffer_count; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
|
for (s32 slot = max_buffer_count; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
|
||||||
const auto state = slots[slot].buffer_state;
|
const auto state = slots[slot].buffer_state;
|
||||||
if (state == BufferState::Queued || state == BufferState::Dequeued) {
|
if (state == BufferState::Queued || state == BufferState::Dequeued) {
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -10,20 +10,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <deque>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "core/hle/service/nvnflinger/buffer_item.h"
|
#include "core/hle/service/nvnflinger/buffer_item.h"
|
||||||
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
|
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
|
||||||
|
#include "core/hle/service/nvnflinger/buffer_slot.h"
|
||||||
#include "core/hle/service/nvnflinger/pixel_format.h"
|
#include "core/hle/service/nvnflinger/pixel_format.h"
|
||||||
#include "core/hle/service/nvnflinger/status.h"
|
#include "core/hle/service/nvnflinger/status.h"
|
||||||
#include "core/hle/service/nvnflinger/window.h"
|
#include "core/hle/service/nvnflinger/window.h"
|
||||||
|
|
||||||
namespace Service::android {
|
namespace Service::android {
|
||||||
|
|
||||||
|
struct BufferHistoryInfo {
|
||||||
|
u64 frame_number{};
|
||||||
|
s64 queue_time{};
|
||||||
|
s64 presentation_time{};
|
||||||
|
BufferState state{};
|
||||||
|
};
|
||||||
|
|
||||||
class IConsumerListener;
|
class IConsumerListener;
|
||||||
class IProducerListener;
|
class IProducerListener;
|
||||||
|
|
||||||
@@ -33,10 +44,14 @@ class BufferQueueCore final {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT;
|
static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT;
|
||||||
|
static constexpr u32 BUFFER_HISTORY_SIZE = 8;
|
||||||
|
|
||||||
BufferQueueCore();
|
BufferQueueCore();
|
||||||
~BufferQueueCore();
|
~BufferQueueCore();
|
||||||
|
|
||||||
|
void PushHistory(u64 frame_number, s64 queue_time, s64 presentation_time, BufferState state);
|
||||||
|
void UpdateHistory(u64 frame_number, BufferState state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SignalDequeueCondition();
|
void SignalDequeueCondition();
|
||||||
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
|
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
|
||||||
@@ -72,6 +87,11 @@ private:
|
|||||||
const s32 max_acquired_buffer_count{}; // This is always zero on HOS
|
const s32 max_acquired_buffer_count{}; // This is always zero on HOS
|
||||||
bool buffer_has_been_queued{};
|
bool buffer_has_been_queued{};
|
||||||
u64 frame_counter{};
|
u64 frame_counter{};
|
||||||
|
|
||||||
|
std::unordered_map<u64, BufferHistoryInfo> buffer_history_map{};
|
||||||
|
mutable std::mutex buffer_history_mutex{};
|
||||||
|
std::deque<u64> buffer_history_order;
|
||||||
|
|
||||||
u32 transform_hint{};
|
u32 transform_hint{};
|
||||||
bool is_allocating{};
|
bool is_allocating{};
|
||||||
mutable std::condition_variable_any is_allocating_condition;
|
mutable std::condition_variable_any is_allocating_condition;
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
#include "core/hle/kernel/k_readable_event.h"
|
#include "core/hle/kernel/k_readable_event.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
@@ -26,7 +27,7 @@ BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext&
|
|||||||
std::shared_ptr<BufferQueueCore> buffer_queue_core_,
|
std::shared_ptr<BufferQueueCore> buffer_queue_core_,
|
||||||
Service::Nvidia::NvCore::NvMap& nvmap_)
|
Service::Nvidia::NvCore::NvMap& nvmap_)
|
||||||
: service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots),
|
: service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots),
|
||||||
nvmap(nvmap_) {
|
clock{Common::CreateOptimalClock()}, nvmap(nvmap_) {
|
||||||
buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent");
|
buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,8 +429,7 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
|
|||||||
return return_flags;
|
return return_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, QueueBufferOutput* output) {
|
||||||
QueueBufferOutput* output) {
|
|
||||||
s64 timestamp{};
|
s64 timestamp{};
|
||||||
bool is_auto_timestamp{};
|
bool is_auto_timestamp{};
|
||||||
Common::Rectangle<s32> crop;
|
Common::Rectangle<s32> crop;
|
||||||
@@ -440,8 +440,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
|||||||
s32 swap_interval{};
|
s32 swap_interval{};
|
||||||
Fence fence{};
|
Fence fence{};
|
||||||
|
|
||||||
input.Deflate(×tamp, &is_auto_timestamp, &crop, &scaling_mode, &transform,
|
input.Deflate(×tamp, &is_auto_timestamp, &crop, &scaling_mode, &transform, &sticky_transform_, &async, &swap_interval, &fence);
|
||||||
&sticky_transform_, &async, &swap_interval, &fence);
|
|
||||||
|
|
||||||
switch (scaling_mode) {
|
switch (scaling_mode) {
|
||||||
case NativeWindowScalingMode::Freeze:
|
case NativeWindowScalingMode::Freeze:
|
||||||
@@ -455,10 +454,9 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
|||||||
return Status::BadValue;
|
return Status::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IConsumerListener> frame_available_listener;
|
|
||||||
std::shared_ptr<IConsumerListener> frame_replaced_listener;
|
|
||||||
s32 callback_ticket{};
|
|
||||||
BufferItem item;
|
BufferItem item;
|
||||||
|
std::shared_ptr<IConsumerListener> listener_available;
|
||||||
|
std::shared_ptr<IConsumerListener> listener_replaced;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{core->mutex};
|
std::scoped_lock lock{core->mutex};
|
||||||
@@ -469,127 +467,82 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
|
const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
|
||||||
if (async && core->override_max_buffer_count) {
|
|
||||||
if (core->override_max_buffer_count < max_buffer_count) {
|
|
||||||
LOG_ERROR(Service_Nvnflinger, "async mode is invalid with "
|
|
||||||
"buffer count override");
|
|
||||||
return Status::BadValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slot < 0 || slot >= max_buffer_count) {
|
if (slot < 0 || slot >= max_buffer_count) {
|
||||||
LOG_ERROR(Service_Nvnflinger, "slot index {} out of range [0, {})", slot,
|
LOG_ERROR(Service_Nvnflinger, "slot {} out of range [0, {})", slot, max_buffer_count);
|
||||||
max_buffer_count);
|
|
||||||
return Status::BadValue;
|
return Status::BadValue;
|
||||||
} else if (slots[slot].buffer_state != BufferState::Dequeued) {
|
}
|
||||||
LOG_ERROR(Service_Nvnflinger,
|
if (slots[slot].buffer_state != BufferState::Dequeued) {
|
||||||
"slot {} is not owned by the producer "
|
LOG_ERROR(Service_Nvnflinger, "slot {} is not owned by producer", slot);
|
||||||
"(state = {})",
|
|
||||||
slot, slots[slot].buffer_state);
|
|
||||||
return Status::BadValue;
|
return Status::BadValue;
|
||||||
} else if (!slots[slot].request_buffer_called) {
|
}
|
||||||
LOG_ERROR(Service_Nvnflinger,
|
if (!slots[slot].request_buffer_called) {
|
||||||
"slot {} was queued without requesting "
|
LOG_ERROR(Service_Nvnflinger, "slot {} was queued without request", slot);
|
||||||
"a buffer",
|
|
||||||
slot);
|
|
||||||
return Status::BadValue;
|
return Status::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG(Service_Nvnflinger,
|
|
||||||
"slot={} frame={} time={} crop=[{},{},{},{}] transform={} scale={}", slot,
|
|
||||||
core->frame_counter + 1, timestamp, crop.Left(), crop.Top(), crop.Right(),
|
|
||||||
crop.Bottom(), transform, scaling_mode);
|
|
||||||
|
|
||||||
const std::shared_ptr<GraphicBuffer>& graphic_buffer(slots[slot].graphic_buffer);
|
|
||||||
Common::Rectangle<s32> buffer_rect(graphic_buffer->Width(), graphic_buffer->Height());
|
|
||||||
Common::Rectangle<s32> cropped_rect;
|
|
||||||
[[maybe_unused]] const bool unused = crop.Intersect(buffer_rect, &cropped_rect);
|
|
||||||
|
|
||||||
if (cropped_rect != crop) {
|
|
||||||
LOG_ERROR(Service_Nvnflinger, "crop rect is not contained within the buffer in slot {}",
|
|
||||||
slot);
|
|
||||||
return Status::BadValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
slots[slot].fence = fence;
|
|
||||||
slots[slot].buffer_state = BufferState::Queued;
|
|
||||||
++core->frame_counter;
|
++core->frame_counter;
|
||||||
|
slots[slot].buffer_state = BufferState::Queued;
|
||||||
slots[slot].frame_number = core->frame_counter;
|
slots[slot].frame_number = core->frame_counter;
|
||||||
|
slots[slot].queue_time = timestamp;
|
||||||
|
slots[slot].presentation_time = clock->GetTimeNS().count();
|
||||||
|
slots[slot].fence = fence;
|
||||||
|
|
||||||
item.acquire_called = slots[slot].acquire_called;
|
item.slot = slot;
|
||||||
item.graphic_buffer = slots[slot].graphic_buffer;
|
item.graphic_buffer = slots[slot].graphic_buffer;
|
||||||
item.crop = crop;
|
item.frame_number = core->frame_counter;
|
||||||
item.transform = transform & ~NativeWindowTransform::InverseDisplay;
|
|
||||||
item.transform_to_display_inverse =
|
|
||||||
(transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None;
|
|
||||||
item.scaling_mode = static_cast<u32>(scaling_mode);
|
|
||||||
item.timestamp = timestamp;
|
item.timestamp = timestamp;
|
||||||
item.is_auto_timestamp = is_auto_timestamp;
|
item.is_auto_timestamp = is_auto_timestamp;
|
||||||
item.frame_number = core->frame_counter;
|
item.crop = crop;
|
||||||
item.slot = slot;
|
item.transform = transform & ~NativeWindowTransform::InverseDisplay;
|
||||||
|
item.transform_to_display_inverse = (transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None;
|
||||||
|
item.scaling_mode = static_cast<u32>(scaling_mode);
|
||||||
item.fence = fence;
|
item.fence = fence;
|
||||||
item.is_droppable = core->dequeue_buffer_cannot_block || async;
|
item.is_droppable = core->dequeue_buffer_cannot_block || async;
|
||||||
item.swap_interval = swap_interval;
|
item.swap_interval = swap_interval;
|
||||||
|
item.acquire_called = slots[slot].acquire_called;
|
||||||
|
|
||||||
sticky_transform = sticky_transform_;
|
sticky_transform = sticky_transform_;
|
||||||
|
|
||||||
if (core->queue.empty()) {
|
if (core->queue.empty()) {
|
||||||
// When the queue is empty, we can simply queue this buffer
|
|
||||||
core->queue.push_back(item);
|
core->queue.push_back(item);
|
||||||
frame_available_listener = core->consumer_listener;
|
listener_available = core->consumer_listener;
|
||||||
} else {
|
} else {
|
||||||
// When the queue is not empty, we need to look at the front buffer
|
auto front = core->queue.begin();
|
||||||
// state to see if we need to replace it
|
if (front->is_droppable && core->StillTracking(*front)) {
|
||||||
auto front(core->queue.begin());
|
slots[front->slot].buffer_state = BufferState::Free;
|
||||||
|
if (Settings::values.enable_buffer_history.GetValue()) {
|
||||||
|
core->UpdateHistory(front->frame_number, BufferState::Free);
|
||||||
|
}
|
||||||
|
slots[front->slot].frame_number = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (front->is_droppable) {
|
if (front->is_droppable) {
|
||||||
// If the front queued buffer is still being tracked, we first
|
|
||||||
// mark it as freed
|
|
||||||
if (core->StillTracking(*front)) {
|
|
||||||
slots[front->slot].buffer_state = BufferState::Free;
|
|
||||||
// Reset the frame number of the freed buffer so that it is the first in line to
|
|
||||||
// be dequeued again
|
|
||||||
slots[front->slot].frame_number = 0;
|
|
||||||
}
|
|
||||||
// Overwrite the droppable buffer with the incoming one
|
|
||||||
*front = item;
|
*front = item;
|
||||||
frame_replaced_listener = core->consumer_listener;
|
listener_replaced = core->consumer_listener;
|
||||||
} else {
|
} else {
|
||||||
core->queue.push_back(item);
|
core->queue.push_back(item);
|
||||||
frame_available_listener = core->consumer_listener;
|
listener_available = core->consumer_listener;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings::values.enable_buffer_history.GetValue()) {
|
||||||
|
core->PushHistory(core->frame_counter, slots[slot].queue_time, slots[slot].presentation_time, BufferState::Queued);
|
||||||
|
}
|
||||||
|
|
||||||
core->buffer_has_been_queued = true;
|
core->buffer_has_been_queued = true;
|
||||||
core->SignalDequeueCondition();
|
core->SignalDequeueCondition();
|
||||||
output->Inflate(core->default_width, core->default_height, core->transform_hint,
|
|
||||||
static_cast<u32>(core->queue.size()));
|
|
||||||
|
|
||||||
// Take a ticket for the callback functions
|
output->Inflate(core->default_width, core->default_height, core->transform_hint, static_cast<u32>(core->queue.size()));
|
||||||
callback_ticket = next_callback_ticket++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't send the GraphicBuffer through the callback, and don't send the slot number, since the
|
|
||||||
// consumer shouldn't need it
|
|
||||||
item.graphic_buffer.reset();
|
item.graphic_buffer.reset();
|
||||||
item.slot = BufferItem::INVALID_BUFFER_SLOT;
|
item.slot = BufferItem::INVALID_BUFFER_SLOT;
|
||||||
|
|
||||||
// Call back without the main BufferQueue lock held, but with the callback lock held so we can
|
if (listener_available) {
|
||||||
// ensure that callbacks occur in order
|
listener_available->OnFrameAvailable(item);
|
||||||
{
|
} else if (listener_replaced) {
|
||||||
std::scoped_lock lock{callback_mutex};
|
listener_replaced->OnFrameReplaced(item);
|
||||||
while (callback_ticket != current_callback_ticket) {
|
|
||||||
callback_condition.wait(callback_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame_available_listener != nullptr) {
|
|
||||||
frame_available_listener->OnFrameAvailable(item);
|
|
||||||
} else if (frame_replaced_listener != nullptr) {
|
|
||||||
frame_replaced_listener->OnFrameReplaced(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
++current_callback_ticket;
|
|
||||||
callback_condition.notify_all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status::NoError;
|
return Status::NoError;
|
||||||
@@ -810,6 +763,10 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
|
|||||||
return Status::NoError;
|
return Status::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) {
|
||||||
|
return &buffer_wait_event->GetReadableEvent();
|
||||||
|
}
|
||||||
|
|
||||||
void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
|
void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
|
||||||
std::span<u8> parcel_reply, u32 flags) {
|
std::span<u8> parcel_reply, u32 flags) {
|
||||||
// Values used by BnGraphicBufferProducer onTransact
|
// Values used by BnGraphicBufferProducer onTransact
|
||||||
@@ -929,9 +886,42 @@ void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
|
|||||||
status = SetBufferCount(buffer_count);
|
status = SetBufferCount(buffer_count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TransactionId::GetBufferHistory:
|
case TransactionId::GetBufferHistory: {
|
||||||
LOG_DEBUG(Service_Nvnflinger, "(STUBBED) called, transaction=GetBufferHistory");
|
if (!Settings::values.enable_buffer_history.GetValue()) {
|
||||||
|
LOG_DEBUG(Service_Nvnflinger, "(STUBBED) called");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Nvnflinger, "called, transaction=GetBufferHistory");
|
||||||
|
|
||||||
|
const s32 request = parcel_in.Read<s32>();
|
||||||
|
if (request <= 0) {
|
||||||
|
parcel_out.Write(Status::BadValue);
|
||||||
|
parcel_out.Write<s32>(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<BufferHistoryInfo> snapshot;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(core->buffer_history_mutex);
|
||||||
|
for (auto& [frame, info] : core->buffer_history_map) {
|
||||||
|
snapshot.push_back(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(snapshot.begin(), snapshot.end(), [](auto& a, auto& b){
|
||||||
|
return a.frame_number > b.frame_number;
|
||||||
|
});
|
||||||
|
|
||||||
|
const s32 limit = std::min(request, (s32)snapshot.size());
|
||||||
|
parcel_out.Write(Status::NoError);
|
||||||
|
parcel_out.Write<s32>(limit);
|
||||||
|
for (s32 i = 0; i < limit; ++i) {
|
||||||
|
parcel_out.Write(snapshot[i]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ASSERT_MSG(false, "Unimplemented TransactionId {}", code);
|
ASSERT_MSG(false, "Unimplemented TransactionId {}", code);
|
||||||
break;
|
break;
|
||||||
@@ -944,8 +934,4 @@ void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
|
|||||||
(std::min)(parcel_reply.size(), serialized.size()));
|
(std::min)(parcel_reply.size(), serialized.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) {
|
|
||||||
return &buffer_wait_event->GetReadableEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::android
|
} // namespace Service::android
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/wall_clock.h"
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
#include "core/hle/service/nvnflinger/binder.h"
|
#include "core/hle/service/nvnflinger/binder.h"
|
||||||
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
|
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
|
||||||
@@ -88,6 +89,7 @@ private:
|
|||||||
s32 next_callback_ticket{};
|
s32 next_callback_ticket{};
|
||||||
s32 current_callback_ticket{};
|
s32 current_callback_ticket{};
|
||||||
std::condition_variable_any callback_condition;
|
std::condition_variable_any callback_condition;
|
||||||
|
std::unique_ptr<Common::WallClock> clock;
|
||||||
|
|
||||||
Service::Nvidia::NvCore::NvMap& nvmap;
|
Service::Nvidia::NvCore::NvMap& nvmap;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -37,6 +37,7 @@ struct BufferSlot final {
|
|||||||
bool needs_cleanup_on_release{};
|
bool needs_cleanup_on_release{};
|
||||||
bool attached_by_consumer{};
|
bool attached_by_consumer{};
|
||||||
bool is_preallocated{};
|
bool is_preallocated{};
|
||||||
|
s64 queue_time{}, presentation_time{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::android
|
} // namespace Service::android
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
@@ -12,7 +12,8 @@ add_library(frontend_common STATIC
|
|||||||
firmware_manager.cpp
|
firmware_manager.cpp
|
||||||
data_manager.h data_manager.cpp
|
data_manager.h data_manager.cpp
|
||||||
play_time_manager.cpp
|
play_time_manager.cpp
|
||||||
play_time_manager.h)
|
play_time_manager.h
|
||||||
|
settings_generator.h settings_generator.cpp)
|
||||||
|
|
||||||
if (ENABLE_UPDATE_CHECKER)
|
if (ENABLE_UPDATE_CHECKER)
|
||||||
target_link_libraries(frontend_common PRIVATE httplib::httplib)
|
target_link_libraries(frontend_common PRIVATE httplib::httplib)
|
||||||
@@ -29,4 +30,6 @@ if (ENABLE_UPDATE_CHECKER)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(frontend_common)
|
create_target_directory_groups(frontend_common)
|
||||||
target_link_libraries(frontend_common PUBLIC core SimpleIni::SimpleIni PRIVATE common Boost::headers)
|
target_link_libraries(frontend_common
|
||||||
|
PUBLIC core SimpleIni::SimpleIni frozen::frozen-headers
|
||||||
|
PRIVATE common Boost::headers)
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include <frozen/string.h>
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "settings_generator.h"
|
||||||
|
|
||||||
|
namespace FrontendCommon {
|
||||||
|
|
||||||
|
void GenerateSettings() {
|
||||||
|
static std::random_device rd;
|
||||||
|
|
||||||
|
// Web Token //
|
||||||
|
auto &token_setting = Settings::values.eden_token;
|
||||||
|
if (token_setting.GetValue().empty()) {
|
||||||
|
static constexpr const size_t token_length = 48;
|
||||||
|
static constexpr const frozen::string token_set = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
static std::uniform_int_distribution<int> token_dist(0, token_set.size() - 1);
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < token_length; ++i) {
|
||||||
|
size_t idx = token_dist(rd);
|
||||||
|
result += token_set[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
token_setting.SetValue(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace FrontendCommon {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GenerateSettings Generate platform-specific or randomized settings.
|
||||||
|
* Run this function at initialization time for your frontend.
|
||||||
|
*/
|
||||||
|
void GenerateSettings();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -78,12 +78,9 @@ target_compile_definitions(qt_common PUBLIC
|
|||||||
QT_NO_URL_CAST_FROM_STRING
|
QT_NO_URL_CAST_FROM_STRING
|
||||||
)
|
)
|
||||||
|
|
||||||
# pass targets
|
|
||||||
find_package(frozen)
|
|
||||||
|
|
||||||
target_link_libraries(qt_common PRIVATE core Qt6::Core Qt6::Concurrent SimpleIni::SimpleIni QuaZip::QuaZip)
|
target_link_libraries(qt_common PRIVATE core Qt6::Core Qt6::Concurrent SimpleIni::SimpleIni QuaZip::QuaZip)
|
||||||
target_link_libraries(qt_common PUBLIC frozen::frozen-headers)
|
target_link_libraries(qt_common PUBLIC frozen::frozen-headers)
|
||||||
target_link_libraries(qt_common PRIVATE gamemode::headers)
|
target_link_libraries(qt_common PRIVATE gamemode::headers frontend_common)
|
||||||
|
|
||||||
if (NOT APPLE AND ENABLE_OPENGL)
|
if (NOT APPLE AND ENABLE_OPENGL)
|
||||||
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
|
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
|
||||||
|
|||||||
@@ -329,6 +329,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||||||
barrier_feedback_loops,
|
barrier_feedback_loops,
|
||||||
tr("Barrier feedback loops"),
|
tr("Barrier feedback loops"),
|
||||||
tr("Improves rendering of transparency effects in specific games."));
|
tr("Improves rendering of transparency effects in specific games."));
|
||||||
|
INSERT(Settings,
|
||||||
|
enable_buffer_history,
|
||||||
|
tr("Enable buffer history"),
|
||||||
|
tr("Enables access to previous buffer states.\nThis option may improve rendering quality and performance consistency in some games."));
|
||||||
INSERT(Settings,
|
INSERT(Settings,
|
||||||
fix_bloom_effects,
|
fix_bloom_effects,
|
||||||
tr("Fix bloom effects"),
|
tr("Fix bloom effects"),
|
||||||
|
|||||||
@@ -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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -148,10 +151,13 @@ Id EmitConvertU32U64(EmitContext& ctx, Id value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitConvertF16F32(EmitContext& ctx, Id value) {
|
Id EmitConvertF16F32(EmitContext& ctx, Id value) {
|
||||||
|
#ifdef ANDROID
|
||||||
|
return ctx.OpFConvert(ctx.F16[1], value);
|
||||||
|
#else
|
||||||
const auto result = ctx.OpFConvert(ctx.F16[1], value);
|
const auto result = ctx.OpFConvert(ctx.F16[1], value);
|
||||||
const auto isOverflowing = ctx.OpIsNan(ctx.U1, result);
|
const auto isOverflowing = ctx.OpIsNan(ctx.U1, result);
|
||||||
return ctx.OpSelect(ctx.F16[1], isOverflowing, ctx.Constant(ctx.F16[1], 0), result);
|
return ctx.OpSelect(ctx.F16[1], isOverflowing, ctx.Constant(ctx.F16[1], 0), result);
|
||||||
//return ctx.OpFConvert(ctx.F16[1], value);
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitConvertF32F16(EmitContext& ctx, Id value) {
|
Id EmitConvertF32F16(EmitContext& ctx, Id value) {
|
||||||
|
|||||||
@@ -36,12 +36,6 @@ struct EncodingData {
|
|||||||
uint data;
|
uint data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PartitionTable {
|
|
||||||
uint s1, s2, s3, s4, s5, s6, s7, s8;
|
|
||||||
uint rnum;
|
|
||||||
bool small_block;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(binding = BINDING_INPUT_BUFFER, std430) readonly restrict buffer InputBufferU32 {
|
layout(binding = BINDING_INPUT_BUFFER, std430) readonly restrict buffer InputBufferU32 {
|
||||||
uvec4 astc_data[];
|
uvec4 astc_data[];
|
||||||
};
|
};
|
||||||
@@ -68,40 +62,26 @@ const uint encoding_values[22] = uint[](
|
|||||||
(QUINT | (4u << 8u)), (TRIT | (5u << 8u)), (JUST_BITS | (7u << 8u)), (QUINT | (5u << 8u)),
|
(QUINT | (4u << 8u)), (TRIT | (5u << 8u)), (JUST_BITS | (7u << 8u)), (QUINT | (5u << 8u)),
|
||||||
(TRIT | (6u << 8u)), (JUST_BITS | (8u << 8u)));
|
(TRIT | (6u << 8u)), (JUST_BITS | (8u << 8u)));
|
||||||
|
|
||||||
// Shared memory for workgroup processing
|
// Input ASTC texture globals
|
||||||
shared uvec4 local_buff;
|
int total_bitsread = 0;
|
||||||
shared int total_bitsread;
|
uvec4 local_buff;
|
||||||
|
|
||||||
// Color data globals
|
// Color data globals
|
||||||
shared uvec4 color_endpoint_data;
|
uvec4 color_endpoint_data;
|
||||||
shared int color_bitsread;
|
int color_bitsread = 0;
|
||||||
|
|
||||||
// Global "vector" to be pushed into when decoding
|
// Global "vector" to be pushed into when decoding
|
||||||
|
// At most will require BLOCK_WIDTH x BLOCK_HEIGHT in single plane mode
|
||||||
|
// At most will require BLOCK_WIDTH x BLOCK_HEIGHT x 2 in dual plane mode
|
||||||
|
// So the maximum would be 144 (12 x 12) elements, x 2 for two planes
|
||||||
#define DIVCEIL(number, divisor) (number + divisor - 1) / divisor
|
#define DIVCEIL(number, divisor) (number + divisor - 1) / divisor
|
||||||
#define ARRAY_NUM_ELEMENTS 144
|
#define ARRAY_NUM_ELEMENTS 144
|
||||||
#define VECTOR_ARRAY_SIZE DIVCEIL(ARRAY_NUM_ELEMENTS * 2, 4)
|
#define VECTOR_ARRAY_SIZE DIVCEIL(ARRAY_NUM_ELEMENTS * 2, 4)
|
||||||
shared uint result_vector[ARRAY_NUM_ELEMENTS * 2];
|
uint result_vector[ARRAY_NUM_ELEMENTS * 2];
|
||||||
|
|
||||||
shared int result_index;
|
int result_index = 0;
|
||||||
shared uint result_vector_max_index;
|
uint result_vector_max_index;
|
||||||
shared bool result_limit_reached;
|
bool result_limit_reached = false;
|
||||||
|
|
||||||
// avoid intermediate result_vector storage during color decode phase
|
|
||||||
shared bool write_color_values;
|
|
||||||
shared uint color_values_direct[32];
|
|
||||||
shared uint color_out_index;
|
|
||||||
shared uint color_num_values;
|
|
||||||
|
|
||||||
// Shared variables for DecompressBlock interthread communication
|
|
||||||
shared uvec4 endpoints0[4];
|
|
||||||
shared uvec4 endpoints1[4];
|
|
||||||
shared PartitionTable pt;
|
|
||||||
shared uvec2 size_params;
|
|
||||||
shared uint num_partitions;
|
|
||||||
shared uint partition_index;
|
|
||||||
shared uint plane_index;
|
|
||||||
shared bool dual_plane;
|
|
||||||
shared vec4 fill_color;
|
|
||||||
|
|
||||||
// EncodingData helpers
|
// EncodingData helpers
|
||||||
uint Encoding(EncodingData val) {
|
uint Encoding(EncodingData val) {
|
||||||
@@ -134,110 +114,9 @@ EncodingData CreateEncodingData(uint encoding, uint num_bits, uint bit_val, uint
|
|||||||
return EncodingData(((encoding) << 0u) | ((num_bits) << 8u) |
|
return EncodingData(((encoding) << 0u) | ((num_bits) << 8u) |
|
||||||
((bit_val) << 16u) | ((quint_trit_val) << 24u));
|
((bit_val) << 16u) | ((quint_trit_val) << 24u));
|
||||||
}
|
}
|
||||||
uint ReplicateBitTo9(uint bit);
|
|
||||||
uint FastReplicateTo8(uint value, uint num_bits);
|
|
||||||
|
|
||||||
void EmitColorValue(EncodingData val) {
|
|
||||||
// write directly to color_values_direct[]
|
|
||||||
const uint encoding = Encoding(val);
|
|
||||||
const uint bitlen = NumBits(val);
|
|
||||||
const uint bitval = BitValue(val);
|
|
||||||
|
|
||||||
if (encoding == JUST_BITS) {
|
|
||||||
color_values_direct[++color_out_index] = FastReplicateTo8(bitval, bitlen);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint A = ReplicateBitTo9((bitval & 1));
|
|
||||||
uint B = 0, C = 0, D = QuintTritValue(val);
|
|
||||||
|
|
||||||
if (encoding == TRIT) {
|
|
||||||
switch (bitlen) {
|
|
||||||
case 1:
|
|
||||||
C = 204;
|
|
||||||
break;
|
|
||||||
case 2: {
|
|
||||||
C = 93;
|
|
||||||
const uint b = (bitval >> 1) & 1;
|
|
||||||
B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
C = 44;
|
|
||||||
const uint cb = (bitval >> 1) & 3;
|
|
||||||
B = (cb << 7) | (cb << 2) | cb;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4: {
|
|
||||||
C = 22;
|
|
||||||
const uint dcb = (bitval >> 1) & 7;
|
|
||||||
B = (dcb << 6) | dcb;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 5: {
|
|
||||||
C = 11;
|
|
||||||
const uint edcb = (bitval >> 1) & 0xF;
|
|
||||||
B = (edcb << 5) | (edcb >> 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 6: {
|
|
||||||
C = 5;
|
|
||||||
const uint fedcb = (bitval >> 1) & 0x1F;
|
|
||||||
B = (fedcb << 4) | (fedcb >> 4);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // QUINT
|
|
||||||
switch (bitlen) {
|
|
||||||
case 1:
|
|
||||||
C = 113;
|
|
||||||
break;
|
|
||||||
case 2: {
|
|
||||||
C = 54;
|
|
||||||
const uint b = (bitval >> 1) & 1;
|
|
||||||
B = (b << 8) | (b << 3) | (b << 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
C = 26;
|
|
||||||
const uint cb = (bitval >> 1) & 3;
|
|
||||||
B = (cb << 7) | (cb << 1) | (cb >> 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4: {
|
|
||||||
C = 13;
|
|
||||||
const uint dcb = (bitval >> 1) & 7;
|
|
||||||
B = (dcb << 6) | (dcb >> 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 5: {
|
|
||||||
C = 6;
|
|
||||||
const uint edcb = (bitval >> 1) & 0xF;
|
|
||||||
B = (edcb << 5) | (edcb >> 3);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint T = (D * C) + B;
|
|
||||||
T ^= A;
|
|
||||||
T = (A & 0x80) | (T >> 2);
|
|
||||||
color_values_direct[++color_out_index] = T;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ResultEmplaceBack(EncodingData val) {
|
void ResultEmplaceBack(EncodingData val) {
|
||||||
if (write_color_values) {
|
|
||||||
if (color_out_index >= color_num_values) {
|
|
||||||
// avoid decoding more than needed by this phase
|
|
||||||
result_limit_reached = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EmitColorValue(val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result_index >= result_vector_max_index) {
|
if (result_index >= result_vector_max_index) {
|
||||||
// Alert callers to avoid decoding more than needed by this phase
|
// Alert callers to avoid decoding more than needed by this phase
|
||||||
result_limit_reached = true;
|
result_limit_reached = true;
|
||||||
@@ -318,31 +197,32 @@ uint Hash52(uint p) {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint Select2DPartition(uint seed, uint x, uint y, uint partition_count) {
|
||||||
PartitionTable GetPartitionTable(uint seed, uint partition_count) {
|
if ((block_dims.y * block_dims.x) < 32) {
|
||||||
PartitionTable pt;
|
x <<= 1;
|
||||||
pt.small_block = (block_dims.y * block_dims.x) < 32;
|
y <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
seed += (partition_count - 1) * 1024;
|
seed += (partition_count - 1) * 1024;
|
||||||
uint rnum = Hash52(uint(seed));
|
|
||||||
pt.rnum = rnum;
|
|
||||||
|
|
||||||
uint seed1 = (rnum & 0xF);
|
const uint rnum = Hash52(uint(seed));
|
||||||
seed1 *= seed1;
|
uint seed1 = uint(rnum & 0xF);
|
||||||
uint seed2 = (rnum >> 4) & 0xF;
|
uint seed2 = uint((rnum >> 4) & 0xF);
|
||||||
seed2 *= seed2;
|
uint seed3 = uint((rnum >> 8) & 0xF);
|
||||||
uint seed3 = (rnum >> 8) & 0xF;
|
uint seed4 = uint((rnum >> 12) & 0xF);
|
||||||
seed3 *= seed3;
|
uint seed5 = uint((rnum >> 16) & 0xF);
|
||||||
uint seed4 = (rnum >> 12) & 0xF;
|
uint seed6 = uint((rnum >> 20) & 0xF);
|
||||||
seed4 *= seed4;
|
uint seed7 = uint((rnum >> 24) & 0xF);
|
||||||
uint seed5 = (rnum >> 16) & 0xF;
|
uint seed8 = uint((rnum >> 28) & 0xF);
|
||||||
seed5 *= seed5;
|
|
||||||
uint seed6 = (rnum >> 20) & 0xF;
|
seed1 = (seed1 * seed1);
|
||||||
seed6 *= seed6;
|
seed2 = (seed2 * seed2);
|
||||||
uint seed7 = (rnum >> 24) & 0xF;
|
seed3 = (seed3 * seed3);
|
||||||
seed7 *= seed7;
|
seed4 = (seed4 * seed4);
|
||||||
uint seed8 = (rnum >> 28) & 0xF;
|
seed5 = (seed5 * seed5);
|
||||||
seed8 *= seed8;
|
seed6 = (seed6 * seed6);
|
||||||
|
seed7 = (seed7 * seed7);
|
||||||
|
seed8 = (seed8 * seed8);
|
||||||
|
|
||||||
uint sh1, sh2;
|
uint sh1, sh2;
|
||||||
if ((seed & 1) > 0) {
|
if ((seed & 1) > 0) {
|
||||||
@@ -352,37 +232,31 @@ PartitionTable GetPartitionTable(uint seed, uint partition_count) {
|
|||||||
sh1 = (partition_count == 3) ? 6 : 5;
|
sh1 = (partition_count == 3) ? 6 : 5;
|
||||||
sh2 = (seed & 2) > 0 ? 4 : 5;
|
sh2 = (seed & 2) > 0 ? 4 : 5;
|
||||||
}
|
}
|
||||||
|
seed1 >>= sh1;
|
||||||
|
seed2 >>= sh2;
|
||||||
|
seed3 >>= sh1;
|
||||||
|
seed4 >>= sh2;
|
||||||
|
seed5 >>= sh1;
|
||||||
|
seed6 >>= sh2;
|
||||||
|
seed7 >>= sh1;
|
||||||
|
seed8 >>= sh2;
|
||||||
|
|
||||||
pt.s1 = seed1 >> sh1;
|
uint a = seed1 * x + seed2 * y + (rnum >> 14);
|
||||||
pt.s2 = seed2 >> sh2;
|
uint b = seed3 * x + seed4 * y + (rnum >> 10);
|
||||||
pt.s3 = seed3 >> sh1;
|
uint c = seed5 * x + seed6 * y + (rnum >> 6);
|
||||||
pt.s4 = seed4 >> sh2;
|
uint d = seed7 * x + seed8 * y + (rnum >> 2);
|
||||||
pt.s5 = seed5 >> sh1;
|
|
||||||
pt.s6 = seed6 >> sh2;
|
|
||||||
pt.s7 = seed7 >> sh1;
|
|
||||||
pt.s8 = seed8 >> sh2;
|
|
||||||
|
|
||||||
return pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint SelectPartition(PartitionTable pt, uint x, uint y, uint partition_count) {
|
|
||||||
if (pt.small_block) {
|
|
||||||
x <<= 1;
|
|
||||||
y <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint a = pt.s1 * x + pt.s2 * y + (pt.rnum >> 14);
|
|
||||||
uint b = pt.s3 * x + pt.s4 * y + (pt.rnum >> 10);
|
|
||||||
uint c = pt.s5 * x + pt.s6 * y + (pt.rnum >> 6);
|
|
||||||
uint d = pt.s7 * x + pt.s8 * y + (pt.rnum >> 2);
|
|
||||||
|
|
||||||
a &= 0x3F;
|
a &= 0x3F;
|
||||||
b &= 0x3F;
|
b &= 0x3F;
|
||||||
c &= 0x3F;
|
c &= 0x3F;
|
||||||
d &= 0x3F;
|
d &= 0x3F;
|
||||||
|
|
||||||
if (partition_count < 4) d = 0;
|
if (partition_count < 4) {
|
||||||
if (partition_count < 3) c = 0;
|
d = 0;
|
||||||
|
}
|
||||||
|
if (partition_count < 3) {
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (a >= b && a >= c && a >= d) {
|
if (a >= b && a >= c && a >= d) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -583,7 +457,7 @@ void DecodeIntegerSequence(uint max_range, uint num_values) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits) {
|
void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits, out uint color_values[32]) {
|
||||||
uint num_values = 0;
|
uint num_values = 0;
|
||||||
for (uint i = 0; i < num_partitions; i++) {
|
for (uint i = 0; i < num_partitions; i++) {
|
||||||
num_values += ((modes[i] >> 2) + 1) << 1;
|
num_values += ((modes[i] >> 2) + 1) << 1;
|
||||||
@@ -597,21 +471,104 @@ void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Decode directly into color_values_direct[]
|
|
||||||
write_color_values = true;
|
|
||||||
color_out_index = 0;
|
|
||||||
color_num_values = num_values;
|
|
||||||
for (uint i = 0; i < 32; ++i) {
|
|
||||||
color_values_direct[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DecodeIntegerSequence(range - 1, num_values);
|
DecodeIntegerSequence(range - 1, num_values);
|
||||||
|
uint out_index = 0;
|
||||||
write_color_values = false;
|
for (int itr = 0; itr < result_index; ++itr) {
|
||||||
|
if (out_index >= num_values) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const EncodingData val = GetEncodingFromVector(itr);
|
||||||
|
const uint encoding = Encoding(val);
|
||||||
|
const uint bitlen = NumBits(val);
|
||||||
|
const uint bitval = BitValue(val);
|
||||||
|
uint A = 0, B = 0, C = 0, D = 0;
|
||||||
|
A = ReplicateBitTo9((bitval & 1));
|
||||||
|
switch (encoding) {
|
||||||
|
case JUST_BITS:
|
||||||
|
color_values[++out_index] = FastReplicateTo8(bitval, bitlen);
|
||||||
|
break;
|
||||||
|
case TRIT: {
|
||||||
|
D = QuintTritValue(val);
|
||||||
|
switch (bitlen) {
|
||||||
|
case 1:
|
||||||
|
C = 204;
|
||||||
|
break;
|
||||||
|
case 2: {
|
||||||
|
C = 93;
|
||||||
|
const uint b = (bitval >> 1) & 1;
|
||||||
|
B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
C = 44;
|
||||||
|
const uint cb = (bitval >> 1) & 3;
|
||||||
|
B = (cb << 7) | (cb << 2) | cb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
C = 22;
|
||||||
|
const uint dcb = (bitval >> 1) & 7;
|
||||||
|
B = (dcb << 6) | dcb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 5: {
|
||||||
|
C = 11;
|
||||||
|
const uint edcb = (bitval >> 1) & 0xF;
|
||||||
|
B = (edcb << 5) | (edcb >> 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
C = 5;
|
||||||
|
const uint fedcb = (bitval >> 1) & 0x1F;
|
||||||
|
B = (fedcb << 4) | (fedcb >> 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QUINT: {
|
||||||
|
D = QuintTritValue(val);
|
||||||
|
switch (bitlen) {
|
||||||
|
case 1:
|
||||||
|
C = 113;
|
||||||
|
break;
|
||||||
|
case 2: {
|
||||||
|
C = 54;
|
||||||
|
const uint b = (bitval >> 1) & 1;
|
||||||
|
B = (b << 8) | (b << 3) | (b << 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
C = 26;
|
||||||
|
const uint cb = (bitval >> 1) & 3;
|
||||||
|
B = (cb << 7) | (cb << 1) | (cb >> 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
C = 13;
|
||||||
|
const uint dcb = (bitval >> 1) & 7;
|
||||||
|
B = (dcb << 6) | (dcb >> 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 5: {
|
||||||
|
C = 6;
|
||||||
|
const uint edcb = (bitval >> 1) & 0xF;
|
||||||
|
B = (edcb << 5) | (edcb >> 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (encoding != JUST_BITS) {
|
||||||
|
uint T = (D * C) + B;
|
||||||
|
T ^= A;
|
||||||
|
T = (A & 0x80) | (T >> 2);
|
||||||
|
color_values[++out_index] = T;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ivec2 BitTransferSigned(int a, int b) {
|
ivec2 BitTransferSigned(int a, int b) {
|
||||||
ivec2 transferred;
|
ivec2 transferred;
|
||||||
transferred.y = b >> 1;
|
transferred.y = b >> 1;
|
||||||
@@ -773,7 +730,7 @@ uint UnquantizeTexelWeight(EncodingData val) {
|
|||||||
uint encoding = Encoding(val), bitlen = NumBits(val), bitval = BitValue(val);
|
uint encoding = Encoding(val), bitlen = NumBits(val), bitval = BitValue(val);
|
||||||
if (encoding == JUST_BITS) {
|
if (encoding == JUST_BITS) {
|
||||||
return (bitlen >= 1 && bitlen <= 5)
|
return (bitlen >= 1 && bitlen <= 5)
|
||||||
? ((bitval * 64) + ((1 << bitlen) - 1) / 2) / ((1 << bitlen) - 1)
|
? uint(floor(0.5f + float(bitval) * 64.0f / float((1 << bitlen) - 1)))
|
||||||
: FastReplicateTo6(bitval, bitlen);
|
: FastReplicateTo6(bitval, bitlen);
|
||||||
} else if (encoding == TRIT || encoding == QUINT) {
|
} else if (encoding == TRIT || encoding == QUINT) {
|
||||||
uint B = 0, C = 0, D = 0;
|
uint B = 0, C = 0, D = 0;
|
||||||
@@ -907,32 +864,27 @@ int FindLayout(uint mode) {
|
|||||||
|
|
||||||
|
|
||||||
void FillError(ivec3 coord) {
|
void FillError(ivec3 coord) {
|
||||||
const uint total_texels = block_dims.x * block_dims.y;
|
for (uint j = 0; j < block_dims.y; j++) {
|
||||||
for (uint tid = gl_LocalInvocationIndex; tid < total_texels; tid += gl_WorkGroupSize.x * gl_WorkGroupSize.y) {
|
for (uint i = 0; i < block_dims.x; i++) {
|
||||||
uint x = tid % block_dims.x;
|
imageStore(dest_image, coord + ivec3(i, j, 0), vec4(0.0, 0.0, 0.0, 0.0));
|
||||||
uint y = tid / block_dims.x;
|
}
|
||||||
imageStore(dest_image, coord + ivec3(x, y, 0), vec4(0.0, 0.0, 0.0, 0.0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillVoidExtentLDR(ivec3 coord) {
|
void FillVoidExtentLDR(ivec3 coord) {
|
||||||
// Thread 0 decodes color
|
SkipBits(52);
|
||||||
|
const uint r_u = StreamBits(16);
|
||||||
if (gl_LocalInvocationIndex == 0) {
|
const uint g_u = StreamBits(16);
|
||||||
SkipBits(52);
|
const uint b_u = StreamBits(16);
|
||||||
const uint r_u = StreamBits(16);
|
const uint a_u = StreamBits(16);
|
||||||
const uint g_u = StreamBits(16);
|
const float a = float(a_u) / 65535.0f;
|
||||||
const uint b_u = StreamBits(16);
|
const float r = float(r_u) / 65535.0f;
|
||||||
const uint a_u = StreamBits(16);
|
const float g = float(g_u) / 65535.0f;
|
||||||
fill_color = vec4(float(r_u) / 65535.0f, float(g_u) / 65535.0f, float(b_u) / 65535.0f, float(a_u) / 65535.0f);
|
const float b = float(b_u) / 65535.0f;
|
||||||
}
|
for (uint j = 0; j < block_dims.y; j++) {
|
||||||
barrier();
|
for (uint i = 0; i < block_dims.x; i++) {
|
||||||
|
imageStore(dest_image, coord + ivec3(i, j, 0), vec4(r, g, b, a));
|
||||||
const uint total_texels = block_dims.x * block_dims.y;
|
}
|
||||||
for (uint tid = gl_LocalInvocationIndex; tid < total_texels; tid += gl_WorkGroupSize.x * gl_WorkGroupSize.y) {
|
|
||||||
uint x = tid % block_dims.x;
|
|
||||||
uint y = tid / block_dims.x;
|
|
||||||
imageStore(dest_image, coord + ivec3(x, y, 0), fill_color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,156 +966,160 @@ uint DecodeMaxWeight(uint mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DecompressBlock(ivec3 coord) {
|
void DecompressBlock(ivec3 coord) {
|
||||||
if (gl_LocalInvocationIndex == 0) {
|
uint mode = StreamBits(11);
|
||||||
uint mode = StreamBits(11);
|
if (IsError(mode)) {
|
||||||
bool early_exit = false;
|
|
||||||
if (IsError(mode)) {
|
|
||||||
size_params = uvec2(0);
|
|
||||||
early_exit = true;
|
|
||||||
} else if ((mode & 0x1ff) == 0x1fc) {
|
|
||||||
size_params = uvec2(0xFFFFFFFF);
|
|
||||||
early_exit = true;
|
|
||||||
} else {
|
|
||||||
size_params = DecodeBlockSize(mode);
|
|
||||||
if ((size_params.x > block_dims.x) || (size_params.y > block_dims.y)) {
|
|
||||||
size_params = uvec2(0);
|
|
||||||
early_exit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!early_exit) {
|
|
||||||
num_partitions = StreamBits(2) + 1;
|
|
||||||
uint mode_layout = FindLayout(mode);
|
|
||||||
dual_plane = (mode_layout != 9) && ((mode & 0x400) != 0);
|
|
||||||
if (num_partitions > 4 || (num_partitions == 4 && dual_plane)) {
|
|
||||||
size_params = uvec2(0);
|
|
||||||
early_exit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!early_exit) {
|
|
||||||
uint partition_index_local = 1;
|
|
||||||
uvec4 color_endpoint_mode = uvec4(0);
|
|
||||||
uint ced_pointer = 0;
|
|
||||||
uint base_cem = 0;
|
|
||||||
if (num_partitions == 1) {
|
|
||||||
color_endpoint_mode.x = StreamBits(4);
|
|
||||||
partition_index_local = 0;
|
|
||||||
} else {
|
|
||||||
partition_index_local = StreamBits(10);
|
|
||||||
base_cem = StreamBits(6);
|
|
||||||
}
|
|
||||||
partition_index = partition_index_local; // Store to shared
|
|
||||||
const uint base_mode = base_cem & 3;
|
|
||||||
const uint max_weight = DecodeMaxWeight(mode);
|
|
||||||
const uint weight_bits = GetPackedBitSize(size_params, dual_plane, max_weight);
|
|
||||||
uint remaining_bits = 128 - weight_bits - total_bitsread;
|
|
||||||
uint extra_cem_bits = 0;
|
|
||||||
if (base_mode > 0) {
|
|
||||||
switch (num_partitions) {
|
|
||||||
case 2: extra_cem_bits += 2; break;
|
|
||||||
case 3: extra_cem_bits += 5; break;
|
|
||||||
case 4: extra_cem_bits += 8; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
remaining_bits -= extra_cem_bits;
|
|
||||||
const uint plane_selector_bits = dual_plane ? 2 : 0;
|
|
||||||
remaining_bits -= plane_selector_bits;
|
|
||||||
if (remaining_bits > 128) {
|
|
||||||
size_params = uvec2(0); // Error
|
|
||||||
} else {
|
|
||||||
const uint color_data_bits = remaining_bits;
|
|
||||||
while (remaining_bits > 0) {
|
|
||||||
const int nb = int(min(remaining_bits, 32U));
|
|
||||||
const uint b = StreamBits(nb);
|
|
||||||
color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb));
|
|
||||||
++ced_pointer;
|
|
||||||
remaining_bits -= nb;
|
|
||||||
}
|
|
||||||
plane_index = uint(StreamBits(plane_selector_bits));
|
|
||||||
if (base_mode > 0) {
|
|
||||||
const uint extra_cem = StreamBits(extra_cem_bits);
|
|
||||||
uint cem = (extra_cem << 6) | base_cem;
|
|
||||||
cem >>= 2;
|
|
||||||
uvec4 C = uvec4(0);
|
|
||||||
for (uint i = 0; i < num_partitions; i++) {
|
|
||||||
C[i] = (cem & 1); cem >>= 1;
|
|
||||||
}
|
|
||||||
uvec4 M = uvec4(0);
|
|
||||||
for (uint i = 0; i < num_partitions; i++) {
|
|
||||||
M[i] = cem & 3; cem >>= 2;
|
|
||||||
}
|
|
||||||
for (uint i = 0; i < num_partitions; i++) {
|
|
||||||
color_endpoint_mode[i] = base_mode;
|
|
||||||
if (C[i] == 0) --color_endpoint_mode[i];
|
|
||||||
color_endpoint_mode[i] <<= 2;
|
|
||||||
color_endpoint_mode[i] |= M[i];
|
|
||||||
}
|
|
||||||
} else if (num_partitions > 1) {
|
|
||||||
const uint cem = base_cem >> 2;
|
|
||||||
for (uint i = 0; i < num_partitions; i++) {
|
|
||||||
color_endpoint_mode[i] = cem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_limit_reached = false;
|
|
||||||
uint colvals_index = 0;
|
|
||||||
DecodeColorValues(color_endpoint_mode, num_partitions, color_data_bits);
|
|
||||||
for (uint i = 0; i < num_partitions; i++) {
|
|
||||||
ComputeEndpoints(endpoints0[i], endpoints1[i], color_endpoint_mode[i], color_values_direct, colvals_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
color_endpoint_data = local_buff;
|
|
||||||
color_endpoint_data = bitfieldReverse(color_endpoint_data).wzyx;
|
|
||||||
const uint clear_byte_start = (weight_bits >> 3) + 1;
|
|
||||||
const uint byte_insert = ExtractBits(color_endpoint_data, int(clear_byte_start - 1) * 8, 8) & uint(((1 << (weight_bits % 8)) - 1));
|
|
||||||
const uint vec_index = (clear_byte_start - 1) >> 2;
|
|
||||||
color_endpoint_data[vec_index] = bitfieldInsert(color_endpoint_data[vec_index], byte_insert, int((clear_byte_start - 1) % 4) * 8, 8);
|
|
||||||
for (uint i = clear_byte_start; i < 16; ++i) {
|
|
||||||
const uint idx = i >> 2;
|
|
||||||
color_endpoint_data[idx] = bitfieldInsert(color_endpoint_data[idx], 0, int(i % 4) * 8, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
result_index = 0;
|
|
||||||
color_bitsread = 0;
|
|
||||||
result_limit_reached = false;
|
|
||||||
result_vector_max_index = size_params.x * size_params.y;
|
|
||||||
if (dual_plane) result_vector_max_index *= 2;
|
|
||||||
DecodeIntegerSequence(max_weight, GetNumWeightValues(size_params, dual_plane));
|
|
||||||
UnquantizeTexelWeights(size_params, dual_plane);
|
|
||||||
|
|
||||||
if (num_partitions > 1) {
|
|
||||||
pt = GetPartitionTable(partition_index, num_partitions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
barrier();
|
|
||||||
|
|
||||||
if (size_params.x == 0) {
|
|
||||||
FillError(coord);
|
FillError(coord);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (size_params.x == 0xFFFFFFFF) {
|
if ((mode & 0x1ff) == 0x1fc) {
|
||||||
|
// params.void_extent_ldr = true;
|
||||||
FillVoidExtentLDR(coord);
|
FillVoidExtentLDR(coord);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const uvec2 size_params = DecodeBlockSize(mode);
|
||||||
const uint total_texels = block_dims.x * block_dims.y;
|
if ((size_params.x > block_dims.x) || (size_params.y > block_dims.y)) {
|
||||||
for (uint tid = gl_LocalInvocationIndex; tid < total_texels; tid += gl_WorkGroupSize.x * gl_WorkGroupSize.y) {
|
FillError(coord);
|
||||||
uint x = tid % block_dims.x;
|
return;
|
||||||
uint y = tid / block_dims.x;
|
}
|
||||||
|
const uint num_partitions = StreamBits(2) + 1;
|
||||||
uint local_partition = 0;
|
const uint mode_layout = FindLayout(mode);
|
||||||
if (num_partitions > 1) {
|
const bool dual_plane = (mode_layout != 9) && ((mode & 0x400) != 0);
|
||||||
local_partition = SelectPartition(pt, x, y, num_partitions);
|
if (num_partitions > 4 || (num_partitions == 4 && dual_plane)) {
|
||||||
|
FillError(coord);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint partition_index = 1;
|
||||||
|
uvec4 color_endpoint_mode = uvec4(0);
|
||||||
|
uint ced_pointer = 0;
|
||||||
|
uint base_cem = 0;
|
||||||
|
if (num_partitions == 1) {
|
||||||
|
color_endpoint_mode.x = StreamBits(4);
|
||||||
|
partition_index = 0;
|
||||||
|
} else {
|
||||||
|
partition_index = StreamBits(10);
|
||||||
|
base_cem = StreamBits(6);
|
||||||
|
}
|
||||||
|
const uint base_mode = base_cem & 3;
|
||||||
|
const uint max_weight = DecodeMaxWeight(mode);
|
||||||
|
const uint weight_bits = GetPackedBitSize(size_params, dual_plane, max_weight);
|
||||||
|
uint remaining_bits = 128 - weight_bits - total_bitsread;
|
||||||
|
uint extra_cem_bits = 0;
|
||||||
|
if (base_mode > 0) {
|
||||||
|
switch (num_partitions) {
|
||||||
|
case 2:
|
||||||
|
extra_cem_bits += 2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
extra_cem_bits += 5;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
extra_cem_bits += 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remaining_bits -= extra_cem_bits;
|
||||||
|
const uint plane_selector_bits = dual_plane ? 2 : 0;
|
||||||
|
remaining_bits -= plane_selector_bits;
|
||||||
|
if (remaining_bits > 128) {
|
||||||
|
// Bad data, more remaining bits than 4 bytes
|
||||||
|
// return early
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Read color data...
|
||||||
|
const uint color_data_bits = remaining_bits;
|
||||||
|
while (remaining_bits > 0) {
|
||||||
|
const int nb = int(min(remaining_bits, 32U));
|
||||||
|
const uint b = StreamBits(nb);
|
||||||
|
color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb));
|
||||||
|
++ced_pointer;
|
||||||
|
remaining_bits -= nb;
|
||||||
|
}
|
||||||
|
const uint plane_index = uint(StreamBits(plane_selector_bits));
|
||||||
|
if (base_mode > 0) {
|
||||||
|
const uint extra_cem = StreamBits(extra_cem_bits);
|
||||||
|
uint cem = (extra_cem << 6) | base_cem;
|
||||||
|
cem >>= 2;
|
||||||
|
uvec4 C = uvec4(0);
|
||||||
|
for (uint i = 0; i < num_partitions; i++) {
|
||||||
|
C[i] = (cem & 1);
|
||||||
|
cem >>= 1;
|
||||||
|
}
|
||||||
|
uvec4 M = uvec4(0);
|
||||||
|
for (uint i = 0; i < num_partitions; i++) {
|
||||||
|
M[i] = cem & 3;
|
||||||
|
cem >>= 2;
|
||||||
|
}
|
||||||
|
for (uint i = 0; i < num_partitions; i++) {
|
||||||
|
color_endpoint_mode[i] = base_mode;
|
||||||
|
if (C[i] == 0) {
|
||||||
|
--color_endpoint_mode[i];
|
||||||
|
}
|
||||||
|
color_endpoint_mode[i] <<= 2;
|
||||||
|
color_endpoint_mode[i] |= M[i];
|
||||||
|
}
|
||||||
|
} else if (num_partitions > 1) {
|
||||||
|
const uint cem = base_cem >> 2;
|
||||||
|
for (uint i = 0; i < num_partitions; i++) {
|
||||||
|
color_endpoint_mode[i] = cem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uvec4 endpoints0[4];
|
||||||
|
uvec4 endpoints1[4];
|
||||||
|
{
|
||||||
|
// This decode phase should at most push 32 elements into the vector
|
||||||
|
result_vector_max_index = 32;
|
||||||
|
uint color_values[32];
|
||||||
|
uint colvals_index = 0;
|
||||||
|
DecodeColorValues(color_endpoint_mode, num_partitions, color_data_bits, color_values);
|
||||||
|
for (uint i = 0; i < num_partitions; i++) {
|
||||||
|
ComputeEndpoints(endpoints0[i], endpoints1[i], color_endpoint_mode[i], color_values,
|
||||||
|
colvals_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color_endpoint_data = local_buff;
|
||||||
|
color_endpoint_data = bitfieldReverse(color_endpoint_data).wzyx;
|
||||||
|
const uint clear_byte_start = (weight_bits >> 3) + 1;
|
||||||
|
|
||||||
|
const uint byte_insert = ExtractBits(color_endpoint_data, int(clear_byte_start - 1) * 8, 8) &
|
||||||
|
uint(((1 << (weight_bits % 8)) - 1));
|
||||||
|
const uint vec_index = (clear_byte_start - 1) >> 2;
|
||||||
|
color_endpoint_data[vec_index] = bitfieldInsert(color_endpoint_data[vec_index], byte_insert,
|
||||||
|
int((clear_byte_start - 1) % 4) * 8, 8);
|
||||||
|
for (uint i = clear_byte_start; i < 16; ++i) {
|
||||||
|
const uint idx = i >> 2;
|
||||||
|
color_endpoint_data[idx] = bitfieldInsert(color_endpoint_data[idx], 0, int(i % 4) * 8, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-init vector variables for next decode phase
|
||||||
|
result_index = 0;
|
||||||
|
color_bitsread = 0;
|
||||||
|
result_limit_reached = false;
|
||||||
|
|
||||||
|
// The limit for the Unquantize phase, avoids decoding more data than needed.
|
||||||
|
result_vector_max_index = size_params.x * size_params.y;
|
||||||
|
if (dual_plane) {
|
||||||
|
result_vector_max_index *= 2;
|
||||||
|
}
|
||||||
|
DecodeIntegerSequence(max_weight, GetNumWeightValues(size_params, dual_plane));
|
||||||
|
|
||||||
|
UnquantizeTexelWeights(size_params, dual_plane);
|
||||||
|
for (uint j = 0; j < block_dims.y; j++) {
|
||||||
|
for (uint i = 0; i < block_dims.x; i++) {
|
||||||
|
uint local_partition = 0;
|
||||||
|
if (num_partitions > 1) {
|
||||||
|
local_partition = Select2DPartition(partition_index, i, j, num_partitions);
|
||||||
|
}
|
||||||
|
const uvec4 C0 = ReplicateByteTo16(endpoints0[local_partition]);
|
||||||
|
const uvec4 C1 = ReplicateByteTo16(endpoints1[local_partition]);
|
||||||
|
const uvec4 weight_vec = GetUnquantizedWeightVector(j, i, size_params, plane_index, dual_plane);
|
||||||
|
const vec4 Cf =
|
||||||
|
vec4((C0 * (uvec4(64) - weight_vec) + C1 * weight_vec + uvec4(32)) / 64);
|
||||||
|
const vec4 p = (Cf / 65535.0f);
|
||||||
|
imageStore(dest_image, coord + ivec3(i, j, 0), p.gbar);
|
||||||
}
|
}
|
||||||
const uvec4 C0 = ReplicateByteTo16(endpoints0[local_partition]);
|
|
||||||
const uvec4 C1 = ReplicateByteTo16(endpoints1[local_partition]);
|
|
||||||
const uvec4 weight_vec = GetUnquantizedWeightVector(y, x, size_params, plane_index, dual_plane);
|
|
||||||
const vec4 Cf = vec4((C0 * (uvec4(64) - weight_vec) + C1 * weight_vec + uvec4(32)) / 64);
|
|
||||||
const vec4 p = (Cf / 65535.0f);
|
|
||||||
imageStore(dest_image, coord + ivec3(x, y, 0), p.gbar);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1176,8 +1132,7 @@ uint SwizzleOffset(uvec2 pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
uvec3 block_id = gl_WorkGroupID;
|
uvec3 pos = gl_GlobalInvocationID;
|
||||||
uvec3 pos = block_id;
|
|
||||||
pos.x <<= BYTES_PER_BLOCK_LOG2;
|
pos.x <<= BYTES_PER_BLOCK_LOG2;
|
||||||
const uint swizzle = SwizzleOffset(pos.xy);
|
const uint swizzle = SwizzleOffset(pos.xy);
|
||||||
const uint block_y = pos.y >> GOB_SIZE_Y_SHIFT;
|
const uint block_y = pos.y >> GOB_SIZE_Y_SHIFT;
|
||||||
@@ -1189,21 +1144,10 @@ void main() {
|
|||||||
offset += (pos.x >> GOB_SIZE_X_SHIFT) << x_shift;
|
offset += (pos.x >> GOB_SIZE_X_SHIFT) << x_shift;
|
||||||
offset += swizzle;
|
offset += swizzle;
|
||||||
|
|
||||||
if (gl_LocalInvocationIndex == 0) {
|
const ivec3 coord = ivec3(gl_GlobalInvocationID * uvec3(block_dims, 1));
|
||||||
total_bitsread = 0;
|
|
||||||
result_index = 0;
|
|
||||||
color_bitsread = 0;
|
|
||||||
write_color_values = false;
|
|
||||||
result_limit_reached = false;
|
|
||||||
color_out_index = 0;
|
|
||||||
color_num_values = 0;
|
|
||||||
local_buff = astc_data[offset / 16];
|
|
||||||
}
|
|
||||||
barrier();
|
|
||||||
|
|
||||||
ivec3 coord = ivec3(block_id * uvec3(block_dims, 1));
|
|
||||||
if (any(greaterThanEqual(coord, imageSize(dest_image)))) {
|
if (any(greaterThanEqual(coord, imageSize(dest_image)))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
local_buff = astc_data[offset / 16];
|
||||||
DecompressBlock(coord);
|
DecompressBlock(coord);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ void WriteResults(uvec2 results[LOCAL_RESULTS]) {
|
|||||||
const uvec2 accum = accumulated_data;
|
const uvec2 accum = accumulated_data;
|
||||||
for (uint i = 0; i < LOCAL_RESULTS; i++) {
|
for (uint i = 0; i < LOCAL_RESULTS; i++) {
|
||||||
uvec2 base_data = current_id * LOCAL_RESULTS + i < min_accumulation_base ? accum : uvec2(0, 0);
|
uvec2 base_data = current_id * LOCAL_RESULTS + i < min_accumulation_base ? accum : uvec2(0, 0);
|
||||||
AddUint64(results[i], base_data);
|
results[i] = AddUint64(results[i], base_data);
|
||||||
}
|
}
|
||||||
for (uint i = 0; i < LOCAL_RESULTS; i++) {
|
for (uint i = 0; i < LOCAL_RESULTS; i++) {
|
||||||
output_data[buffer_offset + current_id * LOCAL_RESULTS + i] = results[i];
|
output_data[buffer_offset + current_id * LOCAL_RESULTS + i] = results[i];
|
||||||
|
|||||||
@@ -586,8 +586,8 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
|||||||
});
|
});
|
||||||
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
||||||
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
||||||
const u32 num_dispatches_x = swizzle.num_tiles.width;
|
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U);
|
||||||
const u32 num_dispatches_y = swizzle.num_tiles.height;
|
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
|
||||||
const u32 num_dispatches_z = image.info.resources.layers;
|
const u32 num_dispatches_z = image.info.resources.layers;
|
||||||
|
|
||||||
compute_pass_descriptor_queue.Acquire();
|
compute_pass_descriptor_queue.Acquire();
|
||||||
@@ -640,6 +640,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
|||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
|
||||||
});
|
});
|
||||||
|
scheduler.Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u32 BL3D_BINDING_SWIZZLE_TABLE = 0;
|
constexpr u32 BL3D_BINDING_SWIZZLE_TABLE = 0;
|
||||||
|
|||||||
@@ -1230,6 +1230,10 @@ void Device::RemoveUnsuitableExtensions() {
|
|||||||
}
|
}
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
||||||
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||||
|
// VK_KHR_unified_image_layouts
|
||||||
|
extensions.unified_image_layouts = features.unified_image_layouts.unifiedImageLayouts;
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.unified_image_layouts, features.unified_image_layouts,
|
||||||
|
VK_KHR_UNIFIED_IMAGE_LAYOUTS_EXTENSION_NAME);
|
||||||
|
|
||||||
// VK_EXT_depth_bias_control
|
// VK_EXT_depth_bias_control
|
||||||
extensions.depth_bias_control =
|
extensions.depth_bias_control =
|
||||||
|
|||||||
@@ -70,7 +70,9 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
||||||
pipeline_executable_properties) \
|
pipeline_executable_properties) \
|
||||||
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
|
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
|
||||||
workgroup_memory_explicit_layout)
|
workgroup_memory_explicit_layout) \
|
||||||
|
FEATURE(KHR, UnifiedImageLayouts, UNIFIED_IMAGE_LAYOUTS, unified_image_layouts)
|
||||||
|
|
||||||
|
|
||||||
// Define miscellaneous extensions which may be used by the implementation here.
|
// Define miscellaneous extensions which may be used by the implementation here.
|
||||||
#define FOR_EACH_VK_EXTENSION(EXTENSION) \
|
#define FOR_EACH_VK_EXTENSION(EXTENSION) \
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
// Qt on macOS doesn't define VMA shit
|
// Qt on macOS doesn't define VMA shit
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include "frontend_common/settings_generator.h"
|
||||||
#include "qt_common/qt_string_lookup.h"
|
#include "qt_common/qt_string_lookup.h"
|
||||||
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
|
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
|
||||||
#undef VMA_IMPLEMENTATION
|
#undef VMA_IMPLEMENTATION
|
||||||
@@ -432,6 +433,7 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
|||||||
Common::Log::Start();
|
Common::Log::Start();
|
||||||
|
|
||||||
LoadTranslation();
|
LoadTranslation();
|
||||||
|
FrontendCommon::GenerateSettings();
|
||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ MAXDEPTH=3
|
|||||||
# For your project you'll want to change this to define what dirs you have cpmfiles in
|
# For your project you'll want to change this to define what dirs you have cpmfiles in
|
||||||
# Remember to account for the MAXDEPTH variable!
|
# Remember to account for the MAXDEPTH variable!
|
||||||
# Adding ./ before each will help to remove duplicates
|
# Adding ./ before each will help to remove duplicates
|
||||||
CPMFILES=$(find . src -maxdepth "$MAXDEPTH" -name cpmfile.json | sort | uniq)
|
CPMFILES=$(find . -maxdepth "$MAXDEPTH" -name cpmfile.json | sort | uniq)
|
||||||
|
|
||||||
# shellcheck disable=SC2016
|
# shellcheck disable=SC2016
|
||||||
PACKAGES=$(echo "$CPMFILES" | xargs jq -s 'reduce .[] as $item ({}; . * $item)')
|
PACKAGES=$(echo "$CPMFILES" | xargs jq -s 'reduce .[] as $item ({}; . * $item)')
|
||||||
|
|||||||
Reference in New Issue
Block a user