early-access version 1424
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 1423. | ||||
| This is the source code for early-access 1424. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
| @@ -374,7 +374,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t | ||||
|     // Get the thread from its handle. | ||||
|     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||||
|     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. | ||||
|     *out_thread_id = thread->GetThreadID(); | ||||
| @@ -484,7 +487,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand | ||||
|     // Get the thread from its handle. | ||||
|     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||||
|     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. | ||||
|     thread->WaitCancel(); | ||||
| @@ -502,8 +508,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd | ||||
|               thread_handle, address, tag); | ||||
|  | ||||
|     // Validate the input address. | ||||
|     R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | ||||
|     R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); | ||||
|     if (Memory::IsKernelAddress(address)) { | ||||
|         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); | ||||
| } | ||||
| @@ -518,8 +531,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) { | ||||
|     LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); | ||||
|  | ||||
|     // Validate the input address. | ||||
|     R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | ||||
|     R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); | ||||
|     if (Memory::IsKernelAddress(address)) { | ||||
|         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); | ||||
| } | ||||
| @@ -1031,37 +1052,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 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 | ||||
| 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, | ||||
|               thread_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. | ||||
|     auto& kernel = system.Kernel(); | ||||
|     const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||||
|     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. | ||||
|     R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle); | ||||
|     R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy); | ||||
|     if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { | ||||
|         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. | ||||
|     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; | ||||
| } | ||||
| @@ -1080,16 +1111,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand | ||||
|     const auto* current_process = system.Kernel().CurrentProcess(); | ||||
|     const std::shared_ptr<KThread> thread = | ||||
|         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. | ||||
|     R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); | ||||
|     R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), | ||||
|              Svc::ResultBusy); | ||||
|     if (thread->GetOwnerProcess() != current_process) { | ||||
|         LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); | ||||
|         return ResultInvalidHandle; | ||||
|     } | ||||
|     if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { | ||||
|         LOG_ERROR(Kernel_SVC, "Current thread is busy."); | ||||
|         return ResultBusy; | ||||
|     } | ||||
|  | ||||
|     // Get the thread 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. | ||||
|     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. | ||||
|     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||||
|     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. | ||||
|     *out_priority = thread->GetPriority(); | ||||
| @@ -1124,13 +1171,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri | ||||
|     LOG_TRACE(Kernel_SVC, "called"); | ||||
|  | ||||
|     // Validate the priority. | ||||
|     R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, | ||||
|              Svc::ResultInvalidPriority); | ||||
|     if (HighestThreadPriority > priority || priority > LowestThreadPriority) { | ||||
|         LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); | ||||
|         return ResultInvalidPriority; | ||||
|     } | ||||
|  | ||||
|     // Get the thread from its handle. | ||||
|     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||||
|     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. | ||||
|     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. | ||||
|     auto& kernel = system.Kernel(); | ||||
|     auto& process = *kernel.CurrentProcess(); | ||||
|     if (core_id == Svc::IdealCoreUseProcessValue) { | ||||
|     if (core_id == IdealCoreUseProcessValue) { | ||||
|         core_id = process.GetIdealCoreId(); | ||||
|     } | ||||
|  | ||||
|     // Validate arguments. | ||||
|     R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); | ||||
|     R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); | ||||
|     if (!IsValidCoreId(core_id)) { | ||||
|         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, | ||||
|              Svc::ResultInvalidPriority); | ||||
|     R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); | ||||
|     if (HighestThreadPriority > priority || priority > LowestThreadPriority) { | ||||
|         LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority); | ||||
|         return ResultInvalidPriority; | ||||
|     } | ||||
|     if (!process.CheckThreadPriority(priority)) { | ||||
|         LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority); | ||||
|         return ResultInvalidPriority; | ||||
|     } | ||||
|  | ||||
|     KScopedResourceReservation thread_reservation( | ||||
|         kernel.CurrentProcess(), LimitableResource::Threads, 1, | ||||
| @@ -1501,10 +1564,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { | ||||
|     // Get the thread from its handle. | ||||
|     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||||
|     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. | ||||
|     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; | ||||
| } | ||||
| @@ -1565,8 +1637,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address, | ||||
|               cv_key, tag, timeout_ns); | ||||
|  | ||||
|     // Validate input. | ||||
|     R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | ||||
|     R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); | ||||
|     if (Memory::IsKernelAddress(address)) { | ||||
|         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. | ||||
|     s64 timeout{}; | ||||
| @@ -1641,9 +1719,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit | ||||
|               address, arb_type, value, timeout_ns); | ||||
|  | ||||
|     // Validate input. | ||||
|     R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | ||||
|     R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); | ||||
|     R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue); | ||||
|     if (Memory::IsKernelAddress(address)) { | ||||
|         LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address); | ||||
|         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. | ||||
|     s64 timeout{}; | ||||
| @@ -1677,9 +1764,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign | ||||
|               address, signal_type, value, count); | ||||
|  | ||||
|     // Validate input. | ||||
|     R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); | ||||
|     R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress); | ||||
|     R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue); | ||||
|     if (Memory::IsKernelAddress(address)) { | ||||
|         LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address); | ||||
|         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, | ||||
|                                                                   count); | ||||
| @@ -1835,10 +1931,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, | ||||
|     // Get the thread from its handle. | ||||
|     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||||
|     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. | ||||
|     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; | ||||
| } | ||||
| @@ -1866,26 +1969,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, | ||||
|     } else { | ||||
|         // Validate the affinity mask. | ||||
|         const u64 process_core_mask = current_process.GetCoreMask(); | ||||
|         R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, | ||||
|                  Svc::ResultInvalidCoreId); | ||||
|         R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); | ||||
|         if ((affinity_mask | process_core_mask) != process_core_mask) { | ||||
|             LOG_ERROR(Kernel_SVC, | ||||
|                       "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. | ||||
|         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 { | ||||
|             R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, | ||||
|                      Svc::ResultInvalidCoreId); | ||||
|             if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { | ||||
|                 LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); | ||||
|                 return ResultInvalidCoreId; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Get the thread from its handle. | ||||
|     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||||
|     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. | ||||
|     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; | ||||
| } | ||||
| @@ -1913,7 +2036,10 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) { | ||||
|  | ||||
|     // Get the writable event. | ||||
|     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. | ||||
|     event_reservation.Commit(); | ||||
| @@ -1965,7 +2091,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o | ||||
|  | ||||
|     // Create a new event. | ||||
|     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. | ||||
|     event->Initialize(); | ||||
|   | ||||
| @@ -37,7 +37,7 @@ void Mouse::UpdateThread() { | ||||
|         if (configuring) { | ||||
|             UpdateYuzuSettings(); | ||||
|         } | ||||
|         if (mouse_panning_timout++ > 12) { | ||||
|         if (mouse_panning_timout++ > 8) { | ||||
|             StopPanning(); | ||||
|         } | ||||
|         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() { | ||||
|     for (MouseInfo& info : mouse_info) { | ||||
|         if (Settings::values.mouse_panning) { | ||||
|             if (info.data.pressed) { | ||||
|                 continue; | ||||
|             } | ||||
|             info.data.axis = {0, 0}; | ||||
|             info.data.axis = {}; | ||||
|             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) { | ||||
|         if (Settings::values.mouse_panning) { | ||||
|             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; | ||||
|  | ||||
|             if (info.data.pressed || length < 4) { | ||||
|             if (mouse_change.y == 0 && mouse_change.x == 0) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             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), | ||||
|                               static_cast<int>(12 * -info.last_mouse_change.y)}; | ||||
|             info.data.axis = {static_cast<int>(16 * info.last_mouse_change.x), | ||||
|                               static_cast<int>(16 * -info.last_mouse_change.y)}; | ||||
|             info.tilt_direction = info.last_mouse_change; | ||||
|             info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; | ||||
|             continue; | ||||
|   | ||||
| @@ -96,7 +96,7 @@ constexpr std::array<FormatTuple, MaxPixelFormat> FORMAT_TABLE = {{ | ||||
|     {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT},                          // BC6H_UFLOAT | ||||
|     {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT},                            // BC6H_SFLOAT | ||||
|     {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_RGBA32I, GL_RGBA_INTEGER, GL_INT},                            // R32G32B32A32_SINT | ||||
|     {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_8x5_KHR},                                // ASTC_2D_8X5_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_DXT3_EXT},                         // BC2_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 | ||||
|  | ||||
| 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, | ||||
|                       view_range.extent.levels, view_range.base.layer, view_range.extent.layers); | ||||
|         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()) { | ||||
|   | ||||
| @@ -126,7 +126,7 @@ public: | ||||
|     /// Create the original context that should be shared from | ||||
|     explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { | ||||
|         QSurfaceFormat format; | ||||
|         format.setVersion(4, 3); | ||||
|         format.setVersion(4, 6); | ||||
|         format.setProfile(QSurfaceFormat::CompatibilityProfile); | ||||
|         format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); | ||||
|         if (Settings::values.renderer_debug) { | ||||
| @@ -656,10 +656,10 @@ bool GRenderWindow::LoadOpenGL() { | ||||
|     const QString renderer = | ||||
|         QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER))); | ||||
|  | ||||
|     if (!GLAD_GL_VERSION_4_3) { | ||||
|         LOG_ERROR(Frontend, "GPU does not support OpenGL 4.3: {}", renderer.toStdString()); | ||||
|         QMessageBox::warning(this, tr("Error while initializing OpenGL 4.3!"), | ||||
|                              tr("Your GPU may not support OpenGL 4.3, or you do not have the " | ||||
|     if (!GLAD_GL_VERSION_4_6) { | ||||
|         LOG_ERROR(Frontend, "GPU does not support OpenGL 4.6: {}", renderer.toStdString()); | ||||
|         QMessageBox::warning(this, tr("Error while initializing OpenGL 4.6!"), | ||||
|                              tr("Your GPU may not support OpenGL 4.6, or you do not have the " | ||||
|                                 "latest graphics driver.<br><br>GL Renderer:<br>%1") | ||||
|                                  .arg(renderer)); | ||||
|         return false; | ||||
| @@ -682,26 +682,13 @@ bool GRenderWindow::LoadOpenGL() { | ||||
| QStringList GRenderWindow::GetUnsupportedGLExtensions() const { | ||||
|     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. | ||||
|     if (!GLAD_GL_EXT_texture_compression_s3tc) | ||||
|     if (!GLAD_GL_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")); | ||||
|     if (!GLAD_GL_ARB_depth_buffer_float) | ||||
|         unsupported_ext.append(QStringLiteral("ARB_depth_buffer_float")); | ||||
|     } | ||||
|  | ||||
|     if (!unsupported_ext.empty()) { | ||||
|         LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", | ||||
|   | ||||
| @@ -59,29 +59,17 @@ private: | ||||
| bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | ||||
|     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. | ||||
|     if (!GLAD_GL_EXT_texture_compression_s3tc) | ||||
|     if (!GLAD_GL_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"); | ||||
|     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); | ||||
|     } | ||||
|  | ||||
|     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{input_subsystem} { | ||||
|     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_DOUBLEBUFFER, 1); | ||||
|     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user