Compare commits

..

81 Commits

Author SHA1 Message Date
Morph a2d40b8185 hwopus: Update to 12.x 2021-04-07 02:57:39 -04:00
bunnei 068b2ffbcc Merge pull request #6146 from lat9nq/vp9_empty_memcpy
vp9: Avoid memcpy with null pointers
2021-04-06 21:57:43 -07:00
lat9nq a60653dcd3 vp9: Avoid memcpy with null pointers
Avoid sending null pointer to memcpy as reported by Undefined Behaviour
Sanitizer. Replaces the std::memcpy calls in SpliceVectors with
std::copy calls. Opting to replace all the memcpy's with copy's.

Co-authored-by: LC <mathew1800@gmail.com>
2021-04-05 00:44:38 -04:00
LC 7feb490f83 Merge pull request #6141 from lat9nq/cfg_gphcs_stack_use
configure_graphics: Prevent stack-use-after-scope
2021-04-04 18:16:50 -04:00
lat9nq 33ed02a239 configure_graphics: Prevent stack-use-after-scope
Address Sanitizer reports stack-use-after-scope on line 231
`vulkan_devices.push_back(QString::fromStdString(name));`. Instead of
using a pointer, copy the string into a std::string and use that,
instead.
2021-04-04 15:05:22 -04:00
Morph 69b2dbdffd Merge pull request #6139 from Morph1984/cmake-fix-build
ci: Fix MSVC build with CMake 3.20.0
2021-04-04 07:54:38 -04:00
Morph 17ad323b36 ci: Fix MSVC build with CMake 3.20.0 2021-04-04 07:49:21 -04:00
bunnei c92a211e7c Merge pull request #6127 from german77/udpSingleConnection
InputCommon: Improve UDP communications
2021-04-03 23:14:23 -07:00
bunnei c5ca8675c8 Merge pull request #6132 from MerryMage/code_size
arm_dynarmic: Increase size of code cache
2021-04-02 18:47:04 -07:00
Morph aca6ab6417 Merge pull request #6131 from german77/rightjoyconSLSR
HID: Fix SL and SR buttons for right joycon
2021-04-02 15:48:04 -04:00
MerryMage 0fbd7752c3 arm_dynarmic: Increase size of code cache 2021-04-02 18:09:15 +01:00
german77 eaf0c4af11 HID: Fix SL and SR buttons for right joycon 2021-04-02 09:03:11 -05:00
bunnei 94d77d0e39 Merge pull request #6129 from degasus/cmake_libzip
externals/cmake: Fix case spelling of libzip.
2021-04-01 23:06:36 -07:00
bunnei 824adb44fa Merge pull request #6128 from bunnei/update-dynarmic-2
externals: dynarmic: Update to latest rev. to increase code size.
2021-04-01 21:02:51 -07:00
Markus Wick d3e87d70ec externals: Fix case spelling of libzip.
CMake is case senstive, so Libzip vs LIBZIP was a bug.
Upstream calls themself libzip, so let's pick this naming.
2021-04-02 00:30:13 +02:00
bunnei 7ff7e65926 externals: dynarmic: Update to latest rev. to increase code size.
- The current limits are being hit in yuzu with some games.
- This should fix the slowdowns in newer updates for Super Smash Bros. Ultimate.
2021-04-01 13:23:12 -07:00
bunnei d69421b1db Merge pull request #6106 from MerryMage/nullptr-jit
[test] arm_dynarmic: Always have a 'valid' jit instance
2021-04-01 09:50:00 -07:00
bunnei e44622860a Merge pull request #6126 from Morph1984/stub-SetAlbumImageTakenNotificationEnabled
ISelfController: Stub SetAlbumImageTakenNotificationEnabled
2021-03-30 21:32:01 -07:00
german77 bb3dce9363 Use a single connection for UDP server, make connection test longer and check all pads instead of only the first one 2021-03-30 22:17:08 -05:00
Rodrigo Locatti 5ee669466f Merge pull request #5927 from ameerj/astc-compute
video_core: Accelerate ASTC texture decoding using compute shaders
2021-03-30 19:31:52 -03:00
bunnei eeea426c74 Merge pull request #6116 from german77/userArgument
yuzu/main: Add user command line argument
2021-03-30 15:01:33 -07:00
Morph ca30190fad ISelfController: Stub SetAlbumImageTakenNotificationEnabled
This service call sets an internal flag whether a notification is shown when an image is captured.
Currently we do not support capturing images via the capture button, so this can be stubbed for now.
2021-03-30 13:45:00 -04:00
bunnei b3f68098d5 Merge pull request #6124 from jbeich/vulkan+opengl
vulkan_common: enable OpenGL interop on other Unices
2021-03-30 09:37:00 -07:00
bunnei f234531f92 Merge pull request #6109 from german77/gestureID
HID: Initialize correctly the gesture finger_id and filter invalid inputs
2021-03-29 18:00:47 -07:00
Jan Beich 9b50b23a50 vulkan_common: enable OpenGL interop on other Unices 2021-03-30 00:25:25 +00:00
bunnei fb7dcbf7af Merge pull request #6102 from ogniK5377/fd-pass
nvdrv: Pass device fd and handle device create methods for device opening and closing
2021-03-29 12:53:55 -07:00
bunnei a63dcb6d56 Merge pull request #6118 from MerryMage/dynarmic
externals: Update dynarmic to c28f13af
2021-03-28 13:59:05 -07:00
bunnei f8561c7a65 Merge pull request #6115 from bunnei/fix-kernel-init
hle: kernel: Initialize preemption task after schedulers.
2021-03-28 12:13:39 -07:00
MerryMage a527e5f0cd externals: Update dynarmic to c28f13af
AVX-512 bugfixes
2021-03-27 21:34:20 +00:00
german77 9cebde760f yuzu/main: Add user command line argument 2021-03-27 12:34:48 -05:00
bunnei 8a5794c4db Merge pull request #6114 from Morph1984/friend-log
service: friend: Change logging class from ACC to Friend
2021-03-27 10:29:43 -07:00
bunnei cb7f2e5616 hle: kernel: Initialize preemption task after schedulers.
- Fixes a startup crash that occurs if CoreTiming tries to preempt before kernel initialization completes.
2021-03-27 10:04:13 -07:00
Morph 3b98fab850 service: friend: Change logging class from ACC to Friend 2021-03-27 11:11:07 -04:00
Narr the Reg 7c26a9aefe HID: Initialize correctly the gesture finger_id and filter invalid results 2021-03-26 11:13:18 -06:00
ameerj 2f83d9a61b astc_decoder: Refactor for style and more efficient memory use 2021-03-25 16:53:51 -04:00
Chloe Marcec 99fdfa1fcd nvdrv: Pass device fd and handle device create methods for device opening and closing
We pass the fd to the ioctl as well as alert the device when it's opened or closed to allow for fd unique actions to take place
2021-03-25 12:56:42 +11:00
bunnei 65774084fd Merge pull request #6101 from ogniK5377/alloc-as-ex
nvdrv: Change InitializeEx to AllocAsEx
2021-03-24 17:37:01 -07:00
bunnei b83eb4dd18 Merge pull request #6108 from jbeich/freebsd-async-shaders
gl_device: unblock async shaders on other Unix systems
2021-03-24 16:52:27 -07:00
Jan Beich 8c016b02e7 gl_device: unblock async shaders on other Unix systems
Mesa is the primary OpenGL provider on all FreeDesktop systems.
For example, iris is used on Intel GPU + FreeBSD by default.
2021-03-24 19:59:20 +00:00
MerryMage 52dae41d7f arm_dynarmic: Always have a 'valid' jit instance 2021-03-24 18:47:17 +00:00
bunnei 716285fab8 Merge pull request #6100 from bunnei/arm-fix
core: arm_dynarmic: Ensure JIT state is saved/restored on page table changes.
2021-03-23 17:08:37 -07:00
bunnei dde074eaab Merge pull request #6092 from ivan-boikov/cancel-dir-select
Fix cancelation of getExistingDirectory dialog
2021-03-22 17:55:18 -07:00
Chloe Marcec 875183e7c5 nvdrv: Change InitializeEx to AllocAsEx
Wee also report the correct "big page size" now in GetVARegions & fix up the struct for IoctlAllocAsEx
2021-03-22 19:59:30 +11:00
LC a50133fc5e Merge pull request #6095 from lat9nq/async-shader-block
gl_device: Block async shaders on AMD and Intel
2021-03-21 23:29:49 -04:00
LC e274e38205 Merge pull request #6078 from Morph1984/libusb-utf8
externals/libusb/CMakeLists: Add /utf-8 compile option for MSVC
2021-03-21 23:29:01 -04:00
bunnei a35717b245 core: arm_dynarmic: Ensure JIT state is saved/restored on page table changes.
- We re-create the JIT here without preserving any state.
2021-03-21 15:25:25 -07:00
lat9nq 538f097f97 gl_device: Block async shaders on AMD and Intel
Currently, the Windows versions of the Intel OpenGL driver and the AMD
proprietary OpenGL driver do not properly support (or in fact degrade)
when asynchronous shader compilation is enabled. This blocks
specifically those drivers from using this feature. This affects
AMDGPU-PRO on Linux, and AMD's and Intel's OpenGL drivers on Windows.
2021-03-21 01:25:45 -04:00
ivan-boikov afa4bcbb3b Fix cancelation of choose directory dialog 2021-03-20 15:52:22 +01:00
bunnei 2e85ee250d Merge pull request #6052 from Morph1984/vi-getindirectlayerimagemap
IApplicationDisplayService: Stub GetIndirectLayerImageMap
2021-03-19 22:59:25 -07:00
bunnei cb48ed2e1a Merge pull request #6056 from zkitX/spl-updates
service: Refactor spl
2021-03-18 15:49:41 -07:00
bunnei 4aa8189328 Merge pull request #6055 from MerryMage/exceed-the-limit
[testing] fiber: Double default stack size
2021-03-17 20:46:45 -07:00
Morph ec514a4d1b IApplicationDisplayService: Stub GetIndirectLayerImageMap
Used by games invoking the inline software keyboard such as GNOSIA
2021-03-17 03:25:12 -04:00
bunnei e1f7938a3b Merge pull request #6070 from Morph1984/sysver-11.0.1
system_version: Update to 11.0.1
2021-03-16 18:13:12 -07:00
bunnei ab102787fa Merge pull request #6083 from Morph1984/bsd-avoid-writebuffer
bsd: Avoid writing empty buffers
2021-03-16 11:59:05 -07:00
Morph 8441094ba3 bsd: Avoid writing empty buffers
Silences log spam on empty buffer writes
2021-03-16 12:50:44 -04:00
bunnei 0687a8370d Merge pull request #6069 from Morph1984/ngWord
system_archive: Update NgWord archive version
2021-03-15 15:44:04 -07:00
Morph df9899eed6 externals/libusb/CMakeLists: Add /utf-8 compile option for MSVC 2021-03-15 10:51:46 -04:00
Morph 824e53149d system_version: Update to 11.0.1 2021-03-14 08:47:36 -04:00
Morph 9761618a8d system_archive: Update NgWord archive version 2021-03-14 08:33:48 -04:00
bunnei d3a4a192fe Merge pull request #6054 from Morph1984/time-GetClockSnapshot
time: Assign the current time point to the ClockSnapshot
2021-03-13 23:15:54 -08:00
Rodrigo Locatti 2f30c10584 astc_decoder: Reimplement Layers
Reimplements the approach to decoding layers in the compute shader. Fixes multilayer astc decoding when using Vulkan.
2021-03-13 12:16:03 -05:00
ameerj c7553abe89 astc_decoder: Fix out of bounds memory access
resolves a crash with some anamolous textures found in Astral Chain.
2021-03-13 12:16:03 -05:00
ameerj 20eb368e14 renderer_vulkan: Accelerate ASTC decoding
Co-Authored-By: Rodrigo Locatti <reinuseslisp@airmail.cc>
2021-03-13 12:16:03 -05:00
ameerj f6566338eb host_shaders: Modify shader cmake integration to allow for larger shaders
using a raw string to encapsulate the entire shader code limits us to shaders of size less than 2KB. This change overcomes this limitation.
2021-03-13 12:16:03 -05:00
ameerj 2985e5e94c renderer_opengl: Accelerate ASTC texture decoding with a compute shader
ASTC texture decoding is currently handled by a CPU decoder for GPU's without native ASTC decoding support (most desktop GPUs). This is the cause for noticeable performance degradation in titles which use the format extensively.

