Compare commits

..

30 Commits

Author SHA1 Message Date
Morph
1a46823ec5 parcel: Optimize small_vector sizes 2023-06-30 22:05:28 -04:00
Morph
5a09fa5012 maxwell_dma: Specify dst_operand.pitch instead of a temp var 2023-06-30 21:49:59 -04:00
Morph
310b6cf4af general: Use ScratchBuffer where possible 2023-06-30 21:49:59 -04:00
Morph
fbd85417ff ring_buffer: Fix const usage on std::span 2023-06-30 13:33:14 -04:00
Morph
b8c906f9d1 scratch_buffer: Add member types to ScratchBuffer
Allows for implicit conversion to std::span<T>.
2023-06-30 13:33:13 -04:00
Fernando S
9252ad4e10 Merge pull request #10956 from FernandoS27/pikmin-another-game-ill-hate
AccelerateDMA: Don't accelerate 3D texture DMA operations
2023-06-30 09:37:07 +02:00
Fernando Sahmkow
596a6132b9 AccelerateDMA: Don't accelerate 3D texture DMA operations 2023-06-29 17:23:29 +02:00
Charles Lombardo
45be4c3214 Merge pull request #10955 from 8bitDream/gradle
android: Suppress a known incompatibility
2023-06-29 11:07:00 -04:00
liamwhite
5e70db0d43 Merge pull request #10935 from Morph1984/mwaitx
x64: Make use of monitorx instructions for power efficient sleeps (AMD)
2023-06-29 10:01:26 -04:00
liamwhite
4c705db73e Merge pull request #10937 from german77/ring
input_common: Remove duplicated enum and fix ring detection
2023-06-29 10:01:19 -04:00
liamwhite
7de778ad39 Merge pull request #10946 from goldenx86/amdBlending
Blacklist EDS3 blending from new AMD drivers
2023-06-29 10:01:11 -04:00
Abandoned Cart
13506e7782 android: Suppress a known incompatibility
Android Gradle plugin 8.0.2 is designed for API 33, but a newer plugin hasn't been released yet. The warning message is rather extravagant, but also suggests adding this property if you are aware of the risks.
2023-06-29 07:32:12 -04:00
german77
ac755476cd input_common: Allow timeouts to happen while scanning for a ring 2023-06-29 01:07:39 -06:00
bunnei
217e958a95 Merge pull request #10945 from t895/android-14
android: Android 14 support
2023-06-28 16:30:12 -07:00
Matías Locatti
ed93cbd462 Blacklist EDS3 blending from new AMD drivers 2023-06-28 20:10:27 -03:00
Charles Lombardo
b76b698c17 android: Android 14 support
Specifies the permissions needed for the changes to foreground services in Android 14.
2023-06-28 16:15:18 -04:00
liamwhite
b60b70e86d Merge pull request #10837 from liamwhite/mali-support
android: Mali support
2023-06-28 12:53:17 -04:00
german77
df9685a21c input_common: Remove duplicated DriverResult enum 2023-06-28 09:49:47 -06:00
Morph
295fc7d0f8 x64: cpu_wait: Implement MWAITX for non-MSVC compilers 2023-06-28 01:39:15 -04:00
Morph
2b68a3cbbf x64: cpu_wait: Remove magic values 2023-06-28 01:39:06 -04:00
Morph
3d868baaa4 x64: cpu_wait: Make use of MWAITX in MicroSleep
MWAITX is equivalent to UMWAIT on Intel's Alder Lake CPUs.
We can emulate TPAUSE by using MONITORX in conjunction with MWAITX to wait for 100K cycles.
2023-06-28 01:38:55 -04:00
Morph
4303ed614d x64: Add detection of monitorx instructions
monitorx introduces 2 instructions: MONITORX and MWAITX.
2023-06-28 01:36:06 -04:00
GPUCode
ddcc958336 renderer_vulkan: Prevent crashes when blitting depth stencil 2023-06-27 18:00:09 -07:00
GPUCode
eac46ad7ce video_core: Add BCn decoding support 2023-06-27 18:00:09 -07:00
GPUCode
b8c96cee5f renderer_vulkan: Add more feature checking 2023-06-27 18:00:09 -07:00
GPUCode
220a42896d renderer_vulkan: Don't assume debug tool with debug renderer
* Causes crashes because mali drivers don't support debug utils
2023-06-27 18:00:09 -07:00
GPUCode
1522b95658 renderer_vulkan: Bump minimum SPIRV version
* 1.3 is guaranteed on all 1.1 drivers
2023-06-27 18:00:09 -07:00
GPUCode
c339af37a7 renderer_vulkan: Respect viewport limit 2023-06-27 18:00:09 -07:00
GPUCode
a9b44d37e1 renderer_vulkan: Don't add transform feedback flag if unsupported 2023-06-27 18:00:09 -07:00
GPUCode
72e7f5b4dd renderer_vulkan: Add suport for debug report callback 2023-06-27 18:00:09 -07:00
83 changed files with 2788 additions and 859 deletions

View File

@@ -157,6 +157,9 @@ endif()
add_library(stb stb/stb_dxt.cpp)
target_include_directories(stb PUBLIC ./stb)
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
if (ANDROID)
if (ARCHITECTURE_arm64)
add_subdirectory(libadrenotools)

1522
externals/bc_decoder/bc_decoder.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

43
externals/bc_decoder/bc_decoder.h vendored Normal file
View File

@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <cstdint>
namespace bcn {
/**
* @brief Decodes a BC1 encoded image to R8G8B8A8
*/
void DecodeBc1(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC2 encoded image to R8G8B8A8
*/
void DecodeBc2(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC3 encoded image to R8G8B8A8
*/
void DecodeBc3(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC4 encoded image to R8
*/
void DecodeBc4(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC5 encoded image to R8G8
*/
void DecodeBc5(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC6 encoded image to R16G16B16A16
*/
void DecodeBc6(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC7 encoded image to R8G8B8A8
*/
void DecodeBc7(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
}

View File

@@ -26,7 +26,7 @@ val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toIn
android {
namespace = "org.yuzu.yuzu_emu"
compileSdkVersion = "android-33"
compileSdkVersion = "android-34"
ndkVersion = "25.2.9519653"
buildFeatures {
@@ -51,7 +51,7 @@ android {
// TODO If this is ever modified, change application_id in strings.xml
applicationId = "org.yuzu.yuzu_emu"
minSdk = 30
targetSdk = 33
targetSdk = 34
versionName = getGitVersion()
// If you want to use autoVersion for the versionCode, create a property in local.properties

View File

@@ -13,6 +13,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
@@ -69,7 +70,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:resource="@xml/nfc_tech_filter" />
</activity>
<service android:name="org.yuzu.yuzu_emu.utils.ForegroundService"/>
<service android:name="org.yuzu.yuzu_emu.utils.ForegroundService" android:foregroundServiceType="specialUse">
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="Keep emulation running in background"/>
</service>
<provider
android:name=".features.DocumentProvider"

View File

@@ -15,3 +15,6 @@ android.useAndroidX=true
kotlin.code.style=official
kotlin.parallel.tasks.in.project=true
android.defaults.buildfeatures.buildconfig=true
# Android Gradle plugin 8.0.2
android.suppressUnsupportedCompileSdk=34

View File

@@ -75,8 +75,10 @@ enum class DriverResult {
ErrorWritingData,
NoDeviceDetected,
InvalidHandle,
InvalidParameters,
NotSupported,
Disabled,
Delayed,
Unknown,
};

View File

@@ -54,7 +54,7 @@ public:
return push_count;
}
std::size_t Push(const std::span<T> input) {
std::size_t Push(std::span<const T> input) {
return Push(input.data(), input.size());
}

View File

@@ -5,7 +5,6 @@
#include <iterator>
#include "common/concepts.h"
#include "common/make_unique_for_overwrite.h"
namespace Common {
@@ -19,15 +18,22 @@ namespace Common {
template <typename T>
class ScratchBuffer {
public:
using iterator = T*;
using const_iterator = const T*;
using value_type = T;
using element_type = T;
using iterator_category = std::contiguous_iterator_tag;
using value_type = T;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = pointer;
using const_iterator = const_pointer;
using iterator_category = std::random_access_iterator_tag;
using iterator_concept = std::contiguous_iterator_tag;
ScratchBuffer() = default;
explicit ScratchBuffer(size_t initial_capacity)
explicit ScratchBuffer(size_type initial_capacity)
: last_requested_size{initial_capacity}, buffer_capacity{initial_capacity},
buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
@@ -39,7 +45,7 @@ public:
/// This will only grow the buffer's capacity if size is greater than the current capacity.
/// The previously held data will remain intact.
void resize(size_t size) {
void resize(size_type size) {
if (size > buffer_capacity) {
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get());
@@ -51,7 +57,7 @@ public:
/// This will only grow the buffer's capacity if size is greater than the current capacity.
/// The previously held data will be destroyed if a reallocation occurs.
void resize_destructive(size_t size) {
void resize_destructive(size_type size) {
if (size > buffer_capacity) {
buffer_capacity = size;
buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity);
@@ -59,43 +65,43 @@ public:
last_requested_size = size;
}
[[nodiscard]] T* data() noexcept {
[[nodiscard]] pointer data() noexcept {
return buffer.get();
}
[[nodiscard]] const T* data() const noexcept {
[[nodiscard]] const_pointer data() const noexcept {
return buffer.get();
}
[[nodiscard]] T* begin() noexcept {
[[nodiscard]] iterator begin() noexcept {
return data();
}
[[nodiscard]] const T* begin() const noexcept {
[[nodiscard]] const_iterator begin() const noexcept {
return data();
}
[[nodiscard]] T* end() noexcept {
[[nodiscard]] iterator end() noexcept {
return data() + last_requested_size;
}
[[nodiscard]] const T* end() const noexcept {
[[nodiscard]] const_iterator end() const noexcept {
return data() + last_requested_size;
}
[[nodiscard]] T& operator[](size_t i) {
[[nodiscard]] reference operator[](size_type i) {
return buffer[i];
}
[[nodiscard]] const T& operator[](size_t i) const {
[[nodiscard]] const_reference operator[](size_type i) const {
return buffer[i];
}
[[nodiscard]] size_t size() const noexcept {
[[nodiscard]] size_type size() const noexcept {
return last_requested_size;
}
[[nodiscard]] size_t capacity() const noexcept {
[[nodiscard]] size_type capacity() const noexcept {
return buffer_capacity;
}
@@ -106,8 +112,8 @@ public:
}
private:
size_t last_requested_size{};
size_t buffer_capacity{};
size_type last_requested_size{};
size_type buffer_capacity{};
std::unique_ptr<T[]> buffer{};
};

View File

@@ -527,10 +527,12 @@ struct Values {
Setting<bool> mouse_panning{false, "mouse_panning"};
Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"};
Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"};
Setting<u8, true> mouse_panning_deadzone_counterweight{20, 0, 100,
"mouse_panning_deadzone_counterweight"};
Setting<u8, true> mouse_panning_decay_strength{18, 0, 100, "mouse_panning_decay_strength"};
Setting<u8, true> mouse_panning_min_decay{6, 0, 100, "mouse_panning_min_decay"};
Setting<u8, true> mouse_panning_deadzone_x_counterweight{
0, 0, 100, "mouse_panning_deadzone_x_counterweight"};
Setting<u8, true> mouse_panning_deadzone_y_counterweight{
0, 0, 100, "mouse_panning_deadzone_y_counterweight"};
Setting<u8, true> mouse_panning_decay_strength{22, 0, 100, "mouse_panning_decay_strength"};
Setting<u8, true> mouse_panning_min_decay{5, 0, 100, "mouse_panning_min_decay"};
Setting<bool> mouse_enabled{false, "mouse_enabled"};
Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};

View File

@@ -93,6 +93,7 @@ void AppendCPUInfo(FieldCollection& fc) {
add_field("CPU_Extension_x64_GFNI", caps.gfni);
add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc);
add_field("CPU_Extension_x64_LZCNT", caps.lzcnt);
add_field("CPU_Extension_x64_MONITORX", caps.monitorx);
add_field("CPU_Extension_x64_MOVBE", caps.movbe);
add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq);
add_field("CPU_Extension_x64_POPCNT", caps.popcnt);

View File

@@ -168,6 +168,7 @@ static CPUCaps Detect() {
__cpuid(cpu_id, 0x80000001);
caps.lzcnt = Common::Bit<5>(cpu_id[2]);
caps.fma4 = Common::Bit<16>(cpu_id[2]);
caps.monitorx = Common::Bit<29>(cpu_id[2]);
}
if (max_ex_fn >= 0x80000007) {

View File

@@ -63,6 +63,7 @@ struct CPUCaps {
bool gfni : 1;
bool invariant_tsc : 1;
bool lzcnt : 1;
bool monitorx : 1;
bool movbe : 1;
bool pclmulqdq : 1;
bool popcnt : 1;

View File

@@ -13,36 +13,60 @@
namespace Common::X64 {
namespace {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
constexpr auto PauseCycles = 100'000U;
} // Anonymous namespace
#ifdef _MSC_VER
__forceinline static void TPAUSE() {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
static constexpr auto PauseCycles = 100'000;
_tpause(0, FencedRDTSC() + PauseCycles);
static constexpr auto RequestC02State = 0U;
_tpause(RequestC02State, FencedRDTSC() + PauseCycles);
}
__forceinline static void MWAITX() {
static constexpr auto EnableWaitTimeFlag = 1U << 1;
static constexpr auto RequestC1State = 0U;
// monitor_var should be aligned to a cache line.
alignas(64) u64 monitor_var{};
_mm_monitorx(&monitor_var, 0, 0);
_mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles);
}
#else
static void TPAUSE() {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
static constexpr auto PauseCycles = 100'000;
static constexpr auto RequestC02State = 0U;
const auto tsc = FencedRDTSC() + PauseCycles;
const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
const auto edx = static_cast<u32>(tsc >> 32);
asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax));
asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax));
}
static void MWAITX() {
static constexpr auto EnableWaitTimeFlag = 1U << 1;
static constexpr auto RequestC1State = 0U;
// monitor_var should be aligned to a cache line.
alignas(64) u64 monitor_var{};
asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0));
asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag));
}
#endif
void MicroSleep() {
static const bool has_waitpkg = GetCPUCaps().waitpkg;
static const bool has_monitorx = GetCPUCaps().monitorx;
if (has_waitpkg) {
TPAUSE();
} else if (has_monitorx) {
MWAITX();
} else {
std::this_thread::yield();
}

View File

@@ -5,7 +5,7 @@
#include "audio_core/renderer/audio_device.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/scratch_buffer.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
@@ -124,12 +124,15 @@ private:
void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
tmp_buffer.resize_destructive(write_buffer_size);
tmp_buffer[0] = 0;
released_buffer.resize_destructive(write_buffer_size);
released_buffer[0] = 0;
const auto count = impl->GetReleasedBuffers(tmp_buffer);
const auto count = impl->GetReleasedBuffers(released_buffer);
ctx.WriteBuffer(tmp_buffer);
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
impl->GetSystem().GetSessionId(), count);
ctx.WriteBuffer(released_buffer);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -155,7 +158,6 @@ private:
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(buffer_count);
}
@@ -195,7 +197,7 @@ private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event;
std::shared_ptr<AudioCore::AudioIn::In> impl;
Common::ScratchBuffer<u64> tmp_buffer;
Common::ScratchBuffer<u64> released_buffer;
};
AudInU::AudInU(Core::System& system_)

View File

@@ -9,6 +9,7 @@
#include "audio_core/renderer/audio_device.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/scratch_buffer.h"
#include "common/string_util.h"
#include "common/swap.h"
#include "core/core.h"
@@ -102,8 +103,8 @@ private:
AudioOutBuffer buffer{};
std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer));
[[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag);
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
impl->GetSystem().GetSessionId(), tag);
auto result = impl->AppendBuffer(buffer, tag);
@@ -123,12 +124,15 @@ private:
void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
tmp_buffer.resize_destructive(write_buffer_size);
tmp_buffer[0] = 0;
released_buffer.resize_destructive(write_buffer_size);
released_buffer[0] = 0;
const auto count = impl->GetReleasedBuffers(tmp_buffer);
const auto count = impl->GetReleasedBuffers(released_buffer);
ctx.WriteBuffer(tmp_buffer);
ctx.WriteBuffer(released_buffer);
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
impl->GetSystem().GetSessionId(), count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -154,7 +158,6 @@ private:
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(buffer_count);
}
@@ -165,7 +168,6 @@ private:
LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(samples_played);
}
@@ -205,7 +207,7 @@ private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event;
std::shared_ptr<AudioCore::AudioOut::Out> impl;
Common::ScratchBuffer<u64> tmp_buffer;
Common::ScratchBuffer<u64> released_buffer;
};
AudOutU::AudOutU(Core::System& system_)

View File

@@ -15,6 +15,7 @@
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/polyfill_ranges.h"
#include "common/scratch_buffer.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
@@ -119,23 +120,23 @@ private:
auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
if (is_buffer_b) {
const auto buffersB{ctx.BufferDescriptorB()};
tmp_output.resize_destructive(buffersB[0].Size());
tmp_performance.resize_destructive(buffersB[1].Size());
output_buffer.resize_destructive(buffersB[0].Size());
performance_buffer.resize_destructive(buffersB[1].Size());
} else {
const auto buffersC{ctx.BufferDescriptorC()};
tmp_output.resize_destructive(buffersC[0].Size());
tmp_performance.resize_destructive(buffersC[1].Size());
output_buffer.resize_destructive(buffersC[0].Size());
performance_buffer.resize_destructive(buffersC[1].Size());
}
auto result = impl->RequestUpdate(input, tmp_performance, tmp_output);
auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
if (result.IsSuccess()) {
if (is_buffer_b) {
ctx.WriteBufferB(tmp_output.data(), tmp_output.size(), 0);
ctx.WriteBufferB(tmp_performance.data(), tmp_performance.size(), 1);
ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
} else {
ctx.WriteBufferC(tmp_output.data(), tmp_output.size(), 0);
ctx.WriteBufferC(tmp_performance.data(), tmp_performance.size(), 1);
ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
}
} else {
LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description);
@@ -233,8 +234,8 @@ private:
Kernel::KEvent* rendered_event;
Manager& manager;
std::unique_ptr<Renderer> impl;
Common::ScratchBuffer<u8> tmp_output;
Common::ScratchBuffer<u8> tmp_performance;
Common::ScratchBuffer<u8> output_buffer;
Common::ScratchBuffer<u8> performance_buffer;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {

View File

@@ -11,6 +11,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scratch_buffer.h"
#include "core/hle/service/audio/hwopus.h"
#include "core/hle/service/ipc_helpers.h"
@@ -68,13 +69,13 @@ private:
ExtraBehavior extra_behavior) {
u32 consumed = 0;
u32 sample_count = 0;
tmp_samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>());
samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>());
if (extra_behavior == ExtraBehavior::ResetContext) {
ResetDecoderContext();
}
if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), tmp_samples, performance)) {
if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), samples, performance)) {
LOG_ERROR(Audio, "Failed to decode opus data");
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
@@ -90,7 +91,7 @@ private:
if (performance) {
rb.Push<u64>(*performance);
}
ctx.WriteBuffer(tmp_samples);
ctx.WriteBuffer(samples);
}
bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input,
@@ -154,7 +155,7 @@ private:
OpusDecoderPtr decoder;
u32 sample_rate;
u32 channel_count;
Common::ScratchBuffer<opus_int16> tmp_samples;
Common::ScratchBuffer<opus_int16> samples;
};
class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {

View File

@@ -2,7 +2,6 @@
// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cinttypes>
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
@@ -63,12 +62,12 @@ void NVDRV::Ioctl1(HLERequestContext& ctx) {
}
// Check device
tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
const auto input_buffer = ctx.ReadBuffer(0);
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output);
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
if (command.is_out != 0) {
ctx.WriteBuffer(tmp_output);
ctx.WriteBuffer(output_buffer);
}
IPC::ResponseBuilder rb{ctx, 3};
@@ -90,12 +89,12 @@ void NVDRV::Ioctl2(HLERequestContext& ctx) {
const auto input_buffer = ctx.ReadBuffer(0);
const auto input_inlined_buffer = ctx.ReadBuffer(1);
tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
const auto nv_result =
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, tmp_output);
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
if (command.is_out != 0) {
ctx.WriteBuffer(tmp_output);
ctx.WriteBuffer(output_buffer);
}
IPC::ResponseBuilder rb{ctx, 3};
@@ -116,12 +115,14 @@ void NVDRV::Ioctl3(HLERequestContext& ctx) {
}
const auto input_buffer = ctx.ReadBuffer(0);
tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
tmp_output_inline.resize_destructive(ctx.GetWriteBufferSize(1));
const auto nv_result = nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output_inline);
output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
inline_output_buffer.resize_destructive(ctx.GetWriteBufferSize(1));
const auto nv_result =
nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, inline_output_buffer);
if (command.is_out != 0) {
ctx.WriteBuffer(tmp_output, 0);
ctx.WriteBuffer(tmp_output_inline, 1);
ctx.WriteBuffer(output_buffer, 0);
ctx.WriteBuffer(inline_output_buffer, 1);
}
IPC::ResponseBuilder rb{ctx, 3};

View File

@@ -4,6 +4,7 @@
#pragma once
#include <memory>
#include "common/scratch_buffer.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/service.h"
@@ -34,8 +35,8 @@ private:
u64 pid{};
bool is_initialized{};
Common::ScratchBuffer<u8> tmp_output;
Common::ScratchBuffer<u8> tmp_output_inline;
Common::ScratchBuffer<u8> output_buffer;
Common::ScratchBuffer<u8> inline_output_buffer;
};
} // namespace Service::Nvidia

