summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/address_space.h7
-rw-r--r--src/common/alignment.h18
-rw-r--r--src/common/atomic_helpers.h2
-rw-r--r--src/common/bit_util.h6
-rw-r--r--src/common/concepts.h6
-rw-r--r--src/common/div_ceil.h4
-rw-r--r--src/common/expected.h60
-rw-r--r--src/common/input.h2
-rw-r--r--src/common/intrusive_red_black_tree.h20
-rw-r--r--src/common/make_unique_for_overwrite.h8
-rw-r--r--src/common/polyfill_ranges.h8
-rw-r--r--src/common/polyfill_thread.h87
-rw-r--r--src/common/settings.h12
-rw-r--r--src/common/string_util.cpp2
-rw-r--r--src/common/string_util.h3
-rw-r--r--src/common/tree.h74
-rw-r--r--src/common/vector_math.h16
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/hardware_properties.h20
-rw-r--r--src/core/hid/emulated_controller.cpp75
-rw-r--r--src/core/hid/emulated_controller.h6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp30
-rw-r--r--src/core/hle/kernel/hle_ipc.h8
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp2
-rw-r--r--src/core/hle/kernel/k_auto_object.h20
-rw-r--r--src/core/hle/kernel/k_capabilities.cpp358
-rw-r--r--src/core/hle/kernel/k_capabilities.h295
-rw-r--r--src/core/hle/kernel/k_device_address_space.cpp150
-rw-r--r--src/core/hle/kernel/k_device_address_space.h60
-rw-r--r--src/core/hle/kernel/k_priority_queue.h54
-rw-r--r--src/core/hle/kernel/k_scoped_lock.h11
-rw-r--r--src/core/hle/kernel/k_thread.h8
-rw-r--r--src/core/hle/kernel/k_thread_local_page.h6
-rw-r--r--src/core/hle/kernel/kernel.h4
-rw-r--r--src/core/hle/kernel/svc_types.h19
-rw-r--r--src/core/hle/kernel/svc_version.h58
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/audio/audren_u.cpp2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp2
-rw-r--r--src/core/hle/service/es/es.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp11
-rw-r--r--src/core/hle/service/glue/arp.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp8
-rw-r--r--src/core/hle/service/hid/controllers/npad.h3
-rw-r--r--src/core/hle/service/hid/hid.cpp4
-rw-r--r--src/core/hle/service/hid/hidbus/hidbus_base.h3
-rw-r--r--src/core/hle/service/hid/hidbus/ringcon.cpp2
-rw-r--r--src/core/hle/service/hid/hidbus/ringcon.h3
-rw-r--r--src/core/hle/service/hid/hidbus/starlink.cpp2
-rw-r--r--src/core/hle/service/hid/hidbus/starlink.h2
-rw-r--r--src/core/hle/service/hid/hidbus/stubbed.cpp2
-rw-r--r--src/core/hle/service/hid/hidbus/stubbed.h2
-rw-r--r--src/core/hle/service/jit/jit.cpp4
-rw-r--r--src/core/hle/service/ldn/ldn.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp26
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h28
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp21
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h22
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp31
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h32
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp35
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h36
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp17
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h22
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp8
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h12
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp4
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.cpp2
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.h4
-rw-r--r--src/core/hle/service/nvflinger/parcel.h87
-rw-r--r--src/core/hle/service/prepo/prepo.cpp8
-rw-r--r--src/core/hle/service/sockets/bsd.cpp15
-rw-r--r--src/core/hle/service/sockets/bsd.h23
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp2
-rw-r--r--src/core/hle/service/ssl/ssl.cpp8
-rw-r--r--src/core/hle/service/vi/vi.cpp4
-rw-r--r--src/core/internal_network/network.cpp4
-rw-r--r--src/core/internal_network/socket_proxy.cpp4
-rw-r--r--src/core/internal_network/socket_proxy.h5
-rw-r--r--src/core/internal_network/sockets.h9
-rw-r--r--src/core/reporter.cpp2
-rw-r--r--src/core/reporter.h4
-rw-r--r--src/input_common/drivers/joycon.cpp4
-rw-r--r--src/input_common/drivers/joycon.h2
-rw-r--r--src/input_common/helpers/joycon_driver.cpp18
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.cpp210
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.h18
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp157
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h52
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.cpp12
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.cpp13
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h186
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp68
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h8
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.cpp8
-rw-r--r--src/input_common/helpers/joycon_protocol/ringcon.cpp12
-rw-r--r--src/input_common/helpers/stick_from_buttons.cpp45
-rw-r--r--src/input_common/input_poller.cpp30
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_image.cpp23
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_instructions.h2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_image.cpp53
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_instructions.h2
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp49
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp31
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h3
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.h1
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp9
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h8
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc6
-rw-r--r--src/shader_recompiler/frontend/ir/value.h24
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_query.cpp8
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp28
-rw-r--r--src/shader_recompiler/object_pool.h4
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt2
-rw-r--r--src/video_core/host_shaders/vulkan_color_clear.frag14
-rw-r--r--src/video_core/host_shaders/vulkan_color_clear.vert10
-rw-r--r--src/video_core/renderer_opengl/gl_compute_pipeline.cpp23
-rw-r--r--src/video_core/renderer_opengl/gl_compute_pipeline.h10
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp17
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h6
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp126
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h10
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp10
-rw-r--r--src/video_core/texture_cache/descriptor_table.h4
-rw-r--r--src/video_core/texture_cache/image_info.cpp4
-rw-r--r--src/video_core/texture_cache/samples_helper.h44
-rw-r--r--src/video_core/texture_cache/slot_vector.h2
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp17
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp35
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h2
-rw-r--r--src/yuzu/configuration/input_profiles.cpp7
-rw-r--r--src/yuzu/multiplayer/lobby.cpp16
-rw-r--r--src/yuzu/multiplayer/lobby.h2
-rw-r--r--src/yuzu/multiplayer/lobby.ui7
-rw-r--r--src/yuzu_cmd/config.cpp3
-rw-r--r--src/yuzu_cmd/default_ini.h13
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp48
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h10
-rw-r--r--src/yuzu_cmd/yuzu.cpp55
154 files changed, 2689 insertions, 1093 deletions
diff --git a/src/common/address_space.h b/src/common/address_space.h
index 9222b2fdc..8683c23c3 100644
--- a/src/common/address_space.h
+++ b/src/common/address_space.h
@@ -12,7 +12,8 @@
namespace Common {
template <typename VaType, size_t AddressSpaceBits>
-concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >= AddressSpaceBits;
+concept AddressSpaceValid = std::is_unsigned_v<VaType> && sizeof(VaType) * 8 >=
+AddressSpaceBits;
struct EmptyStruct {};
@@ -21,7 +22,7 @@ struct EmptyStruct {};
*/
template <typename VaType, VaType UnmappedVa, typename PaType, PaType UnmappedPa,
bool PaContigSplit, size_t AddressSpaceBits, typename ExtraBlockInfo = EmptyStruct>
-requires AddressSpaceValid<VaType, AddressSpaceBits>
+ requires AddressSpaceValid<VaType, AddressSpaceBits>
class FlatAddressSpaceMap {
public:
/// The maximum VA that this AS can technically reach
@@ -109,7 +110,7 @@ private:
* initial, fast linear pass and a subsequent slower pass that iterates until it finds a free block
*/
template <typename VaType, VaType UnmappedVa, size_t AddressSpaceBits>
-requires AddressSpaceValid<VaType, AddressSpaceBits>
+ requires AddressSpaceValid<VaType, AddressSpaceBits>
class FlatAllocator
: public FlatAddressSpaceMap<VaType, UnmappedVa, bool, false, false, AddressSpaceBits> {
private:
diff --git a/src/common/alignment.h b/src/common/alignment.h
index 7e897334b..fa715d497 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -10,7 +10,7 @@
namespace Common {
template <typename T>
-requires std::is_unsigned_v<T>
+ requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignUp(T value, size_t size) {
auto mod{static_cast<T>(value % size)};
value -= mod;
@@ -18,31 +18,31 @@ requires std::is_unsigned_v<T>
}
template <typename T>
-requires std::is_unsigned_v<T>
+ requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
}
template <typename T>
-requires std::is_unsigned_v<T>
+ requires std::is_unsigned_v<T>
[[nodiscard]] constexpr T AlignDown(T value, size_t size) {
return static_cast<T>(value - value % size);
}
template <typename T>
-requires std::is_unsigned_v<T>
+ requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool Is4KBAligned(T value) {
return (value & 0xFFF) == 0;
}
template <typename T>
-requires std::is_unsigned_v<T>
+ requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool IsWordAligned(T value) {
return (value & 0b11) == 0;
}
template <typename T>
-requires std::is_integral_v<T>
+ requires std::is_integral_v<T>
[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
using U = typename std::make_unsigned_t<T>;
const U mask = static_cast<U>(alignment - 1);
@@ -50,7 +50,7 @@ requires std::is_integral_v<T>
}
template <typename T, typename U>
-requires std::is_integral_v<T>
+ requires std::is_integral_v<T>
[[nodiscard]] constexpr T DivideUp(T x, U y) {
return (x + (y - 1)) / y;
}
@@ -73,11 +73,11 @@ public:
constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
[[nodiscard]] T* allocate(size_type n) {
- return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
+ return static_cast<T*>(::operator new(n * sizeof(T), std::align_val_t{Align}));
}
void deallocate(T* p, size_type n) {
- ::operator delete (p, n * sizeof(T), std::align_val_t{Align});
+ ::operator delete(p, n * sizeof(T), std::align_val_t{Align});
}
template <typename T2>
diff --git a/src/common/atomic_helpers.h b/src/common/atomic_helpers.h
index aef3b66a4..d997f10ba 100644
--- a/src/common/atomic_helpers.h
+++ b/src/common/atomic_helpers.h
@@ -75,7 +75,7 @@ extern "C" void AnnotateHappensAfter(const char*, int, void*);
#if defined(AE_VCPP) || defined(AE_ICC)
#define AE_FORCEINLINE __forceinline
#elif defined(AE_GCC)
-//#define AE_FORCEINLINE __attribute__((always_inline))
+// #define AE_FORCEINLINE __attribute__((always_inline))
#define AE_FORCEINLINE inline
#else
#define AE_FORCEINLINE inline
diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index e4e6287f3..13368b439 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -45,19 +45,19 @@ template <typename T>
}
template <typename T>
-requires std::is_unsigned_v<T>
+ requires std::is_unsigned_v<T>
[[nodiscard]] constexpr bool IsPow2(T value) {
return std::has_single_bit(value);
}
template <typename T>
-requires std::is_integral_v<T>
+ requires std::is_integral_v<T>
[[nodiscard]] T NextPow2(T value) {
return static_cast<T>(1ULL << ((8U * sizeof(T)) - std::countl_zero(value - 1U)));
}
template <size_t bit_index, typename T>
-requires std::is_integral_v<T>
+ requires std::is_integral_v<T>
[[nodiscard]] constexpr bool Bit(const T value) {
static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T");
return ((value >> bit_index) & T(1)) == T(1);
diff --git a/src/common/concepts.h b/src/common/concepts.h
index a9acff3e7..61df1d32a 100644
--- a/src/common/concepts.h
+++ b/src/common/concepts.h
@@ -16,9 +16,9 @@ concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>;
// is available on all supported platforms.
template <typename Derived, typename Base>
concept DerivedFrom = requires {
- std::is_base_of_v<Base, Derived>;
- std::is_convertible_v<const volatile Derived*, const volatile Base*>;
-};
+ std::is_base_of_v<Base, Derived>;
+ std::is_convertible_v<const volatile Derived*, const volatile Base*>;
+ };
// TODO: Replace with std::convertible_to when libc++ implements it.
template <typename From, typename To>
diff --git a/src/common/div_ceil.h b/src/common/div_ceil.h
index eebc279c2..c12477d42 100644
--- a/src/common/div_ceil.h
+++ b/src/common/div_ceil.h
@@ -10,14 +10,14 @@ namespace Common {
/// Ceiled integer division.
template <typename N, typename D>
-requires std::is_integral_v<N> && std::is_unsigned_v<D>
+ requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeil(N number, D divisor) {
return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
}
/// Ceiled integer division with logarithmic divisor in base 2
template <typename N, typename D>
-requires std::is_integral_v<N> && std::is_unsigned_v<D>
+ requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
}
diff --git a/src/common/expected.h b/src/common/expected.h
index 6e6c86ee7..5fccfbcbd 100644
--- a/src/common/expected.h
+++ b/src/common/expected.h
@@ -64,7 +64,7 @@ struct no_init_t {
* Additionally, this requires E to be trivially destructible
*/
template <typename T, typename E, bool = std::is_trivially_destructible_v<T>>
-requires std::is_trivially_destructible_v<E>
+ requires std::is_trivially_destructible_v<E>
struct expected_storage_base {
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
@@ -111,7 +111,7 @@ struct expected_storage_base {
* Additionally, this requires E to be trivially destructible
*/
template <typename T, typename E>
-requires std::is_trivially_destructible_v<E>
+ requires std::is_trivially_destructible_v<E>
struct expected_storage_base<T, E, true> {
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
@@ -251,7 +251,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
* Additionally, this requires E to be trivially copy constructible
*/
template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>>
-requires std::is_trivially_copy_constructible_v<E>
+ requires std::is_trivially_copy_constructible_v<E>
struct expected_copy_base : expected_operations_base<T, E> {
using expected_operations_base<T, E>::expected_operations_base;
};
@@ -261,7 +261,7 @@ struct expected_copy_base : expected_operations_base<T, E> {
* Additionally, this requires E to be trivially copy constructible
*/
template <typename T, typename E>
-requires std::is_trivially_copy_constructible_v<E>
+ requires std::is_trivially_copy_constructible_v<E>
struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
using expected_operations_base<T, E>::expected_operations_base;
@@ -289,7 +289,7 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
* Additionally, this requires E to be trivially move constructible
*/
template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>>
-requires std::is_trivially_move_constructible_v<E>
+ requires std::is_trivially_move_constructible_v<E>
struct expected_move_base : expected_copy_base<T, E> {
using expected_copy_base<T, E>::expected_copy_base;
};
@@ -299,7 +299,7 @@ struct expected_move_base : expected_copy_base<T, E> {
* Additionally, this requires E to be trivially move constructible
*/
template <typename T, typename E>
-requires std::is_trivially_move_constructible_v<E>
+ requires std::is_trivially_move_constructible_v<E>
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
using expected_copy_base<T, E>::expected_copy_base;
@@ -330,9 +330,9 @@ template <typename T, typename E,
bool = std::conjunction_v<std::is_trivially_copy_assignable<T>,
std::is_trivially_copy_constructible<T>,
std::is_trivially_destructible<T>>>
-requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
- std::is_trivially_copy_constructible<E>,
- std::is_trivially_destructible<E>>
+ requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
+ std::is_trivially_copy_constructible<E>,
+ std::is_trivially_destructible<E>>
struct expected_copy_assign_base : expected_move_base<T, E> {
using expected_move_base<T, E>::expected_move_base;
};
@@ -342,9 +342,9 @@ struct expected_copy_assign_base : expected_move_base<T, E> {
* Additionally, this requires E to be trivially copy assignable
*/
template <typename T, typename E>
-requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
- std::is_trivially_copy_constructible<E>,
- std::is_trivially_destructible<E>>
+ requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
+ std::is_trivially_copy_constructible<E>,
+ std::is_trivially_destructible<E>>
struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
using expected_move_base<T, E>::expected_move_base;
@@ -371,9 +371,9 @@ template <typename T, typename E,
bool = std::conjunction_v<std::is_trivially_move_assignable<T>,
std::is_trivially_move_constructible<T>,
std::is_trivially_destructible<T>>>
-requires std::conjunction_v<std::is_trivially_move_assignable<E>,
- std::is_trivially_move_constructible<E>,
- std::is_trivially_destructible<E>>
+ requires std::conjunction_v<std::is_trivially_move_assignable<E>,
+ std::is_trivially_move_constructible<E>,
+ std::is_trivially_destructible<E>>
struct expected_move_assign_base : expected_copy_assign_base<T, E> {
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
};
@@ -383,9 +383,9 @@ struct expected_move_assign_base : expected_copy_assign_base<T, E> {
* Additionally, this requires E to be trivially move assignable
*/
template <typename T, typename E>
-requires std::conjunction_v<std::is_trivially_move_assignable<E>,
- std::is_trivially_move_constructible<E>,
- std::is_trivially_destructible<E>>
+ requires std::conjunction_v<std::is_trivially_move_assignable<E>,
+ std::is_trivially_move_constructible<E>,
+ std::is_trivially_destructible<E>>
struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> {
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
@@ -412,7 +412,7 @@ struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E>
*/
template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>,
bool EnableMove = std::is_move_constructible_v<T>>
-requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
+ requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
@@ -422,7 +422,7 @@ struct expected_delete_ctor_base {
};
template <typename T, typename E>
-requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
+ requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, true, false> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
@@ -432,7 +432,7 @@ struct expected_delete_ctor_base<T, E, true, false> {
};
template <typename T, typename E>
-requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
+ requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, false, true> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
@@ -442,7 +442,7 @@ struct expected_delete_ctor_base<T, E, false, true> {
};
template <typename T, typename E>
-requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
+ requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
struct expected_delete_ctor_base<T, E, false, false> {
expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
@@ -460,8 +460,8 @@ template <
typename T, typename E,
bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>,
bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>>
-requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
- std::is_copy_assignable<E>, std::is_move_assignable<E>>
+ requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
+ std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -471,8 +471,8 @@ struct expected_delete_assign_base {
};
template <typename T, typename E>
-requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
- std::is_copy_assignable<E>, std::is_move_assignable<E>>
+ requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
+ std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, true, false> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -482,8 +482,8 @@ struct expected_delete_assign_base<T, E, true, false> {
};
template <typename T, typename E>
-requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
- std::is_copy_assignable<E>, std::is_move_assignable<E>>
+ requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
+ std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, false, true> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
@@ -493,8 +493,8 @@ struct expected_delete_assign_base<T, E, false, true> {
};
template <typename T, typename E>
-requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
- std::is_copy_assignable<E>, std::is_move_assignable<E>>
+ requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
+ std::is_copy_assignable<E>, std::is_move_assignable<E>>
struct expected_delete_assign_base<T, E, false, false> {
expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base&) = default;
diff --git a/src/common/input.h b/src/common/input.h
index d61cd7ca8..b5748a6c8 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -130,6 +130,8 @@ struct ButtonStatus {
bool inverted{};
// Press once to activate, press again to release
bool toggle{};
+ // Spams the button when active
+ bool turbo{};
// Internal lock for the toggle status
bool locked{};
};
diff --git a/src/common/intrusive_red_black_tree.h b/src/common/intrusive_red_black_tree.h
index 93046615e..5f6b34e82 100644
--- a/src/common/intrusive_red_black_tree.h
+++ b/src/common/intrusive_red_black_tree.h
@@ -242,19 +242,21 @@ public:
template <typename T>
concept HasRedBlackKeyType = requires {
- { std::is_same<typename T::RedBlackKeyType, void>::value } -> std::convertible_to<bool>;
-};
+ {
+ std::is_same<typename T::RedBlackKeyType, void>::value
+ } -> std::convertible_to<bool>;
+ };
namespace impl {
- template <typename T, typename Default>
- consteval auto* GetRedBlackKeyType() {
- if constexpr (HasRedBlackKeyType<T>) {
- return static_cast<typename T::RedBlackKeyType*>(nullptr);
- } else {
- return static_cast<Default*>(nullptr);
- }
+template <typename T, typename Default>
+consteval auto* GetRedBlackKeyType() {
+ if constexpr (HasRedBlackKeyType<T>) {
+ return static_cast<typename T::RedBlackKeyType*>(nullptr);
+ } else {
+ return static_cast<Default*>(nullptr);
}
+}
} // namespace impl
diff --git a/src/common/make_unique_for_overwrite.h b/src/common/make_unique_for_overwrite.h
index c7413cf51..17f81bba4 100644
--- a/src/common/make_unique_for_overwrite.h
+++ b/src/common/make_unique_for_overwrite.h
@@ -9,17 +9,19 @@
namespace Common {
template <class T>
-requires(!std::is_array_v<T>) std::unique_ptr<T> make_unique_for_overwrite() {
+ requires(!std::is_array_v<T>)
+std::unique_ptr<T> make_unique_for_overwrite() {
return std::unique_ptr<T>(new T);
}
template <class T>
-requires std::is_unbounded_array_v<T> std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
+ requires std::is_unbounded_array_v<T>
+std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
return std::unique_ptr<T>(new std::remove_extent_t<T>[n]);
}
template <class T, class... Args>
-requires std::is_bounded_array_v<T>
+ requires std::is_bounded_array_v<T>
void make_unique_for_overwrite(Args&&...) = delete;
} // namespace Common
diff --git a/src/common/polyfill_ranges.h b/src/common/polyfill_ranges.h
index ca44bfaef..512dbcbcb 100644
--- a/src/common/polyfill_ranges.h
+++ b/src/common/polyfill_ranges.h
@@ -18,9 +18,9 @@ namespace ranges {
template <typename T>
concept range = requires(T& t) {
- begin(t);
- end(t);
-};
+ begin(t);
+ end(t);
+ };
template <typename T>
concept input_range = range<T>;
@@ -421,7 +421,7 @@ struct generate_fn {
}
template <typename R, std::copy_constructible F>
- requires std::invocable<F&> && ranges::output_range<R>
+ requires std::invocable<F&> && ranges::output_range<R>
constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const {
return operator()(ranges::begin(r), ranges::end(r), std::move(gen));
}
diff --git a/src/common/polyfill_thread.h b/src/common/polyfill_thread.h
index b2c929d2f..b5ef055db 100644
--- a/src/common/polyfill_thread.h
+++ b/src/common/polyfill_thread.h
@@ -41,17 +41,18 @@ bool StoppableTimedWait(std::stop_token token, const std::chrono::duration<Rep,
#include <chrono>
#include <condition_variable>
#include <functional>
-#include <list>
+#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include <type_traits>
+#include <utility>
namespace std {
namespace polyfill {
-using stop_state_callbacks = list<function<void()>>;
+using stop_state_callback = size_t;
class stop_state {
public:
@@ -59,61 +60,69 @@ public:
~stop_state() = default;
bool request_stop() {
- stop_state_callbacks callbacks;
+ unique_lock lk{m_lock};
- {
- scoped_lock lk{m_lock};
+ if (m_stop_requested) {
+ // Already set, nothing to do.
+ return false;
+ }
- if (m_stop_requested.load()) {
- // Already set, nothing to do
- return false;
- }
+ // Mark stop requested.
+ m_stop_requested = true;
- // Set as requested
- m_stop_requested = true;
+ while (!m_callbacks.empty()) {
+ // Get an iterator to the first element.
+ const auto it = m_callbacks.begin();
- // Copy callback list
- callbacks = m_callbacks;
- }
+ // Move the callback function out of the map.
+ function<void()> f;
+ swap(it->second, f);
+
+ // Erase the now-empty map element.
+ m_callbacks.erase(it);
- for (auto callback : callbacks) {
- callback();
+ // Run the callback.
+ if (f) {
+ f();
+ }
}
return true;
}
bool stop_requested() const {
- return m_stop_requested.load();
+ unique_lock lk{m_lock};
+ return m_stop_requested;
}
- stop_state_callbacks::const_iterator insert_callback(function<void()> f) {
- stop_state_callbacks::const_iterator ret{};
- bool should_run{};
-
- {
- scoped_lock lk{m_lock};
- should_run = m_stop_requested.load();
- m_callbacks.push_front(f);
- ret = m_callbacks.begin();
- }
+ stop_state_callback insert_callback(function<void()> f) {
+ unique_lock lk{m_lock};
- if (should_run) {
- f();
+ if (m_stop_requested) {
+ // Stop already requested. Don't insert anything,
+ // just run the callback synchronously.
+ if (f) {
+ f();
+ }
+ return 0;
}
+ // Insert the callback.
+ stop_state_callback ret = ++m_next_callback;
+ m_callbacks.emplace(ret, move(f));
return ret;
}
- void remove_callback(stop_state_callbacks::const_iterator it) {
- scoped_lock lk{m_lock};
- m_callbacks.erase(it);
+ void remove_callback(stop_state_callback cb) {
+ unique_lock lk{m_lock};
+ m_callbacks.erase(cb);
}
private:
- mutex m_lock;
- atomic<bool> m_stop_requested;
- stop_state_callbacks m_callbacks;
+ mutable recursive_mutex m_lock;
+ map<stop_state_callback, function<void()>> m_callbacks;
+ stop_state_callback m_next_callback{0};
+ bool m_stop_requested{false};
};
} // namespace polyfill
@@ -204,7 +213,7 @@ public:
using callback_type = Callback;
template <typename C>
- requires constructible_from<Callback, C>
+ requires constructible_from<Callback, C>
explicit stop_callback(const stop_token& st,
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(st.m_stop_state) {
@@ -213,7 +222,7 @@ public:
}
}
template <typename C>
- requires constructible_from<Callback, C>
+ requires constructible_from<Callback, C>
explicit stop_callback(stop_token&& st,
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(move(st.m_stop_state)) {
@@ -223,7 +232,7 @@ public:
}
~stop_callback() {
if (m_stop_state && m_callback) {
- m_stop_state->remove_callback(*m_callback);
+ m_stop_state->remove_callback(m_callback);
}
}
@@ -234,7 +243,7 @@ public:
private:
shared_ptr<polyfill::stop_state> m_stop_state;
- optional<polyfill::stop_state_callbacks::const_iterator> m_callback;
+ polyfill::stop_state_callback m_callback;
};
template <typename Callback>
diff --git a/src/common/settings.h b/src/common/settings.h
index 4b4da4da2..64db66f37 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -131,7 +131,8 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
- explicit Setting(const Type& default_val, const std::string& name) requires(!ranged)
+ explicit Setting(const Type& default_val, const std::string& name)
+ requires(!ranged)
: value{default_val}, default_value{default_val}, label{name} {}
virtual ~Setting() = default;
@@ -144,7 +145,8 @@ public:
* @param name Label for the setting
*/
explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
- const std::string& name) requires(ranged)
+ const std::string& name)
+ requires(ranged)
: value{default_val},
default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
@@ -232,7 +234,8 @@ public:
* @param default_val Intial value of the setting, and default value of the setting
* @param name Label for the setting
*/
- explicit SwitchableSetting(const Type& default_val, const std::string& name) requires(!ranged)
+ explicit SwitchableSetting(const Type& default_val, const std::string& name)
+ requires(!ranged)
: Setting<Type>{default_val, name} {}
virtual ~SwitchableSetting() = default;
@@ -245,7 +248,8 @@ public:
* @param name Label for the setting
*/
explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
- const std::string& name) requires(ranged)
+ const std::string& name)
+ requires(ranged)
: Setting<Type, true>{default_val, min_val, max_val, name} {}
/**
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index b26db4796..e0b6180c5 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -30,7 +30,7 @@ std::string ToUpper(std::string str) {
return str;
}
-std::string StringFromBuffer(const std::vector<u8>& data) {
+std::string StringFromBuffer(std::span<const u8> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
diff --git a/src/common/string_util.h b/src/common/string_util.h
index ce18a33cf..f8aecc875 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -5,6 +5,7 @@
#pragma once
#include <cstddef>
+#include <span>
#include <string>
#include <vector>
#include "common/common_types.h"
@@ -17,7 +18,7 @@ namespace Common {
/// Make a string uppercase
[[nodiscard]] std::string ToUpper(std::string str);
-[[nodiscard]] std::string StringFromBuffer(const std::vector<u8>& data);
+[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
[[nodiscard]] std::string StripSpaces(const std::string& s);
[[nodiscard]] std::string StripQuotes(const std::string& s);
diff --git a/src/common/tree.h b/src/common/tree.h
index f77859209..f4fc43de3 100644
--- a/src/common/tree.h
+++ b/src/common/tree.h
@@ -103,12 +103,12 @@ concept IsRBEntry = CheckRBEntry<T>::value;
template <typename T>
concept HasRBEntry = requires(T& t, const T& ct) {
- { t.GetRBEntry() } -> std::same_as<RBEntry<T>&>;
- { ct.GetRBEntry() } -> std::same_as<const RBEntry<T>&>;
-};
+ { t.GetRBEntry() } -> std::same_as<RBEntry<T>&>;
+ { ct.GetRBEntry() } -> std::same_as<const RBEntry<T>&>;
+ };
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
class RBHead {
private:
T* m_rbh_root = nullptr;
@@ -130,90 +130,90 @@ public:
};
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr RBEntry<T>& RB_ENTRY(T* t) {
return t->GetRBEntry();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr const RBEntry<T>& RB_ENTRY(const T* t) {
return t->GetRBEntry();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_LEFT(T* t) {
return RB_ENTRY(t).Left();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_LEFT(const T* t) {
return RB_ENTRY(t).Left();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_RIGHT(T* t) {
return RB_ENTRY(t).Right();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_RIGHT(const T* t) {
return RB_ENTRY(t).Right();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr T* RB_PARENT(T* t) {
return RB_ENTRY(t).Parent();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr const T* RB_PARENT(const T* t) {
return RB_ENTRY(t).Parent();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_SET_LEFT(T* t, T* e) {
RB_ENTRY(t).SetLeft(e);
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_SET_RIGHT(T* t, T* e) {
RB_ENTRY(t).SetRight(e);
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_SET_PARENT(T* t, T* e) {
RB_ENTRY(t).SetParent(e);
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr bool RB_IS_BLACK(const T* t) {
return RB_ENTRY(t).IsBlack();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr bool RB_IS_RED(const T* t) {
return RB_ENTRY(t).IsRed();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
[[nodiscard]] constexpr RBColor RB_COLOR(const T* t) {
return RB_ENTRY(t).Color();
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_SET_COLOR(T* t, RBColor c) {
RB_ENTRY(t).SetColor(c);
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_SET(T* elm, T* parent) {
auto& rb_entry = RB_ENTRY(elm);
rb_entry.SetParent(parent);
@@ -223,14 +223,14 @@ constexpr void RB_SET(T* elm, T* parent) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_SET_BLACKRED(T* black, T* red) {
RB_SET_COLOR(black, RBColor::RB_BLACK);
RB_SET_COLOR(red, RBColor::RB_RED);
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) {
tmp = RB_RIGHT(elm);
if (RB_SET_RIGHT(elm, RB_LEFT(tmp)); RB_RIGHT(elm) != nullptr) {
@@ -252,7 +252,7 @@ constexpr void RB_ROTATE_LEFT(RBHead<T>& head, T* elm, T*& tmp) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) {
tmp = RB_LEFT(elm);
if (RB_SET_LEFT(elm, RB_RIGHT(tmp)); RB_LEFT(elm) != nullptr) {
@@ -274,7 +274,7 @@ constexpr void RB_ROTATE_RIGHT(RBHead<T>& head, T* elm, T*& tmp) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) {
T* tmp;
while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head.Root()) {
@@ -358,7 +358,7 @@ constexpr void RB_REMOVE_COLOR(RBHead<T>& head, T* parent, T* elm) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) {
T* child = nullptr;
T* parent = nullptr;
@@ -451,7 +451,7 @@ constexpr T* RB_REMOVE(RBHead<T>& head, T* elm) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) {
T *parent = nullptr, *tmp = nullptr;
while ((parent = RB_PARENT(elm)) != nullptr && RB_IS_RED(parent)) {
@@ -499,7 +499,7 @@ constexpr void RB_INSERT_COLOR(RBHead<T>& head, T* elm) {
}
template <typename T, typename Compare>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) {
T* parent = nullptr;
T* tmp = head.Root();
@@ -534,7 +534,7 @@ constexpr T* RB_INSERT(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename Compare>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
@@ -553,7 +553,7 @@ constexpr T* RB_FIND(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename Compare>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
T* res = nullptr;
@@ -574,7 +574,7 @@ constexpr T* RB_NFIND(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename U, typename Compare>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
@@ -593,7 +593,7 @@ constexpr T* RB_FIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T, typename U, typename Compare>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
T* res = nullptr;
@@ -614,7 +614,7 @@ constexpr T* RB_NFIND_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T, typename Compare>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) {
T* tmp = head.Root();
@@ -631,7 +631,7 @@ constexpr T* RB_FIND_EXISTING(RBHead<T>& head, T* elm, Compare cmp) {
}
template <typename T, typename U, typename Compare>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) {
T* tmp = head.Root();
@@ -648,7 +648,7 @@ constexpr T* RB_FIND_EXISTING_KEY(RBHead<T>& head, const U& key, Compare cmp) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_NEXT(T* elm) {
if (RB_RIGHT(elm)) {
elm = RB_RIGHT(elm);
@@ -669,7 +669,7 @@ constexpr T* RB_NEXT(T* elm) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_PREV(T* elm) {
if (RB_LEFT(elm)) {
elm = RB_LEFT(elm);
@@ -690,7 +690,7 @@ constexpr T* RB_PREV(T* elm) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_MIN(RBHead<T>& head) {
T* tmp = head.Root();
T* parent = nullptr;
@@ -704,7 +704,7 @@ constexpr T* RB_MIN(RBHead<T>& head) {
}
template <typename T>
-requires HasRBEntry<T>
+ requires HasRBEntry<T>
constexpr T* RB_MAX(RBHead<T>& head) {
T* tmp = head.Root();
T* parent = nullptr;
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index e62eeea2e..0e2095c45 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -348,9 +348,7 @@ public:
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
// component names (x<->r) and permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
- [[nodiscard]] constexpr Vec2<T> name() const { \
- return Vec2<T>(a, b); \
- }
+ [[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
_DEFINE_SWIZZLER2(a, b, a##b); \
_DEFINE_SWIZZLER2(a, b, a2##b2); \
@@ -543,9 +541,7 @@ public:
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
// permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
- [[nodiscard]] constexpr Vec2<T> name() const { \
- return Vec2<T>(a, b); \
- }
+ [[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
_DEFINE_SWIZZLER2(a, a, a##a); \
_DEFINE_SWIZZLER2(a, a, a2##a2)
@@ -570,9 +566,7 @@ public:
#undef _DEFINE_SWIZZLER2
#define _DEFINE_SWIZZLER3(a, b, c, name) \
- [[nodiscard]] constexpr Vec3<T> name() const { \
- return Vec3<T>(a, b, c); \
- }
+ [[nodiscard]] constexpr Vec3<T> name() const { return Vec3<T>(a, b, c); }
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
_DEFINE_SWIZZLER3(a, a, a, a##a##a); \
_DEFINE_SWIZZLER3(a, a, a, a2##a2##a2)
@@ -641,8 +635,8 @@ template <typename T>
// linear interpolation via float: 0.0=begin, 1.0=end
template <typename X>
-[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{})
- Lerp(const X& begin, const X& end, const float t) {
+[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
+ const float t) {
return begin * (1.f - t) + end * t;
}
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 5afdeb5ff..112c61b80 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -182,6 +182,8 @@ add_library(core STATIC
hle/kernel/k_auto_object_container.cpp
hle/kernel/k_auto_object_container.h
hle/kernel/k_affinity_mask.h
+ hle/kernel/k_capabilities.cpp
+ hle/kernel/k_capabilities.h
hle/kernel/k_class_token.cpp
hle/kernel/k_class_token.h
hle/kernel/k_client_port.cpp
@@ -193,6 +195,8 @@ add_library(core STATIC
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
hle/kernel/k_debug.h
+ hle/kernel/k_device_address_space.cpp
+ hle/kernel/k_device_address_space.h
hle/kernel/k_dynamic_page_manager.h
hle/kernel/k_dynamic_resource_manager.h
hle/kernel/k_dynamic_slab_heap.h
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h
index 13cbdb734..45567b840 100644
--- a/src/core/hardware_properties.h
+++ b/src/core/hardware_properties.h
@@ -25,6 +25,26 @@ constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
};
+static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>();
+
+static constexpr inline u64 VirtualCoreMask = [] {
+ u64 mask = 0;
+ for (size_t i = 0; i < NumVirtualCores; ++i) {
+ mask |= (UINT64_C(1) << i);
+ }
+ return mask;
+}();
+
+static constexpr inline u64 ConvertVirtualCoreMaskToPhysical(u64 v_core_mask) {
+ u64 p_core_mask = 0;
+ while (v_core_mask != 0) {
+ const u64 next = std::countr_zero(v_core_mask);
+ v_core_mask &= ~(static_cast<u64>(1) << next);
+ p_core_mask |= (static_cast<u64>(1) << VirtualToPhysicalCoreMap[next]);
+ }
+ return p_core_mask;
+}
+
// Cortex-A57 supports 4 memory watchpoints
constexpr u64 NUM_WATCHPOINTS = 4;
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 0e06468da..631aa6ad2 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -12,6 +12,7 @@
namespace Core::HID {
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
+constexpr u32 TURBO_BUTTON_DELAY = 4;
// Use a common UUID for TAS and Virtual Gamepad
constexpr Common::UUID TAS_UUID =
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
@@ -447,6 +448,7 @@ void EmulatedController::ReloadInput() {
},
});
}
+ turbo_button_state = 0;
}
void EmulatedController::UnloadInput() {
@@ -687,6 +689,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
}
current_status.toggle = new_status.toggle;
+ current_status.turbo = new_status.turbo;
current_status.uuid = uuid;
// Update button status with current
@@ -1548,7 +1551,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
if (is_configuring) {
return {};
}
- return controller.npad_button_state;
+ return {controller.npad_button_state.raw & GetTurboButtonMask()};
}
DebugPadButton EmulatedController::GetDebugPadButtons() const {
@@ -1656,4 +1659,74 @@ void EmulatedController::DeleteCallback(int key) {
}
callback_list.erase(iterator);
}
+
+void EmulatedController::TurboButtonUpdate() {
+ turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2);
+}
+
+NpadButton EmulatedController::GetTurboButtonMask() const {
+ // Apply no mask when disabled
+ if (turbo_button_state < TURBO_BUTTON_DELAY) {
+ return {NpadButton::All};
+ }
+
+ NpadButtonState button_mask{};
+ for (std::size_t index = 0; index < controller.button_values.size(); ++index) {
+ if (!controller.button_values[index].turbo) {
+ continue;
+ }
+
+ switch (index) {
+ case Settings::NativeButton::A:
+ button_mask.a.Assign(1);
+ break;
+ case Settings::NativeButton::B:
+ button_mask.b.Assign(1);
+ break;
+ case Settings::NativeButton::X:
+ button_mask.x.Assign(1);
+ break;
+ case Settings::NativeButton::Y:
+ button_mask.y.Assign(1);
+ break;
+ case Settings::NativeButton::L:
+ button_mask.l.Assign(1);
+ break;
+ case Settings::NativeButton::R:
+ button_mask.r.Assign(1);
+ break;
+ case Settings::NativeButton::ZL:
+ button_mask.zl.Assign(1);
+ break;
+ case Settings::NativeButton::ZR:
+ button_mask.zr.Assign(1);
+ break;
+ case Settings::NativeButton::DLeft:
+ button_mask.left.Assign(1);
+ break;
+ case Settings::NativeButton::DUp:
+ button_mask.up.Assign(1);
+ break;
+ case Settings::NativeButton::DRight:
+ button_mask.right.Assign(1);
+ break;
+ case Settings::NativeButton::DDown:
+ button_mask.down.Assign(1);
+ break;
+ case Settings::NativeButton::SL:
+ button_mask.left_sl.Assign(1);
+ button_mask.right_sl.Assign(1);
+ break;
+ case Settings::NativeButton::SR:
+ button_mask.left_sr.Assign(1);
+ button_mask.right_sr.Assign(1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return static_cast<NpadButton>(~button_mask.raw);
+}
+
} // namespace Core::HID
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 3ac77b2b5..b02bf35c4 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -411,6 +411,9 @@ public:
*/
void DeleteCallback(int key);
+ /// Swaps the state of the turbo buttons
+ void TurboButtonUpdate();
+
private:
/// creates input devices from params
void LoadDevices();
@@ -511,6 +514,8 @@ private:
*/
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
+ NpadButton GetTurboButtonMask() const;
+
const NpadIdType npad_id_type;
NpadStyleIndex npad_type{NpadStyleIndex::None};
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
@@ -520,6 +525,7 @@ private:
bool system_buttons_enabled{true};
f32 motion_sensitivity{0.01f};
bool force_update_motion{false};
+ u32 turbo_button_state{0};
// Temporary values to avoid doing changes while the controller is in configuring mode
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 738b6d0f1..494151eef 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -11,6 +11,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/scratch_buffer.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_auto_object.h"
@@ -325,7 +326,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
return ResultSuccess;
}
-std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
+std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) const {
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
BufferDescriptorA()[buffer_index].Size()};
if (is_buffer_a) {
@@ -345,6 +346,33 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
}
}
+std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
+ static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a;
+ static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x;
+
+ const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
+ BufferDescriptorA()[buffer_index].Size()};
+ if (is_buffer_a) {
+ ASSERT_OR_EXECUTE_MSG(
+ BufferDescriptorA().size() > buffer_index, { return {}; },
+ "BufferDescriptorA invalid buffer_index {}", buffer_index);
+ auto& read_buffer = read_buffer_a[buffer_index];
+ read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size());
+ memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(),
+ read_buffer.size());
+ return read_buffer;
+ } else {
+ ASSERT_OR_EXECUTE_MSG(
+ BufferDescriptorX().size() > buffer_index, { return {}; },
+ "BufferDescriptorX invalid buffer_index {}", buffer_index);
+ auto& read_buffer = read_buffer_x[buffer_index];
+ read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size());
+ memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(),
+ read_buffer.size());
+ return read_buffer;
+ }
+}
+
std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
std::size_t buffer_index) const {
if (size == 0) {
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index e252b5f4b..5bf4f171b 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -7,6 +7,7 @@
#include <functional>
#include <memory>
#include <optional>
+#include <span>
#include <string>
#include <type_traits>
#include <vector>
@@ -270,8 +271,11 @@ public:
return domain_message_header.has_value();
}
- /// Helper function to read a buffer using the appropriate buffer descriptor
- [[nodiscard]] std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const;
+ /// Helper function to get a span of a buffer using the appropriate buffer descriptor
+ [[nodiscard]] std::span<const u8> ReadBuffer(std::size_t buffer_index = 0) const;
+
+ /// Helper function to read a copy of a buffer using the appropriate buffer descriptor
+ [[nodiscard]] std::vector<u8> ReadBufferCopy(std::size_t buffer_index = 0) const;
/// Helper function to write a buffer using the appropriate buffer descriptor
std::size_t WriteBuffer(const void* buffer, std::size_t size,
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index 7b363eb1e..571acf4b2 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -11,6 +11,7 @@
#include "core/hle/kernel/init/init_slab_setup.h"
#include "core/hle/kernel/k_code_memory.h"
#include "core/hle/kernel/k_debug.h"
+#include "core/hle/kernel/k_device_address_space.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_event_info.h"
#include "core/hle/kernel/k_memory_layout.h"
@@ -43,6 +44,7 @@ namespace Kernel::Init {
HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \
+ HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ##__VA_ARGS__) \
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
HANDLER(KThreadLocalPage, \
(SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index 2827763d5..e8118c2b8 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -24,9 +24,7 @@ private:
friend class ::Kernel::KClassTokenGenerator; \
static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \
static constexpr inline const char* const TypeName = #CLASS; \
- static constexpr inline ClassTokenType ClassToken() { \
- return ::Kernel::ClassToken<CLASS>; \
- } \
+ static constexpr inline ClassTokenType ClassToken() { return ::Kernel::ClassToken<CLASS>; } \
\
public: \
YUZU_NON_COPYABLE(CLASS); \
@@ -37,15 +35,9 @@ public:
constexpr ClassTokenType Token = ClassToken(); \
return TypeObj(TypeName, Token); \
} \
- static constexpr const char* GetStaticTypeName() { \
- return TypeName; \
- } \
- virtual TypeObj GetTypeObj() ATTRIBUTE { \
- return GetStaticTypeObj(); \
- } \
- virtual const char* GetTypeName() ATTRIBUTE { \
- return GetStaticTypeName(); \
- } \
+ static constexpr const char* GetStaticTypeName() { return TypeName; } \
+ virtual TypeObj GetTypeObj() ATTRIBUTE { return GetStaticTypeObj(); } \
+ virtual const char* GetTypeName() ATTRIBUTE { return GetStaticTypeName(); } \
\
private: \
constexpr bool operator!=(const TypeObj& rhs)
@@ -245,8 +237,8 @@ public:
}
template <typename U>
- requires(std::derived_from<T, U> ||
- std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
+ requires(std::derived_from<T, U> || std::derived_from<U, T>)
+ constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
if constexpr (std::derived_from<U, T>) {
// Upcast.
m_obj = rhs.m_obj;
diff --git a/src/core/hle/kernel/k_capabilities.cpp b/src/core/hle/kernel/k_capabilities.cpp
new file mode 100644
index 000000000..64f1d7371
--- /dev/null
+++ b/src/core/hle/kernel/k_capabilities.cpp
@@ -0,0 +1,358 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hardware_properties.h"
+#include "core/hle/kernel/k_capabilities.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc_results.h"
+#include "core/hle/kernel/svc_version.h"
+
+namespace Kernel {
+
+Result KCapabilities::InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table) {
+ // We're initializing an initial process.
+ m_svc_access_flags.reset();
+ m_irq_access_flags.reset();
+ m_debug_capabilities = 0;
+ m_handle_table_size = 0;
+ m_intended_kernel_version = 0;
+ m_program_type = 0;
+
+ // Initial processes may run on all cores.
+ constexpr u64 VirtMask = Core::Hardware::VirtualCoreMask;
+ constexpr u64 PhysMask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(VirtMask);
+
+ m_core_mask = VirtMask;
+ m_phys_core_mask = PhysMask;
+
+ // Initial processes may use any user priority they like.
+ m_priority_mask = ~0xFULL;
+
+ // Here, Nintendo sets the kernel version to the current kernel version.
+ // We will follow suit and set the version to the highest supported kernel version.
+ KernelVersion intended_kernel_version{};
+ intended_kernel_version.major_version.Assign(Svc::SupportedKernelMajorVersion);
+ intended_kernel_version.minor_version.Assign(Svc::SupportedKernelMinorVersion);
+ m_intended_kernel_version = intended_kernel_version.raw;
+
+ // Parse the capabilities array.
+ R_RETURN(this->SetCapabilities(kern_caps, page_table));
+}
+
+Result KCapabilities::InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table) {
+ // We're initializing a user process.
+ m_svc_access_flags.reset();
+ m_irq_access_flags.reset();
+ m_debug_capabilities = 0;
+ m_handle_table_size = 0;
+ m_intended_kernel_version = 0;
+ m_program_type = 0;
+
+ // User processes must specify what cores/priorities they can use.
+ m_core_mask = 0;
+ m_priority_mask = 0;
+
+ // Parse the user capabilities array.
+ R_RETURN(this->SetCapabilities(user_caps, page_table));
+}
+
+Result KCapabilities::SetCorePriorityCapability(const u32 cap) {
+ // We can't set core/priority if we've already set them.
+ R_UNLESS(m_core_mask == 0, ResultInvalidArgument);
+ R_UNLESS(m_priority_mask == 0, ResultInvalidArgument);
+
+ // Validate the core/priority.
+ CorePriority pack{cap};
+ const u32 min_core = pack.minimum_core_id;
+ const u32 max_core = pack.maximum_core_id;
+ const u32 max_prio = pack.lowest_thread_priority;
+ const u32 min_prio = pack.highest_thread_priority;
+
+ R_UNLESS(min_core <= max_core, ResultInvalidCombination);
+ R_UNLESS(min_prio <= max_prio, ResultInvalidCombination);
+ R_UNLESS(max_core < Core::Hardware::NumVirtualCores, ResultInvalidCoreId);
+
+ ASSERT(max_prio < Common::BitSize<u64>());
+
+ // Set core mask.
+ for (auto core_id = min_core; core_id <= max_core; core_id++) {
+ m_core_mask |= (1ULL << core_id);
+ }
+ ASSERT((m_core_mask & Core::Hardware::VirtualCoreMask) == m_core_mask);
+
+ // Set physical core mask.
+ m_phys_core_mask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(m_core_mask);
+
+ // Set priority mask.
+ for (auto prio = min_prio; prio <= max_prio; prio++) {
+ m_priority_mask |= (1ULL << prio);
+ }
+
+ // We must have some core/priority we can use.
+ R_UNLESS(m_core_mask != 0, ResultInvalidArgument);
+ R_UNLESS(m_priority_mask != 0, ResultInvalidArgument);
+
+ // Processes must not have access to kernel thread priorities.
+ R_UNLESS((m_priority_mask & 0xF) == 0, ResultInvalidArgument);
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetSyscallMaskCapability(const u32 cap, u32& set_svc) {
+ // Validate the index.
+ SyscallMask pack{cap};
+ const u32 mask = pack.mask;
+ const u32 index = pack.index;
+
+ const u32 index_flag = (1U << index);
+ R_UNLESS((set_svc & index_flag) == 0, ResultInvalidCombination);
+ set_svc |= index_flag;
+
+ // Set SVCs.
+ for (size_t i = 0; i < decltype(SyscallMask::mask)::bits; i++) {
+ const u32 svc_id = static_cast<u32>(decltype(SyscallMask::mask)::bits * index + i);
+ if (mask & (1U << i)) {
+ R_UNLESS(this->SetSvcAllowed(svc_id), ResultOutOfRange);
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table) {
+ const auto range_pack = MapRange{cap};
+ const auto size_pack = MapRangeSize{size_cap};
+
+ // Get/validate address/size
+ const u64 phys_addr = range_pack.address.Value() * PageSize;
+
+ // Validate reserved bits are unused.
+ R_UNLESS(size_pack.reserved.Value() == 0, ResultOutOfRange);
+
+ const size_t num_pages = size_pack.pages;
+ const size_t size = num_pages * PageSize;
+ R_UNLESS(num_pages != 0, ResultInvalidSize);
+ R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
+ R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
+
+ // Do the mapping.
+ [[maybe_unused]] const KMemoryPermission perm = range_pack.read_only.Value()
+ ? KMemoryPermission::UserRead
+ : KMemoryPermission::UserReadWrite;
+ if (MapRangeSize{size_cap}.normal) {
+ // R_RETURN(page_table->MapStatic(phys_addr, size, perm));
+ } else {
+ // R_RETURN(page_table->MapIo(phys_addr, size, perm));
+ }
+
+ UNIMPLEMENTED();
+ R_SUCCEED();
+}
+
+Result KCapabilities::MapIoPage_(const u32 cap, KPageTable* page_table) {
+ // Get/validate address/size
+ const u64 phys_addr = MapIoPage{cap}.address.Value() * PageSize;
+ const size_t num_pages = 1;
+ const size_t size = num_pages * PageSize;
+ R_UNLESS(num_pages != 0, ResultInvalidSize);
+ R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
+ R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
+
+ // Do the mapping.
+ // R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission_UserReadWrite));
+
+ UNIMPLEMENTED();
+ R_SUCCEED();
+}
+
+template <typename F>
+Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) {
+ // Define the allowed memory regions.
+ constexpr std::array<KMemoryRegionType, 4> MemoryRegions{
+ KMemoryRegionType_None,
+ KMemoryRegionType_KernelTraceBuffer,
+ KMemoryRegionType_OnMemoryBootImage,
+ KMemoryRegionType_DTB,
+ };
+
+ // Extract regions/read only.
+ const MapRegion pack{cap};
+ const std::array<RegionType, 3> types{pack.region0, pack.region1, pack.region2};
+ const std::array<u32, 3> ro{pack.read_only0, pack.read_only1, pack.read_only2};
+
+ for (size_t i = 0; i < types.size(); i++) {
+ const auto type = types[i];
+ const auto perm = ro[i] ? KMemoryPermission::UserRead : KMemoryPermission::UserReadWrite;
+ switch (type) {
+ case RegionType::NoMapping:
+ break;
+ case RegionType::KernelTraceBuffer:
+ case RegionType::OnMemoryBootImage:
+ case RegionType::DTB:
+ R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
+ break;
+ default:
+ R_THROW(ResultNotFound);
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::MapRegion_(const u32 cap, KPageTable* page_table) {
+ // Map each region into the process's page table.
+ R_RETURN(ProcessMapRegionCapability(
+ cap, [](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
+ // R_RETURN(page_table->MapRegion(region_type, perm));
+ UNIMPLEMENTED();
+ R_SUCCEED();
+ }));
+}
+
+Result KCapabilities::CheckMapRegion(KernelCore& kernel, const u32 cap) {
+ // Check that each region has a physical backing store.
+ R_RETURN(ProcessMapRegionCapability(
+ cap, [&](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
+ R_UNLESS(kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived(
+ region_type) != nullptr,
+ ResultOutOfRange);
+ R_SUCCEED();
+ }));
+}
+
+Result KCapabilities::SetInterruptPairCapability(const u32 cap) {
+ // Extract interrupts.
+ const InterruptPair pack{cap};
+ const std::array<u32, 2> ids{pack.interrupt_id0, pack.interrupt_id1};
+
+ for (size_t i = 0; i < ids.size(); i++) {
+ if (ids[i] != PaddingInterruptId) {
+ UNIMPLEMENTED();
+ // R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(ids[i]), ResultOutOfRange);
+ // R_UNLESS(this->SetInterruptPermitted(ids[i]), ResultOutOfRange);
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetProgramTypeCapability(const u32 cap) {
+ // Validate.
+ const ProgramType pack{cap};
+ R_UNLESS(pack.reserved == 0, ResultReservedUsed);
+
+ m_program_type = pack.type;
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetKernelVersionCapability(const u32 cap) {
+ // Ensure we haven't set our version before.
+ R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version == 0, ResultInvalidArgument);
+
+ // Set, ensure that we set a valid version.
+ m_intended_kernel_version = cap;
+ R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version != 0, ResultInvalidArgument);
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetHandleTableCapability(const u32 cap) {
+ // Validate.
+ const HandleTable pack{cap};
+ R_UNLESS(pack.reserved == 0, ResultReservedUsed);
+
+ m_handle_table_size = pack.size;
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetDebugFlagsCapability(const u32 cap) {
+ // Validate.
+ const DebugFlags pack{cap};
+ R_UNLESS(pack.reserved == 0, ResultReservedUsed);
+
+ DebugFlags debug_capabilities{m_debug_capabilities};
+ debug_capabilities.allow_debug.Assign(pack.allow_debug);
+ debug_capabilities.force_debug.Assign(pack.force_debug);
+ m_debug_capabilities = debug_capabilities.raw;
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetCapability(const u32 cap, u32& set_flags, u32& set_svc,
+ KPageTable* page_table) {
+ // Validate this is a capability we can act on.
+ const auto type = GetCapabilityType(cap);
+ R_UNLESS(type != CapabilityType::Invalid, ResultInvalidArgument);
+
+ // If the type is padding, we have no work to do.
+ R_SUCCEED_IF(type == CapabilityType::Padding);
+
+ // Check that we haven't already processed this capability.
+ const auto flag = GetCapabilityFlag(type);
+ R_UNLESS(((set_flags & InitializeOnceFlags) & flag) == 0, ResultInvalidCombination);
+ set_flags |= flag;
+
+ // Process the capability.
+ switch (type) {
+ case CapabilityType::CorePriority:
+ R_RETURN(this->SetCorePriorityCapability(cap));
+ case CapabilityType::SyscallMask:
+ R_RETURN(this->SetSyscallMaskCapability(cap, set_svc));
+ case CapabilityType::MapIoPage:
+ R_RETURN(this->MapIoPage_(cap, page_table));
+ case CapabilityType::MapRegion:
+ R_RETURN(this->MapRegion_(cap, page_table));
+ case CapabilityType::InterruptPair:
+ R_RETURN(this->SetInterruptPairCapability(cap));
+ case CapabilityType::ProgramType:
+ R_RETURN(this->SetProgramTypeCapability(cap));
+ case CapabilityType::KernelVersion:
+ R_RETURN(this->SetKernelVersionCapability(cap));
+ case CapabilityType::HandleTable:
+ R_RETURN(this->SetHandleTableCapability(cap));
+ case CapabilityType::DebugFlags:
+ R_RETURN(this->SetDebugFlagsCapability(cap));
+ default:
+ R_THROW(ResultInvalidArgument);
+ }
+}
+
+Result KCapabilities::SetCapabilities(std::span<const u32> caps, KPageTable* page_table) {
+ u32 set_flags = 0, set_svc = 0;
+
+ for (size_t i = 0; i < caps.size(); i++) {
+ const u32 cap{caps[i]};
+
+ if (GetCapabilityType(cap) == CapabilityType::MapRange) {
+ // Check that the pair cap exists.
+ R_UNLESS((++i) < caps.size(), ResultInvalidCombination);
+
+ // Check the pair cap is a map range cap.
+ const u32 size_cap{caps[i]};
+ R_UNLESS(GetCapabilityType(size_cap) == CapabilityType::MapRange,
+ ResultInvalidCombination);
+
+ // Map the range.
+ R_TRY(this->MapRange_(cap, size_cap, page_table));
+ } else {
+ R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::CheckCapabilities(KernelCore& kernel, std::span<const u32> caps) {
+ for (auto cap : caps) {
+ // Check the capability refers to a valid region.
+ if (GetCapabilityType(cap) == CapabilityType::MapRegion) {
+ R_TRY(CheckMapRegion(kernel, cap));
+ }
+ }
+
+ R_SUCCEED();
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_capabilities.h b/src/core/hle/kernel/k_capabilities.h
new file mode 100644
index 000000000..cd96f8d23
--- /dev/null
+++ b/src/core/hle/kernel/k_capabilities.h
@@ -0,0 +1,295 @@
+
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <bitset>
+#include <span>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+
+#include "core/hle/kernel/svc_types.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+class KPageTable;
+class KernelCore;
+
+class KCapabilities {
+public:
+ constexpr explicit KCapabilities() = default;
+
+ Result InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table);
+ Result InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table);
+
+ static Result CheckCapabilities(KernelCore& kernel, std::span<const u32> user_caps);
+
+ constexpr u64 GetCoreMask() const {
+ return m_core_mask;
+ }
+
+ constexpr u64 GetPhysicalCoreMask() const {
+ return m_phys_core_mask;
+ }
+
+ constexpr u64 GetPriorityMask() const {
+ return m_priority_mask;
+ }
+
+ constexpr s32 GetHandleTableSize() const {
+ return m_handle_table_size;
+ }
+
+ constexpr const Svc::SvcAccessFlagSet& GetSvcPermissions() const {
+ return m_svc_access_flags;
+ }
+
+ constexpr bool IsPermittedSvc(u32 id) const {
+ return (id < m_svc_access_flags.size()) && m_svc_access_flags[id];
+ }
+
+ constexpr bool IsPermittedInterrupt(u32 id) const {
+ return (id < m_irq_access_flags.size()) && m_irq_access_flags[id];
+ }
+
+ constexpr bool IsPermittedDebug() const {
+ return DebugFlags{m_debug_capabilities}.allow_debug.Value() != 0;
+ }
+
+ constexpr bool CanForceDebug() const {
+ return DebugFlags{m_debug_capabilities}.force_debug.Value() != 0;
+ }
+
+ constexpr u32 GetIntendedKernelMajorVersion() const {
+ return KernelVersion{m_intended_kernel_version}.major_version;
+ }
+
+ constexpr u32 GetIntendedKernelMinorVersion() const {
+ return KernelVersion{m_intended_kernel_version}.minor_version;
+ }
+
+private:
+ static constexpr size_t InterruptIdCount = 0x400;
+ using InterruptFlagSet = std::bitset<InterruptIdCount>;
+
+ enum class CapabilityType : u32 {
+ CorePriority = (1U << 3) - 1,
+ SyscallMask = (1U << 4) - 1,
+ MapRange = (1U << 6) - 1,
+ MapIoPage = (1U << 7) - 1,
+ MapRegion = (1U << 10) - 1,
+ InterruptPair = (1U << 11) - 1,
+ ProgramType = (1U << 13) - 1,
+ KernelVersion = (1U << 14) - 1,
+ HandleTable = (1U << 15) - 1,
+ DebugFlags = (1U << 16) - 1,
+
+ Invalid = 0U,
+ Padding = ~0U,
+ };
+
+ using RawCapabilityValue = u32;
+
+ static constexpr CapabilityType GetCapabilityType(const RawCapabilityValue value) {
+ return static_cast<CapabilityType>((~value & (value + 1)) - 1);
+ }
+
+ static constexpr u32 GetCapabilityFlag(CapabilityType type) {
+ return static_cast<u32>(type) + 1;
+ }
+
+ template <CapabilityType Type>
+ static constexpr inline u32 CapabilityFlag = static_cast<u32>(Type) + 1;
+
+ template <CapabilityType Type>
+ static constexpr inline u32 CapabilityId = std::countr_zero(CapabilityFlag<Type>);
+
+ union CorePriority {
+ static_assert(CapabilityId<CapabilityType::CorePriority> + 1 == 4);
+
+ RawCapabilityValue raw;
+ BitField<0, 4, CapabilityType> id;
+ BitField<4, 6, u32> lowest_thread_priority;
+ BitField<10, 6, u32> highest_thread_priority;
+ BitField<16, 8, u32> minimum_core_id;
+ BitField<24, 8, u32> maximum_core_id;
+ };
+
+ union SyscallMask {
+ static_assert(CapabilityId<CapabilityType::SyscallMask> + 1 == 5);
+
+ RawCapabilityValue raw;
+ BitField<0, 5, CapabilityType> id;
+ BitField<5, 24, u32> mask;
+ BitField<29, 3, u32> index;
+ };
+
+ // #undef MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES
+ static constexpr u64 PhysicalMapAllowedMask = (1ULL << 36) - 1;
+
+ union MapRange {
+ static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7);
+
+ RawCapabilityValue raw;
+ BitField<0, 7, CapabilityType> id;
+ BitField<7, 24, u32> address;
+ BitField<31, 1, u32> read_only;
+ };
+
+ union MapRangeSize {
+ static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7);
+
+ RawCapabilityValue raw;
+ BitField<0, 7, CapabilityType> id;
+ BitField<7, 20, u32> pages;
+ BitField<27, 4, u32> reserved;
+ BitField<31, 1, u32> normal;
+ };
+
+ union MapIoPage {
+ static_assert(CapabilityId<CapabilityType::MapIoPage> + 1 == 8);
+
+ RawCapabilityValue raw;
+ BitField<0, 8, CapabilityType> id;
+ BitField<8, 24, u32> address;
+ };
+
+ enum class RegionType : u32 {
+ NoMapping = 0,
+ KernelTraceBuffer = 1,
+ OnMemoryBootImage = 2,
+ DTB = 3,
+ };
+
+ union MapRegion {
+ static_assert(CapabilityId<CapabilityType::MapRegion> + 1 == 11);
+
+ RawCapabilityValue raw;
+ BitField<0, 11, CapabilityType> id;
+ BitField<11, 6, RegionType> region0;
+ BitField<17, 1, u32> read_only0;
+ BitField<18, 6, RegionType> region1;
+ BitField<24, 1, u32> read_only1;
+ BitField<25, 6, RegionType> region2;
+ BitField<31, 1, u32> read_only2;
+ };
+
+ union InterruptPair {
+ static_assert(CapabilityId<CapabilityType::InterruptPair> + 1 == 12);
+
+ RawCapabilityValue raw;
+ BitField<0, 12, CapabilityType> id;
+ BitField<12, 10, u32> interrupt_id0;
+ BitField<22, 10, u32> interrupt_id1;
+ };
+
+ union ProgramType {
+ static_assert(CapabilityId<CapabilityType::ProgramType> + 1 == 14);
+
+ RawCapabilityValue raw;
+ BitField<0, 14, CapabilityType> id;
+ BitField<14, 3, u32> type;
+ BitField<17, 15, u32> reserved;
+ };
+
+ union KernelVersion {
+ static_assert(CapabilityId<CapabilityType::KernelVersion> + 1 == 15);
+
+ RawCapabilityValue raw;
+ BitField<0, 15, CapabilityType> id;
+ BitField<15, 4, u32> major_version;
+ BitField<19, 13, u32> minor_version;
+ };
+
+ union HandleTable {
+ static_assert(CapabilityId<CapabilityType::HandleTable> + 1 == 16);
+
+ RawCapabilityValue raw;
+ BitField<0, 16, CapabilityType> id;
+ BitField<16, 10, u32> size;
+ BitField<26, 6, u32> reserved;
+ };
+
+ union DebugFlags {
+ static_assert(CapabilityId<CapabilityType::DebugFlags> + 1 == 17);
+
+ RawCapabilityValue raw;
+ BitField<0, 17, CapabilityType> id;
+ BitField<17, 1, u32> allow_debug;
+ BitField<18, 1, u32> force_debug;
+ BitField<19, 13, u32> reserved;
+ };
+
+ static_assert(sizeof(CorePriority) == 4);
+ static_assert(sizeof(SyscallMask) == 4);
+ static_assert(sizeof(MapRange) == 4);
+ static_assert(sizeof(MapRangeSize) == 4);
+ static_assert(sizeof(MapIoPage) == 4);
+ static_assert(sizeof(MapRegion) == 4);
+ static_assert(sizeof(InterruptPair) == 4);
+ static_assert(sizeof(ProgramType) == 4);
+ static_assert(sizeof(KernelVersion) == 4);
+ static_assert(sizeof(HandleTable) == 4);
+ static_assert(sizeof(DebugFlags) == 4);
+
+ static constexpr u32 InitializeOnceFlags =
+ CapabilityFlag<CapabilityType::CorePriority> | CapabilityFlag<CapabilityType::ProgramType> |
+ CapabilityFlag<CapabilityType::KernelVersion> |
+ CapabilityFlag<CapabilityType::HandleTable> | CapabilityFlag<CapabilityType::DebugFlags>;
+
+ static const u32 PaddingInterruptId = 0x3FF;
+ static_assert(PaddingInterruptId < InterruptIdCount);
+
+private:
+ constexpr bool SetSvcAllowed(u32 id) {
+ if (id < m_svc_access_flags.size()) [[likely]] {
+ m_svc_access_flags[id] = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ constexpr bool SetInterruptPermitted(u32 id) {
+ if (id < m_irq_access_flags.size()) [[likely]] {
+ m_irq_access_flags[id] = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ Result SetCorePriorityCapability(const u32 cap);
+ Result SetSyscallMaskCapability(const u32 cap, u32& set_svc);
+ Result MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table);
+ Result MapIoPage_(const u32 cap, KPageTable* page_table);
+ Result MapRegion_(const u32 cap, KPageTable* page_table);
+ Result SetInterruptPairCapability(const u32 cap);
+ Result SetProgramTypeCapability(const u32 cap);
+ Result SetKernelVersionCapability(const u32 cap);
+ Result SetHandleTableCapability(const u32 cap);
+ Result SetDebugFlagsCapability(const u32 cap);
+
+ template <typename F>
+ static Result ProcessMapRegionCapability(const u32 cap, F f);
+ static Result CheckMapRegion(KernelCore& kernel, const u32 cap);
+
+ Result SetCapability(const u32 cap, u32& set_flags, u32& set_svc, KPageTable* page_table);
+ Result SetCapabilities(std::span<const u32> caps, KPageTable* page_table);
+
+private:
+ Svc::SvcAccessFlagSet m_svc_access_flags{};
+ InterruptFlagSet m_irq_access_flags{};
+ u64 m_core_mask{};
+ u64 m_phys_core_mask{};
+ u64 m_priority_mask{};
+ u32 m_debug_capabilities{};
+ s32 m_handle_table_size{};
+ u32 m_intended_kernel_version{};
+ u32 m_program_type{};
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_device_address_space.cpp b/src/core/hle/kernel/k_device_address_space.cpp
new file mode 100644
index 000000000..27659ea3b
--- /dev/null
+++ b/src/core/hle/kernel/k_device_address_space.cpp
@@ -0,0 +1,150 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/assert.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_device_address_space.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel {
+
+KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer(kernel_), m_lock(kernel_), m_is_initialized(false) {}
+KDeviceAddressSpace::~KDeviceAddressSpace() = default;
+
+void KDeviceAddressSpace::Initialize() {
+ // This just forwards to the device page table manager.
+ // KDevicePageTable::Initialize();
+}
+
+// Member functions.
+Result KDeviceAddressSpace::Initialize(u64 address, u64 size) {
+ // Initialize the device page table.
+ // R_TRY(m_table.Initialize(address, size));
+
+ // Set member variables.
+ m_space_address = address;
+ m_space_size = size;
+ m_is_initialized = true;
+
+ R_SUCCEED();
+}
+
+void KDeviceAddressSpace::Finalize() {
+ // Finalize the table.
+ // m_table.Finalize();
+}
+
+Result KDeviceAddressSpace::Attach(Svc::DeviceName device_name) {
+ // Lock the address space.
+ KScopedLightLock lk(m_lock);
+
+ // Attach.
+ // R_RETURN(m_table.Attach(device_name, m_space_address, m_space_size));
+ R_SUCCEED();
+}
+
+Result KDeviceAddressSpace::Detach(Svc::DeviceName device_name) {
+ // Lock the address space.
+ KScopedLightLock lk(m_lock);
+
+ // Detach.
+ // R_RETURN(m_table.Detach(device_name));
+ R_SUCCEED();
+}
+
+Result KDeviceAddressSpace::Map(KPageTable* page_table, VAddr process_address, size_t size,
+ u64 device_address, u32 option, bool is_aligned) {
+ // Check that the address falls within the space.
+ R_UNLESS((m_space_address <= device_address &&
+ device_address + size - 1 <= m_space_address + m_space_size - 1),
+ ResultInvalidCurrentMemory);
+
+ // Decode the option.
+ const Svc::MapDeviceAddressSpaceOption option_pack{option};
+ const auto device_perm = option_pack.permission.Value();
+ const auto flags = option_pack.flags.Value();
+ const auto reserved = option_pack.reserved.Value();
+
+ // Validate the option.
+ // TODO: It is likely that this check for flags == none is only on NX board.
+ R_UNLESS(flags == Svc::MapDeviceAddressSpaceFlag::None, ResultInvalidEnumValue);
+ R_UNLESS(reserved == 0, ResultInvalidEnumValue);
+
+ // Lock the address space.
+ KScopedLightLock lk(m_lock);
+
+ // Lock the page table to prevent concurrent device mapping operations.
+ // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
+
+ // Lock the pages.
+ bool is_io{};
+ R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size,
+ ConvertToKMemoryPermission(device_perm),
+ is_aligned, true));
+
+ // Ensure that if we fail, we don't keep unmapped pages locked.
+ ON_RESULT_FAILURE {
+ ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess);
+ };
+
+ // Check that the io status is allowable.
+ if (is_io) {
+ R_UNLESS(static_cast<u32>(flags & Svc::MapDeviceAddressSpaceFlag::NotIoRegister) == 0,
+ ResultInvalidCombination);
+ }
+
+ // Map the pages.
+ {
+ // Perform the mapping.
+ // R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm,
+ // is_aligned, is_io));
+
+ // Ensure that we unmap the pages if we fail to update the protections.
+ // NOTE: Nintendo does not check the result of this unmap call.
+ // ON_RESULT_FAILURE { m_table.Unmap(device_address, size); };
+
+ // Update the protections in accordance with how much we mapped.
+ // R_TRY(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size));
+ }
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result KDeviceAddressSpace::Unmap(KPageTable* page_table, VAddr process_address, size_t size,
+ u64 device_address) {
+ // Check that the address falls within the space.
+ R_UNLESS((m_space_address <= device_address &&
+ device_address + size - 1 <= m_space_address + m_space_size - 1),
+ ResultInvalidCurrentMemory);
+
+ // Lock the address space.
+ KScopedLightLock lk(m_lock);
+
+ // Lock the page table to prevent concurrent device mapping operations.
+ // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
+
+ // Lock the pages.
+ R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true));
+
+ // Unmap the pages.
+ {
+ // If we fail to unmap, we want to do a partial unlock.
+ // ON_RESULT_FAILURE {
+ // ASSERT(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size) ==
+ // ResultSuccess);
+ // };
+
+ // Perform the unmap.
+ // R_TRY(m_table.Unmap(page_table, process_address, size, device_address));
+ }
+
+ // Unlock the pages.
+ ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess);
+
+ R_SUCCEED();
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_device_address_space.h b/src/core/hle/kernel/k_device_address_space.h
new file mode 100644
index 000000000..4709df995
--- /dev/null
+++ b/src/core/hle/kernel/k_device_address_space.h
@@ -0,0 +1,60 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <string>
+
+#include "common/common_types.h"
+#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/slab_helpers.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+class KDeviceAddressSpace final
+ : public KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject);
+
+public:
+ explicit KDeviceAddressSpace(KernelCore& kernel);
+ ~KDeviceAddressSpace();
+
+ Result Initialize(u64 address, u64 size);
+ void Finalize();
+
+ bool IsInitialized() const {
+ return m_is_initialized;
+ }
+ static void PostDestroy(uintptr_t arg) {}
+
+ Result Attach(Svc::DeviceName device_name);
+ Result Detach(Svc::DeviceName device_name);
+
+ Result MapByForce(KPageTable* page_table, VAddr process_address, size_t size,
+ u64 device_address, u32 option) {
+ R_RETURN(this->Map(page_table, process_address, size, device_address, option, false));
+ }
+
+ Result MapAligned(KPageTable* page_table, VAddr process_address, size_t size,
+ u64 device_address, u32 option) {
+ R_RETURN(this->Map(page_table, process_address, size, device_address, option, true));
+ }
+
+ Result Unmap(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address);
+
+ static void Initialize();
+
+private:
+ Result Map(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address,
+ u32 option, bool is_aligned);
+
+private:
+ KLightLock m_lock;
+ // KDevicePageTable m_table;
+ u64 m_space_address{};
+ u64 m_space_size{};
+ bool m_is_initialized{};
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h
index cb2512b0b..645c5b531 100644
--- a/src/core/hle/kernel/k_priority_queue.h
+++ b/src/core/hle/kernel/k_priority_queue.h
@@ -17,35 +17,41 @@ namespace Kernel {
class KThread;
template <typename T>
-concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
- { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
- {t.SetAffinityMask(0)};
+concept KPriorityQueueAffinityMask = !
+std::is_reference_v<T>&& requires(T& t) {
+ { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
+ { t.SetAffinityMask(0) };
- { t.GetAffinity(0) } -> std::same_as<bool>;
- {t.SetAffinity(0, false)};
- {t.SetAll()};
-};
+ { t.GetAffinity(0) } -> std::same_as<bool>;
+ { t.SetAffinity(0, false) };
+ { t.SetAll() };
+ };
template <typename T>
-concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
- {typename T::QueueEntry()};
- {(typename T::QueueEntry()).Initialize()};
- {(typename T::QueueEntry()).SetPrev(std::addressof(t))};
- {(typename T::QueueEntry()).SetNext(std::addressof(t))};
- { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
- { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
- { t.GetPriorityQueueEntry(0) } -> std::same_as<typename T::QueueEntry&>;
-
- {t.GetAffinityMask()};
- { std::remove_cvref_t<decltype(t.GetAffinityMask())>() } -> KPriorityQueueAffinityMask;
-
- { t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
- { t.GetPriority() } -> Common::ConvertibleTo<s32>;
- { t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
-};
+concept KPriorityQueueMember = !
+std::is_reference_v<T>&& requires(T& t) {
+ { typename T::QueueEntry() };
+ { (typename T::QueueEntry()).Initialize() };
+ { (typename T::QueueEntry()).SetPrev(std::addressof(t)) };
+ { (typename T::QueueEntry()).SetNext(std::addressof(t)) };
+ { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
+ { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
+ {
+ t.GetPriorityQueueEntry(0)
+ } -> std::same_as<typename T::QueueEntry&>;
+
+ { t.GetAffinityMask() };
+ {
+ std::remove_cvref_t<decltype(t.GetAffinityMask())>()
+ } -> KPriorityQueueAffinityMask;
+
+ { t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
+ { t.GetPriority() } -> Common::ConvertibleTo<s32>;
+ { t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
+ };
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
-requires KPriorityQueueMember<Member>
+ requires KPriorityQueueMember<Member>
class KPriorityQueue {
public:
using AffinityMaskType = std::remove_cv_t<
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h
index 857e21156..59b3e32ae 100644
--- a/src/core/hle/kernel/k_scoped_lock.h
+++ b/src/core/hle/kernel/k_scoped_lock.h
@@ -9,13 +9,14 @@
namespace Kernel {
template <typename T>
-concept KLockable = !std::is_reference_v<T> && requires(T & t) {
- { t.Lock() } -> std::same_as<void>;
- { t.Unlock() } -> std::same_as<void>;
-};
+concept KLockable = !
+std::is_reference_v<T>&& requires(T& t) {
+ { t.Lock() } -> std::same_as<void>;
+ { t.Unlock() } -> std::same_as<void>;
+ };
template <typename T>
-requires KLockable<T>
+ requires KLockable<T>
class [[nodiscard]] KScopedLock {
public:
explicit KScopedLock(T* l) : lock_ptr(l) {
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 9d771de0e..8b8dc51be 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -677,7 +677,7 @@ private:
union SyncObjectBuffer {
std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{};
std::array<Handle,
- Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))>
+ Svc::ArgumentHandleCountMax * (sizeof(KSynchronizationObject*) / sizeof(Handle))>
handles;
constexpr SyncObjectBuffer() {}
};
@@ -698,10 +698,8 @@ private:
};
template <typename T>
- requires(
- std::same_as<T, KThread> ||
- std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
- const KThread& rhs) {
+ requires(std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
+ static constexpr int Compare(const T& lhs, const KThread& rhs) {
const u64 l_key = lhs.GetConditionVariableKey();
const u64 r_key = rhs.GetConditionVariableKey();
diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h
index fe0cff084..71254eb55 100644
--- a/src/core/hle/kernel/k_thread_local_page.h
+++ b/src/core/hle/kernel/k_thread_local_page.h
@@ -70,10 +70,8 @@ public:
}
template <typename T>
- requires(std::same_as<T, KThreadLocalPage> ||
- std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
- const KThreadLocalPage&
- rhs) {
+ requires(std::same_as<T, KThreadLocalPage> || std::same_as<T, RedBlackKeyType>)
+ static constexpr int Compare(const T& lhs, const KThreadLocalPage& rhs) {
const VAddr lval = GetRedBlackKey(lhs);
const VAddr rval = GetRedBlackKey(rhs);
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 8d22f8d2c..5f52e1e95 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -35,6 +35,7 @@ class GlobalSchedulerContext;
class KAutoObjectWithListContainer;
class KClientSession;
class KDebug;
+class KDeviceAddressSpace;
class KDynamicPageManager;
class KEvent;
class KEventInfo;
@@ -359,6 +360,8 @@ public:
return slab_heap_container->transfer_memory;
} else if constexpr (std::is_same_v<T, KCodeMemory>) {
return slab_heap_container->code_memory;
+ } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) {
+ return slab_heap_container->device_address_space;
} else if constexpr (std::is_same_v<T, KPageBuffer>) {
return slab_heap_container->page_buffer;
} else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
@@ -431,6 +434,7 @@ private:
KSlabHeap<KThread> thread;
KSlabHeap<KTransferMemory> transfer_memory;
KSlabHeap<KCodeMemory> code_memory;
+ KSlabHeap<KDeviceAddressSpace> device_address_space;
KSlabHeap<KPageBuffer> page_buffer;
KSlabHeap<KThreadLocalPage> thread_local_page;
KSlabHeap<KSessionRequest> session_request;
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 33eebcef6..e90c35601 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -3,6 +3,9 @@
#pragma once
+#include <bitset>
+
+#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -496,6 +499,19 @@ enum class MemoryMapping : u32 {
Memory = 2,
};
+enum class MapDeviceAddressSpaceFlag : u32 {
+ None = (0U << 0),
+ NotIoRegister = (1U << 0),
+};
+DECLARE_ENUM_FLAG_OPERATORS(MapDeviceAddressSpaceFlag);
+
+union MapDeviceAddressSpaceOption {
+ u32 raw;
+ BitField<0, 16, MemoryPermission> permission;
+ BitField<16, 1, MapDeviceAddressSpaceFlag> flags;
+ BitField<17, 15, u32> reserved;
+};
+
enum class KernelDebugType : u32 {
Thread = 0,
ThreadCallStack = 1,
@@ -592,4 +608,7 @@ struct CreateProcessParameter {
};
static_assert(sizeof(CreateProcessParameter) == 0x30);
+constexpr size_t NumSupervisorCalls = 0xC0;
+using SvcAccessFlagSet = std::bitset<NumSupervisorCalls>;
+
} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc_version.h b/src/core/hle/kernel/svc_version.h
new file mode 100644
index 000000000..e4f47b34b
--- /dev/null
+++ b/src/core/hle/kernel/svc_version.h
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/literals.h"
+
+namespace Kernel::Svc {
+
+constexpr inline u32 ConvertToSvcMajorVersion(u32 sdk) {
+ return sdk + 4;
+}
+constexpr inline u32 ConvertToSdkMajorVersion(u32 svc) {
+ return svc - 4;
+}
+
+constexpr inline u32 ConvertToSvcMinorVersion(u32 sdk) {
+ return sdk;
+}
+constexpr inline u32 ConvertToSdkMinorVersion(u32 svc) {
+ return svc;
+}
+
+union KernelVersion {
+ u32 value;
+ BitField<0, 4, u32> minor_version;
+ BitField<4, 13, u32> major_version;
+};
+
+constexpr inline u32 EncodeKernelVersion(u32 major, u32 minor) {
+ return decltype(KernelVersion::minor_version)::FormatValue(minor) |
+ decltype(KernelVersion::major_version)::FormatValue(major);
+}
+
+constexpr inline u32 GetKernelMajorVersion(u32 encoded) {
+ return std::bit_cast<decltype(KernelVersion::major_version)>(encoded).Value();
+}
+
+constexpr inline u32 GetKernelMinorVersion(u32 encoded) {
+ return std::bit_cast<decltype(KernelVersion::minor_version)>(encoded).Value();
+}
+
+// Nintendo doesn't support programs targeting SVC versions < 3.0.
+constexpr inline u32 RequiredKernelMajorVersion = 3;
+constexpr inline u32 RequiredKernelMinorVersion = 0;
+constexpr inline u32 RequiredKernelVersion =
+ EncodeKernelVersion(RequiredKernelMajorVersion, RequiredKernelMinorVersion);
+
+// This is the highest SVC version supported, to be updated on new kernel releases.
+// NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor.
+constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(15);
+constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion(3);
+constexpr inline u32 SupportedKernelVersion =
+ EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 22999c942..ebcf6e164 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1124,7 +1124,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 offset{rp.Pop<u64>()};
- const std::vector<u8> data{ctx.ReadBuffer()};
+ const auto data{ctx.ReadBuffer()};
const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 3a1c231b6..0ee28752c 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -112,7 +112,7 @@ private:
void RequestUpdate(Kernel::HLERequestContext& ctx) {
LOG_TRACE(Service_Audio, "called");
- std::vector<u8> input{ctx.ReadBuffer(0)};
+ const auto input{ctx.ReadBuffer(0)};
// These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
// checking size 0. Performance size is 0 for most games.
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 825fb8bcc..e01f87356 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -93,7 +93,7 @@ private:
ctx.WriteBuffer(samples);
}
- bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input,
+ bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input,
std::vector<opus_int16>& output, u64* out_performance_time) const {
const auto start_time = std::chrono::steady_clock::now();
const std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index d183e5829..fb8686859 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -122,7 +122,7 @@ private:
void ImportTicket(Kernel::HLERequestContext& ctx) {
const auto ticket = ctx.ReadBuffer();
- const auto cert = ctx.ReadBuffer(1);
+ [[maybe_unused]] const auto cert = ctx.ReadBuffer(1);
if (ticket.size() < sizeof(Core::Crypto::Ticket)) {
LOG_ERROR(Service_ETicket, "The input buffer is not large enough!");
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index fbb16a7da..447d624e1 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -190,7 +190,7 @@ private:
return;
}
- const std::vector<u8> data = ctx.ReadBuffer();
+ const auto data = ctx.ReadBuffer();
ASSERT_MSG(
static_cast<s64>(data.size()) <= length,
@@ -401,11 +401,8 @@ public:
}
void RenameFile(Kernel::HLERequestContext& ctx) {
- std::vector<u8> buffer = ctx.ReadBuffer(0);
- const std::string src_name = Common::StringFromBuffer(buffer);
-
- buffer = ctx.ReadBuffer(1);
- const std::string dst_name = Common::StringFromBuffer(buffer);
+ const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
+ const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
@@ -1086,7 +1083,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
}
void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
- const auto raw = ctx.ReadBuffer();
+ const auto raw = ctx.ReadBufferCopy();
auto log = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(raw.data()), raw.size());
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index 49b6d45fe..ce21b69e3 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -228,7 +228,8 @@ private:
return;
}
- control = ctx.ReadBuffer();
+ // TODO: Can this be a span?
+ control = ctx.ReadBufferCopy();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 5713f1288..513ea485a 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -428,6 +428,9 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
return;
}
+ // This function is unique to yuzu for the turbo buttons to work properly
+ controller.device->TurboButtonUpdate();
+
auto& pad_entry = controller.npad_pad_state;
auto& trigger_entry = controller.npad_trigger_state;
const auto button_state = controller.device->GetNpadButtons();
@@ -755,11 +758,12 @@ Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
return hid_core.GetSupportedStyleTag();
}
-void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
+void Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) {
+ const auto length = data.size();
ASSERT(length > 0 && (length % sizeof(u32)) == 0);
supported_npad_id_types.clear();
supported_npad_id_types.resize(length / sizeof(u32));
- std::memcpy(supported_npad_id_types.data(), data, length);
+ std::memcpy(supported_npad_id_types.data(), data.data(), length);
}
void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 1a589cca2..1f7d33459 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -6,6 +6,7 @@
#include <array>
#include <atomic>
#include <mutex>
+#include <span>
#include "common/bit_field.h"
#include "common/common_types.h"
@@ -95,7 +96,7 @@ public:
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
- void SetSupportedNpadIdTypes(u8* data, std::size_t length);
+ void SetSupportedNpadIdTypes(std::span<const u8> data);
void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
std::size_t GetSupportedNpadIdTypesSize() const;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index bf28440c6..f15f1a6bb 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1026,7 +1026,7 @@ void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
const auto applet_resource_user_id{rp.Pop<u64>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
+ .SetSupportedNpadIdTypes(ctx.ReadBuffer());
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
@@ -2104,7 +2104,7 @@ void Hid::WritePalmaRgbLedPatternEntry(Kernel::HLERequestContext& ctx) {
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto unknown{rp.Pop<u64>()};
- const auto buffer = ctx.ReadBuffer();
+ [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
connection_handle.npad_id, unknown);
diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.h b/src/core/hle/service/hid/hidbus/hidbus_base.h
index d3960f506..65e301137 100644
--- a/src/core/hle/service/hid/hidbus/hidbus_base.h
+++ b/src/core/hle/service/hid/hidbus/hidbus_base.h
@@ -4,6 +4,7 @@
#pragma once
#include <array>
+#include <span>
#include "common/common_types.h"
#include "core/hle/result.h"
@@ -150,7 +151,7 @@ public:
}
// Assigns a command from data
- virtual bool SetCommand(const std::vector<u8>& data) {
+ virtual bool SetCommand(std::span<const u8> data) {
return {};
}
diff --git a/src/core/hle/service/hid/hidbus/ringcon.cpp b/src/core/hle/service/hid/hidbus/ringcon.cpp
index 78ed47014..35847cbdd 100644
--- a/src/core/hle/service/hid/hidbus/ringcon.cpp
+++ b/src/core/hle/service/hid/hidbus/ringcon.cpp
@@ -116,7 +116,7 @@ std::vector<u8> RingController::GetReply() const {
}
}
-bool RingController::SetCommand(const std::vector<u8>& data) {
+bool RingController::SetCommand(std::span<const u8> data) {
if (data.size() < 4) {
LOG_ERROR(Service_HID, "Command size not supported {}", data.size());
command = RingConCommands::Error;
diff --git a/src/core/hle/service/hid/hidbus/ringcon.h b/src/core/hle/service/hid/hidbus/ringcon.h
index 845ce85a5..c2fb386b1 100644
--- a/src/core/hle/service/hid/hidbus/ringcon.h
+++ b/src/core/hle/service/hid/hidbus/ringcon.h
@@ -4,6 +4,7 @@
#pragma once
#include <array>
+#include <span>
#include "common/common_types.h"
#include "core/hle/service/hid/hidbus/hidbus_base.h"
@@ -31,7 +32,7 @@ public:
u8 GetDeviceId() const override;
// Assigns a command from data
- bool SetCommand(const std::vector<u8>& data) override;
+ bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command
std::vector<u8> GetReply() const override;
diff --git a/src/core/hle/service/hid/hidbus/starlink.cpp b/src/core/hle/service/hid/hidbus/starlink.cpp
index dd439f60a..d0e760314 100644
--- a/src/core/hle/service/hid/hidbus/starlink.cpp
+++ b/src/core/hle/service/hid/hidbus/starlink.cpp
@@ -42,7 +42,7 @@ std::vector<u8> Starlink::GetReply() const {
return {};
}
-bool Starlink::SetCommand(const std::vector<u8>& data) {
+bool Starlink::SetCommand(std::span<const u8> data) {
LOG_ERROR(Service_HID, "Command not implemented");
return false;
}
diff --git a/src/core/hle/service/hid/hidbus/starlink.h b/src/core/hle/service/hid/hidbus/starlink.h
index 0b1b7ba49..07c800e6e 100644
--- a/src/core/hle/service/hid/hidbus/starlink.h
+++ b/src/core/hle/service/hid/hidbus/starlink.h
@@ -29,7 +29,7 @@ public:
u8 GetDeviceId() const override;
// Assigns a command from data
- bool SetCommand(const std::vector<u8>& data) override;
+ bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command
std::vector<u8> GetReply() const override;
diff --git a/src/core/hle/service/hid/hidbus/stubbed.cpp b/src/core/hle/service/hid/hidbus/stubbed.cpp
index e477443e3..07632c872 100644
--- a/src/core/hle/service/hid/hidbus/stubbed.cpp
+++ b/src/core/hle/service/hid/hidbus/stubbed.cpp
@@ -43,7 +43,7 @@ std::vector<u8> HidbusStubbed::GetReply() const {
return {};
}
-bool HidbusStubbed::SetCommand(const std::vector<u8>& data) {
+bool HidbusStubbed::SetCommand(std::span<const u8> data) {
LOG_ERROR(Service_HID, "Command not implemented");
return false;
}
diff --git a/src/core/hle/service/hid/hidbus/stubbed.h b/src/core/hle/service/hid/hidbus/stubbed.h
index 91165ceff..38eaa0ecc 100644
--- a/src/core/hle/service/hid/hidbus/stubbed.h
+++ b/src/core/hle/service/hid/hidbus/stubbed.h
@@ -29,7 +29,7 @@ public:
u8 GetDeviceId() const override;
// Assigns a command from data
- bool SetCommand(const std::vector<u8>& data) override;
+ bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command
std::vector<u8> GetReply() const override;
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index 8f2920c51..1295a44c7 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -62,7 +62,7 @@ public:
const auto parameters{rp.PopRaw<InputParameters>()};
// Optional input/output buffers
- std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()};
+ const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()};
std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0);
// Function call prototype:
@@ -132,7 +132,7 @@ public:
const auto command{rp.PopRaw<u64>()};
// Optional input/output buffers
- std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()};
+ const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()};
std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0);
// Function call prototype:
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index c49c61cff..e5099d61f 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -412,7 +412,7 @@ public:
}
void SetAdvertiseData(Kernel::HLERequestContext& ctx) {
- std::vector<u8> read_buffer = ctx.ReadBuffer();
+ const auto read_buffer = ctx.ReadBuffer();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.SetAdvertiseData(read_buffer));
@@ -464,7 +464,7 @@ public:
parameters.security_config.passphrase_size,
parameters.security_config.security_mode, parameters.local_communication_version);
- const std::vector<u8> read_buffer = ctx.ReadBuffer();
+ const auto read_buffer = ctx.ReadBuffer();
if (read_buffer.size() != sizeof(NetworkInfo)) {
LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 204b0e757..c562e04d2 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -3,7 +3,9 @@
#pragma once
+#include <span>
#include <vector>
+
#include "common/common_types.h"
#include "core/hle/service/nvdrv/nvdata.h"
@@ -31,7 +33,7 @@ public:
* @param output A buffer where the output data will be written to.
* @returns The result code of the ioctl.
*/
- virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) = 0;
/**
@@ -42,8 +44,8 @@ public:
* @param output A buffer where the output data will be written to.
* @returns The result code of the ioctl.
*/
- virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
+ virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) = 0;
/**
* Handles an ioctl3 request.
@@ -53,7 +55,7 @@ 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) = 0;
/**
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 4122fc98d..5a5b2e305 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -17,19 +17,19 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
: nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
nvdisp_disp0::~nvdisp_disp0() = default;
-NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 04217ab12..81bd7960a 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -25,12 +25,12 @@ public:
explicit nvdisp_disp0(Core::System& system_, NvCore::Container& core);
~nvdisp_disp0() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index b635e6ed1..681bd0867 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -27,7 +27,7 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Con
nvhost_as_gpu::~nvhost_as_gpu() = default;
-NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
switch (command.group) {
case 'A':
@@ -60,13 +60,13 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>
return NvResult::NotImplemented;
}
-NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
switch (command.group) {
case 'A':
@@ -87,7 +87,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>
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) {
+NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::vector<u8>& output) {
IoctlAllocAsEx params{};
std::memcpy(&params, input.data(), input.size());
@@ -141,7 +141,7 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>&
return NvResult::Success;
}
-NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::vector<u8>& output) {
IoctlAllocSpace params{};
std::memcpy(&params, input.data(), input.size());
@@ -220,7 +220,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
mapping_map.erase(offset);
}
-NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::vector<u8>& output) {
IoctlFreeSpace params{};
std::memcpy(&params, input.data(), input.size());
@@ -266,7 +266,7 @@ NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>&
return NvResult::Success;
}
-NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::vector<u8>& output) {
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
@@ -320,7 +320,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& out
return NvResult::Success;
}
-NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::vector<u8>& output) {
IoctlMapBufferEx params{};
std::memcpy(&params, input.data(), input.size());
@@ -424,7 +424,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8
return NvResult::Success;
}
-NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) {
IoctlUnmapBuffer params{};
std::memcpy(&params, input.data(), input.size());
@@ -463,7 +463,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8
return NvResult::Success;
}
-NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::vector<u8>& output) {
IoctlBindChannel params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
@@ -492,7 +492,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
};
}
-NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output) {
IoctlGetVaRegions params{};
std::memcpy(&params, input.data(), input.size());
@@ -511,7 +511,7 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
return NvResult::Success;
}
-NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
+NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
IoctlGetVaRegions params{};
std::memcpy(&params, input.data(), input.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 86fe71c75..1aba8d579 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -47,12 +47,12 @@ public:
explicit nvhost_as_gpu(Core::System& system_, Module& module, NvCore::Container& core);
~nvhost_as_gpu() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -138,17 +138,17 @@ private:
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2,
"IoctlGetVaRegions is incorrect size");
- 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);
- NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult AllocAsEx(std::span<const u8> input, std::vector<u8>& output);
+ NvResult AllocateSpace(std::span<const u8> input, std::vector<u8>& output);
+ NvResult Remap(std::span<const u8> input, std::vector<u8>& output);
+ NvResult MapBufferEx(std::span<const u8> input, std::vector<u8>& output);
+ NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output);
+ NvResult FreeSpace(std::span<const u8> input, std::vector<u8>& output);
+ NvResult BindChannel(std::span<const u8> input, std::vector<u8>& output);
void GetVARegionsImpl(IoctlGetVaRegions& params);
- NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
+ NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output);
+ NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output,
std::vector<u8>& inline_output);
void FreeMappingLocked(u64 offset);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index eee11fab8..0cdde82a7 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -34,7 +34,7 @@ nvhost_ctrl::~nvhost_ctrl() {
}
}
-NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
switch (command.group) {
case 0x0:
@@ -63,13 +63,13 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
return NvResult::NotImplemented;
}
-NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_outpu) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
@@ -79,7 +79,7 @@ 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) {
+NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output) {
IocGetConfigParams params{};
std::memcpy(&params, input.data(), sizeof(params));
LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
@@ -87,7 +87,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector
return NvResult::ConfigVarNotFound; // Returns error on production mode
}
-NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
+NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output,
bool is_allocation) {
IocCtrlEventWaitParams params{};
std::memcpy(&params, input.data(), sizeof(params));
@@ -231,7 +231,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {
return NvResult::Success;
}
-NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output) {
IocCtrlEventRegisterParams params{};
std::memcpy(&params, input.data(), sizeof(params));
const u32 event_id = params.user_event_id;
@@ -252,8 +252,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve
return NvResult::Success;
}
-NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output) {
IocCtrlEventUnregisterParams params{};
std::memcpy(&params, input.data(), sizeof(params));
const u32 event_id = params.user_event_id & 0x00FF;
@@ -263,7 +262,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
return FreeEvent(event_id);
}
-NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector<u8>& input,
+NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input,
std::vector<u8>& output) {
IocCtrlEventUnregisterBatchParams params{};
std::memcpy(&params, input.data(), sizeof(params));
@@ -282,7 +281,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector<u8>& input,
return NvResult::Success;
}
-NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output) {
IocCtrlEventClearParams params{};
std::memcpy(&params, input.data(), sizeof(params));
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 0b56d7070..dd2e7888a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -25,12 +25,12 @@ public:
NvCore::Container& core);
~nvhost_ctrl() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -186,13 +186,13 @@ private:
static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8,
"IocCtrlEventKill is incorrect size");
- NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
+ NvResult NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output,
bool is_allocation);
- NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocCtrlEventUnregisterBatch(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output);
NvResult FreeEvent(u32 slot);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index b97813fbc..be3c083db 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -21,7 +21,7 @@ nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
events_interface.FreeEvent(unknown_event);
}
-NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
switch (command.group) {
case 'G':
@@ -53,13 +53,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u
return NvResult::NotImplemented;
}
-NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
switch (command.group) {
case 'G':
@@ -82,8 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u
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) {
+NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlCharacteristics params{};
std::memcpy(&params, input.data(), input.size());
@@ -128,7 +127,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
+NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlCharacteristics params{};
@@ -176,7 +175,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output) {
IoctlGpuGetTpcMasksArgs params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
@@ -187,7 +186,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
+NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output,
std::vector<u8>& inline_output) {
IoctlGpuGetTpcMasksArgs params{};
std::memcpy(&params, input.data(), input.size());
@@ -200,7 +199,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlActiveSlotMask params{};
@@ -213,7 +212,7 @@ NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::v
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlZcullGetCtxSize params{};
@@ -225,7 +224,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vec
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlNvgpuGpuZcullGetInfoArgs params{};
@@ -248,7 +247,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IoctlZbcSetTable params{};
@@ -264,7 +263,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IoctlZbcQueryTable params{};
@@ -274,7 +273,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vecto
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IoctlFlushL2 params{};
@@ -284,7 +283,7 @@ NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>&
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlGetGpuTime params{};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index 1e8f254e2..b9333d9d3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -21,12 +21,12 @@ public:
explicit nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_);
~nvhost_ctrl_gpu() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -151,21 +151,21 @@ private:
};
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
- NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
+ NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output);
+ NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output,
std::vector<u8>& inline_output);
- NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
+ NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output);
+ NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output,
std::vector<u8>& inline_output);
- NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output);
+ NvResult ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output);
+ NvResult ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output);
+ NvResult ZBCSetTable(std::span<const u8> input, std::vector<u8>& output);
+ NvResult ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output);
+ NvResult FlushL2(std::span<const u8> input, std::vector<u8>& output);
+ NvResult GetGpuTime(std::span<const u8> input, std::vector<u8>& output);
EventInterface& events_interface;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index e123564c6..d2308fffc 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -46,7 +46,7 @@ nvhost_gpu::~nvhost_gpu() {
syncpoint_manager.FreeSyncpoint(channel_syncpoint);
}
-NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
switch (command.group) {
case 0x0:
@@ -98,8 +98,8 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i
return NvResult::NotImplemented;
};
-NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
switch (command.group) {
case 'H':
switch (command.cmd) {
@@ -112,7 +112,7 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& i
return NvResult::NotImplemented;
}
-NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
@@ -121,7 +121,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& i
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) {
+NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
@@ -130,7 +130,7 @@ NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& o
return NvResult::Success;
}
-NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlClientData params{};
@@ -139,7 +139,7 @@ NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>
return NvResult::Success;
}
-NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlClientData params{};
@@ -149,7 +149,7 @@ NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>
return NvResult::Success;
}
-NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::vector<u8>& output) {
std::memcpy(&zcull_params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
zcull_params.mode);
@@ -158,7 +158,7 @@ NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& ou
return NvResult::Success;
}
-NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output) {
IoctlSetErrorNotifier params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
@@ -168,14 +168,14 @@ NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<
return NvResult::Success;
}
-NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::vector<u8>& output) {
std::memcpy(&channel_priority, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
return NvResult::Success;
}
-NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output) {
IoctlAllocGpfifoEx2 params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV,
@@ -197,7 +197,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8
return NvResult::Success;
}
-NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output) {
IoctlAllocObjCtx params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
@@ -293,7 +293,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>
return NvResult::Success;
}
-NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
+NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output,
bool kickoff) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
@@ -314,8 +314,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<
return SubmitGPFIFOImpl(params, output, std::move(entries));
}
-NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
- const std::vector<u8>& input_inline,
+NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
std::vector<u8>& output) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
@@ -328,7 +327,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
return SubmitGPFIFOImpl(params, output, std::move(entries));
}
-NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) {
IoctlGetWaitbase params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
@@ -338,7 +337,7 @@ NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>&
return NvResult::Success;
}
-NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output) {
IoctlChannelSetTimeout params{};
std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
@@ -346,7 +345,7 @@ NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector
return NvResult::Success;
}
-NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output) {
IoctlSetTimeslice params{};
std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice));
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 1e4ecd55b..3ca58202d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -40,12 +40,12 @@ public:
NvCore::Container& core);
~nvhost_gpu() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -186,23 +186,23 @@ private:
u32_le channel_priority{};
u32_le channel_timeslice{};
- NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output);
+ NvResult SetClientData(std::span<const u8> input, std::vector<u8>& output);
+ NvResult GetClientData(std::span<const u8> input, std::vector<u8>& output);
+ NvResult ZCullBind(std::span<const u8> input, std::vector<u8>& output);
+ NvResult SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output);
+ NvResult SetChannelPriority(std::span<const u8> input, std::vector<u8>& output);
+ NvResult AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output);
+ NvResult AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output);
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
Tegra::CommandList&& entries);
- NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
+ NvResult SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output,
bool kickoff = false);
- NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline,
+ NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
std::vector<u8>& output);
- NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output);
+ NvResult ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output);
+ NvResult ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output);
EventInterface& events_interface;
NvCore::Container& core;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 1703f9cc3..0c7aee1b8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -15,7 +15,7 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_)
: nvhost_nvdec_common{system_, core_, NvCore::ChannelType::NvDec} {}
nvhost_nvdec::~nvhost_nvdec() = default;
-NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
switch (command.group) {
case 0x0:
@@ -55,13 +55,13 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
return NvResult::NotImplemented;
}
-NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index c1b4e53e8..0d615bbcb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -13,12 +13,12 @@ public:
explicit nvhost_nvdec(Core::System& system_, NvCore::Container& core);
~nvhost_nvdec() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 99eede702..7bcef105b 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -23,7 +23,7 @@ namespace {
// Copies count amount of type T from the input vector into the dst vector.
// Returns the number of bytes written into dst.
template <typename T>
-std::size_t SliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
+std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::size_t count,
std::size_t offset) {
if (dst.empty()) {
return 0;
@@ -63,7 +63,7 @@ nvhost_nvdec_common::~nvhost_nvdec_common() {
core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint);
}
-NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
+NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
@@ -72,7 +72,7 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input,
+NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input,
std::vector<u8>& output) {
IoctlSubmit params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
@@ -121,7 +121,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input,
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::vector<u8>& output) {
IoctlGetSyncpoint params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
@@ -133,7 +133,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::ve
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) {
IoctlGetWaitbase params{};
LOG_CRITICAL(Service_NVDRV, "called WAITBASE");
std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
@@ -142,7 +142,7 @@ NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vec
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::vector<u8>& output) {
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
@@ -159,7 +159,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) {
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
@@ -173,8 +173,7 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output) {
std::memcpy(&submit_timeout, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
return NvResult::Success;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index fe76100c8..5af26a26f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -107,13 +107,13 @@ protected:
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
/// Ioctl command implementations
- NvResult SetNVMAPfd(const std::vector<u8>& input);
- NvResult Submit(DeviceFD fd, const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult SetNVMAPfd(std::span<const u8> input);
+ NvResult Submit(DeviceFD fd, std::span<const u8> input, std::vector<u8>& output);
+ NvResult GetSyncpoint(std::span<const u8> input, std::vector<u8>& output);
+ NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output);
+ NvResult MapBuffer(std::span<const u8> input, std::vector<u8>& output);
+ NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output);
+ NvResult SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output);
Kernel::KEvent* QueryEvent(u32 event_id) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index bdbc2f9e1..39f30e7c8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -12,7 +12,7 @@ namespace Service::Nvidia::Devices {
nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {}
nvhost_nvjpg::~nvhost_nvjpg() = default;
-NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
switch (command.group) {
case 'H':
@@ -31,13 +31,13 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
return NvResult::NotImplemented;
}
-NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
@@ -46,7 +46,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>&
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) {
+NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 440e7d371..41b57e872 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -15,12 +15,12 @@ public:
explicit nvhost_nvjpg(Core::System& system_);
~nvhost_nvjpg() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -33,7 +33,7 @@ private:
s32_le nvmap_fd{};
- NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 73f97136e..b0ea402a7 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -15,7 +15,7 @@ nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_)
nvhost_vic::~nvhost_vic() = default;
-NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
switch (command.group) {
case 0x0:
@@ -55,13 +55,13 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i
return NvResult::NotImplemented;
}
-NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index f164caafb..b5e350a83 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -12,12 +12,12 @@ public:
explicit nvhost_vic(Core::System& system_, NvCore::Container& core);
~nvhost_vic();
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index fa29db758..29c1e0f01 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -25,7 +25,7 @@ nvmap::nvmap(Core::System& system_, NvCore::Container& container_)
nvmap::~nvmap() = default;
-NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
switch (command.group) {
case 0x1:
@@ -54,13 +54,13 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
return NvResult::NotImplemented;
}
-NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
@@ -69,7 +69,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
void nvmap::OnOpen(DeviceFD fd) {}
void nvmap::OnClose(DeviceFD fd) {}
-NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocCreate(std::span<const u8> input, std::vector<u8>& output) {
IocCreateParams params;
std::memcpy(&params, input.data(), sizeof(params));
LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
@@ -89,7 +89,7 @@ NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output)
return NvResult::Success;
}
-NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocAlloc(std::span<const u8> input, std::vector<u8>& output) {
IocAllocParams params;
std::memcpy(&params, input.data(), sizeof(params));
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
@@ -137,7 +137,7 @@ NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output)
return result;
}
-NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocGetId(std::span<const u8> input, std::vector<u8>& output) {
IocGetIdParams params;
std::memcpy(&params, input.data(), sizeof(params));
@@ -161,7 +161,7 @@ NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output)
return NvResult::Success;
}
-NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocFromId(std::span<const u8> input, std::vector<u8>& output) {
IocFromIdParams params;
std::memcpy(&params, input.data(), sizeof(params));
@@ -192,7 +192,7 @@ NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output)
return NvResult::Success;
}
-NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocParam(std::span<const u8> input, std::vector<u8>& output) {
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
IocParamParams params;
@@ -241,7 +241,7 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output)
return NvResult::Success;
}
-NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocFree(std::span<const u8> input, std::vector<u8>& output) {
IocFreeParams params;
std::memcpy(&params, input.data(), sizeof(params));
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index e9bfd0358..82bd3b118 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -26,12 +26,12 @@ public:
nvmap(const nvmap&) = delete;
nvmap& operator=(const nvmap&) = delete;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const 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(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -106,12 +106,12 @@ private:
};
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
- NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult IocCreate(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocAlloc(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocGetId(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocFromId(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocParam(std::span<const u8> input, std::vector<u8>& output);
+ NvResult IocFree(std::span<const u8> input, std::vector<u8>& output);
NvCore::Container& container;
NvCore::NvMap& file;
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 6fc8565c0..52d27e755 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -124,7 +124,7 @@ DeviceFD Module::Open(const std::string& device_name) {
return fd;
}
-NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output) {
if (fd < 0) {
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
@@ -141,8 +141,8 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input
return itr->second->Ioctl1(fd, command, input, output);
}
-NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output) {
if (fd < 0) {
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
return NvResult::InvalidState;
@@ -158,7 +158,7 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input
return itr->second->Ioctl2(fd, command, input, inline_input, output);
}
-NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::vector<u8>& output, std::vector<u8>& inline_output) {
if (fd < 0) {
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index f3c81bd88..b09b6e585 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -7,6 +7,7 @@
#include <functional>
#include <list>
#include <memory>
+#include <span>
#include <string>
#include <unordered_map>
#include <vector>
@@ -79,14 +80,13 @@ public:
DeviceFD Open(const std::string& device_name);
/// Sends an ioctl command to the specified file descriptor.
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output);
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output);
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output);
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::vector<u8>& output);
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output);
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output,
+ std::vector<u8>& inline_output);
/// Closes a device file descriptor and returns operation success.
NvResult Close(DeviceFD fd);
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
index e601b5da1..bcbe05b0d 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -815,8 +815,8 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId code, u32 flags) {
Status status{Status::NoError};
- Parcel parcel_in{ctx.ReadBuffer()};
- Parcel parcel_out{};
+ InputParcel parcel_in{ctx.ReadBuffer()};
+ OutputParcel parcel_out{};
switch (code) {
case TransactionId::Connect: {
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
index 4043c91f1..769e8c0a3 100644
--- a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
@@ -9,7 +9,7 @@
namespace Service::android {
-QueueBufferInput::QueueBufferInput(Parcel& parcel) {
+QueueBufferInput::QueueBufferInput(InputParcel& parcel) {
parcel.ReadFlattened(*this);
}
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h
index 6ea327bbe..2969f0fd5 100644
--- a/src/core/hle/service/nvflinger/graphic_buffer_producer.h
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h
@@ -14,11 +14,11 @@
namespace Service::android {
-class Parcel;
+class InputParcel;
#pragma pack(push, 1)
struct QueueBufferInput final {
- explicit QueueBufferInput(Parcel& parcel);
+ explicit QueueBufferInput(InputParcel& parcel);
void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h
index f3fa2587d..d1b6201e0 100644
--- a/src/core/hle/service/nvflinger/parcel.h
+++ b/src/core/hle/service/nvflinger/parcel.h
@@ -4,6 +4,7 @@
#pragma once
#include <memory>
+#include <span>
#include <vector>
#include "common/alignment.h"
@@ -12,18 +13,17 @@
namespace Service::android {
-class Parcel final {
-public:
- static constexpr std::size_t DefaultBufferSize = 0x40;
-
- Parcel() : buffer(DefaultBufferSize) {}
-
- template <typename T>
- explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) {
- Write(out_data);
- }
+struct ParcelHeader {
+ u32 data_size;
+ u32 data_offset;
+ u32 objects_size;
+ u32 objects_offset;
+};
+static_assert(sizeof(ParcelHeader) == 16, "ParcelHeader has wrong size");
- explicit Parcel(std::vector<u8> in_data) : buffer(std::move(in_data)) {
+class InputParcel final {
+public:
+ explicit InputParcel(std::span<const u8> in_data) : read_buffer(std::move(in_data)) {
DeserializeHeader();
[[maybe_unused]] const std::u16string token = ReadInterfaceToken();
}
@@ -31,9 +31,9 @@ public:
template <typename T>
void Read(T& val) {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
- ASSERT(read_index + sizeof(T) <= buffer.size());
+ ASSERT(read_index + sizeof(T) <= read_buffer.size());
- std::memcpy(&val, buffer.data() + read_index, sizeof(T));
+ std::memcpy(&val, read_buffer.data() + read_index, sizeof(T));
read_index += sizeof(T);
read_index = Common::AlignUp(read_index, 4);
}
@@ -62,10 +62,10 @@ public:
template <typename T>
T ReadUnaligned() {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
- ASSERT(read_index + sizeof(T) <= buffer.size());
+ ASSERT(read_index + sizeof(T) <= read_buffer.size());
T val;
- std::memcpy(&val, buffer.data() + read_index, sizeof(T));
+ std::memcpy(&val, read_buffer.data() + read_index, sizeof(T));
read_index += sizeof(T);
return val;
}
@@ -101,6 +101,31 @@ public:
return token;
}
+ void DeserializeHeader() {
+ ASSERT(read_buffer.size() > sizeof(ParcelHeader));
+
+ ParcelHeader header{};
+ std::memcpy(&header, read_buffer.data(), sizeof(ParcelHeader));
+
+ read_index = header.data_offset;
+ }
+
+private:
+ std::span<const u8> read_buffer;
+ std::size_t read_index = 0;
+};
+
+class OutputParcel final {
+public:
+ static constexpr std::size_t DefaultBufferSize = 0x40;
+
+ OutputParcel() : buffer(DefaultBufferSize) {}
+
+ template <typename T>
+ explicit OutputParcel(const T& out_data) : buffer(DefaultBufferSize) {
+ Write(out_data);
+ }
+
template <typename T>
void Write(const T& val) {
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
@@ -133,40 +158,20 @@ public:
WriteObject(ptr.get());
}
- void DeserializeHeader() {
- ASSERT(buffer.size() > sizeof(Header));
-
- Header header{};
- std::memcpy(&header, buffer.data(), sizeof(Header));
-
- read_index = header.data_offset;
- }
-
std::vector<u8> Serialize() const {
- ASSERT(read_index == 0);
-
- Header header{};
- header.data_size = static_cast<u32>(write_index - sizeof(Header));
- header.data_offset = sizeof(Header);
+ ParcelHeader header{};
+ header.data_size = static_cast<u32>(write_index - sizeof(ParcelHeader));
+ header.data_offset = sizeof(ParcelHeader);
header.objects_size = 4;
- header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
- std::memcpy(buffer.data(), &header, sizeof(Header));
+ header.objects_offset = static_cast<u32>(sizeof(ParcelHeader) + header.data_size);
+ std::memcpy(buffer.data(), &header, sizeof(ParcelHeader));
return buffer;
}
private:
- struct Header {
- u32 data_size;
- u32 data_offset;
- u32 objects_size;
- u32 objects_offset;
- };
- static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
-
mutable std::vector<u8> buffer;
- std::size_t read_index = 0;
- std::size_t write_index = sizeof(Header);
+ std::size_t write_index = sizeof(ParcelHeader);
};
} // namespace Service::android
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 78f897d3e..01040b32a 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -63,7 +63,7 @@ private:
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
LOG_DEBUG(Service_PREPO,
@@ -90,7 +90,7 @@ private:
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
LOG_DEBUG(Service_PREPO,
@@ -142,7 +142,7 @@ private:
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}",
@@ -166,7 +166,7 @@ private:
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
LOG_DEBUG(Service_PREPO,
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 9e94a462f..bdb499268 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -208,7 +208,6 @@ void BSD::Bind(Kernel::HLERequestContext& ctx) {
const s32 fd = rp.Pop<s32>();
LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
-
BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
}
@@ -312,7 +311,7 @@ void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
const u32 level = rp.Pop<u32>();
const OptName optname = static_cast<OptName>(rp.Pop<u32>());
- const std::vector<u8> buffer = ctx.ReadBuffer();
+ const auto buffer = ctx.ReadBuffer();
const u8* optval = buffer.empty() ? nullptr : buffer.data();
size_t optlen = buffer.size();
@@ -489,7 +488,7 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
return {fd, Errno::SUCCESS};
}
-std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
+std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
s32 nfds, s32 timeout) {
if (write_buffer.size() < nfds * sizeof(PollFD)) {
return {-1, Errno::INVAL};
@@ -584,7 +583,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
return {new_fd, Errno::SUCCESS};
}
-Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
+Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -595,7 +594,7 @@ Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
}
-Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) {
+Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -800,15 +799,15 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
return {ret, bsd_errno};
}
-std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) {
+std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
}
return Translate(file_descriptors[fd]->socket->Send(message, flags));
}
-std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
- const std::vector<u8>& addr) {
+std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
+ std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
}
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 81e855e0f..56bb3f8b1 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -4,6 +4,7 @@
#pragma once
#include <memory>
+#include <span>
#include <vector>
#include "common/common_types.h"
@@ -44,7 +45,7 @@ private:
s32 nfds;
s32 timeout;
- std::vector<u8> read_buffer;
+ std::span<const u8> read_buffer;
std::vector<u8> write_buffer;
s32 ret{};
Errno bsd_errno{};
@@ -65,7 +66,7 @@ private:
void Response(Kernel::HLERequestContext& ctx);
s32 fd;
- std::vector<u8> addr;
+ std::span<const u8> addr;
Errno bsd_errno{};
};
@@ -98,7 +99,7 @@ private:
s32 fd;
u32 flags;
- std::vector<u8> message;
+ std::span<const u8> message;
s32 ret{};
Errno bsd_errno{};
};
@@ -109,8 +110,8 @@ private:
s32 fd;
u32 flags;
- std::vector<u8> message;
- std::vector<u8> addr;
+ std::span<const u8> message;
+ std::span<const u8> addr;
s32 ret{};
Errno bsd_errno{};
};
@@ -143,11 +144,11 @@ private:
void ExecuteWork(Kernel::HLERequestContext& ctx, Work work);
std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
- std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
+ std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
s32 nfds, s32 timeout);
std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
- Errno BindImpl(s32 fd, const std::vector<u8>& addr);
- Errno ConnectImpl(s32 fd, const std::vector<u8>& addr);
+ Errno BindImpl(s32 fd, std::span<const u8> addr);
+ Errno ConnectImpl(s32 fd, std::span<const u8> addr);
Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
Errno ListenImpl(s32 fd, s32 backlog);
@@ -157,9 +158,9 @@ private:
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
std::vector<u8>& addr);
- std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, const std::vector<u8>& message);
- std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
- const std::vector<u8>& addr);
+ std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
+ std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
+ std::span<const u8> addr);
Errno CloseImpl(s32 fd);
s32 FindFreeFileDescriptorHandle() noexcept;
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 097c37d7a..e96eda7f3 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -243,4 +243,4 @@ void SFDNSRES::GetAddrInfoRequestWithOptions(Kernel::HLERequestContext& ctx) {
rb.Push(0);
}
-} // namespace Service::Sockets \ No newline at end of file
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 3735e0452..dcf47083f 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -101,7 +101,7 @@ private:
void ImportServerPki(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto certificate_format = rp.PopEnum<CertificateFormat>();
- const auto pkcs_12_certificates = ctx.ReadBuffer(0);
+ [[maybe_unused]] const auto pkcs_12_certificates = ctx.ReadBuffer(0);
constexpr u64 server_id = 0;
@@ -113,13 +113,13 @@ private:
}
void ImportClientPki(Kernel::HLERequestContext& ctx) {
- const auto pkcs_12_certificate = ctx.ReadBuffer(0);
- const auto ascii_password = [&ctx] {
+ [[maybe_unused]] const auto pkcs_12_certificate = ctx.ReadBuffer(0);
+ [[maybe_unused]] const auto ascii_password = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
constexpr u64 client_id = 0;
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index bb283e74e..2fb631183 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -603,7 +603,7 @@ private:
return;
}
- const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
+ const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}};
const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
IPC::ResponseBuilder rb{ctx, 4};
@@ -649,7 +649,7 @@ private:
return;
}
- const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
+ const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}};
const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
IPC::ResponseBuilder rb{ctx, 6};
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index 282ea1ff9..7494fb62d 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -550,7 +550,7 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock
return {-1, GetAndLogLastError()};
}
-std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
+std::pair<s32, Errno> Socket::Send(std::span<const u8> message, int flags) {
ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
ASSERT(flags == 0);
@@ -563,7 +563,7 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
return {-1, GetAndLogLastError()};
}
-std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
+std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) {
ASSERT(flags == 0);
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
index 1e1c42cea..7a77171c2 100644
--- a/src/core/internal_network/socket_proxy.cpp
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -182,7 +182,7 @@ std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& mes
return {static_cast<u32>(read_bytes), Errno::SUCCESS};
}
-std::pair<s32, Errno> ProxySocket::Send(const std::vector<u8>& message, int flags) {
+std::pair<s32, Errno> ProxySocket::Send(std::span<const u8> message, int flags) {
LOG_WARNING(Network, "(STUBBED) called");
ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
ASSERT(flags == 0);
@@ -200,7 +200,7 @@ void ProxySocket::SendPacket(ProxyPacket& packet) {
}
}
-std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& message,
+std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) {
ASSERT(flags == 0);
diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h
index f12b5f567..9421492bc 100644
--- a/src/core/internal_network/socket_proxy.h
+++ b/src/core/internal_network/socket_proxy.h
@@ -4,6 +4,7 @@
#pragma once
#include <mutex>
+#include <span>
#include <vector>
#include <queue>
@@ -48,11 +49,11 @@ public:
std::pair<s32, Errno> ReceivePacket(int flags, std::vector<u8>& message, SockAddrIn* addr,
std::size_t max_length);
- std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override;
+ std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
void SendPacket(ProxyPacket& packet);
- std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
+ std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) override;
Errno SetLinger(bool enable, u32 linger) override;
diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h
index 2e328c645..4c7489258 100644
--- a/src/core/internal_network/sockets.h
+++ b/src/core/internal_network/sockets.h
@@ -5,6 +5,7 @@
#include <map>
#include <memory>
+#include <span>
#include <utility>
#if defined(_WIN32)
@@ -66,9 +67,9 @@ public:
virtual std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message,
SockAddrIn* addr) = 0;
- virtual std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) = 0;
+ virtual std::pair<s32, Errno> Send(std::span<const u8> message, int flags) = 0;
- virtual std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
+ virtual std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) = 0;
virtual Errno SetLinger(bool enable, u32 linger) = 0;
@@ -138,9 +139,9 @@ public:
std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override;
- std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override;
+ std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
- std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
+ std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) override;
Errno SetLinger(bool enable, u32 linger) override;
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 77821e047..59dfb8767 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -312,7 +312,7 @@ void Reporter::SaveUnimplementedAppletReport(
}
void Reporter::SavePlayReport(PlayReportType type, u64 title_id,
- const std::vector<std::vector<u8>>& data,
+ const std::vector<std::span<const u8>>& data,
std::optional<u64> process_id, std::optional<u128> user_id) const {
if (!IsReportingEnabled()) {
return;
diff --git a/src/core/reporter.h b/src/core/reporter.h
index 9fdb9d6c1..bb11f8e7c 100644
--- a/src/core/reporter.h
+++ b/src/core/reporter.h
@@ -5,6 +5,7 @@
#include <array>
#include <optional>
+#include <span>
#include <string>
#include <vector>
#include "common/common_types.h"
@@ -56,7 +57,8 @@ public:
System,
};
- void SavePlayReport(PlayReportType type, u64 title_id, const std::vector<std::vector<u8>>& data,
+ void SavePlayReport(PlayReportType type, u64 title_id,
+ const std::vector<std::span<const u8>>& data,
std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const;
// Used by error applet
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp
index cedc94e63..4fcfb4510 100644
--- a/src/input_common/drivers/joycon.cpp
+++ b/src/input_common/drivers/joycon.cpp
@@ -668,12 +668,10 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
return "Right Joycon";
case Joycon::ControllerType::Pro:
return "Pro Controller";
- case Joycon::ControllerType::Grip:
- return "Grip Controller";
case Joycon::ControllerType::Dual:
return "Dual Joycon";
default:
- return "Unknown Joycon";
+ return "Unknown Switch Controller";
}
}
} // namespace InputCommon
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h
index 316d383d8..2149ab7fd 100644
--- a/src/input_common/drivers/joycon.h
+++ b/src/input_common/drivers/joycon.h
@@ -15,7 +15,7 @@ using SerialNumber = std::array<u8, 15>;
struct Battery;
struct Color;
struct MotionData;
-enum class ControllerType;
+enum class ControllerType : u8;
enum class DriverResult;
enum class IrsResolution;
class JoyconDriver;
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index 3775e2d35..8f94c9f45 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -162,14 +162,14 @@ void JoyconDriver::InputThread(std::stop_token stop_token) {
}
void JoyconDriver::OnNewData(std::span<u8> buffer) {
- const auto report_mode = static_cast<InputReport>(buffer[0]);
+ const auto report_mode = static_cast<ReportMode>(buffer[0]);
// Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion
// experience
switch (report_mode) {
- case InputReport::STANDARD_FULL_60HZ:
- case InputReport::NFC_IR_MODE_60HZ:
- case InputReport::SIMPLE_HID_MODE: {
+ case ReportMode::STANDARD_FULL_60HZ:
+ case ReportMode::NFC_IR_MODE_60HZ:
+ case ReportMode::SIMPLE_HID_MODE: {
const auto now = std::chrono::steady_clock::now();
const auto new_delta_time = static_cast<u64>(
std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count());
@@ -190,7 +190,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
};
// TODO: Remove this when calibration is properly loaded and not calculated
- if (ring_connected && report_mode == InputReport::STANDARD_FULL_60HZ) {
+ if (ring_connected && report_mode == ReportMode::STANDARD_FULL_60HZ) {
InputReportActive data{};
memcpy(&data, buffer.data(), sizeof(InputReportActive));
calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input);
@@ -228,16 +228,16 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
}
switch (report_mode) {
- case InputReport::STANDARD_FULL_60HZ:
+ case ReportMode::STANDARD_FULL_60HZ:
joycon_poller->ReadActiveMode(buffer, motion_status, ring_status);
break;
- case InputReport::NFC_IR_MODE_60HZ:
+ case ReportMode::NFC_IR_MODE_60HZ:
joycon_poller->ReadNfcIRMode(buffer, motion_status);
break;
- case InputReport::SIMPLE_HID_MODE:
+ case ReportMode::SIMPLE_HID_MODE:
joycon_poller->ReadPassiveMode(buffer);
break;
- case InputReport::SUBCMD_REPLY:
+ case ReportMode::SUBCMD_REPLY:
LOG_DEBUG(Input, "Unhandled command reply");
break;
default:
diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp
index f6e7e97d5..d8f040f75 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.cpp
+++ b/src/input_common/helpers/joycon_protocol/calibration.cpp
@@ -13,33 +13,33 @@ CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
+ JoystickLeftSpiCalibration spi_calibration{};
+ bool has_user_calibration = false;
calibration = {};
- result = ReadSPI(CalAddr::USER_LEFT_MAGIC, sizeof(u16), buffer);
-
if (result == DriverResult::Success) {
- const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
- if (has_user_calibration) {
- result = ReadSPI(CalAddr::USER_LEFT_DATA, 9, buffer);
- } else {
- result = ReadSPI(CalAddr::FACT_LEFT_DATA, 9, buffer);
- }
+ result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
}
- if (result == DriverResult::Success) {
- calibration.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
- calibration.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
- calibration.x.center = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
- calibration.y.center = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
- calibration.x.min = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
- calibration.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
+ // Read User defined calibration
+ if (result == DriverResult::Success && has_user_calibration) {
+ result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
}
- // Nintendo fix for drifting stick
- // result = ReadSPI(0x60, 0x86 ,buffer, 16);
- // calibration.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
+ // Read Factory calibration
+ if (result == DriverResult::Success && !has_user_calibration) {
+ result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
+ }
+
+ if (result == DriverResult::Success) {
+ calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
+ calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
+ calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
+ calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
+ calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
+ calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
+ }
// Set a valid default calibration if data is missing
ValidateCalibration(calibration);
@@ -49,33 +49,33 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
+ JoystickRightSpiCalibration spi_calibration{};
+ bool has_user_calibration = false;
calibration = {};
- result = ReadSPI(CalAddr::USER_RIGHT_MAGIC, sizeof(u16), buffer);
-
if (result == DriverResult::Success) {
- const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
- if (has_user_calibration) {
- result = ReadSPI(CalAddr::USER_RIGHT_DATA, 9, buffer);
- } else {
- result = ReadSPI(CalAddr::FACT_RIGHT_DATA, 9, buffer);
- }
+ result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
}
- if (result == DriverResult::Success) {
- calibration.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
- calibration.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
- calibration.x.min = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
- calibration.y.min = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
- calibration.x.max = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
- calibration.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
+ // Read User defined calibration
+ if (result == DriverResult::Success && has_user_calibration) {
+ result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
+ }
+
+ // Read Factory calibration
+ if (result == DriverResult::Success && !has_user_calibration) {
+ result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
}
- // Nintendo fix for drifting stick
- // buffer = ReadSPI(0x60, 0x98 , 16);
- // joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
+ if (result == DriverResult::Success) {
+ calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
+ calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
+ calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
+ calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
+ calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
+ calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
+ }
// Set a valid default calibration if data is missing
ValidateCalibration(calibration);
@@ -85,39 +85,41 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
+ ImuSpiCalibration spi_calibration{};
+ bool has_user_calibration = false;
calibration = {};
- result = ReadSPI(CalAddr::USER_IMU_MAGIC, sizeof(u16), buffer);
-
if (result == DriverResult::Success) {
- const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
- if (has_user_calibration) {
- result = ReadSPI(CalAddr::USER_IMU_DATA, sizeof(IMUCalibration), buffer);
- } else {
- result = ReadSPI(CalAddr::FACT_IMU_DATA, sizeof(IMUCalibration), buffer);
- }
+ result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
+ }
+
+ // Read User defined calibration
+ if (result == DriverResult::Success && has_user_calibration) {
+ result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
+ }
+
+ // Read Factory calibration
+ if (result == DriverResult::Success && !has_user_calibration) {
+ result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
- IMUCalibration device_calibration{};
- memcpy(&device_calibration, buffer.data(), sizeof(IMUCalibration));
- calibration.accelerometer[0].offset = device_calibration.accelerometer_offset[0];
- calibration.accelerometer[1].offset = device_calibration.accelerometer_offset[1];
- calibration.accelerometer[2].offset = device_calibration.accelerometer_offset[2];
+ calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
+ calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
+ calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
- calibration.accelerometer[0].scale = device_calibration.accelerometer_scale[0];
- calibration.accelerometer[1].scale = device_calibration.accelerometer_scale[1];
- calibration.accelerometer[2].scale = device_calibration.accelerometer_scale[2];
+ calibration.accelerometer[0].scale = spi_calibration.accelerometer_scale[0];
+ calibration.accelerometer[1].scale = spi_calibration.accelerometer_scale[1];
+ calibration.accelerometer[2].scale = spi_calibration.accelerometer_scale[2];
- calibration.gyro[0].offset = device_calibration.gyroscope_offset[0];
- calibration.gyro[1].offset = device_calibration.gyroscope_offset[1];
- calibration.gyro[2].offset = device_calibration.gyroscope_offset[2];
+ calibration.gyro[0].offset = spi_calibration.gyroscope_offset[0];
+ calibration.gyro[1].offset = spi_calibration.gyroscope_offset[1];
+ calibration.gyro[2].offset = spi_calibration.gyroscope_offset[2];
- calibration.gyro[0].scale = device_calibration.gyroscope_scale[0];
- calibration.gyro[1].scale = device_calibration.gyroscope_scale[1];
- calibration.gyro[2].scale = device_calibration.gyroscope_scale[2];
+ calibration.gyro[0].scale = spi_calibration.gyroscope_scale[0];
+ calibration.gyro[1].scale = spi_calibration.gyroscope_scale[1];
+ calibration.gyro[2].scale = spi_calibration.gyroscope_scale[2];
}
ValidateCalibration(calibration);
@@ -127,10 +129,12 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
+ constexpr s16 DefaultRingRange{800};
+
// TODO: Get default calibration form ring itself
if (ring_data_max == 0 && ring_data_min == 0) {
- ring_data_max = current_value + 800;
- ring_data_min = current_value - 800;
+ ring_data_max = current_value + DefaultRingRange;
+ ring_data_min = current_value - DefaultRingRange;
ring_data_default = current_value;
}
ring_data_max = std::max(ring_data_max, current_value);
@@ -143,42 +147,72 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
return DriverResult::Success;
}
+DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
+ bool& has_user_calibration) {
+ MagicSpiCalibration spi_magic{};
+ const DriverResult result{ReadSPI(address, spi_magic)};
+ has_user_calibration = false;
+ if (result == DriverResult::Success) {
+ has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
+ spi_magic.second == CalibrationMagic::USR_MAGIC_1;
+ }
+ return result;
+}
+
+u16 CalibrationProtocol::GetXAxisCalibrationValue(std::span<u8> block) const {
+ return static_cast<u16>(((block[1] & 0x0F) << 8) | block[0]);
+}
+
+u16 CalibrationProtocol::GetYAxisCalibrationValue(std::span<u8> block) const {
+ return static_cast<u16>((block[2] << 4) | (block[1] >> 4));
+}
+
void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) {
- constexpr u16 DefaultStickCenter{2048};
- constexpr u16 DefaultStickRange{1740};
+ constexpr u16 DefaultStickCenter{0x800};
+ constexpr u16 DefaultStickRange{0x6cc};
- if (calibration.x.center == 0xFFF || calibration.x.center == 0) {
- calibration.x.center = DefaultStickCenter;
- }
- if (calibration.x.max == 0xFFF || calibration.x.max == 0) {
- calibration.x.max = DefaultStickRange;
+ calibration.x.center = ValidateValue(calibration.x.center, DefaultStickCenter);
+ calibration.x.max = ValidateValue(calibration.x.max, DefaultStickRange);
+ calibration.x.min = ValidateValue(calibration.x.min, DefaultStickRange);
+
+ calibration.y.center = ValidateValue(calibration.y.center, DefaultStickCenter);
+ calibration.y.max = ValidateValue(calibration.y.max, DefaultStickRange);
+ calibration.y.min = ValidateValue(calibration.y.min, DefaultStickRange);
+}
+
+void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) {
+ constexpr s16 DefaultAccelerometerScale{0x4000};
+ constexpr s16 DefaultGyroScale{0x3be7};
+ constexpr s16 DefaultOffset{0};
+
+ for (auto& sensor : calibration.accelerometer) {
+ sensor.scale = ValidateValue(sensor.scale, DefaultAccelerometerScale);
+ sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
}
- if (calibration.x.min == 0xFFF || calibration.x.min == 0) {
- calibration.x.min = DefaultStickRange;
+ for (auto& sensor : calibration.gyro) {
+ sensor.scale = ValidateValue(sensor.scale, DefaultGyroScale);
+ sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
}
+}
- if (calibration.y.center == 0xFFF || calibration.y.center == 0) {
- calibration.y.center = DefaultStickCenter;
- }
- if (calibration.y.max == 0xFFF || calibration.y.max == 0) {
- calibration.y.max = DefaultStickRange;
+u16 CalibrationProtocol::ValidateValue(u16 value, u16 default_value) const {
+ if (value == 0) {
+ return default_value;
}
- if (calibration.y.min == 0xFFF || calibration.y.min == 0) {
- calibration.y.min = DefaultStickRange;
+ if (value == 0xFFF) {
+ return default_value;
}
+ return value;
}
-void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) {
- for (auto& sensor : calibration.accelerometer) {
- if (sensor.scale == 0) {
- sensor.scale = 0x4000;
- }
+s16 CalibrationProtocol::ValidateValue(s16 value, s16 default_value) const {
+ if (value == 0) {
+ return default_value;
}
- for (auto& sensor : calibration.gyro) {
- if (sensor.scale == 0) {
- sensor.scale = 0x3be7;
- }
+ if (value == 0xFFF) {
+ return default_value;
}
+ return value;
}
} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h
index afb52a36a..c6fd0f729 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.h
+++ b/src/input_common/helpers/joycon_protocol/calibration.h
@@ -53,9 +53,27 @@ public:
DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
private:
+ /// Returns true if the specified address corresponds to the magic value of user calibration
+ DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
+
+ /// Converts a raw calibration block to an u16 value containing the x axis value
+ u16 GetXAxisCalibrationValue(std::span<u8> block) const;
+
+ /// Converts a raw calibration block to an u16 value containing the y axis value
+ u16 GetYAxisCalibrationValue(std::span<u8> block) const;
+
+ /// Ensures that all joystick calibration values are set
void ValidateCalibration(JoyStickCalibration& calibration);
+
+ /// Ensures that all motion calibration values are set
void ValidateCalibration(MotionCalibration& calibration);
+ /// Returns the default value if the value is either zero or 0xFFF
+ u16 ValidateValue(u16 value, u16 default_value) const;
+
+ /// Returns the default value if the value is either zero or 0xFFF
+ s16 ValidateValue(s16 value, s16 default_value) const;
+
s16 ring_data_max = 0;
s16 ring_data_default = 0;
s16 ring_data_min = 0;
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 417d0dcc5..2b42a4555 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -22,12 +22,9 @@ void JoyconCommonProtocol::SetNonBlocking() {
}
DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
- std::vector<u8> buffer;
- const auto result = ReadSPI(CalAddr::DEVICE_TYPE, 1, buffer);
- controller_type = ControllerType::None;
+ const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
if (result == DriverResult::Success) {
- controller_type = static_cast<ControllerType>(buffer[0]);
// Fallback to 3rd party pro controllers
if (controller_type == ControllerType::None) {
controller_type = ControllerType::Pro;
@@ -40,6 +37,7 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) {
ControllerType controller_type{ControllerType::None};
const auto result = GetDeviceType(controller_type);
+
if (result != DriverResult::Success || controller_type == ControllerType::None) {
return DriverResult::UnsupportedControllerType;
}
@@ -62,7 +60,7 @@ DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
}
-DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) {
+DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
if (result == -1) {
@@ -72,15 +70,15 @@ DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) {
return DriverResult::Success;
}
-DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vector<u8>& output) {
+DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
+ SubCommandResponse& output) {
constexpr int timeout_mili = 66;
constexpr int MaxTries = 15;
int tries = 0;
- output.resize(MaxSubCommandResponseSize);
do {
- int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(),
- MaxSubCommandResponseSize, timeout_mili);
+ int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output),
+ sizeof(SubCommandResponse), timeout_mili);
if (result < 1) {
LOG_ERROR(Input, "No response from joycon");
@@ -88,27 +86,28 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vec
if (tries++ > MaxTries) {
return DriverResult::Timeout;
}
- } while (output[0] != 0x21 && output[14] != static_cast<u8>(sc));
-
- if (output[0] != 0x21 && output[14] != static_cast<u8>(sc)) {
- return DriverResult::WrongReply;
- }
+ } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
+ output.sub_command != sc);
return DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer,
- std::vector<u8>& output) {
- std::vector<u8> local_buffer(MaxResponseSize);
-
- local_buffer[0] = static_cast<u8>(OutputReport::RUMBLE_AND_SUBCMD);
- local_buffer[1] = GetCounter();
- local_buffer[10] = static_cast<u8>(sc);
- for (std::size_t i = 0; i < buffer.size(); ++i) {
- local_buffer[11 + i] = buffer[i];
+ SubCommandResponse& output) {
+ SubCommandPacket packet{
+ .output_report = OutputReport::RUMBLE_AND_SUBCMD,
+ .packet_counter = GetCounter(),
+ .sub_command = sc,
+ .command_data = {},
+ };
+
+ if (buffer.size() > packet.command_data.size()) {
+ return DriverResult::InvalidParameters;
}
- auto result = SendData(local_buffer);
+ memcpy(packet.command_data.data(), buffer.data(), buffer.size());
+
+ auto result = SendData(packet);
if (result != DriverResult::Success) {
return result;
@@ -120,44 +119,57 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) {
- std::vector<u8> output;
+ SubCommandResponse output{};
return SendSubCommand(sc, buffer, output);
}
DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) {
- std::vector<u8> local_buffer(MaxResponseSize);
-
- local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA);
- local_buffer[1] = GetCounter();
- local_buffer[10] = static_cast<u8>(sc);
- for (std::size_t i = 0; i < buffer.size(); ++i) {
- local_buffer[11 + i] = buffer[i];
+ SubCommandPacket packet{
+ .output_report = OutputReport::MCU_DATA,
+ .packet_counter = GetCounter(),
+ .sub_command = sc,
+ .command_data = {},
+ };
+
+ if (buffer.size() > packet.command_data.size()) {
+ return DriverResult::InvalidParameters;
}
- return SendData(local_buffer);
+ memcpy(packet.command_data.data(), buffer.data(), buffer.size());
+
+ return SendData(packet);
}
DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
- std::vector<u8> local_buffer(MaxResponseSize);
-
- local_buffer[0] = static_cast<u8>(Joycon::OutputReport::RUMBLE_ONLY);
- local_buffer[1] = GetCounter();
+ VibrationPacket packet{
+ .output_report = OutputReport::RUMBLE_ONLY,
+ .packet_counter = GetCounter(),
+ .vibration_data = {},
+ };
+
+ if (buffer.size() > packet.vibration_data.size()) {
+ return DriverResult::InvalidParameters;
+ }
- memcpy(local_buffer.data() + 2, buffer.data(), buffer.size());
+ memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
- return SendData(local_buffer);
+ return SendData(packet);
}
-DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output) {
+DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
+ constexpr std::size_t HeaderSize = 5;
constexpr std::size_t MaxTries = 10;
std::size_t tries = 0;
- std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, size};
- std::vector<u8> local_buffer(size + 20);
-
- buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF);
- buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8);
+ SubCommandResponse response{};
+ std::array<u8, sizeof(ReadSpiPacket)> buffer{};
+ const ReadSpiPacket packet_data{
+ .spi_address = addr,
+ .size = static_cast<u8>(output.size()),
+ };
+
+ memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
do {
- const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, local_buffer);
+ const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
if (result != DriverResult::Success) {
return result;
}
@@ -165,10 +177,14 @@ DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8
if (tries++ > MaxTries) {
return DriverResult::Timeout;
}
- } while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]);
+ } while (response.spi_address != addr);
+
+ if (response.command_data.size() < packet_data.size + HeaderSize) {
+ return DriverResult::WrongReply;
+ }
// Remove header from output
- output = std::vector<u8>(local_buffer.begin() + 20, local_buffer.begin() + 20 + size);
+ memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
return DriverResult::Success;
}
@@ -177,7 +193,7 @@ DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
if (result != DriverResult::Success) {
- LOG_ERROR(Input, "SendMCUData failed with error {}", result);
+ LOG_ERROR(Input, "Failed with error {}", result);
}
return result;
@@ -192,22 +208,21 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
if (result != DriverResult::Success) {
- LOG_ERROR(Input, "Set MCU config failed with error {}", result);
+ LOG_ERROR(Input, "Failed with error {}", result);
}
return result;
}
-DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_,
- std::vector<u8>& output) {
- const int report_mode = static_cast<u8>(report_mode_);
+DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
+ MCUCommandResponse& output) {
constexpr int TimeoutMili = 200;
constexpr int MaxTries = 9;
int tries = 0;
- output.resize(0x170);
do {
- int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), 0x170, TimeoutMili);
+ int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast<u8*>(&output),
+ sizeof(MCUCommandResponse), TimeoutMili);
if (result < 1) {
LOG_ERROR(Input, "No response from joycon attempt {}", tries);
@@ -215,28 +230,29 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_,
if (tries++ > MaxTries) {
return DriverResult::Timeout;
}
- } while (output[0] != report_mode || output[49] == 0xFF);
-
- if (output[0] != report_mode || output[49] == 0xFF) {
- return DriverResult::WrongReply;
- }
+ } while (output.input_report.report_mode != report_mode ||
+ output.mcu_report == MCUReport::EmptyAwaitingCmd);
return DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc,
std::span<const u8> buffer,
- std::vector<u8>& output) {
- std::vector<u8> local_buffer(MaxResponseSize);
-
- local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA);
- local_buffer[1] = GetCounter();
- local_buffer[9] = static_cast<u8>(sc);
- for (std::size_t i = 0; i < buffer.size(); ++i) {
- local_buffer[10 + i] = buffer[i];
+ MCUCommandResponse& output) {
+ SubCommandPacket packet{
+ .output_report = OutputReport::MCU_DATA,
+ .packet_counter = GetCounter(),
+ .sub_command = sc,
+ .command_data = {},
+ };
+
+ if (buffer.size() > packet.command_data.size()) {
+ return DriverResult::InvalidParameters;
}
- auto result = SendData(local_buffer);
+ memcpy(packet.command_data.data(), buffer.data(), buffer.size());
+
+ auto result = SendData(packet);
if (result != DriverResult::Success) {
return result;
@@ -248,7 +264,7 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubComman
}
DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) {
- std::vector<u8> output;
+ MCUCommandResponse output{};
constexpr std::size_t MaxTries{8};
std::size_t tries{};
@@ -263,7 +279,8 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
if (tries++ > MaxTries) {
return DriverResult::WrongReply;
}
- } while (output[49] != 1 || output[56] != static_cast<u8>(mode));
+ } while (output.mcu_report != MCUReport::StateReport ||
+ output.mcu_data[6] != static_cast<u8>(mode));
return DriverResult::Success;
}
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index 903bcf402..f44f73ba4 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.h
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.h
@@ -57,22 +57,31 @@ public:
* Sends data to the joycon device
* @param buffer data to be send
*/
- DriverResult SendData(std::span<const u8> buffer);
+ DriverResult SendRawData(std::span<const u8> buffer);
+
+ template <typename Output>
+ requires std::is_trivially_copyable_v<Output>
+ DriverResult SendData(const Output& output) {
+ std::array<u8, sizeof(Output)> buffer;
+ std::memcpy(buffer.data(), &output, sizeof(Output));
+ return SendRawData(buffer);
+ }
/**
* Waits for incoming data of the joycon device that matchs the subcommand
* @param sub_command type of data to be returned
- * @returns a buffer containing the responce
+ * @returns a buffer containing the response
*/
- DriverResult GetSubCommandResponse(SubCommand sub_command, std::vector<u8>& output);
+ DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output);
/**
* Sends a sub command to the device and waits for it's reply
* @param sc sub command to be send
* @param buffer data to be send
- * @returns output buffer containing the responce
+ * @returns output buffer containing the response
*/
- DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output);
+ DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
+ SubCommandResponse& output);
/**
* Sends a sub command to the device and waits for it's reply and ignores the output
@@ -97,10 +106,29 @@ public:
/**
* Reads the SPI memory stored on the joycon
* @param Initial address location
- * @param size in bytes to be read
- * @returns output buffer containing the responce
+ * @returns output buffer containing the response
*/
- DriverResult ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output);
+ DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
+
+ /**
+ * Reads the SPI memory stored on the joycon
+ * @param Initial address location
+ * @returns output object containing the response
+ */
+ template <typename Output>
+ requires std::is_trivially_copyable_v<Output>
+ DriverResult ReadSPI(SpiAddress addr, Output& output) {
+ std::array<u8, sizeof(Output)> buffer;
+ output = {};
+
+ const auto result = ReadRawSPI(addr, buffer);
+ if (result != DriverResult::Success) {
+ return result;
+ }
+
+ std::memcpy(&output, buffer.data(), sizeof(Output));
+ return DriverResult::Success;
+ }
/**
* Enables MCU chip on the joycon
@@ -117,19 +145,19 @@ public:
/**
* Waits until there's MCU data available. On timeout returns error
* @param report mode of the expected reply
- * @returns a buffer containing the responce
+ * @returns a buffer containing the response
*/
- DriverResult GetMCUDataResponse(ReportMode report_mode_, std::vector<u8>& output);
+ DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output);
/**
* Sends data to the MCU chip and waits for it's reply
* @param report mode of the expected reply
* @param sub command to be send
* @param buffer data to be send
- * @returns output buffer containing the responce
+ * @returns output buffer containing the response
*/
DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer,
- std::vector<u8>& output);
+ MCUCommandResponse& output);
/**
* Wait's until the MCU chip is on the specified mode
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
index 63cfb1369..548a4b9e3 100644
--- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp
+++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
@@ -32,13 +32,13 @@ DriverResult GenericProtocol::TriggersElapsed() {
DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
ScopedSetBlocking sb(this);
- std::vector<u8> output;
+ SubCommandResponse output{};
const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
device_info = {};
if (result == DriverResult::Success) {
- memcpy(&device_info, output.data(), sizeof(DeviceInfo));
+ device_info = output.device_info;
}
return result;
@@ -71,8 +71,8 @@ DriverResult GenericProtocol::GetBattery(u32& battery_level) {
DriverResult GenericProtocol::GetColor(Color& color) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
- const auto result = ReadSPI(CalAddr::COLOR_DATA, 12, buffer);
+ std::array<u8, 12> buffer{};
+ const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
color = {};
if (result == DriverResult::Success) {
@@ -87,8 +87,8 @@ DriverResult GenericProtocol::GetColor(Color& color) {
DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
- const auto result = ReadSPI(CalAddr::SERIAL_NUMBER, 16, buffer);
+ std::array<u8, 16> buffer{};
+ const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
serial_number = {};
if (result == DriverResult::Success) {
diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp
index 09e17bc5b..731fd5981 100644
--- a/src/input_common/helpers/joycon_protocol/irs.cpp
+++ b/src/input_common/helpers/joycon_protocol/irs.cpp
@@ -132,7 +132,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
DriverResult IrsProtocol::ConfigureIrs() {
LOG_DEBUG(Input, "Configure IRS");
constexpr std::size_t max_tries = 28;
- std::vector<u8> output;
+ SubCommandResponse output{};
std::size_t tries = 0;
const IrsConfigure irs_configuration{
@@ -158,7 +158,7 @@ DriverResult IrsProtocol::ConfigureIrs() {
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
}
- } while (output[15] != 0x0b);
+ } while (output.command_data[0] != 0x0b);
return DriverResult::Success;
}
@@ -167,7 +167,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
LOG_DEBUG(Input, "WriteRegistersStep1");
DriverResult result{DriverResult::Success};
constexpr std::size_t max_tries = 28;
- std::vector<u8> output;
+ SubCommandResponse output{};
std::size_t tries = 0;
const IrsWriteRegisters irs_registers{
@@ -218,7 +218,8 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
}
- } while (!(output[15] == 0x13 && output[17] == 0x07) && output[15] != 0x23);
+ } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) &&
+ output.command_data[0] != 0x23);
return DriverResult::Success;
}
@@ -226,7 +227,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
DriverResult IrsProtocol::WriteRegistersStep2() {
LOG_DEBUG(Input, "WriteRegistersStep2");
constexpr std::size_t max_tries = 28;
- std::vector<u8> output;
+ SubCommandResponse output{};
std::size_t tries = 0;
const IrsWriteRegisters irs_registers{
@@ -260,7 +261,7 @@ DriverResult IrsProtocol::WriteRegistersStep2() {
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
}
- } while (output[15] != 0x13 && output[15] != 0x23);
+ } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);
return DriverResult::Success;
}
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index 182d2c15b..b91934990 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -19,20 +19,24 @@
namespace InputCommon::Joycon {
constexpr u32 MaxErrorCount = 50;
constexpr u32 MaxBufferSize = 368;
-constexpr u32 MaxResponseSize = 49;
-constexpr u32 MaxSubCommandResponseSize = 64;
constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40};
using MacAddress = std::array<u8, 6>;
using SerialNumber = std::array<u8, 15>;
-enum class ControllerType {
- None,
- Left,
- Right,
- Pro,
- Grip,
- Dual,
+enum class ControllerType : u8 {
+ None = 0x00,
+ Left = 0x01,
+ Right = 0x02,
+ Pro = 0x03,
+ Dual = 0x05, // TODO: Verify this id
+ LarkHvc1 = 0x07,
+ LarkHvc2 = 0x08,
+ LarkNesLeft = 0x09,
+ LarkNesRight = 0x0A,
+ Lucia = 0x0B,
+ Lagon = 0x0C,
+ Lager = 0x0D,
};
enum class PadAxes {
@@ -99,14 +103,6 @@ enum class OutputReport : u8 {
USB_CMD = 0x80,
};
-enum class InputReport : u8 {
- SUBCMD_REPLY = 0x21,
- STANDARD_FULL_60HZ = 0x30,
- NFC_IR_MODE_60HZ = 0x31,
- SIMPLE_HID_MODE = 0x3F,
- INPUT_USB_RESPONSE = 0x81,
-};
-
enum class FeatureReport : u8 {
Last_SUBCMD = 0x02,
OTA_GW_UPGRADE = 0x70,
@@ -143,9 +139,10 @@ enum class SubCommand : u8 {
ENABLE_VIBRATION = 0x48,
GET_REGULATED_VOLTAGE = 0x50,
SET_EXTERNAL_CONFIG = 0x58,
- UNKNOWN_RINGCON = 0x59,
- UNKNOWN_RINGCON2 = 0x5A,
- UNKNOWN_RINGCON3 = 0x5C,
+ GET_EXTERNAL_DEVICE_INFO = 0x59,
+ ENABLE_EXTERNAL_POLLING = 0x5A,
+ DISABLE_EXTERNAL_POLLING = 0x5B,
+ SET_EXTERNAL_FORMAT_CONFIG = 0x5C,
};
enum class UsbSubCommand : u8 {
@@ -159,26 +156,31 @@ enum class UsbSubCommand : u8 {
SEND_UART = 0x92,
};
-enum class CalMagic : u8 {
+enum class CalibrationMagic : u8 {
USR_MAGIC_0 = 0xB2,
USR_MAGIC_1 = 0xA1,
- USRR_MAGI_SIZE = 2,
};
-enum class CalAddr {
- SERIAL_NUMBER = 0X6000,
- DEVICE_TYPE = 0X6012,
- COLOR_EXIST = 0X601B,
- FACT_LEFT_DATA = 0X603d,
- FACT_RIGHT_DATA = 0X6046,
- COLOR_DATA = 0X6050,
- FACT_IMU_DATA = 0X6020,
- USER_LEFT_MAGIC = 0X8010,
- USER_LEFT_DATA = 0X8012,
- USER_RIGHT_MAGIC = 0X801B,
- USER_RIGHT_DATA = 0X801D,
- USER_IMU_MAGIC = 0X8026,
- USER_IMU_DATA = 0X8028,
+enum class SpiAddress : u16 {
+ MAGIC = 0x0000,
+ MAC_ADDRESS = 0x0015,
+ PAIRING_INFO = 0x2000,
+ SHIPMENT = 0x5000,
+ SERIAL_NUMBER = 0x6000,
+ DEVICE_TYPE = 0x6012,
+ FORMAT_VERSION = 0x601B,
+ FACT_IMU_DATA = 0x6020,
+ FACT_LEFT_DATA = 0x603d,
+ FACT_RIGHT_DATA = 0x6046,
+ COLOR_DATA = 0x6050,
+ DESIGN_VARIATION = 0x605C,
+ SENSOR_DATA = 0x6080,
+ USER_LEFT_MAGIC = 0x8010,
+ USER_LEFT_DATA = 0x8012,
+ USER_RIGHT_MAGIC = 0x801B,
+ USER_RIGHT_DATA = 0x801D,
+ USER_IMU_MAGIC = 0x8026,
+ USER_IMU_DATA = 0x8028,
};
enum class ReportMode : u8 {
@@ -186,10 +188,12 @@ enum class ReportMode : u8 {
ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01,
ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02,
ACTIVE_POLLING_IR_CAMERA_DATA = 0x03,
+ SUBCMD_REPLY = 0x21,
MCU_UPDATE_STATE = 0x23,
STANDARD_FULL_60HZ = 0x30,
NFC_IR_MODE_60HZ = 0x31,
SIMPLE_HID_MODE = 0x3F,
+ INPUT_USB_RESPONSE = 0x81,
};
enum class GyroSensitivity : u8 {
@@ -360,10 +364,16 @@ enum class IrRegistersAddress : u16 {
DenoiseColor = 0x6901,
};
+enum class ExternalDeviceId : u16 {
+ RingController = 0x2000,
+ Starlink = 0x2800,
+};
+
enum class DriverResult {
Success,
WrongReply,
Timeout,
+ InvalidParameters,
UnsupportedControllerType,
HandleInUse,
ErrorReadingData,
@@ -396,10 +406,35 @@ struct MotionData {
u64 delta_timestamp{};
};
+// Output from SPI read command containing user calibration magic
+struct MagicSpiCalibration {
+ CalibrationMagic first;
+ CalibrationMagic second;
+};
+static_assert(sizeof(MagicSpiCalibration) == 0x2, "MagicSpiCalibration is an invalid size");
+
+// Output from SPI read command containing left joystick calibration
+struct JoystickLeftSpiCalibration {
+ std::array<u8, 3> max;
+ std::array<u8, 3> center;
+ std::array<u8, 3> min;
+};
+static_assert(sizeof(JoystickLeftSpiCalibration) == 0x9,
+ "JoystickLeftSpiCalibration is an invalid size");
+
+// Output from SPI read command containing right joystick calibration
+struct JoystickRightSpiCalibration {
+ std::array<u8, 3> center;
+ std::array<u8, 3> min;
+ std::array<u8, 3> max;
+};
+static_assert(sizeof(JoystickRightSpiCalibration) == 0x9,
+ "JoystickRightSpiCalibration is an invalid size");
+
struct JoyStickAxisCalibration {
- u16 max{1};
- u16 min{1};
- u16 center{0};
+ u16 max;
+ u16 min;
+ u16 center;
};
struct JoyStickCalibration {
@@ -407,6 +442,14 @@ struct JoyStickCalibration {
JoyStickAxisCalibration y;
};
+struct ImuSpiCalibration {
+ std::array<s16, 3> accelerometer_offset;
+ std::array<s16, 3> accelerometer_scale;
+ std::array<s16, 3> gyroscope_offset;
+ std::array<s16, 3> gyroscope_scale;
+};
+static_assert(sizeof(ImuSpiCalibration) == 0x18, "ImuSpiCalibration is an invalid size");
+
struct RingCalibration {
s16 default_value;
s16 max_value;
@@ -453,7 +496,7 @@ static_assert(sizeof(MCUConfig) == 0x26, "MCUConfig is an invalid size");
#pragma pack(push, 1)
struct InputReportPassive {
- InputReport report_mode;
+ ReportMode report_mode;
u16 button_input;
u8 stick_state;
std::array<u8, 10> unknown_data;
@@ -461,7 +504,7 @@ struct InputReportPassive {
static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size");
struct InputReportActive {
- InputReport report_mode;
+ ReportMode report_mode;
u8 packet_id;
Battery battery_status;
std::array<u8, 3> button_input;
@@ -475,7 +518,7 @@ struct InputReportActive {
static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size");
struct InputReportNfcIr {
- InputReport report_mode;
+ ReportMode report_mode;
u8 packet_id;
Battery battery_status;
std::array<u8, 3> button_input;
@@ -488,14 +531,6 @@ struct InputReportNfcIr {
static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size");
#pragma pack(pop)
-struct IMUCalibration {
- std::array<s16, 3> accelerometer_offset;
- std::array<s16, 3> accelerometer_scale;
- std::array<s16, 3> gyroscope_offset;
- std::array<s16, 3> gyroscope_scale;
-};
-static_assert(sizeof(IMUCalibration) == 0x18, "IMUCalibration is an invalid size");
-
struct NFCReadBlock {
u8 start;
u8 end;
@@ -581,9 +616,11 @@ static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid siz
struct DeviceInfo {
FirmwareVersion firmware;
+ std::array<u8, 2> unknown_1;
MacAddress mac_address;
+ std::array<u8, 2> unknown_2;
};
-static_assert(sizeof(DeviceInfo) == 0x8, "DeviceInfo is an invalid size");
+static_assert(sizeof(DeviceInfo) == 0xC, "DeviceInfo is an invalid size");
struct MotionStatus {
bool is_enabled;
@@ -599,6 +636,53 @@ struct RingStatus {
s16 min_value;
};
+struct VibrationPacket {
+ OutputReport output_report;
+ u8 packet_counter;
+ std::array<u8, 0x8> vibration_data;
+};
+static_assert(sizeof(VibrationPacket) == 0xA, "VibrationPacket is an invalid size");
+
+struct SubCommandPacket {
+ OutputReport output_report;
+ u8 packet_counter;
+ INSERT_PADDING_BYTES(0x8); // This contains vibration data
+ SubCommand sub_command;
+ std::array<u8, 0x26> command_data;
+};
+static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size");
+
+#pragma pack(push, 1)
+struct ReadSpiPacket {
+ SpiAddress spi_address;
+ INSERT_PADDING_BYTES(0x2);
+ u8 size;
+};
+static_assert(sizeof(ReadSpiPacket) == 0x5, "ReadSpiPacket is an invalid size");
+
+struct SubCommandResponse {
+ InputReportPassive input_report;
+ SubCommand sub_command;
+ union {
+ std::array<u8, 0x30> command_data;
+ SpiAddress spi_address; // Reply from SPI_FLASH_READ subcommand
+ ExternalDeviceId external_device_id; // Reply from GET_EXTERNAL_DEVICE_INFO subcommand
+ DeviceInfo device_info; // Reply from REQ_DEV_INFO subcommand
+ };
+ u8 crc; // This is never used
+};
+static_assert(sizeof(SubCommandResponse) == 0x40, "SubCommandResponse is an invalid size");
+#pragma pack(pop)
+
+struct MCUCommandResponse {
+ InputReportNfcIr input_report;
+ INSERT_PADDING_BYTES(0x8);
+ MCUReport mcu_report;
+ std::array<u8, 0x13D> mcu_data;
+ u8 crc;
+};
+static_assert(sizeof(MCUCommandResponse) == 0x170, "MCUCommandResponse is an invalid size");
+
struct JoyconCallbacks {
std::function<void(Battery)> on_battery_data;
std::function<void(Color)> on_color_data;
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp
index 5c0f71722..eeba82986 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.cpp
+++ b/src/input_common/helpers/joycon_protocol/nfc.cpp
@@ -110,7 +110,7 @@ bool NfcProtocol::HasAmiibo() {
DriverResult NfcProtocol::WaitUntilNfcIsReady() {
constexpr std::size_t timeout_limit = 10;
- std::vector<u8> output;
+ MCUCommandResponse output{};
std::size_t tries = 0;
do {
@@ -122,8 +122,9 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() {
if (tries++ > timeout_limit) {
return DriverResult::Timeout;
}
- } while (output[49] != 0x2a || (output[51] << 8) + output[50] != 0x0500 || output[55] != 0x31 ||
- output[56] != 0x00);
+ } while (output.mcu_report != MCUReport::NFCState ||
+ (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
+ output.mcu_data[5] != 0x31 || output.mcu_data[6] != 0x00);
return DriverResult::Success;
}
@@ -131,7 +132,7 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() {
DriverResult NfcProtocol::StartPolling(TagFoundData& data) {
LOG_DEBUG(Input, "Start Polling for tag");
constexpr std::size_t timeout_limit = 7;
- std::vector<u8> output;
+ MCUCommandResponse output{};
std::size_t tries = 0;
do {
@@ -142,18 +143,20 @@ DriverResult NfcProtocol::StartPolling(TagFoundData& data) {
if (tries++ > timeout_limit) {
return DriverResult::Timeout;
}
- } while (output[49] != 0x2a || (output[51] << 8) + output[50] != 0x0500 || output[56] != 0x09);
+ } while (output.mcu_report != MCUReport::NFCState ||
+ (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
+ output.mcu_data[6] != 0x09);
- data.type = output[62];
- data.uuid.resize(output[64]);
- memcpy(data.uuid.data(), output.data() + 65, data.uuid.size());
+ data.type = output.mcu_data[12];
+ data.uuid.resize(output.mcu_data[14]);
+ memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());
return DriverResult::Success;
}
DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {
constexpr std::size_t timeout_limit = 10;
- std::vector<u8> output;
+ MCUCommandResponse output{};
std::size_t tries = 0;
std::string uuid_string;
@@ -168,23 +171,24 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {
// Read Tag data
while (true) {
auto result = SendReadAmiiboRequest(output, ntag_pages);
- const auto mcu_report = static_cast<MCUReport>(output[49]);
- const auto nfc_status = static_cast<NFCStatus>(output[56]);
+ const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
return result;
}
- if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) &&
+ if ((output.mcu_report == MCUReport::NFCReadData ||
+ output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
}
- if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07 && output[52] == 0x01) {
+ if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07 &&
+ output.mcu_data[2] == 0x01) {
if (data.type != 2) {
continue;
}
- switch (output[74]) {
+ switch (output.mcu_data[24]) {
case 0:
ntag_pages = NFCPages::Block135;
break;
@@ -200,14 +204,14 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {
continue;
}
- if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
+ if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
// finished
SendStopPollingRequest(output);
return DriverResult::Success;
}
// Ignore other state reports
- if (mcu_report == MCUReport::NFCState) {
+ if (output.mcu_report == MCUReport::NFCState) {
continue;
}
@@ -221,7 +225,7 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) {
DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
constexpr std::size_t timeout_limit = 10;
- std::vector<u8> output;
+ MCUCommandResponse output{};
std::size_t tries = 0;
NFCPages ntag_pages = NFCPages::Block135;
@@ -229,36 +233,38 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
// Read Tag data
while (true) {
auto result = SendReadAmiiboRequest(output, ntag_pages);
- const auto mcu_report = static_cast<MCUReport>(output[49]);
- const auto nfc_status = static_cast<NFCStatus>(output[56]);
+ const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
return result;
}
- if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) &&
+ if ((output.mcu_report == MCUReport::NFCReadData ||
+ output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
}
- if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07) {
- std::size_t payload_size = (output[54] << 8 | output[55]) & 0x7FF;
- if (output[52] == 0x01) {
- memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 116, payload_size - 60);
+ if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
+ std::size_t payload_size = (output.mcu_data[4] << 8 | output.mcu_data[5]) & 0x7FF;
+ if (output.mcu_data[2] == 0x01) {
+ memcpy(ntag_data.data() + ntag_buffer_pos, output.mcu_data.data() + 66,
+ payload_size - 60);
ntag_buffer_pos += payload_size - 60;
} else {
- memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 56, payload_size);
+ memcpy(ntag_data.data() + ntag_buffer_pos, output.mcu_data.data() + 6,
+ payload_size);
}
continue;
}
- if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
+ if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
LOG_INFO(Input, "Finished reading amiibo");
return DriverResult::Success;
}
// Ignore other state reports
- if (mcu_report == MCUReport::NFCState) {
+ if (output.mcu_report == MCUReport::NFCState) {
continue;
}
@@ -270,7 +276,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
return DriverResult::Success;
}
-DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) {
+DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) {
NFCRequestState request{
.sub_command = MCUSubCommand::ReadDeviceMode,
.command_argument = NFCReadCommand::StartPolling,
@@ -294,7 +300,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) {
return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);
}
-DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) {
+DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
NFCRequestState request{
.sub_command = MCUSubCommand::ReadDeviceMode,
.command_argument = NFCReadCommand::StopPolling,
@@ -311,7 +317,7 @@ DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) {
return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);
}
-DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output) {
+DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) {
NFCRequestState request{
.sub_command = MCUSubCommand::ReadDeviceMode,
.command_argument = NFCReadCommand::StartWaitingRecieve,
@@ -328,7 +334,7 @@ DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output
return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output);
}
-DriverResult NfcProtocol::SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages) {
+DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) {
NFCRequestState request{
.sub_command = MCUSubCommand::ReadDeviceMode,
.command_argument = NFCReadCommand::Ntag,
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h
index e63665aa9..11e263e07 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.h
+++ b/src/input_common/helpers/joycon_protocol/nfc.h
@@ -45,13 +45,13 @@ private:
DriverResult GetAmiiboData(std::vector<u8>& data);
- DriverResult SendStartPollingRequest(std::vector<u8>& output);
+ DriverResult SendStartPollingRequest(MCUCommandResponse& output);
- DriverResult SendStopPollingRequest(std::vector<u8>& output);
+ DriverResult SendStopPollingRequest(MCUCommandResponse& output);
- DriverResult SendStartWaitingRecieveRequest(std::vector<u8>& output);
+ DriverResult SendStartWaitingRecieveRequest(MCUCommandResponse& output);
- DriverResult SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages);
+ DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages);
NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const;
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp
index 7f8e093fa..9bb15e935 100644
--- a/src/input_common/helpers/joycon_protocol/poller.cpp
+++ b/src/input_common/helpers/joycon_protocol/poller.cpp
@@ -31,9 +31,7 @@ void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& moti
case Joycon::ControllerType::Pro:
UpdateActiveProPadInput(data, motion_status);
break;
- case Joycon::ControllerType::Grip:
- case Joycon::ControllerType::Dual:
- case Joycon::ControllerType::None:
+ default:
break;
}
@@ -58,9 +56,7 @@ void JoyconPoller::ReadPassiveMode(std::span<u8> buffer) {
case Joycon::ControllerType::Pro:
UpdatePasiveProPadInput(data);
break;
- case Joycon::ControllerType::Grip:
- case Joycon::ControllerType::Dual:
- case Joycon::ControllerType::None:
+ default:
break;
}
}
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp
index 12f81309e..190cef812 100644
--- a/src/input_common/helpers/joycon_protocol/ringcon.cpp
+++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp
@@ -70,14 +70,12 @@ DriverResult RingConProtocol::StartRingconPolling() {
DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
LOG_DEBUG(Input, "IsRingConnected");
constexpr std::size_t max_tries = 28;
- constexpr u8 ring_controller_id = 0x20;
- std::vector<u8> output;
+ SubCommandResponse output{};
std::size_t tries = 0;
is_connected = false;
do {
- std::array<u8, 1> empty_data{};
- const auto result = SendSubCommand(SubCommand::UNKNOWN_RINGCON, empty_data, output);
+ const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output);
if (result != DriverResult::Success) {
return result;
@@ -86,7 +84,7 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
if (tries++ >= max_tries) {
return DriverResult::NoDeviceDetected;
}
- } while (output[16] != ring_controller_id);
+ } while (output.external_device_id != ExternalDeviceId::RingController);
is_connected = true;
return DriverResult::Success;
@@ -100,14 +98,14 @@ DriverResult RingConProtocol::ConfigureRing() {
0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36};
- const DriverResult result = SendSubCommand(SubCommand::UNKNOWN_RINGCON3, ring_config);
+ const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
if (result != DriverResult::Success) {
return result;
}
static constexpr std::array<u8, 4> ringcon_data{0x04, 0x01, 0x01, 0x02};
- return SendSubCommand(SubCommand::UNKNOWN_RINGCON2, ringcon_data);
+ return SendSubCommand(SubCommand::ENABLE_EXTERNAL_POLLING, ringcon_data);
}
bool RingConProtocol::IsEnabled() const {
diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp
index 096c23b07..a6be6dac1 100644
--- a/src/input_common/helpers/stick_from_buttons.cpp
+++ b/src/input_common/helpers/stick_from_buttons.cpp
@@ -15,6 +15,9 @@ public:
// do not play nicely with the theoretical maximum range.
// Using a value one lower from the maximum emulates real stick behavior.
static constexpr float MAX_RANGE = 32766.0f / 32767.0f;
+ static constexpr float TAU = Common::PI * 2.0f;
+ // Use wider angle to ease the transition.
+ static constexpr float APERTURE = TAU * 0.15f;
using Button = std::unique_ptr<Common::Input::InputDevice>;
@@ -61,30 +64,23 @@ public:
}
bool IsAngleGreater(float old_angle, float new_angle) const {
- constexpr float TAU = Common::PI * 2.0f;
- // Use wider angle to ease the transition.
- constexpr float aperture = TAU * 0.15f;
- const float top_limit = new_angle + aperture;
+ const float top_limit = new_angle + APERTURE;
return (old_angle > new_angle && old_angle <= top_limit) ||
(old_angle + TAU > new_angle && old_angle + TAU <= top_limit);
}
bool IsAngleSmaller(float old_angle, float new_angle) const {
- constexpr float TAU = Common::PI * 2.0f;
- // Use wider angle to ease the transition.
- constexpr float aperture = TAU * 0.15f;
- const float bottom_limit = new_angle - aperture;
+ const float bottom_limit = new_angle - APERTURE;
return (old_angle >= bottom_limit && old_angle < new_angle) ||
(old_angle - TAU >= bottom_limit && old_angle - TAU < new_angle);
}
float GetAngle(std::chrono::time_point<std::chrono::steady_clock> now) const {
- constexpr float TAU = Common::PI * 2.0f;
float new_angle = angle;
auto time_difference = static_cast<float>(
- std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count());
- time_difference /= 1000.0f * 1000.0f;
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update).count());
+ time_difference /= 1000.0f;
if (time_difference > 0.5f) {
time_difference = 0.5f;
}
@@ -201,8 +197,6 @@ public:
}
void UpdateStatus() {
- const float coef = modifier_status.value ? modifier_scale : MAX_RANGE;
-
bool r = right_status;
bool l = left_status;
bool u = up_status;
@@ -220,7 +214,7 @@ public:
// Move if a key is pressed
if (r || l || u || d) {
- amplitude = coef;
+ amplitude = modifier_status.value ? modifier_scale : MAX_RANGE;
} else {
amplitude = 0;
}
@@ -274,30 +268,17 @@ public:
Common::Input::StickStatus status{};
status.x.properties = properties;
status.y.properties = properties;
+
if (Settings::values.emulate_analog_keyboard) {
const auto now = std::chrono::steady_clock::now();
- float angle_ = GetAngle(now);
+ const float angle_ = GetAngle(now);
status.x.raw_value = std::cos(angle_) * amplitude;
status.y.raw_value = std::sin(angle_) * amplitude;
return status;
}
- constexpr float SQRT_HALF = 0.707106781f;
- int x = 0, y = 0;
- if (right_status) {
- ++x;
- }
- if (left_status) {
- --x;
- }
- if (up_status) {
- ++y;
- }
- if (down_status) {
- --y;
- }
- const float coef = modifier_status.value ? modifier_scale : MAX_RANGE;
- status.x.raw_value = static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF);
- status.y.raw_value = static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF);
+
+ status.x.raw_value = std::cos(goal_angle) * amplitude;
+ status.y.raw_value = std::sin(goal_angle) * amplitude;
return status;
}
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 15cbf7e5f..8c6a6521a 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -16,10 +16,10 @@ public:
class InputFromButton final : public Common::Input::InputDevice {
public:
- explicit InputFromButton(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_,
- InputEngine* input_engine_)
- : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_),
- input_engine(input_engine_) {
+ explicit InputFromButton(PadIdentifier identifier_, int button_, bool turbo_, bool toggle_,
+ bool inverted_, InputEngine* input_engine_)
+ : identifier(identifier_), button(button_), turbo(turbo_), toggle(toggle_),
+ inverted(inverted_), input_engine(input_engine_) {
UpdateCallback engine_callback{[this]() { OnChange(); }};
const InputIdentifier input_identifier{
.identifier = identifier,
@@ -40,6 +40,7 @@ public:
.value = input_engine->GetButton(identifier, button),
.inverted = inverted,
.toggle = toggle,
+ .turbo = turbo,
};
}
@@ -68,6 +69,7 @@ public:
private:
const PadIdentifier identifier;
const int button;
+ const bool turbo;
const bool toggle;
const bool inverted;
int callback_key;
@@ -77,10 +79,10 @@ private:
class InputFromHatButton final : public Common::Input::InputDevice {
public:
- explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool toggle_,
- bool inverted_, InputEngine* input_engine_)
- : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_),
- inverted(inverted_), input_engine(input_engine_) {
+ explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool turbo_,
+ bool toggle_, bool inverted_, InputEngine* input_engine_)
+ : identifier(identifier_), button(button_), direction(direction_), turbo(turbo_),
+ toggle(toggle_), inverted(inverted_), input_engine(input_engine_) {
UpdateCallback engine_callback{[this]() { OnChange(); }};
const InputIdentifier input_identifier{
.identifier = identifier,
@@ -101,6 +103,7 @@ public:
.value = input_engine->GetHatButton(identifier, button, direction),
.inverted = inverted,
.toggle = toggle,
+ .turbo = turbo,
};
}
@@ -130,6 +133,7 @@ private:
const PadIdentifier identifier;
const int button;
const u8 direction;
+ const bool turbo;
const bool toggle;
const bool inverted;
int callback_key;
@@ -853,14 +857,15 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateButtonDevice(
const auto keyboard_key = params.Get("code", 0);
const auto toggle = params.Get("toggle", false) != 0;
const auto inverted = params.Get("inverted", false) != 0;
+ const auto turbo = params.Get("turbo", false) != 0;
input_engine->PreSetController(identifier);
input_engine->PreSetButton(identifier, button_id);
input_engine->PreSetButton(identifier, keyboard_key);
if (keyboard_key != 0) {
- return std::make_unique<InputFromButton>(identifier, keyboard_key, toggle, inverted,
+ return std::make_unique<InputFromButton>(identifier, keyboard_key, turbo, toggle, inverted,
input_engine.get());
}
- return std::make_unique<InputFromButton>(identifier, button_id, toggle, inverted,
+ return std::make_unique<InputFromButton>(identifier, button_id, turbo, toggle, inverted,
input_engine.get());
}
@@ -876,11 +881,12 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateHatButtonDevice(
const auto direction = input_engine->GetHatButtonId(params.Get("direction", ""));
const auto toggle = params.Get("toggle", false) != 0;
const auto inverted = params.Get("inverted", false) != 0;
+ const auto turbo = params.Get("turbo", false) != 0;
input_engine->PreSetController(identifier);
input_engine->PreSetHatButton(identifier, button_id);
- return std::make_unique<InputFromHatButton>(identifier, button_id, direction, toggle, inverted,
- input_engine.get());
+ return std::make_unique<InputFromHatButton>(identifier, button_id, direction, turbo, toggle,
+ inverted, input_engine.get());
}
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateStickDevice(
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
index 0cb1e193e..fd4a61a4d 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
@@ -279,6 +279,8 @@ void SetupOptions(const IR::Program& program, const Profile& profile,
header += "OPTION NV_internal;"
"OPTION NV_shader_storage_buffer;"
"OPTION NV_gpu_program_fp64;";
+ // TODO: Enable only when MS is used
+ header += "OPTION NV_texture_multisample;";
if (info.uses_int64_bit_atomics) {
header += "OPTION NV_shader_atomic_int64;";
}
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index e67e80fac..85ee27333 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -59,7 +59,14 @@ std::string Image(EmitContext& ctx, IR::TextureInstInfo info,
}
}
-std::string_view TextureType(IR::TextureInstInfo info) {
+bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
+ if (info.type == TextureType::Buffer) {
+ return false;
+ }
+ return ctx.info.texture_descriptors.at(info.descriptor_index).is_multisample;
+}
+
+std::string_view TextureType(IR::TextureInstInfo info, bool is_ms = false) {
if (info.is_depth) {
switch (info.type) {
case TextureType::Color1D:
@@ -88,9 +95,9 @@ std::string_view TextureType(IR::TextureInstInfo info) {
return "ARRAY1D";
case TextureType::Color2D:
case TextureType::Color2DRect:
- return "2D";
+ return is_ms ? "2DMS" : "2D";
case TextureType::ColorArray2D:
- return "ARRAY2D";
+ return is_ms ? "ARRAY2DMS" : "ARRAY2D";
case TextureType::Color3D:
return "3D";
case TextureType::ColorCube:
@@ -510,15 +517,16 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
const auto sparse_inst{PrepareSparse(inst)};
+ const bool is_multisample{ms.type != Type::Void};
const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""};
- const std::string_view type{TextureType(info)};
+ const std::string_view type{TextureType(info, is_multisample)};
const std::string texture{Texture(ctx, info, index)};
const std::string offset_vec{Offset(ctx, offset)};
const auto [coord_vec, coord_alloc]{Coord(ctx, coord)};
const Register ret{ctx.reg_alloc.Define(inst)};
if (info.type == TextureType::Buffer) {
ctx.Add("TXF.F{} {},{},{},{}{};", sparse_mod, ret, coord_vec, texture, type, offset_vec);
- } else if (ms.type != Type::Void) {
+ } else if (is_multisample) {
ctx.Add("MOV.S {}.w,{};"
"TXFMS.F{} {},{},{},{}{};",
coord_vec, ms, sparse_mod, ret, coord_vec, texture, type, offset_vec);
@@ -531,10 +539,11 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
}
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
- ScalarS32 lod) {
+ ScalarS32 lod, [[maybe_unused]] const IR::Value& skip_mips) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
const std::string texture{Texture(ctx, info, index)};
- const std::string_view type{TextureType(info)};
+ const bool is_msaa{IsTextureMsaa(ctx, info)};
+ const std::string_view type{TextureType(info, is_msaa)};
ctx.Add("TXQ {},{},{},{};", inst, lod, texture, type);
}
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
index 415a249e4..1a1ea61d5 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -581,7 +581,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms);
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
- ScalarS32 lod);
+ ScalarS32 lod, const IR::Value& skip_mips);
void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, Register coord);
void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const IR::Value& coord, const IR::Value& derivatives,
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index cecdbb9d6..f335c8af0 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -25,6 +25,13 @@ std::string Image(EmitContext& ctx, const IR::TextureInstInfo& info, const IR::V
return fmt::format("img{}{}", def.binding, index_offset);
}
+bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
+ if (info.type == TextureType::Buffer) {
+ return false;
+ }
+ return ctx.info.texture_descriptors.at(info.descriptor_index).is_multisample;
+}
+
std::string CastToIntVec(std::string_view value, const IR::TextureInstInfo& info) {
switch (info.type) {
case TextureType::Color1D:
@@ -414,7 +421,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view coords, std::string_view offset, std::string_view lod,
- [[maybe_unused]] std::string_view ms) {
+ std::string_view ms) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
if (info.has_bias) {
throw NotImplementedException("EmitImageFetch Bias texture samples");
@@ -431,19 +438,24 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
ctx.AddU1("{}=true;", *sparse_inst);
}
if (!sparse_inst || !supports_sparse) {
- if (!offset.empty()) {
- ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture,
- CoordsCastToInt(coords, info), lod, CoordsCastToInt(offset, info));
+ const auto int_coords{CoordsCastToInt(coords, info)};
+ if (!ms.empty()) {
+ ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, ms);
+ } else if (!offset.empty()) {
+ ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture, int_coords, lod,
+ CoordsCastToInt(offset, info));
} else {
if (info.type == TextureType::Buffer) {
ctx.Add("{}=texelFetch({},int({}));", texel, texture, coords);
} else {
- ctx.Add("{}=texelFetch({},{},int({}));", texel, texture,
- CoordsCastToInt(coords, info), lod);
+ ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, lod);
}
}
return;
}
+ if (!ms.empty()) {
+ throw NotImplementedException("EmitImageFetch Sparse MSAA samples");
+ }
if (!offset.empty()) {
ctx.AddU1("{}=sparseTexelsResidentARB(sparseTexelFetchOffsetARB({},{},int({}),{},{}));",
*sparse_inst, texture, CastToIntVec(coords, info), lod,
@@ -455,29 +467,36 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
}
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
- std::string_view lod) {
+ std::string_view lod, const IR::Value& skip_mips_val) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
const auto texture{Texture(ctx, info, index)};
+ const bool is_msaa{IsTextureMsaa(ctx, info)};
+ const bool skip_mips{skip_mips_val.U1()};
+ const auto mips{skip_mips ? "0u" : fmt::format("uint(textureQueryLevels({}))", texture)};
+ if (is_msaa && !skip_mips) {
+ throw NotImplementedException("EmitImageQueryDimensions MSAA QueryLevels");
+ }
+ if (info.type == TextureType::Buffer && !skip_mips) {
+ throw NotImplementedException("EmitImageQueryDimensions TextureType::Buffer QueryLevels");
+ }
+ const bool uses_lod{!is_msaa && info.type != TextureType::Buffer};
+ const auto lod_str{uses_lod ? fmt::format(",int({})", lod) : ""};
switch (info.type) {
case TextureType::Color1D:
- return ctx.AddU32x4(
- "{}=uvec4(uint(textureSize({},int({}))),0u,0u,uint(textureQueryLevels({})));", inst,
- texture, lod, texture);
+ return ctx.AddU32x4("{}=uvec4(uint(textureSize({}{})),0u,0u,{});", inst, texture, lod_str,
+ mips);
case TextureType::ColorArray1D:
case TextureType::Color2D:
case TextureType::ColorCube:
case TextureType::Color2DRect:
- return ctx.AddU32x4(
- "{}=uvec4(uvec2(textureSize({},int({}))),0u,uint(textureQueryLevels({})));", inst,
- texture, lod, texture);
+ return ctx.AddU32x4("{}=uvec4(uvec2(textureSize({}{})),0u,{});", inst, texture, lod_str,
+ mips);
case TextureType::ColorArray2D:
case TextureType::Color3D:
case TextureType::ColorArrayCube:
- return ctx.AddU32x4(
- "{}=uvec4(uvec3(textureSize({},int({}))),uint(textureQueryLevels({})));", inst, texture,
- lod, texture);
+ return ctx.AddU32x4("{}=uvec4(uvec3(textureSize({}{})),{});", inst, texture, lod_str, mips);
case TextureType::Buffer:
- throw NotImplementedException("EmitImageQueryDimensions Texture buffers");
+ return ctx.AddU32x4("{}=uvec4(uint(textureSize({})),0u,0u,{});", inst, texture, mips);
}
throw LogicError("Unspecified image type {}", info.type.Value());
}
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
index c6df1dba7..8d0a65047 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
@@ -654,7 +654,7 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view coords, std::string_view offset, std::string_view lod,
std::string_view ms);
void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
- std::string_view lod);
+ std::string_view lod, const IR::Value& skip_mips);
void EmitImageQueryLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view coords);
void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index 5d01ec0cd..1b006e811 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -61,24 +61,28 @@ std::string OutputDecorator(Stage stage, u32 size) {
}
}
-std::string_view SamplerType(TextureType type, bool is_depth) {
- if (is_depth) {
- switch (type) {
- case TextureType::Color1D:
- return "sampler1DShadow";
- case TextureType::ColorArray1D:
- return "sampler1DArrayShadow";
- case TextureType::Color2D:
- return "sampler2DShadow";
- case TextureType::ColorArray2D:
- return "sampler2DArrayShadow";
- case TextureType::ColorCube:
- return "samplerCubeShadow";
- case TextureType::ColorArrayCube:
- return "samplerCubeArrayShadow";
- default:
- throw NotImplementedException("Texture type: {}", type);
- }
+std::string_view DepthSamplerType(TextureType type) {
+ switch (type) {
+ case TextureType::Color1D:
+ return "sampler1DShadow";
+ case TextureType::ColorArray1D:
+ return "sampler1DArrayShadow";
+ case TextureType::Color2D:
+ return "sampler2DShadow";
+ case TextureType::ColorArray2D:
+ return "sampler2DArrayShadow";
+ case TextureType::ColorCube:
+ return "samplerCubeShadow";
+ case TextureType::ColorArrayCube:
+ return "samplerCubeArrayShadow";
+ default:
+ throw NotImplementedException("Texture type: {}", type);
+ }
+}
+
+std::string_view ColorSamplerType(TextureType type, bool is_multisample = false) {
+ if (is_multisample) {
+ ASSERT(type == TextureType::Color2D || type == TextureType::ColorArray2D);
}
switch (type) {
case TextureType::Color1D:
@@ -87,9 +91,9 @@ std::string_view SamplerType(TextureType type, bool is_depth) {
return "sampler1DArray";
case TextureType::Color2D:
case TextureType::Color2DRect:
- return "sampler2D";
+ return is_multisample ? "sampler2DMS" : "sampler2D";
case TextureType::ColorArray2D:
- return "sampler2DArray";
+ return is_multisample ? "sampler2DMSArray" : "sampler2DArray";
case TextureType::Color3D:
return "sampler3D";
case TextureType::ColorCube:
@@ -677,7 +681,7 @@ void EmitContext::SetupTextures(Bindings& bindings) {
texture_buffers.reserve(info.texture_buffer_descriptors.size());
for (const auto& desc : info.texture_buffer_descriptors) {
texture_buffers.push_back({bindings.texture, desc.count});
- const auto sampler_type{SamplerType(TextureType::Buffer, false)};
+ const auto sampler_type{ColorSamplerType(TextureType::Buffer)};
const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
sampler_type, bindings.texture, array_decorator);
@@ -686,7 +690,8 @@ void EmitContext::SetupTextures(Bindings& bindings) {
textures.reserve(info.texture_descriptors.size());
for (const auto& desc : info.texture_descriptors) {
textures.push_back({bindings.texture, desc.count});
- const auto sampler_type{SamplerType(desc.type, desc.is_depth)};
+ const auto sampler_type{desc.is_depth ? DepthSamplerType(desc.type)
+ : ColorSamplerType(desc.type, desc.is_multisample)};
const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
sampler_type, bindings.texture, array_decorator);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index c898ce12f..02073c420 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -201,6 +201,13 @@ Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) {
}
}
+bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
+ if (info.type == TextureType::Buffer) {
+ return false;
+ }
+ return ctx.textures.at(info.descriptor_index).is_multisample;
+}
+
Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
if (info.relaxed_precision != 0) {
@@ -445,29 +452,33 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
}
-Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) {
+Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
+ const IR::Value& skip_mips_val) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
const Id image{TextureImage(ctx, info, index)};
const Id zero{ctx.u32_zero_value};
- const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }};
+ const bool skip_mips{skip_mips_val.U1()};
+ const auto mips{[&] { return skip_mips ? zero : ctx.OpImageQueryLevels(ctx.U32[1], image); }};
+ const bool is_msaa{IsTextureMsaa(ctx, info)};
+ const bool uses_lod{!is_msaa && info.type != TextureType::Buffer};
+ const auto query{[&](Id type) {
+ return uses_lod ? ctx.OpImageQuerySizeLod(type, image, lod)
+ : ctx.OpImageQuerySize(type, image);
+ }};
switch (info.type) {
case TextureType::Color1D:
- return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod),
- zero, zero, mips());
+ return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips());
case TextureType::ColorArray1D:
case TextureType::Color2D:
case TextureType::ColorCube:
case TextureType::Color2DRect:
- return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod),
- zero, mips());
+ return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[2]), zero, mips());
case TextureType::ColorArray2D:
case TextureType::Color3D:
case TextureType::ColorArrayCube:
- return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod),
- mips());
+ return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[3]), mips());
case TextureType::Buffer:
- return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySize(ctx.U32[1], image), zero,
- zero, mips());
+ return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[1]), zero, zero, mips());
}
throw LogicError("Unspecified image type {}", info.type.Value());
}
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index db12e8176..a440b557d 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -539,7 +539,8 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
const IR::Value& offset, const IR::Value& offset2, Id dref);
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms);
-Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod);
+Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
+ const IR::Value& skip_mips);
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivates, Id offset, Id lod_clamp);
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 3b97721e1..d48d4860e 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -1288,6 +1288,7 @@ void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_in
.pointer_type = pointer_type,
.image_type = image_type,
.count = desc.count,
+ .is_multisample = desc.is_multisample,
});
if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id);
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
index dbc5c55b9..768a4fbb5 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
@@ -35,6 +35,7 @@ struct TextureDefinition {
Id pointer_type;
Id image_type;
u32 count;
+ bool is_multisample;
};
struct TextureBufferDefinition {
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index 430797d23..b7caa4246 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -1846,15 +1846,16 @@ Value IREmitter::ImageFetch(const Value& handle, const Value& coords, const Valu
return Inst(op, Flags{info}, handle, coords, offset, lod, multisampling);
}
-Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod) {
+Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
+ const IR::U1& skip_mips) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageQueryDimensions
: Opcode::BindlessImageQueryDimensions};
- return Inst(op, handle, lod);
+ return Inst(op, handle, lod, skip_mips);
}
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
- TextureInstInfo info) {
- return Inst(Opcode::ImageQueryDimensions, Flags{info}, handle, lod);
+ const IR::U1& skip_mips, TextureInstInfo info) {
+ return Inst(Opcode::ImageQueryDimensions, Flags{info}, handle, lod, skip_mips);
}
Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, TextureInstInfo info) {
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 7aaaa4ab0..f3c81dbe1 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -320,9 +320,10 @@ public:
[[nodiscard]] F32 ImageSampleDrefExplicitLod(const Value& handle, const Value& coords,
const F32& dref, const F32& lod,
const Value& offset, TextureInstInfo info);
- [[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod);
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod,
- TextureInstInfo info);
+ const IR::U1& skip_mips);
+ [[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod,
+ const IR::U1& skip_mips, TextureInstInfo info);
[[nodiscard]] Value ImageQueryLod(const Value& handle, const Value& coords,
TextureInstInfo info);
@@ -408,7 +409,8 @@ private:
}
template <typename T>
- requires(sizeof(T) <= sizeof(u32) && std::is_trivially_copyable_v<T>) struct Flags {
+ requires(sizeof(T) <= sizeof(u32) && std::is_trivially_copyable_v<T>)
+ struct Flags {
Flags() = default;
Flags(T proxy_) : proxy{proxy_} {}
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 24e82f802..4447d67b0 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -482,7 +482,7 @@ OPCODE(BindlessImageSampleDrefExplicitLod, F32, U32,
OPCODE(BindlessImageGather, F32x4, U32, Opaque, Opaque, Opaque, )
OPCODE(BindlessImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, )
OPCODE(BindlessImageFetch, F32x4, U32, Opaque, Opaque, U32, Opaque, )
-OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, )
+OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, U1, )
OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, )
OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(BindlessImageRead, U32x4, U32, Opaque, )
@@ -495,7 +495,7 @@ OPCODE(BoundImageSampleDrefExplicitLod, F32, U32,
OPCODE(BoundImageGather, F32x4, U32, Opaque, Opaque, Opaque, )
OPCODE(BoundImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, )
OPCODE(BoundImageFetch, F32x4, U32, Opaque, Opaque, U32, Opaque, )
-OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, )
+OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, U1, )
OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, )
OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
OPCODE(BoundImageRead, U32x4, U32, Opaque, )
@@ -508,7 +508,7 @@ OPCODE(ImageSampleDrefExplicitLod, F32, Opaq
OPCODE(ImageGather, F32x4, Opaque, Opaque, Opaque, Opaque, )
OPCODE(ImageGatherDref, F32x4, Opaque, Opaque, Opaque, Opaque, F32, )
OPCODE(ImageFetch, F32x4, Opaque, Opaque, Opaque, U32, Opaque, )
-OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, )
+OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, U1, )
OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, )
OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, )
OPCODE(ImageRead, U32x4, Opaque, Opaque, )
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h
index 883dfa24e..c27546b0e 100644
--- a/src/shader_recompiler/frontend/ir/value.h
+++ b/src/shader_recompiler/frontend/ir/value.h
@@ -43,7 +43,6 @@ public:
explicit Value(u8 value) noexcept;
explicit Value(u16 value) noexcept;
explicit Value(u32 value) noexcept;
- explicit Value(s32 value) noexcept;
explicit Value(f32 value) noexcept;
explicit Value(u64 value) noexcept;
explicit Value(f64 value) noexcept;
@@ -66,7 +65,6 @@ public:
[[nodiscard]] u8 U8() const;
[[nodiscard]] u16 U16() const;
[[nodiscard]] u32 U32() const;
- [[nodiscard]] s32 S32() const;
[[nodiscard]] f32 F32() const;
[[nodiscard]] u64 U64() const;
[[nodiscard]] f64 F64() const;
@@ -86,7 +84,6 @@ private:
u8 imm_u8;
u16 imm_u16;
u32 imm_u32;
- s32 imm_s32;
f32 imm_f32;
u64 imm_u64;
f64 imm_f64;
@@ -101,9 +98,8 @@ public:
TypedValue() = default;
template <IR::Type other_type>
- requires((other_type & type_) != IR::Type::Void) explicit(false)
- TypedValue(const TypedValue<other_type>& value)
- : Value(value) {}
+ requires((other_type & type_) != IR::Type::Void)
+ explicit(false) TypedValue(const TypedValue<other_type>& value) : Value(value) {}
explicit TypedValue(const Value& value) : Value(value) {
if ((value.Type() & type_) == IR::Type::Void) {
@@ -194,16 +190,16 @@ public:
void ReplaceOpcode(IR::Opcode opcode);
template <typename FlagsType>
- requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
- [[nodiscard]] FlagsType Flags() const noexcept {
+ requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
+ [[nodiscard]] FlagsType Flags() const noexcept {
FlagsType ret;
std::memcpy(reinterpret_cast<char*>(&ret), &flags, sizeof(ret));
return ret;
}
template <typename FlagsType>
- requires(sizeof(FlagsType) <= sizeof(u32) &&
- std::is_trivially_copyable_v<FlagsType>) void SetFlags(FlagsType value) noexcept {
+ requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
+ void SetFlags(FlagsType value) noexcept {
std::memcpy(&flags, &value, sizeof(value));
}
@@ -379,14 +375,6 @@ inline u32 Value::U32() const {
return imm_u32;
}
-inline s32 Value::S32() const {
- if (IsIdentity()) {
- return inst->Arg(0).S32();
- }
- DEBUG_ASSERT(type == Type::S32);
- return imm_s32;
-}
-
inline f32 Value::F32() const {
if (IsIdentity()) {
return inst->Arg(0).F32();
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_query.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_query.cpp
index f8cfd4ab6..39af62559 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_query.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_query.cpp
@@ -15,11 +15,13 @@ enum class Mode : u64 {
SamplePos = 5,
};
-IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg) {
+IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg, u64 mask) {
switch (mode) {
case Mode::Dimension: {
+ const bool needs_num_mips{((mask >> 3) & 1) != 0};
+ const IR::U1 skip_mips{v.ir.Imm1(!needs_num_mips)};
const IR::U32 lod{v.X(src_reg)};
- return v.ir.ImageQueryDimension(handle, lod);
+ return v.ir.ImageQueryDimension(handle, lod, skip_mips);
}
case Mode::TextureType:
case Mode::SamplePos:
@@ -46,7 +48,7 @@ void Impl(TranslatorVisitor& v, u64 insn, std::optional<u32> cbuf_offset) {
handle = v.X(src_reg);
++src_reg;
}
- const IR::Value query{Query(v, handle, txq.mode, src_reg)};
+ const IR::Value query{Query(v, handle, txq.mode, src_reg, txq.mask)};
IR::Reg dest_reg{txq.dest_reg};
for (int element = 0; element < 4; ++element) {
if (((txq.mask >> element) & 1) == 0) {
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index 70b620dcb..d374c976a 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -355,21 +355,21 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
};
}
-TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
+u32 GetTextureHandle(Environment& env, const ConstBufferAddr& cbuf) {
const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index};
const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset};
const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset) << cbuf.shift_left};
const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)
<< cbuf.secondary_shift_left};
- return env.ReadTextureType(lhs_raw | rhs_raw);
+ return lhs_raw | rhs_raw;
+}
+
+TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
+ return env.ReadTextureType(GetTextureHandle(env, cbuf));
}
TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
- const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index};
- const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset};
- const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset)};
- const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)};
- return env.ReadTexturePixelFormat(lhs_raw | rhs_raw);
+ return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
}
class Descriptors {
@@ -386,8 +386,10 @@ public:
return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) {
return desc.cbuf_index == existing.cbuf_index &&
desc.cbuf_offset == existing.cbuf_offset &&
+ desc.shift_left == existing.shift_left &&
desc.secondary_cbuf_index == existing.secondary_cbuf_index &&
desc.secondary_cbuf_offset == existing.secondary_cbuf_offset &&
+ desc.secondary_shift_left == existing.secondary_shift_left &&
desc.count == existing.count && desc.size_shift == existing.size_shift &&
desc.has_secondary == existing.has_secondary;
});
@@ -405,15 +407,20 @@ public:
}
u32 Add(const TextureDescriptor& desc) {
- return Add(texture_descriptors, desc, [&desc](const auto& existing) {
+ const u32 index{Add(texture_descriptors, desc, [&desc](const auto& existing) {
return desc.type == existing.type && desc.is_depth == existing.is_depth &&
desc.has_secondary == existing.has_secondary &&
desc.cbuf_index == existing.cbuf_index &&
desc.cbuf_offset == existing.cbuf_offset &&
+ desc.shift_left == existing.shift_left &&
desc.secondary_cbuf_index == existing.secondary_cbuf_index &&
desc.secondary_cbuf_offset == existing.secondary_cbuf_offset &&
+ desc.secondary_shift_left == existing.secondary_shift_left &&
desc.count == existing.count && desc.size_shift == existing.size_shift;
- });
+ })};
+ // TODO: Read this from TIC
+ texture_descriptors[index].is_multisample |= desc.is_multisample;
+ return index;
}
u32 Add(const ImageDescriptor& desc) {
@@ -452,7 +459,8 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
const IR::Value coord(inst.Arg(1));
const IR::Value handle(ir.Imm32(0));
const IR::U32 lod{ir.Imm32(0)};
- const IR::Value texture_size = ir.ImageQueryDimension(handle, lod, info);
+ const IR::U1 skip_mips{ir.Imm1(true)};
+ const IR::Value texture_size = ir.ImageQueryDimension(handle, lod, skip_mips, info);
inst.SetArg(
1, ir.CompositeConstruct(
ir.FPMul(IR::F32(ir.CompositeExtract(coord, 0)),
diff --git a/src/shader_recompiler/object_pool.h b/src/shader_recompiler/object_pool.h
index 2b42c4ba2..5d648b159 100644
--- a/src/shader_recompiler/object_pool.h
+++ b/src/shader_recompiler/object_pool.h
@@ -10,7 +10,7 @@
namespace Shader {
template <typename T>
-requires std::is_destructible_v<T>
+ requires std::is_destructible_v<T>
class ObjectPool {
public:
explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
@@ -18,7 +18,7 @@ public:
}
template <typename... Args>
- requires std::is_constructible_v<T, Args...>
+ requires std::is_constructible_v<T, Args...>
[[nodiscard]] T* Create(Args&&... args) {
return std::construct_at(Memory(), std::forward<Args>(args)...);
}
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index dad7b07d4..52cd5bb81 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -45,6 +45,8 @@ set(SHADER_FILES
smaa_neighborhood_blending.vert
smaa_neighborhood_blending.frag
vulkan_blit_depth_stencil.frag
+ vulkan_color_clear.frag
+ vulkan_color_clear.vert
vulkan_fidelityfx_fsr_easu_fp16.comp
vulkan_fidelityfx_fsr_easu_fp32.comp
vulkan_fidelityfx_fsr_rcas_fp16.comp
diff --git a/src/video_core/host_shaders/vulkan_color_clear.frag b/src/video_core/host_shaders/vulkan_color_clear.frag
new file mode 100644
index 000000000..617bf01e1
--- /dev/null
+++ b/src/video_core/host_shaders/vulkan_color_clear.frag
@@ -0,0 +1,14 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#version 460 core
+
+layout (push_constant) uniform PushConstants {
+ vec4 clear_color;
+};
+
+layout(location = 0) out vec4 color;
+
+void main() {
+ color = clear_color;
+}
diff --git a/src/video_core/host_shaders/vulkan_color_clear.vert b/src/video_core/host_shaders/vulkan_color_clear.vert
new file mode 100644
index 000000000..d85883141
--- /dev/null
+++ b/src/video_core/host_shaders/vulkan_color_clear.vert
@@ -0,0 +1,10 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#version 460 core
+
+void main() {
+ float x = float((gl_VertexIndex & 1) << 2);
+ float y = float((gl_VertexIndex & 2) << 1);
+ gl_Position = vec4(x - 1.0, y - 1.0, 0.0, 1.0);
+}
diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
index 26d066004..1a0cea9b7 100644
--- a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
@@ -30,7 +30,7 @@ bool ComputePipelineKey::operator==(const ComputePipelineKey& rhs) const noexcep
ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cache_,
BufferCache& buffer_cache_, ProgramManager& program_manager_,
const Shader::Info& info_, std::string code,
- std::vector<u32> code_v)
+ std::vector<u32> code_v, bool force_context_flush)
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
program_manager{program_manager_}, info{info_} {
switch (device.GetShaderBackend()) {
@@ -63,6 +63,15 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac
writes_global_memory = !use_storage_buffers &&
std::ranges::any_of(info.storage_buffers_descriptors,
[](const auto& desc) { return desc.is_written; });
+ if (force_context_flush) {
+ std::scoped_lock lock{built_mutex};
+ built_fence.Create();
+ // Flush this context to ensure compilation commands and fence are in the GPU pipe.
+ glFlush();
+ built_condvar.notify_one();
+ } else {
+ is_built = true;
+ }
}
void ComputePipeline::Configure() {
@@ -142,6 +151,9 @@ void ComputePipeline::Configure() {
}
texture_cache.FillComputeImageViews(std::span(views.data(), views.size()));
+ if (!is_built) {
+ WaitForBuild();
+ }
if (assembly_program.handle != 0) {
program_manager.BindComputeAssemblyProgram(assembly_program.handle);
} else {
@@ -223,4 +235,13 @@ void ComputePipeline::Configure() {
}
}
+void ComputePipeline::WaitForBuild() {
+ if (built_fence.handle == 0) {
+ std::unique_lock lock{built_mutex};
+ built_condvar.wait(lock, [this] { return built_fence.handle != 0; });
+ }
+ ASSERT(glClientWaitSync(built_fence.handle, 0, GL_TIMEOUT_IGNORED) != GL_WAIT_FAILED);
+ is_built = true;
+}
+
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.h b/src/video_core/renderer_opengl/gl_compute_pipeline.h
index 6534dec32..9bcc72b59 100644
--- a/src/video_core/renderer_opengl/gl_compute_pipeline.h
+++ b/src/video_core/renderer_opengl/gl_compute_pipeline.h
@@ -50,7 +50,8 @@ class ComputePipeline {
public:
explicit ComputePipeline(const Device& device, TextureCache& texture_cache_,
BufferCache& buffer_cache_, ProgramManager& program_manager_,
- const Shader::Info& info_, std::string code, std::vector<u32> code_v);
+ const Shader::Info& info_, std::string code, std::vector<u32> code_v,
+ bool force_context_flush = false);
void Configure();
@@ -65,6 +66,8 @@ public:
}
private:
+ void WaitForBuild();
+
TextureCache& texture_cache;
BufferCache& buffer_cache;
Tegra::MemoryManager* gpu_memory;
@@ -81,6 +84,11 @@ private:
bool use_storage_buffers{};
bool writes_global_memory{};
+
+ std::mutex built_mutex;
+ std::condition_variable built_condvar;
+ OGLSync built_fence{};
+ bool is_built{false};
};
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
index c115dabe1..29491e762 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
@@ -176,7 +176,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
std::array<std::string, 5> sources,
std::array<std::vector<u32>, 5> sources_spirv,
const std::array<const Shader::Info*, 5>& infos,
- const GraphicsPipelineKey& key_)
+ const GraphicsPipelineKey& key_, bool force_context_flush)
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_},
state_tracker{state_tracker_}, key{key_} {
if (shader_notify) {
@@ -231,7 +231,8 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
const bool in_parallel = thread_worker != nullptr;
const auto backend = device.GetShaderBackend();
auto func{[this, sources = std::move(sources), sources_spirv = std::move(sources_spirv),
- shader_notify, backend, in_parallel](ShaderContext::Context*) mutable {
+ shader_notify, backend, in_parallel,
+ force_context_flush](ShaderContext::Context*) mutable {
for (size_t stage = 0; stage < 5; ++stage) {
switch (backend) {
case Settings::ShaderBackend::GLSL:
@@ -251,7 +252,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
break;
}
}
- if (in_parallel) {
+ if (force_context_flush || in_parallel) {
std::scoped_lock lock{built_mutex};
built_fence.Create();
// Flush this context to ensure compilation commands and fence are in the GPU pipe.
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.h b/src/video_core/renderer_opengl/gl_graphics_pipeline.h
index 1c06b3655..7bab3be0a 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.h
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.h
@@ -78,7 +78,7 @@ public:
std::array<std::string, 5> sources,
std::array<std::vector<u32>, 5> sources_spirv,
const std::array<const Shader::Info*, 5>& infos,
- const GraphicsPipelineKey& key_);
+ const GraphicsPipelineKey& key_, bool force_context_flush = false);
void Configure(bool is_indexed) {
configure_func(this, is_indexed);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 7dd854e0f..626ea7dcb 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -286,7 +286,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
file.read(reinterpret_cast<char*>(&key), sizeof(key));
queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {
ctx->pools.ReleaseContents();
- auto pipeline{CreateComputePipeline(ctx->pools, key, env)};
+ auto pipeline{CreateComputePipeline(ctx->pools, key, env, true)};
std::scoped_lock lock{state.mutex};
if (pipeline) {
compute_cache.emplace(key, std::move(pipeline));
@@ -307,7 +307,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
env_ptrs.push_back(&env);
}
ctx->pools.ReleaseContents();
- auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)};
+ auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false, true)};
std::scoped_lock lock{state.mutex};
if (pipeline) {
graphics_cache.emplace(key, std::move(pipeline));
@@ -439,7 +439,8 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline() {
std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
ShaderContext::ShaderPools& pools, const GraphicsPipelineKey& key,
- std::span<Shader::Environment* const> envs, bool build_in_parallel) try {
+ std::span<Shader::Environment* const> envs, bool use_shader_workers,
+ bool force_context_flush) try {
LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash());
size_t env_index{};
u32 total_storage_buffers{};
@@ -531,10 +532,10 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
}
previous_program = &program;
}
- auto* const thread_worker{build_in_parallel ? workers.get() : nullptr};
+ auto* const thread_worker{use_shader_workers ? workers.get() : nullptr};
return std::make_unique<GraphicsPipeline>(device, texture_cache, buffer_cache, program_manager,
state_tracker, thread_worker, &shader_notify, sources,
- sources_spirv, infos, key);
+ sources_spirv, infos, key, force_context_flush);
} catch (Shader::Exception& exception) {
LOG_ERROR(Render_OpenGL, "{}", exception.what());
@@ -559,8 +560,8 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
}
std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
- ShaderContext::ShaderPools& pools, const ComputePipelineKey& key,
- Shader::Environment& env) try {
+ ShaderContext::ShaderPools& pools, const ComputePipelineKey& key, Shader::Environment& env,
+ bool force_context_flush) try {
LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash());
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
@@ -589,7 +590,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
}
return std::make_unique<ComputePipeline>(device, texture_cache, buffer_cache, program_manager,
- program.info, code, code_spirv);
+ program.info, code, code_spirv, force_context_flush);
} catch (Shader::Exception& exception) {
LOG_ERROR(Render_OpenGL, "{}", exception.what());
return nullptr;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index f82420592..6b9732fca 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -50,14 +50,16 @@ private:
std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline(
ShaderContext::ShaderPools& pools, const GraphicsPipelineKey& key,
- std::span<Shader::Environment* const> envs, bool build_in_parallel);
+ std::span<Shader::Environment* const> envs, bool use_shader_workers,
+ bool force_context_flush = false);
std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineKey& key,
const VideoCommon::ShaderInfo* shader);
std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderContext::ShaderPools& pools,
const ComputePipelineKey& key,
- Shader::Environment& env);
+ Shader::Environment& env,
+ bool force_context_flush = false);
std::unique_ptr<ShaderWorker> CreateWorkers() const;
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index dd00d3edf..cf2964a3f 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -12,6 +12,8 @@
#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
+#include "video_core/host_shaders/vulkan_color_clear_frag_spv.h"
+#include "video_core/host_shaders/vulkan_color_clear_vert_spv.h"
#include "video_core/renderer_vulkan/blit_image.h"
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
@@ -69,10 +71,11 @@ constexpr VkDescriptorSetLayoutCreateInfo TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CRE
.bindingCount = static_cast<u32>(TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.size()),
.pBindings = TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.data(),
};
-constexpr VkPushConstantRange PUSH_CONSTANT_RANGE{
- .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
+template <VkShaderStageFlags stageFlags, size_t size>
+inline constexpr VkPushConstantRange PUSH_CONSTANT_RANGE{
+ .stageFlags = stageFlags,
.offset = 0,
- .size = sizeof(PushConstants),
+ .size = static_cast<u32>(size),
};
constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
@@ -125,10 +128,8 @@ constexpr VkPipelineMultisampleStateCreateInfo PIPELINE_MULTISAMPLE_STATE_CREATE
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
-constexpr std::array DYNAMIC_STATES{
- VK_DYNAMIC_STATE_VIEWPORT,
- VK_DYNAMIC_STATE_SCISSOR,
-};
+constexpr std::array DYNAMIC_STATES{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
+ VK_DYNAMIC_STATE_BLEND_CONSTANTS};
constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.pNext = nullptr,
@@ -205,15 +206,15 @@ inline constexpr VkSamplerCreateInfo SAMPLER_CREATE_INFO{
};
constexpr VkPipelineLayoutCreateInfo PipelineLayoutCreateInfo(
- const VkDescriptorSetLayout* set_layout) {
+ const VkDescriptorSetLayout* set_layout, vk::Span<VkPushConstantRange> push_constants) {
return VkPipelineLayoutCreateInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
- .setLayoutCount = 1,
+ .setLayoutCount = (set_layout != nullptr ? 1u : 0u),
.pSetLayouts = set_layout,
- .pushConstantRangeCount = 1,
- .pPushConstantRanges = &PUSH_CONSTANT_RANGE,
+ .pushConstantRangeCount = push_constants.size(),
+ .pPushConstantRanges = push_constants.data(),
};
}
@@ -302,8 +303,7 @@ void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descri
device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
}
-void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
- const Region2D& src_region, const Extent3D& src_size = {1, 1, 1}) {
+void BindBlitState(vk::CommandBuffer cmdbuf, const Region2D& dst_region) {
const VkOffset2D offset{
.x = std::min(dst_region.start.x, dst_region.end.x),
.y = std::min(dst_region.start.y, dst_region.end.y),
@@ -325,6 +325,13 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi
.offset = offset,
.extent = extent,
};
+ cmdbuf.SetViewport(0, viewport);
+ cmdbuf.SetScissor(0, scissor);
+}
+
+void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
+ const Region2D& src_region, const Extent3D& src_size = {1, 1, 1}) {
+ BindBlitState(cmdbuf, dst_region);
const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x) /
static_cast<float>(src_size.width);
const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y) /
@@ -335,8 +342,6 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi
static_cast<float>(src_region.start.y) /
static_cast<float>(src_size.height)},
};
- cmdbuf.SetViewport(0, viewport);
- cmdbuf.SetScissor(0, scissor);
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
}
@@ -408,13 +413,20 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
descriptor_pool.Allocator(*one_texture_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<1>)},
two_textures_descriptor_allocator{
descriptor_pool.Allocator(*two_textures_set_layout, TEXTURE_DESCRIPTOR_BANK_INFO<2>)},
- one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout(
- PipelineLayoutCreateInfo(one_texture_set_layout.address()))),
- two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout(
- PipelineLayoutCreateInfo(two_textures_set_layout.address()))),
+ one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
+ one_texture_set_layout.address(),
+ PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
+ two_textures_pipeline_layout(
+ device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
+ two_textures_set_layout.address(),
+ PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
+ clear_color_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
+ nullptr, PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 4>))),
full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)),
blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)),
+ clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)),
+ clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)),
convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
@@ -553,6 +565,30 @@ void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
}
+void BlitImageHelper::ClearColor(const Framebuffer* dst_framebuffer, u8 color_mask,
+ const std::array<f32, 4>& clear_color,
+ const Region2D& dst_region) {
+ const BlitImagePipelineKey key{
+ .renderpass = dst_framebuffer->RenderPass(),
+ .operation = Tegra::Engines::Fermi2D::Operation::BlendPremult,
+ };
+ const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key);
+ const VkPipelineLayout layout = *clear_color_pipeline_layout;
+ scheduler.RequestRenderpass(dst_framebuffer);
+ scheduler.Record(
+ [pipeline, layout, color_mask, clear_color, dst_region](vk::CommandBuffer cmdbuf) {
+ cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ const std::array blend_color = {
+ (color_mask & 0x1) ? 1.0f : 0.0f, (color_mask & 0x2) ? 1.0f : 0.0f,
+ (color_mask & 0x4) ? 1.0f : 0.0f, (color_mask & 0x8) ? 1.0f : 0.0f};
+ cmdbuf.SetBlendConstants(blend_color.data());
+ BindBlitState(cmdbuf, dst_region);
+ cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_color);
+ cmdbuf.Draw(3, 1, 0, 0);
+ });
+ scheduler.InvalidateState();
+}
+
void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) {
const VkPipelineLayout layout = *one_texture_pipeline_layout;
@@ -728,6 +764,58 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
return *blit_depth_stencil_pipelines.back();
}
+VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key) {
+ const auto it = std::ranges::find(clear_color_keys, key);
+ if (it != clear_color_keys.end()) {
+ return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)];
+ }
+ clear_color_keys.push_back(key);
+ const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag);
+ const VkPipelineColorBlendAttachmentState color_blend_attachment_state{
+ .blendEnable = VK_TRUE,
+ .srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR,
+ .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
+ .colorBlendOp = VK_BLEND_OP_ADD,
+ .srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
+ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
+ .alphaBlendOp = VK_BLEND_OP_ADD,
+ .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
+ };
+ const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .logicOpEnable = VK_FALSE,
+ .logicOp = VK_LOGIC_OP_CLEAR,
+ .attachmentCount = 1,
+ .pAttachments = &color_blend_attachment_state,
+ .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
+ };
+ clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .stageCount = static_cast<u32>(stages.size()),
+ .pStages = stages.data(),
+ .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .pTessellationState = nullptr,
+ .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+ .pColorBlendState = &color_blend_state_generic_create_info,
+ .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .layout = *clear_color_pipeline_layout,
+ .renderPass = key.renderpass,
+ .subpass = 0,
+ .basePipelineHandle = VK_NULL_HANDLE,
+ .basePipelineIndex = 0,
+ }));
+ return *clear_color_pipelines.back();
+}
+
void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
bool is_target_depth) {
if (pipeline) {
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index be8a9a2f6..2976a7d91 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -61,6 +61,9 @@ public:
void ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
+ void ClearColor(const Framebuffer* dst_framebuffer, u8 color_mask,
+ const std::array<f32, 4>& clear_color, const Region2D& dst_region);
+
private:
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view);
@@ -72,6 +75,8 @@ private:
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
+ [[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key);
+
void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth);
void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
@@ -97,9 +102,12 @@ private:
DescriptorAllocator two_textures_descriptor_allocator;
vk::PipelineLayout one_texture_pipeline_layout;
vk::PipelineLayout two_textures_pipeline_layout;
+ vk::PipelineLayout clear_color_pipeline_layout;
vk::ShaderModule full_screen_vert;
vk::ShaderModule blit_color_to_color_frag;
vk::ShaderModule blit_depth_stencil_frag;
+ vk::ShaderModule clear_color_vert;
+ vk::ShaderModule clear_color_frag;
vk::ShaderModule convert_depth_to_float_frag;
vk::ShaderModule convert_float_to_depth_frag;
vk::ShaderModule convert_abgr8_to_d24s8_frag;
@@ -112,6 +120,8 @@ private:
std::vector<vk::Pipeline> blit_color_pipelines;
std::vector<BlitImagePipelineKey> blit_depth_stencil_keys;
std::vector<vk::Pipeline> blit_depth_stencil_pipelines;
+ std::vector<BlitImagePipelineKey> clear_color_keys;
+ std::vector<vk::Pipeline> clear_color_pipelines;
vk::Pipeline convert_d32_to_r32_pipeline;
vk::Pipeline convert_r32_to_d32_pipeline;
vk::Pipeline convert_d16_to_r16_pipeline;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 86ef0daeb..719edbcfb 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -394,7 +394,15 @@ void RasterizerVulkan::Clear(u32 layer_count) {
cmdbuf.ClearAttachments(attachment, clear_rect);
});
} else {
- UNIMPLEMENTED_MSG("Unimplemented Clear only the specified channel");
+ u8 color_mask = static_cast<u8>(regs.clear_surface.R | regs.clear_surface.G << 1 |
+ regs.clear_surface.B << 2 | regs.clear_surface.A << 3);
+ Region2D dst_region = {
+ Offset2D{.x = clear_rect.rect.offset.x, .y = clear_rect.rect.offset.y},
+ Offset2D{.x = clear_rect.rect.offset.x +
+ static_cast<s32>(clear_rect.rect.extent.width),
+ .y = clear_rect.rect.offset.y +
+ static_cast<s32>(clear_rect.rect.extent.height)}};
+ blit_image.ClearColor(framebuffer, color_mask, regs.clear_color, dst_region);
}
}
diff --git a/src/video_core/texture_cache/descriptor_table.h b/src/video_core/texture_cache/descriptor_table.h
index ee4240288..1bad83fb4 100644
--- a/src/video_core/texture_cache/descriptor_table.h
+++ b/src/video_core/texture_cache/descriptor_table.h
@@ -19,9 +19,7 @@ public:
explicit DescriptorTable(Tegra::MemoryManager& gpu_memory_) : gpu_memory{gpu_memory_} {}
[[nodiscard]] bool Synchronize(GPUVAddr gpu_addr, u32 limit) {
- [[likely]] if (current_gpu_addr == gpu_addr && current_limit == limit) {
- return false;
- }
+ [[likely]] if (current_gpu_addr == gpu_addr && current_limit == limit) { return false; }
Refresh(gpu_addr, limit);
return true;
}
diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp
index 852ec2519..e9100091e 100644
--- a/src/video_core/texture_cache/image_info.cpp
+++ b/src/video_core/texture_cache/image_info.cpp
@@ -100,6 +100,10 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(config.texture_type.Value()));
break;
}
+ if (num_samples > 1) {
+ size.width *= NumSamplesX(config.msaa_mode);
+ size.height *= NumSamplesY(config.msaa_mode);
+ }
if (type != ImageType::Linear) {
// FIXME: Call this without passing *this
layer_stride = CalculateLayerStride(*this);
diff --git a/src/video_core/texture_cache/samples_helper.h b/src/video_core/texture_cache/samples_helper.h
index d552bccf0..203ac1b11 100644
--- a/src/video_core/texture_cache/samples_helper.h
+++ b/src/video_core/texture_cache/samples_helper.h
@@ -51,4 +51,48 @@ namespace VideoCommon {
return 1;
}
+[[nodiscard]] inline int NumSamplesX(Tegra::Texture::MsaaMode msaa_mode) {
+ using Tegra::Texture::MsaaMode;
+ switch (msaa_mode) {
+ case MsaaMode::Msaa1x1:
+ return 1;
+ case MsaaMode::Msaa2x1:
+ case MsaaMode::Msaa2x1_D3D:
+ case MsaaMode::Msaa2x2:
+ case MsaaMode::Msaa2x2_VC4:
+ case MsaaMode::Msaa2x2_VC12:
+ return 2;
+ case MsaaMode::Msaa4x2:
+ case MsaaMode::Msaa4x2_D3D:
+ case MsaaMode::Msaa4x2_VC8:
+ case MsaaMode::Msaa4x2_VC24:
+ case MsaaMode::Msaa4x4:
+ return 4;
+ }
+ ASSERT_MSG(false, "Invalid MSAA mode={}", static_cast<int>(msaa_mode));
+ return 1;
+}
+
+[[nodiscard]] inline int NumSamplesY(Tegra::Texture::MsaaMode msaa_mode) {
+ using Tegra::Texture::MsaaMode;
+ switch (msaa_mode) {
+ case MsaaMode::Msaa1x1:
+ case MsaaMode::Msaa2x1:
+ case MsaaMode::Msaa2x1_D3D:
+ return 1;
+ case MsaaMode::Msaa2x2:
+ case MsaaMode::Msaa2x2_VC4:
+ case MsaaMode::Msaa2x2_VC12:
+ case MsaaMode::Msaa4x2:
+ case MsaaMode::Msaa4x2_D3D:
+ case MsaaMode::Msaa4x2_VC8:
+ case MsaaMode::Msaa4x2_VC24:
+ return 2;
+ case MsaaMode::Msaa4x4:
+ return 4;
+ }
+ ASSERT_MSG(false, "Invalid MSAA mode={}", static_cast<int>(msaa_mode));
+ return 1;
+}
+
} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h
index 1e2aad76a..9df6a2903 100644
--- a/src/video_core/texture_cache/slot_vector.h
+++ b/src/video_core/texture_cache/slot_vector.h
@@ -29,7 +29,7 @@ struct SlotId {
};
template <class T>
-requires std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<T>
+ requires std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<T>
class SlotVector {
public:
class Iterator {
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 4b7e3b01b..723690e71 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -182,12 +182,13 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : "");
const QString inverted = QString::fromStdString(param.Get("inverted", false) ? "!" : "");
const QString invert = QString::fromStdString(param.Get("invert", "+") == "-" ? "-" : "");
+ const QString turbo = QString::fromStdString(param.Get("turbo", false) ? "$" : "");
const auto common_button_name = input_subsystem->GetButtonName(param);
// Retrieve the names from Qt
if (param.Get("engine", "") == "keyboard") {
const QString button_str = GetKeyName(param.Get("code", 0));
- return QObject::tr("%1%2%3").arg(toggle, inverted, button_str);
+ return QObject::tr("%1%2%3%4").arg(turbo, toggle, inverted, button_str);
}
if (common_button_name == Common::Input::ButtonNames::Invalid) {
@@ -201,7 +202,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
if (common_button_name == Common::Input::ButtonNames::Value) {
if (param.Has("hat")) {
const QString hat = GetDirectionName(param.Get("direction", ""));
- return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat);
+ return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, hat);
}
if (param.Has("axis")) {
const QString axis = QString::fromStdString(param.Get("axis", ""));
@@ -219,13 +220,13 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
}
if (param.Has("button")) {
const QString button = QString::fromStdString(param.Get("button", ""));
- return QObject::tr("%1%2Button %3").arg(toggle, inverted, button);
+ return QObject::tr("%1%2%3Button %4").arg(turbo, toggle, inverted, button);
}
}
QString button_name = GetButtonName(common_button_name);
if (param.Has("hat")) {
- return QObject::tr("%1%2Hat %3").arg(toggle, inverted, button_name);
+ return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name);
}
if (param.Has("axis")) {
return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name);
@@ -234,7 +235,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name);
}
if (param.Has("button")) {
- return QObject::tr("%1%2Button %3").arg(toggle, inverted, button_name);
+ return QObject::tr("%1%2%3Button %4").arg(turbo, toggle, inverted, button_name);
}
return QObject::tr("[unknown]");
@@ -395,6 +396,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
button_map[button_id]->setText(ButtonToText(param));
emulated_controller->SetButtonParam(button_id, param);
});
+ context_menu.addAction(tr("Turbo button"), [&] {
+ const bool turbo_value = !param.Get("turbo", false);
+ param.Set("turbo", turbo_value);
+ button_map[button_id]->setText(ButtonToText(param));
+ emulated_controller->SetButtonParam(button_id, param);
+ });
}
if (param.Has("axis")) {
context_menu.addAction(tr("Invert axis"), [&] {
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 68af6c20c..c287220fc 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -81,7 +81,6 @@ void PlayerControlPreview::UpdateColors() {
colors.outline = QColor(0, 0, 0);
colors.primary = QColor(225, 225, 225);
colors.button = QColor(109, 111, 114);
- colors.button2 = QColor(109, 111, 114);
colors.button2 = QColor(77, 80, 84);
colors.slider_arrow = QColor(65, 68, 73);
colors.font2 = QColor(0, 0, 0);
@@ -100,6 +99,7 @@ void PlayerControlPreview::UpdateColors() {
colors.led_off = QColor(170, 238, 255);
colors.indicator2 = QColor(59, 165, 93);
colors.charging = QColor(250, 168, 26);
+ colors.button_turbo = QColor(217, 158, 4);
colors.left = colors.primary;
colors.right = colors.primary;
@@ -2469,7 +2469,6 @@ void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center,
void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& pressed, float width,
float height, Direction direction, float radius) {
- p.setBrush(button_color);
if (pressed.value) {
switch (direction) {
case Direction::Left:
@@ -2487,16 +2486,16 @@ void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center,
case Direction::None:
break;
}
- p.setBrush(colors.highlight);
}
QRectF rect = {center.x() - width, center.y() - height, width * 2.0f, height * 2.0f};
+ p.setBrush(GetButtonColor(button_color, pressed.value, pressed.turbo));
p.drawRoundedRect(rect, radius, radius);
}
void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center,
const Common::Input::ButtonStatus& pressed,
int button_size) {
p.setPen(colors.outline);
- p.setBrush(pressed.value ? colors.highlight : colors.button);
+ p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
DrawRectangle(p, center, button_size, button_size / 3.0f);
}
void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center,
@@ -2504,7 +2503,7 @@ void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center,
int button_size) {
// Draw outer line
p.setPen(colors.outline);
- p.setBrush(pressed.value ? colors.highlight : colors.button);
+ p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
DrawRectangle(p, center, button_size, button_size / 3.0f);
DrawRectangle(p, center, button_size / 3.0f, button_size);
@@ -2526,7 +2525,7 @@ void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center,
}
p.setPen(colors.outline);
- p.setBrush(pressed.value ? colors.highlight : colors.button);
+ p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
DrawPolygon(p, button_x);
}
@@ -2539,7 +2538,7 @@ void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center,
}
p.setPen(colors.outline);
- p.setBrush(pressed.value ? colors.highlight : colors.button);
+ p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
DrawPolygon(p, button_x);
}
@@ -2553,17 +2552,15 @@ void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center,
}
p.setPen(colors.outline);
- p.setBrush(pressed.value ? colors.highlight : colors.button2);
+ p.setBrush(GetButtonColor(colors.button2, pressed.value, pressed.turbo));
DrawPolygon(p, button_x);
}
void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center,
const Common::Input::ButtonStatus& pressed,
float button_size) {
- p.setBrush(button_color);
- if (pressed.value) {
- p.setBrush(colors.highlight);
- }
+
+ p.setBrush(GetButtonColor(button_color, pressed.value, pressed.turbo));
p.drawEllipse(center, button_size, button_size);
}
@@ -2620,7 +2617,7 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
// Draw arrow button
p.setPen(pressed.value ? colors.highlight : colors.button);
- p.setBrush(pressed.value ? colors.highlight : colors.button);
+ p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
DrawPolygon(p, arrow_button);
switch (direction) {
@@ -2672,10 +2669,20 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center,
// Draw arrow button
p.setPen(colors.outline);
- p.setBrush(pressed.value ? colors.highlight : colors.button);
+ p.setBrush(GetButtonColor(colors.button, pressed.value, pressed.turbo));
DrawPolygon(p, qtrigger_button);
}
+QColor PlayerControlPreview::GetButtonColor(QColor default_color, bool is_pressed, bool turbo) {
+ if (is_pressed && turbo) {
+ return colors.button_turbo;
+ }
+ if (is_pressed) {
+ return colors.highlight;
+ }
+ return default_color;
+}
+
void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center,
Common::Input::BatteryLevel battery) {
if (battery == Common::Input::BatteryLevel::None) {
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index b258c6d77..0e9e95e85 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -81,6 +81,7 @@ private:
QColor right{};
QColor button{};
QColor button2{};
+ QColor button_turbo{};
QColor font{};
QColor font2{};
QColor highlight{};
@@ -183,6 +184,7 @@ private:
const Common::Input::ButtonStatus& pressed, float size = 1.0f);
void DrawTriggerButton(QPainter& p, QPointF center, Direction direction,
const Common::Input::ButtonStatus& pressed);
+ QColor GetButtonColor(QColor default_color, bool is_pressed, bool turbo);
// Draw battery functions
void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery);
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp
index 9bb69cab1..41ef4250a 100644
--- a/src/yuzu/configuration/input_profiles.cpp
+++ b/src/yuzu/configuration/input_profiles.cpp
@@ -58,13 +58,16 @@ std::vector<std::string> InputProfiles::GetInputProfileNames() {
std::vector<std::string> profile_names;
profile_names.reserve(map_profiles.size());
- for (const auto& [profile_name, config] : map_profiles) {
+ auto it = map_profiles.cbegin();
+ while (it != map_profiles.cend()) {
+ const auto& [profile_name, config] = *it;
if (!ProfileExistsInFilesystem(profile_name)) {
- DeleteProfile(profile_name);
+ it = map_profiles.erase(it);
continue;
}
profile_names.push_back(profile_name);
+ ++it;
}
std::stable_sort(profile_names.begin(), profile_names.end());
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp
index 08c275696..6c93e3511 100644
--- a/src/yuzu/multiplayer/lobby.cpp
+++ b/src/yuzu/multiplayer/lobby.cpp
@@ -77,6 +77,7 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
// UI Buttons
connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby);
connect(ui->games_owned, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterOwned);
+ connect(ui->hide_empty, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterEmpty);
connect(ui->hide_full, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterFull);
connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);
connect(ui->room_list, &QTreeView::doubleClicked, this, &Lobby::OnJoinRoom);
@@ -329,6 +330,16 @@ bool LobbyFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
return true;
}
+ // filter by empty rooms
+ if (filter_empty) {
+ QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent);
+ int player_count =
+ sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size();
+ if (player_count == 0) {
+ return false;
+ }
+ }
+
// filter by filled rooms
if (filter_full) {
QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent);
@@ -399,6 +410,11 @@ void LobbyFilterProxyModel::SetFilterOwned(bool filter) {
invalidate();
}
+void LobbyFilterProxyModel::SetFilterEmpty(bool filter) {
+ filter_empty = filter;
+ invalidate();
+}
+
void LobbyFilterProxyModel::SetFilterFull(bool filter) {
filter_full = filter;
invalidate();
diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h
index 300dad13e..2674ae7c3 100644
--- a/src/yuzu/multiplayer/lobby.h
+++ b/src/yuzu/multiplayer/lobby.h
@@ -130,12 +130,14 @@ public:
public slots:
void SetFilterOwned(bool);
+ void SetFilterEmpty(bool);
void SetFilterFull(bool);
void SetFilterSearch(const QString&);
private:
QStandardItemModel* game_list;
bool filter_owned = false;
+ bool filter_empty = false;
bool filter_full = false;
QString filter_search;
};
diff --git a/src/yuzu/multiplayer/lobby.ui b/src/yuzu/multiplayer/lobby.ui
index 4c9901c9a..0ef0ef762 100644
--- a/src/yuzu/multiplayer/lobby.ui
+++ b/src/yuzu/multiplayer/lobby.ui
@@ -78,6 +78,13 @@
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="hide_empty">
+ <property name="text">
+ <string>Hide Empty Rooms</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QCheckBox" name="hide_full">
<property name="text">
<string>Hide Full Rooms</string>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 527017282..9c34cdc6e 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -176,6 +176,9 @@ void Config::ReadValues() {
Settings::values.debug_pad_analogs[i] = default_param;
}
+ ReadSetting("ControlsGeneral", Settings::values.enable_raw_input);
+ ReadSetting("ControlsGeneral", Settings::values.enable_joycon_driver);
+ ReadSetting("ControlsGeneral", Settings::values.emulate_analog_keyboard);
ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 67d230462..3f3651dbe 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -14,6 +14,7 @@ const char* sdl2_config_file =
# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values
# Indicates if this player should be connected at boot
+# 0 (default): Disabled, 1: Enabled
connected=
# for button input, the following devices are available:
@@ -94,6 +95,18 @@ motionright=
# 0 (default): Disabled, 1: Enabled
debug_pad_enabled =
+# Enable sdl raw input. Allows to configure up to 8 xinput controllers.
+# 0 (default): Disabled, 1: Enabled
+enable_raw_input =
+
+# Enable yuzu joycon driver instead of SDL drive.
+# 0: Disabled, 1 (default): Enabled
+enable_joycon_driver =
+
+# Emulates an analog input from buttons. Allowing to dial any angle.
+# 0 (default): Disabled, 1: Enabled
+emulate_analog_keyboard =
+
# Whether to enable or disable vibration
# 0: Disabled, 1 (default): Enabled
vibration_enabled=
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 31f28a507..5450b8c38 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -18,11 +18,11 @@
EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
: input_subsystem{input_subsystem_}, system{system_} {
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
+ input_subsystem->Initialize();
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting...");
exit(1);
}
- input_subsystem->Initialize();
SDL_SetMainReady();
}
@@ -32,10 +32,6 @@ EmuWindow_SDL2::~EmuWindow_SDL2() {
SDL_Quit();
}
-void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
- input_subsystem->GetMouse()->MouseMove(x, y, 0, 0, 0, 0);
-}
-
InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const {
switch (button) {
case SDL_BUTTON_LEFT:
@@ -53,44 +49,36 @@ InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) cons
}
}
+std::pair<float, float> EmuWindow_SDL2::MouseToTouchPos(s32 touch_x, s32 touch_y) const {
+ int w, h;
+ SDL_GetWindowSize(render_window, &w, &h);
+ const float fx = static_cast<float>(touch_x) / w;
+ const float fy = static_cast<float>(touch_y) / h;
+
+ return {std::clamp<float>(fx, 0.0f, 1.0f), std::clamp<float>(fy, 0.0f, 1.0f)};
+}
+
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
const auto mouse_button = SDLButtonToMouseButton(button);
if (state == SDL_PRESSED) {
- input_subsystem->GetMouse()->PressButton(x, y, 0, 0, mouse_button);
+ const auto [touch_x, touch_y] = MouseToTouchPos(x, y);
+ input_subsystem->GetMouse()->PressButton(x, y, touch_x, touch_y, mouse_button);
} else {
input_subsystem->GetMouse()->ReleaseButton(mouse_button);
}
}
-std::pair<unsigned, unsigned> EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const {
- int w, h;
- SDL_GetWindowSize(render_window, &w, &h);
-
- touch_x *= w;
- touch_y *= h;
-
- return {static_cast<unsigned>(std::max(std::round(touch_x), 0.0f)),
- static_cast<unsigned>(std::max(std::round(touch_y), 0.0f))};
+void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
+ const auto [touch_x, touch_y] = MouseToTouchPos(x, y);
+ input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, 0, 0);
}
void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) {
- int width, height;
- SDL_GetWindowSize(render_window, &width, &height);
- const auto [px, py] = TouchToPixelPos(x, y);
- const float fx = px * 1.0f / width;
- const float fy = py * 1.0f / height;
-
- input_subsystem->GetTouchScreen()->TouchPressed(fx, fy, id);
+ input_subsystem->GetTouchScreen()->TouchPressed(x, y, id);
}
void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) {
- int width, height;
- SDL_GetWindowSize(render_window, &width, &height);
- const auto [px, py] = TouchToPixelPos(x, y);
- const float fx = px * 1.0f / width;
- const float fy = py * 1.0f / height;
-
- input_subsystem->GetTouchScreen()->TouchMoved(fx, fy, id);
+ input_subsystem->GetTouchScreen()->TouchMoved(x, y, id);
}
void EmuWindow_SDL2::OnFingerUp() {
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index 25c23e2a5..d9b453dee 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -38,17 +38,17 @@ protected:
/// Called by WaitEvent when a key is pressed or released.
void OnKeyEvent(int key, u8 state);
- /// Called by WaitEvent when the mouse moves.
- void OnMouseMotion(s32 x, s32 y);
-
/// Converts a SDL mouse button into MouseInput mouse button
InputCommon::MouseButton SDLButtonToMouseButton(u32 button) const;
+ /// Translates pixel position to float position
+ std::pair<float, float> MouseToTouchPos(s32 touch_x, s32 touch_y) const;
+
/// Called by WaitEvent when a mouse button is pressed or released
void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
- /// Translates pixel position (0..1) to pixel positions
- std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const;
+ /// Called by WaitEvent when the mouse moves.
+ void OnMouseMotion(s32 x, s32 y);
/// Called by WaitEvent when a finger starts touching the touchscreen
void OnFingerDown(float x, float y, std::size_t id);
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 91133569d..d1f7b1d49 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -62,13 +62,15 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
static void PrintHelp(const char* argv0) {
std::cout << "Usage: " << argv0
<< " [options] <filename>\n"
- "-m, --multiplayer=nick:password@address:port"
- " Nickname, password, address and port for multiplayer\n"
+ "-c, --config Load the specified configuration file\n"
"-f, --fullscreen Start in fullscreen mode\n"
+ "-g, --game File path of the game to load\n"
"-h, --help Display this help and exit\n"
- "-v, --version Output version information and exit\n"
+ "-m, --multiplayer=nick:password@address:port"
+ " Nickname, password, address and port for multiplayer\n"
"-p, --program Pass following string as arguments to executable\n"
- "-c, --config Load the specified configuration file\n";
+ "-u, --user Select a specific user profile from 0 to 7\n"
+ "-v, --version Output version information and exit\n";
}
static void PrintVersion() {
@@ -199,6 +201,7 @@ int main(int argc, char** argv) {
std::string filepath;
std::optional<std::string> config_path;
std::string program_args;
+ std::optional<int> selected_user;
bool use_multiplayer = false;
bool fullscreen = false;
@@ -209,12 +212,14 @@ int main(int argc, char** argv) {
static struct option long_options[] = {
// clang-format off
- {"multiplayer", required_argument, 0, 'm'},
+ {"config", required_argument, 0, 'c'},
{"fullscreen", no_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'v'},
+ {"game", required_argument, 0, 'g'},
+ {"multiplayer", required_argument, 0, 'm'},
{"program", optional_argument, 0, 'p'},
- {"config", required_argument, 0, 'c'},
+ {"user", required_argument, 0, 'u'},
+ {"version", no_argument, 0, 'v'},
{0, 0, 0, 0},
// clang-format on
};
@@ -223,6 +228,21 @@ int main(int argc, char** argv) {
int arg = getopt_long(argc, argv, "g:fhvp::c:", long_options, &option_index);
if (arg != -1) {
switch (static_cast<char>(arg)) {
+ case 'c':
+ config_path = optarg;
+ break;
+ case 'f':
+ fullscreen = true;
+ LOG_INFO(Frontend, "Starting in fullscreen mode...");
+ break;
+ case 'h':
+ PrintHelp(argv[0]);
+ return 0;
+ case 'g': {
+ const std::string str_arg(optarg);
+ filepath = str_arg;
+ break;
+ }
case 'm': {
use_multiplayer = true;
const std::string str_arg(optarg);
@@ -255,23 +275,16 @@ int main(int argc, char** argv) {
}
break;
}
- case 'f':
- fullscreen = true;
- LOG_INFO(Frontend, "Starting in fullscreen mode...");
+ case 'p':
+ program_args = argv[optind];
+ ++optind;
break;
- case 'h':
- PrintHelp(argv[0]);
+ case 'u':
+ selected_user = atoi(optarg);
return 0;
case 'v':
PrintVersion();
return 0;
- case 'p':
- program_args = argv[optind];
- ++optind;
- break;
- case 'c':
- config_path = optarg;
- break;
}
} else {
#ifdef _WIN32
@@ -295,6 +308,10 @@ int main(int argc, char** argv) {
Settings::values.program_args = program_args;
}
+ if (selected_user.has_value()) {
+ Settings::values.current_user = std::clamp(*selected_user, 0, 7);
+ }
+
#ifdef _WIN32
LocalFree(argv_w);
#endif