This commit adds support to accelerate ASTC decoding using a compute shader on OpenGL for GPUs without native support.
2021-03-13 12:16:03 -05:00
bunnei 3b85ac2ac4 Merge pull request #6053 from Morph1984/time-CalculateSpanBetween
time: Fix CalculateSpanBetween implementation
2021-03-12 23:31:09 -08:00
bunnei 4735d18bb9 Merge pull request #6028 from bunnei/raster-cache
video_core: rasterizer_accelerated: Use a flat array instead of interval_map for cached pages.
2021-03-12 21:57:27 -08:00
bunnei a9d24b0df3 video_core: rasterizer_accelerated: Fix un/signed mismatch. 2021-03-12 21:52:49 -08:00
bunnei 5dae45b958 Merge pull request #5327 from AniLeo/master
qt: Set DISPLAY env var when not present
2021-03-12 12:10:28 -08:00
bunnei 827dcad26e Merge pull request #6040 from german77/toggleKeyboard
Enable toggle buttons for keyboard and mouse
2021-03-11 11:00:44 -08:00
zkitx 4439801c0f Fix casing on DeallocateAesKeySlot 2021-03-11 02:46:22 -05:00
zkitx ad653550eb Update SPL to fit N's service refactor (4.0.0+) which split into new services. 2021-03-11 02:36:48 -05:00
MerryMage 59173ff7a7 fiber: Double default stack size
Stack overflow occurs with some guest applications
2021-03-10 20:37:56 +00:00
Morph 2490ffbbce time: Assign the current time point to the ClockSnapshot
Fixes the timer in Super Smash Bros Ultimate's Spirit Board.
2021-03-10 11:40:51 -05:00
Ani cd7abba1a9 qt: Set DISPLAY env var when not present
Fixes web browser opening (Help > Open Mods Page, Help > Open Quickstart 
Guide)
2021-03-07 15:56:22 +00:00
german77 41e94b7b99 Enable mouse toggle buttons 2021-03-06 13:27:02 -06:00
german 4bcc5bacff Add toggle button option for normal buttons 2021-03-06 07:36:41 -06:00
german 1f228c51ca Enable button toggle for keyboard in the modifier button 2021-03-05 19:21:04 -06:00
bunnei 50ee9c46ab video_core: rasterizer_accelerated: Fix delta check ordering. 2021-03-02 17:48:02 -08:00
bunnei 6ab839462c video_core: rasterizer_accelerated: Improve error handling & fix implicit conversion. 2021-03-02 17:44:02 -08:00
bunnei 94da1e8a7e video_core: rasterizer_accelerated: Use a flat array instead of interval_map for cached pages.
- Uses a fixed 64MB for the cache instead of an ever growing map.
- Slightly faster by using atomics instead of a single mutex for access.
- Thanks for Rodrigo for the idea.
2021-03-02 16:57:53 -08:00
88 changed files with 2954 additions and 2217 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ steps:
displayName: 'Install vulkan-sdk'
- script: python -m pip install --upgrade pip conan
displayName: 'Install conan'
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd ..
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cmake --install . --config Release && cd ..
displayName: 'Configure CMake'
- task: MSBuild@1
displayName: 'Build'
+2 -2
View File
@@ -64,8 +64,8 @@ endif()
add_subdirectory(sirit)
# libzip
find_package(Libzip 1.5)
if (NOT LIBZIP_FOUND)
find_package(libzip 1.5)
if (NOT libzip_FOUND)
message(STATUS "libzip 1.5 or newer not found, falling back to externals")
add_subdirectory(libzip EXCLUDE_FROM_ALL)
endif()
-72
View File
@@ -1,72 +0,0 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBZIP QUIET libzip)
find_path(LIBZIP_INCLUDE_DIR
NAMES zip.h
PATHS ${PC_LIBZIP_INCLUDE_DIRS}
"$ENV{LIB_DIR}/include"
"$ENV{INCLUDE}"
/usr/local/include
/usr/include
)
find_path(LIBZIP_INCLUDE_DIR_ZIPCONF
NAMES zipconf.h
HINTS ${PC_LIBZIP_INCLUDE_DIRS}
"$ENV{LIB_DIR}/include"
"$ENV{LIB_DIR}/lib/libzip/include"
"$ENV{LIB}/lib/libzip/include"
/usr/local/lib/libzip/include
/usr/lib/libzip/include
/usr/local/include
/usr/include
"$ENV{INCLUDE}"
)
find_library(LIBZIP_LIBRARY
NAMES zip
PATHS ${PC_LIBZIP_LIBRARY_DIRS}
"$ENV{LIB_DIR}/lib" "$ENV{LIB}" /usr/local/lib /usr/lib
)
if (LIBZIP_INCLUDE_DIR_ZIPCONF)
FILE(READ "${LIBZIP_INCLUDE_DIR_ZIPCONF}/zipconf.h" _LIBZIP_VERSION_CONTENTS)
if (_LIBZIP_VERSION_CONTENTS)
STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9.]+)\".*" "\\1" LIBZIP_VERSION "${_LIBZIP_VERSION_CONTENTS}")
endif()
unset(_LIBZIP_VERSION_CONTENTS)
endif()
set(LIBZIP_VERSION ${LIBZIP_VERSION} CACHE STRING "Version number of libzip")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libzip
FOUND_VAR LIBZIP_FOUND
REQUIRED_VARS
LIBZIP_LIBRARY
LIBZIP_INCLUDE_DIR
LIBZIP_INCLUDE_DIR_ZIPCONF
LIBZIP_VERSION
VERSION_VAR LIBZIP_VERSION
)
if(LIBZIP_FOUND)
set(LIBZIP_LIBRARIES ${LIBZIP_LIBRARY})
set(LIBZIP_INCLUDE_DIRS ${LIBZIP_INCLUDE_DIR})
set(LIBZIP_DEFINITIONS ${PC_LIBZIP_CFLAGS_OTHER})
endif()
if(LIBZIP_FOUND AND NOT TARGET libzip::libzip)
add_library(libzip::libzip UNKNOWN IMPORTED)
set_target_properties(libzip::libzip PROPERTIES
IMPORTED_LOCATION "${LIBZIP_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_LIBZIP_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${LIBZIP_INCLUDE_DIR}"
)
endif()
mark_as_advanced(
LIBZIP_INCLUDE_DIR
LIBZIP_INCLUDE_DIR_ZIPCONF
LIBZIP_LIBRARY
LIBZIP_VERSION
)
+72
View File
@@ -0,0 +1,72 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_libzip QUIET libzip)
find_path(libzip_INCLUDE_DIR
NAMES zip.h
PATHS ${PC_libzip_INCLUDE_DIRS}
"$ENV{LIB_DIR}/include"
"$ENV{INCLUDE}"
/usr/local/include
/usr/include
)
find_path(libzip_INCLUDE_DIR_ZIPCONF
NAMES zipconf.h
HINTS ${PC_libzip_INCLUDE_DIRS}
"$ENV{LIB_DIR}/include"
"$ENV{LIB_DIR}/lib/libzip/include"
"$ENV{LIB}/lib/libzip/include"
/usr/local/lib/libzip/include
/usr/lib/libzip/include
/usr/local/include
/usr/include
"$ENV{INCLUDE}"
)
find_library(libzip_LIBRARY
NAMES zip
PATHS ${PC_libzip_LIBRARY_DIRS}
"$ENV{LIB_DIR}/lib" "$ENV{LIB}" /usr/local/lib /usr/lib
)
if (libzip_INCLUDE_DIR_ZIPCONF)
FILE(READ "${libzip_INCLUDE_DIR_ZIPCONF}/zipconf.h" _libzip_VERSION_CONTENTS)
if (_libzip_VERSION_CONTENTS)
STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9.]+)\".*" "\\1" libzip_VERSION "${_libzip_VERSION_CONTENTS}")
endif()
unset(_libzip_VERSION_CONTENTS)
endif()
set(libzip_VERSION ${libzip_VERSION} CACHE STRING "Version number of libzip")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libzip
FOUND_VAR libzip_FOUND
REQUIRED_VARS
libzip_LIBRARY
libzip_INCLUDE_DIR
libzip_INCLUDE_DIR_ZIPCONF
libzip_VERSION
VERSION_VAR libzip_VERSION
)
if(libzip_FOUND)
set(libzip_LIBRARIES ${libzip_LIBRARY})
set(libzip_INCLUDE_DIRS ${libzip_INCLUDE_DIR})
set(libzip_DEFINITIONS ${PC_libzip_CFLAGS_OTHER})
endif()
if(libzip_FOUND AND NOT TARGET libzip::libzip)
add_library(libzip::libzip UNKNOWN IMPORTED)
set_target_properties(libzip::libzip PROPERTIES
IMPORTED_LOCATION "${libzip_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_libzip_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${libzip_INCLUDE_DIR}"
)
endif()
mark_as_advanced(
libzip_INCLUDE_DIR
libzip_INCLUDE_DIR_ZIPCONF
libzip_LIBRARY
libzip_VERSION
)
+5
View File
@@ -1,3 +1,8 @@
# Ensure libusb compiles with UTF-8 encoding on MSVC
if(MSVC)
add_compile_options(/utf-8)
endif()
add_library(usb STATIC EXCLUDE_FROM_ALL
libusb/libusb/core.c
libusb/libusb/core.c
+1 -1
View File
@@ -11,7 +11,7 @@
namespace Common {
constexpr std::size_t default_stack_size = 256 * 1024;
constexpr std::size_t default_stack_size = 512 * 1024;
struct Fiber::FiberImpl {
FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {}
+17 -23
View File
@@ -114,18 +114,17 @@ public:
static constexpr u64 minimum_run_cycles = 1000U;
};
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table,
std::size_t address_space_bits) const {
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
Dynarmic::A32::UserConfig config;
config.callbacks = cb.get();
// TODO(bunnei): Implement page table for 32-bit
// config.page_table = &page_table.pointers;
config.coprocessors[15] = cp15;
config.define_unpredictable_behaviour = true;
static constexpr std::size_t PAGE_BITS = 12;
static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
page_table.pointers.data());
if (page_table) {
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
page_table->pointers.data());
}
config.absolute_offset_page_table = true;
config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
@@ -138,6 +137,10 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
// Timing
config.wall_clock_cntpct = uses_wall_clock;
// Code cache size
config.code_cache_size = 512 * 1024 * 1024;
config.far_code_offset = 256 * 1024 * 1024;
// Safe optimizations
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
@@ -201,7 +204,8 @@ ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handle
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
cb(std::make_unique<DynarmicCallbacks32>(*this)),
cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
jit(MakeJit(nullptr)) {}
ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
@@ -256,9 +260,6 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
if (!jit) {
return;
}
Dynarmic::A32::Context context;
jit->SaveContext(context);
ctx.cpu_registers = context.Regs();
@@ -268,9 +269,6 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
}
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
if (!jit) {
return;
}
Dynarmic::A32::Context context;
context.Regs() = ctx.cpu_registers;
context.ExtRegs() = ctx.extension_registers;
@@ -284,35 +282,31 @@ void ARM_Dynarmic_32::PrepareReschedule() {
}
void ARM_Dynarmic_32::ClearInstructionCache() {
if (!jit) {
return;
}
jit->ClearCache();
}
void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
if (!jit) {
return;
}
jit->InvalidateCacheRange(static_cast<u32>(addr), size);
}
void ARM_Dynarmic_32::ClearExclusiveState() {
if (!jit) {
return;
}
jit->ClearExclusiveState();
}
void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
std::size_t new_address_space_size_in_bits) {
ThreadContext32 ctx{};
SaveContext(ctx);
auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
auto iter = jit_cache.find(key);
if (iter != jit_cache.end()) {
jit = iter->second;
LoadContext(ctx);
return;
}
jit = MakeJit(page_table, new_address_space_size_in_bits);
jit = MakeJit(&page_table);
LoadContext(ctx);
jit_cache.emplace(key, jit);
}
+2 -3
View File
@@ -68,8 +68,7 @@ public:
std::size_t new_address_space_size_in_bits) override;
private:
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable& page_table,
std::size_t address_space_bits) const;
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =
@@ -80,10 +79,10 @@ private:
std::unique_ptr<DynarmicCallbacks32> cb;
JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A32::Jit> jit;
std::shared_ptr<DynarmicCP15> cp15;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
std::shared_ptr<Dynarmic::A32::Jit> jit;
};
} // namespace Core
+22 -25
View File
@@ -142,7 +142,7 @@ public:
static constexpr u64 minimum_run_cycles = 1000U;
};
std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table,
std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const {
Dynarmic::A64::UserConfig config;
@@ -150,13 +150,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
config.callbacks = cb.get();
// Memory
config.page_table = reinterpret_cast<void**>(page_table.pointers.data());
config.page_table_address_space_bits = address_space_bits;
config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.silently_mirror_page_table = false;
config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
if (page_table) {
config.page_table = reinterpret_cast<void**>(page_table->pointers.data());
config.page_table_address_space_bits = address_space_bits;
config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.silently_mirror_page_table = false;
config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
}
// Multi-process state
config.processor_id = core_index;
@@ -175,6 +177,10 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
// Timing
config.wall_clock_cntpct = uses_wall_clock;
// Code cache size
config.code_cache_size = 512 * 1024 * 1024;
config.far_code_offset = 256 * 1024 * 1024;
// Safe optimizations
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
@@ -237,7 +243,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
std::size_t core_index)
: ARM_Interface{system, interrupt_handlers, uses_wall_clock},
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
jit(MakeJit(nullptr, 48)) {}
ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
@@ -294,9 +301,6 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
}
void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
if (!jit) {
return;
}
ctx.cpu_registers = jit->GetRegisters();
ctx.sp = jit->GetSP();
ctx.pc = jit->GetPC();
@@ -308,9 +312,6 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
}
void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
if (!jit) {
return;
}
jit->SetRegisters(ctx.cpu_registers);
jit->SetSP(ctx.sp);
jit->SetPC(ctx.pc);
@@ -326,35 +327,31 @@ void ARM_Dynarmic_64::PrepareReschedule() {
}
void ARM_Dynarmic_64::ClearInstructionCache() {
if (!jit) {
return;
}
jit->ClearCache();
}
void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
if (!jit) {
return;
}
jit->InvalidateCacheRange(addr, size);
}
void ARM_Dynarmic_64::ClearExclusiveState() {
if (!jit) {
return;
}
jit->ClearExclusiveState();
}
void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
std::size_t new_address_space_size_in_bits) {
ThreadContext64 ctx{};
SaveContext(ctx);
auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
auto iter = jit_cache.find(key);
if (iter != jit_cache.end()) {
jit = iter->second;
LoadContext(ctx);
return;
}
jit = MakeJit(page_table, new_address_space_size_in_bits);
jit = MakeJit(&page_table, new_address_space_size_in_bits);
LoadContext(ctx);
jit_cache.emplace(key, jit);
}
+3 -2
View File
@@ -61,7 +61,7 @@ public:
std::size_t new_address_space_size_in_bits) override;
private:
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable& page_table,
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const;
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
@@ -71,10 +71,11 @@ private:
friend class DynarmicCallbacks64;
std::unique_ptr<DynarmicCallbacks64> cb;
JitCacheType jit_cache;
std::shared_ptr<Dynarmic::A64::Jit> jit;
std::size_t core_index;
DynarmicExclusiveMonitor& exclusive_monitor;
std::shared_ptr<Dynarmic::A64::Jit> jit;
};
} // namespace Core
+2 -2
View File
@@ -14,7 +14,7 @@ namespace NgWord1Data {
constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;
// Should this archive replacement mysteriously not work on a future game, consider updating.
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x20}; // 11.0.1 System Version
constexpr std::array<u8, 30> WORD_TXT{
0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
@@ -43,7 +43,7 @@ namespace NgWord2Data {
constexpr std::size_t NUMBER_AC_NX_FILES = 0x10;
// Should this archive replacement mysteriously not work on a future game, consider updating.
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x15}; // 5.1.0 System Version
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x1A}; // 11.0.1 System Version
constexpr std::array<u8, 0x2C> AC_NX_DATA{
0x1F, 0x8B, 0x08, 0x08, 0xD5, 0x2C, 0x09, 0x5C, 0x04, 0x00, 0x61, 0x63, 0x72, 0x61, 0x77,
@@ -14,15 +14,15 @@ namespace SystemVersionData {
constexpr u8 VERSION_MAJOR = 11;
constexpr u8 VERSION_MINOR = 0;
constexpr u8 VERSION_MICRO = 0;
constexpr u8 VERSION_MICRO = 1;
constexpr u8 REVISION_MAJOR = 5;
constexpr u8 REVISION_MAJOR = 1;
constexpr u8 REVISION_MINOR = 0;
constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "34197eba8810e2edd5e9dfcfbde7b340882e856d";
constexpr char DISPLAY_VERSION[] = "11.0.0";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.0-5.0";
constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf";
constexpr char DISPLAY_VERSION[] = "11.0.1";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0";
} // namespace SystemVersionData
+1 -1
View File
@@ -68,9 +68,9 @@ struct KernelCore::Impl {
InitializePhysicalCores();
InitializeSystemResourceLimit(kernel, system);
InitializeMemoryLayout();
InitializePreemption(kernel);
InitializeSchedulers();
InitializeSuspendThreads();
InitializePreemption(kernel);
}
void InitializeCores() {
+16 -1
View File
@@ -295,7 +295,7 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
{80, nullptr, "SetWirelessPriorityMode"},
{90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
{100, nullptr, "SetAlbumImageTakenNotificationEnabled"},
{100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
{110, nullptr, "SetApplicationAlbumUserData"},
{1000, nullptr, "GetDebugStorageChannel"},
};
@@ -560,6 +560,21 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
}
void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
// This service call sets an internal flag whether a notification is shown when an image is
// captured. Currently we do not support capturing images via the capture button, so this can be
// stubbed for now.
const bool album_image_taken_notification_enabled = rp.Pop<bool>();
LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}",
album_image_taken_notification_enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived");
on_new_message->Initialize();
+1
View File
@@ -146,6 +146,7 @@ private:
void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx);
void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx);
enum class ScreenshotPermission : u32 {
Inherit = 0,
+4
View File
@@ -297,6 +297,10 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
{1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
{2, nullptr, "OpenOpusDecoderForMultiStream"},
{3, nullptr, "GetWorkBufferSizeForMultiStream"},
{4, nullptr, "OpenHardwareOpusDecoderEx"},
{5, nullptr, "GetWorkBufferSizeEx"},
{6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
{7, nullptr, "GetWorkBufferSizeForMultiStreamEx"},
};
RegisterHandlers(functions);
}
+12 -11
View File
@@ -133,7 +133,7 @@ private:
void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) {
// This is safe to stub, as there should be no adverse consequences from reporting no
// blocked users.
LOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // Indicates there are no blocked users
@@ -141,14 +141,14 @@ private:
void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
// Stub used by Splatoon 2
LOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
// Stub used by Retro City Rampage
LOG_WARNING(Service_ACC, "(STUBBED) called");
LOG_WARNING(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -159,7 +159,7 @@ private:
const auto uuid = rp.PopRaw<Common::UUID>();
[[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
const auto pid = rp.Pop<u64>();
LOG_WARNING(Service_ACC, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
uuid.Format(), pid);
IPC::ResponseBuilder rb{ctx, 3};
@@ -191,7 +191,7 @@ public:
private:
void GetEvent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
LOG_DEBUG(Service_Friend, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
@@ -199,7 +199,7 @@ private:
}
void Clear(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
LOG_DEBUG(Service_Friend, "called");
while (!notifications.empty()) {
notifications.pop();
}
@@ -210,10 +210,10 @@ private:
}
void Pop(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
LOG_DEBUG(Service_Friend, "called");
if (notifications.empty()) {
LOG_ERROR(Service_ACC, "No notifications in queue!");
LOG_ERROR(Service_Friend, "No notifications in queue!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_NOTIFICATIONS);
return;
@@ -231,7 +231,8 @@ private:
break;
default:
// HOS seems not have an error case for an unknown notification
LOG_WARNING(Service_ACC, "Unknown notification {:08X}", notification.notification_type);
LOG_WARNING(Service_Friend, "Unknown notification {:08X}",
notification.notification_type);
break;
}
@@ -269,14 +270,14 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IFriendService>(system);
LOG_DEBUG(Service_ACC, "called");
LOG_DEBUG(Service_Friend, "called");
}
void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto uuid = rp.PopRaw<Common::UUID>();
LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format());
LOG_DEBUG(Service_Friend, "called, uuid={}", uuid.Format());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -4,6 +4,7 @@
#include <cstring>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/hle/service/hid/controllers/gesture.h"
@@ -19,9 +20,9 @@ Controller_Gesture::~Controller_Gesture() = default;
void Controller_Gesture::OnInit() {
for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
mouse_finger_id[id] = MAX_FINGERS;
keyboard_finger_id[id] = MAX_FINGERS;
udp_finger_id[id] = MAX_FINGERS;
mouse_finger_id[id] = MAX_POINTS;
keyboard_finger_id[id] = MAX_POINTS;
udp_finger_id[id] = MAX_POINTS;
}
}
@@ -142,6 +143,10 @@ std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const {
std::size_t Controller_Gesture::UpdateTouchInputEvent(
const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) {
const auto& [x, y, pressed] = touch_input;
if (finger_id > MAX_POINTS) {
LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id);
return MAX_POINTS;
}
if (pressed) {
if (finger_id == MAX_POINTS) {
const auto first_free_id = GetUnusedFingerID();
@@ -413,12 +413,16 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
}
if (controller_type == NPadControllerType::JoyLeft ||
controller_type == NPadControllerType::JoyRight) {
if (controller_type == NPadControllerType::JoyLeft) {
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
}
if (controller_type == NPadControllerType::JoyRight) {
pad_state.right_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
pad_state.right_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
}
if (controller_type == NPadControllerType::GameCube) {
trigger_entry.l_analog = static_cast<s32>(
button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0);
@@ -5,6 +5,7 @@
#include <algorithm>
#include <cstring>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
@@ -118,6 +119,10 @@ std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const {
std::size_t Controller_Touchscreen::UpdateTouchInputEvent(
const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) {
const auto& [x, y, pressed] = touch_input;
if (finger_id > MAX_FINGERS) {
LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id);
return MAX_FINGERS;
}
if (pressed) {
Attributes attribute{};
if (finger_id == MAX_FINGERS) {
+16 -4
View File
@@ -31,7 +31,7 @@ public:
* @param output A buffer where the output data will be written to.
* @returns The result code of the ioctl.
*/
virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input,
virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) = 0;
/**
@@ -42,7 +42,7 @@ public:
* @param output A buffer where the output data will be written to.
* @returns The result code of the ioctl.
*/
virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
/**
@@ -53,8 +53,20 @@ public:
* @param inline_output A buffer where the inlined output data will be written to.
* @returns The result code of the ioctl.
*/
virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) = 0;
virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) = 0;
/**
* Called once a device is openned
* @param fd The device fd
*/
virtual void OnOpen(DeviceFD fd) = 0;
/**
* Called once a device is closed
* @param fd The device fd
*/
virtual void OnClose(DeviceFD fd) = 0;
protected:
Core::System& system;
@@ -18,24 +18,27 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
nvdisp_disp0 ::~nvdisp_disp0() = default;
NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input,
NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
void nvdisp_disp0::OnOpen(DeviceFD fd) {}
void nvdisp_disp0::OnClose(DeviceFD fd) {}
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform,
const Common::Rectangle<int>& crop_rect) {
@@ -20,11 +20,15 @@ public:
explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
~nvdisp_disp0() override;
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
/// Performs a screen flip, drawing the buffer pointed to by the handle.
void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
@@ -21,7 +21,7 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
nvhost_as_gpu::~nvhost_as_gpu() = default;
NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
switch (command.group) {
case 'A':
@@ -39,7 +39,7 @@ NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
case 0x8:
return GetVARegions(input, output);
case 0x9:
return InitalizeEx(input, output);
return AllocAsEx(input, output);
case 0x14:
return Remap(input, output);
default:
@@ -54,14 +54,14 @@ NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
return NvResult::NotImplemented;
}
NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
switch (command.group) {
case 'A':
switch (command.cmd) {
@@ -78,11 +78,19 @@ NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std:
return NvResult::NotImplemented;
}
NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlInitalizeEx params{};
void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
void nvhost_as_gpu::OnClose(DeviceFD fd) {}
NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlAllocAsEx params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
if (params.big_page_size == 0) {
params.big_page_size = DEFAULT_BIG_PAGE_SIZE;
}
big_page_size = params.big_page_size;
return NvResult::Success;
}
@@ -276,13 +284,18 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
params.buf_size);
params.buf_size = 0x30;
params.regions[0].offset = 0x04000000;
params.regions[0].page_size = 0x1000;
params.regions[0].pages = 0x3fbfff;
params.regions[1].offset = 0x04000000;
params.regions[1].page_size = 0x10000;
params.regions[1].pages = 0x1bffff;
params.small = IoctlVaRegion{
.offset = 0x04000000,
.page_size = DEFAULT_SMALL_PAGE_SIZE,
.pages = 0x3fbfff,
};
params.big = IoctlVaRegion{
.offset = 0x04000000,
.page_size = big_page_size,
.pages = 0x1bffff,
};
// TODO(ogniK): This probably can stay stubbed but should add support way way later
@@ -299,18 +312,25 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
params.buf_size);
params.buf_size = 0x30;
params.regions[0].offset = 0x04000000;
params.regions[0].page_size = 0x1000;
params.regions[0].pages = 0x3fbfff;
params.regions[1].offset = 0x04000000;
params.regions[1].page_size = 0x10000;
params.regions[1].pages = 0x1bffff;
params.small = IoctlVaRegion{
.offset = 0x04000000,
.page_size = 0x1000,
.pages = 0x3fbfff,
};
params.big = IoctlVaRegion{
.offset = 0x04000000,
.page_size = big_page_size,
.pages = 0x1bffff,
};
// TODO(ogniK): This probably can stay stubbed but should add support way way later
std::memcpy(output.data(), &params, output.size());
std::memcpy(inline_output.data(), &params.regions, inline_output.size());
std::memcpy(inline_output.data(), &params.small, sizeof(IoctlVaRegion));
std::memcpy(inline_output.data() + sizeof(IoctlVaRegion), &params.big, sizeof(IoctlVaRegion));
return NvResult::Success;
}
@@ -16,6 +16,9 @@
namespace Service::Nvidia::Devices {
constexpr u32 DEFAULT_BIG_PAGE_SIZE = 1 << 16;
constexpr u32 DEFAULT_SMALL_PAGE_SIZE = 1 << 12;
class nvmap;
enum class AddressSpaceFlags : u32 {
@@ -30,11 +33,15 @@ public:
explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
~nvhost_as_gpu() override;
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
private:
class BufferMap final {
@@ -76,16 +83,16 @@ private:
bool is_allocated{};
};
struct IoctlInitalizeEx {
u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default
s32_le as_fd{}; // ignored; passes 0
u32_le flags{}; // passes 0
u32_le reserved{}; // ignored; passes 0
u64_le unk0{};
u64_le unk1{};
u64_le unk2{};
struct IoctlAllocAsEx {
u32_le flags{}; // usually passes 1
s32_le as_fd{}; // ignored; passes 0
u32_le big_page_size{};
u32_le reserved{}; // ignored; passes 0
u64_le va_range_start{};
u64_le va_range_end{};
u64_le va_range_split{};
};
static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");
static_assert(sizeof(IoctlAllocAsEx) == 40, "IoctlAllocAsEx is incorrect size");
struct IoctlAllocSpace {
u32_le pages{};
@@ -149,14 +156,16 @@ private:
u64_le buf_addr{}; // (contained output user ptr on linux, ignored)
u32_le buf_size{}; // forced to 2*sizeof(struct va_region)
u32_le reserved{};
IoctlVaRegion regions[2]{};
IoctlVaRegion small{};
IoctlVaRegion big{};
};
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
"IoctlGetVaRegions is incorrect size");
s32 channel{};
u32 big_page_size{DEFAULT_BIG_PAGE_SIZE};
NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
NvResult AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output);
NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output);
NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
@@ -20,7 +20,8 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
: nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
nvhost_ctrl::~nvhost_ctrl() = default;
NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
switch (command.group) {
case 0x0:
switch (command.cmd) {
@@ -46,18 +47,21 @@ NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::v
return NvResult::NotImplemented;
}
NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_outpu) {
NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_outpu) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
void nvhost_ctrl::OnOpen(DeviceFD fd) {}
void nvhost_ctrl::OnClose(DeviceFD fd) {}
NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
IocGetConfigParams params{};
std::memcpy(&params, input.data(), sizeof(params));
@@ -18,11 +18,15 @@ public:
SyncpointManager& syncpoint_manager);
~nvhost_ctrl() override;
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
private:
struct IocSyncptReadParams {
@@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices {
nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
switch (command.group) {
case 'G':
@@ -47,13 +47,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
return NvResult::NotImplemented;
}
NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
switch (command.group) {
case 'G':
@@ -73,6 +73,9 @@ NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input,
return NvResult::NotImplemented;
}
void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {}
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
@@ -16,11 +16,15 @@ public:
explicit nvhost_ctrl_gpu(Core::System& system);
~nvhost_ctrl_gpu() override;
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
private:
struct IoctlGpuCharacteristics {
@@ -23,7 +23,8 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
nvhost_gpu::~nvhost_gpu() = default;
NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
switch (command.group) {
case 0x0:
switch (command.cmd) {
@@ -74,7 +75,7 @@ NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
return NvResult::NotImplemented;
};
NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
switch (command.group) {
case 'H':
@@ -88,12 +89,15 @@ NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
return NvResult::NotImplemented;
}
NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
void nvhost_gpu::OnOpen(DeviceFD fd) {}
void nvhost_gpu::OnClose(DeviceFD fd) {}
NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
@@ -26,11 +26,15 @@ public:
SyncpointManager& syncpoint_manager);
~nvhost_gpu() override;
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
private:
enum class CtxObjects : u32_le {
@@ -16,7 +16,7 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de
: nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {}
nvhost_nvdec::~nvhost_nvdec() = default;
NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
switch (command.group) {
case 0x0:
@@ -57,16 +57,19 @@ NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
return NvResult::NotImplemented;
}
NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
void nvhost_nvdec::OnOpen(DeviceFD fd) {}
void nvhost_nvdec::OnClose(DeviceFD fd) {}
} // namespace Service::Nvidia::Devices
@@ -15,11 +15,15 @@ public:
SyncpointManager& syncpoint_manager);
~nvhost_nvdec() override;
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
};
} // namespace Service::Nvidia::Devices
@@ -13,7 +13,7 @@ namespace Service::Nvidia::Devices {
nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
nvhost_nvjpg::~nvhost_nvjpg() = default;
NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
switch (command.group) {
case 'H':
@@ -32,18 +32,21 @@ NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input,
return NvResult::NotImplemented;
}
NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
void nvhost_nvjpg::OnOpen(DeviceFD fd) {}
void nvhost_nvjpg::OnClose(DeviceFD fd) {}
NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
@@ -16,11 +16,15 @@ public:
explicit nvhost_nvjpg(Core::System& system);
~nvhost_nvjpg() override;
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
private:
struct IoctlSetNvmapFD {
@@ -16,7 +16,8 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
nvhost_vic::~nvhost_vic() = default;
NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
switch (command.group) {
case 0x0:
switch (command.cmd) {
@@ -55,16 +56,19 @@ NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
return NvResult::NotImplemented;
}
NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
void nvhost_vic::OnOpen(DeviceFD fd) {}
void nvhost_vic::OnClose(DeviceFD fd) {}
} // namespace Service::Nvidia::Devices
@@ -14,10 +14,14 @@ public:
SyncpointManager& syncpoint_manager);
~nvhost_vic();
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
};
} // namespace Service::Nvidia::Devices
+8 -4
View File
@@ -19,7 +19,8 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {
nvmap::~nvmap() = default;
NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) {
switch (command.group) {
case 0x1:
switch (command.cmd) {
@@ -47,18 +48,21 @@ NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<
return NvResult::NotImplemented;
}
NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
void nvmap::OnOpen(DeviceFD fd) {}
void nvmap::OnClose(DeviceFD fd) {}
VAddr nvmap::GetObjectAddress(u32 handle) const {
auto object = GetObject(handle);
ASSERT(object);
+8 -4
View File
@@ -19,11 +19,15 @@ public:
explicit nvmap(Core::System& system);
~nvmap() override;
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
std::vector<u8>& inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
std::vector<u8>& output, std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
/// Returns the allocated address of an nvmap object given its handle.
VAddr GetObjectAddress(u32 handle) const;
+7 -3
View File
@@ -89,6 +89,8 @@ DeviceFD Module::Open(const std::string& device_name) {
auto device = devices[device_name];
const DeviceFD fd = next_fd++;
device->OnOpen(fd);
open_files[fd] = std::move(device);
return fd;
@@ -108,7 +110,7 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input
return NvResult::NotImplemented;
}
return itr->second->Ioctl1(command, input, output);
return itr->second->Ioctl1(fd, command, input, output);
}
NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -125,7 +127,7 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input
return NvResult::NotImplemented;
}
return itr->second->Ioctl2(command, input, inline_input, output);
return itr->second->Ioctl2(fd, command, input, inline_input, output);
}
NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -142,7 +144,7 @@ NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input
return NvResult::NotImplemented;
}
return itr->second->Ioctl3(command, input, output, inline_output);
return itr->second->Ioctl3(fd, command, input, output, inline_output);
}
NvResult Module::Close(DeviceFD fd) {
@@ -158,6 +160,8 @@ NvResult Module::Close(DeviceFD fd) {
return NvResult::NotImplemented;
}
itr->second->OnClose(fd);
open_files.erase(itr);
return NvResult::Success;
+6 -2
View File
@@ -42,7 +42,9 @@ void BSD::PollWork::Execute(BSD* bsd) {
}
void BSD::PollWork::Response(Kernel::HLERequestContext& ctx) {
ctx.WriteBuffer(write_buffer);
if (write_buffer.size() > 0) {
ctx.WriteBuffer(write_buffer);
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
@@ -55,7 +57,9 @@ void BSD::AcceptWork::Execute(BSD* bsd) {
}
void BSD::AcceptWork::Response(Kernel::HLERequestContext& ctx) {
ctx.WriteBuffer(write_buffer);
if (write_buffer.size() > 0) {
ctx.WriteBuffer(write_buffer);
}
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(RESULT_SUCCESS);
+5
View File
@@ -43,6 +43,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
auto module = std::make_shared<Module>();
std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager);
std::make_shared<SPL>(system, module)->InstallAsService(service_manager);
std::make_shared<SPL_MIG>(system, module)->InstallAsService(service_manager);
std::make_shared<SPL_FS>(system, module)->InstallAsService(service_manager);
std::make_shared<SPL_SSL>(system, module)->InstallAsService(service_manager);
std::make_shared<SPL_ES>(system, module)->InstallAsService(service_manager);
std::make_shared<SPL_MANU>(system, module)->InstallAsService(service_manager);
}
} // namespace Service::SPL
+143 -9
View File
@@ -8,6 +8,79 @@ namespace Service::SPL {
SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
{11, nullptr, "IsDevelopment"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
};
// clang-format on
RegisterHandlers(functions);
}
SPL_MIG::SPL_MIG(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:mig") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
};
// clang-format on
RegisterHandlers(functions);
}
SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:fs") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"},
{12, nullptr, "GenerateSpecificAesKey"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
{19, nullptr, "LoadTitleKey"},
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{31, nullptr, "GetPackage2Hash"},
};
// clang-format on
RegisterHandlers(functions);
}
SPL_SSL::SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:ssl") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
@@ -16,18 +89,11 @@ SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
{9, nullptr, "ImportLotusKey"},
{10, nullptr, "DecryptLotusMessage"},
{11, nullptr, "IsDevelopment"},
{12, nullptr, "GenerateSpecificAesKey"},
{13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
{17, nullptr, "ImportEsKey"},
{18, nullptr, "UnwrapTitleKey"},
{19, nullptr, "LoadTitleKey"},
{20, nullptr, "PrepareEsCommonKey"},
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
@@ -35,15 +101,83 @@ SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
{25, nullptr, "GetBootReason"},
{26, nullptr, "DecryptAndStoreSslClientCertKey"},
{27, nullptr, "ModularExponentiateWithSslClientCertKey"},
};
// clang-format on
RegisterHandlers(functions);
}
SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:es") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
{11, nullptr, "IsDevelopment"},
{13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
{18, nullptr, "UnwrapTitleKey"},
{20, nullptr, "PrepareEsCommonKey"},
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{28, nullptr, "DecryptAndStoreDrmDeviceCertKey"},
{29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"},
{30, nullptr, "ReencryptDeviceUniqueData "},
{31, nullptr, "PrepareEsArchiveKey"}, // This is also GetPackage2Hash?
{31, nullptr, "PrepareEsArchiveKey"},
{32, nullptr, "LoadPreparedAesKey"},
};
// clang-format on
RegisterHandlers(functions);
}
SPL_MANU::SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_)
: Interface(system_, std::move(module_), "spl:manu") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
{11, nullptr, "IsDevelopment"},
{13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
{21, nullptr, "AllocateAesKeyslot"},
{22, nullptr, "DeallocateAesKeySlot"},
{23, nullptr, "GetAesKeyslotAvailableEvent"},
{24, nullptr, "SetBootReason"},
{25, nullptr, "GetBootReason"},
{30, nullptr, "ReencryptDeviceUniqueData"},
};
// clang-format on
RegisterHandlers(functions);
}
SPL::~SPL() = default;
SPL_MIG::~SPL_MIG() = default;
SPL_FS::~SPL_FS() = default;
SPL_SSL::~SPL_SSL() = default;
SPL_ES::~SPL_ES() = default;
SPL_MANU::~SPL_MANU() = default;
} // namespace Service::SPL
+30
View File
@@ -18,4 +18,34 @@ public:
~SPL() override;
};
class SPL_MIG final : public Module::Interface {
public:
explicit SPL_MIG(Core::System& system_, std::shared_ptr<Module> module_);
~SPL_MIG() override;
};
class SPL_FS final : public Module::Interface {
public:
explicit SPL_FS(Core::System& system_, std::shared_ptr<Module> module_);
~SPL_FS() override;
};
class SPL_SSL final : public Module::Interface {
public:
explicit SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_);
~SPL_SSL() override;
};
class SPL_ES final : public Module::Interface {
public:
explicit SPL_ES(Core::System& system_, std::shared_ptr<Module> module_);
~SPL_ES() override;
};
class SPL_MANU final : public Module::Interface {
public:
explicit SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_);
~SPL_MANU() override;
};
} // namespace Service::SPL
+2
View File
@@ -140,6 +140,8 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
const auto current_time_point{
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
clock_snapshot.steady_clock_time_point = current_time_point;
if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime(
clock_snapshot.user_time, current_time_point, clock_snapshot.user_context)};
result != RESULT_SUCCESS) {
+27 -1
View File
@@ -1217,6 +1217,32 @@ private:
}
}
void GetIndirectLayerImageMap(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto width = rp.Pop<s64>();
const auto height = rp.Pop<s64>();
const auto indirect_layer_consumer_handle = rp.Pop<u64>();
const auto applet_resource_user_id = rp.Pop<u64>();
LOG_WARNING(Service_VI,
"(STUBBED) called, width={}, height={}, indirect_layer_consumer_handle={}, "
"applet_resource_user_id={}",
width, height, indirect_layer_consumer_handle, applet_resource_user_id);
std::vector<u8> out_buffer(0x46);
ctx.WriteBuffer(out_buffer);
// TODO: Figure out what these are
constexpr s64 unknown_result_1 = 0;
constexpr s64 unknown_result_2 = 0;
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(unknown_result_1);
rb.Push(unknown_result_2);
rb.Push(RESULT_SUCCESS);
}
void GetIndirectLayerImageRequiredMemoryInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto width = rp.Pop<u64>();
@@ -1276,7 +1302,7 @@ IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
{2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
{2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
{2450, nullptr, "GetIndirectLayerImageMap"},
{2450, &IApplicationDisplayService::GetIndirectLayerImageMap, "GetIndirectLayerImageMap"},
{2451, nullptr, "GetIndirectLayerImageCropMap"},
{2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
"GetIndirectLayerImageRequiredMemoryInfo"},
+28 -3
View File
@@ -12,20 +12,39 @@ namespace InputCommon {
class KeyButton final : public Input::ButtonDevice {
public:
explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_)
: key_button_list(std::move(key_button_list_)) {}
explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_, bool toggle_)
: key_button_list(std::move(key_button_list_)), toggle(toggle_) {}
~KeyButton() override;
bool GetStatus() const override {
if (toggle) {
return toggled_status.load(std::memory_order_relaxed);
}
return status.load();
}
void ToggleButton() {
if (lock) {
return;
}
lock = true;
const bool old_toggle_status = toggled_status.load();
toggled_status.store(!old_toggle_status);
}
void UnlockButton() {
lock = false;
}
friend class KeyButtonList;
private:
std::shared_ptr<KeyButtonList> key_button_list;
std::atomic<bool> status{false};
std::atomic<bool> toggled_status{false};
bool lock{false};
const bool toggle;
};
struct KeyButtonPair {
@@ -51,6 +70,11 @@ public:
for (const KeyButtonPair& pair : list) {
if (pair.key_code == key_code) {
pair.key_button->status.store(pressed);
if (pressed) {
pair.key_button->ToggleButton();
} else {
pair.key_button->UnlockButton();
}
}
}
}
@@ -75,7 +99,8 @@ KeyButton::~KeyButton() {
std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) {
const int key_code = params.Get("code", 0);
std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list);
const bool toggle = params.Get("toggle", false);
std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list, toggle);
key_button_list->AddKeyButton(key_code, button.get());
return button;
}
+36
View File
@@ -162,6 +162,42 @@ void Mouse::EndConfiguration() {
configuring = false;
}
bool Mouse::ToggleButton(std::size_t button_) {
if (button_ >= mouse_info.size()) {
return false;
}
const auto button = 1U << button_;
const bool button_state = (toggle_buttons & button) != 0;
const bool button_lock = (lock_buttons & button) != 0;
if (button_lock) {
return button_state;
}
lock_buttons |= static_cast<u16>(button);
if (button_state) {
toggle_buttons &= static_cast<u16>(0xFF - button);
} else {
toggle_buttons |= static_cast<u16>(button);
}
return !button_state;
}
bool Mouse::UnlockButton(std::size_t button_) {
if (button_ >= mouse_info.size()) {
return false;
}
const auto button = 1U << button_;
const bool button_state = (toggle_buttons & button) != 0;
lock_buttons &= static_cast<u16>(0xFF - button);
return button_state;
}
Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() {
return mouse_queue;
}
+5
View File
@@ -69,6 +69,9 @@ public:
*/
void ReleaseButton(MouseButton button_);
[[nodiscard]] bool ToggleButton(std::size_t button_);
[[nodiscard]] bool UnlockButton(std::size_t button_);
[[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
[[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
@@ -94,6 +97,8 @@ private:
};
u16 buttons{};
u16 toggle_buttons{};
u16 lock_buttons{};
std::thread update_thread;
MouseButton last_button{MouseButton::Undefined};
std::array<MouseInfo, 7> mouse_info;
+15 -5
View File
@@ -14,16 +14,25 @@ namespace InputCommon {
class MouseButton final : public Input::ButtonDevice {
public:
explicit MouseButton(u32 button_, const MouseInput::Mouse* mouse_input_)
: button(button_), mouse_input(mouse_input_) {}
explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_)
: button(button_), toggle(toggle_), mouse_input(mouse_input_) {}
bool GetStatus() const override {
return mouse_input->GetMouseState(button).pressed;
const bool button_state = mouse_input->GetMouseState(button).pressed;
if (!toggle) {
return button_state;
}
if (button_state) {
return mouse_input->ToggleButton(button);
}
return mouse_input->UnlockButton(button);
}
private:
const u32 button;
const MouseInput::Mouse* mouse_input;
const bool toggle;
MouseInput::Mouse* mouse_input;
};
MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
@@ -32,8 +41,9 @@ MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_
std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create(
const Common::ParamPackage& params) {
const auto button_id = params.Get("button", 0);
const auto toggle = params.Get("toggle", false);
return std::make_unique<MouseButton>(button_id, mouse_input.get());
return std::make_unique<MouseButton>(button_id, toggle, mouse_input.get());
}
Common::ParamPackage MouseButtonFactory::GetNextInput() const {
+72 -75
View File
@@ -27,11 +27,9 @@ class Socket {
public:
using clock = std::chrono::system_clock;
explicit Socket(const std::string& host, u16 port, std::size_t pad_index_,
SocketCallback callback_)
explicit Socket(const std::string& host, u16 port, SocketCallback callback_)
: callback(std::move(callback_)), timer(io_service),
socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()),
pad_index(pad_index_) {
socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) {
boost::system::error_code ec{};
auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
if (ec.value() != boost::system::errc::success) {
@@ -99,15 +97,15 @@ private:
void HandleSend(const boost::system::error_code&) {
boost::system::error_code _ignored{};
// Send a request for getting port info for the pad
const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}};
const Request::PortInfo port_info{4, {0, 1, 2, 3}};
const auto port_message = Request::Create(port_info, client_id);
std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);
socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);
// Send a request for getting pad data for the pad
const Request::PadData pad_data{
Request::PadData::Flags::Id,
static_cast<u8>(pad_index),
Request::PadData::Flags::AllPorts,
0,
EMPTY_MAC_ADDRESS,
};
const auto pad_message = Request::Create(pad_data, client_id);
@@ -122,7 +120,6 @@ private:
udp::socket socket;
const u32 client_id;
std::size_t pad_index{};
static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>);
@@ -150,34 +147,32 @@ Client::~Client() {
Reset();
}
Client::ClientData::ClientData() = default;
Client::ClientConnection::ClientConnection() = default;
Client::ClientData::~ClientData() = default;
Client::ClientConnection::~ClientConnection() = default;
std::vector<Common::ParamPackage> Client::GetInputDevices() const {
std::vector<Common::ParamPackage> devices;
for (std::size_t client = 0; client < clients.size(); client++) {
if (!DeviceConnected(client)) {
for (std::size_t pad = 0; pad < pads.size(); pad++) {
if (!DeviceConnected(pad)) {
continue;
}
std::string name = fmt::format("UDP Controller {}", client);
std::string name = fmt::format("UDP Controller {}", pad);
devices.emplace_back(Common::ParamPackage{
{"class", "cemuhookudp"},
{"display", std::move(name)},
{"port", std::to_string(client)},
{"port", std::to_string(pad)},
});
}
return devices;
}
bool Client::DeviceConnected(std::size_t client) const {
bool Client::DeviceConnected(std::size_t pad) const {
// Use last timestamp to detect if the socket has stopped sending data
const auto now = std::chrono::steady_clock::now();
const auto time_difference =
static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>(
now - clients[client].last_motion_update)
.count());
return time_difference < 1000 && clients[client].active == 1;
const auto time_difference = static_cast<u64>(
std::chrono::duration_cast<std::chrono::milliseconds>(now - pads[pad].last_update).count());
return time_difference < 1000 && pads[pad].connected;
}
void Client::ReloadSockets() {
@@ -202,25 +197,21 @@ void Client::ReloadSockets() {
continue;
}
for (std::size_t pad = 0; pad < 4; ++pad) {
const std::size_t client_number =
GetClientNumber(udp_input_address, udp_input_port, pad);
if (client_number != MAX_UDP_CLIENTS) {
LOG_ERROR(Input, "Duplicated UDP servers found");
continue;
}
StartCommunication(client++, udp_input_address, udp_input_port, pad);
const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port);
if (client_number != MAX_UDP_CLIENTS) {
LOG_ERROR(Input, "Duplicated UDP servers found");
continue;
}
StartCommunication(client++, udp_input_address, udp_input_port);
}
}
std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const {
std::size_t Client::GetClientNumber(std::string_view host, u16 port) const {
for (std::size_t client = 0; client < clients.size(); client++) {
if (clients[client].active == -1) {
continue;
}
if (clients[client].host == host && clients[client].port == port &&
clients[client].pad_index == pad) {
if (clients[client].host == host && clients[client].port == port) {
return client;
}
}
@@ -236,69 +227,75 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) {
}
void Client::OnPadData(Response::PadData data, std::size_t client) {
// Accept packets only for the correct pad
if (static_cast<u8>(clients[client].pad_index) != data.info.id) {
const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id;
if (pad_index >= pads.size()) {
LOG_ERROR(Input, "Invalid pad id {}", data.info.id);
return;
}
LOG_TRACE(Input, "PadData packet received");
if (data.packet_counter == clients[client].packet_sequence) {
if (data.packet_counter == pads[pad_index].packet_sequence) {
LOG_WARNING(
Input,
"PadData packet dropped because its stale info. Current count: {} Packet count: {}",
clients[client].packet_sequence, data.packet_counter);
pads[pad_index].packet_sequence, data.packet_counter);
pads[pad_index].connected = false;
return;
}
clients[client].active = static_cast<s8>(data.info.is_pad_active);
clients[client].packet_sequence = data.packet_counter;
clients[client].active = 1;
pads[pad_index].connected = true;
pads[pad_index].packet_sequence = data.packet_counter;
const auto now = std::chrono::steady_clock::now();
const auto time_difference =
static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>(
now - clients[client].last_motion_update)
.count());
clients[client].last_motion_update = now;
const auto time_difference = static_cast<u64>(
std::chrono::duration_cast<std::chrono::microseconds>(now - pads[pad_index].last_update)
.count());
pads[pad_index].last_update = now;
const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw};
clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
// Gyroscope values are not it the correct scale from better joy.
// Dividing by 312 allows us to make one full turn = 1 turn
// This must be a configurable valued called sensitivity
clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f);
clients[client].motion.UpdateRotation(time_difference);
clients[client].motion.UpdateOrientation(time_difference);
pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f);
pads[pad_index].motion.UpdateRotation(time_difference);
pads[pad_index].motion.UpdateOrientation(time_difference);
{
std::lock_guard guard(clients[client].status.update_mutex);
clients[client].status.motion_status = clients[client].motion.GetMotion();
std::lock_guard guard(pads[pad_index].status.update_mutex);
pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion();
for (std::size_t id = 0; id < data.touch.size(); ++id) {
UpdateTouchInput(data.touch[id], client, id);
}
if (configuring) {
const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
UpdateYuzuSettings(client, accelerometer, gyroscope);
const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope();
const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration();
UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope);
}
}
}
void Client::StartCommunication(std::size_t client, const std::string& host, u16 port,
std::size_t pad_index) {
void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) {
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
[this](Response::PortInfo info) { OnPortInfo(info); },
[this, client](Response::PadData data) { OnPadData(data, client); }};
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port,
pad_index);
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
clients[client].host = host;
clients[client].port = port;
clients[client].pad_index = pad_index;
clients[client].active = 0;
clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback);
clients[client].socket = std::make_unique<Socket>(host, port, callback);
clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
// Set motion parameters
// SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
// Real HW values are unknown, 0.0001 is an approximate to Standard
clients[client].motion.SetGyroThreshold(0.0001f);
for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) {
pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f);
}
}
void Client::Reset() {
@@ -311,8 +308,8 @@ void Client::Reset() {
}
}
void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
const Common::Vec3<float>& gyro) {
void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro) {
if (gyro.Length() > 0.2f) {
LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client,
gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]);
@@ -320,7 +317,7 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a
UDPPadStatus pad{
.host = clients[client].host,
.port = clients[client].port,
.pad_index = clients[client].pad_index,
.pad_index = pad_index,
};
for (std::size_t i = 0; i < 3; ++i) {
if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
@@ -391,19 +388,19 @@ void Client::EndConfiguration() {
}
DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) {
const std::size_t client_number = GetClientNumber(host, port, pad);
if (client_number == MAX_UDP_CLIENTS) {
return clients[0].status;
const std::size_t client_number = GetClientNumber(host, port);
if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) {
return pads[0].status;
}
return clients[client_number].status;
return pads[(client_number * PADS_PER_CLIENT) + pad].status;
}
const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const {
const std::size_t client_number = GetClientNumber(host, port, pad);
if (client_number == MAX_UDP_CLIENTS) {
return clients[0].status;
const std::size_t client_number = GetClientNumber(host, port);
if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) {
return pads[0].status;
}
return clients[client_number].status;
return pads[(client_number * PADS_PER_CLIENT) + pad].status;
}
Input::TouchStatus& Client::GetTouchState() {
@@ -422,7 +419,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
return pad_queue;
}
void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
void TestCommunication(const std::string& host, u16 port,
const std::function<void()>& success_callback,
const std::function<void()>& failure_callback) {
std::thread([=] {
@@ -432,9 +429,10 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
.port_info = [](Response::PortInfo) {},
.pad_data = [&](Response::PadData) { success_event.Set(); },
};
Socket socket{host, port, pad_index, std::move(callback)};
Socket socket{host, port, std::move(callback)};
std::thread worker_thread{SocketLoop, &socket};
const bool result = success_event.WaitFor(std::chrono::seconds(5));
const bool result =
success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10));
socket.Stop();
worker_thread.join();
if (result) {
@@ -446,8 +444,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
}
CalibrationConfigurationJob::CalibrationConfigurationJob(
const std::string& host, u16 port, std::size_t pad_index,
std::function<void(Status)> status_callback,
const std::string& host, u16 port, std::function<void(Status)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback) {
std::thread([=, this] {
@@ -491,7 +488,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
complete_event.Set();
}
}};
Socket socket{host, port, pad_index, std::move(callback)};
Socket socket{host, port, std::move(callback)};
std::thread worker_thread{SocketLoop, &socket};
complete_event.Wait();
socket.Stop();
+24 -20
View File
@@ -84,7 +84,7 @@ public:
std::vector<Common::ParamPackage> GetInputDevices() const;
bool DeviceConnected(std::size_t client) const;
bool DeviceConnected(std::size_t pad) const;
void ReloadSockets();
Common::SPSCQueue<UDPPadStatus>& GetPadQueue();
@@ -97,38 +97,40 @@ public:
const Input::TouchStatus& GetTouchState() const;
private:
struct ClientData {
ClientData();
~ClientData();
std::string host{"127.0.0.1"};
u16 port{26760};
struct PadData {
std::size_t pad_index{};
std::unique_ptr<Socket> socket;
bool connected{};
DeviceStatus status;
std::thread thread;
u64 packet_sequence{};
s8 active{-1};
// Realtime values
// motion is initalized with PID values for drift correction on joycons
InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f};
std::chrono::time_point<std::chrono::steady_clock> last_motion_update;
std::chrono::time_point<std::chrono::steady_clock> last_update;
};
struct ClientConnection {
ClientConnection();
~ClientConnection();
std::string host{"127.0.0.1"};
u16 port{26760};
s8 active{-1};
std::unique_ptr<Socket> socket;
std::thread thread;
};
// For shutting down, clear all data, join all threads, release usb
void Reset();
// Translates configuration to client number
std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const;
std::size_t GetClientNumber(std::string_view host, u16 port) const;
void OnVersion(Response::Version);
void OnPortInfo(Response::PortInfo);
void OnPadData(Response::PadData, std::size_t client);
void StartCommunication(std::size_t client, const std::string& host, u16 port,
std::size_t pad_index);
void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
const Common::Vec3<float>& gyro);
void StartCommunication(std::size_t client, const std::string& host, u16 port);
void UpdateYuzuSettings(std::size_t client, std::size_t pad_index,
const Common::Vec3<float>& acc, const Common::Vec3<float>& gyro);
// Returns an unused finger id, if there is no fingers available std::nullopt will be
// returned
@@ -140,10 +142,12 @@ private:
bool configuring = false;
// Allocate clients for 8 udp servers
static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8;
static constexpr std::size_t MAX_UDP_CLIENTS = 8;
static constexpr std::size_t PADS_PER_CLIENT = 4;
// Each client can have up 2 touch inputs
static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2;
std::array<ClientData, MAX_UDP_CLIENTS> clients{};
std::array<PadData, MAX_UDP_CLIENTS * PADS_PER_CLIENT> pads{};
std::array<ClientConnection, MAX_UDP_CLIENTS> clients{};
Common::SPSCQueue<UDPPadStatus> pad_queue{};
Input::TouchStatus touch_status{};
std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{};
@@ -164,7 +168,7 @@ public:
* @param status_callback Callback for job status updates
* @param data_callback Called when calibration data is ready
*/
explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index,
explicit CalibrationConfigurationJob(const std::string& host, u16 port,
std::function<void(Status)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback);
~CalibrationConfigurationJob();
@@ -174,7 +178,7 @@ private:
Common::Event complete_event;
};
void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
void TestCommunication(const std::string& host, u16 port,
const std::function<void()>& success_callback,
const std::function<void()>& failure_callback);
-1
View File
@@ -236,7 +236,6 @@ add_library(video_core STATIC
texture_cache/types.h
texture_cache/util.cpp
texture_cache/util.h
textures/astc.cpp
textures/astc.h
textures/decoders.cpp
textures/decoders.h
@@ -2,8 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring> // for std::memcpy
#include <algorithm> // for std::copy
#include <numeric>
#include "common/assert.h"
#include "video_core/command_classes/codecs/vp9.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
@@ -362,7 +363,8 @@ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state)
// surface_luma_offset[0:3] contains the address of the reference frame offsets in the following
// order: last, golden, altref, current. It may be worthwhile to track the updates done here
// to avoid buffering frame data needed for reference frame updating in the header composition.
std::memcpy(vp9_info.frame_offsets.data(), state.surface_luma_offset.data(), 4 * sizeof(u64));
std::copy(state.surface_luma_offset.begin(), state.surface_luma_offset.begin() + 4,
vp9_info.frame_offsets.begin());
return vp9_info;
}
@@ -821,11 +823,11 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
// Write headers and frame to buffer
frame.resize(uncompressed_header.size() + compressed_header.size() + bitstream.size());
std::memcpy(frame.data(), uncompressed_header.data(), uncompressed_header.size());
std::memcpy(frame.data() + uncompressed_header.size(), compressed_header.data(),
compressed_header.size());
std::memcpy(frame.data() + uncompressed_header.size() + compressed_header.size(),
bitstream.data(), bitstream.size());
std::copy(uncompressed_header.begin(), uncompressed_header.end(), frame.begin());
std::copy(compressed_header.begin(), compressed_header.end(),
frame.begin() + uncompressed_header.size());
std::copy(bitstream.begin(), bitstream.end(),
frame.begin() + uncompressed_header.size() + compressed_header.size());
// keep track of frame number
current_frame_number++;
@@ -1,4 +1,5 @@
set(SHADER_FILES
astc_decoder.comp
block_linear_unswizzle_2d.comp
block_linear_unswizzle_3d.comp
convert_depth_to_float.frag
@@ -6,7 +6,27 @@ get_filename_component(CONTENTS_NAME ${SOURCE_FILE} NAME)
string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME})
string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
file(READ ${SOURCE_FILE} CONTENTS)
FILE(READ ${SOURCE_FILE} line_contents)
# Replace double quotes with single quotes,
# as double quotes will be used to wrap the lines
STRING(REGEX REPLACE "\"" "'" line_contents "${line_contents}")
# CMake separates list elements with semicolons, but semicolons
# are used extensively in the shader code.
# Replace with a temporary marker, to be reverted later.
STRING(REGEX REPLACE ";" "{{SEMICOLON}}" line_contents "${line_contents}")
# Make every line an individual element in the CMake list.
STRING(REGEX REPLACE "\n" ";" line_contents "${line_contents}")
# Build the shader string, wrapping each line in double quotes.
foreach(line IN LISTS line_contents)
string(CONCAT CONTENTS "${CONTENTS}" \"${line}\\n\"\n)
endforeach()
# Revert the original semicolons in the source.
STRING(REGEX REPLACE "{{SEMICOLON}}" ";" CONTENTS "${CONTENTS}")
get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY)
make_directory(${OUTPUT_DIR})
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,8 @@
namespace HostShaders {
constexpr std::string_view @CONTENTS_NAME@ = R"(@CONTENTS@)";
constexpr std::string_view @CONTENTS_NAME@ = {
@CONTENTS@
};
} // namespace HostShaders
+20 -40
View File
@@ -2,63 +2,43 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <mutex>
#include <boost/icl/interval_map.hpp>
#include <boost/range/iterator_range.hpp>
#include "common/assert.h"
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "core/memory.h"
#include "video_core/rasterizer_accelerated.h"
namespace VideoCore {
namespace {
template <typename Map, typename Interval>
constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
return boost::make_iterator_range(map.equal_range(interval));
}
} // Anonymous namespace
RasterizerAccelerated::RasterizerAccelerated(Core::Memory::Memory& cpu_memory_)
: cpu_memory{cpu_memory_} {}
RasterizerAccelerated::~RasterizerAccelerated() = default;
void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
std::lock_guard lock{pages_mutex};
const u64 page_start{addr >> Core::Memory::PAGE_BITS};
const u64 page_end{(addr + size + Core::Memory::PAGE_SIZE - 1) >> Core::Memory::PAGE_BITS};
const auto page_end = Common::DivCeil(addr + size, Core::Memory::PAGE_SIZE);
for (auto page = addr >> Core::Memory::PAGE_BITS; page != page_end; ++page) {
auto& count = cached_pages.at(page >> 3).Count(page);
// Interval maps will erase segments if count reaches 0, so if delta is negative we have to
// subtract after iterating
const auto pages_interval = CachedPageMap::interval_type::right_open(page_start, page_end);
if (delta > 0) {
cached_pages.add({pages_interval, delta});
}
for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) {
const auto interval = pair.first & pages_interval;
const int count = pair.second;
const VAddr interval_start_addr = boost::icl::first(interval) << Core::Memory::PAGE_BITS;
const VAddr interval_end_addr = boost::icl::last_next(interval) << Core::Memory::PAGE_BITS;
const u64 interval_size = interval_end_addr - interval_start_addr;
if (delta > 0 && count == delta) {
cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
} else if (delta < 0 && count == -delta) {
cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
if (delta > 0) {
ASSERT_MSG(count < UINT8_MAX, "Count may overflow!");
} else if (delta < 0) {
ASSERT_MSG(count > 0, "Count may underflow!");
} else {
ASSERT(count >= 0);
ASSERT_MSG(true, "Delta must be non-zero!");
}
}
if (delta < 0) {
cached_pages.add({pages_interval, delta});
// Adds or subtracts 1, as count is a unsigned 8-bit value
count += static_cast<u8>(delta);
// Assume delta is either -1 or 1
if (count == 0) {
cpu_memory.RasterizerMarkRegionCached(page << Core::Memory::PAGE_BITS,
Core::Memory::PAGE_SIZE, false);
} else if (count == 1 && delta > 0) {
cpu_memory.RasterizerMarkRegionCached(page << Core::Memory::PAGE_BITS,
Core::Memory::PAGE_SIZE, true);
}
}
}
+19 -6
View File
@@ -4,9 +4,8 @@
#pragma once
#include <mutex>
#include <boost/icl/interval_map.hpp>
#include <array>
#include <atomic>
#include "common/common_types.h"
#include "video_core/rasterizer_interface.h"
@@ -26,10 +25,24 @@ public:
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
private:
using CachedPageMap = boost::icl::interval_map<u64, int>;
CachedPageMap cached_pages;
std::mutex pages_mutex;
class CacheEntry final {
public:
CacheEntry() = default;
std::atomic_uint8_t& Count(std::size_t page) {
return values[page & 7];
}
const std::atomic_uint8_t& Count(std::size_t page) const {
return values[page & 7];
}
private:
std::array<std::atomic_uint8_t, 8> values{};
};
static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
std::array<CacheEntry, 0x800000> cached_pages;
Core::Memory::Memory& cpu_memory;
};
+13 -1
View File
@@ -210,6 +210,12 @@ Device::Device() {
const bool is_amd = vendor == "ATI Technologies Inc.";
const bool is_intel = vendor == "Intel";
#ifdef __unix__
const bool is_linux = true;
#else
const bool is_linux = false;
#endif
bool disable_fast_buffer_sub_data = false;
if (is_nvidia && version == "4.6.0 NVIDIA 443.24") {
LOG_WARNING(
@@ -249,7 +255,9 @@ Device::Device() {
GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue();
// Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation.
use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() &&
!(is_amd || (is_intel && !is_linux));
use_driver_cache = is_nvidia;
LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
@@ -261,6 +269,10 @@ Device::Device() {
if (Settings::values.use_assembly_shaders.GetValue() && !use_assembly_shaders) {
LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
}
if (Settings::values.use_asynchronous_shaders.GetValue() && !use_asynchronous_shaders) {
LOG_WARNING(Render_OpenGL, "Asynchronous shader compilation enabled but not supported");
}
}
Device::Device(std::nullptr_t) {
@@ -307,7 +307,8 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
const VideoCommon::ImageInfo& info) {
// Disable accelerated uploads for now as they don't implement swizzled uploads
return !runtime.HasNativeASTC() && IsPixelFormatASTC(info.format);
// Disable other accelerated uploads for now as they don't implement swizzled uploads
return false;
switch (info.type) {
case ImageType::e2D:
@@ -569,7 +570,11 @@ void TextureCacheRuntime::AccelerateImageUpload(Image& image, const ImageBufferM
std::span<const SwizzleParameters> swizzles) {
switch (image.info.type) {
case ImageType::e2D:
return util_shaders.BlockLinearUpload2D(image, map, swizzles);
if (IsPixelFormatASTC(image.info.format)) {
return util_shaders.ASTCDecode(image, map, swizzles);
} else {
return util_shaders.BlockLinearUpload2D(image, map, swizzles);
}
case ImageType::e3D:
return util_shaders.BlockLinearUpload3D(image, map, swizzles);
case ImageType::Linear:
@@ -599,6 +604,10 @@ FormatProperties TextureCacheRuntime::FormatInfo(ImageType type, GLenum internal
}
}
bool TextureCacheRuntime::HasNativeASTC() const noexcept {
return device.HasASTC();
}
TextureCacheRuntime::StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_)
: storage_flags{storage_flags_}, map_flags{map_flags_} {}
@@ -95,6 +95,8 @@ public:
return has_broken_texture_view_formats;
}
bool HasNativeASTC() const noexcept;
private:
struct StagingBuffers {
explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_);
@@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <bit>
#include <span>
#include <string_view>
@@ -11,6 +10,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "video_core/host_shaders/astc_decoder_comp.h"
#include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h"
#include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h"
#include "video_core/host_shaders/opengl_copy_bc4_comp.h"
@@ -20,16 +20,18 @@
#include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_texture_cache.h"
#include "video_core/renderer_opengl/util_shaders.h"
#include "video_core/surface.h"
#include "video_core/texture_cache/accelerated_swizzle.h"
#include "video_core/texture_cache/types.h"
#include "video_core/texture_cache/util.h"
#include "video_core/textures/astc.h"
#include "video_core/textures/decoders.h"
namespace OpenGL {
using namespace HostShaders;
using namespace Tegra::Texture::ASTC;
using VideoCommon::Extent2D;
using VideoCommon::Extent3D;
using VideoCommon::ImageCopy;
using VideoCommon::ImageType;
@@ -57,7 +59,7 @@ size_t NumPixelsInCopy(const VideoCommon::ImageCopy& copy) {
} // Anonymous namespace
UtilShaders::UtilShaders(ProgramManager& program_manager_)
: program_manager{program_manager_},
: program_manager{program_manager_}, astc_decoder_program(MakeProgram(ASTC_DECODER_COMP)),
block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)),
block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)),
pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)),
@@ -65,11 +67,79 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) {
const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
swizzle_table_buffer.Create();
astc_buffer.Create();
glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_BUFFER_DATA), &ASTC_BUFFER_DATA, 0);
}
UtilShaders::~UtilShaders() = default;
void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles) {
static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
static constexpr GLuint BINDING_INPUT_BUFFER = 1;
static constexpr GLuint BINDING_ENC_BUFFER = 2;
static constexpr GLuint BINDING_6_TO_8_BUFFER = 3;
static constexpr GLuint BINDING_7_TO_8_BUFFER = 4;
static constexpr GLuint BINDING_8_TO_8_BUFFER = 5;
static constexpr GLuint BINDING_BYTE_TO_16_BUFFER = 6;
static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
const Extent2D tile_size{
.width = VideoCore::Surface::DefaultBlockWidth(image.info.format),
.height = VideoCore::Surface::DefaultBlockHeight(image.info.format),
};
program_manager.BindHostCompute(astc_decoder_program.handle);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, encoding_values),
sizeof(AstcBufferData::encoding_values));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_6_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_6_to_8),
sizeof(AstcBufferData::replicate_6_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_7_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_7_to_8),
sizeof(AstcBufferData::replicate_7_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_8_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_8_to_8),
sizeof(AstcBufferData::replicate_8_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_BYTE_TO_16_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_byte_to_16),
sizeof(AstcBufferData::replicate_byte_to_16));
glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
glUniform2ui(1, tile_size.width, tile_size.height);
// Ensure buffer data is valid before dispatching
glFlush();
for (const SwizzleParameters& swizzle : swizzles) {
const size_t input_offset = swizzle.buffer_offset + map.offset;
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
glUniform1ui(2, params.bytes_per_block_log2);
glUniform1ui(3, params.layer_stride);
glUniform1ui(4, params.block_size);
glUniform1ui(5, params.x_shift);
glUniform1ui(6, params.block_height);
glUniform1ui(7, params.block_height_mask);
glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
GL_WRITE_ONLY, GL_RGBA8);
// ASTC texture data
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset,
image.guest_size_bytes - swizzle.buffer_offset);
glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
}
program_manager.RestoreGuestCompute();
}
void UtilShaders::BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
std::span<const SwizzleParameters> swizzles) {
static constexpr Extent3D WORKGROUP_SIZE{32, 32, 1};
@@ -40,6 +40,9 @@ public:
explicit UtilShaders(ProgramManager& program_manager);
~UtilShaders();
void ASTCDecode(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
void BlockLinearUpload2D(Image& image, const ImageBufferMap& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
@@ -59,7 +62,9 @@ private:
ProgramManager& program_manager;
OGLBuffer swizzle_table_buffer;
OGLBuffer astc_buffer;
OGLProgram astc_decoder_program;
OGLProgram block_linear_unswizzle_2d_program;
OGLProgram block_linear_unswizzle_3d_program;
OGLProgram pitch_unswizzle_program;
@@ -166,7 +166,7 @@ struct FormatTuple {
{VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT
{VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM
{VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT
{VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB
{VK_FORMAT_A8B8G8R8_SRGB_PACK32, Attachable}, // A8B8G8R8_SRGB
{VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // R8G8_UNORM
{VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // R8G8_SNORM
{VK_FORMAT_R8G8_SINT, Attachable | Storage}, // R8G8_SINT
@@ -11,18 +11,39 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "video_core/host_shaders/astc_decoder_comp_spv.h"
#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
#include "video_core/renderer_vulkan/vk_compute_pass.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/texture_cache/accelerated_swizzle.h"
#include "video_core/texture_cache/types.h"
#include "video_core/textures/astc.h"
#include "video_core/textures/decoders.h"
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
using Tegra::Texture::SWIZZLE_TABLE;
using Tegra::Texture::ASTC::EncodingsValues;
using namespace Tegra::Texture::ASTC;
namespace {
constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
constexpr u32 ASTC_BINDING_ENC_BUFFER = 1;
constexpr u32 ASTC_BINDING_6_TO_8_BUFFER = 2;
constexpr u32 ASTC_BINDING_7_TO_8_BUFFER = 3;
constexpr u32 ASTC_BINDING_8_TO_8_BUFFER = 4;
constexpr u32 ASTC_BINDING_BYTE_TO_16_BUFFER = 5;
constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 6;
constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 7;
VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
return {
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
@@ -50,6 +71,67 @@ std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBinding
}};
}
std::array<VkDescriptorSetLayoutBinding, 8> BuildASTCDescriptorSetBindings() {
return {{
{
.binding = ASTC_BINDING_INPUT_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_ENC_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_6_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_7_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_8_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_BYTE_TO_16_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_SWIZZLE_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_OUTPUT_IMAGE,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
}};
}
VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
return {
.dstBinding = 0,
@@ -61,6 +143,94 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
};
}
std::array<VkDescriptorUpdateTemplateEntryKHR, 8> BuildASTCPassDescriptorUpdateTemplateEntry() {
return {{
{
.dstBinding = ASTC_BINDING_INPUT_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_ENC_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_ENC_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_6_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_6_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_7_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_7_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_8_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_8_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_BYTE_TO_16_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_BYTE_TO_16_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_SWIZZLE_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_SWIZZLE_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_OUTPUT_IMAGE,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.offset = ASTC_BINDING_OUTPUT_IMAGE * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
}};
}
struct AstcPushConstants {
std::array<u32, 2> blocks_dims;
u32 bytes_per_block_log2;
u32 layer_stride;
u32 block_size;
u32 x_shift;
u32 block_height;
u32 block_height_mask;
};
struct AstcBufferData {
decltype(SWIZZLE_TABLE) swizzle_table_buffer = SWIZZLE_TABLE;
decltype(EncodingsValues) encoding_values = EncodingsValues;
decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
} constexpr ASTC_BUFFER_DATA;
} // Anonymous namespace
VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool,
@@ -238,4 +408,167 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
return {staging.buffer, staging.offset};
}
ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
VKDescriptorPool& descriptor_pool_,
StagingBufferPool& staging_buffer_pool_,
VKUpdateDescriptorQueue& update_descriptor_queue_,
MemoryAllocator& memory_allocator_)
: VKComputePass(device_, descriptor_pool_, BuildASTCDescriptorSetBindings(),
BuildASTCPassDescriptorUpdateTemplateEntry(),
BuildComputePushConstantRange(sizeof(AstcPushConstants)),
ASTC_DECODER_COMP_SPV),
device{device_}, scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
update_descriptor_queue{update_descriptor_queue_}, memory_allocator{memory_allocator_} {}
ASTCDecoderPass::~ASTCDecoderPass() = default;
void ASTCDecoderPass::MakeDataBuffer() {
constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_BUFFER_DATA) + sizeof(SWIZZLE_TABLE);
data_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = TOTAL_BUFFER_SIZE,
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
data_buffer_commit = memory_allocator.Commit(data_buffer, MemoryUsage::Upload);
const auto staging_ref = staging_buffer_pool.Request(TOTAL_BUFFER_SIZE, MemoryUsage::Upload);
std::memcpy(staging_ref.mapped_span.data(), &ASTC_BUFFER_DATA, sizeof(ASTC_BUFFER_DATA));
// Tack on the swizzle table at the end of the buffer
std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_BUFFER_DATA), &SWIZZLE_TABLE,
sizeof(SWIZZLE_TABLE));
scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
TOTAL_BUFFER_SIZE](vk::CommandBuffer cmdbuf) {
cmdbuf.CopyBuffer(src, dst,
VkBufferCopy{
.srcOffset = offset,
.dstOffset = 0,
.size = TOTAL_BUFFER_SIZE,
});
cmdbuf.PipelineBarrier(
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
VkMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
});
});
}
void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles) {
using namespace VideoCommon::Accelerated;
const std::array<u32, 2> block_dims{
VideoCore::Surface::DefaultBlockWidth(image.info.format),
VideoCore::Surface::DefaultBlockHeight(image.info.format),
};
scheduler.RequestOutsideRenderPassOperationContext();
if (!data_buffer) {
MakeDataBuffer();
}
const VkPipeline vk_pipeline = *pipeline;
const VkImageAspectFlags aspect_mask = image.AspectMask();
const VkImage vk_image = image.Handle();
const bool is_initialized = image.ExchangeInitialization();
scheduler.Record(
[vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier image_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = vk_image,
.subresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : 0,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
});
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
const size_t input_offset = swizzle.buffer_offset + map.offset;
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
const u32 num_dispatches_z = image.info.resources.layers;
update_descriptor_queue.Acquire();
update_descriptor_queue.AddBuffer(map.buffer, input_offset,
image.guest_size_bytes - swizzle.buffer_offset);
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, encoding_values),
sizeof(AstcBufferData::encoding_values));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_6_to_8),
sizeof(AstcBufferData::replicate_6_to_8));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_7_to_8),
sizeof(AstcBufferData::replicate_7_to_8));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_8_to_8),
sizeof(AstcBufferData::replicate_8_to_8));
update_descriptor_queue.AddBuffer(*data_buffer,
offsetof(AstcBufferData, replicate_byte_to_16),
sizeof(AstcBufferData::replicate_byte_to_16));
update_descriptor_queue.AddBuffer(*data_buffer, sizeof(AstcBufferData),
sizeof(SWIZZLE_TABLE));
update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue);
const VkPipelineLayout vk_layout = *layout;
// To unswizzle the ASTC data
const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
scheduler.Record([vk_layout, num_dispatches_x, num_dispatches_y, num_dispatches_z,
block_dims, params, set](vk::CommandBuffer cmdbuf) {
const AstcPushConstants uniforms{
.blocks_dims = block_dims,
.bytes_per_block_log2 = params.bytes_per_block_log2,
.layer_stride = params.layer_stride,
.block_size = params.block_size,
.x_shift = params.x_shift,
.block_height = params.block_height,
.block_height_mask = params.block_height_mask,
};
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, vk_layout, 0, set, {});
cmdbuf.PushConstants(vk_layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, num_dispatches_z);
});
}
scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier image_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = vk_image,
.subresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, image_barrier);
});
}
} // namespace Vulkan
@@ -11,14 +11,21 @@
#include "common/common_types.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace VideoCommon {
struct SwizzleParameters;
}
namespace Vulkan {
class Device;
class StagingBufferPool;
class VKScheduler;
class VKUpdateDescriptorQueue;
class Image;
struct StagingBufferRef;
class VKComputePass {
public:
@@ -77,4 +84,29 @@ private:
VKUpdateDescriptorQueue& update_descriptor_queue;
};
class ASTCDecoderPass final : public VKComputePass {
public:
explicit ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
VKDescriptorPool& descriptor_pool_,
StagingBufferPool& staging_buffer_pool_,
VKUpdateDescriptorQueue& update_descriptor_queue_,
MemoryAllocator& memory_allocator_);
~ASTCDecoderPass();
void Assemble(Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles);
private:
void MakeDataBuffer();
const Device& device;
VKScheduler& scheduler;
StagingBufferPool& staging_buffer_pool;
VKUpdateDescriptorQueue& update_descriptor_queue;
MemoryAllocator& memory_allocator;
vk::Buffer data_buffer;
MemoryCommit data_buffer_commit;
};
} // namespace Vulkan
@@ -241,7 +241,10 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
update_descriptor_queue(device, scheduler),
blit_image(device, scheduler, state_tracker, descriptor_pool),
texture_cache_runtime{device, scheduler, memory_allocator, staging_pool, blit_image},
astc_decoder_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue,
memory_allocator),
texture_cache_runtime{device, scheduler, memory_allocator,
staging_pool, blit_image, astc_decoder_pass},
texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory),
buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
update_descriptor_queue, descriptor_pool),
@@ -173,6 +173,7 @@ private:
VKDescriptorPool descriptor_pool;
VKUpdateDescriptorQueue update_descriptor_queue;
BlitImageHelper blit_image;
ASTCDecoderPass astc_decoder_pass;
GraphicsPipelineCacheKey graphics_key;
@@ -10,6 +10,7 @@
#include "video_core/engines/fermi_2d.h"
#include "video_core/renderer_vulkan/blit_image.h"
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
#include "video_core/renderer_vulkan/vk_compute_pass.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -807,7 +808,7 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
}
if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
flags |= VideoCommon::ImageFlagBits::Converted;
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
}
if (runtime.device.HasDebuggingToolAttached()) {
if (image) {
@@ -816,6 +817,38 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
}
}
static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
.pNext = nullptr,
.usage = VK_IMAGE_USAGE_STORAGE_BIT,
};
if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
const auto& device = runtime.device.GetLogical();
storage_image_views.reserve(info.resources.levels);
for (s32 level = 0; level < info.resources.levels; ++level) {
storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = &storage_image_view_usage_create_info,
.flags = 0,
.image = *image,
.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32,
.components{
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
},
.subresourceRange{
.aspectMask = aspect_mask,
.baseMipLevel = static_cast<u32>(level),
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
}));
}
}
}
void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
@@ -918,7 +951,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
}
}
const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
const VkFormat vk_format = format_info.format;
const VkImageViewUsageCreateInfo image_view_usage{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
.pNext = nullptr,
@@ -930,7 +962,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.flags = 0,
.image = image.Handle(),
.viewType = VkImageViewType{},
.format = vk_format,
.format = format_info.format,
.components{
.r = ComponentSwizzle(swizzle[0]),
.g = ComponentSwizzle(swizzle[1]),
@@ -982,7 +1014,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.pNext = nullptr,
.flags = 0,
.buffer = image.Buffer(),
.format = vk_format,
.format = format_info.format,
.offset = 0, // TODO: Redesign buffer cache to support this
.range = image.guest_size_bytes,
});
@@ -1167,4 +1199,13 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
}
}
void TextureCacheRuntime::AccelerateImageUpload(
Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles) {
if (IsPixelFormatASTC(image.info.format)) {
return astc_decoder_pass.Assemble(image, map, swizzles);
}
UNREACHABLE();
}
} // namespace Vulkan
@@ -20,6 +20,7 @@ using VideoCommon::Offset2D;
using VideoCommon::RenderTargets;
using VideoCore::Surface::PixelFormat;
class ASTCDecoderPass;
class BlitImageHelper;
class Device;
class Image;
@@ -60,6 +61,7 @@ struct TextureCacheRuntime {
MemoryAllocator& memory_allocator;
StagingBufferPool& staging_buffer_pool;
BlitImageHelper& blit_image_helper;
ASTCDecoderPass& astc_decoder_pass;
std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache{};
void Finish();
@@ -83,9 +85,7 @@ struct TextureCacheRuntime {
}
void AccelerateImageUpload(Image&, const StagingBufferRef&,
std::span<const VideoCommon::SwizzleParameters>) {
UNREACHABLE();
}
std::span<const VideoCommon::SwizzleParameters>);
void InsertUploadMemoryBarrier() {}
@@ -121,15 +121,26 @@ public:
return *buffer;
}
[[nodiscard]] VkImageCreateFlags AspectMask() const noexcept {
[[nodiscard]] VkImageAspectFlags AspectMask() const noexcept {
return aspect_mask;
}
[[nodiscard]] VkImageView StorageImageView(s32 level) const noexcept {
return *storage_image_views[level];
}
/// Returns true when the image is already initialized and mark it as initialized
[[nodiscard]] bool ExchangeInitialization() noexcept {
return std::exchange(initialized, true);
}
private:
VKScheduler* scheduler;
vk::Image image;
vk::Buffer buffer;
MemoryCommit commit;
vk::ImageView image_view;
std::vector<vk::ImageView> storage_image_views;
VkImageAspectFlags aspect_mask = 0;
bool initialized = false;
};
@@ -13,8 +13,8 @@
namespace VideoCommon::Accelerated {
struct BlockLinearSwizzle2DParams {
std::array<u32, 3> origin;
std::array<s32, 3> destination;
alignas(16) std::array<u32, 3> origin;
alignas(16) std::array<s32, 3> destination;
u32 bytes_per_block_log2;
u32 layer_stride;
u32 block_size;
+2 -12
View File
@@ -47,7 +47,6 @@
#include "video_core/texture_cache/formatter.h"
#include "video_core/texture_cache/samples_helper.h"
#include "video_core/texture_cache/util.h"
#include "video_core/textures/astc.h"
#include "video_core/textures/decoders.h"
namespace VideoCommon {
@@ -879,17 +878,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
ASSERT(copy.image_extent == mip_size);
ASSERT(copy.buffer_row_length == Common::AlignUp(mip_size.width, tile_size.width));
ASSERT(copy.buffer_image_height == Common::AlignUp(mip_size.height, tile_size.height));
if (IsPixelFormatASTC(info.format)) {
ASSERT(copy.image_extent.depth == 1);
Tegra::Texture::ASTC::Decompress(input.subspan(copy.buffer_offset),
copy.image_extent.width, copy.image_extent.height,
copy.image_subresource.num_layers, tile_size.width,
tile_size.height, output.subspan(output_offset));
} else {
DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
output.subspan(output_offset));
}
DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
output.subspan(output_offset));
copy.buffer_offset = output_offset;
copy.buffer_row_length = mip_size.width;
copy.buffer_image_height = mip_size.height;
File diff suppressed because it is too large Load Diff
+121 -3
View File
@@ -4,11 +4,129 @@
#pragma once
#include <cstdint>
#include <bit>
#include "common/common_types.h"
namespace Tegra::Texture::ASTC {
void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
uint32_t block_width, uint32_t block_height, std::span<uint8_t> output);
enum class IntegerEncoding { JustBits, Quint, Trit };
struct IntegerEncodedValue {
constexpr IntegerEncodedValue() = default;
constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
: encoding{encoding_}, num_bits{num_bits_} {}
constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
return encoding == other.encoding && num_bits == other.num_bits;
}
// Returns the number of bits required to encode num_vals values.
u32 GetBitLength(u32 num_vals) const {
u32 total_bits = num_bits * num_vals;
if (encoding == IntegerEncoding::Trit) {
total_bits += (num_vals * 8 + 4) / 5;
} else if (encoding == IntegerEncoding::Quint) {
total_bits += (num_vals * 7 + 2) / 3;
}
return total_bits;
}
IntegerEncoding encoding{};
u32 num_bits = 0;
u32 bit_value = 0;
union {
u32 quint_value = 0;
u32 trit_value;
};
};
// Returns a new instance of this struct that corresponds to the
// can take no more than mav_value values
constexpr IntegerEncodedValue CreateEncoding(u32 mav_value) {
while (mav_value > 0) {
u32 check = mav_value + 1;
// Is mav_value a power of two?
if (!(check & (check - 1))) {
return IntegerEncodedValue(IntegerEncoding::JustBits, std::popcount(mav_value));
}
// Is mav_value of the type 3*2^n - 1?
if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
return IntegerEncodedValue(IntegerEncoding::Trit, std::popcount(check / 3 - 1));
}
// Is mav_value of the type 5*2^n - 1?
if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
return IntegerEncodedValue(IntegerEncoding::Quint, std::popcount(check / 5 - 1));
}
// Apparently it can't be represented with a bounded integer sequence...
// just iterate.
mav_value--;
}
return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
}
constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
std::array<IntegerEncodedValue, 256> encodings{};
for (std::size_t i = 0; i < encodings.size(); ++i) {
encodings[i] = CreateEncoding(static_cast<u32>(i));
}
return encodings;
}
constexpr std::array<IntegerEncodedValue, 256> EncodingsValues = MakeEncodedValues();
// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
// is the same as [(num_bits - 1):0] and repeats all the way down.
template <typename IntType>
constexpr IntType Replicate(IntType val, u32 num_bits, u32 to_bit) {
if (num_bits == 0 || to_bit == 0) {
return 0;
}
const IntType v = val & static_cast<IntType>((1 << num_bits) - 1);
IntType res = v;
u32 reslen = num_bits;
while (reslen < to_bit) {
u32 comp = 0;
if (num_bits > to_bit - reslen) {
u32 newshift = to_bit - reslen;
comp = num_bits - newshift;
num_bits = newshift;
}
res = static_cast<IntType>(res << num_bits);
res = static_cast<IntType>(res | (v >> comp));
reslen += num_bits;
}
return res;
}
constexpr std::size_t NumReplicateEntries(u32 num_bits) {
return std::size_t(1) << num_bits;
}
template <typename IntType, u32 num_bits, u32 to_bit>
constexpr auto MakeReplicateTable() {
std::array<IntType, NumReplicateEntries(num_bits)> table{};
for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
table[value] = Replicate(value, num_bits, to_bit);
}
return table;
}
constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
struct AstcBufferData {
decltype(EncodingsValues) encoding_values = EncodingsValues;
decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
} constexpr ASTC_BUFFER_DATA;
} // namespace Tegra::Texture::ASTC
-23
View File
@@ -17,26 +17,7 @@
#include "video_core/textures/texture.h"
namespace Tegra::Texture {
namespace {
/**
* This table represents the internal swizzle of a gob, in format 16 bytes x 2 sector packing.
* Calculates the offset of an (x, y) position within a swizzled texture.
* Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
*/
constexpr SwizzleTable MakeSwizzleTableConst() {
SwizzleTable table{};
for (u32 y = 0; y < table.size(); ++y) {
for (u32 x = 0; x < table[0].size(); ++x) {
table[y][x] = ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
(y % 2) * 16 + (x % 16);
}
}
return table;
}
constexpr SwizzleTable SWIZZLE_TABLE = MakeSwizzleTableConst();
template <bool TO_LINEAR>
void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width,
u32 height, u32 depth, u32 block_height, u32 block_depth, u32 stride_alignment) {
@@ -91,10 +72,6 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe
}
} // Anonymous namespace
SwizzleTable MakeSwizzleTable() {
return SWIZZLE_TABLE;
}
void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth,
u32 stride_alignment) {
+16 -2
View File
@@ -23,8 +23,22 @@ constexpr u32 GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_
using SwizzleTable = std::array<std::array<u32, GOB_SIZE_X>, GOB_SIZE_Y>;
/// Returns a z-order swizzle table
SwizzleTable MakeSwizzleTable();
/**
* This table represents the internal swizzle of a gob, in format 16 bytes x 2 sector packing.
* Calculates the offset of an (x, y) position within a swizzled texture.
* Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
*/
constexpr SwizzleTable MakeSwizzleTable() {
SwizzleTable table{};
for (u32 y = 0; y < table.size(); ++y) {
for (u32 x = 0; x < table[0].size(); ++x) {
table[y][x] = ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
(y % 2) * 16 + (x % 16);
}
}
return table;
}
constexpr SwizzleTable SWIZZLE_TABLE = MakeSwizzleTable();
/// Unswizzles a block linear texture into linear memory.
void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
@@ -51,7 +51,7 @@ constexpr std::array REQUIRED_EXTENSIONS{
#ifdef _WIN32
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
#endif
#ifdef __linux__
#ifdef __unix__
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
#endif
};
@@ -62,7 +62,7 @@ public:
: memory{std::move(memory_)}, allocation_size{allocation_size_}, property_flags{properties},
shifted_memory_type{1U << type} {}
#if defined(_WIN32) || defined(__linux__)
#if defined(_WIN32) || defined(__unix__)
~MemoryAllocation() {
if (owning_opengl_handle != 0) {
glDeleteMemoryObjectsEXT(1, &owning_opengl_handle);
@@ -114,7 +114,7 @@ public:
}
return owning_opengl_handle;
}
#elif __linux__
#elif __unix__
[[nodiscard]] u32 ExportOpenGLHandle() {
if (!owning_opengl_handle) {
glCreateMemoryObjectsEXT(1, &owning_opengl_handle);
@@ -165,7 +165,7 @@ private:
const u32 shifted_memory_type; ///< Shifted Vulkan memory type.
std::vector<Range> commits; ///< All commit ranges done from this allocation.
std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before.
#if defined(_WIN32) || defined(__linux__)
#if defined(_WIN32) || defined(__unix__)
u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle.
#endif
};
@@ -249,7 +249,7 @@ void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u6
.pNext = nullptr,
#ifdef _WIN32
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
#elif __linux__
#elif __unix__
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
#else
.handleTypes = 0,
+6 -2
View File
@@ -376,11 +376,15 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
}
void GRenderWindow::keyPressEvent(QKeyEvent* event) {
input_subsystem->GetKeyboard()->PressKey(event->key());
if (!event->isAutoRepeat()) {
input_subsystem->GetKeyboard()->PressKey(event->key());
}
}
void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
input_subsystem->GetKeyboard()->ReleaseKey(event->key());
if (!event->isAutoRepeat()) {
input_subsystem->GetKeyboard()->ReleaseKey(event->key());
}
}
MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) {
@@ -103,7 +103,10 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit)
str = QFileDialog::getOpenFileName(this, caption, QFileInfo(edit->text()).dir().path(),
QStringLiteral("NX Gamecard;*.xci"));
} else {
str = QFileDialog::getExistingDirectory(this, caption, edit->text()) + QDir::separator();
str = QFileDialog::getExistingDirectory(this, caption, edit->text());
if (!str.isNull() && str.back() != QDir::separator()) {
str.append(QDir::separator());
}
}
if (str.isEmpty())
@@ -227,7 +227,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
vulkan_devices.clear();
vulkan_devices.reserve(physical_devices.size());
for (const VkPhysicalDevice device : physical_devices) {
const char* const name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
vulkan_devices.push_back(QString::fromStdString(name));
}
@@ -105,7 +105,9 @@ QString ButtonToText(const Common::ParamPackage& param) {
}
if (param.Get("engine", "") == "keyboard") {
return GetKeyName(param.Get("code", 0));
const QString button_str = GetKeyName(param.Get("code", 0));
const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : "");
return QObject::tr("%1%2").arg(toggle, button_str);
}
if (param.Get("engine", "") == "gcpad") {
@@ -157,7 +159,8 @@ QString ButtonToText(const Common::ParamPackage& param) {
if (param.Get("engine", "") == "mouse") {
if (param.Has("button")) {
const QString button_str = QString::number(int(param.Get("button", 0)));
return QObject::tr("Click %1").arg(button_str);
const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : "");
return QObject::tr("%1Click %2").arg(toggle, button_str);
}
return GetKeyName(param.Get("code", 0));
}
@@ -301,6 +304,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
buttons_param[button_id].Clear();
button_map[button_id]->setText(tr("[not set]"));
});
context_menu.addAction(tr("Toggle button"), [&] {
const bool toggle_value = !buttons_param[button_id].Get("toggle", false);
buttons_param[button_id].Set("toggle", toggle_value);
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
});
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
});
@@ -413,6 +421,15 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
analogs_param[analog_id].Set("modifier", "");
analog_map_modifier_button[analog_id]->setText(tr("[not set]"));
});
context_menu.addAction(tr("Toggle button"), [&] {
Common::ParamPackage modifier_param =
Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")};
const bool toggle_value = !modifier_param.Get("toggle", false);
modifier_param.Set("toggle", toggle_value);
analogs_param[analog_id].Set("modifier", modifier_param.Serialize());
analog_map_modifier_button[analog_id]->setText(
ButtonToText(modifier_param));
});
context_menu.exec(
analog_map_modifier_button[analog_id]->mapToGlobal(menu_location));
});
@@ -23,8 +23,7 @@
#include "yuzu/configuration/configure_touch_from_button.h"
CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
const std::string& host, u16 port,
u8 pad_index)
const std::string& host, u16 port)
: QDialog(parent) {
layout = new QVBoxLayout;
status_label = new QLabel(tr("Communicating with the server..."));
@@ -41,7 +40,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
using namespace InputCommon::CemuhookUDP;
job = std::make_unique<CalibrationConfigurationJob>(
host, port, pad_index,
host, port,
[this](CalibrationConfigurationJob::Status status) {
QString text;
switch (status) {
@@ -217,7 +216,7 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
ui->udp_test->setText(tr("Testing"));
udp_test_in_progress = true;
InputCommon::CemuhookUDP::TestCommunication(
ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0,
ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()),
[this] {
LOG_INFO(Frontend, "UDP input test success");
QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
@@ -232,7 +231,7 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() {
ui->touch_calibration_config->setEnabled(false);
ui->touch_calibration_config->setText(tr("Configuring"));
CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(),
static_cast<u16>(ui->udp_port->text().toUInt()), 0);
static_cast<u16>(ui->udp_port->text().toUInt()));
dialog.exec();
if (dialog.completed) {
min_x = dialog.min_x;
@@ -29,8 +29,7 @@ class ConfigureMotionTouch;
class CalibrationConfigurationDialog : public QDialog {
Q_OBJECT
public:
explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port,
u8 pad_index);
explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port);
~CalibrationConfigurationDialog() override;
private:
+37
View File
@@ -60,6 +60,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include <QPushButton>
#include <QShortcut>
#include <QStatusBar>
#include <QString>
#include <QSysInfo>
#include <QUrl>
#include <QtConcurrent/QtConcurrent>
@@ -319,6 +320,34 @@ GMainWindow::GMainWindow()
continue;
}
// Launch game with a specific user
if (args[i] == QStringLiteral("-u")) {
if (i >= args.size() - 1) {
continue;
}
if (args[i + 1].startsWith(QChar::fromLatin1('-'))) {
continue;
}
bool argument_ok;
const std::size_t selected_user = args[++i].toUInt(&argument_ok);
if (!argument_ok) {
LOG_ERROR(Frontend, "Invalid user argument");
continue;
}
const Service::Account::ProfileManager manager;
if (!manager.UserExistsIndex(selected_user)) {
LOG_ERROR(Frontend, "Selected user doesn't exist");
continue;
}
Settings::values.current_user = selected_user;
continue;
}
// Launch game at path
if (args[i] == QStringLiteral("-g")) {
if (i >= args.size() - 1) {
@@ -3061,6 +3090,14 @@ int main(int argc, char* argv[]) {
chdir(bin_path.c_str());
#endif
#ifdef __linux__
// Set the DISPLAY variable in order to open web browsers
// TODO (lat9nq): Find a better solution for AppImages to start external applications
if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) {
qputenv("DISPLAY", ":0");
}
#endif
// Enables the core to make the qt created contexts current on std::threads
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
QApplication app(argc, argv);