View File

@@ -6,6 +6,7 @@
#include <memory>
#include <span>
#include <vector>
#include <boost/container/small_vector.hpp>
#include "common/alignment.h"
@@ -148,9 +149,9 @@ public:
this->WriteImpl(0U, m_object_buffer);
}
std::vector<u8> Serialize() const {
std::vector<u8> output_buffer(sizeof(ParcelHeader) + m_data_buffer.size() +
m_object_buffer.size());
std::span<u8> Serialize() {
m_output_buffer.resize(sizeof(ParcelHeader) + m_data_buffer.size() +
m_object_buffer.size());
ParcelHeader header{};
header.data_size = static_cast<u32>(m_data_buffer.size());
@@ -158,17 +159,17 @@ public:
header.objects_size = static_cast<u32>(m_object_buffer.size());
header.objects_offset = header.data_offset + header.data_size;
std::memcpy(output_buffer.data(), &header, sizeof(header));
std::ranges::copy(m_data_buffer, output_buffer.data() + header.data_offset);
std::ranges::copy(m_object_buffer, output_buffer.data() + header.objects_offset);
std::memcpy(m_output_buffer.data(), &header, sizeof(ParcelHeader));
std::ranges::copy(m_data_buffer, m_output_buffer.data() + header.data_offset);
std::ranges::copy(m_object_buffer, m_output_buffer.data() + header.objects_offset);
return output_buffer;
return m_output_buffer;
}
private:
template <typename T>
template <typename T, size_t BufferSize>
requires(std::is_trivially_copyable_v<T>)
void WriteImpl(const T& val, boost::container::small_vector<u8, 0x200>& buffer) {
void WriteImpl(const T& val, boost::container::small_vector<u8, BufferSize>& buffer) {
const size_t aligned_size = Common::AlignUp(sizeof(T), 4);
const size_t old_size = buffer.size();
buffer.resize(old_size + aligned_size);
@@ -177,8 +178,9 @@ private:
}
private:
boost::container::small_vector<u8, 0x200> m_data_buffer;
boost::container::small_vector<u8, 0x200> m_object_buffer;
boost::container::small_vector<u8, 0x1B0> m_data_buffer;
boost::container::small_vector<u8, 0x40> m_object_buffer;
boost::container::small_vector<u8, 0x200> m_output_buffer;
};
} // namespace Service::android

View File

