Compare commits

...

63 Commits

Author SHA1 Message Date
lat9nq bedb5135c0 nx_tzdb: Rename GNU_DATE variable
The repository can handle either GNU date or Apple date now.
2023-06-19 15:30:11 -04:00
lat9nq 256c7ec0a7 externals: Update tzdb_to_nx
Includes a fix for the Apple date utility.
2023-06-19 15:27:54 -04:00
liamwhite ce191ba32b Merge pull request #10825 from 8bitDream/vcpkg-zlib
externals: Update vcpkg to 2023.06.17
2023-06-18 09:43:12 -04:00
liamwhite 23371fa187 Merge pull request #10829 from lat9nq/remove-external-mem
vulkan_device: Remove external memory extension
2023-06-18 09:43:03 -04:00
liamwhite af7f3f078c Merge pull request #10486 from lat9nq/vk-device-find-once
yuzu-qt: Load Vulkan device info at startup
2023-06-18 09:42:55 -04:00
liamwhite 66b8042b59 Merge pull request #10798 from vonchenplus/draw_texture_scale
video_core: drawtexture support upscale
2023-06-18 09:42:41 -04:00
liamwhite 8acf728d5d Merge pull request #10809 from Kelebek1/reduce_vertex_bindings
Synchronize vertex buffer even when it doesn't require binding
2023-06-18 09:42:32 -04:00
bunnei 6e293be20b Merge pull request #10797 from lat9nq/tzdb-patch
time: Various time zone fixes
2023-06-17 23:47:16 -07:00
bunnei 20db91f0fc Merge pull request #10828 from liamwhite/somehow-still-using-llvm-14
renderer_vulkan: add missing include
2023-06-17 23:45:44 -07:00
lat9nq 8a526b2c26 vulkan_device: Remove external memory extension
Unused in yuzu. Enables yuzu to boot games in Wine using Vulkan.
2023-06-18 01:20:08 -04:00
Liam 565a1226d7 renderer_vulkan: add missing include 2023-06-17 23:57:47 -04:00
Abandoned Cart fd0ef5411c externals: Update vcpkg to 2023.06.17
Fixes for zlib and qt5
2023-06-17 21:46:09 -04:00
lat9nq b99c4dd568 time_zone_service: Always write time zone rule data
Switch firmware will initialize this data even if the given parameters
are invalid. We should do the same.
2023-06-17 20:53:39 -04:00
Morph c0fd793ef6 Merge pull request #10813 from lat9nq/no-atomic-bool
k_thread: Use a mutex and cond_var to sync bool
2023-06-17 20:29:57 -04:00
Fernando S 27a36cd51b Merge pull request #10744 from Wollnashorn/af-for-all
video_core: Improved anisotropic filtering heuristics
2023-06-18 00:02:05 +02:00
Kelebek1 e681f5678c Synchronize vertex buffer even when it doesn't require binding 2023-06-17 17:47:00 -04:00
lat9nq e34e1b1c95 k_thread: Use a mutex and cond_var to sync bool
std::atomic<bool> is broken on MinGW and causes deadlocks there.
Use a normal cond var in its stead.
2023-06-17 15:25:36 -04:00
Wollnashorn 3e47ebe2e9 video_core: Only apply AF to 2D (array) image types 2023-06-17 14:20:44 +02:00
Wollnashorn c309a1c69b video_core: Removed AF for all mip modes option as it's default now 2023-06-17 11:19:39 +02:00
lat9nq 4cbdce17b6 nx_tzdb: Directly reference variables in if statements
Addresses review feedback.
2023-06-17 01:48:46 -04:00
bunnei ec423c6919 Merge pull request #10783 from liamwhite/memory
video_core: preallocate fewer IR blocks
2023-06-16 16:53:25 -07:00
bunnei 24e1e4dcee Merge pull request #10808 from t895/settings-stuffs
android: Expose settings
2023-06-16 16:52:54 -07:00
bunnei 975122f4bb Merge pull request #10807 from t895/ktlint-fixes
android: Ktlint fixes
2023-06-16 16:47:14 -07:00
liamwhite a1adcc31d3 Merge pull request #10731 from german77/misc_fixes
service: nfc: Accuracy fixes
2023-06-16 18:18:24 -04:00
Charles Lombardo 9f92104f3e android: Expose audio output engine setting 2023-06-16 16:42:56 -04:00
Charles Lombardo 330358cd16 android: Bump ktlint version to 0.47.1 2023-06-16 16:32:08 -04:00
Charles Lombardo fc6a2fe779 android: Disable import-ordering ktlint check 2023-06-16 16:31:49 -04:00
Charles Lombardo 13a4de647d android: Expose CPU debugging option 2023-06-16 16:25:06 -04:00
Charles Lombardo 3ac2c74e85 android: Expose fastmem option 2023-06-16 16:24:40 -04:00
Charles Lombardo 5aca03d0ff android: Support changing multiple settings at once 2023-06-16 15:49:49 -04:00
bunnei 4112031c81 Merge pull request #10801 from 8bitDream/fix_aspect
android: Fix aspect ratio when rotating screen
2023-06-16 11:45:32 -07:00
Abandoned Cart c89be0dfab android: Fix aspect ratio when rotating screen 2023-06-16 10:11:18 -04:00
Feng Chen b77a247e8c video_core: drawtexture support upscale 2023-06-16 20:51:15 +08:00
Wollnashorn 2dc0ff79ec video_core: Use sampler IDs instead pointers in the pipeline config
The previous approach of storing pointers returned by `GetGraphicsSampler`/`GetComputeSampler` caused UB, as these functions can cause reallocation of the sampler slot vector and therefore invalidate the pointers
2023-06-16 13:45:14 +02:00
lat9nq 1fa16bc594 cmake: Add warn about cross compiling, disable android 2023-06-16 05:38:33 -04:00
lat9nq d9e2824c4e cmake: Check for target is Windows
MinGW has issues building tzdb2nx due to the headers being Windows
specific. Download for this toolchain as well.
2023-06-16 05:32:11 -04:00
lat9nq d35c989902 cmake: Use non-conflicting variable names 2023-06-16 05:17:06 -04:00
lat9nq 7ffb96f474 cmake: Extra time zone data download checks
Extra sanitization for Windows hosts, and fail loudly when the
download fails.

cmake: Fix status code reading
2023-06-16 05:17:03 -04:00
lat9nq e9701a3cda cmake: Add option to always download time zone data 2023-06-16 04:32:31 -04:00
lat9nq b23c358e3d externals: submodule tzdb_to_nx
Fix for Flatpak being unable to download during CMake configure.
2023-06-16 04:15:19 -04:00
lat9nq cdc73498e3 nx_tzdb: Support submoduling tzdb_to_nx
Fix for flatpak having no internet access during CMake configure.
2023-06-16 04:00:19 -04:00
liamwhite c7fc5b9348 Merge pull request #10739 from zeltermann/sdl-cpuinfo
Re-enable SDL's `CPUinfo` subsystem
2023-06-16 00:08:53 -04:00
liamwhite 41295ff8fe Merge pull request #10795 from german77/foomiibo
input_common: Add foomiibo support
2023-06-16 00:08:30 -04:00
Charles Lombardo 9dd52019a9 Merge pull request #10767 from t895/lint
android: Linting
2023-06-16 00:06:55 -04:00
lat9nq 8d8f850bd6 time_zone_manager: Compare to the correct boolean
Reference implementation does not compare the booleans as we had them.
Use the correct ones as in the reference.

Also adds an assert. I have been made aware of a crash here and am
not able to reproduce currently.
2023-06-15 23:05:41 -04:00
lat9nq 03e8d9aca7 nx_tzdb: Correct Antarctica spelling 2023-06-15 23:03:54 -04:00
Narr the Reg 0c90a0926f input_common: Add amiibo with originality signature support 2023-06-15 18:22:13 -06:00
Wollnashorn a3b7b5b22a video_core: Fallback to default anisotropy instead to 1x anisotropy 2023-06-15 23:16:26 +02:00
Wollnashorn 745d16132b video_core: Disable AF for non-color image formats 2023-06-15 20:59:33 +02:00
Wollnashorn 3e8cd91d54 video_core: Fixed compilation errors because of name shadowing 2023-06-15 18:46:40 +02:00
Wollnashorn 42c944b250 video_core: Add per-image anisotropy heuristics (format & mip count) 2023-06-15 18:19:32 +02:00
Liam 2c01669046 video_core: preallocate fewer IR blocks 2023-06-14 21:37:57 -04:00
Narr the Reg 61b4588517 service: nfc: Read tag protocol only for nfc backend 2023-06-14 18:16:23 -06:00
Narr the Reg b1b13ddc6b service: nfc: Accuracy fixes 2023-06-14 18:08:35 -06:00
Wollnashorn 0de6b9e3f5 video_core: Apply AF only to samplers with normal LOD range [0, 1+x] 2023-06-14 13:27:27 +02:00
Wollnashorn a9e4dddad5 video_core: Fix default anisotropic heuristic 2023-06-14 11:21:22 +02:00
Wollnashorn 44f616edb9 video_core: Never apply AF to None mipmap mode
Should fix some artifacts with the "apply anisotropic filtering for all mipmap modes" option
2023-06-14 03:57:39 +02:00
Wollnashorn b9bba3ac89 video_core: Disable anisotropic filtering for samplers with depth compare 2023-06-13 21:32:32 +02:00
Wollnashorn 0eacf547c0 video_core: Option to apply anisotropic filtering for all mipmap modes 2023-06-13 03:21:01 +02:00
zeltermann 0c04e27df3 Re-enable SDL's CPUinfo subsystem
See https://github.com/libsdl-org/SDL/issues/7809.
Disabling CPUinfo triggers a bug in SDL's audio subsystem, which breaks
SDL's JACK output on Linux. We're lucky it hasn't broken anything else.
2023-06-12 21:36:07 +07:00
lat9nq 013c34cb32 vk_device_info: Clean up includes [IWYU] 2023-06-06 01:54:44 -04:00
lat9nq f9fc996083 vk_device_info: Add SPDX data 2023-06-06 01:54:44 -04:00
lat9nq fc0c4db20d yuzu-qt: Load Vulkan device info at startup
Loading it when the configuration opens now incurs a noticeable delay.
We also don't need to rediscover the same data repeatedly each time the
configuration opens.

