early-access version 1424

This commit is contained in:
pineappleEA 2021-02-08 06:07:34 +01:00
parent 5ff3465447
commit 5c7b8e9d6c
6 changed files with 231 additions and 114 deletions

View file

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

View file

@ -374,7 +374,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Get the thread's id. // Get the thread's id.
*out_thread_id = thread->GetThreadID(); *out_thread_id = thread->GetThreadID();
@ -484,7 +487,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Cancel the thread's wait. // Cancel the thread's wait.
thread->WaitCancel(); thread->WaitCancel();
@ -502,8 +508,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd
thread_handle, address, tag); thread_handle, address, tag);
// Validate the input address. // Validate the input address.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(u32))) {
LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
return ResultInvalidAddress;
}
return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag);
} }
@ -518,8 +531,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) {
LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
// Validate the input address. // Validate the input address.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC,
"Attempting to arbitrate an unlock on a kernel address (address={:08X})",
address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(u32))) {
LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
return ResultInvalidAddress;
}
return system.Kernel().CurrentProcess()->SignalToAddress(address); return system.Kernel().CurrentProcess()->SignalToAddress(address);
} }
@ -1031,37 +1052,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
return UnmapPhysicalMemory(system, addr, size); return UnmapPhysicalMemory(system, addr, size);
} }
constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
switch (thread_activity) {
case Svc::ThreadActivity::Runnable:
case Svc::ThreadActivity::Paused:
return true;
default:
return false;
}
}
/// Sets the thread activity /// Sets the thread activity
static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
Svc::ThreadActivity thread_activity) { ThreadActivity thread_activity) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
thread_activity); thread_activity);
// Validate the activity. // Validate the activity.
R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue); constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
};
if (!IsValidThreadActivity(thread_activity)) {
LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
thread_activity);
return ResultInvalidEnumValue;
}
// Get the thread from its handle. // Get the thread from its handle.
auto& kernel = system.Kernel(); auto& kernel = system.Kernel();
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Check that the activity is being set on a non-current thread for the current process. // Check that the activity is being set on a non-current thread for the current process.
R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle); if (thread->GetOwnerProcess() != kernel.CurrentProcess()) {
R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy); LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread.");
return ResultInvalidHandle;
}
if (thread.get() == GetCurrentThreadPointer(kernel)) {
LOG_ERROR(Kernel_SVC, "Thread is busy");
return ResultBusy;
}
// Set the activity. // Set the activity.
R_TRY(thread->SetActivity(thread_activity)); const auto set_result = thread->SetActivity(thread_activity);
if (set_result.IsError()) {
LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
return set_result;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1080,16 +1111,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
const auto* current_process = system.Kernel().CurrentProcess(); const auto* current_process = system.Kernel().CurrentProcess();
const std::shared_ptr<KThread> thread = const std::shared_ptr<KThread> thread =
current_process->GetHandleTable().Get<KThread>(thread_handle); current_process->GetHandleTable().Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
return ResultInvalidHandle;
}
// Require the handle be to a non-current thread in the current process. // Require the handle be to a non-current thread in the current process.
R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); if (thread->GetOwnerProcess() != current_process) {
R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process.");
Svc::ResultBusy); return ResultInvalidHandle;
}
if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
LOG_ERROR(Kernel_SVC, "Current thread is busy.");
return ResultBusy;
}
// Get the thread context. // Get the thread context.
std::vector<u8> context; std::vector<u8> context;
R_TRY(thread->GetThreadContext3(context)); const auto context_result = thread->GetThreadContext3(context);
if (context_result.IsError()) {
LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})",
context_result.raw);
return context_result;
}
// Copy the thread context to user space. // Copy the thread context to user space.
system.Memory().WriteBlock(out_context, context.data(), context.size()); system.Memory().WriteBlock(out_context, context.data(), context.size());
@ -1108,7 +1152,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
return ResultInvalidHandle;
}
// Get the thread's priority. // Get the thread's priority.
*out_priority = thread->GetPriority(); *out_priority = thread->GetPriority();
@ -1124,13 +1171,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
LOG_TRACE(Kernel_SVC, "called"); LOG_TRACE(Kernel_SVC, "called");
// Validate the priority. // Validate the priority.
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
Svc::ResultInvalidPriority); LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority);
return ResultInvalidPriority;
}
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
return ResultInvalidHandle;
}
// Set the thread priority. // Set the thread priority.
thread->SetBasePriority(priority); thread->SetBasePriority(priority);
@ -1446,17 +1498,28 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
// Adjust core id, if it's the default magic. // Adjust core id, if it's the default magic.
auto& kernel = system.Kernel(); auto& kernel = system.Kernel();
auto& process = *kernel.CurrentProcess(); auto& process = *kernel.CurrentProcess();
if (core_id == Svc::IdealCoreUseProcessValue) { if (core_id == IdealCoreUseProcessValue) {
core_id = process.GetIdealCoreId(); core_id = process.GetIdealCoreId();
} }
// Validate arguments. // Validate arguments.
R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); if (!IsValidCoreId(core_id)) {
R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
return ResultInvalidCoreId;
}
if (((1ULL << core_id) & process.GetCoreMask()) == 0) {
LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id);
return ResultInvalidCoreId;
}
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
Svc::ResultInvalidPriority); LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority);
R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); return ResultInvalidPriority;
}
if (!process.CheckThreadPriority(priority)) {
LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority);
return ResultInvalidPriority;
}
KScopedResourceReservation thread_reservation( KScopedResourceReservation thread_reservation(
kernel.CurrentProcess(), LimitableResource::Threads, 1, kernel.CurrentProcess(), LimitableResource::Threads, 1,
@ -1501,10 +1564,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Try to start the thread. // Try to start the thread.
R_TRY(thread->Run()); const auto run_result = thread->Run();
if (run_result.IsError()) {
LOG_ERROR(Kernel_SVC,
"Unable to successfuly start thread (thread handle={:08X}, result={})",
thread_handle, run_result.raw);
return run_result;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1565,8 +1637,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address,
cv_key, tag, timeout_ns); cv_key, tag, timeout_ns);
// Validate input. // Validate input.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
// Convert timeout from nanoseconds to ticks. // Convert timeout from nanoseconds to ticks.
s64 timeout{}; s64 timeout{};
@ -1641,9 +1719,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit
address, arb_type, value, timeout_ns); address, arb_type, value, timeout_ns);
// Validate input. // Validate input.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue); return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
if (!IsValidArbitrationType(arb_type)) {
LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type);
return ResultInvalidEnumValue;
}
// Convert timeout from nanoseconds to ticks. // Convert timeout from nanoseconds to ticks.
s64 timeout{}; s64 timeout{};
@ -1677,9 +1764,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
address, signal_type, value, count); address, signal_type, value, count);
// Validate input. // Validate input.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue); return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
if (!IsValidSignalType(signal_type)) {
LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type);
return ResultInvalidEnumValue;
}
return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value,
count); count);
@ -1835,10 +1931,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Get the core mask. // Get the core mask.
R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask);
if (result.IsError()) {
LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
return result;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1866,26 +1969,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
} else { } else {
// Validate the affinity mask. // Validate the affinity mask.
const u64 process_core_mask = current_process.GetCoreMask(); const u64 process_core_mask = current_process.GetCoreMask();
R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, if ((affinity_mask | process_core_mask) != process_core_mask) {
Svc::ResultInvalidCoreId); LOG_ERROR(Kernel_SVC,
R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); "Affinity mask does match the process core mask (affinity mask={:016X}, core "
"mask={:016X})",
affinity_mask, process_core_mask);
return ResultInvalidCoreId;
}
if (affinity_mask == 0) {
LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
return ResultInvalidCombination;
}
// Validate the core id. // Validate the core id.
if (IsValidCoreId(core_id)) { if (IsValidCoreId(core_id)) {
R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); if (((1ULL << core_id) & affinity_mask) == 0) {
LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
return ResultInvalidCombination;
}
} else { } else {
R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) {
Svc::ResultInvalidCoreId); LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
return ResultInvalidCoreId;
}
} }
} }
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Set the core mask. // Set the core mask.
R_TRY(thread->SetCoreMask(core_id, affinity_mask)); const auto set_result = thread->SetCoreMask(core_id, affinity_mask);
if (set_result.IsError()) {
LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
return set_result;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1913,7 +2036,10 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
// Get the writable event. // Get the writable event.
auto writable_event = handle_table.Get<KWritableEvent>(event_handle); auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
R_UNLESS(writable_event, Svc::ResultInvalidHandle); if (!writable_event) {
LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
return ResultInvalidHandle;
}
// Commit the successfuly reservation. // Commit the successfuly reservation.
event_reservation.Commit(); event_reservation.Commit();
@ -1965,7 +2091,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o
// Create a new event. // Create a new event.
const auto event = KEvent::Create(kernel, "CreateEvent"); const auto event = KEvent::Create(kernel, "CreateEvent");
R_UNLESS(event != nullptr, Svc::ResultOutOfResource); if (!event) {
LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
return ResultOutOfResource;
}
// Initialize the event. // Initialize the event.
event->Initialize(); event->Initialize();

View file

@ -37,7 +37,7 @@ void Mouse::UpdateThread() {
if (configuring) { if (configuring) {
UpdateYuzuSettings(); UpdateYuzuSettings();
} }
if (mouse_panning_timout++ > 12) { if (mouse_panning_timout++ > 8) {
StopPanning(); StopPanning();
} }
std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
@ -72,11 +72,9 @@ void Mouse::PressButton(int x, int y, int button_) {
void Mouse::StopPanning() { void Mouse::StopPanning() {
for (MouseInfo& info : mouse_info) { for (MouseInfo& info : mouse_info) {
if (Settings::values.mouse_panning) { if (Settings::values.mouse_panning) {
if (info.data.pressed) { info.data.axis = {};
continue;
}
info.data.axis = {0, 0};
info.tilt_speed = 0; info.tilt_speed = 0;
info.last_mouse_change = {};
} }
} }
} }
@ -85,17 +83,15 @@ void Mouse::MouseMove(int x, int y, int center_x, int center_y) {
for (MouseInfo& info : mouse_info) { for (MouseInfo& info : mouse_info) {
if (Settings::values.mouse_panning) { if (Settings::values.mouse_panning) {
const auto mouse_change = Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y); const auto mouse_change = Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y);
const auto length =
(mouse_change.y * mouse_change.y) + (mouse_change.x * mouse_change.x);
mouse_panning_timout = 0; mouse_panning_timout = 0;
if (info.data.pressed || length < 4) { if (mouse_change.y == 0 && mouse_change.x == 0) {
continue; continue;
} }
info.last_mouse_change = (info.last_mouse_change * 0.8f) + (mouse_change * 0.2f); info.last_mouse_change = (info.last_mouse_change * 0.8f) + (mouse_change * 0.2f);
info.data.axis = {static_cast<int>(12 * info.last_mouse_change.x), info.data.axis = {static_cast<int>(16 * info.last_mouse_change.x),
static_cast<int>(12 * -info.last_mouse_change.y)}; static_cast<int>(16 * -info.last_mouse_change.y)};
info.tilt_direction = info.last_mouse_change; info.tilt_direction = info.last_mouse_change;
info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity;
continue; continue;

View file

@ -96,7 +96,7 @@ constexpr std::array<FormatTuple, MaxPixelFormat> FORMAT_TABLE = {{
{GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UFLOAT {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UFLOAT
{GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SFLOAT {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SFLOAT
{GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4_UNORM {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4_UNORM
{GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM
{GL_RGBA32F, GL_RGBA, GL_FLOAT}, // R32G32B32A32_FLOAT {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // R32G32B32A32_FLOAT
{GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, // R32G32B32A32_SINT {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, // R32G32B32A32_SINT
{GL_RG32F, GL_RG, GL_FLOAT}, // R32G32_FLOAT {GL_RG32F, GL_RG, GL_FLOAT}, // R32G32_FLOAT
@ -125,7 +125,7 @@ constexpr std::array<FormatTuple, MaxPixelFormat> FORMAT_TABLE = {{
{GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8_UNORM {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8_UNORM
{GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5_UNORM {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5_UNORM
{GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4_UNORM {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4_UNORM
{GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE}, // B8G8R8A8_SRGB
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // BC1_RGBA_SRGB {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // BC1_RGBA_SRGB
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // BC2_SRGB {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // BC2_SRGB
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB
@ -396,6 +396,18 @@ void AttachTexture(GLuint fbo, GLenum attachment, const ImageView* image_view) {
} }
} }
[[nodiscard]] bool IsPixelFormatBGRA(PixelFormat format) {
switch (format) {
case PixelFormat::B5G6R5_UNORM:
case PixelFormat::B10G11R11_FLOAT:
case PixelFormat::B8G8R8A8_UNORM:
case PixelFormat::B8G8R8A8_SRGB:
return true;
default:
return false;
}
}
} // Anonymous namespace } // Anonymous namespace
ImageBufferMap::~ImageBufferMap() { ImageBufferMap::~ImageBufferMap() {
@ -944,7 +956,12 @@ void ImageView::SetupView(const Device& device, Image& image, ImageViewType view
glTextureView(handle, target, parent, internal_format, view_range.base.level, glTextureView(handle, target, parent, internal_format, view_range.base.level,
view_range.extent.levels, view_range.base.layer, view_range.extent.layers); view_range.extent.levels, view_range.base.layer, view_range.extent.layers);
if (!info.IsRenderTarget()) { if (!info.IsRenderTarget()) {
ApplySwizzle(handle, format, info.Swizzle()); auto swizzle = info.Swizzle();
if (IsPixelFormatBGRA(image.info.format)) {
// Swap the R and B channels of the swizzle.
std::swap(swizzle[0], swizzle[2]);
}
ApplySwizzle(handle, format, swizzle);
} }
} }
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {

View file

@ -126,7 +126,7 @@ public:
/// Create the original context that should be shared from /// Create the original context that should be shared from
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
QSurfaceFormat format; QSurfaceFormat format;
format.setVersion(4, 3); format.setVersion(4, 6);
format.setProfile(QSurfaceFormat::CompatibilityProfile); format.setProfile(QSurfaceFormat::CompatibilityProfile);
format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions);
if (Settings::values.renderer_debug) { if (Settings::values.renderer_debug) {
@ -656,10 +656,10 @@ bool GRenderWindow::LoadOpenGL() {
const QString renderer = const QString renderer =
QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER))); QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
if (!GLAD_GL_VERSION_4_3) { if (!GLAD_GL_VERSION_4_6) {
LOG_ERROR(Frontend, "GPU does not support OpenGL 4.3: {}", renderer.toStdString()); LOG_ERROR(Frontend, "GPU does not support OpenGL 4.6: {}", renderer.toStdString());
QMessageBox::warning(this, tr("Error while initializing OpenGL 4.3!"), QMessageBox::warning(this, tr("Error while initializing OpenGL 4.6!"),
tr("Your GPU may not support OpenGL 4.3, or you do not have the " tr("Your GPU may not support OpenGL 4.6, or you do not have the "
"latest graphics driver.<br><br>GL Renderer:<br>%1") "latest graphics driver.<br><br>GL Renderer:<br>%1")
.arg(renderer)); .arg(renderer));
return false; return false;
@ -682,26 +682,13 @@ bool GRenderWindow::LoadOpenGL() {
QStringList GRenderWindow::GetUnsupportedGLExtensions() const { QStringList GRenderWindow::GetUnsupportedGLExtensions() const {
QStringList unsupported_ext; QStringList unsupported_ext;
if (!GLAD_GL_ARB_buffer_storage)
unsupported_ext.append(QStringLiteral("ARB_buffer_storage"));
if (!GLAD_GL_ARB_direct_state_access)
unsupported_ext.append(QStringLiteral("ARB_direct_state_access"));
if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
unsupported_ext.append(QStringLiteral("ARB_vertex_type_10f_11f_11f_rev"));
if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
unsupported_ext.append(QStringLiteral("ARB_texture_mirror_clamp_to_edge"));
if (!GLAD_GL_ARB_multi_bind)
unsupported_ext.append(QStringLiteral("ARB_multi_bind"));
if (!GLAD_GL_ARB_clip_control)
unsupported_ext.append(QStringLiteral("ARB_clip_control"));
// Extensions required to support some texture formats. // Extensions required to support some texture formats.
if (!GLAD_GL_EXT_texture_compression_s3tc) if (!GLAD_GL_EXT_texture_compression_s3tc) {
unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc")); unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc"));
if (!GLAD_GL_ARB_texture_compression_rgtc) }
if (!GLAD_GL_ARB_texture_compression_rgtc) {
unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc")); unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc"));
if (!GLAD_GL_ARB_depth_buffer_float) }
unsupported_ext.append(QStringLiteral("ARB_depth_buffer_float"));
if (!unsupported_ext.empty()) { if (!unsupported_ext.empty()) {
LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", LOG_ERROR(Frontend, "GPU does not support all required extensions: {}",

View file

@ -59,29 +59,17 @@ private:
bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
std::vector<std::string_view> unsupported_ext; std::vector<std::string_view> unsupported_ext;
if (!GLAD_GL_ARB_buffer_storage)
unsupported_ext.push_back("ARB_buffer_storage");
if (!GLAD_GL_ARB_direct_state_access)
unsupported_ext.push_back("ARB_direct_state_access");
if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev");
if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
if (!GLAD_GL_ARB_multi_bind)
unsupported_ext.push_back("ARB_multi_bind");
if (!GLAD_GL_ARB_clip_control)
unsupported_ext.push_back("ARB_clip_control");
// Extensions required to support some texture formats. // Extensions required to support some texture formats.
if (!GLAD_GL_EXT_texture_compression_s3tc) if (!GLAD_GL_EXT_texture_compression_s3tc) {
unsupported_ext.push_back("EXT_texture_compression_s3tc"); unsupported_ext.push_back("EXT_texture_compression_s3tc");
if (!GLAD_GL_ARB_texture_compression_rgtc) }
if (!GLAD_GL_ARB_texture_compression_rgtc) {
unsupported_ext.push_back("ARB_texture_compression_rgtc"); unsupported_ext.push_back("ARB_texture_compression_rgtc");
if (!GLAD_GL_ARB_depth_buffer_float) }
unsupported_ext.push_back("ARB_depth_buffer_float");
for (const auto& extension : unsupported_ext) for (const auto& extension : unsupported_ext) {
LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension); LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension);
}
return unsupported_ext.empty(); return unsupported_ext.empty();
} }
@ -89,7 +77,7 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen)
: EmuWindow_SDL2{input_subsystem} { : EmuWindow_SDL2{input_subsystem} {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);