@@ -102,12 +102,12 @@ bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const {
Joycon::SerialNumber serial_number{};
const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
if (result != Joycon::DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return false;
}
const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number);
if (result2 != Joycon::DriverResult::Success) {
if (result2 != Common::Input::DriverResult::Success) {
return false;
}
@@ -171,10 +171,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
LOG_WARNING(Input, "No free handles available");
return;
}
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = handle->RequestDeviceAccess(device_info);
}
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
LOG_WARNING(Input, "Initialize device");
const std::size_t port = handle->GetDevicePort();
@@ -273,8 +273,7 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier,
led_config += led_status.led_3 ? 4 : 0;
led_config += led_status.led_4 ? 8 : 0;
return static_cast<Common::Input::DriverResult>(
handle->SetLedConfig(static_cast<u8>(led_config)));
return handle->SetLedConfig(static_cast<u8>(led_config));
}
Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier,
@@ -283,8 +282,8 @@ Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identi
if (handle == nullptr) {
return Common::Input::DriverResult::InvalidHandle;
}
return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig(
Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format)));
return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer,
static_cast<Joycon::IrsResolution>(camera_format));
};
Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const {
@@ -351,7 +350,7 @@ Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier,
std::vector<Joycon::MifareReadData> read_data(read_request.size());
const auto result = handle->ReadMifareData(read_request, read_data);
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
for (std::size_t i = 0; i < read_request.size(); i++) {
data.data[i] = {
.command = static_cast<u8>(command),
@@ -402,15 +401,15 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif
switch (polling_mode) {
case Common::Input::PollingMode::Active:
return static_cast<Common::Input::DriverResult>(handle->SetActiveMode());
return handle->SetActiveMode();
case Common::Input::PollingMode::Passive:
return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode());
return handle->SetPassiveMode();
case Common::Input::PollingMode::IR:
return static_cast<Common::Input::DriverResult>(handle->SetIrMode());
return handle->SetIrMode();
case Common::Input::PollingMode::NFC:
return static_cast<Common::Input::DriverResult>(handle->SetNfcMode());
return handle->SetNfcMode();
case Common::Input::PollingMode::Ring:
return static_cast<Common::Input::DriverResult>(handle->SetRingConMode());
return handle->SetRingConMode();
default:
return Common::Input::DriverResult::NotSupported;
}
@@ -828,13 +827,13 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
}
}
Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const {
Common::Input::NfcState Joycons::TranslateDriverResult(Common::Input::DriverResult result) const {
switch (result) {
case Joycon::DriverResult::Success:
case Common::Input::DriverResult::Success:
return Common::Input::NfcState::Success;
case Joycon::DriverResult::Disabled:
case Common::Input::DriverResult::Disabled:
return Common::Input::NfcState::WrongDeviceState;
case Joycon::DriverResult::NotSupported:
case Common::Input::DriverResult::NotSupported:
return Common::Input::NfcState::NotSupported;
default:
return Common::Input::NfcState::Unknown;

View File

@@ -17,7 +17,6 @@ struct Color;
struct MotionData;
struct TagInfo;
enum class ControllerType : u8;
enum class DriverResult;
enum class IrsResolution;
class JoyconDriver;
} // namespace InputCommon::Joycon
@@ -112,7 +111,7 @@ private:
/// Returns the name of the device in text format
std::string JoyconName(Joycon::ControllerType type) const;
Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const;
Common::Input::NfcState TranslateDriverResult(Common::Input::DriverResult result) const;
std::jthread scan_thread;

View File

@@ -12,13 +12,9 @@
namespace InputCommon {
constexpr int update_time = 10;
constexpr float default_panning_sensitivity = 0.0010f;
constexpr float default_stick_sensitivity = 0.0006f;
constexpr float default_deadzone_counterweight = 0.01f;
constexpr float default_motion_panning_sensitivity = 2.5f;
constexpr float default_motion_sensitivity = 0.416f;
constexpr float default_stick_sensitivity = 0.0044f;
constexpr float default_motion_sensitivity = 0.0003f;
constexpr float maximum_rotation_speed = 2.0f;
constexpr float maximum_stick_range = 1.5f;
constexpr int mouse_axis_x = 0;
constexpr int mouse_axis_y = 1;
constexpr int wheel_axis_x = 2;
@@ -85,7 +81,7 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
}
void Mouse::UpdateStickInput() {
if (!IsMousePanningEnabled()) {
if (!Settings::values.mouse_panning) {
return;
}
@@ -93,13 +89,26 @@ void Mouse::UpdateStickInput() {
// Prevent input from exceeding the max range (1.0f) too much,
// but allow some room to make it easier to sustain
if (length > maximum_stick_range) {
if (length > 1.2f) {
last_mouse_change /= length;
last_mouse_change *= maximum_stick_range;
last_mouse_change *= 1.2f;
}
SetAxis(identifier, mouse_axis_x, last_mouse_change.x);
SetAxis(identifier, mouse_axis_y, -last_mouse_change.y);
auto mouse_change = last_mouse_change;
// Bind the mouse change to [0 <= deadzone_counterweight <= 1,1]
if (length < 1.0f) {
const float deadzone_h_counterweight =
Settings::values.mouse_panning_deadzone_x_counterweight.GetValue();
const float deadzone_v_counterweight =
Settings::values.mouse_panning_deadzone_y_counterweight.GetValue();
mouse_change /= length;
mouse_change.x *= length + (1 - length) * deadzone_h_counterweight * 0.01f;
mouse_change.y *= length + (1 - length) * deadzone_v_counterweight * 0.01f;
}
SetAxis(identifier, mouse_axis_x, mouse_change.x);
SetAxis(identifier, mouse_axis_y, -mouse_change.y);
// Decay input over time
const float clamped_length = std::min(1.0f, length);
@@ -111,13 +120,14 @@ void Mouse::UpdateStickInput() {
}
void Mouse::UpdateMotionInput() {
const float sensitivity =
IsMousePanningEnabled() ? default_motion_panning_sensitivity : default_motion_sensitivity;
// This may need its own sensitivity instead of using the average
const float sensitivity = (Settings::values.mouse_panning_x_sensitivity.GetValue() +
Settings::values.mouse_panning_y_sensitivity.GetValue()) /
2.0f * default_motion_sensitivity;
const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x +
last_motion_change.y * last_motion_change.y);
// Clamp rotation speed
if (rotation_velocity > maximum_rotation_speed / sensitivity) {
const float multiplier = maximum_rotation_speed / rotation_velocity / sensitivity;
last_motion_change.x = last_motion_change.x * multiplier;
@@ -134,7 +144,7 @@ void Mouse::UpdateMotionInput() {
.delta_timestamp = update_time * 1000,
};
if (IsMousePanningEnabled()) {
if (Settings::values.mouse_panning) {
last_motion_change.x = 0;
last_motion_change.y = 0;
}
@@ -144,42 +154,33 @@ void Mouse::UpdateMotionInput() {
}
void Mouse::Move(int x, int y, int center_x, int center_y) {
if (IsMousePanningEnabled()) {
if (Settings::values.mouse_panning) {
const auto mouse_change =
(Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
const float x_sensitivity =
Settings::values.mouse_panning_x_sensitivity.GetValue() * default_panning_sensitivity;
Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
const float y_sensitivity =
Settings::values.mouse_panning_y_sensitivity.GetValue() * default_panning_sensitivity;
const float deadzone_counterweight =
Settings::values.mouse_panning_deadzone_counterweight.GetValue() *
default_deadzone_counterweight;
Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
last_motion_change += {-mouse_change.y * x_sensitivity, -mouse_change.x * y_sensitivity, 0};
last_mouse_change.x += mouse_change.x * x_sensitivity;
last_mouse_change.y += mouse_change.y * y_sensitivity;
// Bind the mouse change to [0 <= deadzone_counterweight <= 1.0]
if (last_mouse_change.Length() < deadzone_counterweight) {
last_mouse_change /= last_mouse_change.Length();
last_mouse_change *= deadzone_counterweight;
}
last_motion_change += {-mouse_change.y, -mouse_change.x, 0};
last_mouse_change.x += mouse_change.x * x_sensitivity * 0.09f;
last_mouse_change.y += mouse_change.y * y_sensitivity * 0.09f;
return;
}
if (button_pressed) {
const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
const float x_sensitivity =
Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
const float y_sensitivity =
Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * x_sensitivity);
SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * y_sensitivity);
const float x_sensitivity = Settings::values.mouse_panning_x_sensitivity.GetValue();
const float y_sensitivity = Settings::values.mouse_panning_y_sensitivity.GetValue();
SetAxis(identifier, mouse_axis_x,
static_cast<float>(mouse_move.x) * x_sensitivity * 0.0012f);
SetAxis(identifier, mouse_axis_y,
static_cast<float>(-mouse_move.y) * y_sensitivity * 0.0012f);
last_motion_change = {
static_cast<float>(-mouse_move.y) * x_sensitivity,
static_cast<float>(-mouse_move.x) * y_sensitivity,
static_cast<float>(-mouse_move.y) / 50.0f,
static_cast<float>(-mouse_move.x) / 50.0f,
last_motion_change.z,
};
}
@@ -219,7 +220,7 @@ void Mouse::ReleaseButton(MouseButton button) {
SetButton(real_mouse_identifier, static_cast<int>(button), false);
SetButton(touch_identifier, static_cast<int>(button), false);
if (!IsMousePanningEnabled()) {
if (!Settings::values.mouse_panning) {
SetAxis(identifier, mouse_axis_x, 0);
SetAxis(identifier, mouse_axis_y, 0);
}
@@ -233,7 +234,7 @@ void Mouse::ReleaseButton(MouseButton button) {
void Mouse::MouseWheelChange(int x, int y) {
wheel_position.x += x;
wheel_position.y += y;
last_motion_change.z += static_cast<f32>(y);
last_motion_change.z += static_cast<f32>(y) / 100.0f;
SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
}
@@ -243,11 +244,6 @@ void Mouse::ReleaseAllButtons() {
button_pressed = false;
}
bool Mouse::IsMousePanningEnabled() {
// Disable mouse panning when a real mouse is connected
return Settings::values.mouse_panning && !Settings::values.mouse_enabled;
}
std::vector<Common::ParamPackage> Mouse::GetInputDevices() const {
std::vector<Common::ParamPackage> devices;
devices.emplace_back(Common::ParamPackage{

View File

@@ -99,8 +99,6 @@ private:
void UpdateStickInput();
void UpdateMotionInput();
bool IsMousePanningEnabled();
Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
Common::Vec2<int> mouse_origin;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/swap.h"
@@ -28,13 +29,13 @@ void JoyconDriver::Stop() {
input_thread = {};
}
DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
std::scoped_lock lock{mutex};
handle_device_type = ControllerType::None;
GetDeviceType(device_info, handle_device_type);
if (handle_device_type == ControllerType::None) {
return DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
hidapi_handle->handle =
@@ -43,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info)
if (!hidapi_handle->handle) {
LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
device_info->vendor_id, device_info->product_id);
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconDriver::InitializeDevice() {
Common::Input::DriverResult JoyconDriver::InitializeDevice() {
if (!hidapi_handle->handle) {
return DriverResult::InvalidHandle;
return Common::Input::DriverResult::InvalidHandle;
}
std::scoped_lock lock{mutex};
disable_input_thread = true;
@@ -87,7 +88,7 @@ DriverResult JoyconDriver::InitializeDevice() {
rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
// Get fixed joycon info
if (generic_protocol->GetVersionNumber(version) != DriverResult::Success) {
if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) {
// If this command fails the device doesn't accept configuration commands
input_only_device = true;
}
@@ -129,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() {
}
disable_input_thread = false;
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
void JoyconDriver::InputThread(std::stop_token stop_token) {
@@ -229,7 +230,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
if (!amiibo_detected) {
Joycon::TagInfo tag_info;
const auto result = nfc_protocol->GetTagInfo(tag_info);
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
joycon_poller->UpdateAmiibo(tag_info);
amiibo_detected = true;
}
@@ -255,7 +256,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
}
}
DriverResult JoyconDriver::SetPollingMode() {
Common::Input::DriverResult JoyconDriver::SetPollingMode() {
SCOPE_EXIT({ disable_input_thread = false; });
disable_input_thread = true;
@@ -270,7 +271,7 @@ DriverResult JoyconDriver::SetPollingMode() {
}
if (input_only_device) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (irs_protocol->IsEnabled()) {
@@ -289,7 +290,7 @@ DriverResult JoyconDriver::SetPollingMode() {
if (irs_enabled && supported_features.irs) {
auto result = irs_protocol->EnableIrs();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
irs_protocol->DisableIrs();
@@ -299,7 +300,7 @@ DriverResult JoyconDriver::SetPollingMode() {
if (nfc_enabled && supported_features.nfc) {
auto result = nfc_protocol->EnableNfc();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
nfc_protocol->DisableNfc();
@@ -309,10 +310,10 @@ DriverResult JoyconDriver::SetPollingMode() {
if (hidbus_enabled && supported_features.hidbus) {
auto result = ring_protocol->EnableRingCon();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = ring_protocol->StartRingconPolling();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
ring_connected = true;
return result;
}
@@ -324,7 +325,7 @@ DriverResult JoyconDriver::SetPollingMode() {
if (passive_enabled && supported_features.passive) {
const auto result = generic_protocol->EnablePassiveMode();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
LOG_ERROR(Input, "Error enabling passive mode");
@@ -332,7 +333,7 @@ DriverResult JoyconDriver::SetPollingMode() {
// Default Mode
const auto result = generic_protocol->EnableActiveMode();
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Error enabling active mode");
}
// Switch calls this function after enabling active mode
@@ -396,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
return true;
}
DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
return rumble_protocol->SendVibration(vibration);
}
DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
return generic_protocol->SetLedPattern(led_pattern);
}
DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
disable_input_thread = true;
const auto result = irs_protocol->SetIrsConfig(mode_, format_);
@@ -423,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
return result;
}
DriverResult JoyconDriver::SetPassiveMode() {
Common::Input::DriverResult JoyconDriver::SetPassiveMode() {
std::scoped_lock lock{mutex};
motion_enabled = false;
hidbus_enabled = false;
@@ -433,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetActiveMode() {
Common::Input::DriverResult JoyconDriver::SetActiveMode() {
if (is_ring_disabled_by_irs) {
is_ring_disabled_by_irs = false;
SetActiveMode();
@@ -449,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetIrMode() {
Common::Input::DriverResult JoyconDriver::SetIrMode() {
std::scoped_lock lock{mutex};
if (!supported_features.irs) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (ring_connected) {
@@ -468,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetNfcMode() {
Common::Input::DriverResult JoyconDriver::SetNfcMode() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
motion_enabled = true;
@@ -483,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetRingConMode() {
Common::Input::DriverResult JoyconDriver::SetRingConMode() {
std::scoped_lock lock{mutex};
if (!supported_features.hidbus) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
motion_enabled = true;
@@ -499,20 +500,20 @@ DriverResult JoyconDriver::SetRingConMode() {
const auto result = SetPollingMode();
if (!ring_connected) {
return DriverResult::NoDeviceDetected;
return Common::Input::DriverResult::NoDeviceDetected;
}
return result;
}
DriverResult JoyconDriver::StartNfcPolling() {
Common::Input::DriverResult JoyconDriver::StartNfcPolling() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
disable_input_thread = true;
@@ -522,14 +523,14 @@ DriverResult JoyconDriver::StartNfcPolling() {
return result;
}
DriverResult JoyconDriver::StopNfcPolling() {
Common::Input::DriverResult JoyconDriver::StopNfcPolling() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
disable_input_thread = true;
@@ -544,17 +545,17 @@ DriverResult JoyconDriver::StopNfcPolling() {
return result;
}
DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
out_data.resize(0x21C);
@@ -565,17 +566,17 @@ DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
return result;
}
DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -585,18 +586,18 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
return result;
}
DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
std::span<MifareReadData> out_data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -606,17 +607,17 @@ DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
return result;
}
DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -675,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) {
joycon_poller->SetCallbacks(callbacks);
}
DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type) {
Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type) {
static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{
std::pair<u32, ControllerType>{0x2006, ControllerType::Left},
{0x2007, ControllerType::Right},
@@ -686,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
controller_type = ControllerType::None;
if (device_info->vendor_id != nintendo_vendor_id) {
return DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
for (const auto& [product_id, type] : supported_devices) {
if (device_info->product_id == static_cast<u16>(product_id)) {
controller_type = type;
return Joycon::DriverResult::Success;
return Common::Input::DriverResult::Success;
}
}
return Joycon::DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number) {
Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number) {
if (device_info->serial_number == nullptr) {
return DriverResult::Unknown;
return Common::Input::DriverResult::Unknown;
}
std::memcpy(&serial_number, device_info->serial_number, 15);
return Joycon::DriverResult::Success;
return Common::Input::DriverResult::Success;
}
} // namespace InputCommon::Joycon

View File

@@ -11,6 +11,10 @@
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class CalibrationProtocol;
class GenericProtocol;
@@ -26,8 +30,8 @@ public:
~JoyconDriver();
DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
DriverResult InitializeDevice();
Common::Input::DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
Common::Input::DriverResult InitializeDevice();
void Stop();
bool IsConnected() const;
@@ -41,31 +45,31 @@ public:
SerialNumber GetSerialNumber() const;
SerialNumber GetHandleSerialNumber() const;
DriverResult SetVibration(const VibrationValue& vibration);
DriverResult SetLedConfig(u8 led_pattern);
DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
DriverResult SetPassiveMode();
DriverResult SetActiveMode();
DriverResult SetIrMode();
DriverResult SetNfcMode();
DriverResult SetRingConMode();
DriverResult StartNfcPolling();
DriverResult StopNfcPolling();
DriverResult ReadAmiiboData(std::vector<u8>& out_data);
DriverResult WriteNfcData(std::span<const u8> data);
DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
std::span<MifareReadData> out_data);
DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
Common::Input::DriverResult SetVibration(const VibrationValue& vibration);
Common::Input::DriverResult SetLedConfig(u8 led_pattern);
Common::Input::DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
Common::Input::DriverResult SetPassiveMode();
Common::Input::DriverResult SetActiveMode();
Common::Input::DriverResult SetIrMode();
Common::Input::DriverResult SetNfcMode();
Common::Input::DriverResult SetRingConMode();
Common::Input::DriverResult StartNfcPolling();
Common::Input::DriverResult StopNfcPolling();
Common::Input::DriverResult ReadAmiiboData(std::vector<u8>& out_data);
Common::Input::DriverResult WriteNfcData(std::span<const u8> data);
Common::Input::DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
void SetCallbacks(const JoyconCallbacks& callbacks);
// Returns device type from hidapi handle
static DriverResult GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type);
static Common::Input::DriverResult GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type);
// Returns serial number from hidapi handle
static DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number);
static Common::Input::DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number);
private:
struct SupportedFeatures {
@@ -84,7 +88,7 @@ private:
void OnNewData(std::span<u8> buffer);
/// Updates device configuration to enable or disable features
DriverResult SetPollingMode();
Common::Input::DriverResult SetPollingMode();
/// Returns true if input thread is valid and doesn't need to be stopped
bool IsInputThreadValid() const;

View File

@@ -3,6 +3,7 @@
#include <cstring>
#include "common/input.h"
#include "input_common/helpers/joycon_protocol/calibration.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
@@ -11,28 +12,29 @@ namespace InputCommon::Joycon {
CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(
JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
JoystickLeftSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -47,28 +49,29 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
return result;
}
DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetRightJoyStickCalibration(
JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
JoystickRightSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -83,28 +86,28 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
return result;
}
DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
ImuSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
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];
@@ -127,8 +130,8 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
return result;
}
DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
Common::Input::DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
constexpr s16 DefaultRingRange{800};
// TODO: Get default calibration form ring itself
@@ -144,15 +147,15 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
.max_value = ring_data_max,
.min_value = ring_data_min,
};
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
bool& has_user_calibration) {
Common::Input::DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
bool& has_user_calibration) {
MagicSpiCalibration spi_magic{};
const DriverResult result{ReadSPI(address, spi_magic)};
const Common::Input::DriverResult result{ReadSPI(address, spi_magic)};
has_user_calibration = false;
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
spi_magic.second == CalibrationMagic::USR_MAGIC_1;
}

View File

@@ -12,8 +12,11 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
namespace InputCommon::Joycon {
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
struct JoyStickCalibration;
struct IMUCalibration;
struct JoyconHandle;
@@ -31,30 +34,30 @@ public:
* @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the left joystick
*/
DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
Common::Input::DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
/**
* Sends a request to obtain the right stick calibration from memory
* @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the right joystick
*/
DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
Common::Input::DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
/**
* Sends a request to obtain the motion calibration from memory
* @returns ImuCalibration of the motion sensor
*/
DriverResult GetImuCalibration(MotionCalibration& calibration);
Common::Input::DriverResult GetImuCalibration(MotionCalibration& calibration);
/**
* Calculates on run time the proper calibration of the ring controller
* @returns RingCalibration of the ring sensor
*/
DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
Common::Input::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);
Common::Input::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;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/common_protocol.h"
@@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() {
SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
}
DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
// Fallback to 3rd party pro controllers
if (controller_type == ControllerType::None) {
controller_type = ControllerType::Pro;
@@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
return result;
}
DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) {
Common::Input::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;
if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) {
return Common::Input::DriverResult::UnsupportedControllerType;
}
hidapi_handle->handle =
@@ -48,32 +50,32 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device
if (!hidapi_handle->handle) {
LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
device_info->vendor_id, device_info->product_id);
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
SetNonBlocking();
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
const std::array<u8, 1> buffer{static_cast<u8>(report_mode)};
return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
}
DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
if (result == -1) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
SubCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(
SubCommand sc, SubCommandResponse& output) {
constexpr int timeout_mili = 66;
constexpr int MaxTries = 3;
constexpr int MaxTries = 10;
int tries = 0;
do {
@@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
LOG_ERROR(Input, "No response from joycon");
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
output.sub_command != sc);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer,
SubCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
std::span<const u8> buffer,
SubCommandResponse& output) {
SubCommandPacket packet{
.output_report = OutputReport::RUMBLE_AND_SUBCMD,
.packet_counter = GetCounter(),
@@ -102,26 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
auto result = SendData(packet);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
return GetSubCommandResponse(sc, output);
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
std::span<const u8> buffer) {
SubCommandResponse output{};
return SendSubCommand(sc, buffer, output);
}
DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc,
std::span<const u8> buffer) {
SubCommandPacket packet{
.output_report = OutputReport::MCU_DATA,
.packet_counter = GetCounter(),
@@ -130,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
@@ -138,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
return SendData(packet);
}
DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
VibrationPacket packet{
.output_report = OutputReport::RUMBLE_ONLY,
.packet_counter = GetCounter(),
@@ -146,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
};
if (buffer.size() > packet.vibration_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
@@ -154,7 +159,8 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
return SendData(packet);
}
DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr,
std::span<u8> output) {
constexpr std::size_t HeaderSize = 5;
constexpr std::size_t MaxTries = 5;
std::size_t tries = 0;
@@ -168,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
do {
const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (response.spi_address != addr);
if (response.command_data.size() < packet_data.size + HeaderSize) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
// Remove header from output
memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)};
const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Failed with error {}", result);
}
return result;
}
DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
LOG_DEBUG(Input, "ConfigureMCU");
std::array<u8, sizeof(MCUConfig)> config_buffer;
memcpy(config_buffer.data(), &config, sizeof(MCUConfig));
@@ -205,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Failed with error {}", result);
}
return result;
}
DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
MCUCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
MCUCommandResponse& output) {
constexpr int TimeoutMili = 200;
constexpr int MaxTries = 9;
int tries = 0;
@@ -226,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
LOG_ERROR(Input, "No response from joycon attempt {}", tries);
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.input_report.report_mode != report_mode ||
output.mcu_report == MCUReport::EmptyAwaitingCmd);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc,
std::span<const u8> buffer,
MCUCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode,
MCUSubCommand sc,
std::span<const u8> buffer,
MCUCommandResponse& output) {
SubCommandPacket packet{
.output_report = OutputReport::MCU_DATA,
.packet_counter = GetCounter(),
@@ -245,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
auto result = SendData(packet);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
result = GetMCUDataResponse(report_mode, output);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) {
Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode,
MCUMode mode) {
MCUCommandResponse output{};
constexpr std::size_t MaxTries{16};
std::size_t tries{};
@@ -269,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
do {
const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > MaxTries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.mcu_report != MCUReport::StateReport ||
output.mcu_data[6] != static_cast<u8>(mode));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
// crc-8-ccitt / polynomial 0x07 look up table

View File

@@ -38,30 +38,30 @@ public:
* Sends a request to obtain the joycon type from device
* @returns controller type of the joycon
*/
DriverResult GetDeviceType(ControllerType& controller_type);
Common::Input::DriverResult GetDeviceType(ControllerType& controller_type);
/**
* Verifies and sets the joycon_handle if device is valid
* @param device info from the driver
* @returns success if the device is valid
*/
DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
Common::Input::DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
/**
* Sends a request to set the polling mode of the joycon
* @param report_mode polling mode to be set
*/
DriverResult SetReportMode(Joycon::ReportMode report_mode);
Common::Input::DriverResult SetReportMode(Joycon::ReportMode report_mode);
/**
* Sends data to the joycon device
* @param buffer data to be send
*/
DriverResult SendRawData(std::span<const u8> buffer);
Common::Input::DriverResult SendRawData(std::span<const u8> buffer);
template <typename Output>
requires std::is_trivially_copyable_v<Output>
DriverResult SendData(const Output& output) {
Common::Input::DriverResult SendData(const Output& output) {
std::array<u8, sizeof(Output)> buffer;
std::memcpy(buffer.data(), &output, sizeof(Output));
return SendRawData(buffer);
@@ -72,7 +72,8 @@ public:
* @param sub_command type of data to be returned
* @returns a buffer containing the response
*/
DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output);
Common::Input::DriverResult GetSubCommandResponse(SubCommand sub_command,
SubCommandResponse& output);
/**
* Sends a sub command to the device and waits for it's reply
@@ -80,35 +81,35 @@ public:
* @param buffer data to be send
* @returns output buffer containing the response
*/
DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
SubCommandResponse& output);
Common::Input::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
* @param sc sub command to be send
* @param buffer data to be send
*/
DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
/**
* Sends a mcu command to the device
* @param sc sub command to be send
* @param buffer data to be send
*/
DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
Common::Input::DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
/**
* Sends vibration data to the joycon
* @param buffer data to be send
*/
DriverResult SendVibrationReport(std::span<const u8> buffer);
Common::Input::DriverResult SendVibrationReport(std::span<const u8> buffer);
/**
* Reads the SPI memory stored on the joycon
* @param Initial address location
* @returns output buffer containing the response
*/
DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
Common::Input::DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
/**
* Reads the SPI memory stored on the joycon
@@ -117,37 +118,38 @@ public:
*/
template <typename Output>
requires std::is_trivially_copyable_v<Output>
DriverResult ReadSPI(SpiAddress addr, Output& output) {
Common::Input::DriverResult ReadSPI(SpiAddress addr, Output& output) {
std::array<u8, sizeof(Output)> buffer;
output = {};
const auto result = ReadRawSPI(addr, buffer);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
std::memcpy(&output, buffer.data(), sizeof(Output));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
/**
* Enables MCU chip on the joycon
* @param enable if true the chip will be enabled
*/
DriverResult EnableMCU(bool enable);
Common::Input::DriverResult EnableMCU(bool enable);
/**
* Configures the MCU to the corresponding mode
* @param MCUConfig configuration
*/
DriverResult ConfigureMCU(const MCUConfig& config);
Common::Input::DriverResult ConfigureMCU(const MCUConfig& config);
/**
* Waits until there's MCU data available. On timeout returns error
* @param report mode of the expected reply
* @returns a buffer containing the response
*/
DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output);
Common::Input::DriverResult GetMCUDataResponse(ReportMode report_mode_,
MCUCommandResponse& output);
/**
* Sends data to the MCU chip and waits for it's reply
@@ -156,15 +158,15 @@ public:
* @param buffer data to be send
* @returns output buffer containing the response
*/
DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span<const u8> buffer,
MCUCommandResponse& output);
Common::Input::DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc,
std::span<const u8> buffer, MCUCommandResponse& output);
/**
* Wait's until the MCU chip is on the specified mode
* @param report mode of the expected reply
* @param MCUMode configuration
*/
DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
Common::Input::DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
/**
* Calculates the checksum from the MCU data

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/generic_functions.h"
@@ -9,73 +10,74 @@ namespace InputCommon::Joycon {
GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult GenericProtocol::EnablePassiveMode() {
Common::Input::DriverResult GenericProtocol::EnablePassiveMode() {
ScopedSetBlocking sb(this);
return SetReportMode(ReportMode::SIMPLE_HID_MODE);
}
DriverResult GenericProtocol::EnableActiveMode() {
Common::Input::DriverResult GenericProtocol::EnableActiveMode() {
ScopedSetBlocking sb(this);
return SetReportMode(ReportMode::STANDARD_FULL_60HZ);
}
DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
Common::Input::DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer);
}
DriverResult GenericProtocol::TriggersElapsed() {
Common::Input::DriverResult GenericProtocol::TriggersElapsed() {
ScopedSetBlocking sb(this);
return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {});
}
DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
Common::Input::DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
ScopedSetBlocking sb(this);
SubCommandResponse output{};
const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
device_info = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
device_info = output.device_info;
}
return result;
}
DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
Common::Input::DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
return GetDeviceType(controller_type);
}
DriverResult GenericProtocol::EnableImu(bool enable) {
Common::Input::DriverResult GenericProtocol::EnableImu(bool enable) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
return SendSubCommand(SubCommand::ENABLE_IMU, buffer);
}
DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec) {
Common::Input::DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen,
GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec) {
ScopedSetBlocking sb(this);
const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen),
static_cast<u8>(gfrec), static_cast<u8>(afrec)};
return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer);
}
DriverResult GenericProtocol::GetBattery(u32& battery_level) {
Common::Input::DriverResult GenericProtocol::GetBattery(u32& battery_level) {
// This function is meant to request the high resolution battery status
battery_level = 0;
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::GetColor(Color& color) {
Common::Input::DriverResult GenericProtocol::GetColor(Color& color) {
ScopedSetBlocking sb(this);
std::array<u8, 12> buffer{};
const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
color = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]);
color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]);
color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]);
@@ -85,26 +87,26 @@ DriverResult GenericProtocol::GetColor(Color& color) {
return result;
}
DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
Common::Input::DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
ScopedSetBlocking sb(this);
std::array<u8, 16> buffer{};
const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
serial_number = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber));
}
return result;
}
DriverResult GenericProtocol::GetTemperature(u32& temperature) {
Common::Input::DriverResult GenericProtocol::GetTemperature(u32& temperature) {
// Not all devices have temperature sensor
temperature = 25;
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
Common::Input::DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
DeviceInfo device_info{};
const auto result = GetDeviceInfo(device_info);
@@ -113,23 +115,23 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
return result;
}
DriverResult GenericProtocol::SetHomeLight() {
Common::Input::DriverResult GenericProtocol::SetHomeLight() {
ScopedSetBlocking sb(this);
static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00};
return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer);
}
DriverResult GenericProtocol::SetLedBusy() {
return DriverResult::NotSupported;
Common::Input::DriverResult GenericProtocol::SetLedBusy() {
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::SetLedPattern(u8 leds) {
Common::Input::DriverResult GenericProtocol::SetLedPattern(u8 leds) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{leds};
return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer);
}
DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
Common::Input::DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
return SetLedPattern(static_cast<u8>(leds << 4));
}

View File

@@ -11,6 +11,10 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
/// Joycon driver functions that easily implemented
@@ -20,34 +24,34 @@ public:
/// Enables passive mode. This mode only sends button data on change. Sticks will return digital
/// data instead of analog. Motion will be disabled
DriverResult EnablePassiveMode();
Common::Input::DriverResult EnablePassiveMode();
/// Enables active mode. This mode will return the current status every 5-15ms
DriverResult EnableActiveMode();
Common::Input::DriverResult EnableActiveMode();
/// Enables or disables the low power mode
DriverResult SetLowPowerMode(bool enable);
Common::Input::DriverResult SetLowPowerMode(bool enable);
/// Unknown function used by the switch
DriverResult TriggersElapsed();
Common::Input::DriverResult TriggersElapsed();
/**
* Sends a request to obtain the joycon firmware and mac from handle
* @returns controller device info
*/
DriverResult GetDeviceInfo(DeviceInfo& controller_type);
Common::Input::DriverResult GetDeviceInfo(DeviceInfo& controller_type);
/**
* Sends a request to obtain the joycon type from handle
* @returns controller type of the joycon
*/
DriverResult GetControllerType(ControllerType& controller_type);
Common::Input::DriverResult GetControllerType(ControllerType& controller_type);
/**
* Enables motion input
* @param enable if true motion data will be enabled
*/
DriverResult EnableImu(bool enable);
Common::Input::DriverResult EnableImu(bool enable);
/**
* Configures the motion sensor with the specified parameters
@@ -56,59 +60,60 @@ public:
* @param asen accelerometer sensitivity in G force
* @param afrec accelerometer frequency in hertz
*/
DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen, AccelerometerPerformance afrec);
Common::Input::DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec);
/**
* Request battery level from the device
* @returns battery level
*/
DriverResult GetBattery(u32& battery_level);
Common::Input::DriverResult GetBattery(u32& battery_level);
/**
* Request joycon colors from the device
* @returns colors of the body and buttons
*/
DriverResult GetColor(Color& color);
Common::Input::DriverResult GetColor(Color& color);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetSerialNumber(SerialNumber& serial_number);
Common::Input::DriverResult GetSerialNumber(SerialNumber& serial_number);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetTemperature(u32& temperature);
Common::Input::DriverResult GetTemperature(u32& temperature);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetVersionNumber(FirmwareVersion& version);
Common::Input::DriverResult GetVersionNumber(FirmwareVersion& version);
/**
* Sets home led behaviour
*/
DriverResult SetHomeLight();
Common::Input::DriverResult SetHomeLight();
/**
* Sets home led into a slow breathing state
*/
DriverResult SetLedBusy();
Common::Input::DriverResult SetLedBusy();
/**
* Sets the 4 player leds on the joycon on a solid state
* @params bit flag containing the led state
*/
DriverResult SetLedPattern(u8 leds);
Common::Input::DriverResult SetLedPattern(u8 leds);
/**
* Sets the 4 player leds on the joycon on a blinking state
* @returns bit flag containing the led state
*/
DriverResult SetLedBlinkPattern(u8 leds);
Common::Input::DriverResult SetLedBlinkPattern(u8 leds);
};
} // namespace InputCommon::Joycon

View File

@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/irs.h"
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult IrsProtocol::EnableIrs() {
Common::Input::DriverResult IrsProtocol::EnableIrs() {
LOG_INFO(Input, "Enable IRS");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetMCUMode,
@@ -34,16 +34,16 @@ DriverResult IrsProtocol::EnableIrs() {
result = ConfigureMCU(config);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = ConfigureIrs();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteRegistersStep1();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteRegistersStep2();
}
@@ -52,12 +52,12 @@ DriverResult IrsProtocol::EnableIrs() {
return result;
}
DriverResult IrsProtocol::DisableIrs() {
Common::Input::DriverResult IrsProtocol::DisableIrs() {
LOG_DEBUG(Input, "Disable IRS");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -66,7 +66,7 @@ DriverResult IrsProtocol::DisableIrs() {
return result;
}
DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
Common::Input::DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
irs_mode = mode;
switch (format) {
case IrsResolution::Size320x240:
@@ -103,10 +103,10 @@ DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
return EnableIrs();
}
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
Common::Input::DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
const u8 next_packet_fragment =
static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1));
@@ -129,7 +129,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
return RequestFrame(packet_fragment);
}
DriverResult IrsProtocol::ConfigureIrs() {
Common::Input::DriverResult IrsProtocol::ConfigureIrs() {
LOG_DEBUG(Input, "Configure IRS");
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
@@ -152,20 +152,20 @@ DriverResult IrsProtocol::ConfigureIrs() {
do {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.command_data[0] != 0x0b);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::WriteRegistersStep1() {
Common::Input::DriverResult IrsProtocol::WriteRegistersStep1() {
LOG_DEBUG(Input, "WriteRegistersStep1");
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
std::size_t tries = 0;
@@ -197,7 +197,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
mcu_request[37] = 0xFF;
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -205,26 +205,26 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
// First time we need to set the report mode
if (result == DriverResult::Success && tries == 0) {
if (result == Common::Input::DriverResult::Success && tries == 0) {
result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
}
if (result == DriverResult::Success && tries == 0) {
if (result == Common::Input::DriverResult::Success && tries == 0) {
GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output);
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) &&
output.command_data[0] != 0x23);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::WriteRegistersStep2() {
Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() {
LOG_DEBUG(Input, "WriteRegistersStep2");
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
@@ -255,18 +255,18 @@ DriverResult IrsProtocol::WriteRegistersStep2() {
do {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::RequestFrame(u8 frame) {
Common::Input::DriverResult IrsProtocol::RequestFrame(u8 frame) {
std::array<u8, 38> mcu_request{};
mcu_request[3] = frame;
mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
@@ -274,7 +274,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) {
return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
}
DriverResult IrsProtocol::ResendFrame(u8 frame) {
Common::Input::DriverResult IrsProtocol::ResendFrame(u8 frame) {
std::array<u8, 38> mcu_request{};
mcu_request[1] = 0x1;
mcu_request[2] = frame;

View File

@@ -13,19 +13,23 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class IrsProtocol final : private JoyconCommonProtocol {
public:
explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableIrs();
Common::Input::DriverResult EnableIrs();
DriverResult DisableIrs();
Common::Input::DriverResult DisableIrs();
DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
Common::Input::DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
DriverResult RequestImage(std::span<u8> buffer);
Common::Input::DriverResult RequestImage(std::span<u8> buffer);
std::vector<u8> GetImage() const;
@@ -34,13 +38,13 @@ public:
bool IsEnabled() const;
private:
DriverResult ConfigureIrs();
Common::Input::DriverResult ConfigureIrs();
DriverResult WriteRegistersStep1();
DriverResult WriteRegistersStep2();
Common::Input::DriverResult WriteRegistersStep1();
Common::Input::DriverResult WriteRegistersStep2();
DriverResult RequestFrame(u8 frame);
DriverResult ResendFrame(u8 frame);
Common::Input::DriverResult RequestFrame(u8 frame);
Common::Input::DriverResult ResendFrame(u8 frame);
IrsMode irs_mode{IrsMode::ImageTransfer};
IrsResolution resolution{IrsResolution::Size40x30};

View File

@@ -402,23 +402,6 @@ enum class ExternalDeviceId : u16 {
Starlink = 0x2800,
};
enum class DriverResult {
Success,
WrongReply,
Timeout,
InvalidParameters,
UnsupportedControllerType,
HandleInUse,
ErrorReadingData,
ErrorWritingData,
NoDeviceDetected,
InvalidHandle,
NotSupported,
Disabled,
Delayed,
Unknown,
};
struct MotionSensorCalibration {
s16 offset;
s16 scale;

View File

@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/nfc.h"
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult NfcProtocol::EnableNfc() {
Common::Input::DriverResult NfcProtocol::EnableNfc() {
LOG_INFO(Input, "Enable NFC");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetMCUMode,
@@ -34,32 +34,32 @@ DriverResult NfcProtocol::EnableNfc() {
result = ConfigureMCU(config);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_enabled = true;
}
return result;
}
DriverResult NfcProtocol::DisableNfc() {
Common::Input::DriverResult NfcProtocol::DisableNfc() {
LOG_DEBUG(Input, "Disable NFC");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -69,60 +69,60 @@ DriverResult NfcProtocol::DisableNfc() {
return result;
}
DriverResult NfcProtocol::StartNFCPollingMode() {
Common::Input::DriverResult NfcProtocol::StartNFCPollingMode() {
LOG_DEBUG(Input, "Start NFC polling Mode");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Polling);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_polling = true;
}
return result;
}
DriverResult NfcProtocol::StopNFCPollingMode() {
Common::Input::DriverResult NfcProtocol::StopNFCPollingMode() {
LOG_DEBUG(Input, "Stop NFC polling Mode");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_polling = false;
}
return result;
}
DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
Common::Input::DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
if (update_counter++ < AMIIBO_UPDATE_DELAY) {
return DriverResult::Delayed;
return Common::Input::DriverResult::Delayed;
}
update_counter = 0;
LOG_DEBUG(Input, "Scan for amiibos");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
tag_info = {
.uuid_length = tag_data.uuid_size,
.protocol = 1,
@@ -147,59 +147,59 @@ DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
return result;
}
DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
Common::Input::DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
LOG_DEBUG(Input, "Scan for amiibos");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = GetAmiiboData(data);
}
return result;
}
DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
LOG_DEBUG(Input, "Write amiibo");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagUUID tag_uuid = GetTagUUID(data);
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
if (tag_data.uuid != tag_uuid) {
result = DriverResult::InvalidParameters;
result = Common::Input::DriverResult::InvalidParameters;
}
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteAmiiboData(tag_uuid, data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteDone);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
@@ -207,64 +207,65 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
return result;
}
DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
LOG_DEBUG(Input, "Read mifare");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
MifareUUID tag_uuid{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
result = GetMifareData(tag_uuid, read_request, out_data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
return result;
}
DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) {
Common::Input::DriverResult NfcProtocol::WriteMifare(
std::span<const MifareWriteChunk> write_request) {
LOG_DEBUG(Input, "Write mifare");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
MifareUUID tag_uuid{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
result = WriteMifareData(tag_uuid, write_request);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
return result;
@@ -277,17 +278,17 @@ bool NfcProtocol::HasAmiibo() {
update_counter = 0;
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
return result == DriverResult::Success;
return result == Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
Common::Input::DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
constexpr std::size_t timeout_limit = 10;
MCUCommandResponse output{};
std::size_t tries = 0;
@@ -295,30 +296,31 @@ DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
do {
auto result = SendNextPackageRequest(output, {});
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > timeout_limit) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} 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] != static_cast<u8>(status));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_limit) {
Common::Input::DriverResult NfcProtocol::IsTagInRange(TagFoundData& data,
std::size_t timeout_limit) {
MCUCommandResponse output{};
std::size_t tries = 0;
do {
const auto result = SendNextPackageRequest(output, {});
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > timeout_limit) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.mcu_report != MCUReport::NFCState ||
(output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
@@ -328,10 +330,10 @@ DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_l
data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID)));
memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
Common::Input::DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
constexpr std::size_t timeout_limit = 60;
MCUCommandResponse output{};
std::size_t tries = 0;
@@ -340,7 +342,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
std::size_t ntag_buffer_pos = 0;
auto result = SendReadAmiiboRequest(output, NFCPages::Block135);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -349,14 +351,14 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -375,14 +377,15 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
LOG_INFO(Input, "Finished reading amiibo");
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
}
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid,
std::span<const u8> data) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data);
const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data);
@@ -397,7 +400,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
auto result = SendWriteAmiiboRequest(output, tag_uuid);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -406,14 +409,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -442,7 +445,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -457,14 +460,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
return result;
}
DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult NfcProtocol::GetMifareData(
const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request);
const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data);
std::span<const u8> buffer(nfc_buffer_data);
DriverResult result = DriverResult::Success;
Common::Input::DriverResult result = Common::Input::DriverResult::Success;
MCUCommandResponse output{};
u8 block_id = 1;
u8 package_index = 0;
@@ -486,7 +489,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -498,7 +501,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
}
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -507,12 +510,12 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -538,13 +541,13 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
return result;
}
DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request) {
Common::Input::DriverResult NfcProtocol::WriteMifareData(
const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> write_request) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request);
const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data);
std::span<const u8> buffer(nfc_buffer_data);
DriverResult result = DriverResult::Success;
Common::Input::DriverResult result = Common::Input::DriverResult::Success;
MCUCommandResponse output{};
u8 block_id = 1;
u8 package_index = 0;
@@ -566,7 +569,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -578,7 +581,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
}
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -587,12 +590,12 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -609,8 +612,8 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
return result;
}
DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt) {
Common::Input::DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt) {
NFCRequestState request{
.command_argument = NFCCommand::StartPolling,
.block_id = {},
@@ -635,7 +638,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
NFCRequestState request{
.command_argument = NFCCommand::StopPolling,
.block_id = {},
@@ -653,7 +656,8 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
output);
}
DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id) {
Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output,
u8 packet_id) {
NFCRequestState request{
.command_argument = NFCCommand::StartWaitingRecieve,
.block_id = {},
@@ -671,7 +675,8 @@ DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8
output);
}
DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) {
Common::Input::DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output,
NFCPages ntag_pages) {
NFCRequestState request{
.command_argument = NFCCommand::ReadNtag,
.block_id = {},
@@ -696,8 +701,8 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP
output);
}
DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid) {
Common::Input::DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid) {
NFCRequestState request{
.command_argument = NFCCommand::ReadNtag,
.block_id = {},
@@ -722,9 +727,10 @@ DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
u8 block_id,
bool is_last_packet,
std::span<const u8> data) {
const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
NFCRequestState request{
.command_argument = NFCCommand::WriteNtag,
@@ -745,8 +751,9 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output,
u8 block_id, bool is_last_packet,
std::span<const u8> data) {
const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
NFCRequestState request{
.command_argument = NFCCommand::Mifare,

View File

@@ -13,30 +13,34 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class NfcProtocol final : private JoyconCommonProtocol {
public:
explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableNfc();
Common::Input::DriverResult EnableNfc();
DriverResult DisableNfc();
Common::Input::DriverResult DisableNfc();
DriverResult StartNFCPollingMode();
Common::Input::DriverResult StartNFCPollingMode();
DriverResult StopNFCPollingMode();
Common::Input::DriverResult StopNFCPollingMode();
DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
Common::Input::DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
DriverResult ReadAmiibo(std::vector<u8>& data);
Common::Input::DriverResult ReadAmiibo(std::vector<u8>& data);
DriverResult WriteAmiibo(std::span<const u8> data);
Common::Input::DriverResult WriteAmiibo(std::span<const u8> data);
DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
Common::Input::DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
bool HasAmiibo();
@@ -54,37 +58,41 @@ private:
TagUUID uuid;
};
DriverResult WaitUntilNfcIs(NFCStatus status);
Common::Input::DriverResult WaitUntilNfcIs(NFCStatus status);
DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
Common::Input::DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
DriverResult GetAmiiboData(std::vector<u8>& data);
Common::Input::DriverResult GetAmiiboData(std::vector<u8>& data);
DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
Common::Input::DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
DriverResult GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
DriverResult WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request);
Common::Input::DriverResult WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request);
DriverResult SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt = false);
Common::Input::DriverResult SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt = false);
DriverResult SendStopPollingRequest(MCUCommandResponse& output);
Common::Input::DriverResult SendStopPollingRequest(MCUCommandResponse& output);
DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
Common::Input::DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages);
Common::Input::DriverResult SendReadAmiiboRequest(MCUCommandResponse& output,
NFCPages ntag_pages);
DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, const TagUUID& tag_uuid);
Common::Input::DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid);
DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data);
Common::Input::DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data);
DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data);
Common::Input::DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data);
std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/ringcon.h"
@@ -9,18 +10,18 @@ namespace InputCommon::Joycon {
RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult RingConProtocol::EnableRingCon() {
Common::Input::DriverResult RingConProtocol::EnableRingCon() {
LOG_DEBUG(Input, "Enable Ringcon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::STANDARD_FULL_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetDeviceMode,
@@ -33,12 +34,12 @@ DriverResult RingConProtocol::EnableRingCon() {
return result;
}
DriverResult RingConProtocol::DisableRingCon() {
Common::Input::DriverResult RingConProtocol::DisableRingCon() {
LOG_DEBUG(Input, "Disable RingCon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -47,29 +48,29 @@ DriverResult RingConProtocol::DisableRingCon() {
return result;
}
DriverResult RingConProtocol::StartRingconPolling() {
Common::Input::DriverResult RingConProtocol::StartRingconPolling() {
LOG_DEBUG(Input, "Enable Ringcon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
bool is_connected = false;
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsRingConnected(is_connected);
}
if (result == DriverResult::Success && is_connected) {
if (result == Common::Input::DriverResult::Success && is_connected) {
LOG_INFO(Input, "Ringcon detected");
result = ConfigureRing();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_enabled = true;
}
return result;
}
DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
Common::Input::DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
LOG_DEBUG(Input, "IsRingConnected");
constexpr std::size_t max_tries = 28;
constexpr std::size_t max_tries = 42;
SubCommandResponse output{};
std::size_t tries = 0;
is_connected = false;
@@ -77,20 +78,21 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
do {
const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success &&
result != Common::Input::DriverResult::Timeout) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::NoDeviceDetected;
return Common::Input::DriverResult::NoDeviceDetected;
}
} while (output.external_device_id != ExternalDeviceId::RingController);
is_connected = true;
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult RingConProtocol::ConfigureRing() {
Common::Input::DriverResult RingConProtocol::ConfigureRing() {
LOG_DEBUG(Input, "ConfigureRing");
static constexpr std::array<u8, 37> ring_config{
@@ -98,9 +100,10 @@ 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::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
const Common::Input::DriverResult result =
SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}

View File

@@ -13,24 +13,28 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class RingConProtocol final : private JoyconCommonProtocol {
public:
explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableRingCon();
Common::Input::DriverResult EnableRingCon();
DriverResult DisableRingCon();
Common::Input::DriverResult DisableRingCon();
DriverResult StartRingconPolling();
Common::Input::DriverResult StartRingconPolling();
bool IsEnabled() const;
private:
DriverResult IsRingConnected(bool& is_connected);
Common::Input::DriverResult IsRingConnected(bool& is_connected);
DriverResult ConfigureRing();
Common::Input::DriverResult ConfigureRing();
bool is_enabled{};
};

View File

@@ -4,6 +4,7 @@
#include <algorithm>
#include <cmath>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/rumble.h"
@@ -12,14 +13,14 @@ namespace InputCommon::Joycon {
RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
Common::Input::DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
LOG_DEBUG(Input, "Enable Rumble");
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)};
return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer);
}
DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
Common::Input::DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{};
if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) {

View File

@@ -13,15 +13,19 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class RumbleProtocol final : private JoyconCommonProtocol {
public:
explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableRumble(bool is_enabled);
Common::Input::DriverResult EnableRumble(bool is_enabled);
DriverResult SendVibration(const VibrationValue& vibration);
Common::Input::DriverResult SendVibration(const VibrationValue& vibration);
private:
u16 EncodeHighFrequency(f32 frequency) const;

View File

@@ -220,8 +220,8 @@ add_library(video_core STATIC
surface.h
texture_cache/accelerated_swizzle.cpp
texture_cache/accelerated_swizzle.h
texture_cache/decode_bc4.cpp
texture_cache/decode_bc4.h
texture_cache/decode_bc.cpp
texture_cache/decode_bc.h
texture_cache/descriptor_table.h
texture_cache/formatter.cpp
texture_cache/formatter.h
@@ -279,7 +279,7 @@ add_library(video_core STATIC
create_target_directory_groups(video_core)
target_link_libraries(video_core PUBLIC common core)
target_link_libraries(video_core PUBLIC glad shader_recompiler stb)
target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder)
if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID))
add_dependencies(video_core ffmpeg-build)

View File

@@ -174,8 +174,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
src_operand.address = regs.offset_in;
DMA::BufferOperand dst_operand;
u32 abs_pitch_out = std::abs(static_cast<s32>(regs.pitch_out));
dst_operand.pitch = abs_pitch_out;
dst_operand.pitch = static_cast<u32>(std::abs(regs.pitch_out));
dst_operand.width = regs.line_length_in;
dst_operand.height = regs.line_count;
dst_operand.address = regs.offset_out;
@@ -222,7 +221,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
const size_t src_size =
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
const size_t dst_size = static_cast<size_t>(abs_pitch_out) * regs.line_count;
const size_t dst_size = dst_operand.pitch * regs.line_count;
read_buffer.resize_destructive(src_size);
write_buffer.resize_destructive(dst_size);
@@ -231,7 +230,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset,
src_params.origin.y, x_elements, regs.line_count, block_height, block_depth,
abs_pitch_out);
dst_operand.pitch);
memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
}

View File

@@ -290,7 +290,7 @@ void Codec::Decode() {
return vp9_decoder->GetFrameBytes();
default:
ASSERT(false);
return std::vector<u8>{};
return std::span<const u8>{};
}
}();
AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter};

View File

@@ -29,15 +29,15 @@ H264::H264(Host1x::Host1x& host1x_) : host1x{host1x_} {}
H264::~H264() = default;
const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
bool is_first_frame) {
std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
bool is_first_frame) {
H264DecoderContext context;
host1x.MemoryManager().ReadBlock(state.picture_info_offset, &context,
sizeof(H264DecoderContext));
const s64 frame_number = context.h264_parameter_set.frame_number.Value();
if (!is_first_frame && frame_number != 0) {
frame.resize(context.stream_len);
frame.resize_destructive(context.stream_len);
host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size());
return frame;
}
@@ -135,14 +135,14 @@ const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegist
for (s32 index = 0; index < 6; index++) {
writer.WriteBit(true);
std::span<const u8> matrix{context.weight_scale};
writer.WriteScalingList(matrix, index * 16, 16);
writer.WriteScalingList(scan, matrix, index * 16, 16);
}
if (context.h264_parameter_set.transform_8x8_mode_flag) {
for (s32 index = 0; index < 2; index++) {
writer.WriteBit(true);
std::span<const u8> matrix{context.weight_scale_8x8};
writer.WriteScalingList(matrix, index * 64, 64);
writer.WriteScalingList(scan, matrix, index * 64, 64);
}
}
@@ -188,8 +188,8 @@ void H264BitWriter::WriteBit(bool state) {
WriteBits(state ? 1 : 0, 1);
}
void H264BitWriter::WriteScalingList(std::span<const u8> list, s32 start, s32 count) {
static Common::ScratchBuffer<u8> scan{};
void H264BitWriter::WriteScalingList(Common::ScratchBuffer<u8>& scan, std::span<const u8> list,
s32 start, s32 count) {
scan.resize_destructive(count);
if (count == 16) {
std::memcpy(scan.data(), zig_zag_scan.data(), scan.size());

View File

@@ -5,9 +5,11 @@
#include <span>
#include <vector>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/scratch_buffer.h"
#include "video_core/host1x/nvdec_common.h"
namespace Tegra {
@@ -37,7 +39,8 @@ public:
/// Based on section 7.3.2.1.1.1 and Table 7-4 in the H.264 specification
/// Writes the scaling matrices of the sream
void WriteScalingList(std::span<const u8> list, s32 start, s32 count);
void WriteScalingList(Common::ScratchBuffer<u8>& scan, std::span<const u8> list, s32 start,
s32 count);
/// Return the bitstream as a vector.
[[nodiscard]] std::vector<u8>& GetByteArray();
@@ -63,11 +66,12 @@ public:
~H264();
/// Compose the H264 frame for FFmpeg decoding
[[nodiscard]] const std::vector<u8>& ComposeFrame(
const Host1x::NvdecCommon::NvdecRegisters& state, bool is_first_frame = false);
[[nodiscard]] std::span<const u8> ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
bool is_first_frame = false);
private:
std::vector<u8> frame;
Common::ScratchBuffer<u8> frame;
Common::ScratchBuffer<u8> scan;
Host1x::Host1x& host1x;
struct H264ParameterSet {

View File

@@ -12,7 +12,7 @@ VP8::VP8(Host1x::Host1x& host1x_) : host1x{host1x_} {}
VP8::~VP8() = default;
const std::vector<u8>& VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state) {
std::span<const u8> VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state) {
VP8PictureInfo info;
host1x.MemoryManager().ReadBlock(state.picture_info_offset, &info, sizeof(VP8PictureInfo));

View File

@@ -4,10 +4,11 @@
#pragma once
#include <array>
#include <vector>
#include <span>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/scratch_buffer.h"
#include "video_core/host1x/nvdec_common.h"
namespace Tegra {
@@ -24,11 +25,11 @@ public:
~VP8();
/// Compose the VP8 frame for FFmpeg decoding
[[nodiscard]] const std::vector<u8>& ComposeFrame(
[[nodiscard]] std::span<const u8> ComposeFrame(
const Host1x::NvdecCommon::NvdecRegisters& state);
private:
std::vector<u8> frame;
Common::ScratchBuffer<u8> frame;
Host1x::Host1x& host1x;
struct VP8PictureInfo {

View File

@@ -3,6 +3,7 @@
#include <algorithm> // for std::copy
#include <numeric>
#include "common/assert.h"
#include "video_core/host1x/codecs/vp9.h"
#include "video_core/host1x/host1x.h"

View File

@@ -4,9 +4,11 @@
#pragma once
#include <array>
#include <span>
#include <vector>
#include "common/common_types.h"
#include "common/scratch_buffer.h"
#include "common/stream.h"
#include "video_core/host1x/codecs/vp9_types.h"
#include "video_core/host1x/nvdec_common.h"
@@ -128,8 +130,8 @@ public:
return !current_frame_info.show_frame;
}
/// Returns a const reference to the composed frame data.
[[nodiscard]] const std::vector<u8>& GetFrameBytes() const {
/// Returns a const span to the composed frame data.
[[nodiscard]] std::span<const u8> GetFrameBytes() const {
return frame;
}
@@ -181,7 +183,7 @@ private:
[[nodiscard]] VpxBitStreamWriter ComposeUncompressedHeader();
Host1x::Host1x& host1x;
std::vector<u8> frame;
Common::ScratchBuffer<u8> frame;
std::array<s8, 4> loop_filter_ref_deltas{};
std::array<s8, 2> loop_filter_mode_deltas{};

View File

@@ -5,6 +5,7 @@
#include <array>
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"

View File

@@ -495,6 +495,9 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation) {
if (!device.IsExtShaderStencilExportSupported()) {
return;
}
ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
const BlitImagePipelineKey key{

View File

@@ -259,6 +259,26 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with
break;
}
}
// Transcode on hardware that doesn't support BCn natively
if (!device.IsOptimalBcnSupported() && VideoCore::Surface::IsPixelFormatBCn(pixel_format)) {
const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format);
if (pixel_format == PixelFormat::BC4_SNORM) {
tuple.format = VK_FORMAT_R8_SNORM;
} else if (pixel_format == PixelFormat::BC4_UNORM) {
tuple.format = VK_FORMAT_R8_UNORM;
} else if (pixel_format == PixelFormat::BC5_SNORM) {
tuple.format = VK_FORMAT_R8G8_SNORM;
} else if (pixel_format == PixelFormat::BC5_UNORM) {
tuple.format = VK_FORMAT_R8G8_UNORM;
} else if (pixel_format == PixelFormat::BC6H_SFLOAT ||
pixel_format == PixelFormat::BC6H_UFLOAT) {
tuple.format = VK_FORMAT_R16G16B16A16_SFLOAT;
} else if (is_srgb) {
tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
} else {
tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
}
}
const bool attachable = (tuple.usage & Attachable) != 0;
const bool storage = (tuple.usage & Storage) != 0;

View File

@@ -12,6 +12,7 @@
#include <fmt/format.h>
#include "common/logging/log.h"
#include "common/polyfill_ranges.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/telemetry.h"
@@ -65,6 +66,21 @@ std::string BuildCommaSeparatedExtensions(
return fmt::format("{}", fmt::join(available_extensions, ","));
}
DebugCallback MakeDebugCallback(const vk::Instance& instance, const vk::InstanceDispatch& dld) {
if (!Settings::values.renderer_debug) {
return DebugCallback{};
}
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
const auto it = std::ranges::find_if(*properties, [](const auto& prop) {
return std::strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, prop.extensionName) == 0;
});
if (it != properties->end()) {
return CreateDebugUtilsCallback(instance);
} else {
return CreateDebugReportCallback(instance);
}
}
} // Anonymous namespace
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
@@ -87,7 +103,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())),
instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
Settings::values.renderer_debug.GetValue())),
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
debug_callback(MakeDebugCallback(instance, dld)),
surface(CreateSurface(instance, render_window.GetWindowInfo())),
device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(),
scheduler(device, state_tracker),

View File

@@ -5,6 +5,7 @@
#include <memory>
#include <string>
#include <variant>
#include "common/dynamic_library.h"
#include "video_core/renderer_base.h"
@@ -33,6 +34,8 @@ class GPU;
namespace Vulkan {
using DebugCallback = std::variant<vk::DebugUtilsMessenger, vk::DebugReportCallback>;
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
VkSurfaceKHR surface);
@@ -71,7 +74,7 @@ private:
vk::InstanceDispatch dld;
vk::Instance instance;
vk::DebugUtilsMessenger debug_callback;
DebugCallback debug_callback;
vk::SurfaceKHR surface;
ScreenInfo screen_info;

View File

@@ -590,7 +590,8 @@ void BufferCacheRuntime::ReserveNullBuffer() {
.pNext = nullptr,
.flags = 0,
.size = 4,
.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,

View File

@@ -652,13 +652,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.pNext = nullptr,
.negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE,
};
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
VkPipelineViewportStateCreateInfo viewport_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.viewportCount = Maxwell::NumViewports,
.viewportCount = num_viewports,
.pViewports = nullptr,
.scissorCount = Maxwell::NumViewports,
.scissorCount = num_viewports,
.pScissors = nullptr,
};
if (device.IsNvViewportSwizzleSupported()) {

View File

@@ -309,7 +309,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.support_int16 = device.IsShaderInt16Supported(),
.support_int64 = device.IsShaderInt64Supported(),
.support_vertex_instance_id = false,
.support_float_controls = true,
.support_float_controls = device.IsKhrShaderFloatControlsSupported(),
.support_separate_denorm_behavior =
float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
.support_separate_rounding_mode =
@@ -325,12 +325,13 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.support_fp64_signed_zero_nan_preserve =
float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
.support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
.support_vote = true,
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
.support_viewport_index_layer_non_geometry =
device.IsExtShaderViewportIndexLayerSupported(),
.support_viewport_mask = device.IsNvViewportArray2Supported(),
.support_typeless_image_loads = device.IsFormatlessImageLoadSupported(),
.support_demote_to_helper_invocation = true,
.support_demote_to_helper_invocation =
device.IsExtShaderDemoteToHelperInvocationSupported(),
.support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
.support_derivative_control = true,
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),

View File

@@ -315,7 +315,14 @@ void RasterizerVulkan::Clear(u32 layer_count) {
FlushWork();
gpu_memory->FlushCaching();
#if ANDROID
if (Settings::IsGPULevelHigh()) {
// This is problematic on Android, disable on GPU Normal.
query_cache.UpdateCounters();
}
#else
query_cache.UpdateCounters();
#endif
auto& regs = maxwell3d->regs;
const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B ||
@@ -925,7 +932,7 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
}
const bool is_rescaling{texture_cache.IsRescaling()};
const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
const std::array viewports{
const std::array viewport_list{
GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale),
GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale),
GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale),
@@ -935,7 +942,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
};
scheduler.Record([viewports](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewports); });
scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
cmdbuf.SetViewport(0, viewports);
});
}
void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) {
@@ -948,7 +959,7 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
up_scale = Settings::values.resolution_info.up_scale;
down_shift = Settings::values.resolution_info.down_shift;
}
const std::array scissors{
const std::array scissor_list{
GetScissorState(regs, 0, up_scale, down_shift),
GetScissorState(regs, 1, up_scale, down_shift),
GetScissorState(regs, 2, up_scale, down_shift),
@@ -966,7 +977,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
GetScissorState(regs, 14, up_scale, down_shift),
GetScissorState(regs, 15, up_scale, down_shift),
};
scheduler.Record([scissors](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissors); });
scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
cmdbuf.SetScissor(0, scissors);
});
}
void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {

View File

@@ -38,18 +38,20 @@ size_t Region(size_t iterator) noexcept {
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
Scheduler& scheduler_)
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
const VkBufferCreateInfo stream_ci = {
VkBufferCreateInfo stream_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = STREAM_BUFFER_SIZE,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
if (device.IsExtTransformFeedbackSupported()) {
stream_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
if (device.HasDebuggingToolAttached()) {
stream_buffer.SetObjectNameEXT("Stream Buffer");
@@ -164,19 +166,21 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
bool deferred) {
const u32 log2 = Common::Log2Ceil64(size);
const VkBufferCreateInfo buffer_ci = {
VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = 1ULL << log2,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
if (device.IsExtTransformFeedbackSupported()) {
buffer_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage);
if (device.HasDebuggingToolAttached()) {
++buffer_index;

View File

@@ -1279,6 +1279,10 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
flags |= VideoCommon::ImageFlagBits::Converted;
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
}
if (IsPixelFormatBCn(info.format) && !runtime->device.IsOptimalBcnSupported()) {
flags |= VideoCommon::ImageFlagBits::Converted;
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
}
if (runtime->device.HasDebuggingToolAttached()) {
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
}

View File

@@ -269,6 +269,28 @@ bool IsPixelFormatASTC(PixelFormat format) {
}
}
bool IsPixelFormatBCn(PixelFormat format) {
switch (format) {
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC2_UNORM:
case PixelFormat::BC3_UNORM:
case PixelFormat::BC4_UNORM:
case PixelFormat::BC4_SNORM:
case PixelFormat::BC5_UNORM:
case PixelFormat::BC5_SNORM:
case PixelFormat::BC1_RGBA_SRGB:
case PixelFormat::BC2_SRGB:
case PixelFormat::BC3_SRGB:
case PixelFormat::BC7_UNORM:
case PixelFormat::BC6H_UFLOAT:
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC7_SRGB:
return true;
default:
return false;
}
}
bool IsPixelFormatSRGB(PixelFormat format) {
switch (format) {
case PixelFormat::A8B8G8R8_SRGB:

View File

@@ -501,6 +501,8 @@ SurfaceType GetFormatType(PixelFormat pixel_format);
bool IsPixelFormatASTC(PixelFormat format);
bool IsPixelFormatBCn(PixelFormat format);
bool IsPixelFormatSRGB(PixelFormat format);
bool IsPixelFormatInteger(PixelFormat format);

View File

@@ -0,0 +1,129 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <span>
#include <bc_decoder.h>
#include "common/common_types.h"
#include "video_core/texture_cache/decode_bc.h"
namespace VideoCommon {
namespace {
constexpr u32 BLOCK_SIZE = 4;
using VideoCore::Surface::PixelFormat;
constexpr bool IsSigned(PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
return true;
default:
return false;
}
}
constexpr u32 BlockSize(PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC1_RGBA_SRGB:
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
return 8;
default:
return 16;
}
}
} // Anonymous namespace
u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
return 1;
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
return 2;
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
return 8;
default:
return 4;
}
}
template <auto decompress, PixelFormat pixel_format>
void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent,
bool is_signed = false) {
const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
const u32 block_width = std::min(extent.width, BLOCK_SIZE);
const u32 block_height = std::min(extent.height, BLOCK_SIZE);
const u32 pitch = extent.width * out_bpp;
size_t input_offset = 0;
size_t output_offset = 0;
for (u32 slice = 0; slice < extent.depth; ++slice) {
for (u32 y = 0; y < extent.height; y += block_height) {
size_t row_offset = 0;
for (u32 x = 0; x < extent.width;
x += block_width, row_offset += block_width * out_bpp) {
const u8* src = input.data() + input_offset;
u8* const dst = output.data() + output_offset + row_offset;
if constexpr (IsSigned(pixel_format)) {
decompress(src, dst, x, y, extent.width, extent.height, is_signed);
} else {
decompress(src, dst, x, y, extent.width, extent.height);
}
input_offset += BlockSize(pixel_format);
}
output_offset += block_height * pitch;
}
}
}
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
VideoCore::Surface::PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC1_RGBA_SRGB:
DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent);
break;
case PixelFormat::BC2_UNORM:
case PixelFormat::BC2_SRGB:
DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent);
break;
case PixelFormat::BC3_UNORM:
case PixelFormat::BC3_SRGB:
DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent);
break;
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
input, output, extent, pixel_format == PixelFormat::BC4_SNORM);
break;
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
input, output, extent, pixel_format == PixelFormat::BC5_SNORM);
break;
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT);
break;
case PixelFormat::BC7_SRGB:
case PixelFormat::BC7_UNORM:
DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent);
break;
default:
LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
}
}
} // namespace VideoCommon