Moves vulkan device info discovery to yuzu's startup as opposed to the
configure_graphics constructor.
2023-06-06 01:54:44 -04:00
74 changed files with 901 additions and 444 deletions
+3
View File
@@ -52,3 +52,6 @@
[submodule "libadrenotools"]
path = externals/libadrenotools
url = https://github.com/bylaws/libadrenotools
[submodule "tzdb_to_nx"]
path = externals/nx_tzdb/tzdb_to_nx
url = https://github.com/lat9nq/tzdb_to_nx.git
+2
View File
@@ -59,6 +59,8 @@ option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON)
option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF)
option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
# On Android, fetch and compile libcxx before doing anything else
+2 -1
View File
@@ -63,8 +63,9 @@ if (YUZU_USE_EXTERNAL_SDL2)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
set(SDL_UNUSED_SUBSYSTEMS
CPUinfo File Filesystem
File Filesystem
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
+68 -32
View File
@@ -1,24 +1,60 @@
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
set(NX_TZDB_VERSION "220816")
set(NX_TZDB_DOWNLOAD_URL "https://github.com/lat9nq/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip")
set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
set(NX_TZDB_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
set(NX_TZDB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include")
if (NOT EXISTS ${NX_TZDB_ARCHIVE})
file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE})
add_library(nx_tzdb INTERFACE)
find_program(GIT git)
find_program(GNU_MAKE make)
find_program(DATE_PROG date)
set(CAN_BUILD_NX_TZDB true)
if (NOT GIT)
set(CAN_BUILD_NX_TZDB false)
endif()
if (NOT GNU_MAKE)
set(CAN_BUILD_NX_TZDB false)
endif()
if (NOT DATE_PROG)
set(CAN_BUILD_NX_TZDB false)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID)
# tzdb_to_nx currently requires a posix-compliant host
# MinGW and Android are handled here due to the executable format being different from the host system
# TODO (lat9nq): cross-compiling support
set(CAN_BUILD_NX_TZDB false)
endif()
set(NX_TZDB_VERSION "220816")
set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")
if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ARCHIVE})
set(NX_TZDB_DOWNLOAD_URL "https://github.com/lat9nq/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip")
message(STATUS "Downloading time zone data from ${NX_TZDB_DOWNLOAD_URL}...")
file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE}
STATUS NX_TZDB_DOWNLOAD_STATUS)
list(GET NX_TZDB_DOWNLOAD_STATUS 0 NX_TZDB_DOWNLOAD_STATUS_CODE)
if (NOT NX_TZDB_DOWNLOAD_STATUS_CODE EQUAL 0)
message(FATAL_ERROR "Time zone data download failed (status code ${NX_TZDB_DOWNLOAD_STATUS_CODE})")
endif()
file(ARCHIVE_EXTRACT
INPUT
${NX_TZDB_ARCHIVE}
DESTINATION
${NX_TZDB_DIR})
${NX_TZDB_ROMFS_DIR})
elseif (CAN_BUILD_NX_TZDB AND NOT YUZU_DOWNLOAD_TIME_ZONE_DATA)
add_subdirectory(tzdb_to_nx)
add_dependencies(nx_tzdb x80e)
set(NX_TZDB_ROMFS_DIR "${NX_TZDB_DIR}")
endif()
add_library(nx_tzdb INTERFACE)
target_include_directories(nx_tzdb
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
INTERFACE ${NX_TZDB_INCLUDE_DIR})
@@ -41,25 +77,25 @@ function(CreateHeader ZONE_PATH HEADER_NAME)
target_sources(nx_tzdb PRIVATE ${HEADER_PATH})
endfunction()
CreateHeader(${NX_TZDB_DIR} base)
CreateHeader(${NX_TZDB_DIR}/zoneinfo zoneinfo)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Africa africa)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America america)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Argentina america_argentina)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Indiana america_indiana)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/Kentucky america_kentucky)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/America/North_Dakota america_north_dakota)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Antartica antartica)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Arctic arctic)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Asia asia)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Atlantic atlantic)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Australia australia)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Brazil brazil)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Canada canada)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Chile chile)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Etc etc)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Europe europe)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Indian indian)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Mexico mexico)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/Pacific pacific)
CreateHeader(${NX_TZDB_DIR}/zoneinfo/US us)
CreateHeader(${NX_TZDB_ROMFS_DIR} base)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo zoneinfo)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Africa africa)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America america)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Argentina america_argentina)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Indiana america_indiana)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Kentucky america_kentucky)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/North_Dakota america_north_dakota)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Antarctica antarctica)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Arctic arctic)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Asia asia)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Atlantic atlantic)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Australia australia)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Brazil brazil)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Canada canada)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Chile chile)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Etc etc)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Europe europe)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Indian indian)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Mexico mexico)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Pacific pacific)
CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/US us)
+4 -4
View File
@@ -15,7 +15,7 @@ set(DIRECTORY_NAME ${HEADER_NAME})
set(FILE_DATA "")
foreach(ZONE_FILE ${FILE_LIST})
if ("${ZONE_FILE}" STREQUAL "\n")
if (ZONE_FILE STREQUAL "\n")
continue()
endif()
@@ -26,13 +26,13 @@ foreach(ZONE_FILE ${FILE_LIST})
foreach(I RANGE 0 ${ZONE_DATA_LEN} 2)
math(EXPR BREAK_LINE "(${I} + 2) % 38")
string(SUBSTRING "${ZONE_DATA}" "${I}" "2" HEX_DATA)
if ("${HEX_DATA}" STREQUAL "")
string(SUBSTRING "${ZONE_DATA}" "${I}" 2 HEX_DATA)
if (NOT HEX_DATA)
break()
endif()
string(APPEND FILE_DATA "0x${HEX_DATA},")
if ("${BREAK_LINE}" STREQUAL "0")
if (BREAK_LINE EQUAL 0)
string(APPEND FILE_DATA "\n")
else()
string(APPEND FILE_DATA " ")
+1 -1
View File
@@ -9,7 +9,7 @@
#include "nx_tzdb/america_indiana.h"
#include "nx_tzdb/america_kentucky.h"
#include "nx_tzdb/america_north_dakota.h"
#include "nx_tzdb/antartica.h"
#include "nx_tzdb/antarctica.h"
#include "nx_tzdb/arctic.h"
#include "nx_tzdb/asia.h"
#include "nx_tzdb/atlantic.h"
+3 -2
View File
@@ -163,13 +163,14 @@ android {
tasks.getByPath("preBuild").dependsOn("ktlintCheck")
ktlint {
version.set("0.47.0")
version.set("0.47.1")
android.set(true)
ignoreFailures.set(false)
disabledRules.set(
setOf(
"no-wildcard-imports",
"package-name"
"package-name",
"import-ordering"
)
)
reporters {
@@ -53,6 +53,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
<activity
android:name="org.yuzu.yuzu_emu.activities.EmulationActivity"
android:theme="@style/Theme.Yuzu.Main"
android:screenOrientation="userLandscape"
android:supportsPictureInPicture="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode"
android:exported="true">
@@ -8,6 +8,9 @@ enum class BooleanSetting(
override val section: String,
override val defaultValue: Boolean
) : AbstractBooleanSetting {
CPU_DEBUG_MODE("cpu_debug_mode", Settings.SECTION_CPU, false),
FASTMEM("cpuopt_fastmem", Settings.SECTION_CPU, true),
FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives", Settings.SECTION_CPU, true),
PICTURE_IN_PICTURE("picture_in_picture", Settings.SECTION_GENERAL, true),
USE_CUSTOM_RTC("custom_rtc_enabled", Settings.SECTION_SYSTEM, false);
@@ -8,6 +8,7 @@ enum class StringSetting(
override val section: String,
override val defaultValue: String
) : AbstractStringSetting {
AUDIO_OUTPUT_ENGINE("output_engine", Settings.SECTION_AUDIO, "auto"),
CUSTOM_RTC("custom_rtc", Settings.SECTION_SYSTEM, "0");
override var string: String = defaultValue
@@ -3,12 +3,8 @@
package org.yuzu.yuzu_emu.features.settings.model.view
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
class HeaderSetting(
setting: AbstractSetting?,
titleId: Int,
descriptionId: Int
) : SettingsItem(setting, titleId, descriptionId) {
titleId: Int
) : SettingsItem(null, titleId, 0) {
override val type = TYPE_HEADER
}
@@ -7,20 +7,20 @@ import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
class StringSingleChoiceSetting(
val key: String? = null,
setting: AbstractSetting?,
titleId: Int,
descriptionId: Int,
val choicesId: Array<String>,
private val valuesId: Array<String>?,
val choices: Array<String>,
val values: Array<String>?,
val key: String? = null,
private val defaultValue: String? = null
) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_STRING_SINGLE_CHOICE
fun getValueAt(index: Int): String? {
if (valuesId == null) return null
return if (index >= 0 && index < valuesId.size) {
valuesId[index]
if (values == null) return null
return if (index >= 0 && index < values.size) {
values[index]
} else {
""
}
@@ -36,8 +36,8 @@ class StringSingleChoiceSetting(
val selectValueIndex: Int
get() {
val selectedValue = selectedValue
for (i in valuesId!!.indices) {
if (valuesId[i] == selectedValue) {
for (i in values!!.indices) {
if (values[i] == selectedValue) {
return i
}
}
@@ -138,7 +138,7 @@ class SettingsAdapter(
clickedItem = item
dialog = MaterialAlertDialogBuilder(context)
.setTitle(item.nameId)
.setSingleChoiceItems(item.choicesId, item.selectValueIndex, this)
.setSingleChoiceItems(item.choices, item.selectValueIndex, this)
.show()
}
@@ -42,7 +42,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
}
fun putSetting(setting: AbstractSetting) {
if (setting.section == null) {
if (setting.section == null || setting.key == null) {
return
}
@@ -353,18 +353,31 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
private fun addAudioSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_audio))
sl.add(
SliderSetting(
IntSetting.AUDIO_VOLUME,
R.string.audio_volume,
R.string.audio_volume_description,
0,
100,
"%",
IntSetting.AUDIO_VOLUME.key,
IntSetting.AUDIO_VOLUME.defaultValue
sl.apply {
add(
StringSingleChoiceSetting(
StringSetting.AUDIO_OUTPUT_ENGINE,
R.string.audio_output_engine,
0,
settingsActivity.resources.getStringArray(R.array.outputEngineEntries),
settingsActivity.resources.getStringArray(R.array.outputEngineValues),
StringSetting.AUDIO_OUTPUT_ENGINE.key,
StringSetting.AUDIO_OUTPUT_ENGINE.defaultValue
)
)
)
add(
SliderSetting(
IntSetting.AUDIO_VOLUME,
R.string.audio_volume,
R.string.audio_volume_description,
0,
100,
"%",
IntSetting.AUDIO_VOLUME.key,
IntSetting.AUDIO_VOLUME.defaultValue
)
)
}
}
private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
@@ -467,6 +480,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
private fun addDebugSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_debug))
sl.apply {
add(HeaderSetting(R.string.gpu))
add(
SingleChoiceSetting(
IntSetting.RENDERER_BACKEND,
@@ -487,6 +501,39 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
IntSetting.RENDERER_DEBUG.defaultValue
)
)
add(HeaderSetting(R.string.cpu))
add(
SwitchSetting(
BooleanSetting.CPU_DEBUG_MODE,
R.string.cpu_debug_mode,
R.string.cpu_debug_mode_description,
BooleanSetting.CPU_DEBUG_MODE.key,
BooleanSetting.CPU_DEBUG_MODE.defaultValue
)
)
val fastmem = object : AbstractBooleanSetting {
override var boolean: Boolean
get() =
BooleanSetting.FASTMEM.boolean && BooleanSetting.FASTMEM_EXCLUSIVES.boolean
set(value) {
BooleanSetting.FASTMEM.boolean = value
BooleanSetting.FASTMEM_EXCLUSIVES.boolean = value
}
override val key: String? = null
override val section: String = Settings.SECTION_CPU
override val isRuntimeEditable: Boolean = false
override val valueAsString: String = ""
override val defaultValue: Any = true
}
add(
SwitchSetting(
fastmem,
R.string.fastmem,
0
)
)
}
}
}
@@ -26,6 +26,14 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
for (i in values.indices) {
if (values[i] == item.selectedValue) {
binding.textSettingDescription.text = resMgr.getStringArray(item.choicesId)[i]
return
}
}
} else if (item is StringSingleChoiceSetting) {
for (i in item.values!!.indices) {
if (item.values[i] == item.selectedValue) {
binding.textSettingDescription.text = item.choices[i]
return
}
}
} else {
@@ -244,5 +244,21 @@ object SettingsFile {
val setting = settings[key]
parser.put(header, setting!!.key, setting.valueAsString)
}
BooleanSetting.values().forEach {
if (!keySet.contains(it.key)) {
parser.put(header, it.key, it.valueAsString)
}
}
IntSetting.values().forEach {
if (!keySet.contains(it.key)) {
parser.put(header, it.key, it.valueAsString)
}
}
StringSetting.values().forEach {
if (!keySet.contains(it.key)) {
parser.put(header, it.key, it.valueAsString)
}
}
}
}
@@ -85,20 +85,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
onReturnFromSettings = context.activityResultRegistry.register(
"SettingsResult",
ActivityResultContracts.StartActivityForResult()
) {
binding.surfaceEmulation.setAspectRatio(
when (IntSetting.RENDERER_ASPECT_RATIO.int) {
0 -> Rational(16, 9)
1 -> Rational(4, 3)
2 -> Rational(21, 9)
3 -> Rational(16, 10)
4 -> null // Stretch
else -> Rational(16, 9)
}
)
emulationActivity?.buildPictureInPictureParams()
updateScreenLayout()
}
) { updateScreenLayout() }
} else {
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
}
@@ -242,17 +229,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
DirectoryInitialization.start(requireContext())
}
binding.surfaceEmulation.setAspectRatio(
when (IntSetting.RENDERER_ASPECT_RATIO.int) {
0 -> Rational(16, 9)
1 -> Rational(4, 3)
2 -> Rational(21, 9)
3 -> Rational(16, 10)
4 -> null // Stretch
else -> Rational(16, 9)
}
)
updateScreenLayout()
emulationState.run(emulationActivity!!.isActivityRecreated)
@@ -315,7 +291,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
@SuppressLint("SourceLockedOrientationActivity")
private fun updateScreenLayout() {
private fun updateOrientation() {
emulationActivity?.let {
it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.int) {
Settings.LayoutOption_MobileLandscape ->
@@ -326,7 +302,21 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
else -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
}
}
onConfigurationChanged(resources.configuration)
}
private fun updateScreenLayout() {
binding.surfaceEmulation.setAspectRatio(
when (IntSetting.RENDERER_ASPECT_RATIO.int) {
0 -> Rational(16, 9)
1 -> Rational(4, 3)
2 -> Rational(21, 9)
3 -> Rational(16, 10)
4 -> null // Stretch
else -> Rational(16, 9)
}
)
emulationActivity?.buildPictureInPictureParams()
updateOrientation()
}
private fun updateFoldableLayout(
@@ -359,7 +349,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.overlayContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
binding.inGameMenu.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
isInFoldableLayout = false
updateScreenLayout()
updateOrientation()
onConfigurationChanged(resources.configuration)
}
binding.emulationContainer.requestLayout()
binding.inputContainer.requestLayout()
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:minHeight="72dp"
android:paddingVertical="@dimen/spacing_large"
android:paddingStart="@dimen/spacing_large"
android:paddingEnd="24dp"
android:paddingVertical="@dimen/spacing_large">
android:paddingEnd="24dp">
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/switch_widget"
@@ -19,32 +19,35 @@
android:layout_alignParentEnd="true"
android:layout_centerVertical="true" />
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.BodySmall"
android:id="@+id/text_setting_description"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignStart="@+id/text_setting_name"
android:layout_below="@+id/text_setting_name"
android:layout_marginEnd="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_small"
android:layout_toStartOf="@+id/switch_widget"
android:textAlignment="viewStart"
tools:text="@string/frame_limit_enable_description" />
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.HeadlineMedium"
android:id="@+id/text_setting_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/spacing_large"
android:layout_toStartOf="@+id/switch_widget"
android:textSize="16sp"
android:textAlignment="viewStart"
app:lineHeight="28dp"
tools:text="@string/frame_limit_enable" />
android:gravity="center_vertical"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_setting_name"
style="@style/TextAppearance.Material3.HeadlineMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:textSize="16sp"
app:lineHeight="28dp"
tools:text="@string/frame_limit_enable" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_setting_description"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_small"
android:textAlignment="viewStart"
tools:text="@string/frame_limit_enable_description" />
</LinearLayout>
</RelativeLayout>
@@ -1,20 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.material.textview.MaterialTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/text_header_name"
style="@style/TextAppearance.Material3.TitleSmall"
android:layout_width="match_parent"
android:layout_height="48dp"
android:paddingVertical="4dp"
android:paddingHorizontal="@dimen/spacing_large">
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.TitleSmall"
android:id="@+id/text_header_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:textColor="?attr/colorPrimary"
android:textAlignment="viewStart"
android:textStyle="bold"
tools:text="CPU Settings" />
</FrameLayout>
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:paddingHorizontal="@dimen/spacing_large"
android:paddingVertical="16dp"
android:textAlignment="viewStart"
android:textColor="?attr/colorPrimary"
android:textStyle="bold"
tools:text="CPU Settings" />
@@ -236,4 +236,15 @@
<item>2</item>
</integer-array>
<string-array name="outputEngineEntries">
<item>@string/auto</item>
<item>@string/cubeb</item>
<item>@string/string_null</item>
</string-array>
<string-array name="outputEngineValues">
<item>auto</item>
<item>cubeb</item>
<item>null</item>
</string-array>
</resources>
@@ -158,7 +158,6 @@
<string name="set_custom_rtc">Set custom RTC</string>
<!-- Graphics settings strings -->
<string name="renderer_api">API</string>
<string name="renderer_accuracy">Accuracy level</string>
<string name="renderer_resolution">Resolution (Handheld/Docked)</string>
<string name="renderer_vsync">VSync mode</string>
@@ -172,12 +171,21 @@
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, reducing stutter but may introduce glitches.</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_debug">Graphics debugging</string>
<string name="renderer_debug_description">Sets the graphics API to a slow debugging mode.</string>
<string name="use_disk_shader_cache">Disk shader cache</string>
<string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU Debugging</string>
<string name="cpu_debug_mode_description">Puts the CPU in a slow debugging mode.</string>
<string name="gpu">GPU</string>
<string name="renderer_api">API</string>
<string name="renderer_debug">Graphics debugging</string>
<string name="renderer_debug_description">Sets the graphics API to a slow debugging mode.</string>
<string name="fastmem">Fastmem</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Output engine</string>
<string name="audio_volume">Volume</string>
<string name="audio_volume_description">Specifies the volume of audio output.</string>
@@ -196,6 +204,7 @@
<string name="learn_more">Learn more</string>
<string name="auto">Auto</string>
<string name="submit">Submit</string>
<string name="string_null">Null</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Select GPU driver</string>
@@ -366,6 +375,9 @@
<string name="theme_mode_light">Light</string>
<string name="theme_mode_dark">Dark</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Black backgrounds</string>
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
@@ -15,7 +15,7 @@ namespace FileSys::SystemArchive {
const static std::map<std::string, const std::map<const char*, const std::vector<u8>>&>
tzdb_zoneinfo_dirs = {{"Africa", NxTzdb::africa},
{"America", NxTzdb::america},
{"Antartica", NxTzdb::antartica},
{"Antarctica", NxTzdb::antarctica},
{"Arctic", NxTzdb::arctic},
{"Asia", NxTzdb::asia},
{"Atlantic", NxTzdb::atlantic},
+11 -4
View File
@@ -4,6 +4,8 @@
#include <algorithm>
#include <atomic>
#include <cinttypes>
#include <condition_variable>
#include <mutex>
#include <optional>
#include <vector>
@@ -1313,7 +1315,8 @@ void KThread::RequestDummyThreadWait() {
ASSERT(this->IsDummyThread());
// We will block when the scheduler lock is released.
m_dummy_thread_runnable.store(false);
std::scoped_lock lock{m_dummy_thread_mutex};
m_dummy_thread_runnable = false;
}
void KThread::DummyThreadBeginWait() {
@@ -1323,7 +1326,8 @@ void KThread::DummyThreadBeginWait() {
}
// Block until runnable is no longer false.
m_dummy_thread_runnable.wait(false);
std::unique_lock lock{m_dummy_thread_mutex};
m_dummy_thread_cv.wait(lock, [this] { return m_dummy_thread_runnable; });
}
void KThread::DummyThreadEndWait() {
@@ -1331,8 +1335,11 @@ void KThread::DummyThreadEndWait() {
ASSERT(this->IsDummyThread());
// Wake up the waiting thread.
m_dummy_thread_runnable.store(true);
m_dummy_thread_runnable.notify_one();
{
std::scoped_lock lock{m_dummy_thread_mutex};
m_dummy_thread_runnable = true;
}
m_dummy_thread_cv.notify_one();
}
void KThread::BeginWait(KThreadQueue* queue) {
+3 -1
View File
@@ -892,7 +892,9 @@ private:
std::shared_ptr<Common::Fiber> m_host_context{};
ThreadType m_thread_type{};
StepState m_step_state{};
std::atomic<bool> m_dummy_thread_runnable{true};
bool m_dummy_thread_runnable{true};
std::mutex m_dummy_thread_mutex{};
std::condition_variable m_dummy_thread_cv{};
// For debugging
std::vector<KSynchronizationObject*> m_wait_objects_for_debugging{};
@@ -36,12 +36,12 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
// Validate UUID
constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3`
if ((CT ^ ntag_file.uuid.uid[0] ^ ntag_file.uuid.uid[1] ^ ntag_file.uuid.uid[2]) !=
ntag_file.uuid.uid[3]) {
if ((CT ^ ntag_file.uuid.part1[0] ^ ntag_file.uuid.part1[1] ^ ntag_file.uuid.part1[2]) !=
ntag_file.uuid.crc_check1) {
return false;
}
if ((ntag_file.uuid.uid[4] ^ ntag_file.uuid.uid[5] ^ ntag_file.uuid.uid[6] ^
ntag_file.uuid.nintendo_id) != ntag_file.uuid.lock_bytes[0]) {
if ((ntag_file.uuid.part2[0] ^ ntag_file.uuid.part2[1] ^ ntag_file.uuid.part2[2] ^
ntag_file.uuid.nintendo_id) != ntag_file.uuid_crc_check2) {
return false;
}
@@ -74,8 +74,9 @@ bool IsAmiiboValid(const NTAG215File& ntag_file) {
NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
NTAG215File encoded_data{};
encoded_data.uid = nfc_data.uuid.uid;
encoded_data.nintendo_id = nfc_data.uuid.nintendo_id;
encoded_data.uid = nfc_data.uuid;
encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2;
encoded_data.internal_number = nfc_data.internal_number;
encoded_data.static_lock = nfc_data.static_lock;
encoded_data.compability_container = nfc_data.compability_container;
encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
@@ -94,7 +95,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc;
encoded_data.application_area = nfc_data.user_memory.application_area;
encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag;
encoded_data.lock_bytes = nfc_data.uuid.lock_bytes;
encoded_data.model_info = nfc_data.user_memory.model_info;
encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt;
encoded_data.dynamic_lock = nfc_data.dynamic_lock;
@@ -108,9 +108,9 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
EncryptedNTAG215File nfc_data{};
nfc_data.uuid.uid = encoded_data.uid;
nfc_data.uuid.nintendo_id = encoded_data.nintendo_id;
nfc_data.uuid.lock_bytes = encoded_data.lock_bytes;
nfc_data.uuid = encoded_data.uid;
nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2;
nfc_data.internal_number = encoded_data.internal_number;
nfc_data.static_lock = encoded_data.static_lock;
nfc_data.compability_container = encoded_data.compability_container;
nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
@@ -139,23 +139,12 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
return nfc_data;
}
u32 GetTagPassword(const TagUuid& uuid) {
// Verify that the generated password is correct
u32 password = 0xAA ^ (uuid.uid[1] ^ uuid.uid[3]);
password &= (0x55 ^ (uuid.uid[2] ^ uuid.uid[4])) << 8;
password &= (0xAA ^ (uuid.uid[3] ^ uuid.uid[5])) << 16;
password &= (0x55 ^ (uuid.uid[4] ^ uuid.uid[6])) << 24;
return password;
}
HashSeed GetSeed(const NTAG215File& data) {
HashSeed seed{
.magic = data.write_counter,
.padding = {},
.uid_1 = data.uid,
.nintendo_id_1 = data.nintendo_id,
.uid_2 = data.uid,
.nintendo_id_2 = data.nintendo_id,
.keygen_salt = data.keygen_salt,
};
@@ -177,10 +166,11 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
output.insert(output.end(), key.magic_bytes.begin(),
key.magic_bytes.begin() + key.magic_length);
output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end());
output.emplace_back(seed.nintendo_id_1);
output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end());
output.emplace_back(seed.nintendo_id_2);
std::array<u8, sizeof(NFP::TagUuid)> seed_uuid{};
memcpy(seed_uuid.data(), &seed.uid_1, sizeof(NFP::TagUuid));
output.insert(output.end(), seed_uuid.begin(), seed_uuid.end());
memcpy(seed_uuid.data(), &seed.uid_2, sizeof(NFP::TagUuid));
output.insert(output.end(), seed_uuid.begin(), seed_uuid.end());
for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) {
output.emplace_back(static_cast<u8>(seed.keygen_salt[i] ^ key.xor_pad[i]));
@@ -264,8 +254,8 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
// Copy the rest of the data directly
out_data.uid = in_data.uid;
out_data.nintendo_id = in_data.nintendo_id;
out_data.lock_bytes = in_data.lock_bytes;
out_data.uid_crc_check2 = in_data.uid_crc_check2;
out_data.internal_number = in_data.internal_number;
out_data.static_lock = in_data.static_lock;
out_data.compability_container = in_data.compability_container;
@@ -24,10 +24,8 @@ using DrgbOutput = std::array<u8, 0x20>;
struct HashSeed {
u16_be magic;
std::array<u8, 0xE> padding;
NFC::UniqueSerialNumber uid_1;
u8 nintendo_id_1;
NFC::UniqueSerialNumber uid_2;
u8 nintendo_id_2;
TagUuid uid_1;
TagUuid uid_2;
std::array<u8, 0x20> keygen_salt;
};
static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size");
@@ -69,9 +67,6 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data);
/// Converts from encoded file format to encrypted file format
EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data);
/// Returns password needed to allow write access to protected memory
u32 GetTagPassword(const TagUuid& uuid);
// Generates Seed needed for key derivation
HashSeed GetSeed(const NTAG215File& data);
+119 -45
View File
@@ -242,34 +242,39 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
return ResultWrongDeviceState;
}
UniqueSerialNumber uuid = encrypted_tag_data.uuid.uid;
// Generate random UUID to bypass amiibo load limits
if (Settings::values.random_amiibo_id) {
Common::TinyMT rng{};
rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
rng.GenerateRandomBytes(uuid.data(), sizeof(UniqueSerialNumber));
uuid[3] = 0x88 ^ uuid[0] ^ uuid[1] ^ uuid[2];
}
UniqueSerialNumber uuid{};
u8 uuid_length{};
NfcProtocol protocol{NfcProtocol::TypeA};
TagType tag_type{TagType::Type2};
if (is_mifare) {
tag_info = {
.uuid = uuid,
.uuid_extension = {},
.uuid_length = static_cast<u8>(uuid.size()),
.protocol = NfcProtocol::TypeA,
.tag_type = TagType::Type4,
tag_type = TagType::Mifare;
uuid_length = sizeof(NFP::NtagTagUuid);
memcpy(uuid.data(), mifare_data.data(), uuid_length);
} else {
tag_type = TagType::Type2;
uuid_length = sizeof(NFP::NtagTagUuid);
NFP::NtagTagUuid nUuid{
.part1 = encrypted_tag_data.uuid.part1,
.part2 = encrypted_tag_data.uuid.part2,
.nintendo_id = encrypted_tag_data.uuid.nintendo_id,
};
return ResultSuccess;
memcpy(uuid.data(), &nUuid, uuid_length);
// Generate random UUID to bypass amiibo load limits
if (Settings::values.random_amiibo_id) {
Common::TinyMT rng{};
rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
rng.GenerateRandomBytes(uuid.data(), uuid_length);
}
}
// Protocol and tag type may change here
tag_info = {
.uuid = uuid,
.uuid_extension = {},
.uuid_length = static_cast<u8>(uuid.size()),
.protocol = NfcProtocol::TypeA,
.tag_type = TagType::Type2,
.uuid_length = uuid_length,
.protocol = protocol,
.tag_type = tag_type,
};
return ResultSuccess;
@@ -277,8 +282,38 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters,
std::span<MifareReadBlockData> read_block_data) const {
if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
if (device_state == DeviceState::TagRemoved) {
return ResultTagRemoved;
}
return ResultWrongDeviceState;
}
Result result = ResultSuccess;
TagInfo tag_info{};
result = GetTagInfo(tag_info, true);
if (result.IsError()) {
return result;
}
if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
return ResultInvalidTagType;
}
if (parameters.size() == 0) {
return ResultInvalidArgument;
}
const auto unknown = parameters[0].sector_key.unknown;
for (std::size_t i = 0; i < parameters.size(); i++) {
if (unknown != parameters[i].sector_key.unknown) {
return ResultInvalidArgument;
}
}
for (std::size_t i = 0; i < parameters.size(); i++) {
result = ReadMifare(parameters[i], read_block_data[i]);
if (result.IsError()) {
@@ -293,17 +328,8 @@ Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
MifareReadBlockData& read_block_data) const {
const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
read_block_data.sector_number = parameter.sector_number;
if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
if (device_state == DeviceState::TagRemoved) {
return ResultTagRemoved;
}
return ResultWrongDeviceState;
}
if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
return Mifare::ResultReadError;
return ResultMifareError288;
}
// TODO: Use parameter.sector_key to read encrypted data
@@ -315,6 +341,28 @@ Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) {
Result result = ResultSuccess;
TagInfo tag_info{};
result = GetTagInfo(tag_info, true);
if (result.IsError()) {
return result;
}
if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
return ResultInvalidTagType;
}
if (parameters.size() == 0) {
return ResultInvalidArgument;
}
const auto unknown = parameters[0].sector_key.unknown;
for (std::size_t i = 0; i < parameters.size(); i++) {
if (unknown != parameters[i].sector_key.unknown) {
return ResultInvalidArgument;
}
}
for (std::size_t i = 0; i < parameters.size(); i++) {
result = WriteMifare(parameters[i]);
if (result.IsError()) {
@@ -324,7 +372,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
if (!npad_device->WriteNfc(mifare_data)) {
LOG_ERROR(Service_NFP, "Error writing to file");
return Mifare::ResultReadError;
return ResultMifareError288;
}
return result;
@@ -342,7 +390,7 @@ Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
}
if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
return Mifare::ResultReadError;
return ResultMifareError288;
}
// TODO: Use parameter.sector_key to encrypt the data
@@ -366,7 +414,7 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
LOG_ERROR(Service_NFP, "Not an amiibo");
return ResultNotAnAmiibo;
return ResultInvalidTagType;
}
// The loaded amiibo is not encrypted
@@ -381,14 +429,14 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
}
if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
bool has_backup = HasBackup(encrypted_tag_data.uuid.uid).IsSuccess();
bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess();
LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup);
return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
}
std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
WriteBackupData(encrypted_tag_data.uuid.uid, data);
WriteBackupData(encrypted_tag_data.uuid, data);
device_state = DeviceState::TagMounted;
mount_target = mount_target_;
@@ -492,7 +540,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
}
memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
WriteBackupData(encrypted_tag_data.uuid.uid, data);
WriteBackupData(encrypted_tag_data.uuid, data);
}
if (!npad_device->WriteNfc(data)) {
@@ -520,7 +568,7 @@ Result NfcDevice::Restore() {
return result;
}
result = ReadBackupData(tag_info.uuid, data);
result = ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
if (result.IsError()) {
return result;
@@ -548,7 +596,7 @@ Result NfcDevice::Restore() {
}
if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) {
return ResultNotAnAmiibo;
return ResultInvalidTagType;
}
if (!is_plain_amiibo) {
@@ -1194,10 +1242,12 @@ Result NfcDevice::BreakTag(NFP::BreakType break_type) {
return FlushWithBreak(break_type);
}
Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const {
Result NfcDevice::HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const {
ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
constexpr auto backup_dir = "backup";
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
const auto file_name =
fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) {
return ResultUnableToAccessBackupFile;
@@ -1206,10 +1256,19 @@ Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const {
return ResultSuccess;
}
Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const {
Result NfcDevice::HasBackup(const NFP::TagUuid& tag_uid) const {
UniqueSerialNumber uuid{};
memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
return HasBackup(uuid, sizeof(NFP::TagUuid));
}
Result NfcDevice::ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
std::span<u8> data) const {
ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
constexpr auto backup_dir = "backup";
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
const auto file_name =
fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
Common::FS::FileAccessMode::Read,
@@ -1228,12 +1287,21 @@ Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u
return ResultSuccess;
}
Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data) {
Result NfcDevice::ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const {
UniqueSerialNumber uuid{};
memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
return ReadBackupData(uuid, sizeof(NFP::TagUuid), data);
}
Result NfcDevice::WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
std::span<const u8> data) {
ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
constexpr auto backup_dir = "backup";
const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
const auto file_name =
fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
if (HasBackup(uid).IsError()) {
if (HasBackup(uid, uuid_size).IsError()) {
if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) {
return ResultBackupPathAlreadyExist;
}
@@ -1260,6 +1328,12 @@ Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<
return ResultSuccess;
}
Result NfcDevice::WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data) {
UniqueSerialNumber uuid{};
memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
return WriteBackupData(uuid, sizeof(NFP::TagUuid), data);
}
Result NfcDevice::WriteNtf(std::span<const u8> data) {
if (device_state != DeviceState::TagMounted) {
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+8 -3
View File
@@ -86,9 +86,14 @@ public:
Result GetAll(NFP::NfpData& data) const;
Result SetAll(const NFP::NfpData& data);
Result BreakTag(NFP::BreakType break_type);
Result HasBackup(const NFC::UniqueSerialNumber& uid) const;
Result ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const;
Result WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data);
Result HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const;
Result HasBackup(const NFP::TagUuid& tag_uid) const;
Result ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
std::span<u8> data) const;
Result ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const;
Result WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
std::span<const u8> data);
Result WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data);
Result WriteNtf(std::span<const u8> data);
u64 GetHandle() const;
@@ -550,7 +550,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
}
if (result.IsSuccess()) {
result = device->ReadBackupData(tag_info.uuid, data);
result = device->ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
result = VerifyDeviceResult(device, result);
}
@@ -569,7 +569,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
}
if (result.IsSuccess()) {
result = device->WriteBackupData(tag_info.uuid, data);
result = device->WriteBackupData(tag_info.uuid, tag_info.uuid_length, data);
result = VerifyDeviceResult(device, result);
}
+1 -1
View File
@@ -12,6 +12,6 @@ constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65);
constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73);
constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80);
constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97);
constexpr Result ResultReadError(ErrorModule::NFCMifare, 288);
constexpr Result ResultNotAMifare(ErrorModule::NFCMifare, 288);
} // namespace Service::NFC::Mifare
+10 -3
View File
@@ -142,9 +142,13 @@ void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
void NfcInterface::StartDetection(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto tag_protocol{rp.PopEnum<NfcProtocol>()};
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
auto tag_protocol{NfcProtocol::All};
if (backend_type == BackendType::Nfc) {
tag_protocol = rp.PopEnum<NfcProtocol>();
}
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
auto result = GetManager()->StartDetection(device_handle, tag_protocol);
result = TranslateResultToServiceError(result);
@@ -355,7 +359,7 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
if (result == ResultApplicationAreaExist) {
return NFP::ResultApplicationAreaExist;
}
if (result == ResultNotAnAmiibo) {
if (result == ResultInvalidTagType) {
return NFP::ResultNotAnAmiibo;
}
if (result == ResultUnableToAccessBackupFile) {
@@ -381,6 +385,9 @@ Result NfcInterface::TranslateResultToMifare(Result result) const {
if (result == ResultTagRemoved) {
return Mifare::ResultTagRemoved;
}
if (result == ResultInvalidTagType) {
return Mifare::ResultNotAMifare;
}
LOG_WARNING(Service_NFC, "Result conversion not handled");
return result;
}
+2 -1
View File
@@ -24,7 +24,8 @@ constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);
constexpr Result ResultCorruptedData(ErrorModule::NFC, 144);
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFC, 152);
constexpr Result ResultApplicationAreaExist(ErrorModule::NFC, 168);
constexpr Result ResultNotAnAmiibo(ErrorModule::NFC, 178);
constexpr Result ResultInvalidTagType(ErrorModule::NFC, 178);
constexpr Result ResultBackupPathAlreadyExist(ErrorModule::NFC, 216);
constexpr Result ResultMifareError288(ErrorModule::NFC, 288);
} // namespace Service::NFC
+19 -18
View File
@@ -35,32 +35,35 @@ enum class State : u32 {
// This is nn::nfc::TagType
enum class TagType : u32 {
None,
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
None = 0,
Type1 = 1U << 0, // ISO14443A RW. Topaz
Type2 = 1U << 1, // ISO14443A RW. Ultralight, NTAGX, ST25TN
Type3 = 1U << 2, // ISO14443A RW/RO. Sony FeliCa
Type4A = 1U << 3, // ISO14443A RW/RO. DESFire
Type4B = 1U << 4, // ISO14443B RW/RO. DESFire
Type5 = 1U << 5, // ISO15693 RW/RO. SLI, SLIX, ST25TV
Mifare = 1U << 6, // Mifare classic. Skylanders
All = 0xFFFFFFFF,
};
enum class PackedTagType : u8 {
None,
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
None = 0,
Type1 = 1U << 0, // ISO14443A RW. Topaz
Type2 = 1U << 1, // ISO14443A RW. Ultralight, NTAGX, ST25TN
Type3 = 1U << 2, // ISO14443A RW/RO. Sony FeliCa
Type4A = 1U << 3, // ISO14443A RW/RO. DESFire
Type4B = 1U << 4, // ISO14443B RW/RO. DESFire
Type5 = 1U << 5, // ISO15693 RW/RO. SLI, SLIX, ST25TV
Mifare = 1U << 6, // Mifare classic. Skylanders
All = 0xFF,
};
// This is nn::nfc::NfcProtocol
// Verify this enum. It might be completely wrong default protocol is 0x48
enum class NfcProtocol : u32 {
None,
TypeA = 1U << 0, // ISO14443A
TypeB = 1U << 1, // ISO14443B
TypeF = 1U << 2, // Sony FeliCa
Unknown1 = 1U << 3,
Unknown2 = 1U << 5,
All = 0xFFFFFFFFU,
};
@@ -69,8 +72,7 @@ enum class TestWaveType : u32 {
Unknown,
};
using UniqueSerialNumber = std::array<u8, 7>;
using UniqueSerialNumberExtension = std::array<u8, 3>;
using UniqueSerialNumber = std::array<u8, 10>;
// This is nn::nfc::DeviceHandle
using DeviceHandle = u64;
@@ -78,7 +80,6 @@ using DeviceHandle = u64;
// This is nn::nfc::TagInfo
struct TagInfo {
UniqueSerialNumber uuid;
UniqueSerialNumberExtension uuid_extension;
u8 uuid_length;
INSERT_PADDING_BYTES(0x15);
NfcProtocol protocol;
+19 -9
View File
@@ -85,7 +85,7 @@ enum class CabinetMode : u8 {
StartFormatter,
};
using LockBytes = std::array<u8, 2>;
using UuidPart = std::array<u8, 3>;
using HashData = std::array<u8, 0x20>;
using ApplicationArea = std::array<u8, 0xD8>;
using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
@@ -93,12 +93,20 @@ using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
// This is nn::nfp::TagInfo
using TagInfo = NFC::TagInfo;
struct TagUuid {
NFC::UniqueSerialNumber uid;
struct NtagTagUuid {
UuidPart part1;
UuidPart part2;
u8 nintendo_id;
LockBytes lock_bytes;
};
static_assert(sizeof(TagUuid) == 10, "TagUuid is an invalid size");
static_assert(sizeof(NtagTagUuid) == 7, "NtagTagUuid is an invalid size");
struct TagUuid {
UuidPart part1;
u8 crc_check1;
UuidPart part2;
u8 nintendo_id;
};
static_assert(sizeof(TagUuid) == 8, "TagUuid is an invalid size");
struct WriteDate {
u16 year;
@@ -231,7 +239,8 @@ struct EncryptedAmiiboFile {
static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size");
struct NTAG215File {
LockBytes lock_bytes; // Tag UUID
u8 uid_crc_check2;
u8 internal_number;
u16 static_lock; // Set defined pages as read only
u32 compability_container; // Defines available memory
HashData hmac_data; // Hash
@@ -250,8 +259,7 @@ struct NTAG215File {
u32_be register_info_crc;
ApplicationArea application_area; // Encrypted Game data
HashData hmac_tag; // Hash
NFC::UniqueSerialNumber uid; // Unique serial number
u8 nintendo_id; // Tag UUID
TagUuid uid;
AmiiboModelInfo model_info;
HashData keygen_salt; // Salt
u32 dynamic_lock; // Dynamic lock
@@ -264,7 +272,9 @@ static_assert(std::is_trivially_copyable_v<NTAG215File>, "NTAG215File must be tr
#pragma pack()
struct EncryptedNTAG215File {
TagUuid uuid; // Unique serial number
TagUuid uuid;
u8 uuid_crc_check2;
u8 internal_number;
u16 static_lock; // Set defined pages as read only
u32 compability_container; // Defines available memory
EncryptedAmiiboFile user_memory; // Writable data
@@ -849,8 +849,9 @@ static Result CreateCalendarTime(s64 time, int gmt_offset, CalendarTimeInternal&
static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time,
CalendarTimeInternal& calendar_time,
CalendarAdditionalInfo& calendar_additional_info) {
if ((rules.go_ahead && time < rules.ats[0]) ||
(rules.go_back && time > rules.ats[rules.time_count - 1])) {
ASSERT(rules.go_ahead ? rules.time_count > 0 : true);
if ((rules.go_back && time < rules.ats[0]) ||
(rules.go_ahead && time > rules.ats[rules.time_count - 1])) {
s64 seconds{};
if (time < rules.ats[0]) {
seconds = rules.ats[0] - time;
@@ -112,20 +112,14 @@ void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called, location_name={}", location_name);
TimeZone::TimeZoneRule time_zone_rule{};
if (const Result result{
time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
const Result result{time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule));
std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule));
ctx.WriteBuffer(time_zone_rule_outbuffer);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(result);
}
void ITimeZoneService::ToCalendarTime(HLERequestContext& ctx) {
@@ -82,6 +82,7 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) {
switch (nfc_file.GetSize()) {
case AmiiboSize:
case AmiiboSizeWithoutPassword:
case AmiiboSizeWithSignature:
data.resize(AmiiboSize);
if (nfc_file.Read(data) < AmiiboSizeWithoutPassword) {
return Info::NotAnAmiibo;
@@ -109,6 +110,7 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) {
switch (data.size_bytes()) {
case AmiiboSize:
case AmiiboSizeWithoutPassword:
case AmiiboSizeWithSignature:
nfc_data.resize(AmiiboSize);
break;
case MifareSize:
@@ -57,6 +57,7 @@ public:
private:
static constexpr std::size_t AmiiboSize = 0x21C;
static constexpr std::size_t AmiiboSizeWithoutPassword = AmiiboSize - 0x8;
static constexpr std::size_t AmiiboSizeWithSignature = AmiiboSize + 0x20;
static constexpr std::size_t MifareSize = 0x400;
std::string file_path{};
+6 -3
View File
@@ -719,9 +719,15 @@ void BufferCache<P>::BindHostVertexBuffers() {
bool any_valid{false};
auto& flags = maxwell3d->dirty.flags;
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
const Binding& binding = channel_state->vertex_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id);
SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
if (!flags[Dirty::VertexBuffer0 + index]) {
continue;
}
flags[Dirty::VertexBuffer0 + index] = false;
host_bindings.min_index = std::min(host_bindings.min_index, index);
host_bindings.max_index = std::max(host_bindings.max_index, index);
any_valid = true;
@@ -735,9 +741,6 @@ void BufferCache<P>::BindHostVertexBuffers() {
const Binding& binding = channel_state->vertex_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id);
SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
const u32 stride = maxwell3d->regs.vertex_streams[index].stride;
const u32 offset = buffer.Offset(binding.cpu_addr);
+7 -3
View File
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "video_core/dirty_flags.h"
#include "video_core/engines/draw_manager.h"
#include "video_core/rasterizer_interface.h"
@@ -195,8 +196,12 @@ void DrawManager::DrawTexture() {
if (lower_left) {
draw_texture_state.dst_y0 -= dst_height;
}
draw_texture_state.dst_x1 = draw_texture_state.dst_x0 + dst_width;
draw_texture_state.dst_y1 = draw_texture_state.dst_y0 + dst_height;
draw_texture_state.dst_x1 =
draw_texture_state.dst_x0 +
static_cast<f32>(Settings::values.resolution_info.ScaleUp(static_cast<u32>(dst_width)));
draw_texture_state.dst_y1 =
draw_texture_state.dst_y0 +
static_cast<f32>(Settings::values.resolution_info.ScaleUp(static_cast<u32>(dst_height)));
draw_texture_state.src_x0 = static_cast<float>(regs.draw_texture.src_x0) / 4096.f;
draw_texture_state.src_y0 = static_cast<float>(regs.draw_texture.src_y0) / 4096.f;
draw_texture_state.src_x1 =
@@ -207,7 +212,6 @@ void DrawManager::DrawTexture() {
draw_texture_state.src_y0;
draw_texture_state.src_sampler = regs.draw_texture.src_sampler;
draw_texture_state.src_texture = regs.draw_texture.src_texture;
maxwell3d->rasterizer->DrawTexture();
}
@@ -87,7 +87,8 @@ void ComputePipeline::Configure() {
texture_cache.SynchronizeComputeDescriptors();
boost::container::static_vector<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
std::array<GLuint, MAX_TEXTURES> samplers;
boost::container::static_vector<VideoCommon::SamplerId, MAX_TEXTURES> samplers;
std::array<GLuint, MAX_TEXTURES> gl_samplers;
std::array<GLuint, MAX_TEXTURES> textures;
std::array<GLuint, MAX_IMAGES> images;
GLsizei sampler_binding{};
@@ -131,7 +132,6 @@ void ComputePipeline::Configure() {
for (u32 index = 0; index < desc.count; ++index) {
const auto handle{read_handle(desc, index)};
views.push_back({handle.first});
samplers[sampler_binding++] = 0;
}
}
for (const auto& desc : info.image_buffer_descriptors) {
@@ -142,8 +142,8 @@ void ComputePipeline::Configure() {
const auto handle{read_handle(desc, index)};
views.push_back({handle.first});
Sampler* const sampler = texture_cache.GetComputeSampler(handle.second);
samplers[sampler_binding++] = sampler->Handle();
VideoCommon::SamplerId sampler = texture_cache.GetComputeSamplerId(handle.second);
samplers.push_back(sampler);
}
}
for (const auto& desc : info.image_descriptors) {
@@ -186,10 +186,17 @@ void ComputePipeline::Configure() {
const VideoCommon::ImageViewInOut* views_it{views.data() + num_texture_buffers +
num_image_buffers};
const VideoCommon::SamplerId* samplers_it{samplers.data()};
texture_binding += num_texture_buffers;
image_binding += num_image_buffers;
u32 texture_scaling_mask{};
for (const auto& desc : info.texture_buffer_descriptors) {
for (u32 index = 0; index < desc.count; ++index) {
gl_samplers[sampler_binding++] = 0;
}
}
for (const auto& desc : info.texture_descriptors) {
for (u32 index = 0; index < desc.count; ++index) {
ImageView& image_view{texture_cache.GetImageView((views_it++)->id)};
@@ -198,6 +205,12 @@ void ComputePipeline::Configure() {
texture_scaling_mask |= 1u << texture_binding;
}
++texture_binding;
const Sampler& sampler{texture_cache.GetSampler(*(samplers_it++))};
const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
!image_view.SupportsAnisotropy()};
gl_samplers[sampler_binding++] =
use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() : sampler.Handle();
}
}
u32 image_scaling_mask{};
@@ -228,7 +241,7 @@ void ComputePipeline::Configure() {
if (texture_binding != 0) {
ASSERT(texture_binding == sampler_binding);
glBindTextures(0, texture_binding, textures.data());
glBindSamplers(0, sampler_binding, samplers.data());
glBindSamplers(0, sampler_binding, gl_samplers.data());
}
if (image_binding != 0) {
glBindImageTextures(0, image_binding, images.data());
@@ -275,9 +275,9 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
template <typename Spec>
void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
std::array<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
std::array<GLuint, MAX_TEXTURES> samplers;
std::array<VideoCommon::SamplerId, MAX_TEXTURES> samplers;
size_t views_index{};
GLsizei sampler_binding{};
size_t samplers_index{};
texture_cache.SynchronizeGraphicsDescriptors();
@@ -337,7 +337,6 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
for (u32 index = 0; index < desc.count; ++index) {
const auto handle{read_handle(desc, index)};
views[views_index++] = {handle.first};
samplers[sampler_binding++] = 0;
}
}
}
@@ -351,8 +350,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
const auto handle{read_handle(desc, index)};
views[views_index++] = {handle.first};
Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.second)};
samplers[sampler_binding++] = sampler->Handle();
VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
samplers[samplers_index++] = sampler;
}
}
if constexpr (Spec::has_images) {
@@ -445,10 +444,13 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
program_manager.BindSourcePrograms(source_programs);
}
const VideoCommon::ImageViewInOut* views_it{views.data()};
const VideoCommon::SamplerId* samplers_it{samplers.data()};
GLsizei texture_binding = 0;
GLsizei image_binding = 0;
GLsizei sampler_binding{};
std::array<GLuint, MAX_TEXTURES> textures;
std::array<GLuint, MAX_IMAGES> images;
std::array<GLuint, MAX_TEXTURES> gl_samplers;
const auto prepare_stage{[&](size_t stage) {
buffer_cache.runtime.SetImagePointers(&textures[texture_binding], &images[image_binding]);
buffer_cache.BindHostStageBuffers(stage);
@@ -465,6 +467,13 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
u32 stage_image_binding{};
const auto& info{stage_infos[stage]};
if constexpr (Spec::has_texture_buffers) {
for (const auto& desc : info.texture_buffer_descriptors) {
for (u32 index = 0; index < desc.count; ++index) {
gl_samplers[sampler_binding++] = 0;
}
}
}
for (const auto& desc : info.texture_descriptors) {
for (u32 index = 0; index < desc.count; ++index) {
ImageView& image_view{texture_cache.GetImageView((views_it++)->id)};
@@ -474,6 +483,12 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
}
++texture_binding;
++stage_texture_binding;
const Sampler& sampler{texture_cache.GetSampler(*(samplers_it++))};
const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
!image_view.SupportsAnisotropy()};
gl_samplers[sampler_binding++] =
use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() : sampler.Handle();
}
}
for (const auto& desc : info.image_descriptors) {
@@ -534,7 +549,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
if (texture_binding != 0) {
ASSERT(texture_binding == sampler_binding);
glBindTextures(0, texture_binding, textures.data());
glBindSamplers(0, sampler_binding, samplers.data());
glBindSamplers(0, sampler_binding, gl_samplers.data());
}
if (image_binding != 0) {
glBindImageTextures(0, image_binding, images.data());
@@ -16,9 +16,9 @@ struct ShaderPools {
inst.ReleaseContents();
}
Shader::ObjectPool<Shader::IR::Inst> inst;
Shader::ObjectPool<Shader::IR::Block> block;
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block;
Shader::ObjectPool<Shader::IR::Inst> inst{8192};
Shader::ObjectPool<Shader::IR::Block> block{32};
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block{32};
};
struct Context {
@@ -1268,36 +1268,48 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const TSCEntry& config) {
UNIMPLEMENTED_IF(config.cubemap_anisotropy != 1);
sampler.Create();
const GLuint handle = sampler.handle;
glSamplerParameteri(handle, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(config.wrap_u));
glSamplerParameteri(handle, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(config.wrap_v));
glSamplerParameteri(handle, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(config.wrap_p));
glSamplerParameteri(handle, GL_TEXTURE_COMPARE_MODE, compare_mode);
glSamplerParameteri(handle, GL_TEXTURE_COMPARE_FUNC, compare_func);
glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, mag);
glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, min);
glSamplerParameterf(handle, GL_TEXTURE_LOD_BIAS, config.LodBias());
glSamplerParameterf(handle, GL_TEXTURE_MIN_LOD, config.MinLod());
glSamplerParameterf(handle, GL_TEXTURE_MAX_LOD, config.MaxLod());
glSamplerParameterfv(handle, GL_TEXTURE_BORDER_COLOR, config.BorderColor().data());
const f32 max_anisotropy = std::clamp(config.MaxAnisotropy(), 1.0f, 16.0f);
if (GLAD_GL_ARB_texture_filter_anisotropic || GLAD_GL_EXT_texture_filter_anisotropic) {
const f32 max_anisotropy = std::clamp(config.MaxAnisotropy(), 1.0f, 16.0f);
glSamplerParameterf(handle, GL_TEXTURE_MAX_ANISOTROPY, max_anisotropy);
} else {
LOG_WARNING(Render_OpenGL, "GL_ARB_texture_filter_anisotropic is required");
}
if (GLAD_GL_ARB_texture_filter_minmax || GLAD_GL_EXT_texture_filter_minmax) {
glSamplerParameteri(handle, GL_TEXTURE_REDUCTION_MODE_ARB, reduction_filter);
} else if (reduction_filter != GL_WEIGHTED_AVERAGE_ARB) {
LOG_WARNING(Render_OpenGL, "GL_ARB_texture_filter_minmax is required");
}
if (GLAD_GL_ARB_seamless_cubemap_per_texture || GLAD_GL_AMD_seamless_cubemap_per_texture) {
glSamplerParameteri(handle, GL_TEXTURE_CUBE_MAP_SEAMLESS, seamless);
} else if (seamless == GL_FALSE) {
// We default to false because it's more common
LOG_WARNING(Render_OpenGL, "GL_ARB_seamless_cubemap_per_texture is required");
const auto create_sampler = [&](const f32 anisotropy) {
OGLSampler new_sampler;
new_sampler.Create();
const GLuint handle = new_sampler.handle;
glSamplerParameteri(handle, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(config.wrap_u));
glSamplerParameteri(handle, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(config.wrap_v));
glSamplerParameteri(handle, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(config.wrap_p));
glSamplerParameteri(handle, GL_TEXTURE_COMPARE_MODE, compare_mode);
glSamplerParameteri(handle, GL_TEXTURE_COMPARE_FUNC, compare_func);
glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, mag);
glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, min);
glSamplerParameterf(handle, GL_TEXTURE_LOD_BIAS, config.LodBias());
glSamplerParameterf(handle, GL_TEXTURE_MIN_LOD, config.MinLod());
glSamplerParameterf(handle, GL_TEXTURE_MAX_LOD, config.MaxLod());
glSamplerParameterfv(handle, GL_TEXTURE_BORDER_COLOR, config.BorderColor().data());
if (GLAD_GL_ARB_texture_filter_anisotropic || GLAD_GL_EXT_texture_filter_anisotropic) {
glSamplerParameterf(handle, GL_TEXTURE_MAX_ANISOTROPY, anisotropy);
} else {
LOG_WARNING(Render_OpenGL, "GL_ARB_texture_filter_anisotropic is required");
}
if (GLAD_GL_ARB_texture_filter_minmax || GLAD_GL_EXT_texture_filter_minmax) {
glSamplerParameteri(handle, GL_TEXTURE_REDUCTION_MODE_ARB, reduction_filter);
} else if (reduction_filter != GL_WEIGHTED_AVERAGE_ARB) {
LOG_WARNING(Render_OpenGL, "GL_ARB_texture_filter_minmax is required");
}
if (GLAD_GL_ARB_seamless_cubemap_per_texture || GLAD_GL_AMD_seamless_cubemap_per_texture) {
glSamplerParameteri(handle, GL_TEXTURE_CUBE_MAP_SEAMLESS, seamless);
} else if (seamless == GL_FALSE) {
// We default to false because it's more common
LOG_WARNING(Render_OpenGL, "GL_ARB_seamless_cubemap_per_texture is required");
}
return new_sampler;
};
sampler = create_sampler(max_anisotropy);
const f32 max_anisotropy_default = static_cast<f32>(1U << config.max_anisotropy);
if (max_anisotropy > max_anisotropy_default) {
sampler_default_anisotropy = create_sampler(max_anisotropy_default);
}
}
@@ -309,12 +309,21 @@ class Sampler {
public:
explicit Sampler(TextureCacheRuntime&, const Tegra::Texture::TSCEntry&);
GLuint Handle() const noexcept {
[[nodiscard]] GLuint Handle() const noexcept {
return sampler.handle;
}
[[nodiscard]] GLuint HandleWithDefaultAnisotropy() const noexcept {
return sampler_default_anisotropy.handle;
}
[[nodiscard]] bool HasAddedAnisotropy() const noexcept {
return static_cast<bool>(sampler_default_anisotropy.handle);
}
private:
OGLSampler sampler;
OGLSampler sampler_default_anisotropy;
};
class Framebuffer {
@@ -178,7 +178,7 @@ public:
inline void PushImageDescriptors(TextureCache& texture_cache,
GuestDescriptorQueue& guest_descriptor_queue,
const Shader::Info& info, RescalingPushConstant& rescaling,
const VkSampler*& samplers,
const VideoCommon::SamplerId*& samplers,
const VideoCommon::ImageViewInOut*& views) {
const u32 num_texture_buffers = Shader::NumDescriptors(info.texture_buffer_descriptors);
const u32 num_image_buffers = Shader::NumDescriptors(info.image_buffer_descriptors);
@@ -187,10 +187,15 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
for (const auto& desc : info.texture_descriptors) {
for (u32 index = 0; index < desc.count; ++index) {
const VideoCommon::ImageViewId image_view_id{(views++)->id};
const VkSampler sampler{*(samplers++)};
const VideoCommon::SamplerId sampler_id{*(samplers++)};
ImageView& image_view{texture_cache.GetImageView(image_view_id)};
const VkImageView vk_image_view{image_view.Handle(desc.type)};
guest_descriptor_queue.AddSampledImage(vk_image_view, sampler);
const Sampler& sampler{texture_cache.GetSampler(sampler_id)};
const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
!image_view.SupportsAnisotropy()};
const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy()
: sampler.Handle()};
guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler);
rescaling.PushTexture(texture_cache.IsRescaling(image_view));
}
}
@@ -516,15 +516,15 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
buffer_handles.push_back(handle);
}
if (device.IsExtExtendedDynamicStateSupported()) {
scheduler.Record([bindings = bindings,
buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) {
scheduler.Record([bindings = std::move(bindings),
buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
cmdbuf.BindVertexBuffers2EXT(
bindings.min_index, bindings.max_index - bindings.min_index, buffer_handles.data(),
bindings.offsets.data(), bindings.sizes.data(), bindings.strides.data());
});
} else {
scheduler.Record([bindings = bindings,
buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) {
scheduler.Record([bindings = std::move(bindings),
buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
cmdbuf.BindVertexBuffers(bindings.min_index, bindings.max_index - bindings.min_index,
buffer_handles.data(), bindings.offsets.data());
});
@@ -561,12 +561,12 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<
for (u32 index = 0; index < bindings.buffers.size(); ++index) {
buffer_handles.push_back(bindings.buffers[index]->Handle());
}
scheduler.Record(
[bindings = bindings, buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) {
cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast<u32>(buffer_handles.size()),
buffer_handles.data(), bindings.offsets.data(),
bindings.sizes.data());
});
scheduler.Record([bindings = std::move(bindings),
buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) {
cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast<u32>(buffer_handles.size()),
buffer_handles.data(), bindings.offsets.data(),
bindings.sizes.data());
});
}
void BufferCacheRuntime::ReserveNullBuffer() {
@@ -115,7 +115,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
static constexpr size_t max_elements = 64;
boost::container::static_vector<VideoCommon::ImageViewInOut, max_elements> views;
boost::container::static_vector<VkSampler, max_elements> samplers;
boost::container::static_vector<VideoCommon::SamplerId, max_elements> samplers;
const auto& qmd{kepler_compute.launch_description};
const auto& cbufs{qmd.const_buffer_config};
@@ -160,8 +160,8 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
const auto handle{read_handle(desc, index)};
views.push_back({handle.first});
Sampler* const sampler = texture_cache.GetComputeSampler(handle.second);
samplers.push_back(sampler->Handle());
VideoCommon::SamplerId sampler = texture_cache.GetComputeSamplerId(handle.second);
samplers.push_back(sampler);
}
}
for (const auto& desc : info.image_descriptors) {
@@ -192,7 +192,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
buffer_cache.BindHostComputeBuffers();
RescalingPushConstant rescaling;
const VkSampler* samplers_it{samplers.data()};
const VideoCommon::SamplerId* samplers_it{samplers.data()};
const VideoCommon::ImageViewInOut* views_it{views.data()};
PushImageDescriptors(texture_cache, guest_descriptor_queue, info, rescaling, samplers_it,
views_it);
@@ -298,7 +298,7 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) {
template <typename Spec>
void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
std::array<VideoCommon::ImageViewInOut, MAX_IMAGE_ELEMENTS> views;
std::array<VkSampler, MAX_IMAGE_ELEMENTS> samplers;
std::array<VideoCommon::SamplerId, MAX_IMAGE_ELEMENTS> samplers;
size_t sampler_index{};
size_t view_index{};
@@ -367,8 +367,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
const auto handle{read_handle(desc, index)};
views[view_index++] = {handle.first};
Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.second)};
samplers[sampler_index++] = sampler->Handle();
VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
samplers[sampler_index++] = sampler;
}
}
if constexpr (Spec::has_images) {
@@ -453,7 +453,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
RescalingPushConstant rescaling;
RenderAreaPushConstant render_area;
const VkSampler* samplers_it{samplers.data()};
const VideoCommon::SamplerId* samplers_it{samplers.data()};
const VideoCommon::ImageViewInOut* views_it{views.data()};
const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE {
buffer_cache.BindHostStageBuffers(stage);
@@ -3,6 +3,7 @@
#include <thread>
#include "common/polyfill_ranges.h"
#include "common/settings.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/vulkan_common/vulkan_device.h"
@@ -92,9 +92,9 @@ struct ShaderPools {
inst.ReleaseContents();
}
Shader::ObjectPool<Shader::IR::Inst> inst;
Shader::ObjectPool<Shader::IR::Block> block;
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block;
Shader::ObjectPool<Shader::IR::Inst> inst{8192};
Shader::ObjectPool<Shader::IR::Block> block{32};
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block{32};
};
class PipelineCache : public VideoCommon::ShaderCache {
@@ -1802,27 +1802,36 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
// Some games have samplers with garbage. Sanitize them here.
const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f);
sampler = device.GetLogical().CreateSampler(VkSamplerCreateInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = pnext,
.flags = 0,
.magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
.minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
.mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
.addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
.addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
.addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
.mipLodBias = tsc.LodBias(),
.anisotropyEnable = static_cast<VkBool32>(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
.maxAnisotropy = max_anisotropy,
.compareEnable = tsc.depth_compare_enabled,
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
.borderColor =
arbitrary_borders ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : ConvertBorderColor(color),
.unnormalizedCoordinates = VK_FALSE,
});
const auto create_sampler = [&](const f32 anisotropy) {
return device.GetLogical().CreateSampler(VkSamplerCreateInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = pnext,
.flags = 0,
.magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
.minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
.mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
.addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
.addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
.addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
.mipLodBias = tsc.LodBias(),
.anisotropyEnable = static_cast<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
.maxAnisotropy = anisotropy,
.compareEnable = tsc.depth_compare_enabled,
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
.borderColor =
arbitrary_borders ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : ConvertBorderColor(color),
.unnormalizedCoordinates = VK_FALSE,
});
};
sampler = create_sampler(max_anisotropy);
const f32 max_anisotropy_default = static_cast<f32>(1U << tsc.max_anisotropy);
if (max_anisotropy > max_anisotropy_default) {
sampler_default_anisotropy = create_sampler(max_anisotropy_default);
}
}
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
@@ -279,8 +279,17 @@ public:
return *sampler;
}
[[nodiscard]] VkSampler HandleWithDefaultAnisotropy() const noexcept {
return *sampler_default_anisotropy;
}
[[nodiscard]] bool HasAddedAnisotropy() const noexcept {
return static_cast<bool>(sampler_default_anisotropy);
}
private:
vk::Sampler sampler;
vk::Sampler sampler_default_anisotropy;
};
class Framebuffer {
@@ -45,4 +45,56 @@ ImageViewBase::ImageViewBase(const ImageInfo& info, const ImageViewInfo& view_in
ImageViewBase::ImageViewBase(const NullImageViewParams&) : image_id{NULL_IMAGE_ID} {}
bool ImageViewBase::SupportsAnisotropy() const noexcept {
const bool has_mips = range.extent.levels > 1;
const bool is_2d = type == ImageViewType::e2D || type == ImageViewType::e2DArray;
if (!has_mips || !is_2d) {
return false;
}
switch (format) {
case PixelFormat::R8_UNORM:
case PixelFormat::R8_SNORM:
case PixelFormat::R8_SINT:
case PixelFormat::R8_UINT:
case PixelFormat::BC4_UNORM:
case PixelFormat::BC4_SNORM:
case PixelFormat::BC5_UNORM:
case PixelFormat::BC5_SNORM:
case PixelFormat::R32G32_FLOAT:
case PixelFormat::R32G32_SINT:
case PixelFormat::R32_FLOAT:
case PixelFormat::R16_FLOAT:
case PixelFormat::R16_UNORM:
case PixelFormat::R16_SNORM:
case PixelFormat::R16_UINT:
case PixelFormat::R16_SINT:
case PixelFormat::R16G16_UNORM:
case PixelFormat::R16G16_FLOAT:
case PixelFormat::R16G16_UINT:
case PixelFormat::R16G16_SINT:
case PixelFormat::R16G16_SNORM:
case PixelFormat::R8G8_UNORM:
case PixelFormat::R8G8_SNORM:
case PixelFormat::R8G8_SINT:
case PixelFormat::R8G8_UINT:
case PixelFormat::R32G32_UINT:
case PixelFormat::R32_UINT:
case PixelFormat::R32_SINT:
case PixelFormat::G4R4_UNORM:
// Depth formats
case PixelFormat::D32_FLOAT:
case PixelFormat::D16_UNORM:
// Stencil formats
case PixelFormat::S8_UINT:
// DepthStencil formats
case PixelFormat::D24_UNORM_S8_UINT:
case PixelFormat::S8_UINT_D24_UNORM:
case PixelFormat::D32_FLOAT_S8_UINT:
return false;
default:
return true;
}
}
} // namespace VideoCommon
@@ -33,6 +33,8 @@ struct ImageViewBase {
return type == ImageViewType::Buffer;
}
[[nodiscard]] bool SupportsAnisotropy() const noexcept;
ImageId image_id{};
GPUVAddr gpu_addr = 0;
PixelFormat format{};
+25 -5
View File
@@ -222,30 +222,50 @@ void TextureCache<P>::CheckFeedbackLoop(std::span<const ImageViewInOut> views) {
template <class P>
typename P::Sampler* TextureCache<P>::GetGraphicsSampler(u32 index) {
return &slot_samplers[GetGraphicsSamplerId(index)];
}
template <class P>
typename P::Sampler* TextureCache<P>::GetComputeSampler(u32 index) {
return &slot_samplers[GetComputeSamplerId(index)];
}
template <class P>
SamplerId TextureCache<P>::GetGraphicsSamplerId(u32 index) {
if (index > channel_state->graphics_sampler_table.Limit()) {
LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index);
return &slot_samplers[NULL_SAMPLER_ID];
return NULL_SAMPLER_ID;
}
const auto [descriptor, is_new] = channel_state->graphics_sampler_table.Read(index);
SamplerId& id = channel_state->graphics_sampler_ids[index];
if (is_new) {
id = FindSampler(descriptor);
}
return &slot_samplers[id];
return id;
}
template <class P>
typename P::Sampler* TextureCache<P>::GetComputeSampler(u32 index) {
SamplerId TextureCache<P>::GetComputeSamplerId(u32 index) {
if (index > channel_state->compute_sampler_table.Limit()) {
LOG_DEBUG(HW_GPU, "Invalid sampler index={}", index);
return &slot_samplers[NULL_SAMPLER_ID];
return NULL_SAMPLER_ID;
}
const auto [descriptor, is_new] = channel_state->compute_sampler_table.Read(index);
SamplerId& id = channel_state->compute_sampler_ids[index];
if (is_new) {
id = FindSampler(descriptor);
}
return &slot_samplers[id];
return id;
}
template <class P>
const typename P::Sampler& TextureCache<P>::GetSampler(SamplerId id) const noexcept {
return slot_samplers[id];
}
template <class P>
typename P::Sampler& TextureCache<P>::GetSampler(SamplerId id) noexcept {
return slot_samplers[id];
}
template <class P>
@@ -159,6 +159,18 @@ public:
/// Get the sampler from the compute descriptor table in the specified index
Sampler* GetComputeSampler(u32 index);
/// Get the sampler id from the graphics descriptor table in the specified index
SamplerId GetGraphicsSamplerId(u32 index);
/// Get the sampler id from the compute descriptor table in the specified index
SamplerId GetComputeSamplerId(u32 index);
/// Return a constant reference to the given sampler id
[[nodiscard]] const Sampler& GetSampler(SamplerId id) const noexcept;
/// Return a reference to the given sampler id
[[nodiscard]] Sampler& GetSampler(SamplerId id) noexcept;
/// Refresh the state for graphics image view and sampler descriptors
void SynchronizeGraphicsDescriptors();
+6 -1
View File
@@ -62,7 +62,12 @@ std::array<float, 4> TSCEntry::BorderColor() const noexcept {
}
float TSCEntry::MaxAnisotropy() const noexcept {
if (max_anisotropy == 0 && mipmap_filter != TextureMipmapFilter::Linear) {
const bool is_suitable_mipmap_filter = mipmap_filter != TextureMipmapFilter::None;
const bool has_regular_lods = min_lod_clamp == 0 && max_lod_clamp >= 256;
const bool is_bilinear_filter = min_filter == TextureFilter::Linear &&
reduction_filter == SamplerReduction::WeightedAverage;
if (max_anisotropy == 0 && (!is_suitable_mipmap_filter || !has_regular_lods ||
!is_bilinear_filter || depth_compare_enabled)) {
return 1.0f;
}
const auto anisotropic_settings = Settings::values.max_anisotropy.GetValue();
@@ -783,9 +783,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
FOR_EACH_VK_EXTENSION(EXTENSION);
#ifdef _WIN32
FOR_EACH_VK_EXTENSION_WIN32(EXTENSION);
#endif
#undef FEATURE_EXTENSION
#undef EXTENSION
@@ -804,11 +801,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
FOR_EACH_VK_RECOMMENDED_EXTENSION(LOG_EXTENSION);
FOR_EACH_VK_MANDATORY_EXTENSION(CHECK_EXTENSION);
#ifdef _WIN32
FOR_EACH_VK_MANDATORY_EXTENSION_WIN32(CHECK_EXTENSION);
#else
FOR_EACH_VK_MANDATORY_EXTENSION_GENERIC(CHECK_EXTENSION);
#endif
if (requires_swapchain) {
CHECK_EXTENSION(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
@@ -68,7 +68,6 @@
EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \
EXTENSION(KHR, DRAW_INDIRECT_COUNT, draw_indirect_count) \
EXTENSION(KHR, DRIVER_PROPERTIES, driver_properties) \
EXTENSION(KHR, EXTERNAL_MEMORY_FD, external_memory_fd) \
EXTENSION(KHR, PUSH_DESCRIPTOR, push_descriptor) \
EXTENSION(KHR, SAMPLER_MIRROR_CLAMP_TO_EDGE, sampler_mirror_clamp_to_edge) \
EXTENSION(KHR, SHADER_FLOAT_CONTROLS, shader_float_controls) \
@@ -80,9 +79,6 @@
EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \
EXTENSION(NV, VIEWPORT_SWIZZLE, viewport_swizzle)
#define FOR_EACH_VK_EXTENSION_WIN32(EXTENSION) \
EXTENSION(KHR, EXTERNAL_MEMORY_WIN32, external_memory_win32)
// Define extensions which must be supported.
#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) \
@@ -90,12 +86,6 @@
EXTENSION_NAME(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME) \
EXTENSION_NAME(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)
#define FOR_EACH_VK_MANDATORY_EXTENSION_GENERIC(EXTENSION_NAME) \
EXTENSION_NAME(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME)
#define FOR_EACH_VK_MANDATORY_EXTENSION_WIN32(EXTENSION_NAME) \
EXTENSION_NAME(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME)
// Define extensions where the absence of the extension may result in a degraded experience.
#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \
@@ -636,7 +626,6 @@ private:
FOR_EACH_VK_FEATURE_1_3(FEATURE);
FOR_EACH_VK_FEATURE_EXT(FEATURE);
FOR_EACH_VK_EXTENSION(EXTENSION);
FOR_EACH_VK_EXTENSION_WIN32(EXTENSION);
#undef EXTENSION
#undef FEATURE
+2
View File
@@ -210,6 +210,8 @@ add_executable(yuzu
util/url_request_interceptor.h
util/util.cpp
util/util.h
vk_device_info.cpp
vk_device_info.h
compatdb.cpp
compatdb.h
yuzu.qrc
+4 -1
View File
@@ -6,6 +6,7 @@
#include "common/settings.h"
#include "core/core.h"
#include "ui_configure.h"
#include "vk_device_info.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_audio.h"
#include "yuzu/configuration/configure_cpu.h"
@@ -28,6 +29,7 @@
ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
InputCommon::InputSubsystem* input_subsystem,
std::vector<VkDeviceInfo::Record>& vk_device_records,
Core::System& system_, bool enable_web_config)
: QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()},
registry(registry_), system{system_}, audio_tab{std::make_unique<ConfigureAudio>(system_,
@@ -38,7 +40,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
general_tab{std::make_unique<ConfigureGeneral>(system_, this)},
graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)},
graphics_tab{std::make_unique<ConfigureGraphics>(
system_, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this)},
system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
this)},
hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)},
input_tab{std::make_unique<ConfigureInput>(system_, this)},
network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
+5 -2
View File
@@ -4,7 +4,9 @@
#pragma once
#include <memory>
#include <vector>
#include <QDialog>
#include "yuzu/vk_device_info.h"
namespace Core {
class System;
@@ -40,8 +42,9 @@ class ConfigureDialog : public QDialog {
public:
explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
InputCommon::InputSubsystem* input_subsystem, Core::System& system_,
bool enable_web_config = true);
InputCommon::InputSubsystem* input_subsystem,
std::vector<VkDeviceInfo::Record>& vk_device_records,
Core::System& system_, bool enable_web_config = true);
~ConfigureDialog() override;
void ApplyConfiguration();
+10 -43
View File
@@ -1,10 +1,6 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Include this early to include Vulkan headers how we want to
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
#include <algorithm>
#include <functional>
#include <iosfwd>
@@ -34,13 +30,11 @@
#include "common/settings.h"
#include "core/core.h"
#include "ui_configure_graphics.h"
#include "video_core/vulkan_common/vulkan_instance.h"
#include "video_core/vulkan_common/vulkan_library.h"
#include "video_core/vulkan_common/vulkan_surface.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_graphics.h"
#include "yuzu/qt_common.h"
#include "yuzu/uisettings.h"
#include "yuzu/vk_device_info.h"
static const std::vector<VkPresentModeKHR> default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR,
VK_PRESENT_MODE_FIFO_KHR};
@@ -77,9 +71,10 @@ static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode)
}
ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
std::vector<VkDeviceInfo::Record>& records_,
const std::function<void()>& expose_compute_option_,
QWidget* parent)
: QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()},
: QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, records{records_},
expose_compute_option{expose_compute_option_}, system{system_} {
vulkan_device = Settings::values.vulkan_device.GetValue();
RetrieveVulkanDevices();
@@ -504,47 +499,19 @@ void ConfigureGraphics::UpdateAPILayout() {
}
}
void ConfigureGraphics::RetrieveVulkanDevices() try {
if (UISettings::values.has_broken_vulkan) {
return;
}
using namespace Vulkan;
auto* window = this->window()->windowHandle();
auto wsi = QtCommon::GetWindowSystemInfo(window);
vk::InstanceDispatch dld;
const auto library = OpenLibrary();
const vk::Instance instance = CreateInstance(*library, dld, VK_API_VERSION_1_1, wsi.type);
const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
vk::SurfaceKHR surface = CreateSurface(instance, wsi);
void ConfigureGraphics::RetrieveVulkanDevices() {
vulkan_devices.clear();
vulkan_devices.reserve(physical_devices.size());
vulkan_devices.reserve(records.size());
device_present_modes.clear();
device_present_modes.reserve(physical_devices.size());
for (const VkPhysicalDevice device : physical_devices) {
const auto physical_device = vk::PhysicalDevice(device, dld);
const std::string name = physical_device.GetProperties().deviceName;
const std::vector<VkPresentModeKHR> present_modes =
physical_device.GetSurfacePresentModesKHR(*surface);
vulkan_devices.push_back(QString::fromStdString(name));
device_present_modes.push_back(present_modes);
device_present_modes.reserve(records.size());
for (const auto& record : records) {
vulkan_devices.push_back(QString::fromStdString(record.name));
device_present_modes.push_back(record.vsync_support);
VkPhysicalDeviceDriverProperties driver_properties{};
driver_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
driver_properties.pNext = nullptr;
VkPhysicalDeviceProperties2 properties{};
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
properties.pNext = &driver_properties;
dld.vkGetPhysicalDeviceProperties2(physical_device, &properties);
if (driver_properties.driverID == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
if (record.is_intel_proprietary) {
expose_compute_option();
}
}
} catch (const Vulkan::vk::Exception& exception) {
LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
}
Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
@@ -12,6 +12,7 @@
#include <qobjectdefs.h>
#include <vulkan/vulkan_core.h>
#include "common/common_types.h"
#include "vk_device_info.h"
class QEvent;
class QObject;
@@ -39,6 +40,7 @@ class ConfigureGraphics : public QWidget {
public:
explicit ConfigureGraphics(const Core::System& system_,
std::vector<VkDeviceInfo::Record>& records,
const std::function<void()>& expose_compute_option_,
QWidget* parent = nullptr);
~ConfigureGraphics() override;
@@ -77,6 +79,7 @@ private:
ConfigurationShared::CheckState use_disk_shader_cache;
ConfigurationShared::CheckState use_asynchronous_gpu_emulation;
std::vector<VkDeviceInfo::Record>& records;
std::vector<QString> vulkan_devices;
std::vector<std::vector<VkPresentModeKHR>> device_present_modes;
std::vector<VkPresentModeKHR>
@@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <fmt/format.h>
@@ -34,8 +35,10 @@
#include "yuzu/configuration/configure_system.h"
#include "yuzu/uisettings.h"
#include "yuzu/util/util.h"
#include "yuzu/vk_device_info.h"
ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name,
std::vector<VkDeviceInfo::Record>& vk_device_records,
Core::System& system_)
: QDialog(parent),
ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_} {
@@ -50,7 +53,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
general_tab = std::make_unique<ConfigureGeneral>(system_, this);
graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(system_, this);
graphics_tab = std::make_unique<ConfigureGraphics>(
system_, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this);
system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this);
input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);
system_tab = std::make_unique<ConfigureSystem>(system_, this);
@@ -5,11 +5,13 @@
#include <memory>
#include <string>
#include <vector>
#include <QDialog>
#include <QList>
#include "core/file_sys/vfs_types.h"
#include "vk_device_info.h"
#include "yuzu/configuration/config.h"
namespace Core {
@@ -45,6 +47,7 @@ class ConfigurePerGame : public QDialog {
public:
// Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263
explicit ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name,
std::vector<VkDeviceInfo::Record>& vk_device_records,
Core::System& system_);
~ConfigurePerGame() override;
+6 -2
View File
@@ -147,6 +147,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/startup_checks.h"
#include "yuzu/uisettings.h"
#include "yuzu/util/clickable_label.h"
#include "yuzu/vk_device_info.h"
#ifdef YUZU_DBGHELP
#include "yuzu/mini_dump.h"
@@ -440,6 +441,8 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan
renderer_status_button->setDisabled(true);
renderer_status_button->setChecked(false);
} else {
VkDeviceInfo::PopulateRecords(vk_device_records, this->window()->windowHandle());
}
#if defined(HAVE_SDL2) && !defined(_WIN32)
@@ -3494,7 +3497,8 @@ void GMainWindow::OnConfigure() {
const auto old_language_index = Settings::values.language_index.GetValue();
Settings::SetConfiguringGlobal(true);
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system,
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(),
vk_device_records, *system,
!multiplayer_state->IsHostingPublicRoom());
connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
&GMainWindow::OnLanguageChanged);
@@ -3765,7 +3769,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
const auto v_file = Core::GetGameFileFromPath(vfs, file_name);
Settings::SetConfiguringGlobal(false);
ConfigurePerGame dialog(this, title_id, file_name, *system);
ConfigurePerGame dialog(this, title_id, file_name, vk_device_records, *system);
dialog.LoadFromFile(v_file);
const auto result = dialog.exec();
+6
View File
@@ -118,6 +118,10 @@ enum class ReinitializeKeyBehavior {
Warning,
};
namespace VkDeviceInfo {
class Record;
}
class GMainWindow : public QMainWindow {
Q_OBJECT
@@ -418,6 +422,8 @@ private:
GameListPlaceholder* game_list_placeholder;
std::vector<VkDeviceInfo::Record> vk_device_records;
// Status bar elements
QLabel* message_label = nullptr;
QLabel* shader_building_label = nullptr;
+58
View File
@@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <utility>
#include <vector>
#include "common/dynamic_library.h"
#include "common/logging/log.h"
#include "video_core/vulkan_common/vulkan_instance.h"
#include "video_core/vulkan_common/vulkan_library.h"
#include "video_core/vulkan_common/vulkan_surface.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
#include "yuzu/qt_common.h"
#include "yuzu/vk_device_info.h"
class QWindow;
namespace VkDeviceInfo {
Record::Record(std::string_view name_, const std::vector<VkPresentModeKHR>& vsync_modes_,
bool is_intel_proprietary_)
: name{name_}, vsync_support{vsync_modes_}, is_intel_proprietary{is_intel_proprietary_} {}
Record::~Record() = default;
void PopulateRecords(std::vector<Record>& records, QWindow* window) try {
using namespace Vulkan;
auto wsi = QtCommon::GetWindowSystemInfo(window);
vk::InstanceDispatch dld;
const auto library = OpenLibrary();
const vk::Instance instance = CreateInstance(*library, dld, VK_API_VERSION_1_1, wsi.type);
const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
vk::SurfaceKHR surface = CreateSurface(instance, wsi);
records.clear();
records.reserve(physical_devices.size());
for (const VkPhysicalDevice device : physical_devices) {
const auto physical_device = vk::PhysicalDevice(device, dld);
const std::string name = physical_device.GetProperties().deviceName;
const std::vector<VkPresentModeKHR> present_modes =
physical_device.GetSurfacePresentModesKHR(*surface);
VkPhysicalDeviceDriverProperties driver_properties{};
driver_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
driver_properties.pNext = nullptr;
VkPhysicalDeviceProperties2 properties{};
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
properties.pNext = &driver_properties;
dld.vkGetPhysicalDeviceProperties2(physical_device, &properties);
records.push_back(VkDeviceInfo::Record(name, present_modes,
driver_properties.driverID ==
VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS));
}
} catch (const Vulkan::vk::Exception& exception) {
LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
}
} // namespace VkDeviceInfo
+36
View File
@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <algorithm>
#include <iterator>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "common/common_types.h"
#include "vulkan/vulkan_core.h"
class QWindow;
namespace Settings {
enum class VSyncMode : u32;
}
// #include "common/settings.h"
namespace VkDeviceInfo {
// Short class to record Vulkan driver information for configuration purposes
class Record {
public:
explicit Record(std::string_view name, const std::vector<VkPresentModeKHR>& vsync_modes,
bool is_intel_proprietary);
~Record();
const std::string name;
const std::vector<VkPresentModeKHR> vsync_support;
const bool is_intel_proprietary;
};
void PopulateRecords(std::vector<Record>& records, QWindow* window);
} // namespace VkDeviceInfo
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "yuzu",
"builtin-baseline": "a487471068f4cb1cbb4eeb340763cdcc0a75fd68",
"builtin-baseline": "cbf56573a987527b39272e88cbdd11389b78c6e4",
"version": "1.0",
"dependencies": [
"boost-algorithm",