Compare commits
36 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
865abfc37c | ||
|
|
09bfc852dc | ||
|
|
ace74bd066 | ||
|
|
f6ee53af14 | ||
|
|
6c6cb5745f | ||
|
|
3262c0f747 | ||
|
|
9323a1f9b2 | ||
|
|
f02a8d0ae9 | ||
|
|
8517d7cb44 | ||
|
|
cb4b4f3d6e | ||
|
|
21e7f86697 | ||
|
|
347b3bd18d | ||
|
|
755c45777f | ||
|
|
d677052e8c | ||
|
|
95bfc542aa | ||
|
|
d0c60605ab | ||
|
|
6697b665ca | ||
|
|
12178c694a | ||
|
|
de1e5584b3 | ||
|
|
1559984f77 | ||
|
|
467ac4fdfe | ||
|
|
69b7100dac | ||
|
|
14dc41d4b3 | ||
|
|
ad049f13aa | ||
|
|
20e0407235 | ||
|
|
4f569fd568 | ||
|
|
553dac2ae0 | ||
|
|
96abe0d7d3 | ||
|
|
47e44a6693 | ||
|
|
cf8c7d4ed3 | ||
|
|
5165ed9efd | ||
|
|
05e3db3ac9 | ||
|
|
e3491a9ee8 | ||
|
|
6a1ddc5028 | ||
|
|
b1d4804c07 | ||
|
|
bbc0ed118d |
@@ -6,7 +6,12 @@
|
||||
export NDK_CCACHE="$(which ccache)"
|
||||
ccache -s
|
||||
|
||||
BUILD_FLAVOR=mainline
|
||||
BUILD_FLAVOR="mainline"
|
||||
|
||||
BUILD_TYPE="release"
|
||||
if [ "${GITHUB_REPOSITORY}" == "yuzu-emu/yuzu" ]; then
|
||||
BUILD_TYPE="relWithDebInfo"
|
||||
fi
|
||||
|
||||
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
|
||||
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
|
||||
@@ -15,7 +20,7 @@ fi
|
||||
|
||||
cd src/android
|
||||
chmod +x ./gradlew
|
||||
./gradlew "assemble${BUILD_FLAVOR}Release" "bundle${BUILD_FLAVOR}Release"
|
||||
./gradlew "assemble${BUILD_FLAVOR}${BUILD_TYPE}" "bundle${BUILD_FLAVOR}${BUILD_TYPE}"
|
||||
|
||||
ccache -s
|
||||
|
||||
|
||||
@@ -7,9 +7,16 @@
|
||||
|
||||
REV_NAME="yuzu-${GITDATE}-${GITREV}"
|
||||
|
||||
BUILD_FLAVOR=mainline
|
||||
BUILD_FLAVOR="mainline"
|
||||
|
||||
cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/release/app-${BUILD_FLAVOR}-release.apk" \
|
||||
BUILD_TYPE_LOWER="release"
|
||||
BUILD_TYPE_UPPER="Release"
|
||||
if [ "${GITHUB_REPOSITORY}" == "yuzu-emu/yuzu" ]; then
|
||||
BUILD_TYPE_LOWER="relWithDebInfo"
|
||||
BUILD_TYPE_UPPER="RelWithDebInfo"
|
||||
fi
|
||||
|
||||
cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/${BUILD_TYPE_LOWER}/app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.apk" \
|
||||
"artifacts/${REV_NAME}.apk"
|
||||
cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}Release"/"app-${BUILD_FLAVOR}-release.aab" \
|
||||
cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}${BUILD_TYPE_UPPER}"/"app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.aab" \
|
||||
"artifacts/${REV_NAME}.aab"
|
||||
|
||||
@@ -18,7 +18,8 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
RENDERER_ANTI_ALIASING("anti_aliasing"),
|
||||
RENDERER_SCREEN_LAYOUT("screen_layout"),
|
||||
RENDERER_ASPECT_RATIO("aspect_ratio"),
|
||||
AUDIO_OUTPUT_ENGINE("output_engine");
|
||||
AUDIO_OUTPUT_ENGINE("output_engine"),
|
||||
MAX_ANISOTROPY("max_anisotropy");
|
||||
|
||||
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
||||
|
||||
|
||||
@@ -243,6 +243,15 @@ abstract class SettingsItem(
|
||||
R.string.renderer_reactive_flushing_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.MAX_ANISOTROPY,
|
||||
R.string.anisotropic_filtering,
|
||||
R.string.anisotropic_filtering_description,
|
||||
R.array.anisoEntries,
|
||||
R.array.anisoValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.AUDIO_OUTPUT_ENGINE,
|
||||
@@ -298,6 +307,7 @@ abstract class SettingsItem(
|
||||
|
||||
override val key: String = FASTMEM_COMBINED
|
||||
override val isRuntimeModifiable: Boolean = false
|
||||
override val pairedSettingKey = BooleanSetting.CPU_DEBUG_MODE.key
|
||||
override val defaultValue: Boolean = true
|
||||
override val isSwitchable: Boolean = true
|
||||
override var global: Boolean
|
||||
|
||||
@@ -149,6 +149,7 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.RENDERER_VSYNC.key)
|
||||
add(IntSetting.RENDERER_SCALING_FILTER.key)
|
||||
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
||||
add(IntSetting.MAX_ANISOTROPY.key)
|
||||
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
||||
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1">
|
||||
|
||||
|
||||
@@ -267,4 +267,21 @@
|
||||
<item>3</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="anisoEntries">
|
||||
<item>@string/auto</item>
|
||||
<item>@string/slider_default</item>
|
||||
<item>@string/multiplier_two</item>
|
||||
<item>@string/multiplier_four</item>
|
||||
<item>@string/multiplier_eight</item>
|
||||
<item>@string/multiplier_sixteen</item>
|
||||
</string-array>
|
||||
<integer-array name="anisoValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
</integer-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -225,6 +225,8 @@
|
||||
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
||||
<string name="use_disk_shader_cache">Disk shader cache</string>
|
||||
<string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string>
|
||||
<string name="anisotropic_filtering">Anisotropic filtering</string>
|
||||
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
|
||||
|
||||
<!-- Debug settings strings -->
|
||||
<string name="cpu">CPU</string>
|
||||
@@ -506,6 +508,12 @@
|
||||
<string name="oboe">oboe</string>
|
||||
<string name="cubeb">cubeb</string>
|
||||
|
||||
<!-- Anisotropic filtering options -->
|
||||
<string name="multiplier_two">2x</string>
|
||||
<string name="multiplier_four">4x</string>
|
||||
<string name="multiplier_eight">8x</string>
|
||||
<string name="multiplier_sixteen">16x</string>
|
||||
|
||||
<!-- Black backgrounds theme -->
|
||||
<string name="use_black_backgrounds">Black backgrounds</string>
|
||||
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
|
||||
|
||||
@@ -3,16 +3,19 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/backend.h"
|
||||
|
||||
#include "common/settings.h"
|
||||
|
||||
void assert_fail_impl() {
|
||||
if (Settings::values.use_debug_asserts) {
|
||||
Common::Log::Stop();
|
||||
Crash();
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void unreachable_impl() {
|
||||
Common::Log::Stop();
|
||||
Crash();
|
||||
throw std::runtime_error("Unreachable code");
|
||||
}
|
||||
|
||||
@@ -208,6 +208,10 @@ public:
|
||||
instance->StartBackendThread();
|
||||
}
|
||||
|
||||
static void Stop() {
|
||||
instance->StopBackendThread();
|
||||
}
|
||||
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
|
||||
@@ -259,6 +263,15 @@ private:
|
||||
});
|
||||
}
|
||||
|
||||
void StopBackendThread() {
|
||||
backend_thread.request_stop();
|
||||
if (backend_thread.joinable()) {
|
||||
backend_thread.join();
|
||||
}
|
||||
|
||||
ForEachBackend([](Backend& backend) { backend.Flush(); });
|
||||
}
|
||||
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, std::string&& message) const {
|
||||
using std::chrono::duration_cast;
|
||||
@@ -313,6 +326,10 @@ void Start() {
|
||||
Impl::Start();
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
Impl::Stop();
|
||||
}
|
||||
|
||||
void DisableLoggingInTests() {
|
||||
initialization_in_progress_suppress_logging = true;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ void Initialize();
|
||||
|
||||
void Start();
|
||||
|
||||
/// Explicitly stops the logger thread and flushes the buffers
|
||||
void Stop();
|
||||
|
||||
void DisableLoggingInTests();
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,7 +103,7 @@ private:
|
||||
// Having them on the same cache-line would result in false-sharing between them.
|
||||
// TODO: Remove this ifdef whenever clang and GCC support
|
||||
// std::hardware_destructive_interference_size.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1911
|
||||
#ifdef __cpp_lib_hardware_interference_size
|
||||
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
|
||||
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
|
||||
#else
|
||||
|
||||
@@ -553,17 +553,26 @@ add_library(core STATIC
|
||||
hle/service/hid/controllers/types/keyboard_types.h
|
||||
hle/service/hid/controllers/types/mouse_types.h
|
||||
hle/service/hid/controllers/types/npad_types.h
|
||||
hle/service/hid/controllers/types/shared_memory_format.h
|
||||
hle/service/hid/controllers/types/touch_types.h
|
||||
hle/service/hid/controllers/applet_resource.cpp
|
||||
hle/service/hid/controllers/applet_resource.h
|
||||
hle/service/hid/controllers/capture_button.cpp
|
||||
hle/service/hid/controllers/capture_button.h
|
||||
hle/service/hid/controllers/console_six_axis.cpp
|
||||
hle/service/hid/controllers/console_six_axis.h
|
||||
hle/service/hid/controllers/controller_base.cpp
|
||||
hle/service/hid/controllers/controller_base.h
|
||||
hle/service/hid/controllers/debug_mouse.cpp
|
||||
hle/service/hid/controllers/debug_mouse.h
|
||||
hle/service/hid/controllers/debug_pad.cpp
|
||||
hle/service/hid/controllers/debug_pad.h
|
||||
hle/service/hid/controllers/digitizer.cpp
|
||||
hle/service/hid/controllers/digitizer.h
|
||||
hle/service/hid/controllers/gesture.cpp
|
||||
hle/service/hid/controllers/gesture.h
|
||||
hle/service/hid/controllers/home_button.cpp
|
||||
hle/service/hid/controllers/home_button.h
|
||||
hle/service/hid/controllers/keyboard.cpp
|
||||
hle/service/hid/controllers/keyboard.h
|
||||
hle/service/hid/controllers/mouse.cpp
|
||||
@@ -574,15 +583,16 @@ add_library(core STATIC
|
||||
hle/service/hid/controllers/palma.h
|
||||
hle/service/hid/controllers/seven_six_axis.cpp
|
||||
hle/service/hid/controllers/seven_six_axis.h
|
||||
hle/service/hid/controllers/shared_memory_format.h
|
||||
hle/service/hid/controllers/shared_memory_holder.cpp
|
||||
hle/service/hid/controllers/shared_memory_holder.h
|
||||
hle/service/hid/controllers/six_axis.cpp
|
||||
hle/service/hid/controllers/six_axis.h
|
||||
hle/service/hid/controllers/stubbed.cpp
|
||||
hle/service/hid/controllers/stubbed.h
|
||||
hle/service/hid/controllers/sleep_button.cpp
|
||||
hle/service/hid/controllers/sleep_button.h
|
||||
hle/service/hid/controllers/touchscreen.cpp
|
||||
hle/service/hid/controllers/touchscreen.h
|
||||
hle/service/hid/controllers/unique_pad.cpp
|
||||
hle/service/hid/controllers/unique_pad.h
|
||||
hle/service/hid/hidbus/hidbus_base.cpp
|
||||
hle/service/hid/hidbus/hidbus_base.h
|
||||
hle/service/hid/hidbus/ringcon.cpp
|
||||
|
||||
@@ -8,19 +8,22 @@
|
||||
namespace Kernel {
|
||||
|
||||
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
m_object_list.insert_unique(*obj);
|
||||
}
|
||||
|
||||
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
m_object_list.erase(*obj);
|
||||
}
|
||||
|
||||
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
return std::count_if(m_object_list.begin(), m_object_list.end(),
|
||||
[&](const auto& obj) { return obj.GetOwner() == owner; });
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -21,32 +21,7 @@ public:
|
||||
|
||||
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
|
||||
|
||||
class ListAccessor : public KScopedLightLock {
|
||||
public:
|
||||
explicit ListAccessor(KAutoObjectWithListContainer* container)
|
||||
: KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
|
||||
explicit ListAccessor(KAutoObjectWithListContainer& container)
|
||||
: KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
|
||||
|
||||
typename ListType::iterator begin() const {
|
||||
return m_list.begin();
|
||||
}
|
||||
|
||||
typename ListType::iterator end() const {
|
||||
return m_list.end();
|
||||
}
|
||||
|
||||
typename ListType::iterator find(typename ListType::const_reference ref) const {
|
||||
return m_list.find(ref);
|
||||
}
|
||||
|
||||
private:
|
||||
ListType& m_list;
|
||||
};
|
||||
|
||||
friend class ListAccessor;
|
||||
|
||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
|
||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {}
|
||||
|
||||
void Initialize() {}
|
||||
void Finalize() {}
|
||||
@@ -56,7 +31,7 @@ public:
|
||||
size_t GetOwnedCount(KProcess* owner);
|
||||
|
||||
private:
|
||||
KLightLock m_lock;
|
||||
KSpinLock m_lock;
|
||||
ListType m_object_list;
|
||||
};
|
||||
|
||||
|
||||
@@ -185,6 +185,10 @@ Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) {
|
||||
case RegionType::NoMapping:
|
||||
break;
|
||||
case RegionType::KernelTraceBuffer:
|
||||
if constexpr (!IsKTraceEnabled) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case RegionType::OnMemoryBootImage:
|
||||
case RegionType::DTB:
|
||||
R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
|
||||
@@ -330,8 +334,6 @@ Result KCapabilities::SetCapabilities(std::span<const u32> caps, KProcessPageTab
|
||||
|
||||
// Map the range.
|
||||
R_TRY(this->MapRange_(cap, size_cap, page_table));
|
||||
} else if (GetCapabilityType(cap) == CapabilityType::MapRegion && !IsKTraceEnabled) {
|
||||
continue;
|
||||
} else {
|
||||
R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
public:
|
||||
explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
|
||||
|
||||
Result Initialize(KProcess* owner, s32 size) {
|
||||
Result Initialize(s32 size) {
|
||||
// Check that the table size is valid.
|
||||
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
|
||||
|
||||
@@ -44,7 +44,6 @@ public:
|
||||
m_next_linear_id = MinLinearId;
|
||||
m_count = 0;
|
||||
m_free_head_index = -1;
|
||||
m_owner = owner;
|
||||
|
||||
// Free all entries.
|
||||
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
|
||||
@@ -91,8 +90,7 @@ public:
|
||||
// Handle pseudo-handles.
|
||||
if constexpr (std::derived_from<KProcess, T>) {
|
||||
if (handle == Svc::PseudoHandle::CurrentProcess) {
|
||||
// TODO: this should be the current process
|
||||
auto* const cur_process = m_owner;
|
||||
auto* const cur_process = GetCurrentProcessPointer(m_kernel);
|
||||
ASSERT(cur_process != nullptr);
|
||||
return cur_process;
|
||||
}
|
||||
@@ -302,7 +300,6 @@ private:
|
||||
|
||||
private:
|
||||
KernelCore& m_kernel;
|
||||
KProcess* m_owner{};
|
||||
std::array<EntryInfo, MaxTableSize> m_entry_infos{};
|
||||
std::array<KAutoObject*, MaxTableSize> m_objects{};
|
||||
mutable KSpinLock m_lock;
|
||||
|
||||
@@ -552,7 +552,7 @@ private:
|
||||
|
||||
Result InitializeHandleTable(s32 size) {
|
||||
// Try to initialize the handle table.
|
||||
R_TRY(m_handle_table.Initialize(this, size));
|
||||
R_TRY(m_handle_table.Initialize(size));
|
||||
|
||||
// We succeeded, so note that we did.
|
||||
m_is_handle_table_initialized = true;
|
||||
|
||||
@@ -1147,8 +1147,7 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
|
||||
*out_context =
|
||||
std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread);
|
||||
(*out_context)->SetSessionRequestManager(manager);
|
||||
(*out_context)
|
||||
->PopulateFromIncomingCommandBuffer(*client_thread->GetOwnerProcess(), cmd_buf);
|
||||
(*out_context)->PopulateFromIncomingCommandBuffer(cmd_buf);
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_page_group.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
|
||||
@@ -1513,8 +1513,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem =
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||
|
||||
if (transfer_mem.IsNull()) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
@@ -1524,8 +1523,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
||||
}
|
||||
|
||||
std::vector<u8> memory(transfer_mem->GetSize());
|
||||
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
||||
memory.size());
|
||||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -1547,8 +1545,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem =
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||
|
||||
if (transfer_mem.IsNull()) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
@@ -1558,8 +1555,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
std::vector<u8> memory(transfer_mem->GetSize());
|
||||
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
||||
memory.size());
|
||||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
@@ -454,10 +454,8 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
|
||||
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
|
||||
auto transfer_memory{
|
||||
process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
const auto session_id{impl->GetSessionId()};
|
||||
if (session_id == -1) {
|
||||
|
||||
@@ -278,9 +278,7 @@ void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
|
||||
auto params = rp.PopRaw<OpusParameters>();
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
||||
params.sample_rate, params.channel_count, transfer_memory_size);
|
||||
@@ -323,9 +321,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
|
||||
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio,
|
||||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
||||
@@ -374,9 +370,7 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
|
||||
auto params = rp.PopRaw<OpusParametersEx>();
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
||||
params.sample_rate, params.channel_count, transfer_memory_size);
|
||||
@@ -414,9 +408,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
|
||||
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio,
|
||||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
|
||||
namespace Service::HID {
|
||||
@@ -164,6 +164,22 @@ Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_mem
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
AruidData* AppletResource::GetAruidData(u64 aruid) {
|
||||
const u64 aruid_index = GetIndexFromAruid(aruid);
|
||||
if (aruid_index == AruidIndexMax) {
|
||||
return nullptr;
|
||||
}
|
||||
return &data[aruid_index];
|
||||
}
|
||||
|
||||
AruidData* AppletResource::GetAruidDataByIndex(std::size_t aruid_index) {
|
||||
return &data[aruid_index];
|
||||
}
|
||||
|
||||
bool AppletResource::IsVibrationAruidActive(u64 aruid) const {
|
||||
return aruid == 0 || aruid == active_vibration_aruid;
|
||||
}
|
||||
|
||||
u64 AppletResource::GetIndexFromAruid(u64 aruid) {
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
if (registration_list.flag[i] == RegistrationStatus::Initialized &&
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
@@ -20,6 +21,59 @@ class KSharedMemory;
|
||||
|
||||
namespace Service::HID {
|
||||
struct SharedMemoryFormat;
|
||||
class AppletResource;
|
||||
class NPadResource;
|
||||
|
||||
static constexpr std::size_t AruidIndexMax = 0x20;
|
||||
|
||||
enum class RegistrationStatus : u32 {
|
||||
None,
|
||||
Initialized,
|
||||
PendingDelete,
|
||||
};
|
||||
|
||||
struct DataStatusFlag {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> is_initialized;
|
||||
BitField<1, 1, u32> is_assigned;
|
||||
BitField<16, 1, u32> enable_pad_input;
|
||||
BitField<17, 1, u32> enable_six_axis_sensor;
|
||||
BitField<18, 1, u32> bit_18;
|
||||
BitField<19, 1, u32> is_palma_connectable;
|
||||
BitField<20, 1, u32> enable_palma_boost_mode;
|
||||
BitField<21, 1, u32> enable_touchscreen;
|
||||
};
|
||||
};
|
||||
|
||||
struct AruidRegisterList {
|
||||
std::array<RegistrationStatus, AruidIndexMax> flag{};
|
||||
std::array<u64, AruidIndexMax> aruid{};
|
||||
};
|
||||
static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size");
|
||||
|
||||
struct AruidData {
|
||||
DataStatusFlag flag{};
|
||||
u64 aruid{};
|
||||
SharedMemoryFormat* shared_memory_format{nullptr};
|
||||
};
|
||||
|
||||
struct HandheldConfig {
|
||||
bool is_handheld_hid_enabled;
|
||||
bool is_force_handheld;
|
||||
bool is_joycon_rail_enabled;
|
||||
bool is_force_handheld_style_vibration;
|
||||
};
|
||||
static_assert(sizeof(HandheldConfig) == 0x4, "HandheldConfig is an invalid size");
|
||||
|
||||
struct AppletResourceHolder {
|
||||
std::shared_ptr<AppletResource> applet_resource{nullptr};
|
||||
std::recursive_mutex* shared_mutex{nullptr};
|
||||
NPadResource* shared_npad_resource{nullptr};
|
||||
std::shared_ptr<HandheldConfig> handheld_config{nullptr};
|
||||
long* handle_1;
|
||||
};
|
||||
|
||||
class AppletResource {
|
||||
public:
|
||||
@@ -36,6 +90,10 @@ public:
|
||||
u64 GetActiveAruid();
|
||||
Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
|
||||
Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid);
|
||||
AruidData* GetAruidData(u64 aruid);
|
||||
AruidData* GetAruidDataByIndex(std::size_t aruid_index);
|
||||
|
||||
bool IsVibrationAruidActive(u64 aruid) const;
|
||||
|
||||
u64 GetIndexFromAruid(u64 aruid);
|
||||
|
||||
@@ -52,46 +110,12 @@ public:
|
||||
Result UnregisterCoreAppletResource();
|
||||
|
||||
private:
|
||||
static constexpr std::size_t AruidIndexMax = 0x20;
|
||||
|
||||
enum RegistrationStatus : u32 {
|
||||
None,
|
||||
Initialized,
|
||||
PendingDelete,
|
||||
};
|
||||
|
||||
struct DataStatusFlag {
|
||||
union {
|
||||
u32 raw{};
|
||||
|
||||
BitField<0, 1, u32> is_initialized;
|
||||
BitField<1, 1, u32> is_assigned;
|
||||
BitField<16, 1, u32> enable_pad_input;
|
||||
BitField<17, 1, u32> enable_six_axis_sensor;
|
||||
BitField<18, 1, u32> bit_18;
|
||||
BitField<19, 1, u32> is_palma_connectable;
|
||||
BitField<20, 1, u32> enable_palma_boost_mode;
|
||||
BitField<21, 1, u32> enable_touchscreen;
|
||||
};
|
||||
};
|
||||
|
||||
struct AruidRegisterList {
|
||||
std::array<RegistrationStatus, AruidIndexMax> flag{};
|
||||
std::array<u64, AruidIndexMax> aruid{};
|
||||
};
|
||||
static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size");
|
||||
|
||||
struct AruidData {
|
||||
DataStatusFlag flag{};
|
||||
u64 aruid{};
|
||||
SharedMemoryFormat* shared_memory_format{nullptr};
|
||||
};
|
||||
|
||||
u64 active_aruid{};
|
||||
AruidRegisterList registration_list{};
|
||||
std::array<AruidData, AruidIndexMax> data{};
|
||||
std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{};
|
||||
s32 ref_counter{};
|
||||
u64 active_vibration_aruid;
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
38
src/core/hle/service/hid/controllers/capture_button.cpp
Normal file
38
src/core/hle/service/hid/controllers/capture_button.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/capture_button.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
CaptureButton::CaptureButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
CaptureButton::~CaptureButton() = default;
|
||||
|
||||
void CaptureButton::OnInit() {}
|
||||
|
||||
void CaptureButton::OnRelease() {}
|
||||
|
||||
void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->capture_button.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
@@ -6,12 +6,11 @@
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
struct CommonHeader;
|
||||
|
||||
class Controller_Stubbed final : public ControllerBase {
|
||||
class CaptureButton final : public ControllerBase {
|
||||
public:
|
||||
explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, CommonHeader& ring_lifo_header);
|
||||
~Controller_Stubbed() override;
|
||||
explicit CaptureButton(Core::HID::HIDCore& hid_core_);
|
||||
~CaptureButton() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
@@ -23,7 +22,6 @@ public:
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
CommonHeader& header;
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
||||
@@ -5,13 +5,11 @@
|
||||
#include "core/hid/emulated_console.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/console_six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
|
||||
ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory)
|
||||
: ControllerBase{hid_core_}, shared_memory{console_shared_memory} {
|
||||
ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
|
||||
@@ -22,6 +20,15 @@ void ConsoleSixAxis::OnInit() {}
|
||||
void ConsoleSixAxis::OnRelease() {}
|
||||
|
||||
void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConsoleSixAxisSensorSharedMemoryFormat& shared_memory = data->shared_memory_format->console;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,12 +10,9 @@ class EmulatedConsole;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
struct ConsoleSixAxisSensorSharedMemoryFormat;
|
||||
|
||||
class ConsoleSixAxis final : public ControllerBase {
|
||||
public:
|
||||
explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
|
||||
ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory);
|
||||
explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_);
|
||||
~ConsoleSixAxis() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
@@ -28,7 +25,6 @@ public:
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
ConsoleSixAxisSensorSharedMemoryFormat& shared_memory;
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -31,4 +31,9 @@ void ControllerBase::DeactivateController() {
|
||||
bool ControllerBase::IsControllerActivated() const {
|
||||
return is_activated;
|
||||
}
|
||||
|
||||
void ControllerBase::SetAppletResource(std::shared_ptr<AppletResource> resource) {
|
||||
applet_resource = resource;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
@@ -12,7 +15,7 @@ class CoreTiming;
|
||||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
}
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class ControllerBase {
|
||||
@@ -39,8 +42,11 @@ public:
|
||||
|
||||
bool IsControllerActivated() const;
|
||||
|
||||
void SetAppletResource(std::shared_ptr<AppletResource> resource);
|
||||
|
||||
protected:
|
||||
bool is_activated{false};
|
||||
std::shared_ptr<AppletResource> applet_resource{nullptr};
|
||||
|
||||
Core::HID::HIDCore& hid_core;
|
||||
};
|
||||
|
||||
63
src/core/hle/service/hid/controllers/debug_mouse.cpp
Normal file
63
src/core/hle/service/hid/controllers/debug_mouse.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/debug_mouse.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
DebugMouse::DebugMouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
emulated_devices = hid_core.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
DebugMouse::~DebugMouse() = default;
|
||||
|
||||
void DebugMouse::OnInit() {}
|
||||
void DebugMouse::OnRelease() {}
|
||||
|
||||
void DebugMouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_mouse;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.mouse_lifo.buffer_count = 0;
|
||||
shared_memory.mouse_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
next_state = {};
|
||||
|
||||
const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state;
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
if (Settings::values.mouse_enabled) {
|
||||
const auto& mouse_button_state = emulated_devices->GetMouseButtons();
|
||||
const auto& mouse_position_state = emulated_devices->GetMousePosition();
|
||||
const auto& mouse_wheel_state = emulated_devices->GetMouseWheel();
|
||||
next_state.attribute.is_connected.Assign(1);
|
||||
next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width);
|
||||
next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height);
|
||||
next_state.delta_x = next_state.x - last_entry.x;
|
||||
next_state.delta_y = next_state.y - last_entry.y;
|
||||
next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x;
|
||||
next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
|
||||
|
||||
last_mouse_wheel_state = mouse_wheel_state;
|
||||
next_state.button = mouse_button_state;
|
||||
}
|
||||
|
||||
shared_memory.mouse_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
34
src/core/hle/service/hid/controllers/debug_mouse.h
Normal file
34
src/core/hle/service/hid/controllers/debug_mouse.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedDevices;
|
||||
struct MouseState;
|
||||
struct AnalogStickState;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
class DebugMouse final : public ControllerBase {
|
||||
public:
|
||||
explicit DebugMouse(Core::HID::HIDCore& hid_core_);
|
||||
~DebugMouse() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
Core::HID::MouseState next_state{};
|
||||
Core::HID::AnalogStickState last_mouse_wheel_state{};
|
||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
||||
@@ -6,14 +6,13 @@
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
DebugPad::DebugPad(Core::HID::HIDCore& hid_core_,
|
||||
DebugPadSharedMemoryFormat& debug_pad_shared_memory)
|
||||
: ControllerBase{hid_core_}, shared_memory{debug_pad_shared_memory} {
|
||||
DebugPad::DebugPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
|
||||
}
|
||||
|
||||
@@ -24,6 +23,15 @@ void DebugPad::OnInit() {}
|
||||
void DebugPad::OnRelease() {}
|
||||
|
||||
void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
DebugPadSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_pad;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.debug_pad_lifo.buffer_count = 0;
|
||||
shared_memory.debug_pad_lifo.buffer_tail = 0;
|
||||
|
||||
@@ -15,12 +15,9 @@ class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
struct DebugPadSharedMemoryFormat;
|
||||
|
||||
class DebugPad final : public ControllerBase {
|
||||
public:
|
||||
explicit DebugPad(Core::HID::HIDCore& hid_core_,
|
||||
DebugPadSharedMemoryFormat& debug_pad_shared_memory);
|
||||
explicit DebugPad(Core::HID::HIDCore& hid_core_);
|
||||
~DebugPad() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
@@ -34,7 +31,6 @@ public:
|
||||
|
||||
private:
|
||||
DebugPadState next_state{};
|
||||
DebugPadSharedMemoryFormat& shared_memory;
|
||||
Core::HID::EmulatedController* controller = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
||||
|
||||
38
src/core/hle/service/hid/controllers/digitizer.cpp
Normal file
38
src/core/hle/service/hid/controllers/digitizer.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/digitizer.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Digitizer::Digitizer(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
Digitizer::~Digitizer() = default;
|
||||
|
||||
void Digitizer::OnInit() {}
|
||||
|
||||
void Digitizer::OnRelease() {}
|
||||
|
||||
void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->digitizer.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
27
src/core/hle/service/hid/controllers/digitizer.h
Normal file
27
src/core/hle/service/hid/controllers/digitizer.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class Digitizer final : public ControllerBase {
|
||||
public:
|
||||
explicit Digitizer(Core::HID::HIDCore& hid_core_);
|
||||
~Digitizer() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
||||
@@ -6,8 +6,9 @@
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_console.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/gesture.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
// HW is around 700, value is set to 400 to make it easier to trigger with mouse
|
||||
@@ -21,24 +22,40 @@ constexpr f32 Square(s32 num) {
|
||||
return static_cast<f32>(num * num);
|
||||
}
|
||||
|
||||
Gesture::Gesture(Core::HID::HIDCore& hid_core_, GestureSharedMemoryFormat& gesture_shared_memory)
|
||||
: ControllerBase(hid_core_), shared_memory{gesture_shared_memory} {
|
||||
Gesture::Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) {
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
Gesture::~Gesture() = default;
|
||||
|
||||
void Gesture::OnInit() {
|
||||
shared_memory.gesture_lifo.buffer_count = 0;
|
||||
shared_memory.gesture_lifo.buffer_tail = 0;
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
shared_memory = &data->shared_memory_format->gesture;
|
||||
shared_memory->gesture_lifo.buffer_count = 0;
|
||||
shared_memory->gesture_lifo.buffer_tail = 0;
|
||||
force_update = true;
|
||||
}
|
||||
|
||||
void Gesture::OnRelease() {}
|
||||
|
||||
void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
shared_memory = &data->shared_memory_format->gesture;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.gesture_lifo.buffer_count = 0;
|
||||
shared_memory.gesture_lifo.buffer_tail = 0;
|
||||
shared_memory->gesture_lifo.buffer_count = 0;
|
||||
shared_memory->gesture_lifo.buffer_tail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,7 +63,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
|
||||
GestureProperties gesture = GetGestureProperties();
|
||||
f32 time_difference =
|
||||
static_cast<f32>(shared_memory.gesture_lifo.timestamp - last_update_timestamp) /
|
||||
static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
|
||||
(1000 * 1000 * 1000);
|
||||
|
||||
// Only update if necessary
|
||||
@@ -54,7 +71,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_update_timestamp = shared_memory.gesture_lifo.timestamp;
|
||||
last_update_timestamp = shared_memory->gesture_lifo.timestamp;
|
||||
UpdateGestureSharedMemory(gesture, time_difference);
|
||||
}
|
||||
|
||||
@@ -97,7 +114,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
|
||||
GestureType type = GestureType::Idle;
|
||||
GestureAttribute attributes{};
|
||||
|
||||
const auto& last_entry = shared_memory.gesture_lifo.ReadCurrentEntry().state;
|
||||
const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state;
|
||||
|
||||
// Reset next state to default
|
||||
next_state.sampling_number = last_entry.sampling_number + 1;
|
||||
@@ -127,7 +144,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
|
||||
next_state.points = gesture.points;
|
||||
last_gesture = gesture;
|
||||
|
||||
shared_memory.gesture_lifo.WriteNextEntry(next_state);
|
||||
shared_memory->gesture_lifo.WriteNextEntry(next_state);
|
||||
}
|
||||
|
||||
void Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
|
||||
@@ -300,7 +317,7 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_
|
||||
}
|
||||
|
||||
const GestureState& Gesture::GetLastGestureEntry() const {
|
||||
return shared_memory.gesture_lifo.ReadCurrentEntry().state;
|
||||
return shared_memory->gesture_lifo.ReadCurrentEntry().state;
|
||||
}
|
||||
|
||||
GestureProperties Gesture::GetGestureProperties() {
|
||||
|
||||
@@ -18,8 +18,7 @@ struct GestureSharedMemoryFormat;
|
||||
|
||||
class Gesture final : public ControllerBase {
|
||||
public:
|
||||
explicit Gesture(Core::HID::HIDCore& hid_core_,
|
||||
GestureSharedMemoryFormat& gesture_shared_memory);
|
||||
explicit Gesture(Core::HID::HIDCore& hid_core_);
|
||||
~Gesture() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
@@ -74,7 +73,7 @@ private:
|
||||
GestureProperties GetGestureProperties();
|
||||
|
||||
GestureState next_state{};
|
||||
GestureSharedMemoryFormat& shared_memory;
|
||||
GestureSharedMemoryFormat* shared_memory;
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
|
||||
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
|
||||
|
||||
38
src/core/hle/service/hid/controllers/home_button.cpp
Normal file
38
src/core/hle/service/hid/controllers/home_button.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/home_button.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
HomeButton::HomeButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
HomeButton::~HomeButton() = default;
|
||||
|
||||
void HomeButton::OnInit() {}
|
||||
|
||||
void HomeButton::OnRelease() {}
|
||||
|
||||
void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->home_button.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
27
src/core/hle/service/hid/controllers/home_button.h
Normal file
27
src/core/hle/service/hid/controllers/home_button.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class HomeButton final : public ControllerBase {
|
||||
public:
|
||||
explicit HomeButton(Core::HID::HIDCore& hid_core_);
|
||||
~HomeButton() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
||||
@@ -5,14 +5,13 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/keyboard.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Keyboard::Keyboard(Core::HID::HIDCore& hid_core_,
|
||||
KeyboardSharedMemoryFormat& keyboard_shared_memory)
|
||||
: ControllerBase{hid_core_}, shared_memory{keyboard_shared_memory} {
|
||||
Keyboard::Keyboard(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
emulated_devices = hid_core.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
@@ -23,6 +22,15 @@ void Keyboard::OnInit() {}
|
||||
void Keyboard::OnRelease() {}
|
||||
|
||||
void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
KeyboardSharedMemoryFormat& shared_memory = data->shared_memory_format->keyboard;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.keyboard_lifo.buffer_count = 0;
|
||||
shared_memory.keyboard_lifo.buffer_tail = 0;
|
||||
|
||||
@@ -7,12 +7,9 @@
|
||||
#include "core/hle/service/hid/controllers/types/keyboard_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
struct KeyboardSharedMemoryFormat;
|
||||
|
||||
class Keyboard final : public ControllerBase {
|
||||
public:
|
||||
explicit Keyboard(Core::HID::HIDCore& hid_core_,
|
||||
KeyboardSharedMemoryFormat& keyboard_shared_memory);
|
||||
explicit Keyboard(Core::HID::HIDCore& hid_core_);
|
||||
~Keyboard() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
@@ -26,7 +23,6 @@ public:
|
||||
|
||||
private:
|
||||
KeyboardState next_state{};
|
||||
KeyboardSharedMemoryFormat& shared_memory;
|
||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_devices.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/mouse.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Mouse::Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory)
|
||||
: ControllerBase{hid_core_}, shared_memory{mouse_shared_memory} {
|
||||
Mouse::Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
|
||||
emulated_devices = hid_core.GetEmulatedDevices();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,15 @@ void Mouse::OnInit() {}
|
||||
void Mouse::OnRelease() {}
|
||||
|
||||
void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->mouse;
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
shared_memory.mouse_lifo.buffer_count = 0;
|
||||
shared_memory.mouse_lifo.buffer_tail = 0;
|
||||
|
||||
@@ -12,11 +12,9 @@ struct AnalogStickState;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::HID {
|
||||
struct MouseSharedMemoryFormat;
|
||||
|
||||
class Mouse final : public ControllerBase {
|
||||
public:
|
||||
explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory);
|
||||
explicit Mouse(Core::HID::HIDCore& hid_core_);
|
||||
~Mouse() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
@@ -31,7 +29,6 @@ public:
|
||||
private:
|
||||
Core::HID::MouseState next_state{};
|
||||
Core::HID::AnalogStickState last_mouse_wheel_state{};
|
||||
MouseSharedMemoryFormat& shared_memory;
|
||||
Core::HID::EmulatedDevices* emulated_devices = nullptr;
|
||||
};
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_util.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
@@ -30,12 +31,10 @@ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
|
||||
Core::HID::NpadIdType::Handheld,
|
||||
};
|
||||
|
||||
NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
|
||||
KernelHelpers::ServiceContext& service_context_)
|
||||
NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
|
||||
: ControllerBase{hid_core_}, service_context{service_context_} {
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
auto& controller = controller_data[i];
|
||||
controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state;
|
||||
controller.device = hid_core.GetEmulatedControllerByIndex(i);
|
||||
controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
|
||||
Core::HID::DEFAULT_VIBRATION_VALUE;
|
||||
@@ -297,12 +296,20 @@ void NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
}
|
||||
|
||||
void NPad::OnInit() {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
auto& controller = controller_data[i];
|
||||
controller.shared_memory = &data->shared_memory_format->npad.npad_entry[i].internal_state;
|
||||
controller.styleset_changed_event =
|
||||
service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
|
||||
}
|
||||
@@ -355,7 +362,9 @@ void NPad::OnRelease() {
|
||||
is_controller_initialized = false;
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
auto& controller = controller_data[i];
|
||||
service_context.CloseEvent(controller.styleset_changed_event);
|
||||
if (controller.styleset_changed_event) {
|
||||
service_context.CloseEvent(controller.styleset_changed_event);
|
||||
}
|
||||
for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
|
||||
VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {});
|
||||
}
|
||||
@@ -432,12 +441,20 @@ void NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
|
||||
}
|
||||
|
||||
void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
auto& controller = controller_data[i];
|
||||
controller.shared_memory = &data->shared_memory_format->npad.npad_entry[i].internal_state;
|
||||
auto* npad = controller.shared_memory;
|
||||
|
||||
const auto& controller_type = controller.device->GetNpadStyleIndex();
|
||||
@@ -976,30 +993,6 @@ Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
NpadSixAxisSensorLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
|
||||
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo;
|
||||
}
|
||||
|
||||
NpadSixAxisSensorLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
|
||||
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo;
|
||||
}
|
||||
|
||||
NpadSixAxisSensorLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
|
||||
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo;
|
||||
}
|
||||
|
||||
NpadSixAxisSensorLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
|
||||
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo;
|
||||
}
|
||||
|
||||
NpadSixAxisSensorLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
|
||||
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo;
|
||||
}
|
||||
|
||||
NpadSixAxisSensorLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
|
||||
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo;
|
||||
}
|
||||
|
||||
Result NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
|
||||
Core::HID::NpadIdType npad_id_2) {
|
||||
if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
|
||||
|
||||
@@ -30,14 +30,14 @@ class ServiceContext;
|
||||
union Result;
|
||||
|
||||
namespace Service::HID {
|
||||
class AppletResource;
|
||||
struct NpadInternalState;
|
||||
struct NpadSixAxisSensorLifo;
|
||||
struct NpadSharedMemoryFormat;
|
||||
|
||||
class NPad final : public ControllerBase {
|
||||
public:
|
||||
explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
|
||||
KernelHelpers::ServiceContext& service_context_);
|
||||
explicit NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
|
||||
~NPad() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
@@ -106,13 +106,6 @@ public:
|
||||
Result ResetIsSixAxisSensorDeviceNewlyAssigned(
|
||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle);
|
||||
|
||||
NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
|
||||
NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
|
||||
NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
|
||||
NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
|
||||
NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
|
||||
NpadSixAxisSensorLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
|
||||
|
||||
Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
|
||||
Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
|
||||
bool& is_enabled) const;
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_holder.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_util.h"
|
||||
|
||||
@@ -27,14 +27,20 @@ void SixAxis::OnInit() {}
|
||||
void SixAxis::OnRelease() {}
|
||||
|
||||
void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i];
|
||||
auto& controller = controller_data[i];
|
||||
|
||||
const auto npad_id = IndexToNpadIdType(i);
|
||||
const auto& controller_type = controller.device->GetNpadStyleIndex();
|
||||
|
||||
if (controller_type == Core::HID::NpadStyleIndex::None ||
|
||||
@@ -50,12 +56,12 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
|
||||
auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
|
||||
|
||||
auto& sixaxis_fullkey_lifo = npad->GetSixAxisFullkeyLifo(npad_id);
|
||||
auto& sixaxis_handheld_lifo = npad->GetSixAxisHandheldLifo(npad_id);
|
||||
auto& sixaxis_dual_left_lifo = npad->GetSixAxisDualLeftLifo(npad_id);
|
||||
auto& sixaxis_dual_right_lifo = npad->GetSixAxisDualRightLifo(npad_id);
|
||||
auto& sixaxis_left_lifo = npad->GetSixAxisLeftLifo(npad_id);
|
||||
auto& sixaxis_right_lifo = npad->GetSixAxisRightLifo(npad_id);
|
||||
auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo;
|
||||
auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo;
|
||||
auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo;
|
||||
auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo;
|
||||
auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo;
|
||||
auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo;
|
||||
|
||||
// Clear previous state
|
||||
sixaxis_fullkey_state = {};
|
||||
|
||||
38
src/core/hle/service/hid/controllers/sleep_button.cpp
Normal file
38
src/core/hle/service/hid/controllers/sleep_button.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/sleep_button.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
SleepButton::SleepButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
SleepButton::~SleepButton() = default;
|
||||
|
||||
void SleepButton::OnInit() {}
|
||||
|
||||
void SleepButton::OnRelease() {}
|
||||
|
||||
void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->capture_button.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
27
src/core/hle/service/hid/controllers/sleep_button.h
Normal file
27
src/core/hle/service/hid/controllers/sleep_button.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class SleepButton final : public ControllerBase {
|
||||
public:
|
||||
explicit SleepButton(Core::HID::HIDCore& hid_core_);
|
||||
~SleepButton() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
||||
@@ -1,31 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/stubbed.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_,
|
||||
CommonHeader& ring_lifo_header)
|
||||
: ControllerBase{hid_core_}, header{ring_lifo_header} {}
|
||||
|
||||
Controller_Stubbed::~Controller_Stubbed() = default;
|
||||
|
||||
void Controller_Stubbed::OnInit() {}
|
||||
|
||||
void Controller_Stubbed::OnRelease() {}
|
||||
|
||||
void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
@@ -8,15 +8,14 @@
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hid/emulated_console.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_,
|
||||
TouchScreenSharedMemoryFormat& touch_shared_memory)
|
||||
: ControllerBase{hid_core_}, shared_memory{touch_shared_memory},
|
||||
touchscreen_width(Layout::ScreenUndocked::Width),
|
||||
TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_)
|
||||
: ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width),
|
||||
touchscreen_height(Layout::ScreenUndocked::Height) {
|
||||
console = hid_core.GetEmulatedConsole();
|
||||
}
|
||||
@@ -28,6 +27,14 @@ void TouchScreen::OnInit() {}
|
||||
void TouchScreen::OnRelease() {}
|
||||
|
||||
void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
TouchScreenSharedMemoryFormat& shared_memory = data->shared_memory_format->touch_screen;
|
||||
shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
|
||||
@@ -18,8 +18,7 @@ struct TouchScreenSharedMemoryFormat;
|
||||
|
||||
class TouchScreen final : public ControllerBase {
|
||||
public:
|
||||
explicit TouchScreen(Core::HID::HIDCore& hid_core_,
|
||||
TouchScreenSharedMemoryFormat& touch_shared_memory);
|
||||
explicit TouchScreen(Core::HID::HIDCore& hid_core_);
|
||||
~TouchScreen() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
@@ -35,7 +34,6 @@ public:
|
||||
|
||||
private:
|
||||
TouchScreenState next_state{};
|
||||
TouchScreenSharedMemoryFormat& shared_memory;
|
||||
Core::HID::EmulatedConsole* console = nullptr;
|
||||
|
||||
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
|
||||
|
||||
38
src/core/hle/service/hid/controllers/unique_pad.cpp
Normal file
38
src/core/hle/service/hid/controllers/unique_pad.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/unique_pad.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
UniquePad::UniquePad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
|
||||
|
||||
UniquePad::~UniquePad() = default;
|
||||
|
||||
void UniquePad::OnInit() {}
|
||||
|
||||
void UniquePad::OnRelease() {}
|
||||
|
||||
void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& header = data->shared_memory_format->capture_button.header;
|
||||
header.timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
header.total_entry_count = 17;
|
||||
header.entry_count = 0;
|
||||
header.last_entry_index = 0;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
27
src/core/hle/service/hid/controllers/unique_pad.h
Normal file
27
src/core/hle/service/hid/controllers/unique_pad.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
class UniquePad final : public ControllerBase {
|
||||
public:
|
||||
explicit UniquePad(Core::HID::HIDCore& hid_core_);
|
||||
~UniquePad() override;
|
||||
|
||||
// Called when the controller is initialized
|
||||
void OnInit() override;
|
||||
|
||||
// When the controller is released
|
||||
void OnRelease() override;
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
||||
@@ -1850,8 +1850,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
|
||||
ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
|
||||
ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
|
||||
|
||||
auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_1_handle);
|
||||
auto t_mem_1 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_1_handle);
|
||||
|
||||
if (t_mem_1.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
|
||||
@@ -1860,8 +1859,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_2_handle);
|
||||
auto t_mem_2 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_2_handle);
|
||||
|
||||
if (t_mem_2.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
|
||||
@@ -2142,8 +2140,7 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
|
||||
|
||||
ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
|
||||
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
|
||||
@@ -448,8 +448,7 @@ void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
|
||||
|
||||
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
|
||||
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
|
||||
@@ -197,8 +197,7 @@ void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
@@ -444,8 +443,7 @@ void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
|
||||
@@ -10,18 +10,23 @@
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
#include "core/hle/service/hid/controllers/applet_resource.h"
|
||||
#include "core/hle/service/hid/controllers/capture_button.h"
|
||||
#include "core/hle/service/hid/controllers/console_six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/debug_mouse.h"
|
||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
||||
#include "core/hle/service/hid/controllers/digitizer.h"
|
||||
#include "core/hle/service/hid/controllers/gesture.h"
|
||||
#include "core/hle/service/hid/controllers/home_button.h"
|
||||
#include "core/hle/service/hid/controllers/keyboard.h"
|
||||
#include "core/hle/service/hid/controllers/mouse.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/palma.h"
|
||||
#include "core/hle/service/hid/controllers/seven_six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/six_axis.h"
|
||||
#include "core/hle/service/hid/controllers/stubbed.h"
|
||||
#include "core/hle/service/hid/controllers/sleep_button.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/controllers/types/shared_memory_format.h"
|
||||
#include "core/hle/service/hid/controllers/unique_pad.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
@@ -46,44 +51,15 @@ void ResourceManager::Initialize() {
|
||||
}
|
||||
|
||||
system.HIDCore().ReloadInputDevices();
|
||||
|
||||
InitializeHidCommonSampler();
|
||||
InitializeTouchScreenSampler();
|
||||
InitializeConsoleSixAxisSampler();
|
||||
InitializeAHidSampler();
|
||||
|
||||
is_initialized = true;
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeController(u64 aruid) {
|
||||
SharedMemoryFormat* shared_memory = nullptr;
|
||||
const auto result = applet_resource->GetSharedMemoryFormat(&shared_memory, aruid);
|
||||
if (result.IsError()) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory->debug_pad);
|
||||
mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory->mouse);
|
||||
debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory->debug_mouse);
|
||||
keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory->keyboard);
|
||||
unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory->unique_pad.header);
|
||||
npad = std::make_shared<NPad>(system.HIDCore(), shared_memory->npad, service_context);
|
||||
gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory->gesture);
|
||||
touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory->touch_screen);
|
||||
|
||||
palma = std::make_shared<Palma>(system.HIDCore(), service_context);
|
||||
|
||||
home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory->home_button.header);
|
||||
sleep_button =
|
||||
std::make_shared<SleepButton>(system.HIDCore(), shared_memory->sleep_button.header);
|
||||
capture_button =
|
||||
std::make_shared<CaptureButton>(system.HIDCore(), shared_memory->capture_button.header);
|
||||
digitizer = std::make_shared<Digitizer>(system.HIDCore(), shared_memory->digitizer.header);
|
||||
|
||||
six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
|
||||
console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory->console);
|
||||
seven_six_axis = std::make_shared<SevenSixAxis>(system);
|
||||
|
||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
||||
npad->Activate();
|
||||
six_axis->Activate();
|
||||
touch_screen->Activate();
|
||||
}
|
||||
|
||||
std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const {
|
||||
return applet_resource;
|
||||
}
|
||||
@@ -165,16 +141,65 @@ Result ResourceManager::CreateAppletResource(u64 aruid) {
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
||||
npad->Activate();
|
||||
six_axis->Activate();
|
||||
touch_screen->Activate();
|
||||
|
||||
return GetNpad()->Activate(aruid);
|
||||
}
|
||||
|
||||
Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
|
||||
std::scoped_lock lock{shared_mutex};
|
||||
const auto result = applet_resource->CreateAppletResource(aruid);
|
||||
if (result.IsSuccess()) {
|
||||
InitializeController(aruid);
|
||||
}
|
||||
return result;
|
||||
return applet_resource->CreateAppletResource(aruid);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeHidCommonSampler() {
|
||||
debug_pad = std::make_shared<DebugPad>(system.HIDCore());
|
||||
mouse = std::make_shared<Mouse>(system.HIDCore());
|
||||
debug_mouse = std::make_shared<DebugMouse>(system.HIDCore());
|
||||
keyboard = std::make_shared<Keyboard>(system.HIDCore());
|
||||
unique_pad = std::make_shared<UniquePad>(system.HIDCore());
|
||||
npad = std::make_shared<NPad>(system.HIDCore(), service_context);
|
||||
gesture = std::make_shared<Gesture>(system.HIDCore());
|
||||
home_button = std::make_shared<HomeButton>(system.HIDCore());
|
||||
sleep_button = std::make_shared<SleepButton>(system.HIDCore());
|
||||
capture_button = std::make_shared<CaptureButton>(system.HIDCore());
|
||||
digitizer = std::make_shared<Digitizer>(system.HIDCore());
|
||||
|
||||
palma = std::make_shared<Palma>(system.HIDCore(), service_context);
|
||||
six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
|
||||
|
||||
debug_pad->SetAppletResource(applet_resource);
|
||||
digitizer->SetAppletResource(applet_resource);
|
||||
keyboard->SetAppletResource(applet_resource);
|
||||
npad->SetAppletResource(applet_resource);
|
||||
six_axis->SetAppletResource(applet_resource);
|
||||
mouse->SetAppletResource(applet_resource);
|
||||
debug_mouse->SetAppletResource(applet_resource);
|
||||
home_button->SetAppletResource(applet_resource);
|
||||
sleep_button->SetAppletResource(applet_resource);
|
||||
capture_button->SetAppletResource(applet_resource);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeTouchScreenSampler() {
|
||||
gesture = std::make_shared<Gesture>(system.HIDCore());
|
||||
touch_screen = std::make_shared<TouchScreen>(system.HIDCore());
|
||||
|
||||
touch_screen->SetAppletResource(applet_resource);
|
||||
gesture->SetAppletResource(applet_resource);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeConsoleSixAxisSampler() {
|
||||
console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore());
|
||||
seven_six_axis = std::make_shared<SevenSixAxis>(system);
|
||||
|
||||
console_six_axis->SetAppletResource(applet_resource);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeAHidSampler() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
Result ResourceManager::RegisterCoreAppletResource() {
|
||||
|
||||
@@ -20,24 +20,23 @@ class KSharedMemory;
|
||||
|
||||
namespace Service::HID {
|
||||
class AppletResource;
|
||||
class CaptureButton;
|
||||
class Controller_Stubbed;
|
||||
class ConsoleSixAxis;
|
||||
class DebugMouse;
|
||||
class DebugPad;
|
||||
class Digitizer;
|
||||
class Gesture;
|
||||
class HomeButton;
|
||||
class Keyboard;
|
||||
class Mouse;
|
||||
class NPad;
|
||||
class Palma;
|
||||
class SevenSixAxis;
|
||||
class SixAxis;
|
||||
class SleepButton;
|
||||
class TouchScreen;
|
||||
|
||||
using CaptureButton = Controller_Stubbed;
|
||||
using DebugMouse = Mouse;
|
||||
using Digitizer = Controller_Stubbed;
|
||||
using HomeButton = Controller_Stubbed;
|
||||
using SleepButton = Controller_Stubbed;
|
||||
using UniquePad = Controller_Stubbed;
|
||||
class UniquePad;
|
||||
|
||||
class ResourceManager {
|
||||
|
||||
@@ -46,7 +45,6 @@ public:
|
||||
~ResourceManager();
|
||||
|
||||
void Initialize();
|
||||
void InitializeController(u64 aruid);
|
||||
|
||||
std::shared_ptr<AppletResource> GetAppletResource() const;
|
||||
std::shared_ptr<CaptureButton> GetCaptureButton() const;
|
||||
@@ -88,6 +86,10 @@ public:
|
||||
|
||||
private:
|
||||
Result CreateAppletResourceImpl(u64 aruid);
|
||||
void InitializeHidCommonSampler();
|
||||
void InitializeTouchScreenSampler();
|
||||
void InitializeConsoleSixAxisSampler();
|
||||
void InitializeAHidSampler();
|
||||
|
||||
bool is_initialized{false};
|
||||
|
||||
|
||||
@@ -146,10 +146,7 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory::
|
||||
|
||||
HLERequestContext::~HLERequestContext() = default;
|
||||
|
||||
void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf,
|
||||
bool incoming) {
|
||||
client_handle_table = &process.GetHandleTable();
|
||||
|
||||
void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||
IPC::RequestParser rp(src_cmdbuf);
|
||||
command_header = rp.PopRaw<IPC::CommandHeader>();
|
||||
|
||||
@@ -162,7 +159,7 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr
|
||||
if (command_header->enable_handle_descriptor) {
|
||||
handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
|
||||
if (handle_descriptor_header->send_current_pid) {
|
||||
pid = process.GetProcessId();
|
||||
pid = thread->GetOwnerProcess()->GetProcessId();
|
||||
rp.Skip(2, false);
|
||||
}
|
||||
if (incoming) {
|
||||
@@ -270,9 +267,10 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr
|
||||
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
|
||||
}
|
||||
|
||||
Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process,
|
||||
u32_le* src_cmdbuf) {
|
||||
ParseCommandBuffer(process, src_cmdbuf, true);
|
||||
Result HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf) {
|
||||
client_handle_table = &thread->GetOwnerProcess()->GetHandleTable();
|
||||
|
||||
ParseCommandBuffer(src_cmdbuf, true);
|
||||
|
||||
if (command_header->IsCloseCommand()) {
|
||||
// Close does not populate the rest of the IPC header
|
||||
@@ -284,9 +282,9 @@ Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& pr
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread) {
|
||||
Result HLERequestContext::WriteToOutgoingCommandBuffer() {
|
||||
auto current_offset = handles_offset;
|
||||
auto& owner_process = *requesting_thread.GetOwnerProcess();
|
||||
auto& owner_process = *thread->GetOwnerProcess();
|
||||
auto& handle_table = owner_process.GetHandleTable();
|
||||
|
||||
for (auto& object : outgoing_copy_objects) {
|
||||
@@ -319,7 +317,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesti
|
||||
}
|
||||
|
||||
// Copy the translated command buffer back into the thread's command buffer area.
|
||||
memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
|
||||
memory.WriteBlock(thread->GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "common/concepts.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/k_handle_table.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
|
||||
union Result;
|
||||
@@ -196,10 +197,10 @@ public:
|
||||
}
|
||||
|
||||
/// Populates this context with data from the requesting process/thread.
|
||||
Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf);
|
||||
Result PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf);
|
||||
|
||||
/// Writes data from this context back to the requesting process/thread.
|
||||
Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread);
|
||||
Result WriteToOutgoingCommandBuffer();
|
||||
|
||||
[[nodiscard]] u32_le GetHipcCommand() const {
|
||||
return command;
|
||||
@@ -359,8 +360,17 @@ public:
|
||||
return *thread;
|
||||
}
|
||||
|
||||
Kernel::KHandleTable& GetClientHandleTable() {
|
||||
return *client_handle_table;
|
||||
[[nodiscard]] Core::Memory::Memory& GetMemory() const {
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Kernel::KScopedAutoObject<T> GetObjectFromHandle(u32 handle) {
|
||||
auto obj = client_handle_table->GetObjectForIpc(handle, thread);
|
||||
if (obj.IsNotNull()) {
|
||||
return obj->DynamicCast<T*>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const {
|
||||
@@ -378,7 +388,7 @@ public:
|
||||
private:
|
||||
friend class IPC::ResponseBuilder;
|
||||
|
||||
void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming);
|
||||
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
|
||||
|
||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||
Kernel::KServerSession* server_session{};
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx,
|
||||
CodeRange user_ro)
|
||||
: ServiceFramework{system_, "IJitEnvironment"}, process{&process_},
|
||||
context{system_.ApplicationMemory()} {
|
||||
context{process->GetMemory()} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IJitEnvironment::GenerateCode, "GenerateCode"},
|
||||
@@ -188,7 +188,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto tmem{process->GetHandleTable().GetObject<Kernel::KTransferMemory>(tmem_handle)};
|
||||
auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)};
|
||||
if (tmem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -356,11 +356,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch using the handle table for the application process here,
|
||||
// since we are not multiprocess yet.
|
||||
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
|
||||
|
||||
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
|
||||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
|
||||
if (process.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -368,7 +364,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto rx_mem{handle_table.GetObject<Kernel::KCodeMemory>(rx_mem_handle)};
|
||||
auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)};
|
||||
if (rx_mem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -376,7 +372,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto ro_mem{handle_table.GetObject<Kernel::KCodeMemory>(ro_mem_handle)};
|
||||
auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)};
|
||||
if (ro_mem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
@@ -651,10 +651,9 @@ private:
|
||||
void RegisterProcessHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDR, "(called)");
|
||||
|
||||
auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
|
||||
auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
|
||||
auto client_pid = ctx.GetPID();
|
||||
auto result = interface.RegisterProcessHandle(client_pid,
|
||||
process_h->DynamicCast<Kernel::KProcess*>());
|
||||
auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
@@ -671,12 +670,11 @@ private:
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params = rp.PopRaw<InputParameters>();
|
||||
auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
|
||||
auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
|
||||
|
||||
auto client_pid = ctx.GetPID();
|
||||
auto result =
|
||||
interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size,
|
||||
process_h->DynamicCast<Kernel::KProcess*>());
|
||||
auto result = interface.RegisterProcessModuleInfo(
|
||||
client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
|
||||
@@ -203,7 +203,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
|
||||
// If emulation was shutdown, we are closing service threads, do not write the response back to
|
||||
// memory that may be shutting down as well.
|
||||
if (system.IsPoweredOn()) {
|
||||
ctx.WriteToOutgoingCommandBuffer(ctx.GetThread());
|
||||
ctx.WriteToOutgoingCommandBuffer();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -96,9 +96,9 @@ Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) {
|
||||
}
|
||||
|
||||
Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin,
|
||||
spv::StorageClass storage_class) {
|
||||
spv::StorageClass storage_class, std::optional<Id> initializer = std::nullopt) {
|
||||
const Id pointer_type{ctx.TypePointer(storage_class, type)};
|
||||
const Id id{ctx.AddGlobalVariable(pointer_type, storage_class)};
|
||||
const Id id{ctx.AddGlobalVariable(pointer_type, storage_class, initializer)};
|
||||
if (builtin) {
|
||||
ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin);
|
||||
}
|
||||
@@ -144,11 +144,12 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
|
||||
}
|
||||
|
||||
Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations,
|
||||
std::optional<spv::BuiltIn> builtin = std::nullopt) {
|
||||
std::optional<spv::BuiltIn> builtin = std::nullopt,
|
||||
std::optional<Id> initializer = std::nullopt) {
|
||||
if (invocations && ctx.stage == Stage::TessellationControl) {
|
||||
type = ctx.TypeArray(type, ctx.Const(*invocations));
|
||||
}
|
||||
return DefineVariable(ctx, type, builtin, spv::StorageClass::Output);
|
||||
return DefineVariable(ctx, type, builtin, spv::StorageClass::Output, initializer);
|
||||
}
|
||||
|
||||
void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) {
|
||||
@@ -811,10 +812,14 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
||||
labels.push_back(OpLabel());
|
||||
}
|
||||
if (info.stores.ClipDistances()) {
|
||||
literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2);
|
||||
labels.push_back(OpLabel());
|
||||
literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2);
|
||||
labels.push_back(OpLabel());
|
||||
if (profile.max_user_clip_distances >= 4) {
|
||||
literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2);
|
||||
labels.push_back(OpLabel());
|
||||
}
|
||||
if (profile.max_user_clip_distances >= 8) {
|
||||
literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2);
|
||||
labels.push_back(OpLabel());
|
||||
}
|
||||
}
|
||||
OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone);
|
||||
OpSwitch(compare_index, default_label, literals, labels);
|
||||
@@ -843,17 +848,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
||||
++label_index;
|
||||
}
|
||||
if (info.stores.ClipDistances()) {
|
||||
AddLabel(labels[label_index]);
|
||||
const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)};
|
||||
OpStore(pointer, store_value);
|
||||
OpReturn();
|
||||
++label_index;
|
||||
AddLabel(labels[label_index]);
|
||||
const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))};
|
||||
const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)};
|
||||
OpStore(pointer2, store_value);
|
||||
OpReturn();
|
||||
++label_index;
|
||||
if (profile.max_user_clip_distances >= 4) {
|
||||
AddLabel(labels[label_index]);
|
||||
const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)};
|
||||
OpStore(pointer, store_value);
|
||||
OpReturn();
|
||||
++label_index;
|
||||
}
|
||||
if (profile.max_user_clip_distances >= 8) {
|
||||
AddLabel(labels[label_index]);
|
||||
const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))};
|
||||
const Id pointer{OpAccessChain(output_f32, clip_distances, fixed_index)};
|
||||
OpStore(pointer, store_value);
|
||||
OpReturn();
|
||||
++label_index;
|
||||
}
|
||||
}
|
||||
AddLabel(end_block);
|
||||
OpUnreachable();
|
||||
@@ -1532,9 +1541,16 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
|
||||
if (stage == Stage::Fragment) {
|
||||
throw NotImplementedException("Storing ClipDistance in fragment stage");
|
||||
}
|
||||
const Id type{TypeArray(
|
||||
F32[1], Const(std::min(info.used_clip_distances, profile.max_user_clip_distances)))};
|
||||
clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance);
|
||||
if (profile.max_user_clip_distances > 0) {
|
||||
const u32 used{std::min(profile.max_user_clip_distances, 8u)};
|
||||
const std::array<Id, 8> zero{f32_zero_value, f32_zero_value, f32_zero_value,
|
||||
f32_zero_value, f32_zero_value, f32_zero_value,
|
||||
f32_zero_value, f32_zero_value};
|
||||
const Id type{TypeArray(F32[1], Const(used))};
|
||||
const Id initializer{ConstantComposite(type, std::span(zero).subspan(0, used))};
|
||||
clip_distances =
|
||||
DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance, initializer);
|
||||
}
|
||||
}
|
||||
if (info.stores[IR::Attribute::Layer] &&
|
||||
(profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) {
|
||||
|
||||
@@ -327,12 +327,13 @@ public:
|
||||
explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback();
|
||||
|
||||
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU);
|
||||
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
|
||||
if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) {
|
||||
Fallback(parameters);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& params = maxwell3d.draw_manager->GetIndirectParams();
|
||||
params.is_byte_count = true;
|
||||
params.is_indexed = false;
|
||||
@@ -503,6 +504,8 @@ public:
|
||||
maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
|
||||
maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)),
|
||||
regs.transform_feedback.controls[0].stride, true);
|
||||
|
||||
maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -173,5 +173,13 @@ public:
|
||||
virtual void BindChannel(Tegra::Control::ChannelState& channel) {}
|
||||
|
||||
virtual void ReleaseChannel(s32 channel_id) {}
|
||||
|
||||
/// Register the address as a Transform Feedback Object
|
||||
virtual void RegisterTransformFeedback(GPUVAddr tfb_object_addr) {}
|
||||
|
||||
/// Returns true when the rasterizer has Draw Transform Feedback capabilities
|
||||
virtual bool HasDrawTransformFeedback() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // namespace VideoCore
|
||||
|
||||
@@ -376,4 +376,15 @@ void BufferCacheRuntime::BindImageBuffer(Buffer& buffer, u32 offset, u32 size, P
|
||||
*image_handles++ = buffer.View(offset, size, format);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindTransformFeedbackObject(GPUVAddr tfb_object_addr) {
|
||||
OGLTransformFeedback& tfb_object = tfb_objects[tfb_object_addr];
|
||||
tfb_object.Create();
|
||||
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb_object.handle);
|
||||
}
|
||||
|
||||
GLuint BufferCacheRuntime::GetTransformFeedbackObject(GPUVAddr tfb_object_addr) {
|
||||
ASSERT(tfb_objects.contains(tfb_object_addr));
|
||||
return tfb_objects[tfb_object_addr].handle;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/buffer_cache/buffer_cache_base.h"
|
||||
@@ -121,6 +122,9 @@ public:
|
||||
void BindImageBuffer(Buffer& buffer, u32 offset, u32 size,
|
||||
VideoCore::Surface::PixelFormat format);
|
||||
|
||||
void BindTransformFeedbackObject(GPUVAddr tfb_object_addr);
|
||||
GLuint GetTransformFeedbackObject(GPUVAddr tfb_object_addr);
|
||||
|
||||
u64 GetDeviceMemoryUsage() const;
|
||||
|
||||
void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) {
|
||||
@@ -233,6 +237,7 @@ private:
|
||||
u32 index_buffer_offset = 0;
|
||||
|
||||
u64 device_access_memory;
|
||||
std::unordered_map<GPUVAddr, OGLTransformFeedback> tfb_objects;
|
||||
};
|
||||
|
||||
struct BufferCacheParams {
|
||||
|
||||
@@ -309,6 +309,13 @@ void RasterizerOpenGL::DrawIndirect() {
|
||||
const auto& params = maxwell3d->draw_manager->GetIndirectParams();
|
||||
buffer_cache.SetDrawIndirect(¶ms);
|
||||
PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) {
|
||||
if (params.is_byte_count) {
|
||||
const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
|
||||
const GLuint tfb_object =
|
||||
buffer_cache_runtime.GetTransformFeedbackObject(tfb_object_base_addr);
|
||||
glDrawTransformFeedback(primitive_mode, tfb_object);
|
||||
return;
|
||||
}
|
||||
const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer();
|
||||
const GLvoid* const gl_offset =
|
||||
reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset));
|
||||
@@ -1371,6 +1378,10 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) {
|
||||
query_cache.EraseChannel(channel_id);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::RegisterTransformFeedback(GPUVAddr tfb_object_addr) {
|
||||
buffer_cache_runtime.BindTransformFeedbackObject(tfb_object_addr);
|
||||
}
|
||||
|
||||
AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_)
|
||||
: buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {}
|
||||
|
||||
|
||||
@@ -139,6 +139,12 @@ public:
|
||||
|
||||
void ReleaseChannel(s32 channel_id) override;
|
||||
|
||||
void RegisterTransformFeedback(GPUVAddr tfb_object_addr) override;
|
||||
|
||||
bool HasDrawTransformFeedback() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_TEXTURES = 192;
|
||||
static constexpr size_t MAX_IMAGES = 48;
|
||||
|
||||
@@ -207,4 +207,21 @@ void OGLQuery::Release() {
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLTransformFeedback::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glCreateTransformFeedbacks(1, &handle);
|
||||
}
|
||||
|
||||
void OGLTransformFeedback::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteTransformFeedbacks(1, &handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -323,4 +323,31 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLTransformFeedback final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLTransformFeedback);
|
||||
|
||||
OGLTransformFeedback() = default;
|
||||
|
||||
OGLTransformFeedback(OGLTransformFeedback&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
|
||||
~OGLTransformFeedback() {
|
||||
Release();
|
||||
}
|
||||
|
||||
OGLTransformFeedback& operator=(OGLTransformFeedback&& o) noexcept {
|
||||
Release();
|
||||
handle = std::exchange(o.handle, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -60,66 +60,72 @@ u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
|
||||
}
|
||||
|
||||
template <auto decompress, PixelFormat pixel_format>
|
||||
void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent,
|
||||
void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
|
||||
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;
|
||||
const u32 block_size = BlockSize(pixel_format);
|
||||
const u32 width = copy.image_extent.width;
|
||||
const u32 height = copy.image_extent.height * copy.image_subresource.num_layers;
|
||||
const u32 depth = copy.image_extent.depth;
|
||||
const u32 block_width = std::min(width, BLOCK_SIZE);
|
||||
const u32 block_height = std::min(height, BLOCK_SIZE);
|
||||
const u32 pitch = 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;
|
||||
for (u32 slice = 0; slice < depth; ++slice) {
|
||||
for (u32 y = 0; y < height; y += block_height) {
|
||||
size_t src_offset = input_offset;
|
||||
size_t dst_offset = output_offset;
|
||||
for (u32 x = 0; x < width; x += block_width) {
|
||||
const u8* src = input.data() + src_offset;
|
||||
u8* const dst = output.data() + dst_offset;
|
||||
if constexpr (IsSigned(pixel_format)) {
|
||||
decompress(src, dst, x, y, extent.width, extent.height, is_signed);
|
||||
decompress(src, dst, x, y, width, height, is_signed);
|
||||
} else {
|
||||
decompress(src, dst, x, y, extent.width, extent.height);
|
||||
decompress(src, dst, x, y, width, height);
|
||||
}
|
||||
input_offset += BlockSize(pixel_format);
|
||||
src_offset += block_size;
|
||||
dst_offset += block_width * out_bpp;
|
||||
}
|
||||
input_offset += copy.buffer_row_length * block_size / block_width;
|
||||
output_offset += block_height * pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
|
||||
void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
|
||||
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);
|
||||
DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, copy);
|
||||
break;
|
||||
case PixelFormat::BC2_UNORM:
|
||||
case PixelFormat::BC2_SRGB:
|
||||
DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent);
|
||||
DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, copy);
|
||||
break;
|
||||
case PixelFormat::BC3_UNORM:
|
||||
case PixelFormat::BC3_SRGB:
|
||||
DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent);
|
||||
DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, copy);
|
||||
break;
|
||||
case PixelFormat::BC4_SNORM:
|
||||
case PixelFormat::BC4_UNORM:
|
||||
DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
|
||||
input, output, extent, pixel_format == PixelFormat::BC4_SNORM);
|
||||
input, output, copy, 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);
|
||||
input, output, copy, 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);
|
||||
input, output, copy, pixel_format == PixelFormat::BC6H_SFLOAT);
|
||||
break;
|
||||
case PixelFormat::BC7_SRGB:
|
||||
case PixelFormat::BC7_UNORM:
|
||||
DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent);
|
||||
DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, copy);
|
||||
break;
|
||||
default:
|
||||
LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace VideoCommon {
|
||||
|
||||
[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
|
||||
|
||||
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
|
||||
void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
|
||||
VideoCore::Surface::PixelFormat pixel_format);
|
||||
|
||||
} // namespace VideoCommon
|
||||
|
||||
@@ -837,6 +837,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
|
||||
std::span<u8> output) {
|
||||
const size_t guest_size_bytes = input.size_bytes();
|
||||
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
|
||||
const Extent2D tile_size = DefaultBlockSize(info.format);
|
||||
const Extent3D size = info.size;
|
||||
|
||||
if (info.type == ImageType::Linear) {
|
||||
@@ -847,7 +848,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
|
||||
return {{
|
||||
.buffer_offset = 0,
|
||||
.buffer_size = guest_size_bytes,
|
||||
.buffer_row_length = info.pitch >> bpp_log2,
|
||||
.buffer_row_length = info.pitch * tile_size.width >> bpp_log2,
|
||||
.buffer_image_height = size.height,
|
||||
.image_subresource =
|
||||
{
|
||||
@@ -862,7 +863,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
|
||||
const LevelInfo level_info = MakeLevelInfo(info);
|
||||
const s32 num_layers = info.resources.layers;
|
||||
const s32 num_levels = info.resources.levels;
|
||||
const Extent2D tile_size = DefaultBlockSize(info.format);
|
||||
const std::array level_sizes = CalculateLevelSizes(level_info, num_levels);
|
||||
const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing);
|
||||
const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels);
|
||||
@@ -926,8 +926,6 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
|
||||
|
||||
const auto input_offset = input.subspan(copy.buffer_offset);
|
||||
copy.buffer_offset = output_offset;
|
||||
copy.buffer_row_length = mip_size.width;
|
||||
copy.buffer_image_height = mip_size.height;
|
||||
|
||||
const auto recompression_setting = Settings::values.astc_recompression.GetValue();
|
||||
const bool astc = IsPixelFormatASTC(info.format);
|
||||
@@ -972,16 +970,14 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
|
||||
bpp_div;
|
||||
output_offset += static_cast<u32>(copy.buffer_size);
|
||||
} else {
|
||||
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);
|
||||
DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format);
|
||||
output_offset += copy.image_extent.width * copy.image_extent.height *
|
||||
copy.image_subresource.num_layers *
|
||||
ConvertedBytesPerBlock(info.format);
|
||||
}
|
||||
|
||||
copy.buffer_row_length = mip_size.width;
|
||||
copy.buffer_image_height = mip_size.height;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -755,10 +755,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
|
||||
// The wanted format is not supported by hardware, search for alternatives
|
||||
const VkFormat* alternatives = GetFormatAlternatives(wanted_format);
|
||||
if (alternatives == nullptr) {
|
||||
ASSERT_MSG(false,
|
||||
"Format={} with usage={} and type={} has no defined alternatives and host "
|
||||
"hardware does not support it",
|
||||
wanted_format, wanted_usage, format_type);
|
||||
LOG_ERROR(Render_Vulkan,
|
||||
"Format={} with usage={} and type={} has no defined alternatives and host "
|
||||
"hardware does not support it",
|
||||
wanted_format, wanted_usage, format_type);
|
||||
return wanted_format;
|
||||
}
|
||||
|
||||
@@ -774,10 +774,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
|
||||
}
|
||||
|
||||
// No alternatives found, panic
|
||||
ASSERT_MSG(false,
|
||||
"Format={} with usage={} and type={} is not supported by the host hardware and "
|
||||
"doesn't support any of the alternatives",
|
||||
wanted_format, wanted_usage, format_type);
|
||||
LOG_ERROR(Render_Vulkan,
|
||||
"Format={} with usage={} and type={} is not supported by the host hardware and "
|
||||
"doesn't support any of the alternatives",
|
||||
wanted_format, wanted_usage, format_type);
|
||||
return wanted_format;
|
||||
}
|
||||
|
||||
|
||||
@@ -246,7 +246,9 @@ void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjec
|
||||
.objectHandle = reinterpret_cast<u64>(handle),
|
||||
.pObjectName = name,
|
||||
};
|
||||
Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info));
|
||||
if (dld->vkSetDebugUtilsObjectNameEXT) {
|
||||
Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info));
|
||||
}
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
@@ -5342,6 +5342,10 @@ int main(int argc, char* argv[]) {
|
||||
if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) {
|
||||
qputenv("DISPLAY", ":0");
|
||||
}
|
||||
|
||||
// Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop
|
||||
// suffix.
|
||||
QGuiApplication::setDesktopFileName(QStringLiteral("org.yuzu_emu.yuzu"));
|
||||
#endif
|
||||
|
||||
SetHighDPIAttributes();
|
||||
|
||||
@@ -168,14 +168,6 @@ class GMainWindow : public QMainWindow {
|
||||
/// Max number of recently loaded items to keep track of
|
||||
static const int max_recent_files_item = 10;
|
||||
|
||||
// TODO: Make use of this!
|
||||
enum {
|
||||
UI_IDLE,
|
||||
UI_EMU_BOOTING,
|
||||
UI_EMU_RUNNING,
|
||||
UI_EMU_STOPPING,
|
||||
};
|
||||
|
||||
enum {
|
||||
CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES,
|
||||
CREATE_SHORTCUT_MSGBOX_SUCCESS,
|
||||
|
||||
@@ -20,7 +20,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Co
|
||||
: input_subsystem{input_subsystem_}, system{system_} {
|
||||
input_subsystem->Initialize();
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
|
||||
LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting...");
|
||||
LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}, Exiting...", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
SDL_SetMainReady();
|
||||
|
||||
@@ -28,7 +28,8 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
|
||||
SDL_SysWMinfo wm;
|
||||
SDL_VERSION(&wm.version);
|
||||
if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) {
|
||||
LOG_CRITICAL(Frontend, "Failed to get information from the window manager");
|
||||
LOG_CRITICAL(Frontend, "Failed to get information from the window manager: {}",
|
||||
SDL_GetError());
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user