View File

@@ -6,10 +6,14 @@
#include <span>
#include "common/common_types.h"
#include "video_core/surface.h"
#include "video_core/texture_cache/types.h"
namespace VideoCommon {
void DecompressBC4(std::span<const u8> data, Extent3D extent, std::span<u8> output);
[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
VideoCore::Surface::PixelFormat pixel_format);
} // namespace VideoCommon

View File

@@ -1,96 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <span>
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/texture_cache/decode_bc4.h"
#include "video_core/texture_cache/types.h"
namespace VideoCommon {
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt
[[nodiscard]] constexpr u32 DecompressBlock(u64 bits, u32 x, u32 y) {
const u32 code_offset = 16 + 3 * (4 * y + x);
const u32 code = (bits >> code_offset) & 7;
const u32 red0 = (bits >> 0) & 0xff;
const u32 red1 = (bits >> 8) & 0xff;
if (red0 > red1) {
switch (code) {
case 0:
return red0;
case 1:
return red1;
case 2:
return (6 * red0 + 1 * red1) / 7;
case 3:
return (5 * red0 + 2 * red1) / 7;
case 4:
return (4 * red0 + 3 * red1) / 7;
case 5:
return (3 * red0 + 4 * red1) / 7;
case 6:
return (2 * red0 + 5 * red1) / 7;
case 7:
return (1 * red0 + 6 * red1) / 7;
}
} else {
switch (code) {
case 0:
return red0;
case 1:
return red1;
case 2:
return (4 * red0 + 1 * red1) / 5;
case 3:
return (3 * red0 + 2 * red1) / 5;
case 4:
return (2 * red0 + 3 * red1) / 5;
case 5:
return (1 * red0 + 4 * red1) / 5;
case 6:
return 0;
case 7:
return 0xff;
}
}
return 0;
}
void DecompressBC4(std::span<const u8> input, Extent3D extent, std::span<u8> output) {
UNIMPLEMENTED_IF_MSG(extent.width % 4 != 0, "Unaligned width={}", extent.width);
UNIMPLEMENTED_IF_MSG(extent.height % 4 != 0, "Unaligned height={}", extent.height);
static constexpr u32 BLOCK_SIZE = 4;
size_t input_offset = 0;
for (u32 slice = 0; slice < extent.depth; ++slice) {
for (u32 block_y = 0; block_y < extent.height / 4; ++block_y) {
for (u32 block_x = 0; block_x < extent.width / 4; ++block_x) {
u64 bits;
std::memcpy(&bits, &input[input_offset], sizeof(bits));
input_offset += sizeof(bits);
for (u32 y = 0; y < BLOCK_SIZE; ++y) {
for (u32 x = 0; x < BLOCK_SIZE; ++x) {
const u32 linear_z = slice;
const u32 linear_y = block_y * BLOCK_SIZE + y;
const u32 linear_x = block_x * BLOCK_SIZE + x;
const u32 offset_z = linear_z * extent.width * extent.height;
const u32 offset_y = linear_y * extent.width;
const u32 offset_x = linear_x;
const u32 output_offset = (offset_z + offset_y + offset_x) * 4ULL;
const u32 color = DecompressBlock(bits, x, y);
output[output_offset + 0] = static_cast<u8>(color);
output[output_offset + 1] = 0;
output[output_offset + 2] = 0;
output[output_offset + 3] = 0xff;
}
}
}
}
}
}
} // namespace VideoCommon

