early-access version 1324

This commit is contained in:
pineappleEA 2021-01-15 21:03:50 +01:00
parent d0abd4ba50
commit 6b11334f8f
28 changed files with 504 additions and 287 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 1322. This is the source code for early-access 1324.
## Legal Notice ## Legal Notice

View file

@ -130,7 +130,6 @@ add_subdirectory(tests)
if (ENABLE_SDL2) if (ENABLE_SDL2)
add_subdirectory(yuzu_cmd) add_subdirectory(yuzu_cmd)
add_subdirectory(yuzu_tester)
endif() endif()
if (ENABLE_QT) if (ENABLE_QT)

View file

@ -107,7 +107,6 @@ add_library(common STATIC
bit_util.h bit_util.h
cityhash.cpp cityhash.cpp
cityhash.h cityhash.h
color.h
common_funcs.h common_funcs.h
common_paths.h common_paths.h
common_types.h common_types.h
@ -166,8 +165,6 @@ add_library(common STATIC
threadsafe_queue.h threadsafe_queue.h
time_zone.cpp time_zone.cpp
time_zone.h time_zone.h
timer.cpp
timer.h
tree.h tree.h
uint128.cpp uint128.cpp
uint128.h uint128.h

View file

@ -9,50 +9,45 @@
namespace Common { namespace Common {
template <typename T> template <typename T>
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) { requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUp(T value, size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
auto mod{static_cast<T>(value % size)}; auto mod{static_cast<T>(value % size)};
value -= mod; value -= mod;
return static_cast<T>(mod == T{0} ? value : value + size); return static_cast<T>(mod == T{0} ? value : value + size);
} }
template <typename T> template <typename T>
[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) { requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
}
template <typename T>
requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignDown(T value, size_t size) {
return static_cast<T>(value - value % size); return static_cast<T>(value - value % size);
} }
template <typename T> template <typename T>
[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) { requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool Is4KBAligned(T value) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
}
template <typename T>
[[nodiscard]] constexpr bool Is4KBAligned(T value) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return (value & 0xFFF) == 0; return (value & 0xFFF) == 0;
} }
template <typename T> template <typename T>
[[nodiscard]] constexpr bool IsWordAligned(T value) { requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool IsWordAligned(T value) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return (value & 0b11) == 0; return (value & 0b11) == 0;
} }
template <typename T> template <typename T>
[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) { requires std::is_integral_v<T>[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
using U = typename std::make_unsigned<T>::type; using U = typename std::make_unsigned_t<T>;
const U mask = static_cast<U>(alignment - 1); const U mask = static_cast<U>(alignment - 1);
return (value & mask) == 0; return (value & mask) == 0;
} }
template <typename T, std::size_t Align = 16> template <typename T, size_t Align = 16>
class AlignmentAllocator { class AlignmentAllocator {
public: public:
using value_type = T; using value_type = T;
using size_type = std::size_t; using size_type = size_t;
using difference_type = std::ptrdiff_t; using difference_type = ptrdiff_t;
using propagate_on_container_copy_assignment = std::true_type; using propagate_on_container_copy_assignment = std::true_type;
using propagate_on_container_move_assignment = std::true_type; using propagate_on_container_move_assignment = std::true_type;

View file

@ -21,82 +21,6 @@ template <typename T>
return sizeof(T) * CHAR_BIT; return sizeof(T) * CHAR_BIT;
} }
#ifdef _MSC_VER
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
unsigned long leading_zero = 0;
if (_BitScanReverse(&leading_zero, value) != 0) {
return 31 - leading_zero;
}
return 32;
}
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
unsigned long leading_zero = 0;
if (_BitScanReverse64(&leading_zero, value) != 0) {
return 63 - leading_zero;
}
return 64;
}
#else
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
if (value == 0) {
return 32;
}
return static_cast<u32>(__builtin_clz(value));
}
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
if (value == 0) {
return 64;
}
return static_cast<u32>(__builtin_clzll(value));
}
#endif
#ifdef _MSC_VER
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
unsigned long trailing_zero = 0;
if (_BitScanForward(&trailing_zero, value) != 0) {
return trailing_zero;
}
return 32;
}
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
unsigned long trailing_zero = 0;
if (_BitScanForward64(&trailing_zero, value) != 0) {
return trailing_zero;
}
return 64;
}
#else
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
if (value == 0) {
return 32;
}
return static_cast<u32>(__builtin_ctz(value));
}
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
if (value == 0) {
return 64;
}
return static_cast<u32>(__builtin_ctzll(value));
}
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) { [[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {

View file

@ -8,11 +8,11 @@
#pragma once #pragma once
#include <array> #include <array>
#include <bit>
#include <concepts> #include <concepts>
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_set.h" #include "common/bit_set.h"
#include "common/bit_util.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/concepts.h" #include "common/concepts.h"
@ -268,7 +268,7 @@ private:
} }
constexpr s32 GetNextCore(u64& affinity) { constexpr s32 GetNextCore(u64& affinity) {
const s32 core = Common::CountTrailingZeroes64(affinity); const s32 core = std::countr_zero(affinity);
ClearAffinityBit(affinity, core); ClearAffinityBit(affinity, core);
return core; return core;
} }

View file

@ -5,6 +5,8 @@
// This file references various implementation details from Atmosphere, an open-source firmware for // This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#include <bit>
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_util.h" #include "common/bit_util.h"
#include "common/fiber.h" #include "common/fiber.h"
@ -31,12 +33,12 @@ static void IncrementScheduledCount(Kernel::Thread* thread) {
void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
Core::EmuThreadHandle global_thread) { Core::EmuThreadHandle global_thread) {
u32 current_core = global_thread.host_handle; const u32 current_core = global_thread.host_handle;
bool must_context_switch = global_thread.guest_handle != InvalidHandle && bool must_context_switch = global_thread.guest_handle != InvalidHandle &&
(current_core < Core::Hardware::NUM_CPU_CORES); (current_core < Core::Hardware::NUM_CPU_CORES);
while (cores_pending_reschedule != 0) { while (cores_pending_reschedule != 0) {
u32 core = Common::CountTrailingZeroes64(cores_pending_reschedule); const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule));
ASSERT(core < Core::Hardware::NUM_CPU_CORES); ASSERT(core < Core::Hardware::NUM_CPU_CORES);
if (!must_context_switch || core != current_core) { if (!must_context_switch || core != current_core) {
auto& phys_core = kernel.PhysicalCore(core); auto& phys_core = kernel.PhysicalCore(core);
@ -109,7 +111,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
// Idle cores are bad. We're going to try to migrate threads to each idle core in turn. // Idle cores are bad. We're going to try to migrate threads to each idle core in turn.
while (idle_cores != 0) { while (idle_cores != 0) {
u32 core_id = Common::CountTrailingZeroes64(idle_cores); const auto core_id = static_cast<u32>(std::countr_zero(idle_cores));
if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) {
s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; s32 migration_candidates[Core::Hardware::NUM_CPU_CORES];
size_t num_candidates = 0; size_t num_candidates = 0;

View file

@ -8,11 +8,11 @@
#pragma once #pragma once
#include <array> #include <array>
#include <bit>
#include <vector> #include <vector>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_util.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/kernel/memory/memory_types.h" #include "core/hle/kernel/memory/memory_types.h"
@ -105,7 +105,7 @@ private:
ASSERT(depth == 0); ASSERT(depth == 0);
return -1; return -1;
} }
offset = offset * 64 + Common::CountTrailingZeroes64(v); offset = offset * 64 + static_cast<u32>(std::countr_zero(v));
++depth; ++depth;
} while (depth < static_cast<s32>(used_depths)); } while (depth < static_cast<s32>(used_depths));

View file

@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <bit>
#include "common/bit_util.h" #include "common/bit_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/kernel/errors.h" #include "core/hle/kernel/errors.h"
@ -60,7 +62,7 @@ constexpr CapabilityType GetCapabilityType(u32 value) {
u32 GetFlagBitOffset(CapabilityType type) { u32 GetFlagBitOffset(CapabilityType type) {
const auto value = static_cast<u32>(type); const auto value = static_cast<u32>(type);
return static_cast<u32>(Common::BitSize<u32>() - Common::CountLeadingZeroes32(value)); return static_cast<u32>(Common::BitSize<u32>() - static_cast<u32>(std::countl_zero(value)));
} }
} // Anonymous namespace } // Anonymous namespace

View file

@ -34,7 +34,8 @@ NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
case 0xa: { case 0xa: {
if (command.length == 0x1c) { if (command.length == 0x1c) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}}; Tegra::ChCommandHeaderList cmdlist(1);
cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
system.GPU().PushCommandBuffer(cmdlist); system.GPU().PushCommandBuffer(cmdlist);
system.GPU().MemoryManager().InvalidateQueuedCaches(); system.GPU().MemoryManager().InvalidateQueuedCaches();
} }

View file

@ -29,13 +29,8 @@ NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
return GetWaitbase(input, output); return GetWaitbase(input, output);
case 0x9: case 0x9:
return MapBuffer(input, output); return MapBuffer(input, output);
case 0xa: { case 0xa:
if (command.length == 0x1c) {
Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}};
system.GPU().PushCommandBuffer(cmdlist);
}
return UnmapBuffer(input, output); return UnmapBuffer(input, output);
}
default: default:
break; break;
} }

