Compare commits
21 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8758378dc4 | ||
|
|
102630f2b2 | ||
|
|
d88baa746b | ||
|
|
acc14d233f | ||
|
|
b00f4abe36 | ||
|
|
c47c3d723f | ||
|
|
3794c91145 | ||
|
|
b7cd5d742e | ||
|
|
56ecafc204 | ||
|
|
715f0c3b0c | ||
|
|
bba7e8ea4b | ||
|
|
e883101999 | ||
|
|
1889b641d9 | ||
|
|
3f2e605dd1 | ||
|
|
6971d08893 | ||
|
|
6e37676482 | ||
|
|
5b6545b141 | ||
|
|
412044960a | ||
|
|
be4fc777c0 | ||
|
|
622830f4e1 | ||
|
|
9ea8cffe35 |
@@ -102,6 +102,7 @@ add_library(common STATIC
|
||||
atomic_ops.h
|
||||
detached_tasks.cpp
|
||||
detached_tasks.h
|
||||
bit_cast.h
|
||||
bit_field.h
|
||||
bit_util.h
|
||||
cityhash.cpp
|
||||
|
||||
22
src/common/bit_cast.h
Normal file
22
src/common/bit_cast.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <typename To, typename From>
|
||||
[[nodiscard]] std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> &&
|
||||
std::is_trivially_copyable_v<To>,
|
||||
To>
|
||||
BitCast(const From& src) noexcept {
|
||||
To dst;
|
||||
std::memcpy(&dst, &src, sizeof(To));
|
||||
return dst;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
@@ -222,6 +222,7 @@ void DebuggerBackend::Write(const Entry& entry) {
|
||||
SUB(Service, NPNS) \
|
||||
SUB(Service, NS) \
|
||||
SUB(Service, NVDRV) \
|
||||
SUB(Service, OLSC) \
|
||||
SUB(Service, PCIE) \
|
||||
SUB(Service, PCTL) \
|
||||
SUB(Service, PCV) \
|
||||
|
||||
@@ -95,6 +95,7 @@ enum class Class : ClassType {
|
||||
Service_NPNS, ///< The NPNS service
|
||||
Service_NS, ///< The NS services
|
||||
Service_NVDRV, ///< The NVDRV (Nvidia driver) service
|
||||
Service_OLSC, ///< The OLSC service
|
||||
Service_PCIE, ///< The PCIe service
|
||||
Service_PCTL, ///< The PCTL (Parental control) service
|
||||
Service_PCV, ///< The PCV service
|
||||
|
||||
@@ -43,9 +43,14 @@ public:
|
||||
}
|
||||
|
||||
void resize(std::size_t count) {
|
||||
const auto new_size = count * sizeof(T);
|
||||
if (new_size == alloc_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreeMemoryPages(base_ptr, alloc_size);
|
||||
|
||||
alloc_size = count * sizeof(T);
|
||||
alloc_size = new_size;
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
|
||||
@@ -458,6 +458,8 @@ add_library(core STATIC
|
||||
hle/service/nvflinger/buffer_queue.h
|
||||
hle/service/nvflinger/nvflinger.cpp
|
||||
hle/service/nvflinger/nvflinger.h
|
||||
hle/service/olsc/olsc.cpp
|
||||
hle/service/olsc/olsc.h
|
||||
hle/service/pcie/pcie.cpp
|
||||
hle/service/pcie/pcie.h
|
||||
hle/service/pctl/module.cpp
|
||||
|
||||
69
src/core/hle/service/olsc/olsc.cpp
Normal file
69
src/core/hle/service/olsc/olsc.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/service/olsc/olsc.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::OLSC {
|
||||
|
||||
class OLSC final : public ServiceFramework<OLSC> {
|
||||
public:
|
||||
explicit OLSC() : ServiceFramework{"olsc:u"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &OLSC::Initialize, "Initialize"},
|
||||
{10, nullptr, "VerifySaveDataBackupLicenseAsync"},
|
||||
{13, nullptr, "GetSaveDataBackupSetting"},
|
||||
{14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
|
||||
{15, nullptr, "SetCustomData"},
|
||||
{16, nullptr, "DeleteSaveDataBackupSetting"},
|
||||
{18, nullptr, "GetSaveDataBackupInfoCache"},
|
||||
{19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
|
||||
{22, nullptr, "DeleteSaveDataBackupAsync"},
|
||||
{25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
|
||||
{26, nullptr, "DownloadSaveDataBackupAsync"},
|
||||
{9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
|
||||
{9013, nullptr, "GetSaveDataBackupSettingForDebug"},
|
||||
{9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
|
||||
{9015, nullptr, "SetCustomDataForDebug"},
|
||||
{9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
|
||||
{9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
|
||||
{9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
|
||||
{9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
|
||||
{9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
|
||||
{9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_OLSC, "(STUBBED) called");
|
||||
|
||||
initialized = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_OLSC, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
bool initialized{};
|
||||
};
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
std::make_shared<OLSC>()->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
} // namespace Service::OLSC
|
||||
16
src/core/hle/service/olsc/olsc.h
Normal file
16
src/core/hle/service/olsc/olsc.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Service::OLSC {
|
||||
|
||||
/// Registers all SSL services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||
|
||||
} // namespace Service::OLSC
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
#include "core/hle/service/nvflinger/nvflinger.h"
|
||||
#include "core/hle/service/olsc/olsc.h"
|
||||
#include "core/hle/service/pcie/pcie.h"
|
||||
#include "core/hle/service/pctl/module.h"
|
||||
#include "core/hle/service/pcv/pcv.h"
|
||||
@@ -231,6 +232,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
|
||||
NPNS::InstallInterfaces(*sm);
|
||||
NS::InstallInterfaces(*sm, system);
|
||||
Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
|
||||
OLSC::InstallInterfaces(*sm);
|
||||
PCIe::InstallInterfaces(*sm);
|
||||
PCTL::InstallInterfaces(*sm);
|
||||
PCV::InstallInterfaces(*sm);
|
||||
|
||||
@@ -302,8 +302,8 @@ public:
|
||||
|
||||
bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
|
||||
const auto mean_amplitude = (amp_low + amp_high) * 0.5f;
|
||||
const auto processed_amplitude = static_cast<u8>(
|
||||
pow(mean_amplitude, 0.5f) * (3.0f - 2.0f * pow(mean_amplitude, 0.15f)) * 0x8);
|
||||
const auto processed_amplitude =
|
||||
static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);
|
||||
|
||||
return gcadapter->RumblePlay(port, processed_amplitude);
|
||||
}
|
||||
|
||||
@@ -402,8 +402,7 @@ public:
|
||||
|
||||
bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
|
||||
const auto process_amplitude = [](f32 amplitude) {
|
||||
return static_cast<u16>(std::pow(amplitude, 0.5f) *
|
||||
(3.0f - 2.0f * std::pow(amplitude, 0.15f)) * 0xFFFF);
|
||||
return static_cast<u16>((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF);
|
||||
};
|
||||
|
||||
const auto processed_amp_low = process_amplitude(amp_low);
|
||||
|
||||
@@ -124,6 +124,112 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||
mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
|
||||
if (executing_macro == 0) {
|
||||
// A macro call must begin by writing the macro method's register, not its argument.
|
||||
ASSERT_MSG((method % 2) == 0,
|
||||
"Can't start macro execution by writing to the ARGS register");
|
||||
executing_macro = method;
|
||||
}
|
||||
|
||||
macro_params.insert(macro_params.end(), base_start, base_start + amount);
|
||||
|
||||
// Call the macro when there are no more parameters in the command buffer
|
||||
if (is_last_call) {
|
||||
CallMacroMethod(executing_macro, macro_params);
|
||||
macro_params.clear();
|
||||
}
|
||||
}
|
||||
|
||||
u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
|
||||
// Keep track of the register value in shadow_state when requested.
|
||||
const auto control = shadow_state.shadow_ram_control;
|
||||
if (control == Regs::ShadowRamControl::Track ||
|
||||
control == Regs::ShadowRamControl::TrackWithFilter) {
|
||||
shadow_state.reg_array[method] = argument;
|
||||
return argument;
|
||||
}
|
||||
if (control == Regs::ShadowRamControl::Replay) {
|
||||
return shadow_state.reg_array[method];
|
||||
}
|
||||
return argument;
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument) {
|
||||
if (regs.reg_array[method] == argument) {
|
||||
return;
|
||||
}
|
||||
regs.reg_array[method] = argument;
|
||||
|
||||
for (const auto& table : dirty.tables) {
|
||||
dirty.flags[table[method]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argument,
|
||||
bool is_last_call) {
|
||||
switch (method) {
|
||||
case MAXWELL3D_REG_INDEX(wait_for_idle):
|
||||
return rasterizer->WaitForIdle();
|
||||
case MAXWELL3D_REG_INDEX(shadow_ram_control):
|
||||
shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(nonshadow_argument);
|
||||
return;
|
||||
case MAXWELL3D_REG_INDEX(macros.data):
|
||||
return macro_engine->AddCode(regs.macros.upload_address, argument);
|
||||
case MAXWELL3D_REG_INDEX(macros.bind):
|
||||
return ProcessMacroBind(argument);
|
||||
case MAXWELL3D_REG_INDEX(firmware[4]):
|
||||
return ProcessFirmwareCall4();
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]):
|
||||
return StartCBData(method);
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[0]):
|
||||
return ProcessCBBind(0);
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[1]):
|
||||
return ProcessCBBind(1);
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[2]):
|
||||
return ProcessCBBind(2);
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[3]):
|
||||
return ProcessCBBind(3);
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[4]):
|
||||
return ProcessCBBind(4);
|
||||
case MAXWELL3D_REG_INDEX(draw.vertex_end_gl):
|
||||
return DrawArrays();
|
||||
case MAXWELL3D_REG_INDEX(clear_buffers):
|
||||
return ProcessClearBuffers();
|
||||
case MAXWELL3D_REG_INDEX(query.query_get):
|
||||
return ProcessQueryGet();
|
||||
case MAXWELL3D_REG_INDEX(condition.mode):
|
||||
return ProcessQueryCondition();
|
||||
case MAXWELL3D_REG_INDEX(counter_reset):
|
||||
return ProcessCounterReset();
|
||||
case MAXWELL3D_REG_INDEX(sync_info):
|
||||
return ProcessSyncPoint();
|
||||
case MAXWELL3D_REG_INDEX(exec_upload):
|
||||
return upload_state.ProcessExec(regs.exec_upload.linear != 0);
|
||||
case MAXWELL3D_REG_INDEX(data_upload):
|
||||
upload_state.ProcessData(argument, is_last_call);
|
||||
if (is_last_call) {
|
||||
OnMemoryWrite();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) {
|
||||
// Reset the current macro.
|
||||
executing_macro = 0;
|
||||
@@ -157,142 +263,16 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
||||
// Methods after 0xE00 are special, they're actually triggers for some microcode that was
|
||||
// uploaded to the GPU during initialization.
|
||||
if (method >= MacroRegistersStart) {
|
||||
// We're trying to execute a macro
|
||||
if (executing_macro == 0) {
|
||||
// A macro call must begin by writing the macro method's register, not its argument.
|
||||
ASSERT_MSG((method % 2) == 0,
|
||||
"Can't start macro execution by writing to the ARGS register");
|
||||
executing_macro = method;
|
||||
}
|
||||
|
||||
macro_params.push_back(method_argument);
|
||||
|
||||
// Call the macro when there are no more parameters in the command buffer
|
||||
if (is_last_call) {
|
||||
CallMacroMethod(executing_macro, macro_params);
|
||||
macro_params.clear();
|
||||
}
|
||||
ProcessMacro(method, &method_argument, 1, is_last_call);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_MSG(method < Regs::NUM_REGS,
|
||||
"Invalid Maxwell3D register, increase the size of the Regs structure");
|
||||
|
||||
u32 arg = method_argument;
|
||||
// Keep track of the register value in shadow_state when requested.
|
||||
if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Track ||
|
||||
shadow_state.shadow_ram_control == Regs::ShadowRamControl::TrackWithFilter) {
|
||||
shadow_state.reg_array[method] = arg;
|
||||
} else if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Replay) {
|
||||
arg = shadow_state.reg_array[method];
|
||||
}
|
||||
|
||||
if (regs.reg_array[method] != arg) {
|
||||
regs.reg_array[method] = arg;
|
||||
|
||||
for (const auto& table : dirty.tables) {
|
||||
dirty.flags[table[method]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case MAXWELL3D_REG_INDEX(wait_for_idle): {
|
||||
rasterizer->WaitForIdle();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(shadow_ram_control): {
|
||||
shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(method_argument);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(macros.data): {
|
||||
macro_engine->AddCode(regs.macros.upload_address, arg);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(macros.bind): {
|
||||
ProcessMacroBind(arg);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(firmware[4]): {
|
||||
ProcessFirmwareCall4();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): {
|
||||
StartCBData(method);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[0]): {
|
||||
ProcessCBBind(0);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[1]): {
|
||||
ProcessCBBind(1);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[2]): {
|
||||
ProcessCBBind(2);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[3]): {
|
||||
ProcessCBBind(3);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(cb_bind[4]): {
|
||||
ProcessCBBind(4);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(draw.vertex_end_gl): {
|
||||
DrawArrays();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(clear_buffers): {
|
||||
ProcessClearBuffers();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(query.query_get): {
|
||||
ProcessQueryGet();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(condition.mode): {
|
||||
ProcessQueryCondition();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(counter_reset): {
|
||||
ProcessCounterReset();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(sync_info): {
|
||||
ProcessSyncPoint();
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(exec_upload): {
|
||||
upload_state.ProcessExec(regs.exec_upload.linear != 0);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(data_upload): {
|
||||
upload_state.ProcessData(arg, is_last_call);
|
||||
if (is_last_call) {
|
||||
OnMemoryWrite();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const u32 argument = ProcessShadowRam(method, method_argument);
|
||||
ProcessDirtyRegisters(method, argument);
|
||||
ProcessMethodCall(method, argument, method_argument, is_last_call);
|
||||
}
|
||||
|
||||
void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||
@@ -300,23 +280,7 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||
// Methods after 0xE00 are special, they're actually triggers for some microcode that was
|
||||
// uploaded to the GPU during initialization.
|
||||
if (method >= MacroRegistersStart) {
|
||||
// We're trying to execute a macro
|
||||
if (executing_macro == 0) {
|
||||
// A macro call must begin by writing the macro method's register, not its argument.
|
||||
ASSERT_MSG((method % 2) == 0,
|
||||
"Can't start macro execution by writing to the ARGS register");
|
||||
executing_macro = method;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < amount; i++) {
|
||||
macro_params.push_back(base_start[i]);
|
||||
}
|
||||
|
||||
// Call the macro when there are no more parameters in the command buffer
|
||||
if (amount == methods_pending) {
|
||||
CallMacroMethod(executing_macro, macro_params);
|
||||
macro_params.clear();
|
||||
}
|
||||
ProcessMacro(method, base_start, amount, amount == methods_pending);
|
||||
return;
|
||||
}
|
||||
switch (method) {
|
||||
@@ -335,15 +299,14 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): {
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]):
|
||||
ProcessCBMultiData(method, base_start, amount);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
default:
|
||||
for (std::size_t i = 0; i < amount; i++) {
|
||||
CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1461,6 +1461,14 @@ public:
|
||||
private:
|
||||
void InitializeRegisterDefaults();
|
||||
|
||||
void ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call);
|
||||
|
||||
u32 ProcessShadowRam(u32 method, u32 argument);
|
||||
|
||||
void ProcessDirtyRegisters(u32 method, u32 argument);
|
||||
|
||||
void ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argument, bool is_last_call);
|
||||
|
||||
Core::System& system;
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
|
||||
@@ -32,31 +32,31 @@ struct Register {
|
||||
|
||||
constexpr Register() = default;
|
||||
|
||||
constexpr Register(u64 value) : value(value) {}
|
||||
constexpr Register(u64 value_) : value(value_) {}
|
||||
|
||||
constexpr operator u64() const {
|
||||
[[nodiscard]] constexpr operator u64() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr u64 operator-(const T& oth) const {
|
||||
[[nodiscard]] constexpr u64 operator-(const T& oth) const {
|
||||
return value - oth;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr u64 operator&(const T& oth) const {
|
||||
[[nodiscard]] constexpr u64 operator&(const T& oth) const {
|
||||
return value & oth;
|
||||
}
|
||||
|
||||
constexpr u64 operator&(const Register& oth) const {
|
||||
[[nodiscard]] constexpr u64 operator&(const Register& oth) const {
|
||||
return value & oth.value;
|
||||
}
|
||||
|
||||
constexpr u64 operator~() const {
|
||||
[[nodiscard]] constexpr u64 operator~() const {
|
||||
return ~value;
|
||||
}
|
||||
|
||||
u64 GetSwizzledIndex(u64 elem) const {
|
||||
[[nodiscard]] u64 GetSwizzledIndex(u64 elem) const {
|
||||
elem = (value + elem) & 3;
|
||||
return (value & ~3) + elem;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ enum class AttributeSize : u64 {
|
||||
union Attribute {
|
||||
Attribute() = default;
|
||||
|
||||
constexpr explicit Attribute(u64 value) : value(value) {}
|
||||
constexpr explicit Attribute(u64 value_) : value(value_) {}
|
||||
|
||||
enum class Index : u64 {
|
||||
LayerViewportPointSize = 6,
|
||||
@@ -107,7 +107,7 @@ union Attribute {
|
||||
BitField<31, 1, u64> patch;
|
||||
BitField<47, 3, AttributeSize> size;
|
||||
|
||||
bool IsPhysical() const {
|
||||
[[nodiscard]] bool IsPhysical() const {
|
||||
return patch == 0 && element == 0 && static_cast<u64>(index.Value()) == 0;
|
||||
}
|
||||
} fmt20;
|
||||
@@ -124,7 +124,7 @@ union Attribute {
|
||||
union Sampler {
|
||||
Sampler() = default;
|
||||
|
||||
constexpr explicit Sampler(u64 value) : value(value) {}
|
||||
constexpr explicit Sampler(u64 value_) : value(value_) {}
|
||||
|
||||
enum class Index : u64 {
|
||||
Sampler_0 = 8,
|
||||
@@ -137,7 +137,7 @@ union Sampler {
|
||||
union Image {
|
||||
Image() = default;
|
||||
|
||||
constexpr explicit Image(u64 value) : value{value} {}
|
||||
constexpr explicit Image(u64 value_) : value{value_} {}
|
||||
|
||||
BitField<36, 13, u64> index;
|
||||
u64 value;
|
||||
@@ -505,14 +505,14 @@ struct IpaMode {
|
||||
IpaInterpMode interpolation_mode;
|
||||
IpaSampleMode sampling_mode;
|
||||
|
||||
bool operator==(const IpaMode& a) const {
|
||||
[[nodiscard]] bool operator==(const IpaMode& a) const {
|
||||
return std::tie(interpolation_mode, sampling_mode) ==
|
||||
std::tie(a.interpolation_mode, a.sampling_mode);
|
||||
}
|
||||
bool operator!=(const IpaMode& a) const {
|
||||
[[nodiscard]] bool operator!=(const IpaMode& a) const {
|
||||
return !operator==(a);
|
||||
}
|
||||
bool operator<(const IpaMode& a) const {
|
||||
[[nodiscard]] bool operator<(const IpaMode& a) const {
|
||||
return std::tie(interpolation_mode, sampling_mode) <
|
||||
std::tie(a.interpolation_mode, a.sampling_mode);
|
||||
}
|
||||
@@ -658,10 +658,10 @@ union Instruction {
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Instruction(u64 value) : value{value} {}
|
||||
constexpr Instruction(u64 value_) : value{value_} {}
|
||||
constexpr Instruction(const Instruction& instr) : value(instr.value) {}
|
||||
|
||||
constexpr bool Bit(u64 offset) const {
|
||||
[[nodiscard]] constexpr bool Bit(u64 offset) const {
|
||||
return ((value >> offset) & 1) != 0;
|
||||
}
|
||||
|
||||
@@ -746,34 +746,34 @@ union Instruction {
|
||||
BitField<28, 8, u64> imm_lut28;
|
||||
BitField<48, 8, u64> imm_lut48;
|
||||
|
||||
u32 GetImmLut28() const {
|
||||
[[nodiscard]] u32 GetImmLut28() const {
|
||||
return static_cast<u32>(imm_lut28);
|
||||
}
|
||||
|
||||
u32 GetImmLut48() const {
|
||||
[[nodiscard]] u32 GetImmLut48() const {
|
||||
return static_cast<u32>(imm_lut48);
|
||||
}
|
||||
} lop3;
|
||||
|
||||
u16 GetImm20_16() const {
|
||||
[[nodiscard]] u16 GetImm20_16() const {
|
||||
return static_cast<u16>(imm20_16);
|
||||
}
|
||||
|
||||
u32 GetImm20_19() const {
|
||||
[[nodiscard]] u32 GetImm20_19() const {
|
||||
u32 imm{static_cast<u32>(imm20_19)};
|
||||
imm <<= 12;
|
||||
imm |= negate_imm ? 0x80000000 : 0;
|
||||
return imm;
|
||||
}
|
||||
|
||||
u32 GetImm20_32() const {
|
||||
[[nodiscard]] u32 GetImm20_32() const {
|
||||
return static_cast<u32>(imm20_32);
|
||||
}
|
||||
|
||||
s32 GetSignedImm20_20() const {
|
||||
u32 immediate = static_cast<u32>(imm20_19 | (negate_imm << 19));
|
||||
[[nodiscard]] s32 GetSignedImm20_20() const {
|
||||
const auto immediate = static_cast<u32>(imm20_19 | (negate_imm << 19));
|
||||
// Sign extend the 20-bit value.
|
||||
u32 mask = 1U << (20 - 1);
|
||||
const auto mask = 1U << (20 - 1);
|
||||
return static_cast<s32>((immediate ^ mask) - mask);
|
||||
}
|
||||
} alu;
|
||||
@@ -857,7 +857,7 @@ union Instruction {
|
||||
BitField<56, 1, u64> second_negate;
|
||||
BitField<30, 9, u64> second;
|
||||
|
||||
u32 PackImmediates() const {
|
||||
[[nodiscard]] u32 PackImmediates() const {
|
||||
// Immediates are half floats shifted.
|
||||
constexpr u32 imm_shift = 6;
|
||||
return static_cast<u32>((first << imm_shift) | (second << (16 + imm_shift)));
|
||||
@@ -1033,7 +1033,7 @@ union Instruction {
|
||||
BitField<28, 2, AtomicType> type;
|
||||
BitField<30, 22, s64> offset;
|
||||
|
||||
s32 GetImmediateOffset() const {
|
||||
[[nodiscard]] s32 GetImmediateOffset() const {
|
||||
return static_cast<s32>(offset << 2);
|
||||
}
|
||||
} atoms;
|
||||
@@ -1215,7 +1215,7 @@ union Instruction {
|
||||
BitField<39, 4, u64> rounding;
|
||||
// H0, H1 extract for F16 missing
|
||||
BitField<41, 1, u64> selector; // Guessed as some games set it, TODO: reverse this value
|
||||
F2fRoundingOp GetRoundingMode() const {
|
||||
[[nodiscard]] F2fRoundingOp GetRoundingMode() const {
|
||||
constexpr u64 rounding_mask = 0x0B;
|
||||
return static_cast<F2fRoundingOp>(rounding.Value() & rounding_mask);
|
||||
}
|
||||
@@ -1239,15 +1239,15 @@ union Instruction {
|
||||
BitField<54, 1, u64> aoffi_flag;
|
||||
BitField<55, 3, TextureProcessMode> process_mode;
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ull << component) & component_mask) != 0;
|
||||
[[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ULL << component) & component_mask) != 0;
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
[[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
|
||||
return process_mode;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
@@ -1271,15 +1271,15 @@ union Instruction {
|
||||
BitField<36, 1, u64> aoffi_flag;
|
||||
BitField<37, 3, TextureProcessMode> process_mode;
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
[[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ULL << component) & component_mask) != 0;
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
[[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
|
||||
return process_mode;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
@@ -1299,7 +1299,7 @@ union Instruction {
|
||||
BitField<31, 4, u64> component_mask;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NODEP:
|
||||
return nodep_flag != 0;
|
||||
@@ -1309,7 +1309,7 @@ union Instruction {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
[[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ULL << component) & component_mask) != 0;
|
||||
}
|
||||
} txq;
|
||||
@@ -1321,11 +1321,11 @@ union Instruction {
|
||||
BitField<35, 1, u64> ndv_flag;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ull << component) & component_mask) != 0;
|
||||
[[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
|
||||
return ((1ULL << component) & component_mask) != 0;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NDV:
|
||||
return (ndv_flag != 0);
|
||||
@@ -1347,7 +1347,7 @@ union Instruction {
|
||||
BitField<54, 2, u64> offset_mode;
|
||||
BitField<56, 2, u64> component;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NDV:
|
||||
return ndv_flag != 0;
|
||||
@@ -1373,7 +1373,7 @@ union Instruction {
|
||||
BitField<33, 2, u64> offset_mode;
|
||||
BitField<37, 2, u64> component;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::NDV:
|
||||
return ndv_flag != 0;
|
||||
@@ -1399,7 +1399,7 @@ union Instruction {
|
||||
BitField<52, 2, u64> component;
|
||||
BitField<55, 1, u64> fp16_flag;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return dc_flag != 0;
|
||||
@@ -1422,16 +1422,20 @@ union Instruction {
|
||||
BitField<53, 4, u64> texture_info;
|
||||
BitField<59, 1, u64> fp32_flag;
|
||||
|
||||
TextureType GetTextureType() const {
|
||||
[[nodiscard]] TextureType GetTextureType() const {
|
||||
// The TEXS instruction has a weird encoding for the texture type.
|
||||
if (texture_info == 0)
|
||||
if (texture_info == 0) {
|
||||
return TextureType::Texture1D;
|
||||
if (texture_info >= 1 && texture_info <= 9)
|
||||
}
|
||||
if (texture_info >= 1 && texture_info <= 9) {
|
||||
return TextureType::Texture2D;
|
||||
if (texture_info >= 10 && texture_info <= 11)
|
||||
}
|
||||
if (texture_info >= 10 && texture_info <= 11) {
|
||||
return TextureType::Texture3D;
|
||||
if (texture_info >= 12 && texture_info <= 13)
|
||||
}
|
||||
if (texture_info >= 12 && texture_info <= 13) {
|
||||
return TextureType::TextureCube;
|
||||
}
|
||||
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled texture_info: {}",
|
||||
static_cast<u32>(texture_info.Value()));
|
||||
@@ -1439,7 +1443,7 @@ union Instruction {
|
||||
return TextureType::Texture1D;
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
[[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
|
||||
switch (texture_info) {
|
||||
case 0:
|
||||
case 2:
|
||||
@@ -1458,7 +1462,7 @@ union Instruction {
|
||||
return TextureProcessMode::None;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::DC:
|
||||
return (texture_info >= 4 && texture_info <= 6) || texture_info == 9;
|
||||
@@ -1470,16 +1474,16 @@ union Instruction {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsArrayTexture() const {
|
||||
[[nodiscard]] bool IsArrayTexture() const {
|
||||
// TEXS only supports Texture2D arrays.
|
||||
return texture_info >= 7 && texture_info <= 9;
|
||||
}
|
||||
|
||||
bool HasTwoDestinations() const {
|
||||
[[nodiscard]] bool HasTwoDestinations() const {
|
||||
return gpr28.Value() != Register::ZeroIndex;
|
||||
}
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
[[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
|
||||
static constexpr std::array<std::array<u32, 8>, 4> mask_lut{{
|
||||
{},
|
||||
{0x1, 0x2, 0x4, 0x8, 0x3, 0x9, 0xa, 0xc},
|
||||
@@ -1506,7 +1510,7 @@ union Instruction {
|
||||
BitField<54, 1, u64> cl;
|
||||
BitField<55, 1, u64> process_mode;
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
[[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
|
||||
return process_mode == 0 ? TextureProcessMode::LZ : TextureProcessMode::LL;
|
||||
}
|
||||
} tld;
|
||||
@@ -1516,7 +1520,7 @@ union Instruction {
|
||||
BitField<53, 4, u64> texture_info;
|
||||
BitField<59, 1, u64> fp32_flag;
|
||||
|
||||
TextureType GetTextureType() const {
|
||||
[[nodiscard]] TextureType GetTextureType() const {
|
||||
// The TLDS instruction has a weird encoding for the texture type.
|
||||
if (texture_info <= 1) {
|
||||
return TextureType::Texture1D;
|
||||
@@ -1535,13 +1539,14 @@ union Instruction {
|
||||
return TextureType::Texture1D;
|
||||
}
|
||||
|
||||
TextureProcessMode GetTextureProcessMode() const {
|
||||
if (texture_info == 1 || texture_info == 5 || texture_info == 12)
|
||||
[[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
|
||||
if (texture_info == 1 || texture_info == 5 || texture_info == 12) {
|
||||
return TextureProcessMode::LL;
|
||||
}
|
||||
return TextureProcessMode::LZ;
|
||||
}
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::AOFFI:
|
||||
return texture_info == 12 || texture_info == 4;
|
||||
@@ -1555,7 +1560,7 @@ union Instruction {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsArrayTexture() const {
|
||||
[[nodiscard]] bool IsArrayTexture() const {
|
||||
// TEXS only supports Texture2D arrays.
|
||||
return texture_info == 8;
|
||||
}
|
||||
@@ -1567,7 +1572,7 @@ union Instruction {
|
||||
BitField<35, 1, u64> aoffi_flag;
|
||||
BitField<49, 1, u64> nodep_flag;
|
||||
|
||||
bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
[[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
|
||||
switch (mode) {
|
||||
case TextureMiscMode::AOFFI:
|
||||
return aoffi_flag != 0;
|
||||
@@ -1591,7 +1596,7 @@ union Instruction {
|
||||
BitField<20, 3, StoreType> store_data_layout;
|
||||
BitField<20, 4, u64> component_mask_selector;
|
||||
|
||||
bool IsComponentEnabled(std::size_t component) const {
|
||||
[[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
|
||||
ASSERT(mode == SurfaceDataMode::P);
|
||||
constexpr u8 R = 0b0001;
|
||||
constexpr u8 G = 0b0010;
|
||||
@@ -1604,7 +1609,7 @@ union Instruction {
|
||||
return std::bitset<4>{mask.at(component_mask_selector)}.test(component);
|
||||
}
|
||||
|
||||
StoreType GetStoreDataLayout() const {
|
||||
[[nodiscard]] StoreType GetStoreDataLayout() const {
|
||||
ASSERT(mode == SurfaceDataMode::D_BA);
|
||||
return store_data_layout;
|
||||
}
|
||||
@@ -1622,14 +1627,15 @@ union Instruction {
|
||||
BitField<20, 24, u64> target;
|
||||
BitField<5, 1, u64> constant_buffer;
|
||||
|
||||
s32 GetBranchTarget() const {
|
||||
[[nodiscard]] s32 GetBranchTarget() const {
|
||||
// Sign extend the branch target offset
|
||||
u32 mask = 1U << (24 - 1);
|
||||
u32 value = static_cast<u32>(target);
|
||||
const auto mask = 1U << (24 - 1);
|
||||
const auto target_value = static_cast<u32>(target);
|
||||
constexpr auto instruction_size = static_cast<s32>(sizeof(Instruction));
|
||||
|
||||
// The branch offset is relative to the next instruction and is stored in bytes, so
|
||||
// divide it by the size of an instruction and add 1 to it.
|
||||
return static_cast<s32>((value ^ mask) - mask) / static_cast<s32>(sizeof(Instruction)) +
|
||||
1;
|
||||
return static_cast<s32>((target_value ^ mask) - mask) / instruction_size + 1;
|
||||
}
|
||||
} bra;
|
||||
|
||||
@@ -1637,14 +1643,15 @@ union Instruction {
|
||||
BitField<20, 24, u64> target;
|
||||
BitField<5, 1, u64> constant_buffer;
|
||||
|
||||
s32 GetBranchExtend() const {
|
||||
[[nodiscard]] s32 GetBranchExtend() const {
|
||||
// Sign extend the branch target offset
|
||||
u32 mask = 1U << (24 - 1);
|
||||
u32 value = static_cast<u32>(target);
|
||||
const auto mask = 1U << (24 - 1);
|
||||
const auto target_value = static_cast<u32>(target);
|
||||
constexpr auto instruction_size = static_cast<s32>(sizeof(Instruction));
|
||||
|
||||
// The branch offset is relative to the next instruction and is stored in bytes, so
|
||||
// divide it by the size of an instruction and add 1 to it.
|
||||
return static_cast<s32>((value ^ mask) - mask) / static_cast<s32>(sizeof(Instruction)) +
|
||||
1;
|
||||
return static_cast<s32>((target_value ^ mask) - mask) / instruction_size + 1;
|
||||
}
|
||||
} brx;
|
||||
|
||||
@@ -1697,7 +1704,7 @@ union Instruction {
|
||||
BitField<50, 1, u64> is_op_b_register;
|
||||
BitField<51, 3, VmnmxOperation> operation;
|
||||
|
||||
VmnmxType SourceFormatA() const {
|
||||
[[nodiscard]] VmnmxType SourceFormatA() const {
|
||||
switch (src_format_a) {
|
||||
case 0b11:
|
||||
return VmnmxType::Bits32;
|
||||
@@ -1708,7 +1715,7 @@ union Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
VmnmxType SourceFormatB() const {
|
||||
[[nodiscard]] VmnmxType SourceFormatB() const {
|
||||
switch (src_format_b) {
|
||||
case 0b11:
|
||||
return VmnmxType::Bits32;
|
||||
@@ -1739,7 +1746,7 @@ union Instruction {
|
||||
BitField<20, 14, u64> shifted_offset;
|
||||
BitField<34, 5, u64> index;
|
||||
|
||||
u64 GetOffset() const {
|
||||
[[nodiscard]] u64 GetOffset() const {
|
||||
return shifted_offset * 4;
|
||||
}
|
||||
} cbuf34;
|
||||
@@ -1748,7 +1755,7 @@ union Instruction {
|
||||
BitField<20, 16, s64> offset;
|
||||
BitField<36, 5, u64> index;
|
||||
|
||||
s64 GetOffset() const {
|
||||
[[nodiscard]] s64 GetOffset() const {
|
||||
return offset;
|
||||
}
|
||||
} cbuf36;
|
||||
@@ -1997,29 +2004,29 @@ public:
|
||||
|
||||
/// Returns whether an opcode has an execution predicate field or not (ie, whether it can be
|
||||
/// conditionally executed).
|
||||
static bool IsPredicatedInstruction(Id opcode) {
|
||||
[[nodiscard]] static bool IsPredicatedInstruction(Id opcode) {
|
||||
// TODO(Subv): Add the rest of unpredicated instructions.
|
||||
return opcode != Id::SSY && opcode != Id::PBK;
|
||||
}
|
||||
|
||||
class Matcher {
|
||||
public:
|
||||
constexpr Matcher(const char* const name, u16 mask, u16 expected, Id id, Type type)
|
||||
: name{name}, mask{mask}, expected{expected}, id{id}, type{type} {}
|
||||
constexpr Matcher(const char* const name_, u16 mask_, u16 expected_, Id id_, Type type_)
|
||||
: name{name_}, mask{mask_}, expected{expected_}, id{id_}, type{type_} {}
|
||||
|
||||
constexpr const char* GetName() const {
|
||||
[[nodiscard]] constexpr const char* GetName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
constexpr u16 GetMask() const {
|
||||
[[nodiscard]] constexpr u16 GetMask() const {
|
||||
return mask;
|
||||
}
|
||||
|
||||
constexpr Id GetId() const {
|
||||
[[nodiscard]] constexpr Id GetId() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
constexpr Type GetType() const {
|
||||
[[nodiscard]] constexpr Type GetType() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -2028,7 +2035,7 @@ public:
|
||||
* @param instruction The instruction to test
|
||||
* @returns true if the given instruction matches.
|
||||
*/
|
||||
constexpr bool Matches(u16 instruction) const {
|
||||
[[nodiscard]] constexpr bool Matches(u16 instruction) const {
|
||||
return (instruction & mask) == expected;
|
||||
}
|
||||
|
||||
@@ -2040,7 +2047,8 @@ public:
|
||||
Type type;
|
||||
};
|
||||
|
||||
static std::optional<std::reference_wrapper<const Matcher>> Decode(Instruction instr) {
|
||||
using DecodeResult = std::optional<std::reference_wrapper<const Matcher>>;
|
||||
[[nodiscard]] static DecodeResult Decode(Instruction instr) {
|
||||
static const auto table{GetDecodeTable()};
|
||||
|
||||
const auto matches_instruction = [instr](const auto& matcher) {
|
||||
@@ -2062,7 +2070,7 @@ private:
|
||||
* A '0' in a bitstring indicates that a zero must be present at that bit position.
|
||||
* A '1' in a bitstring indicates that a one must be present at that bit position.
|
||||
*/
|
||||
static constexpr auto GetMaskAndExpect(const char* const bitstring) {
|
||||
[[nodiscard]] static constexpr auto GetMaskAndExpect(const char* const bitstring) {
|
||||
u16 mask = 0, expect = 0;
|
||||
for (std::size_t i = 0; i < opcode_bitsize; i++) {
|
||||
const std::size_t bit_position = opcode_bitsize - i - 1;
|
||||
@@ -2084,14 +2092,14 @@ private:
|
||||
|
||||
public:
|
||||
/// Creates a matcher that can match and parse instructions based on bitstring.
|
||||
static constexpr auto GetMatcher(const char* const bitstring, Id op, Type type,
|
||||
const char* const name) {
|
||||
[[nodiscard]] static constexpr auto GetMatcher(const char* const bitstring, Id op,
|
||||
Type type, const char* const name) {
|
||||
const auto [mask, expected] = GetMaskAndExpect(bitstring);
|
||||
return Matcher(name, mask, expected, op, type);
|
||||
}
|
||||
};
|
||||
|
||||
static std::vector<Matcher> GetDecodeTable() {
|
||||
[[nodiscard]] static std::vector<Matcher> GetDecodeTable() {
|
||||
std::vector<Matcher> table = {
|
||||
#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
|
||||
INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
|
||||
|
||||
@@ -1579,10 +1579,6 @@ void RasterizerOpenGL::SyncAlphaTest() {
|
||||
flags[Dirty::AlphaTest] = false;
|
||||
|
||||
const auto& regs = maxwell3d.regs;
|
||||
if (regs.alpha_test_enabled && regs.rt_control.count > 1) {
|
||||
LOG_WARNING(Render_OpenGL, "Alpha testing with more than one render target is not tested");
|
||||
}
|
||||
|
||||
if (regs.alpha_test_enabled) {
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(MaxwellToGL::ComparisonOp(regs.alpha_test_func), regs.alpha_test_ref);
|
||||
|
||||
@@ -43,8 +43,8 @@ void AsyncShaders::AllocateWorkers() {
|
||||
// Create workers
|
||||
for (std::size_t i = 0; i < num_workers; i++) {
|
||||
context_list.push_back(emu_window.CreateSharedContext());
|
||||
worker_threads.emplace_back(&AsyncShaders::ShaderCompilerThread, this,
|
||||
context_list[i].get());
|
||||
worker_threads.push_back(
|
||||
std::thread(&AsyncShaders::ShaderCompilerThread, this, context_list[i].get()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,8 @@ std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() {
|
||||
std::vector<Result> results;
|
||||
{
|
||||
std::unique_lock lock{completed_mutex};
|
||||
results = std::move(finished_work);
|
||||
results.assign(std::make_move_iterator(finished_work.begin()),
|
||||
std::make_move_iterator(finished_work.end()));
|
||||
finished_work.clear();
|
||||
}
|
||||
return results;
|
||||
@@ -115,10 +116,11 @@ std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() {
|
||||
void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device,
|
||||
Tegra::Engines::ShaderType shader_type, u64 uid,
|
||||
std::vector<u64> code, std::vector<u64> code_b,
|
||||
u32 main_offset, CompilerSettings compiler_settings,
|
||||
const Registry& registry, VAddr cpu_addr) {
|
||||
std::unique_lock lock(queue_mutex);
|
||||
pending_queue.push({
|
||||
u32 main_offset,
|
||||
VideoCommon::Shader::CompilerSettings compiler_settings,
|
||||
const VideoCommon::Shader::Registry& registry,
|
||||
VAddr cpu_addr) {
|
||||
WorkerParams params{
|
||||
.backend = device.UseAssemblyShaders() ? Backend::GLASM : Backend::OpenGL,
|
||||
.device = &device,
|
||||
.shader_type = shader_type,
|
||||
@@ -129,7 +131,9 @@ void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device,
|
||||
.compiler_settings = compiler_settings,
|
||||
.registry = registry,
|
||||
.cpu_address = cpu_addr,
|
||||
});
|
||||
};
|
||||
std::unique_lock lock(queue_mutex);
|
||||
pending_queue.push(std::move(params));
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
@@ -141,8 +145,7 @@ void AsyncShaders::QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache,
|
||||
std::vector<VkDescriptorSetLayoutBinding> bindings,
|
||||
Vulkan::SPIRVProgram program,
|
||||
Vulkan::GraphicsPipelineCacheKey key) {
|
||||
std::unique_lock lock(queue_mutex);
|
||||
pending_queue.push({
|
||||
WorkerParams params{
|
||||
.backend = Backend::Vulkan,
|
||||
.pp_cache = pp_cache,
|
||||
.vk_device = &device,
|
||||
@@ -150,10 +153,13 @@ void AsyncShaders::QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache,
|
||||
.descriptor_pool = &descriptor_pool,
|
||||
.update_descriptor_queue = &update_descriptor_queue,
|
||||
.renderpass_cache = &renderpass_cache,
|
||||
.bindings = std::move(bindings),
|
||||
.program = std::move(program),
|
||||
.bindings = bindings,
|
||||
.program = program,
|
||||
.key = key,
|
||||
});
|
||||
};
|
||||
|
||||
std::unique_lock lock(queue_mutex);
|
||||
pending_queue.push(std::move(params));
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
|
||||
@@ -72,40 +72,6 @@ bool IsControllerCompatible(Settings::ControllerType controller_type,
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps the controller type combobox index to Controller Type enum
|
||||
constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
default:
|
||||
return Settings::ControllerType::ProController;
|
||||
case 1:
|
||||
return Settings::ControllerType::DualJoyconDetached;
|
||||
case 2:
|
||||
return Settings::ControllerType::LeftJoycon;
|
||||
case 3:
|
||||
return Settings::ControllerType::RightJoycon;
|
||||
case 4:
|
||||
return Settings::ControllerType::Handheld;
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps the Controller Type enum to controller type combobox index
|
||||
constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
|
||||
switch (type) {
|
||||
case Settings::ControllerType::ProController:
|
||||
default:
|
||||
return 0;
|
||||
case Settings::ControllerType::DualJoyconDetached:
|
||||
return 1;
|
||||
case Settings::ControllerType::LeftJoycon:
|
||||
return 2;
|
||||
case Settings::ControllerType::RightJoycon:
|
||||
return 3;
|
||||
case Settings::ControllerType::Handheld:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QtControllerSelectorDialog::QtControllerSelectorDialog(
|
||||
@@ -184,6 +150,11 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
|
||||
// This avoids unintentionally changing the states of elements while loading them in.
|
||||
SetSupportedControllers();
|
||||
DisableUnsupportedPlayers();
|
||||
|
||||
for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) {
|
||||
SetEmulatedControllers(player_index);
|
||||
}
|
||||
|
||||
LoadConfiguration();
|
||||
|
||||
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
|
||||
@@ -223,8 +194,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
|
||||
|
||||
if (i == 0) {
|
||||
connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
[this](int index) {
|
||||
UpdateDockedState(GetControllerTypeFromIndex(index) ==
|
||||
[this, i](int index) {
|
||||
UpdateDockedState(GetControllerTypeFromIndex(index, i) ==
|
||||
Settings::ControllerType::Handheld);
|
||||
});
|
||||
}
|
||||
@@ -281,8 +252,8 @@ void QtControllerSelectorDialog::LoadConfiguration() {
|
||||
(index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
|
||||
player_groupboxes[index]->setChecked(connected);
|
||||
connected_controller_checkboxes[index]->setChecked(connected);
|
||||
emulated_controllers[index]->setCurrentIndex(
|
||||
GetIndexFromControllerType(Settings::values.players.GetValue()[index].controller_type));
|
||||
emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType(
|
||||
Settings::values.players.GetValue()[index].controller_type, index));
|
||||
}
|
||||
|
||||
UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
|
||||
@@ -338,7 +309,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() {
|
||||
}
|
||||
|
||||
const auto compatible = IsControllerCompatible(
|
||||
GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex()),
|
||||
GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex(), index),
|
||||
parameters);
|
||||
|
||||
// If any controller is found to be incompatible, return false early.
|
||||
@@ -422,6 +393,63 @@ void QtControllerSelectorDialog::SetSupportedControllers() {
|
||||
}
|
||||
}
|
||||
|
||||
void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) {
|
||||
auto& pairs = index_controller_type_pairs[player_index];
|
||||
|
||||
pairs.clear();
|
||||
emulated_controllers[player_index]->clear();
|
||||
|
||||
pairs.emplace_back(emulated_controllers[player_index]->count(),
|
||||
Settings::ControllerType::ProController);
|
||||
emulated_controllers[player_index]->addItem(tr("Pro Controller"));
|
||||
|
||||
pairs.emplace_back(emulated_controllers[player_index]->count(),
|
||||
Settings::ControllerType::DualJoyconDetached);
|
||||
emulated_controllers[player_index]->addItem(tr("Dual Joycons"));
|
||||
|
||||
pairs.emplace_back(emulated_controllers[player_index]->count(),
|
||||
Settings::ControllerType::LeftJoycon);
|
||||
emulated_controllers[player_index]->addItem(tr("Left Joycon"));
|
||||
|
||||
pairs.emplace_back(emulated_controllers[player_index]->count(),
|
||||
Settings::ControllerType::RightJoycon);
|
||||
emulated_controllers[player_index]->addItem(tr("Right Joycon"));
|
||||
|
||||
if (player_index == 0) {
|
||||
pairs.emplace_back(emulated_controllers[player_index]->count(),
|
||||
Settings::ControllerType::Handheld);
|
||||
emulated_controllers[player_index]->addItem(tr("Handheld"));
|
||||
}
|
||||
}
|
||||
|
||||
Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
|
||||
int index, std::size_t player_index) const {
|
||||
const auto& pairs = index_controller_type_pairs[player_index];
|
||||
|
||||
const auto it = std::find_if(pairs.begin(), pairs.end(),
|
||||
[index](const auto& pair) { return pair.first == index; });
|
||||
|
||||
if (it == pairs.end()) {
|
||||
return Settings::ControllerType::ProController;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type,
|
||||
std::size_t player_index) const {
|
||||
const auto& pairs = index_controller_type_pairs[player_index];
|
||||
|
||||
const auto it = std::find_if(pairs.begin(), pairs.end(),
|
||||
[type](const auto& pair) { return pair.second == type; });
|
||||
|
||||
if (it == pairs.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return it->first;
|
||||
}
|
||||
|
||||
void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) {
|
||||
if (!player_groupboxes[player_index]->isChecked()) {
|
||||
connected_controller_icons[player_index]->setStyleSheet(QString{});
|
||||
@@ -430,7 +458,8 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
|
||||
}
|
||||
|
||||
const QString stylesheet = [this, player_index] {
|
||||
switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex())) {
|
||||
switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
|
||||
player_index)) {
|
||||
case Settings::ControllerType::ProController:
|
||||
return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
|
||||
case Settings::ControllerType::DualJoyconDetached:
|
||||
@@ -446,6 +475,12 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
|
||||
}
|
||||
}();
|
||||
|
||||
if (stylesheet.isEmpty()) {
|
||||
connected_controller_icons[player_index]->setStyleSheet(QString{});
|
||||
player_labels[player_index]->show();
|
||||
return;
|
||||
}
|
||||
|
||||
const QString theme = [] {
|
||||
if (QIcon::themeName().contains(QStringLiteral("dark"))) {
|
||||
return QStringLiteral("_dark");
|
||||
@@ -463,8 +498,8 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
|
||||
void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
|
||||
auto& player = Settings::values.players.GetValue()[player_index];
|
||||
|
||||
const auto controller_type =
|
||||
GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex());
|
||||
const auto controller_type = GetControllerTypeFromIndex(
|
||||
emulated_controllers[player_index]->currentIndex(), player_index);
|
||||
const auto player_connected = player_groupboxes[player_index]->isChecked() &&
|
||||
controller_type != Settings::ControllerType::Handheld;
|
||||
|
||||
@@ -507,8 +542,8 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index)
|
||||
|
||||
void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
|
||||
if (!player_groupboxes[player_index]->isChecked() ||
|
||||
GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()) ==
|
||||
Settings::ControllerType::Handheld) {
|
||||
GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
|
||||
player_index) == Settings::ControllerType::Handheld) {
|
||||
led_patterns_boxes[player_index][0]->setChecked(false);
|
||||
led_patterns_boxes[player_index][1]->setChecked(false);
|
||||
led_patterns_boxes[player_index][2]->setChecked(false);
|
||||
|
||||
@@ -22,6 +22,10 @@ namespace InputCommon {
|
||||
class InputSubsystem;
|
||||
}
|
||||
|
||||
namespace Settings {
|
||||
enum class ControllerType;
|
||||
}
|
||||
|
||||
namespace Ui {
|
||||
class QtControllerSelectorDialog;
|
||||
}
|
||||
@@ -57,6 +61,15 @@ private:
|
||||
// Sets the controller icons for "Supported Controller Types".
|
||||
void SetSupportedControllers();
|
||||
|
||||
// Sets the emulated controllers per player.
|
||||
void SetEmulatedControllers(std::size_t player_index);
|
||||
|
||||
// Gets the Controller Type for a given controller combobox index per player.
|
||||
Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const;
|
||||
|
||||
// Gets the controller combobox index for a given Controller Type per player.
|
||||
int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const;
|
||||
|
||||
// Updates the controller icons per player.
|
||||
void UpdateControllerIcon(std::size_t player_index);
|
||||
|
||||
@@ -114,6 +127,10 @@ private:
|
||||
// Comboboxes with a list of emulated controllers per player.
|
||||
std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
|
||||
|
||||
/// Pairs of emulated controller index and Controller Type enum per player.
|
||||
std::array<std::vector<std::pair<int, Settings::ControllerType>>, NUM_PLAYERS>
|
||||
index_controller_type_pairs;
|
||||
|
||||
// Labels representing the number of connected controllers
|
||||
// above the "Connected Controllers" checkboxes.
|
||||
std::array<QLabel*, NUM_PLAYERS> connected_controller_labels;
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "yuzu/configuration/input_profiles.h"
|
||||
#include "yuzu/util/limitable_input_dialog.h"
|
||||
|
||||
using namespace Service::HID;
|
||||
|
||||
const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM>
|
||||
ConfigureInputPlayer::analog_sub_buttons{{
|
||||
"up",
|
||||
@@ -47,48 +49,12 @@ void UpdateController(Settings::ControllerType controller_type, std::size_t npad
|
||||
}
|
||||
Service::SM::ServiceManager& sm = system.ServiceManager();
|
||||
|
||||
auto& npad =
|
||||
sm.GetService<Service::HID::Hid>("hid")
|
||||
->GetAppletResource()
|
||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
|
||||
auto& npad = sm.GetService<Hid>("hid")->GetAppletResource()->GetController<Controller_NPad>(
|
||||
HidController::NPad);
|
||||
|
||||
npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
|
||||
}
|
||||
|
||||
/// Maps the controller type combobox index to Controller Type enum
|
||||
constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
default:
|
||||
return Settings::ControllerType::ProController;
|
||||
case 1:
|
||||
return Settings::ControllerType::DualJoyconDetached;
|
||||
case 2:
|
||||
return Settings::ControllerType::LeftJoycon;
|
||||
case 3:
|
||||
return Settings::ControllerType::RightJoycon;
|
||||
case 4:
|
||||
return Settings::ControllerType::Handheld;
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps the Controller Type enum to controller type combobox index
|
||||
constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
|
||||
switch (type) {
|
||||
case Settings::ControllerType::ProController:
|
||||
default:
|
||||
return 0;
|
||||
case Settings::ControllerType::DualJoyconDetached:
|
||||
return 1;
|
||||
case Settings::ControllerType::LeftJoycon:
|
||||
return 2;
|
||||
case Settings::ControllerType::RightJoycon:
|
||||
return 3;
|
||||
case Settings::ControllerType::Handheld:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
QString GetKeyName(int key_code) {
|
||||
switch (key_code) {
|
||||
case Qt::LeftButton:
|
||||
@@ -453,18 +419,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
connect(ui->groupConnectedController, &QGroupBox::toggled,
|
||||
[this](bool checked) { emit Connected(checked); });
|
||||
|
||||
// Set up controller type. Only Player 1 can choose Handheld.
|
||||
ui->comboControllerType->clear();
|
||||
|
||||
QStringList controller_types = {
|
||||
tr("Pro Controller"),
|
||||
tr("Dual Joycons"),
|
||||
tr("Left Joycon"),
|
||||
tr("Right Joycon"),
|
||||
};
|
||||
|
||||
if (player_index == 0) {
|
||||
controller_types.append(tr("Handheld"));
|
||||
connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
[this](int index) {
|
||||
emit HandheldStateChanged(GetControllerTypeFromIndex(index) ==
|
||||
@@ -480,12 +435,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
if (debug) {
|
||||
ui->buttonScreenshot->setEnabled(false);
|
||||
ui->buttonHome->setEnabled(false);
|
||||
QStringList debug_controller_types = {
|
||||
tr("Pro Controller"),
|
||||
};
|
||||
ui->comboControllerType->addItems(debug_controller_types);
|
||||
ui->comboControllerType->addItem(tr("Pro Controller"));
|
||||
} else {
|
||||
ui->comboControllerType->addItems(controller_types);
|
||||
SetConnectableControllers();
|
||||
}
|
||||
|
||||
UpdateControllerIcon();
|
||||
@@ -667,7 +619,7 @@ void ConfigureInputPlayer::LoadConfiguration() {
|
||||
return;
|
||||
}
|
||||
|
||||
ui->comboControllerType->setCurrentIndex(static_cast<int>(player.controller_type));
|
||||
ui->comboControllerType->setCurrentIndex(GetIndexFromControllerType(player.controller_type));
|
||||
ui->groupConnectedController->setChecked(
|
||||
player.connected ||
|
||||
(player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected));
|
||||
@@ -841,6 +793,82 @@ void ConfigureInputPlayer::UpdateUI() {
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::SetConnectableControllers() {
|
||||
const auto add_controllers = [this](bool enable_all,
|
||||
Controller_NPad::NpadStyleSet npad_style_set = {}) {
|
||||
index_controller_type_pairs.clear();
|
||||
ui->comboControllerType->clear();
|
||||
|
||||
if (enable_all || npad_style_set.pro_controller == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Settings::ControllerType::ProController);
|
||||
ui->comboControllerType->addItem(tr("Pro Controller"));
|
||||
}
|
||||
|
||||
if (enable_all || npad_style_set.joycon_dual == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Settings::ControllerType::DualJoyconDetached);
|
||||
ui->comboControllerType->addItem(tr("Dual Joycons"));
|
||||
}
|
||||
|
||||
if (enable_all || npad_style_set.joycon_left == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Settings::ControllerType::LeftJoycon);
|
||||
ui->comboControllerType->addItem(tr("Left Joycon"));
|
||||
}
|
||||
|
||||
if (enable_all || npad_style_set.joycon_right == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Settings::ControllerType::RightJoycon);
|
||||
ui->comboControllerType->addItem(tr("Right Joycon"));
|
||||
}
|
||||
|
||||
if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Settings::ControllerType::Handheld);
|
||||
ui->comboControllerType->addItem(tr("Handheld"));
|
||||
}
|
||||
};
|
||||
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
|
||||
if (!system.IsPoweredOn()) {
|
||||
add_controllers(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Service::SM::ServiceManager& sm = system.ServiceManager();
|
||||
|
||||
auto& npad = sm.GetService<Hid>("hid")->GetAppletResource()->GetController<Controller_NPad>(
|
||||
HidController::NPad);
|
||||
|
||||
add_controllers(false, npad.GetSupportedStyleSet());
|
||||
}
|
||||
|
||||
Settings::ControllerType ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const {
|
||||
const auto it =
|
||||
std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(),
|
||||
[index](const auto& pair) { return pair.first == index; });
|
||||
|
||||
if (it == index_controller_type_pairs.end()) {
|
||||
return Settings::ControllerType::ProController;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
int ConfigureInputPlayer::GetIndexFromControllerType(Settings::ControllerType type) const {
|
||||
const auto it =
|
||||
std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(),
|
||||
[type](const auto& pair) { return pair.second == type; });
|
||||
|
||||
if (it == index_controller_type_pairs.end()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return it->first;
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::UpdateInputDevices() {
|
||||
input_devices = input_subsystem->GetInputDevices();
|
||||
ui->comboDevices->clear();
|
||||
@@ -1137,7 +1165,7 @@ void ConfigureInputPlayer::CreateProfile() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!profiles->IsProfileNameValid(profile_name.toStdString())) {
|
||||
if (!InputProfiles::IsProfileNameValid(profile_name.toStdString())) {
|
||||
QMessageBox::critical(this, tr("Create Input Profile"),
|
||||
tr("The given profile name is not valid!"));
|
||||
return;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
@@ -112,6 +113,15 @@ private:
|
||||
/// Update UI to reflect current configuration.
|
||||
void UpdateUI();
|
||||
|
||||
/// Sets the available controllers.
|
||||
void SetConnectableControllers();
|
||||
|
||||
/// Gets the Controller Type for a given controller combobox index.
|
||||
Settings::ControllerType GetControllerTypeFromIndex(int index) const;
|
||||
|
||||
/// Gets the controller combobox index for a given Controller Type.
|
||||
int GetIndexFromControllerType(Settings::ControllerType type) const;
|
||||
|
||||
/// Update the available input devices.
|
||||
void UpdateInputDevices();
|
||||
|
||||
@@ -151,6 +161,9 @@ private:
|
||||
std::unique_ptr<QTimer> timeout_timer;
|
||||
std::unique_ptr<QTimer> poll_timer;
|
||||
|
||||
/// Stores a pair of "Connected Controllers" combobox index and Controller Type enum.
|
||||
std::vector<std::pair<int, Settings::ControllerType>> index_controller_type_pairs;
|
||||
|
||||
static constexpr int PLAYER_COUNT = 8;
|
||||
std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user