View File

@@ -879,6 +879,10 @@ ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, boo
return NULL_IMAGE_ID;
}
auto& image = slot_images[image_id];
if (image.info.type == ImageType::e3D) {
// Don't accelerate 3D images.
return NULL_IMAGE_ID;
}
if (!is_upload && !image.info.dma_downloaded) {
// Force a full sync.
image.info.dma_downloaded = true;

View File

@@ -24,7 +24,7 @@
#include "video_core/engines/maxwell_3d.h"
#include "video_core/memory_manager.h"
#include "video_core/surface.h"
#include "video_core/texture_cache/decode_bc4.h"
#include "video_core/texture_cache/decode_bc.h"
#include "video_core/texture_cache/format_lookup_table.h"
#include "video_core/texture_cache/formatter.h"
#include "video_core/texture_cache/samples_helper.h"
@@ -61,8 +61,6 @@ using VideoCore::Surface::PixelFormatFromDepthFormat;
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
using VideoCore::Surface::SurfaceType;
constexpr u32 CONVERTED_BYTES_PER_BLOCK = BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
struct LevelInfo {
Extent3D size;
Extent3D block;
@@ -612,7 +610,8 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept {
}
return output_size;
}
return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * CONVERTED_BYTES_PER_BLOCK;
return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers *
ConvertedBytesPerBlock(info.format);
}
u32 CalculateLayerStride(const ImageInfo& info) noexcept {
@@ -945,7 +944,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
tile_size.height, output.subspan(output_offset));
output_offset += copy.image_extent.width * copy.image_extent.height *
copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK;
copy.image_subresource.num_layers *
BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
} else if (astc) {
// BC1 uses 0.5 bytes per texel
// BC3 uses 1 byte per texel
@@ -956,7 +956,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
const u32 plane_dim = copy.image_extent.width * copy.image_extent.height;
const u32 level_size = plane_dim * copy.image_extent.depth *
copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK;
copy.image_subresource.num_layers *
BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
decode_scratch.resize_destructive(level_size);
Tegra::Texture::ASTC::Decompress(
@@ -976,10 +977,15 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
bpp_div;
output_offset += static_cast<u32>(copy.buffer_size);
} else {
DecompressBC4(input_offset, copy.image_extent, output.subspan(output_offset));
const Extent3D image_extent{
.width = copy.image_extent.width,
.height = copy.image_extent.height * copy.image_subresource.num_layers,
.depth = copy.image_extent.depth,
};
DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
output_offset += copy.image_extent.width * copy.image_extent.height *
copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK;
copy.image_subresource.num_layers *
ConvertedBytesPerBlock(info.format);
}
}
}