View file

@ -1,6 +1,5 @@
add_executable(tests add_executable(tests
common/bit_field.cpp common/bit_field.cpp
common/bit_utils.cpp
common/fibers.cpp common/fibers.cpp
common/param_package.cpp common/param_package.cpp
common/ring_buffer.cpp common/ring_buffer.cpp

View file

@ -18,10 +18,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// //
#include <bit>
#include "command_classes/host1x.h" #include "command_classes/host1x.h"
#include "command_classes/nvdec.h" #include "command_classes/nvdec.h"
#include "command_classes/vic.h" #include "command_classes/vic.h"
#include "common/bit_util.h"
#include "video_core/cdma_pusher.h" #include "video_core/cdma_pusher.h"
#include "video_core/command_classes/nvdec_common.h" #include "video_core/command_classes/nvdec_common.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
@ -37,43 +37,59 @@ CDmaPusher::CDmaPusher(GPU& gpu_)
CDmaPusher::~CDmaPusher() = default; CDmaPusher::~CDmaPusher() = default;
void CDmaPusher::ProcessEntries(ChCommandHeaderList&& entries) { void CDmaPusher::Push(ChCommandHeaderList&& entries) {
for (const auto& value : entries) { cdma_queue.push(std::move(entries));
}
void CDmaPusher::DispatchCalls() {
while (!cdma_queue.empty()) {
Step();
}
}
void CDmaPusher::Step() {
const auto entries{cdma_queue.front()};
cdma_queue.pop();
std::vector<u32> values(entries.size());
std::memcpy(values.data(), entries.data(), entries.size() * sizeof(u32));
for (const u32 value : values) {
if (mask != 0) { if (mask != 0) {
const u32 lbs = Common::CountTrailingZeroes32(mask); const auto lbs = static_cast<u32>(std::countr_zero(mask));
mask &= ~(1U << lbs); mask &= ~(1U << lbs);
ExecuteCommand(offset + lbs, value.raw); ExecuteCommand(static_cast<u32>(offset + lbs), value);
continue; continue;
} else if (count != 0) { } else if (count != 0) {
--count; --count;
ExecuteCommand(offset, value.raw); ExecuteCommand(static_cast<u32>(offset), value);
if (incrementing) { if (incrementing) {
++offset; ++offset;
} }
continue; continue;
} }
const auto mode = value.submission_mode.Value(); const auto mode = static_cast<ChSubmissionMode>((value >> 28) & 0xf);
switch (mode) { switch (mode) {
case ChSubmissionMode::SetClass: { case ChSubmissionMode::SetClass: {
mask = value.value & 0x3f; mask = value & 0x3f;
offset = value.method_offset; offset = (value >> 16) & 0xfff;
current_class = static_cast<ChClassId>((value.value >> 6) & 0x3ff); current_class = static_cast<ChClassId>((value >> 6) & 0x3ff);
break; break;
} }
case ChSubmissionMode::Incrementing: case ChSubmissionMode::Incrementing:
case ChSubmissionMode::NonIncrementing: case ChSubmissionMode::NonIncrementing:
count = value.value; count = value & 0xffff;
offset = value.method_offset; offset = (value >> 16) & 0xfff;
incrementing = mode == ChSubmissionMode::Incrementing; incrementing = mode == ChSubmissionMode::Incrementing;
break; break;
case ChSubmissionMode::Mask: case ChSubmissionMode::Mask:
mask = value.value; mask = value & 0xffff;
offset = value.method_offset; offset = (value >> 16) & 0xfff;
break; break;
case ChSubmissionMode::Immediate: { case ChSubmissionMode::Immediate: {
const u32 data = value.value & 0xfff; const u32 data = value & 0xfff;
offset = value.method_offset; offset = (value >> 16) & 0xfff;
ExecuteCommand(offset, data); ExecuteCommand(static_cast<u32>(offset), data);
break; break;
} }
default: default:
@ -86,8 +102,8 @@ void CDmaPusher::ProcessEntries(ChCommandHeaderList&& entries) {
void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) { void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
switch (current_class) { switch (current_class) {
case ChClassId::NvDec: case ChClassId::NvDec:
ThiStateWrite(nvdec_thi_state, offset, data); ThiStateWrite(nvdec_thi_state, state_offset, {data});
switch (static_cast<ThiMethod>(offset)) { switch (static_cast<ThiMethod>(state_offset)) {
case ThiMethod::IncSyncpt: { case ThiMethod::IncSyncpt: {
LOG_DEBUG(Service_NVDRV, "NVDEC Class IncSyncpt Method"); LOG_DEBUG(Service_NVDRV, "NVDEC Class IncSyncpt Method");
const auto syncpoint_id = static_cast<u32>(data & 0xFF); const auto syncpoint_id = static_cast<u32>(data & 0xFF);
@ -104,7 +120,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
LOG_DEBUG(Service_NVDRV, "NVDEC method 0x{:X}", LOG_DEBUG(Service_NVDRV, "NVDEC method 0x{:X}",
static_cast<u32>(nvdec_thi_state.method_0)); static_cast<u32>(nvdec_thi_state.method_0));
nvdec_processor->ProcessMethod(static_cast<Nvdec::Method>(nvdec_thi_state.method_0), nvdec_processor->ProcessMethod(static_cast<Nvdec::Method>(nvdec_thi_state.method_0),
data); {data});
break; break;
default: default:
break; break;
@ -128,7 +144,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
case ThiMethod::SetMethod1: case ThiMethod::SetMethod1:
LOG_DEBUG(Service_NVDRV, "VIC method 0x{:X}, Args=({})", LOG_DEBUG(Service_NVDRV, "VIC method 0x{:X}, Args=({})",
static_cast<u32>(vic_thi_state.method_0), data); static_cast<u32>(vic_thi_state.method_0), data);
vic_processor->ProcessMethod(static_cast<Vic::Method>(vic_thi_state.method_0), data); vic_processor->ProcessMethod(static_cast<Vic::Method>(vic_thi_state.method_0), {data});
break; break;
default: default:
break; break;
@ -137,7 +153,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
case ChClassId::Host1x: case ChClassId::Host1x:
// This device is mainly for syncpoint synchronization // This device is mainly for syncpoint synchronization
LOG_DEBUG(Service_NVDRV, "Host1X Class Method"); LOG_DEBUG(Service_NVDRV, "Host1X Class Method");
host1x_processor->ProcessMethod(static_cast<Host1x::Method>(offset), data); host1x_processor->ProcessMethod(static_cast<Host1x::Method>(state_offset), {data});
break; break;
default: default:
UNIMPLEMENTED_MSG("Current class not implemented {:X}", static_cast<u32>(current_class)); UNIMPLEMENTED_MSG("Current class not implemented {:X}", static_cast<u32>(current_class));
@ -145,9 +161,10 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
} }
} }
void CDmaPusher::ThiStateWrite(ThiRegisters& state, u32 state_offset, u32 argument) { void CDmaPusher::ThiStateWrite(ThiRegisters& state, u32 state_offset,
u8* const offset_ptr = reinterpret_cast<u8*>(&state) + sizeof(u32) * state_offset; const std::vector<u32>& arguments) {
std::memcpy(offset_ptr, &argument, sizeof(u32)); u8* const state_offset_ptr = reinterpret_cast<u8*>(&state) + sizeof(u32) * state_offset;
std::memcpy(state_offset_ptr, arguments.data(), sizeof(u32) * arguments.size());
} }
} // namespace Tegra } // namespace Tegra

View file

@ -5,7 +5,9 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <unordered_map>
#include <vector> #include <vector>
#include <queue>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
@ -14,9 +16,9 @@
namespace Tegra { namespace Tegra {
class GPU; class GPU;
class Host1x;
class Nvdec; class Nvdec;
class Vic; class Vic;
class Host1x;
enum class ChSubmissionMode : u32 { enum class ChSubmissionMode : u32 {
SetClass = 0, SetClass = 0,
@ -46,10 +48,16 @@ enum class ChClassId : u32 {
NvDec = 0xf0 NvDec = 0xf0
}; };
enum class ChMethod : u32 {
Empty = 0,
SetMethod = 0x10,
SetData = 0x11,
};
union ChCommandHeader { union ChCommandHeader {
u32 raw; u32 raw;
BitField<0, 16, u32> value; BitField<0, 16, u32> value;
BitField<16, 12, u32> method_offset; BitField<16, 12, ChMethod> method_offset;
BitField<28, 4, ChSubmissionMode> submission_mode; BitField<28, 4, ChSubmissionMode> submission_mode;
}; };
static_assert(sizeof(ChCommandHeader) == sizeof(u32), "ChCommand header is an invalid size"); static_assert(sizeof(ChCommandHeader) == sizeof(u32), "ChCommand header is an invalid size");
@ -91,15 +99,21 @@ public:
explicit CDmaPusher(GPU& gpu_); explicit CDmaPusher(GPU& gpu_);
~CDmaPusher(); ~CDmaPusher();
/// Process the command entry /// Push NVDEC command buffer entries into queue
void ProcessEntries(ChCommandHeaderList&& entries); void Push(ChCommandHeaderList&& entries);
/// Process queued command buffer entries
void DispatchCalls();
/// Process one queue element
void Step();
private:
/// Invoke command class devices to execute the command based on the current state /// Invoke command class devices to execute the command based on the current state
void ExecuteCommand(u32 state_offset, u32 data); void ExecuteCommand(u32 state_offset, u32 data);
private:
/// Write arguments value to the ThiRegisters member at the specified offset /// Write arguments value to the ThiRegisters member at the specified offset
void ThiStateWrite(ThiRegisters& state, u32 offset, u32 argument); void ThiStateWrite(ThiRegisters& state, u32 state_offset, const std::vector<u32>& arguments);
GPU& gpu; GPU& gpu;
std::shared_ptr<Tegra::Nvdec> nvdec_processor; std::shared_ptr<Tegra::Nvdec> nvdec_processor;
@ -110,10 +124,13 @@ private:
ThiRegisters vic_thi_state{}; ThiRegisters vic_thi_state{};
ThiRegisters nvdec_thi_state{}; ThiRegisters nvdec_thi_state{};
u32 count{}; s32 count{};
u32 offset{}; s32 offset{};
u32 mask{}; u32 mask{};
bool incrementing{}; bool incrementing{};
// Queue of command lists to be processed
std::queue<ChCommandHeaderList> cdma_queue;
}; };
} // namespace Tegra } // namespace Tegra

View file

@ -44,11 +44,9 @@ Codec::~Codec() {
} }
void Codec::SetTargetCodec(NvdecCommon::VideoCodec codec) { void Codec::SetTargetCodec(NvdecCommon::VideoCodec codec) {
if (current_codec != codec) { LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", codec);
LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", static_cast<u32>(codec));
current_codec = codec; current_codec = codec;
} }
}
void Codec::StateWrite(u32 offset, u64 arguments) { void Codec::StateWrite(u32 offset, u64 arguments) {
u8* const state_offset = reinterpret_cast<u8*>(&state) + offset * sizeof(u64); u8* const state_offset = reinterpret_cast<u8*>(&state) + offset * sizeof(u64);
@ -57,6 +55,7 @@ void Codec::StateWrite(u32 offset, u64 arguments) {
void Codec::Decode() { void Codec::Decode() {
bool is_first_frame = false; bool is_first_frame = false;
if (!initialized) { if (!initialized) {
if (current_codec == NvdecCommon::VideoCodec::H264) { if (current_codec == NvdecCommon::VideoCodec::H264) {
av_codec = avcodec_find_decoder(AV_CODEC_ID_H264); av_codec = avcodec_find_decoder(AV_CODEC_ID_H264);

View file

@ -19,7 +19,7 @@
// //
#include <array> #include <array>
#include "common/bit_util.h" #include <bit>
#include "video_core/command_classes/codecs/h264.h" #include "video_core/command_classes/codecs/h264.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
@ -266,7 +266,7 @@ void H264BitWriter::WriteExpGolombCodedInt(s32 value) {
} }
void H264BitWriter::WriteExpGolombCodedUInt(u32 value) { void H264BitWriter::WriteExpGolombCodedUInt(u32 value) {
const s32 size = 32 - Common::CountLeadingZeroes32(static_cast<s32>(value + 1)); const s32 size = 32 - std::countl_zero(value + 1);
WriteBits(1, size); WriteBits(1, size);
value -= (1U << (size - 1)) - 1; value -= (1U << (size - 1)) - 1;

View file

@ -12,16 +12,16 @@ Nvdec::Nvdec(GPU& gpu_) : gpu(gpu_), codec(std::make_unique<Codec>(gpu)) {}
Nvdec::~Nvdec() = default; Nvdec::~Nvdec() = default;
void Nvdec::ProcessMethod(Method method, u32 argument) { void Nvdec::ProcessMethod(Method method, const std::vector<u32>& arguments) {
if (method == Method::SetVideoCodec) { if (method == Method::SetVideoCodec) {
codec->StateWrite(static_cast<u32>(method), argument); codec->StateWrite(static_cast<u32>(method), arguments[0]);
} else { } else {
codec->StateWrite(static_cast<u32>(method), static_cast<u64>(argument) << 8); codec->StateWrite(static_cast<u32>(method), static_cast<u64>(arguments[0]) << 8);
} }
switch (method) { switch (method) {
case Method::SetVideoCodec: case Method::SetVideoCodec:
codec->SetTargetCodec(static_cast<NvdecCommon::VideoCodec>(argument)); codec->SetTargetCodec(static_cast<NvdecCommon::VideoCodec>(arguments[0]));
break; break;
case Method::Execute: case Method::Execute:
Execute(); Execute();

View file

@ -23,7 +23,7 @@ public:
~Nvdec(); ~Nvdec();
/// Writes the method into the state, Invoke Execute() if encountered /// Writes the method into the state, Invoke Execute() if encountered
void ProcessMethod(Method method, u32 argument); void ProcessMethod(Method method, const std::vector<u32>& arguments);
/// Return most recently decoded frame /// Return most recently decoded frame
[[nodiscard]] AVFramePtr GetFrame(); [[nodiscard]] AVFramePtr GetFrame();

View file

@ -18,14 +18,18 @@ extern "C" {
namespace Tegra { namespace Tegra {
Vic::Vic(GPU& gpu_, std::shared_ptr<Nvdec> nvdec_processor_) Vic::Vic(GPU& gpu_, std::shared_ptr<Nvdec> nvdec_processor_)
: gpu(gpu_), : gpu(gpu_), nvdec_processor(std::move(nvdec_processor_)) {}
nvdec_processor(std::move(nvdec_processor_)), converted_frame_buffer{nullptr, av_free} {}
Vic::~Vic() = default; Vic::~Vic() = default;
void Vic::ProcessMethod(Method method, u32 argument) { void Vic::VicStateWrite(u32 offset, u32 arguments) {
LOG_DEBUG(HW_GPU, "Vic method 0x{:X}", static_cast<u32>(method)); u8* const state_offset = reinterpret_cast<u8*>(&vic_state) + offset * sizeof(u32);
const u64 arg = static_cast<u64>(argument) << 8; std::memcpy(state_offset, &arguments, sizeof(u32));
}
void Vic::ProcessMethod(Method method, const std::vector<u32>& arguments) {
LOG_DEBUG(HW_GPU, "Vic method 0x{:X}", method);
VicStateWrite(static_cast<u32>(method), arguments[0]);
const u64 arg = static_cast<u64>(arguments[0]) << 8;
switch (method) { switch (method) {
case Method::Execute: case Method::Execute:
Execute(); Execute();
@ -49,7 +53,8 @@ void Vic::ProcessMethod(Method method, u32 argument) {
void Vic::Execute() { void Vic::Execute() {
if (output_surface_luma_address == 0) { if (output_surface_luma_address == 0) {
LOG_ERROR(Service_NVDRV, "VIC Luma address not set."); LOG_ERROR(Service_NVDRV, "VIC Luma address not set. Received 0x{:X}",
vic_state.output_surface.luma_offset);
return; return;
} }
const VicConfig config{gpu.MemoryManager().Read<u64>(config_struct_address + 0x20)}; const VicConfig config{gpu.MemoryManager().Read<u64>(config_struct_address + 0x20)};
@ -84,10 +89,8 @@ void Vic::Execute() {
// Get Converted frame // Get Converted frame
const std::size_t linear_size = frame->width * frame->height * 4; const std::size_t linear_size = frame->width * frame->height * 4;
// Only allocate frame_buffer once per stream, as the size is not expected to change using AVMallocPtr = std::unique_ptr<u8, decltype(&av_free)>;
if (!converted_frame_buffer) { AVMallocPtr converted_frame_buffer{static_cast<u8*>(av_malloc(linear_size)), av_free};
converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(linear_size)), av_free};
}
const int converted_stride{frame->width * 4}; const int converted_stride{frame->width * 4};
u8* const converted_frame_buf_addr{converted_frame_buffer.get()}; u8* const converted_frame_buf_addr{converted_frame_buffer.get()};
@ -101,12 +104,12 @@ void Vic::Execute() {
const u32 block_height = static_cast<u32>(config.block_linear_height_log2); const u32 block_height = static_cast<u32>(config.block_linear_height_log2);
const auto size = Tegra::Texture::CalculateSize(true, 4, frame->width, frame->height, 1, const auto size = Tegra::Texture::CalculateSize(true, 4, frame->width, frame->height, 1,
block_height, 0); block_height, 0);
luma_buffer.resize(size); std::vector<u8> swizzled_data(size);
Tegra::Texture::SwizzleSubrect(frame->width, frame->height, frame->width * 4, Tegra::Texture::SwizzleSubrect(frame->width, frame->height, frame->width * 4,
frame->width, 4, luma_buffer.data(), frame->width, 4, swizzled_data.data(),
converted_frame_buffer.get(), block_height, 0, 0); converted_frame_buffer.get(), block_height, 0, 0);
gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), size); gpu.MemoryManager().WriteBlock(output_surface_luma_address, swizzled_data.data(), size);
gpu.Maxwell3D().OnMemoryWrite(); gpu.Maxwell3D().OnMemoryWrite();
} else { } else {
// send pitch linear frame // send pitch linear frame
@ -131,15 +134,15 @@ void Vic::Execute() {
const auto stride = frame->linesize[0]; const auto stride = frame->linesize[0];
const auto half_stride = frame->linesize[1]; const auto half_stride = frame->linesize[1];
luma_buffer.resize(aligned_width * surface_height); std::vector<u8> luma_buffer(aligned_width * surface_height);
chroma_buffer.resize(aligned_width * half_height); std::vector<u8> chroma_buffer(aligned_width * half_height);
// Populate luma buffer // Populate luma buffer
for (std::size_t y = 0; y < surface_height - 1; ++y) { for (std::size_t y = 0; y < surface_height - 1; ++y) {
const std::size_t src = y * stride; std::size_t src = y * stride;
const std::size_t dst = y * aligned_width; std::size_t dst = y * aligned_width;
const std::size_t size = surface_width; std::size_t size = surface_width;
for (std::size_t offset = 0; offset < size; ++offset) { for (std::size_t offset = 0; offset < size; ++offset) {
luma_buffer[dst + offset] = luma_ptr[src + offset]; luma_buffer[dst + offset] = luma_ptr[src + offset];
@ -150,8 +153,8 @@ void Vic::Execute() {
// Populate chroma buffer from both channels with interleaving. // Populate chroma buffer from both channels with interleaving.
for (std::size_t y = 0; y < half_height; ++y) { for (std::size_t y = 0; y < half_height; ++y) {
const std::size_t src = y * half_stride; std::size_t src = y * half_stride;
const std::size_t dst = y * aligned_width; std::size_t dst = y * aligned_width;
for (std::size_t x = 0; x < half_width; ++x) { for (std::size_t x = 0; x < half_width; ++x) {
chroma_buffer[dst + x * 2] = chroma_b_ptr[src + x]; chroma_buffer[dst + x * 2] = chroma_b_ptr[src + x];

View file

@ -15,6 +15,43 @@ namespace Tegra {
class GPU; class GPU;
class Nvdec; class Nvdec;
struct PlaneOffsets {
u32 luma_offset{};
u32 chroma_u_offset{};
u32 chroma_v_offset{};
};
struct VicRegisters {
INSERT_PADDING_WORDS(64);
u32 nop{};
INSERT_PADDING_WORDS(15);
u32 pm_trigger{};
INSERT_PADDING_WORDS(47);
u32 set_application_id{};
u32 set_watchdog_timer{};
INSERT_PADDING_WORDS(17);
u32 context_save_area{};
u32 context_switch{};
INSERT_PADDING_WORDS(43);
u32 execute{};
INSERT_PADDING_WORDS(63);
std::array<std::array<PlaneOffsets, 8>, 8> surfacex_slots{};
u32 picture_index{};
u32 control_params{};
u32 config_struct_offset{};
u32 filter_struct_offset{};
u32 palette_offset{};
u32 hist_offset{};
u32 context_id{};
u32 fce_ucode_size{};
PlaneOffsets output_surface{};
u32 fce_ucode_offset{};
INSERT_PADDING_WORDS(4);
std::array<u32, 8> slot_context_id{};
INSERT_PADDING_WORDS(16);
};
static_assert(sizeof(VicRegisters) == 0x7A0, "VicRegisters is an invalid size");
class Vic { class Vic {
public: public:
enum class Method : u32 { enum class Method : u32 {
@ -30,11 +67,14 @@ public:
~Vic(); ~Vic();
/// Write to the device state. /// Write to the device state.
void ProcessMethod(Method method, u32 argument); void ProcessMethod(Method method, const std::vector<u32>& arguments);
private: private:
void Execute(); void Execute();
void VicStateWrite(u32 offset, u32 arguments);
VicRegisters vic_state{};
enum class VideoPixelFormat : u64_le { enum class VideoPixelFormat : u64_le {
RGBA8 = 0x1f, RGBA8 = 0x1f,
BGRA8 = 0x20, BGRA8 = 0x20,
@ -48,6 +88,8 @@ private:
BitField<9, 2, u64_le> chroma_loc_vert; BitField<9, 2, u64_le> chroma_loc_vert;
BitField<11, 4, u64_le> block_linear_kind; BitField<11, 4, u64_le> block_linear_kind;
BitField<15, 4, u64_le> block_linear_height_log2; BitField<15, 4, u64_le> block_linear_height_log2;
BitField<19, 3, u64_le> reserved0;
BitField<22, 10, u64_le> reserved1;
BitField<32, 14, u64_le> surface_width_minus1; BitField<32, 14, u64_le> surface_width_minus1;
BitField<46, 14, u64_le> surface_height_minus1; BitField<46, 14, u64_le> surface_height_minus1;
}; };
@ -55,13 +97,6 @@ private:
GPU& gpu; GPU& gpu;
std::shared_ptr<Tegra::Nvdec> nvdec_processor; std::shared_ptr<Tegra::Nvdec> nvdec_processor;
/// Avoid reallocation of the following buffers every frame, as their
/// size does not change during a stream
using AVMallocPtr = std::unique_ptr<u8, decltype(&av_free)>;
AVMallocPtr converted_frame_buffer;
std::vector<u8> luma_buffer;
std::vector<u8> chroma_buffer;
GPUVAddr config_struct_address{}; GPUVAddr config_struct_address{};
GPUVAddr output_surface_luma_address{}; GPUVAddr output_surface_luma_address{};
GPUVAddr output_surface_chroma_u_address{}; GPUVAddr output_surface_chroma_u_address{};

View file

@ -30,7 +30,8 @@ MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
GPU::GPU(Core::System& system_, bool is_async_, bool use_nvdec_) GPU::GPU(Core::System& system_, bool is_async_, bool use_nvdec_)
: system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(system)}, : system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(system)},
dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)}, use_nvdec{use_nvdec_}, dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)},
cdma_pusher{std::make_unique<Tegra::CDmaPusher>(*this)}, use_nvdec{use_nvdec_},
maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)}, maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)},
fermi_2d{std::make_unique<Engines::Fermi2D>()}, fermi_2d{std::make_unique<Engines::Fermi2D>()},
kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)}, kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)},
@ -493,7 +494,8 @@ void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) {
// TODO(ameerj): RE proper async nvdec operation // TODO(ameerj): RE proper async nvdec operation
// gpu_thread.SubmitCommandBuffer(std::move(entries)); // gpu_thread.SubmitCommandBuffer(std::move(entries));
cdma_pusher->ProcessEntries(std::move(entries)); cdma_pusher->Push(std::move(entries));
cdma_pusher->DispatchCalls();
} }
void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {

View file

@ -47,7 +47,8 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
dma_pusher.DispatchCalls(); dma_pusher.DispatchCalls();
} else if (auto* command_list = std::get_if<SubmitChCommandEntries>(&next.data)) { } else if (auto* command_list = std::get_if<SubmitChCommandEntries>(&next.data)) {
// NVDEC // NVDEC
cdma_pusher.ProcessEntries(std::move(command_list->entries)); cdma_pusher.Push(std::move(command_list->entries));
cdma_pusher.DispatchCalls();
} else if (const auto* data = std::get_if<SwapBuffersCommand>(&next.data)) { } else if (const auto* data = std::get_if<SwapBuffersCommand>(&next.data)) {
renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr); renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr);
} else if (std::holds_alternative<OnCommandListEndCommand>(next.data)) { } else if (std::holds_alternative<OnCommandListEndCommand>(next.data)) {

View file

@ -27,7 +27,7 @@ BlockLinearSwizzle2DParams MakeBlockLinearSwizzle2DParams(const SwizzleParameter
const Extent3D num_tiles = swizzle.num_tiles; const Extent3D num_tiles = swizzle.num_tiles;
const u32 bytes_per_block = BytesPerBlock(info.format); const u32 bytes_per_block = BytesPerBlock(info.format);
const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level); const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level);
const u32 stride = Common::AlignBits(num_tiles.width, stride_alignment) * bytes_per_block; const u32 stride = Common::AlignUpLog2(num_tiles.width, stride_alignment) * bytes_per_block;
const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT); const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT);
return BlockLinearSwizzle2DParams{ return BlockLinearSwizzle2DParams{
.origin{0, 0, 0}, .origin{0, 0, 0},
@ -47,7 +47,7 @@ BlockLinearSwizzle3DParams MakeBlockLinearSwizzle3DParams(const SwizzleParameter
const Extent3D num_tiles = swizzle.num_tiles; const Extent3D num_tiles = swizzle.num_tiles;
const u32 bytes_per_block = BytesPerBlock(info.format); const u32 bytes_per_block = BytesPerBlock(info.format);
const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level); const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level);
const u32 stride = Common::AlignBits(num_tiles.width, stride_alignment) * bytes_per_block; const u32 stride = Common::AlignUpLog2(num_tiles.width, stride_alignment) * bytes_per_block;
const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) >> GOB_SIZE_X_SHIFT; const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) >> GOB_SIZE_X_SHIFT;
const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block.height + block.depth); const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block.height + block.depth);

View file

@ -279,7 +279,7 @@ template <u32 GOB_EXTENT>
const bool is_small = IsSmallerThanGobSize(blocks, gob, info.block.depth); const bool is_small = IsSmallerThanGobSize(blocks, gob, info.block.depth);
const u32 alignment = is_small ? 0 : info.tile_width_spacing; const u32 alignment = is_small ? 0 : info.tile_width_spacing;
return Extent2D{ return Extent2D{
.width = Common::AlignBits(gobs.width, alignment), .width = Common::AlignUpLog2(gobs.width, alignment),
.height = gobs.height, .height = gobs.height,
}; };
} }
@ -352,7 +352,7 @@ template <u32 GOB_EXTENT>
// https://github.com/Ryujinx/Ryujinx/blob/1c9aba6de1520aea5480c032e0ff5664ac1bb36f/Ryujinx.Graphics.Texture/SizeCalculator.cs#L134 // https://github.com/Ryujinx/Ryujinx/blob/1c9aba6de1520aea5480c032e0ff5664ac1bb36f/Ryujinx.Graphics.Texture/SizeCalculator.cs#L134
if (tile_width_spacing > 0) { if (tile_width_spacing > 0) {
const u32 alignment_log2 = GOB_SIZE_SHIFT + tile_width_spacing + block.height + block.depth; const u32 alignment_log2 = GOB_SIZE_SHIFT + tile_width_spacing + block.height + block.depth;
return Common::AlignBits(size_bytes, alignment_log2); return Common::AlignUpLog2(size_bytes, alignment_log2);
} }
const u32 aligned_height = Common::AlignUp(size.height, tile_size_y); const u32 aligned_height = Common::AlignUp(size.height, tile_size_y);
while (block.height != 0 && aligned_height <= (1U << (block.height - 1)) * GOB_SIZE_Y) { while (block.height != 0 && aligned_height <= (1U << (block.height - 1)) * GOB_SIZE_Y) {
@ -528,9 +528,9 @@ template <u32 GOB_EXTENT>
const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing); const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing);
const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0); const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0);
return Extent3D{ return Extent3D{
.width = Common::AlignBits(num_tiles.width, alignment), .width = Common::AlignUpLog2(num_tiles.width, alignment),
.height = Common::AlignBits(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height), .height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height),
.depth = Common::AlignBits(num_tiles.depth, GOB_SIZE_Z_SHIFT + mip_block.depth), .depth = Common::AlignUpLog2(num_tiles.depth, GOB_SIZE_Z_SHIFT + mip_block.depth),
}; };
} }

View file

@ -49,7 +49,7 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe
// We can configure here a custom pitch // We can configure here a custom pitch
// As it's not exposed 'width * bpp' will be the expected pitch. // As it's not exposed 'width * bpp' will be the expected pitch.
const u32 pitch = width * bytes_per_pixel; const u32 pitch = width * bytes_per_pixel;
const u32 stride = Common::AlignBits(width, stride_alignment) * bytes_per_pixel; const u32 stride = Common::AlignUpLog2(width, stride_alignment) * bytes_per_pixel;
const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT); const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT);
const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth);
@ -217,9 +217,9 @@ void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32
std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
u32 block_height, u32 block_depth) { u32 block_height, u32 block_depth) {
if (tiled) { if (tiled) {
const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, GOB_SIZE_X_SHIFT); const u32 aligned_width = Common::AlignUpLog2(width * bytes_per_pixel, GOB_SIZE_X_SHIFT);
const u32 aligned_height = Common::AlignBits(height, GOB_SIZE_Y_SHIFT + block_height); const u32 aligned_height = Common::AlignUpLog2(height, GOB_SIZE_Y_SHIFT + block_height);
const u32 aligned_depth = Common::AlignBits(depth, GOB_SIZE_Z_SHIFT + block_depth); const u32 aligned_depth = Common::AlignUpLog2(depth, GOB_SIZE_Z_SHIFT + block_depth);
return aligned_width * aligned_height * aligned_depth; return aligned_width * aligned_height * aligned_depth;
} else { } else {
return width * height * depth * bytes_per_pixel; return width * height * depth * bytes_per_pixel;

View file

@ -112,7 +112,7 @@ private:
if (commit->Contains(*candidate, size)) { if (commit->Contains(*candidate, size)) {
candidate = std::nullopt; candidate = std::nullopt;
} }
iterator = Common::AlignBits(commit->end, alignment_log2); iterator = Common::AlignUpLog2(commit->end, alignment_log2);
++commit; ++commit;
} }
return candidate; return candidate;

View file

@ -250,9 +250,9 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
// D-pad constants // D-pad constants
const QPointF dpad_center = center + QPoint(9, 14); const QPointF dpad_center = center + QPoint(9, 14);
const int dpad_distance = 23; constexpr int dpad_distance = 23;
const int dpad_radius = 11; constexpr int dpad_radius = 11;
const float dpad_arrow_size = 1.2f; constexpr float dpad_arrow_size = 1.2f;
// D-pad buttons // D-pad buttons
p.setPen(colors.outline); p.setPen(colors.outline);
@ -344,8 +344,9 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
// Face buttons constants // Face buttons constants
const QPointF face_center = center + QPoint(-9, -73); const QPointF face_center = center + QPoint(-9, -73);
const int face_distance = 23; constexpr int face_distance = 23;
const int face_radius = 11; constexpr int face_radius = 11;
constexpr float text_size = 1.1f;
// Face buttons // Face buttons
p.setPen(colors.outline); p.setPen(colors.outline);
@ -356,11 +357,12 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
// Face buttons text // Face buttons text
p.setPen(colors.font); p.setPen(colors.transparent);
DrawText(p, face_center + QPoint(face_distance, 0), 10, QStringLiteral("A")); p.setBrush(colors.font);
DrawText(p, face_center + QPoint(0, face_distance), 10, QStringLiteral("B")); DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
DrawText(p, face_center + QPoint(0, -face_distance), 10, QStringLiteral("X")); DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
DrawText(p, face_center + QPoint(-face_distance + 1, 1), 10, QStringLiteral("Y")); DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
// SR and SL buttons // SR and SL buttons
p.setPen(colors.outline); p.setPen(colors.outline);
@ -385,7 +387,9 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 12); DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 12);
button_color = colors.button; button_color = colors.button;
DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 9); DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 9);
DrawHouseIcon(p, center + QPoint(-26, 66), 5); p.setPen(colors.transparent);
p.setBrush(colors.font2);
DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5);
} }
void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) { void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) {
@ -457,9 +461,9 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
// Face buttons constants // Face buttons constants
const QPointF face_center = center + QPoint(65, -65); const QPointF face_center = center + QPoint(65, -65);
const int face_distance = 20; constexpr int face_distance = 20;
const int face_radius = 10; constexpr int face_radius = 10;
const int text_size = 10; constexpr float text_size = 1.0f;
// Face buttons // Face buttons
p.setPen(colors.outline); p.setPen(colors.outline);
@ -470,17 +474,18 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
// Face buttons text // Face buttons text
p.setPen(colors.font); p.setPen(colors.transparent);
DrawText(p, face_center + QPoint(face_distance, 0), text_size, QStringLiteral("A")); p.setBrush(colors.font);
DrawText(p, face_center + QPoint(0, face_distance), text_size, QStringLiteral("B")); DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
DrawText(p, face_center + QPoint(0, -face_distance), text_size, QStringLiteral("X")); DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
DrawText(p, face_center + QPointF(-face_distance + 0.5f, 1), text_size, QStringLiteral("Y")); DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
// D-pad constants // D-pad constants
const QPointF dpad_center = center + QPoint(-65, 12); const QPointF dpad_center = center + QPoint(-65, 12);
const int dpad_distance = 20; constexpr int dpad_distance = 20;
const int dpad_radius = 10; constexpr int dpad_radius = 10;
const float dpad_arrow_size = 1.1f; constexpr float dpad_arrow_size = 1.1f;
// D-pad buttons // D-pad buttons
p.setPen(colors.outline); p.setPen(colors.outline);
@ -516,7 +521,9 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 11); DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 11);
button_color = colors.button; button_color = colors.button;
DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 8.5f); DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 8.5f);
DrawHouseIcon(p, center + QPoint(50, 60), 4.2f); p.setPen(colors.transparent);
p.setBrush(colors.font2);
DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f);
} }
void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) { void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) {
@ -539,9 +546,9 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
// Face buttons constants // Face buttons constants
const QPointF face_center = center + QPoint(171, -41); const QPointF face_center = center + QPoint(171, -41);
const int face_distance = 12; constexpr int face_distance = 12;
const int face_radius = 6; constexpr int face_radius = 6;
const float text_size = 5.5f; constexpr float text_size = 0.6f;
// Face buttons // Face buttons
p.setPen(colors.outline); p.setPen(colors.outline);
@ -552,17 +559,18 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
// Face buttons text // Face buttons text
p.setPen(colors.font); p.setPen(colors.transparent);
DrawText(p, face_center + QPointF(face_distance + 0.2f, 0), text_size, QStringLiteral("A")); p.setBrush(colors.font);
DrawText(p, face_center + QPoint(0, face_distance), text_size, QStringLiteral("B")); DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
DrawText(p, face_center + QPoint(0, -face_distance), text_size, QStringLiteral("X")); DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
DrawText(p, face_center + QPointF(-face_distance + 0.2f, 0), text_size, QStringLiteral("Y")); DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
// D-pad constants // D-pad constants
const QPointF dpad_center = center + QPoint(-171, 8); const QPointF dpad_center = center + QPoint(-171, 8);
const int dpad_distance = 12; constexpr int dpad_distance = 12;
const int dpad_radius = 6; constexpr int dpad_radius = 6;
const float dpad_arrow_size = 0.68f; constexpr float dpad_arrow_size = 0.68f;
// D-pad buttons // D-pad buttons
p.setPen(colors.outline); p.setPen(colors.outline);
@ -582,11 +590,12 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
// ZL and ZR buttons // ZL and ZR buttons
p.setPen(colors.outline); p.setPen(colors.outline);
DrawCircleButton(p, center + QPoint(-175, -120), button_values[ZL], 15); DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
DrawCircleButton(p, center + QPoint(175, -120), button_values[ZR], 15); DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
p.setPen(colors.font); p.setPen(colors.transparent);
DrawText(p, center + QPoint(-175, -120), 9, QStringLiteral("ZL")); p.setBrush(colors.font);
DrawText(p, center + QPoint(175, -120), 9, QStringLiteral("ZR")); DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
// Minus and Plus button // Minus and Plus button
p.setPen(colors.outline); p.setPen(colors.outline);
@ -607,7 +616,9 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 7); DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 7);
button_color = colors.button; button_color = colors.button;
DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 5); DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 5);
DrawHouseIcon(p, center + QPoint(161, 37), 2.75f); p.setPen(colors.transparent);
p.setBrush(colors.font2);
DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f);
} }
void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) { void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) {
@ -630,9 +641,9 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
// Face buttons constants // Face buttons constants
const QPointF face_center = center + QPoint(105, -56); const QPointF face_center = center + QPoint(105, -56);
const int face_distance = 31; constexpr int face_distance = 31;
const int face_radius = 15; constexpr int face_radius = 15;
const int text_size = 13; constexpr float text_size = 1.5f;
// Face buttons // Face buttons
p.setPen(colors.outline); p.setPen(colors.outline);
@ -643,11 +654,12 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
// Face buttons text // Face buttons text
p.setPen(colors.font); p.setPen(colors.transparent);
DrawText(p, face_center + QPoint(face_distance, 0), text_size, QStringLiteral("A")); p.setBrush(colors.font);
DrawText(p, face_center + QPoint(0, face_distance), text_size, QStringLiteral("B")); DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
DrawText(p, face_center + QPoint(0, -face_distance), text_size, QStringLiteral("X")); DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
DrawText(p, face_center + QPoint(-face_distance, 1), text_size, QStringLiteral("Y")); DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
// D-pad buttons // D-pad buttons
const QPointF dpad_postion = center + QPoint(-61, 0); const QPointF dpad_postion = center + QPoint(-61, 0);
@ -655,23 +667,28 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft]); DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft]);
DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight]); DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight]);
DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown]); DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown]);
DrawArrowButtonOutline(p, dpad_postion);
// ZL and ZR buttons // ZL and ZR buttons
p.setPen(colors.outline); p.setPen(colors.outline);
DrawCircleButton(p, center + QPoint(-175, -120), button_values[ZL], 15); DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
DrawCircleButton(p, center + QPoint(175, -120), button_values[ZR], 15); DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
p.setPen(colors.font); p.setPen(colors.transparent);
DrawText(p, center + QPoint(-175, -120), 9, QStringLiteral("ZL")); p.setBrush(colors.font);
DrawText(p, center + QPoint(175, -120), 9, QStringLiteral("ZR")); DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
// Minus and Plus buttons // Minus and Plus buttons
p.setPen(colors.outline); p.setPen(colors.outline);
DrawCircleButton(p, center + QPoint(-50, -86), button_values[Minus], 9); DrawCircleButton(p, center + QPoint(-50, -86), button_values[Minus], 9);
DrawCircleButton(p, center + QPoint(49, -86), button_values[Plus], 9); DrawCircleButton(p, center + QPoint(50, -86), button_values[Plus], 9);
// Minus and Plus symbols
p.setPen(colors.font2); p.setPen(colors.font2);
p.setBrush(colors.font2); p.setBrush(colors.font2);
DrawRectangle(p, center + QPoint(-50, -86), 8, 2); DrawRectangle(p, center + QPoint(-50, -86), 9, 1.5f);
DrawText(p, center + QPointF(49.5f, -86), 12, QStringLiteral("+")); DrawRectangle(p, center + QPoint(50, -86), 9, 1.5f);
DrawRectangle(p, center + QPoint(50, -86), 1.5f, 9);
// Screenshot button // Screenshot button
p.setPen(colors.outline); p.setPen(colors.outline);
@ -683,21 +700,96 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
// Home Button // Home Button
p.setPen(colors.outline); p.setPen(colors.outline);
button_color = colors.slider_button; button_color = colors.slider_button;
DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 9); DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 10.0f);
button_color = colors.button; button_color = colors.button;
DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 7.1f); DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 7.1f);
DrawHouseIcon(p, center + QPoint(29, -56), 3.9f); p.setPen(colors.transparent);
p.setBrush(colors.font2);
DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f);
} }
constexpr std::array<float, 13 * 2> symbol_a = {
-1.085f, -5.2f, 1.085f, -5.2f, 5.085f, 5.0f, 2.785f, 5.0f, 1.785f,
2.65f, -1.785f, 2.65f, -2.785f, 5.0f, -5.085f, 5.0f, -1.4f, 1.0f,
0.0f, -2.8f, 1.4f, 1.0f, -1.4f, 1.0f, -5.085f, 5.0f,
};
constexpr std::array<float, 134 * 2> symbol_b = {
-4.0f, 0.0f, -4.0f, 0.0f, -4.0f, -0.1f, -3.8f, -5.1f, 1.8f, -5.0f, 2.3f, -4.9f, 2.6f,
-4.8f, 2.8f, -4.7f, 2.9f, -4.6f, 3.1f, -4.5f, 3.2f, -4.4f, 3.4f, -4.3f, 3.4f, -4.2f,
3.5f, -4.1f, 3.7f, -4.0f, 3.7f, -3.9f, 3.8f, -3.8f, 3.8f, -3.7f, 3.9f, -3.6f, 3.9f,
-3.5f, 4.0f, -3.4f, 4.0f, -3.3f, 4.1f, -3.1f, 4.1f, -3.0f, 4.0f, -2.0f, 4.0f, -1.9f,
3.9f, -1.7f, 3.9f, -1.6f, 3.8f, -1.5f, 3.8f, -1.4f, 3.7f, -1.3f, 3.7f, -1.2f, 3.6f,
-1.1f, 3.6f, -1.0f, 3.5f, -0.9f, 3.3f, -0.8f, 3.3f, -0.7f, 3.2f, -0.6f, 3.0f, -0.5f,
2.9f, -0.4f, 2.7f, -0.3f, 2.9f, -0.2f, 3.2f, -0.1f, 3.3f, 0.0f, 3.5f, 0.1f, 3.6f,
0.2f, 3.8f, 0.3f, 3.9f, 0.4f, 4.0f, 0.6f, 4.1f, 0.7f, 4.3f, 0.8f, 4.3f, 0.9f,
4.4f, 1.0f, 4.4f, 1.1f, 4.5f, 1.3f, 4.5f, 1.4f, 4.6f, 1.6f, 4.6f, 1.7f, 4.5f,
2.8f, 4.5f, 2.9f, 4.4f, 3.1f, 4.4f, 3.2f, 4.3f, 3.4f, 4.3f, 3.5f, 4.2f, 3.6f,
4.2f, 3.7f, 4.1f, 3.8f, 4.1f, 3.9f, 4.0f, 4.0f, 3.9f, 4.2f, 3.8f, 4.3f, 3.6f,
4.4f, 3.6f, 4.5f, 3.4f, 4.6f, 3.3f, 4.7f, 3.1f, 4.8f, 2.8f, 4.9f, 2.6f, 5.0f,
2.1f, 5.1f, -4.0f, 5.0f, -4.0f, 4.9f,
-4.0f, 0.0f, 1.1f, 3.4f, 1.1f, 3.4f, 1.5f, 3.3f, 1.8f, 3.2f, 2.0f, 3.1f, 2.1f,
3.0f, 2.3f, 2.9f, 2.3f, 2.8f, 2.4f, 2.7f, 2.4f, 2.6f, 2.5f, 2.3f, 2.5f, 2.2f,
2.4f, 1.7f, 2.4f, 1.6f, 2.3f, 1.4f, 2.3f, 1.3f, 2.2f, 1.2f, 2.2f, 1.1f, 2.1f,
1.0f, 1.9f, 0.9f, 1.6f, 0.8f, 1.4f, 0.7f, -1.9f, 0.6f, -1.9f, 0.7f, -1.8f, 3.4f,
1.1f, 3.4f, -4.0f, 0.0f,
0.3f, -1.1f, 0.3f, -1.1f, 1.3f, -1.2f, 1.5f, -1.3f, 1.8f, -1.4f, 1.8f, -1.5f, 1.9f,
-1.6f, 2.0f, -1.8f, 2.0f, -1.9f, 2.1f, -2.0f, 2.1f, -2.1f, 2.0f, -2.7f, 2.0f, -2.8f,
1.9f, -2.9f, 1.9f, -3.0f, 1.8f, -3.1f, 1.6f, -3.2f, 1.6f, -3.3f, 1.3f, -3.4f, -1.9f,
-3.3f, -1.9f, -3.2f, -1.8f, -1.0f, 0.2f, -1.1f, 0.3f, -1.1f, -4.0f, 0.0f,
};
constexpr std::array<float, 9 * 2> symbol_y = {
-4.79f, -4.9f, -2.44f, -4.9f, 0.0f, -0.9f, 2.44f, -4.9f, 4.79f,
-4.9f, 1.05f, 1.0f, 1.05f, 5.31f, -1.05f, 5.31f, -1.05f, 1.0f,
};
constexpr std::array<float, 12 * 2> symbol_x = {
-4.4f, -5.0f, -2.0f, -5.0f, 0.0f, -1.7f, 2.0f, -5.0f, 4.4f, -5.0f, 1.2f, 0.0f,
4.4f, 5.0f, 2.0f, 5.0f, 0.0f, 1.7f, -2.0f, 5.0f, -4.4f, 5.0f, -1.2f, 0.0f,
};
constexpr std::array<float, 18 * 2> symbol_zl = {
-2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f,
-0.7f, 2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f, 2.4f, -3.23f, 2.4f, 2.1f,
5.43f, 2.1f, 5.43f, 3.22f, 0.98f, 3.22f, 0.98f, -3.23f, 2.4f, -3.23f, -6.0f, 2.12f,
};
constexpr std::array<float, 110 * 2> symbol_zr = {
-2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f, -0.7f,
2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f,
1.0f, 0.0f, 1.0f, -0.1f, 1.1f, -3.3f, 4.3f, -3.2f, 5.1f, -3.1f, 5.4f, -3.0f, 5.6f,
-2.9f, 5.7f, -2.8f, 5.9f, -2.7f, 5.9f, -2.6f, 6.0f, -2.5f, 6.1f, -2.3f, 6.2f, -2.2f,
6.2f, -2.1f, 6.3f, -2.0f, 6.3f, -1.9f, 6.2f, -0.8f, 6.2f, -0.7f, 6.1f, -0.6f, 6.1f,
-0.5f, 6.0f, -0.4f, 6.0f, -0.3f, 5.9f, -0.2f, 5.7f, -0.1f, 5.7f, 0.0f, 5.6f, 0.1f,
5.4f, 0.2f, 5.1f, 0.3f, 4.7f, 0.4f, 4.7f, 0.5f, 4.9f, 0.6f, 5.0f, 0.7f, 5.2f,
0.8f, 5.2f, 0.9f, 5.3f, 1.0f, 5.5f, 1.1f, 5.5f, 1.2f, 5.6f, 1.3f, 5.7f, 1.5f,
5.8f, 1.6f, 5.9f, 1.8f, 6.0f, 1.9f, 6.1f, 2.1f, 6.2f, 2.2f, 6.2f, 2.3f, 6.3f,
2.4f, 6.4f, 2.6f, 6.5f, 2.7f, 6.6f, 2.9f, 6.7f, 3.0f, 6.7f, 3.1f, 6.8f, 3.2f,
6.8f, 3.3f, 5.3f, 3.2f, 5.2f, 3.1f, 5.2f, 3.0f, 5.1f, 2.9f, 5.0f, 2.7f, 4.9f,
2.6f, 4.8f, 2.4f, 4.7f, 2.3f, 4.6f, 2.1f, 4.5f, 2.0f, 4.4f, 1.8f, 4.3f, 1.7f,
4.1f, 1.4f, 4.0f, 1.3f, 3.9f, 1.1f, 3.8f, 1.0f, 3.6f, 0.9f, 3.6f, 0.8f, 3.5f,
0.7f, 3.3f, 0.6f, 2.9f, 0.5f, 2.3f, 0.6f, 2.3f, 0.7f, 2.2f, 3.3f, 1.0f, 3.2f,
1.0f, 3.1f, 1.0f, 0.0f,
4.2f, -0.5f, 4.2f, -0.5f, 4.4f, -0.6f, 4.7f, -0.7f, 4.8f, -0.8f, 4.9f, -1.0f, 5.0f,
-1.1f, 5.0f, -1.2f, 4.9f, -1.7f, 4.9f, -1.8f, 4.8f, -1.9f, 4.8f, -2.0f, 4.6f, -2.1f,
4.3f, -2.2f, 2.3f, -2.1f, 2.3f, -2.0f, 2.4f, -0.5f, 4.2f, -0.5f, 1.0f, 0.0f, -6.0f,
2.12f,
};
constexpr std::array<float, 12 * 2> house = { constexpr std::array<float, 12 * 2> house = {
-1.3f, 0.0f, -0.93f, 0.0f, -0.93f, 1.15f, 0.93f, 1.15f, 0.93f, 0.0f, 1.3f, 0.0f, -1.3f, 0.0f, -0.93f, 0.0f, -0.93f, 1.15f, 0.93f, 1.15f, 0.93f, 0.0f, 1.3f, 0.0f,
0.0f, -1.2f, -1.3f, 0.0f, -0.43f, 0.0f, -0.43f, .73f, 0.43f, .73f, 0.43f, 0.0f, 0.0f, -1.2f, -1.3f, 0.0f, -0.43f, 0.0f, -0.43f, .73f, 0.43f, .73f, 0.43f, 0.0f,
}; };
constexpr std::array<float, 15 * 2> up_arrow_button = { constexpr std::array<float, 11 * 2> up_arrow_button = {
-8.6f, -30.0f, -9.0f, -29.8f, -9.3f, -29.5f, -9.5f, -29.1f, -9.5f, -28.7f, 9.1f, -9.1f, 9.1f, -30.0f, 8.1f, -30.1f, 7.7f, -30.1f, -8.6f, -30.0f, -9.0f,
-9.1f, -9.1f, -8.8f, -8.8f, 0.3f, -0.3f, 0.6f, -0.6f, 9.4f, -9.8f, -29.8f, -9.3f, -29.5f, -9.5f, -29.1f, -9.1f, -28.7f, -9.1f, -9.1f, 0.0f, 0.6f,
9.4f, -10.2f, 8.9f, -29.8f, 8.5f, -30.0f, 8.1f, -30.1f, 7.7f, -30.1f,
}; };
constexpr std::array<float, 3 * 2> up_arrow_symbol = { constexpr std::array<float, 3 * 2> up_arrow_symbol = {
@ -710,6 +802,20 @@ constexpr std::array<float, 13 * 2> up_arrow = {
-9.5f, -29.1f, -9.5f, -28.7f, -9.1f, -9.1f, -8.8f, -8.8f, -9.5f, -29.1f, -9.5f, -28.7f, -9.1f, -9.1f, -8.8f, -8.8f,
}; };
constexpr std::array<float, 64 * 2> trigger_button = {
5.5f, -12.6f, 5.8f, -12.6f, 6.7f, -12.5f, 8.1f, -12.3f, 8.6f, -12.2f, 9.2f, -12.0f,
9.5f, -11.9f, 9.9f, -11.8f, 10.6f, -11.5f, 11.0f, -11.3f, 11.2f, -11.2f, 11.4f, -11.1f,
11.8f, -10.9f, 12.0f, -10.8f, 12.2f, -10.7f, 12.4f, -10.5f, 12.6f, -10.4f, 12.8f, -10.3f,
13.6f, -9.7f, 13.8f, -9.6f, 13.9f, -9.4f, 14.1f, -9.3f, 14.8f, -8.6f, 15.0f, -8.5f,
15.1f, -8.3f, 15.6f, -7.8f, 15.7f, -7.6f, 16.1f, -7.0f, 16.3f, -6.8f, 16.4f, -6.6f,
16.5f, -6.4f, 16.8f, -6.0f, 16.9f, -5.8f, 17.0f, -5.6f, 17.1f, -5.4f, 17.2f, -5.2f,
17.3f, -5.0f, 17.4f, -4.8f, 17.5f, -4.6f, 17.6f, -4.4f, 17.7f, -4.1f, 17.8f, -3.9f,
17.9f, -3.5f, 18.0f, -3.3f, 18.1f, -3.0f, 18.2f, -2.6f, 18.2f, -2.3f, 18.3f, -2.1f,
18.3f, -1.9f, 18.4f, -1.4f, 18.5f, -1.2f, 18.6f, -0.3f, 18.6f, 0.0f, 18.3f, 13.9f,
-17.0f, 13.8f, -17.0f, 13.6f, -16.4f, -11.4f, -16.3f, -11.6f, -16.1f, -11.8f, -15.7f, -12.0f,
-15.5f, -12.1f, -15.1f, -12.3f, -14.6f, -12.4f, -13.4f, -12.5f,
};
constexpr std::array<float, 36 * 2> pro_left_trigger = { constexpr std::array<float, 36 * 2> pro_left_trigger = {
-65.2f, -132.6f, -68.2f, -134.1f, -71.3f, -135.5f, -74.4f, -136.7f, -77.6f, -65.2f, -132.6f, -68.2f, -134.1f, -71.3f, -135.5f, -74.4f, -136.7f, -77.6f,
-137.6f, -80.9f, -138.1f, -84.3f, -138.3f, -87.6f, -138.3f, -91.0f, -138.1f, -137.6f, -80.9f, -138.1f, -84.3f, -138.3f, -87.6f, -138.3f, -91.0f, -138.1f,
@ -1660,9 +1766,29 @@ void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, b
} }
p.drawEllipse(center, button_size, button_size); p.drawEllipse(center, button_size, button_size);
} }
void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF center) {
const std::size_t arrow_points = up_arrow_button.size() / 2;
std::array<QPointF, (arrow_points - 1) * 4> arrow_button_outline;
for (std::size_t point = 0; point < arrow_points - 1; ++point) {
arrow_button_outline[point] =
center + QPointF(up_arrow_button[point * 2], up_arrow_button[point * 2 + 1]);
arrow_button_outline[(arrow_points - 1) * 2 - point - 1] =
center + QPointF(up_arrow_button[point * 2 + 1], up_arrow_button[point * 2]);
arrow_button_outline[(arrow_points - 1) * 2 + point] =
center + QPointF(-up_arrow_button[point * 2], -up_arrow_button[point * 2 + 1]);
arrow_button_outline[(arrow_points - 1) * 4 - point - 1] =
center + QPointF(-up_arrow_button[point * 2 + 1], -up_arrow_button[point * 2]);
}
// Draw arrow button outline
p.setPen(colors.outline);
p.setBrush(colors.transparent);
DrawPolygon(p, arrow_button_outline);
}
void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
const Direction direction, bool pressed) { const Direction direction, bool pressed) {
std::array<QPointF, up_arrow_button.size() / 2> arrow_button; std::array<QPointF, up_arrow_button.size() / 2> arrow_button;
QPoint offset; QPoint offset;
@ -1671,23 +1797,70 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
case Direction::Up: case Direction::Up:
arrow_button[point] = arrow_button[point] =
center + QPointF(up_arrow_button[point * 2], up_arrow_button[point * 2 + 1]); center + QPointF(up_arrow_button[point * 2], up_arrow_button[point * 2 + 1]);
offset = QPoint(0, -20);
break; break;
case Direction::Left: case Direction::Left:
arrow_button[point] = arrow_button[point] =
center + QPointF(up_arrow_button[point * 2 + 1], up_arrow_button[point * 2]); center + QPointF(up_arrow_button[point * 2 + 1], up_arrow_button[point * 2]);
offset = QPoint(-20, 0);
break; break;
case Direction::Right: case Direction::Right:
arrow_button[point] = arrow_button[point] =
center + QPointF(-up_arrow_button[point * 2 + 1], up_arrow_button[point * 2]); center + QPointF(-up_arrow_button[point * 2 + 1], up_arrow_button[point * 2]);
offset = QPoint(20, 0);
break; break;
case Direction::Down: case Direction::Down:
arrow_button[point] = arrow_button[point] =
center + QPointF(up_arrow_button[point * 2], -up_arrow_button[point * 2 + 1]); center + QPointF(up_arrow_button[point * 2], -up_arrow_button[point * 2 + 1]);
break;
case Direction::None:
break;
}
}
// Draw arrow button
p.setPen(pressed ? colors.highlight : colors.button);
p.setBrush(pressed ? colors.highlight : colors.button);
DrawPolygon(p, arrow_button);
switch (direction) {
case Direction::Up:
offset = QPoint(0, -20);
break;
case Direction::Left:
offset = QPoint(-20, 0);
break;
case Direction::Right:
offset = QPoint(20, 0);
break;
case Direction::Down:
offset = QPoint(0, 20); offset = QPoint(0, 20);
break; break;
case Direction::None:
offset = QPoint(0, 0);
break;
}
// Draw arrow icon
p.setPen(colors.font2);
p.setBrush(colors.font2);
DrawArrow(p, center + offset, direction, 1.0f);
}
void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center,
const Direction direction, bool pressed) {
std::array<QPointF, trigger_button.size() / 2> qtrigger_button;
QPoint offset;
for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) {
switch (direction) {
case Direction::Left:
qtrigger_button[point] =
center + QPointF(-trigger_button[point * 2], trigger_button[point * 2 + 1]);
break;
case Direction::Right:
qtrigger_button[point] =
center + QPointF(trigger_button[point * 2], trigger_button[point * 2 + 1]);
break;
case Direction::Up:
case Direction::Down:
case Direction::None: case Direction::None:
break; break;
} }
@ -1696,25 +1869,69 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
// Draw arrow button // Draw arrow button
p.setPen(colors.outline); p.setPen(colors.outline);
p.setBrush(pressed ? colors.highlight : colors.button); p.setBrush(pressed ? colors.highlight : colors.button);
DrawPolygon(p, arrow_button); DrawPolygon(p, qtrigger_button);
// Draw arrow icon
p.setPen(colors.font2);
p.setBrush(colors.font2);
DrawArrow(p, center + offset, direction, 1.0f);
} }
void PlayerControlPreview::DrawHouseIcon(QPainter& p, const QPointF center, float icon_size) { void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol symbol,
float icon_size) {
std::array<QPointF, house.size() / 2> house_icon; std::array<QPointF, house.size() / 2> house_icon;
std::array<QPointF, symbol_a.size() / 2> a_icon;
std::array<QPointF, symbol_b.size() / 2> b_icon;
std::array<QPointF, symbol_x.size() / 2> x_icon;
std::array<QPointF, symbol_y.size() / 2> y_icon;
std::array<QPointF, symbol_zl.size() / 2> zl_icon;
std::array<QPointF, symbol_zr.size() / 2> zr_icon;
switch (symbol) {
case Symbol::House:
for (std::size_t point = 0; point < house.size() / 2; ++point) { for (std::size_t point = 0; point < house.size() / 2; ++point) {
house_icon[point] = center + QPointF(house[point * 2] * icon_size, house_icon[point] = center + QPointF(house[point * 2] * icon_size,
(house[point * 2 + 1] - 0.025f) * icon_size); (house[point * 2 + 1] - 0.025f) * icon_size);
} }
p.setPen(colors.transparent);
p.setBrush(colors.font2);
p.drawPolygon(house_icon.data(), static_cast<int>(house_icon.size())); p.drawPolygon(house_icon.data(), static_cast<int>(house_icon.size()));
break;
case Symbol::A:
for (std::size_t point = 0; point < symbol_a.size() / 2; ++point) {
a_icon[point] = center + QPointF(symbol_a[point * 2] * icon_size,
symbol_a[point * 2 + 1] * icon_size);
}
p.drawPolygon(a_icon.data(), static_cast<int>(a_icon.size()));
break;
case Symbol::B:
for (std::size_t point = 0; point < symbol_b.size() / 2; ++point) {
b_icon[point] = center + QPointF(symbol_b[point * 2] * icon_size,
symbol_b[point * 2 + 1] * icon_size);
}
p.drawPolygon(b_icon.data(), static_cast<int>(b_icon.size()));
break;
case Symbol::X:
for (std::size_t point = 0; point < symbol_x.size() / 2; ++point) {
x_icon[point] = center + QPointF(symbol_x[point * 2] * icon_size,
symbol_x[point * 2 + 1] * icon_size);
}
p.drawPolygon(x_icon.data(), static_cast<int>(x_icon.size()));
break;
case Symbol::Y:
for (std::size_t point = 0; point < symbol_y.size() / 2; ++point) {
y_icon[point] = center + QPointF(symbol_y[point * 2] * icon_size,
(symbol_y[point * 2 + 1] - 1.0f) * icon_size);
}
p.drawPolygon(y_icon.data(), static_cast<int>(y_icon.size()));
break;
case Symbol::ZL:
for (std::size_t point = 0; point < symbol_zl.size() / 2; ++point) {
zl_icon[point] = center + QPointF(symbol_zl[point * 2] * icon_size,
symbol_zl[point * 2 + 1] * icon_size);
}
p.drawPolygon(zl_icon.data(), static_cast<int>(zl_icon.size()));
break;
case Symbol::ZR:
for (std::size_t point = 0; point < symbol_zr.size() / 2; ++point) {
zr_icon[point] = center + QPointF(symbol_zr[point * 2] * icon_size,
symbol_zr[point * 2 + 1] * icon_size);
}
p.drawPolygon(zr_icon.data(), static_cast<int>(zr_icon.size()));
break;
}
} }
void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Direction direction, void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Direction direction,

View file

@ -43,6 +43,16 @@ private:
Left, Left,
}; };
enum class Symbol {
House,
A,
B,
X,
Y,
ZL,
ZR,
};
struct AxisValue { struct AxisValue {
QPointF value{}; QPointF value{};
QPointF raw_value{}; QPointF raw_value{};
@ -120,10 +130,12 @@ private:
Direction direction = Direction::None, float radius = 2); Direction direction = Direction::None, float radius = 2);
void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size); void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size);
void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size); void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size);
void DrawArrowButtonOutline(QPainter& p, const QPointF center);
void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed); void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed);
void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, bool pressed);
// Draw icon functions // Draw icon functions
void DrawHouseIcon(QPainter& p, QPointF center, float icon_size); void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
void DrawArrow(QPainter& p, QPointF center, Direction direction, float size); void DrawArrow(QPainter& p, QPointF center, Direction direction, float size);
// Draw primitive types // Draw primitive types