View File

@@ -3,7 +3,6 @@
#include <stb_dxt.h>
#include <string.h>
#include "common/alignment.h"
#include "video_core/textures/bcn.h"
#include "video_core/textures/workers.h"

View File

@@ -4,14 +4,13 @@
#pragma once
#include <span>
#include <stdint.h>
#include "common/common_types.h"
namespace Tegra::Texture::BCN {
void CompressBC1(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
std::span<uint8_t> output);
void CompressBC1(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
void CompressBC3(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
std::span<uint8_t> output);
void CompressBC3(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
} // namespace Tegra::Texture::BCN

View File

@@ -7,10 +7,10 @@
namespace Vulkan {
namespace {
VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT* data,
[[maybe_unused]] void* user_data) {
VkBool32 DebugUtilCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT* data,
[[maybe_unused]] void* user_data) {
// Skip logging known false-positive validation errors
switch (static_cast<u32>(data->messageIdNumber)) {
#ifdef ANDROID
@@ -62,9 +62,26 @@ VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
}
return VK_FALSE;
}
VkBool32 DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType,
uint64_t object, size_t location, int32_t messageCode,
const char* pLayerPrefix, const char* pMessage, void* pUserData) {
const VkDebugReportFlagBitsEXT severity = static_cast<VkDebugReportFlagBitsEXT>(flags);
const std::string_view message{pMessage};
if (severity & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
LOG_CRITICAL(Render_Vulkan, "{}", message);
} else if (severity & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
LOG_WARNING(Render_Vulkan, "{}", message);
} else if (severity & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
LOG_INFO(Render_Vulkan, "{}", message);
} else if (severity & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
LOG_DEBUG(Render_Vulkan, "{}", message);
}
return VK_FALSE;
}
} // Anonymous namespace
vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) {
vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance) {
return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.pNext = nullptr,
@@ -76,7 +93,18 @@ vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) {
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
.pfnUserCallback = Callback,
.pfnUserCallback = DebugUtilCallback,
.pUserData = nullptr,
});
}
vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance) {
return instance.CreateDebugReportCallback({
.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
.pNext = nullptr,
.flags = VK_DEBUG_REPORT_DEBUG_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
.pfnCallback = DebugReportCallback,
.pUserData = nullptr,
});
}

View File

@@ -7,6 +7,8 @@
namespace Vulkan {
vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance);
vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance);
vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance);
} // namespace Vulkan

View File

@@ -349,7 +349,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
const bool is_s8gen2 = device_id == 0x43050a01;
const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
if ((is_mvk || is_qualcomm || is_turnip) && !is_suitable) {
if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) {
LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway");
} else if (!is_suitable) {
throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
@@ -528,6 +528,14 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
}
sets_per_pool = 64;
if (extensions.extended_dynamic_state3 && is_amd_driver &&
properties.properties.driverVersion >= VK_MAKE_API_VERSION(0, 2, 0, 270)) {
LOG_WARNING(Render_Vulkan,
"AMD drivers after 23.5.2 have broken extendedDynamicState3ColorBlendEquation");
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
dynamic_state3_blending = false;
}
if (is_amd_driver) {
// AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2.
sets_per_pool = 96;
@@ -905,6 +913,10 @@ bool Device::GetSuitability(bool requires_swapchain) {
properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
SetNext(next, properties.driver);
// Retrieve subgroup properties.
properties.subgroup_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
SetNext(next, properties.subgroup_properties);
// Retrieve relevant extension properties.
if (extensions.shader_float_controls) {
properties.float_controls.sType =

View File

@@ -293,6 +293,11 @@ public:
return features.features.textureCompressionASTC_LDR;
}
/// Returns true if BCn is natively supported.
bool IsOptimalBcnSupported() const {
return features.features.textureCompressionBC;
}
/// Returns true if descriptor aliasing is natively supported.
bool IsDescriptorAliasingSupported() const {
return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
@@ -323,6 +328,11 @@ public:
return properties.subgroup_size_control.requiredSubgroupSizeStages & stage;
}
/// Returns true if the device supports the provided subgroup feature.
bool IsSubgroupFeatureSupported(VkSubgroupFeatureFlagBits feature) const {
return properties.subgroup_properties.supportedOperations & feature;
}
/// Returns the maximum number of push descriptors.
u32 MaxPushDescriptors() const {
return properties.push_descriptor.maxPushDescriptors;
@@ -388,6 +398,11 @@ public:
return extensions.swapchain_mutable_format;
}
/// Returns true if VK_KHR_shader_float_controls is enabled.
bool IsKhrShaderFloatControlsSupported() const {
return extensions.shader_float_controls;
}
/// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
return extensions.workgroup_memory_explicit_layout;
@@ -413,6 +428,11 @@ public:
return extensions.sampler_filter_minmax;
}
/// Returns true if the device supports VK_EXT_shader_stencil_export.
bool IsExtShaderStencilExportSupported() const {
return extensions.shader_stencil_export;
}
/// Returns true if the device supports VK_EXT_depth_range_unrestricted.
bool IsExtDepthRangeUnrestrictedSupported() const {
return extensions.depth_range_unrestricted;
@@ -482,9 +502,9 @@ public:
return extensions.vertex_input_dynamic_state;
}
/// Returns true if the device supports VK_EXT_shader_stencil_export.
bool IsExtShaderStencilExportSupported() const {
return extensions.shader_stencil_export;
/// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation
bool IsExtShaderDemoteToHelperInvocationSupported() const {
return extensions.shader_demote_to_helper_invocation;
}
/// Returns true if the device supports VK_EXT_conservative_rasterization.
@@ -518,12 +538,12 @@ public:
if (extensions.spirv_1_4) {
return 0x00010400U;
}
return 0x00010000U;
return 0x00010300U;
}
/// Returns true when a known debugging tool is attached.
bool HasDebuggingToolAttached() const {
return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue();
return has_renderdoc || has_nsight_graphics;
}
/// @returns True if compute pipelines can cause crashing.
@@ -588,6 +608,10 @@ public:
return properties.properties.limits.maxVertexInputBindings;
}
u32 GetMaxViewports() const {
return properties.properties.limits.maxViewports;
}
bool SupportsConditionalBarriers() const {
return supports_conditional_barriers;
}
@@ -680,6 +704,7 @@ private:
struct Properties {
VkPhysicalDeviceDriverProperties driver{};
VkPhysicalDeviceSubgroupProperties subgroup_properties{};
VkPhysicalDeviceFloatControlsProperties float_controls{};
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};

View File

@@ -31,10 +31,34 @@
namespace Vulkan {
namespace {
[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
std::span<const char* const> extensions) {
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
if (!properties) {
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
return false;
}
for (const char* extension : extensions) {
const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
return std::strcmp(extension, prop.extensionName) == 0;
});
if (it == properties->end()) {
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
return false;
}
}
return true;
}
[[nodiscard]] std::vector<const char*> RequiredExtensions(
Core::Frontend::WindowSystemType window_type, bool enable_validation) {
const vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type,
bool enable_validation) {
std::vector<const char*> extensions;
extensions.reserve(6);
#ifdef __APPLE__
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
switch (window_type) {
case Core::Frontend::WindowSystemType::Headless:
break;
@@ -66,35 +90,14 @@ namespace {
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
}
if (enable_validation) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
const bool debug_utils =
AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
extensions.push_back(debug_utils ? VK_EXT_DEBUG_UTILS_EXTENSION_NAME
: VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
}
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef __APPLE__
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
return extensions;
}
[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
std::span<const char* const> extensions) {
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
if (!properties) {
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
return false;
}
for (const char* extension : extensions) {
const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
return std::strcmp(extension, prop.extensionName) == 0;
});
if (it == properties->end()) {
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
return false;
}
}
return true;
}
[[nodiscard]] std::vector<const char*> Layers(bool enable_validation) {
std::vector<const char*> layers;
if (enable_validation) {
@@ -138,7 +141,8 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_validation);
const std::vector<const char*> extensions =
RequiredExtensions(dld, window_type, enable_validation);
if (!AreExtensionsSupported(dld, extensions)) {
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
}

View File

@@ -259,7 +259,9 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
// These functions may fail to load depending on the enabled extensions.
// Don't return a failure on these.
X(vkCreateDebugUtilsMessengerEXT);
X(vkCreateDebugReportCallbackEXT);
X(vkDestroyDebugUtilsMessengerEXT);
X(vkDestroyDebugReportCallbackEXT);
X(vkDestroySurfaceKHR);
X(vkGetPhysicalDeviceFeatures2);
X(vkGetPhysicalDeviceProperties2);
@@ -481,6 +483,11 @@ void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle,
dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr);
}
void Destroy(VkInstance instance, VkDebugReportCallbackEXT handle,
const InstanceDispatch& dld) noexcept {
dld.vkDestroyDebugReportCallbackEXT(instance, handle, nullptr);
}
void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept {
dld.vkDestroySurfaceKHR(instance, handle, nullptr);
}
@@ -549,6 +556,13 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger(
return DebugUtilsMessenger(object, handle, *dld);
}
DebugReportCallback Instance::CreateDebugReportCallback(
const VkDebugReportCallbackCreateInfoEXT& create_info) const {
VkDebugReportCallbackEXT object;
Check(dld->vkCreateDebugReportCallbackEXT(handle, &create_info, nullptr, &object));
return DebugReportCallback(object, handle, *dld);
}
void Image::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
}

View File

@@ -164,8 +164,10 @@ struct InstanceDispatch {
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{};
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{};
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT{};
PFN_vkCreateDevice vkCreateDevice{};
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{};
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT{};
PFN_vkDestroyDevice vkDestroyDevice{};
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{};
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{};
@@ -366,6 +368,7 @@ void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
void Destroy(VkInstance, VkDebugReportCallbackEXT, const InstanceDispatch&) noexcept;
void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
@@ -581,6 +584,7 @@ private:
};
using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
using DebugReportCallback = Handle<VkDebugReportCallbackEXT, VkInstance, InstanceDispatch>;
using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>;
using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
@@ -613,6 +617,11 @@ public:
DebugUtilsMessenger CreateDebugUtilsMessenger(
const VkDebugUtilsMessengerCreateInfoEXT& create_info) const;
/// Creates a debug report callback.
/// @throw Exception on creation failure.
DebugReportCallback CreateDebugReportCallback(
const VkDebugReportCallbackCreateInfoEXT& create_info) const;
/// Returns dispatch table.
const InstanceDispatch& Dispatch() const noexcept {
return *dld;

View File

@@ -503,7 +503,8 @@ void Config::ReadMousePanningValues() {
ReadBasicSetting(Settings::values.mouse_panning);
ReadBasicSetting(Settings::values.mouse_panning_x_sensitivity);
ReadBasicSetting(Settings::values.mouse_panning_y_sensitivity);
ReadBasicSetting(Settings::values.mouse_panning_deadzone_counterweight);
ReadBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight);
ReadBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight);
ReadBasicSetting(Settings::values.mouse_panning_decay_strength);
ReadBasicSetting(Settings::values.mouse_panning_min_decay);
}
@@ -1121,7 +1122,8 @@ void Config::SaveMousePanningValues() {
// Don't overwrite values.mouse_panning
WriteBasicSetting(Settings::values.mouse_panning_x_sensitivity);
WriteBasicSetting(Settings::values.mouse_panning_y_sensitivity);
WriteBasicSetting(Settings::values.mouse_panning_deadzone_counterweight);
WriteBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight);
WriteBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight);
WriteBasicSetting(Settings::values.mouse_panning_decay_strength);
WriteBasicSetting(Settings::values.mouse_panning_min_decay);
}

View File

@@ -3105,6 +3105,21 @@
</property>
<item>
<widget class="QPushButton" name="mousePanningButton">
<property name="minimumSize">
<size>
<width>68</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>68</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">min-width: 68px;</string>
</property>
<property name="text">
<string>Configure</string>
</property>

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QCloseEvent>
#include <QMessageBox>
#include "common/settings.h"
#include "ui_configure_mouse_panning.h"
@@ -28,34 +27,31 @@ void ConfigureMousePanning::SetConfiguration(float right_stick_deadzone, float r
ui->enable->setChecked(Settings::values.mouse_panning.GetValue());
ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetValue());
ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetValue());
ui->deadzone_counterweight->setValue(
Settings::values.mouse_panning_deadzone_counterweight.GetValue());
ui->deadzone_x_counterweight->setValue(
Settings::values.mouse_panning_deadzone_x_counterweight.GetValue());
ui->deadzone_y_counterweight->setValue(
Settings::values.mouse_panning_deadzone_y_counterweight.GetValue());
ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetValue());
ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetValue());
if (right_stick_deadzone > 0.0f || right_stick_range != 1.0f) {
const QString right_stick_deadzone_str =
QString::fromStdString(std::to_string(static_cast<int>(right_stick_deadzone * 100.0f)));
const QString right_stick_range_str =
QString::fromStdString(std::to_string(static_cast<int>(right_stick_range * 100.0f)));
ui->warning_label->setText(
tr("Mouse panning works better with a deadzone of 0% and a range of 100%.\nCurrent "
"values are %1% and %2% respectively.")
.arg(right_stick_deadzone_str, right_stick_range_str));
}
if (Settings::values.mouse_enabled) {
ui->warning_label->setText(
tr("Emulated mouse is enabled. This is incompatible with mouse panning."));
ui->warning_label->setText(QString::fromStdString(
"Mouse panning works better with a deadzone of 0% and a range of 100%.\n"
"Current values are " +
std::to_string(static_cast<int>(right_stick_deadzone * 100.0f)) + "% and " +
std::to_string(static_cast<int>(right_stick_range * 100.0f)) + "% respectively."));
} else {
ui->warning_label->hide();
}
}
void ConfigureMousePanning::SetDefaultConfiguration() {
ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetDefault());
ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetDefault());
ui->deadzone_counterweight->setValue(
Settings::values.mouse_panning_deadzone_counterweight.GetDefault());
ui->deadzone_x_counterweight->setValue(
Settings::values.mouse_panning_deadzone_x_counterweight.GetDefault());
ui->deadzone_y_counterweight->setValue(
Settings::values.mouse_panning_deadzone_y_counterweight.GetDefault());
ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetDefault());
ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetDefault());
}
@@ -72,19 +68,12 @@ void ConfigureMousePanning::ApplyConfiguration() {
Settings::values.mouse_panning = ui->enable->isChecked();
Settings::values.mouse_panning_x_sensitivity = static_cast<float>(ui->x_sensitivity->value());
Settings::values.mouse_panning_y_sensitivity = static_cast<float>(ui->y_sensitivity->value());
Settings::values.mouse_panning_deadzone_counterweight =
static_cast<float>(ui->deadzone_counterweight->value());
Settings::values.mouse_panning_deadzone_x_counterweight =
static_cast<float>(ui->deadzone_x_counterweight->value());
Settings::values.mouse_panning_deadzone_y_counterweight =
static_cast<float>(ui->deadzone_y_counterweight->value());
Settings::values.mouse_panning_decay_strength = static_cast<float>(ui->decay_strength->value());
Settings::values.mouse_panning_min_decay = static_cast<float>(ui->min_decay->value());
if (Settings::values.mouse_enabled && Settings::values.mouse_panning) {
Settings::values.mouse_panning = false;
QMessageBox::critical(
this, tr("Emulated mouse is enabled"),
tr("Real mouse input and mouse panning are incompatible. Please disable the "
"emulated mouse in input advanced settings to allow mouse panning."));
return;
}
accept();
}

View File

@@ -9,10 +9,10 @@
<item>
<widget class="QCheckBox" name="enable">
<property name="text">
<string>Enable mouse panning</string>
<string>Enable</string>
</property>
<property name="toolTip">
<string>Can be toggled via a hotkey. Default hotkey is Ctrl + F9</string>
<string>Can be toggled via a hotkey</string>
</property>
</widget>
</item>
@@ -89,14 +89,40 @@
</property>
<layout class="QGridLayout">
<item row="0" column="0">
<widget class="QLabel" name="deadzone_counterweight_label">
<widget class="QLabel" name="deadzone_x_counterweight_label">
<property name="text">
<string>Deadzone</string>
<string>Horizontal</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="deadzone_counterweight">
<widget class="QSpinBox" name="deadzone_x_counterweight">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="deadzone_y_counterweight_label">
<property name="text">
<string>Vertical</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="deadzone_y_counterweight">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>

View File

@@ -305,6 +305,9 @@ void ConfigureRingController::EnableRingController() {
QMessageBox::warning(this, dialog_title,
tr("The current mapped device doesn't have a ring attached"));
break;
case Common::Input::DriverResult::InvalidHandle:
QMessageBox::warning(this, dialog_title, tr("The current mapped device is not connected"));
break;
default:
QMessageBox::warning(this, dialog_title,
tr("Unexpected driver result %1").arg(static_cast<int>(result)));