diff options
Diffstat (limited to 'src')
24 files changed, 204 insertions, 104 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 40a610435..d8934be52 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -137,6 +137,7 @@ struct System::Impl { | |||
| 137 | device_memory = std::make_unique<Core::DeviceMemory>(); | 137 | device_memory = std::make_unique<Core::DeviceMemory>(); |
| 138 | 138 | ||
| 139 | is_multicore = Settings::values.use_multi_core.GetValue(); | 139 | is_multicore = Settings::values.use_multi_core.GetValue(); |
| 140 | extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue(); | ||
| 140 | 141 | ||
| 141 | core_timing.SetMulticore(is_multicore); | 142 | core_timing.SetMulticore(is_multicore); |
| 142 | core_timing.Initialize([&system]() { system.RegisterHostThread(); }); | 143 | core_timing.Initialize([&system]() { system.RegisterHostThread(); }); |
| @@ -166,13 +167,18 @@ struct System::Impl { | |||
| 166 | } | 167 | } |
| 167 | 168 | ||
| 168 | void ReinitializeIfNecessary(System& system) { | 169 | void ReinitializeIfNecessary(System& system) { |
| 169 | if (is_multicore == Settings::values.use_multi_core.GetValue()) { | 170 | const bool must_reinitialize = |
| 171 | is_multicore != Settings::values.use_multi_core.GetValue() || | ||
| 172 | extended_memory_layout != Settings::values.use_extended_memory_layout.GetValue(); | ||
| 173 | |||
| 174 | if (!must_reinitialize) { | ||
| 170 | return; | 175 | return; |
| 171 | } | 176 | } |
| 172 | 177 | ||
| 173 | LOG_DEBUG(Kernel, "Re-initializing"); | 178 | LOG_DEBUG(Kernel, "Re-initializing"); |
| 174 | 179 | ||
| 175 | is_multicore = Settings::values.use_multi_core.GetValue(); | 180 | is_multicore = Settings::values.use_multi_core.GetValue(); |
| 181 | extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue(); | ||
| 176 | 182 | ||
| 177 | Initialize(system); | 183 | Initialize(system); |
| 178 | } | 184 | } |
| @@ -521,6 +527,7 @@ struct System::Impl { | |||
| 521 | 527 | ||
| 522 | bool is_multicore{}; | 528 | bool is_multicore{}; |
| 523 | bool is_async_gpu{}; | 529 | bool is_async_gpu{}; |
| 530 | bool extended_memory_layout{}; | ||
| 524 | 531 | ||
| 525 | ExecuteProgramCallback execute_program_callback; | 532 | ExecuteProgramCallback execute_program_callback; |
| 526 | ExitCallback exit_callback; | 533 | ExitCallback exit_callback; |
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 32135473b..188aef4af 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h | |||
| @@ -91,7 +91,7 @@ private: | |||
| 91 | 91 | ||
| 92 | /// List of threads which are pending a reply. | 92 | /// List of threads which are pending a reply. |
| 93 | boost::intrusive::list<KSessionRequest> m_request_list; | 93 | boost::intrusive::list<KSessionRequest> m_request_list; |
| 94 | KSessionRequest* m_current_request; | 94 | KSessionRequest* m_current_request{}; |
| 95 | 95 | ||
| 96 | KLightLock m_lock; | 96 | KLightLock m_lock; |
| 97 | }; | 97 | }; |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index d57b42fdf..cc88d08f0 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -1185,8 +1185,10 @@ void KThread::RequestDummyThreadWait() { | |||
| 1185 | } | 1185 | } |
| 1186 | 1186 | ||
| 1187 | void KThread::DummyThreadBeginWait() { | 1187 | void KThread::DummyThreadBeginWait() { |
| 1188 | ASSERT(this->IsDummyThread()); | 1188 | if (!this->IsDummyThread() || kernel.IsPhantomModeForSingleCore()) { |
| 1189 | ASSERT(!kernel.IsPhantomModeForSingleCore()); | 1189 | // Occurs in single core mode. |
| 1190 | return; | ||
| 1191 | } | ||
| 1190 | 1192 | ||
| 1191 | // Block until runnable is no longer false. | 1193 | // Block until runnable is no longer false. |
| 1192 | dummy_thread_runnable.wait(false); | 1194 | dummy_thread_runnable.wait(false); |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index e55233054..8ea7fd760 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -299,7 +299,7 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv | |||
| 299 | {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, | 299 | {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, |
| 300 | {110, nullptr, "SetApplicationAlbumUserData"}, | 300 | {110, nullptr, "SetApplicationAlbumUserData"}, |
| 301 | {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, | 301 | {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, |
| 302 | {130, nullptr, "SetRecordVolumeMuted"}, | 302 | {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"}, |
| 303 | {1000, nullptr, "GetDebugStorageChannel"}, | 303 | {1000, nullptr, "GetDebugStorageChannel"}, |
| 304 | }; | 304 | }; |
| 305 | // clang-format on | 305 | // clang-format on |
| @@ -597,6 +597,17 @@ void ISelfController::SaveCurrentScreenshot(Kernel::HLERequestContext& ctx) { | |||
| 597 | rb.Push(ResultSuccess); | 597 | rb.Push(ResultSuccess); |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | void ISelfController::SetRecordVolumeMuted(Kernel::HLERequestContext& ctx) { | ||
| 601 | IPC::RequestParser rp{ctx}; | ||
| 602 | |||
| 603 | const auto is_record_volume_muted = rp.Pop<bool>(); | ||
| 604 | |||
| 605 | LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); | ||
| 606 | |||
| 607 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 608 | rb.Push(ResultSuccess); | ||
| 609 | } | ||
| 610 | |||
| 600 | AppletMessageQueue::AppletMessageQueue(Core::System& system) | 611 | AppletMessageQueue::AppletMessageQueue(Core::System& system) |
| 601 | : service_context{system, "AppletMessageQueue"} { | 612 | : service_context{system, "AppletMessageQueue"} { |
| 602 | on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); | 613 | on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index bb75c6281..a0fbfcfc5 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -182,6 +182,7 @@ private: | |||
| 182 | void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); | 182 | void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); |
| 183 | void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx); | 183 | void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx); |
| 184 | void SaveCurrentScreenshot(Kernel::HLERequestContext& ctx); | 184 | void SaveCurrentScreenshot(Kernel::HLERequestContext& ctx); |
| 185 | void SetRecordVolumeMuted(Kernel::HLERequestContext& ctx); | ||
| 185 | 186 | ||
| 186 | enum class ScreenshotPermission : u32 { | 187 | enum class ScreenshotPermission : u32 { |
| 187 | Inherit = 0, | 188 | Inherit = 0, |
diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index fbd8a74a5..a51ca5444 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp | |||
| @@ -255,15 +255,16 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna | |||
| 255 | .address = handle_description->address, | 255 | .address = handle_description->address, |
| 256 | .size = handle_description->size, | 256 | .size = handle_description->size, |
| 257 | .was_uncached = handle_description->flags.map_uncached.Value() != 0, | 257 | .was_uncached = handle_description->flags.map_uncached.Value() != 0, |
| 258 | .can_unlock = true, | ||
| 258 | }; | 259 | }; |
| 259 | } else { | 260 | } else { |
| 260 | return std::nullopt; | 261 | return std::nullopt; |
| 261 | } | 262 | } |
| 262 | 263 | ||
| 263 | // Handle hasn't been freed from memory, set address to 0 to mark that the handle wasn't freed | 264 | // If the handle hasn't been freed from memory, mark that |
| 264 | if (!hWeak.expired()) { | 265 | if (!hWeak.expired()) { |
| 265 | LOG_DEBUG(Service_NVDRV, "nvmap handle: {} wasn't freed as it is still in use", handle); | 266 | LOG_DEBUG(Service_NVDRV, "nvmap handle: {} wasn't freed as it is still in use", handle); |
| 266 | freeInfo.address = 0; | 267 | freeInfo.can_unlock = false; |
| 267 | } | 268 | } |
| 268 | 269 | ||
| 269 | return freeInfo; | 270 | return freeInfo; |
diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index b9dd3801f..a8e573890 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h | |||
| @@ -105,6 +105,7 @@ public: | |||
| 105 | u64 address; //!< Address the handle referred to before deletion | 105 | u64 address; //!< Address the handle referred to before deletion |
| 106 | u64 size; //!< Page-aligned handle size | 106 | u64 size; //!< Page-aligned handle size |
| 107 | bool was_uncached; //!< If the handle was allocated as uncached | 107 | bool was_uncached; //!< If the handle was allocated as uncached |
| 108 | bool can_unlock; //!< If the address region is ready to be unlocked | ||
| 108 | }; | 109 | }; |
| 109 | 110 | ||
| 110 | explicit NvMap(Tegra::Host1x::Host1x& host1x); | 111 | explicit NvMap(Tegra::Host1x::Host1x& host1x); |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index b60679021..44388655d 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -251,10 +251,12 @@ NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | if (auto freeInfo{file.FreeHandle(params.handle, false)}) { | 253 | if (auto freeInfo{file.FreeHandle(params.handle, false)}) { |
| 254 | ASSERT(system.CurrentProcess() | 254 | if (freeInfo->can_unlock) { |
| 255 | ->PageTable() | 255 | ASSERT(system.CurrentProcess() |
| 256 | .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) | 256 | ->PageTable() |
| 257 | .IsSuccess()); | 257 | .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) |
| 258 | .IsSuccess()); | ||
| 259 | } | ||
| 258 | params.address = freeInfo->address; | 260 | params.address = freeInfo->address; |
| 259 | params.size = static_cast<u32>(freeInfo->size); | 261 | params.size = static_cast<u32>(freeInfo->size); |
| 260 | params.flags.raw = 0; | 262 | params.flags.raw = 0; |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 77ddbb6ef..41ba44b21 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp | |||
| @@ -742,6 +742,13 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) { | |||
| 742 | return Status::NoError; | 742 | return Status::NoError; |
| 743 | } | 743 | } |
| 744 | 744 | ||
| 745 | // HACK: We are not Android. Remove handle for items in queue, and clear queue. | ||
| 746 | // Allows synchronous destruction of nvmap handles. | ||
| 747 | for (auto& item : core->queue) { | ||
| 748 | nvmap.FreeHandle(item.graphic_buffer->BufferId(), true); | ||
| 749 | } | ||
| 750 | core->queue.clear(); | ||
| 751 | |||
| 745 | switch (api) { | 752 | switch (api) { |
| 746 | case NativeWindowApi::Egl: | 753 | case NativeWindowApi::Egl: |
| 747 | case NativeWindowApi::Cpu: | 754 | case NativeWindowApi::Cpu: |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index dad93b38e..c3af12c90 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -138,6 +138,19 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { | |||
| 138 | return itr->GetID(); | 138 | return itr->GetID(); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | bool NVFlinger::CloseDisplay(u64 display_id) { | ||
| 142 | const auto lock_guard = Lock(); | ||
| 143 | auto* const display = FindDisplay(display_id); | ||
| 144 | |||
| 145 | if (display == nullptr) { | ||
| 146 | return false; | ||
| 147 | } | ||
| 148 | |||
| 149 | display->Reset(); | ||
| 150 | |||
| 151 | return true; | ||
| 152 | } | ||
| 153 | |||
| 141 | std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { | 154 | std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { |
| 142 | const auto lock_guard = Lock(); | 155 | const auto lock_guard = Lock(); |
| 143 | auto* const display = FindDisplay(display_id); | 156 | auto* const display = FindDisplay(display_id); |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index b8191c595..460bef976 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -58,6 +58,11 @@ public: | |||
| 58 | /// If an invalid display name is provided, then an empty optional is returned. | 58 | /// If an invalid display name is provided, then an empty optional is returned. |
| 59 | [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name); | 59 | [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name); |
| 60 | 60 | ||
| 61 | /// Closes the specified display by its ID. | ||
| 62 | /// | ||
| 63 | /// Returns false if an invalid display ID is provided. | ||
| 64 | [[nodiscard]] bool CloseDisplay(u64 display_id); | ||
| 65 | |||
| 61 | /// Creates a layer on the specified display and returns the layer ID. | 66 | /// Creates a layer on the specified display and returns the layer ID. |
| 62 | /// | 67 | /// |
| 63 | /// If an invalid display ID is specified, then an empty optional is returned. | 68 | /// If an invalid display ID is specified, then an empty optional is returned. |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 48e70f93c..cb6c0e96f 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -80,7 +80,6 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | auto* port = Kernel::KPort::Create(kernel); | 82 | auto* port = Kernel::KPort::Create(kernel); |
| 83 | SCOPE_EXIT({ port->Close(); }); | ||
| 84 | 83 | ||
| 85 | port->Initialize(ServerSessionCountMax, false, name); | 84 | port->Initialize(ServerSessionCountMax, false, name); |
| 86 | auto handler = it->second; | 85 | auto handler = it->second; |
| @@ -150,9 +149,10 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& | |||
| 150 | return port_result.Code(); | 149 | return port_result.Code(); |
| 151 | } | 150 | } |
| 152 | auto& port = port_result.Unwrap(); | 151 | auto& port = port_result.Unwrap(); |
| 153 | SCOPE_EXIT({ port->GetClientPort().Close(); }); | 152 | SCOPE_EXIT({ |
| 154 | 153 | port->GetClientPort().Close(); | |
| 155 | kernel.RegisterServerObject(&port->GetServerPort()); | 154 | port->GetServerPort().Close(); |
| 155 | }); | ||
| 156 | 156 | ||
| 157 | // Create a new session. | 157 | // Create a new session. |
| 158 | Kernel::KClientSession* session{}; | 158 | Kernel::KClientSession* session{}; |
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp index 273f79568..46a8439d8 100644 --- a/src/core/hle/service/sm/sm_controller.cpp +++ b/src/core/hle/service/sm/sm_controller.cpp | |||
| @@ -28,23 +28,36 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { | |||
| 28 | void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { | 28 | void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { |
| 29 | LOG_DEBUG(Service, "called"); | 29 | LOG_DEBUG(Service, "called"); |
| 30 | 30 | ||
| 31 | auto& process = *ctx.GetThread().GetOwnerProcess(); | ||
| 31 | auto& parent_session = *ctx.Session()->GetParent(); | 32 | auto& parent_session = *ctx.Session()->GetParent(); |
| 32 | auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort(); | ||
| 33 | auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager(); | 33 | auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager(); |
| 34 | auto& session_handler = session_manager->SessionHandler(); | ||
| 34 | 35 | ||
| 35 | // Create a session. | 36 | // FIXME: this is duplicated from the SVC, it should just call it instead |
| 36 | Kernel::KClientSession* session{}; | 37 | // once this is a proper process |
| 37 | const Result result = parent_port.CreateSession(std::addressof(session), session_manager); | 38 | |
| 38 | if (result.IsError()) { | 39 | // Reserve a new session from the process resource limit. |
| 39 | LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw); | 40 | Kernel::KScopedResourceReservation session_reservation(&process, |
| 40 | IPC::ResponseBuilder rb{ctx, 2}; | 41 | Kernel::LimitableResource::Sessions); |
| 41 | rb.Push(result); | 42 | ASSERT(session_reservation.Succeeded()); |
| 42 | } | 43 | |
| 44 | // Create the session. | ||
| 45 | Kernel::KSession* session = Kernel::KSession::Create(system.Kernel()); | ||
| 46 | ASSERT(session != nullptr); | ||
| 47 | |||
| 48 | // Initialize the session. | ||
| 49 | session->Initialize(nullptr, parent_session.GetName(), session_manager); | ||
| 50 | |||
| 51 | // Commit the session reservation. | ||
| 52 | session_reservation.Commit(); | ||
| 53 | |||
| 54 | // Register the session. | ||
| 55 | session_handler.ClientConnected(&session->GetServerSession()); | ||
| 43 | 56 | ||
| 44 | // We succeeded. | 57 | // We succeeded. |
| 45 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 58 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
| 46 | rb.Push(ResultSuccess); | 59 | rb.Push(ResultSuccess); |
| 47 | rb.PushMoveObjects(session); | 60 | rb.PushMoveObjects(session->GetClientSession()); |
| 48 | } | 61 | } |
| 49 | 62 | ||
| 50 | void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { | 63 | void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 33d5f398c..0b65a65da 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h | |||
| @@ -106,6 +106,12 @@ public: | |||
| 106 | /// | 106 | /// |
| 107 | void CloseLayer(u64 layer_id); | 107 | void CloseLayer(u64 layer_id); |
| 108 | 108 | ||
| 109 | /// Resets the display for a new connection. | ||
| 110 | void Reset() { | ||
| 111 | layers.clear(); | ||
| 112 | got_vsync_event = false; | ||
| 113 | } | ||
| 114 | |||
| 109 | /// Attempts to find a layer with the given ID. | 115 | /// Attempts to find a layer with the given ID. |
| 110 | /// | 116 | /// |
| 111 | /// @param layer_id The layer ID. | 117 | /// @param layer_id The layer ID. |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 9c917cacf..bb283e74e 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -324,10 +324,10 @@ private: | |||
| 324 | IPC::RequestParser rp{ctx}; | 324 | IPC::RequestParser rp{ctx}; |
| 325 | const u64 display = rp.Pop<u64>(); | 325 | const u64 display = rp.Pop<u64>(); |
| 326 | 326 | ||
| 327 | LOG_WARNING(Service_VI, "(STUBBED) called. display=0x{:016X}", display); | 327 | const Result rc = nv_flinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; |
| 328 | 328 | ||
| 329 | IPC::ResponseBuilder rb{ctx, 2}; | 329 | IPC::ResponseBuilder rb{ctx, 2}; |
| 330 | rb.Push(ResultSuccess); | 330 | rb.Push(rc); |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | void CreateManagedLayer(Kernel::HLERequestContext& ctx) { | 333 | void CreateManagedLayer(Kernel::HLERequestContext& ctx) { |
| @@ -508,10 +508,10 @@ private: | |||
| 508 | IPC::RequestParser rp{ctx}; | 508 | IPC::RequestParser rp{ctx}; |
| 509 | const u64 display_id = rp.Pop<u64>(); | 509 | const u64 display_id = rp.Pop<u64>(); |
| 510 | 510 | ||
| 511 | LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); | 511 | const Result rc = nv_flinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; |
| 512 | 512 | ||
| 513 | IPC::ResponseBuilder rb{ctx, 2}; | 513 | IPC::ResponseBuilder rb{ctx, 2}; |
| 514 | rb.Push(ResultSuccess); | 514 | rb.Push(rc); |
| 515 | } | 515 | } |
| 516 | 516 | ||
| 517 | // This literally does nothing internally in the actual service itself, | 517 | // This literally does nothing internally in the actual service itself, |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 5208bea75..f9794dfe4 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -123,9 +123,6 @@ void Maxwell3D::InitializeRegisterDefaults() { | |||
| 123 | draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; | 123 | draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; |
| 124 | draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true; | 124 | draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true; |
| 125 | draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true; | 125 | draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true; |
| 126 | draw_command[MAXWELL3D_REG_INDEX(index_buffer32_first)] = true; | ||
| 127 | draw_command[MAXWELL3D_REG_INDEX(index_buffer16_first)] = true; | ||
| 128 | draw_command[MAXWELL3D_REG_INDEX(index_buffer8_first)] = true; | ||
| 129 | draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true; | 126 | draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true; |
| 130 | draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true; | 127 | draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true; |
| 131 | draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true; | 128 | draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true; |
| @@ -216,6 +213,21 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume | |||
| 216 | return ProcessCBBind(3); | 213 | return ProcessCBBind(3); |
| 217 | case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): | 214 | case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): |
| 218 | return ProcessCBBind(4); | 215 | return ProcessCBBind(4); |
| 216 | case MAXWELL3D_REG_INDEX(index_buffer32_first): | ||
| 217 | regs.index_buffer.count = regs.index_buffer32_first.count; | ||
| 218 | regs.index_buffer.first = regs.index_buffer32_first.first; | ||
| 219 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 220 | return ProcessDraw(); | ||
| 221 | case MAXWELL3D_REG_INDEX(index_buffer16_first): | ||
| 222 | regs.index_buffer.count = regs.index_buffer16_first.count; | ||
| 223 | regs.index_buffer.first = regs.index_buffer16_first.first; | ||
| 224 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 225 | return ProcessDraw(); | ||
| 226 | case MAXWELL3D_REG_INDEX(index_buffer8_first): | ||
| 227 | regs.index_buffer.count = regs.index_buffer8_first.count; | ||
| 228 | regs.index_buffer.first = regs.index_buffer8_first.first; | ||
| 229 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 230 | return ProcessDraw(); | ||
| 219 | case MAXWELL3D_REG_INDEX(topology_override): | 231 | case MAXWELL3D_REG_INDEX(topology_override): |
| 220 | use_topology_override = true; | 232 | use_topology_override = true; |
| 221 | return; | 233 | return; |
| @@ -583,6 +595,31 @@ void Maxwell3D::ProcessClearBuffers() { | |||
| 583 | rasterizer->Clear(); | 595 | rasterizer->Clear(); |
| 584 | } | 596 | } |
| 585 | 597 | ||
| 598 | void Maxwell3D::ProcessDraw(u32 instance_count) { | ||
| 599 | LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), | ||
| 600 | regs.vertex_buffer.count); | ||
| 601 | |||
| 602 | ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); | ||
| 603 | |||
| 604 | // Both instance configuration registers can not be set at the same time. | ||
| 605 | ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || | ||
| 606 | regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, | ||
| 607 | "Illegal combination of instancing parameters"); | ||
| 608 | |||
| 609 | ProcessTopologyOverride(); | ||
| 610 | |||
| 611 | const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count; | ||
| 612 | if (ShouldExecute()) { | ||
| 613 | rasterizer->Draw(is_indexed, instance_count); | ||
| 614 | } | ||
| 615 | |||
| 616 | if (is_indexed) { | ||
| 617 | regs.index_buffer.count = 0; | ||
| 618 | } else { | ||
| 619 | regs.vertex_buffer.count = 0; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 586 | void Maxwell3D::ProcessDeferredDraw() { | 623 | void Maxwell3D::ProcessDeferredDraw() { |
| 587 | if (deferred_draw_method.empty()) { | 624 | if (deferred_draw_method.empty()) { |
| 588 | return; | 625 | return; |
| @@ -596,23 +633,28 @@ void Maxwell3D::ProcessDeferredDraw() { | |||
| 596 | DrawMode draw_mode{DrawMode::Undefined}; | 633 | DrawMode draw_mode{DrawMode::Undefined}; |
| 597 | u32 instance_count = 1; | 634 | u32 instance_count = 1; |
| 598 | 635 | ||
| 599 | auto first_method = deferred_draw_method[0]; | 636 | u32 index = 0; |
| 600 | if (MAXWELL3D_REG_INDEX(draw.begin) == first_method) { | 637 | u32 method = 0; |
| 601 | // The minimum number of methods for drawing must be greater than or equal to | 638 | u32 method_count = static_cast<u32>(deferred_draw_method.size()); |
| 602 | // 3[draw.begin->vertex(index)count->draw.end] to avoid errors in index mode drawing | 639 | for (; index < method_count && |
| 603 | if (deferred_draw_method.size() < 3) { | 640 | (method = deferred_draw_method[index]) != MAXWELL3D_REG_INDEX(draw.begin); |
| 604 | return; | 641 | ++index) |
| 605 | } | 642 | ; |
| 606 | draw_mode = (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || | 643 | |
| 607 | (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) | 644 | if (MAXWELL3D_REG_INDEX(draw.begin) != method) { |
| 608 | ? DrawMode::Instance | 645 | return; |
| 609 | : DrawMode::General; | ||
| 610 | } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method || | ||
| 611 | MAXWELL3D_REG_INDEX(index_buffer16_first) == first_method || | ||
| 612 | MAXWELL3D_REG_INDEX(index_buffer8_first) == first_method) { | ||
| 613 | draw_mode = DrawMode::General; | ||
| 614 | } | 646 | } |
| 615 | 647 | ||
| 648 | // The minimum number of methods for drawing must be greater than or equal to | ||
| 649 | // 3[draw.begin->vertex(index)count(first)->draw.end] to avoid errors in index mode drawing | ||
| 650 | if ((method_count - index) < 3) { | ||
| 651 | return; | ||
| 652 | } | ||
| 653 | draw_mode = (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || | ||
| 654 | (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) | ||
| 655 | ? DrawMode::Instance | ||
| 656 | : DrawMode::General; | ||
| 657 | |||
| 616 | // Drawing will only begin with draw.begin or index_buffer method, other methods directly | 658 | // Drawing will only begin with draw.begin or index_buffer method, other methods directly |
| 617 | // clear | 659 | // clear |
| 618 | if (draw_mode == DrawMode::Undefined) { | 660 | if (draw_mode == DrawMode::Undefined) { |
| @@ -622,53 +664,18 @@ void Maxwell3D::ProcessDeferredDraw() { | |||
| 622 | 664 | ||
| 623 | if (draw_mode == DrawMode::Instance) { | 665 | if (draw_mode == DrawMode::Instance) { |
| 624 | ASSERT_MSG(deferred_draw_method.size() % 4 == 0, "Instance mode method size error"); | 666 | ASSERT_MSG(deferred_draw_method.size() % 4 == 0, "Instance mode method size error"); |
| 625 | instance_count = static_cast<u32>(deferred_draw_method.size()) / 4; | 667 | instance_count = static_cast<u32>(method_count - index) / 4; |
| 626 | } else { | 668 | } else { |
| 627 | if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { | 669 | method = deferred_draw_method[index + 1]; |
| 628 | regs.index_buffer.count = regs.index_buffer32_first.count; | 670 | if (MAXWELL3D_REG_INDEX(draw_inline_index) == method || |
| 629 | regs.index_buffer.first = regs.index_buffer32_first.first; | 671 | MAXWELL3D_REG_INDEX(inline_index_2x16.even) == method || |
| 630 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | 672 | MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == method) { |
| 631 | } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { | 673 | regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4); |
| 632 | regs.index_buffer.count = regs.index_buffer16_first.count; | 674 | regs.index_buffer.format = Regs::IndexFormat::UnsignedInt; |
| 633 | regs.index_buffer.first = regs.index_buffer16_first.first; | ||
| 634 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 635 | } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { | ||
| 636 | regs.index_buffer.count = regs.index_buffer8_first.count; | ||
| 637 | regs.index_buffer.first = regs.index_buffer8_first.first; | ||
| 638 | dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 639 | } else { | ||
| 640 | auto second_method = deferred_draw_method[1]; | ||
| 641 | if (MAXWELL3D_REG_INDEX(draw_inline_index) == second_method || | ||
| 642 | MAXWELL3D_REG_INDEX(inline_index_2x16.even) == second_method || | ||
| 643 | MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == second_method) { | ||
| 644 | regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4); | ||
| 645 | regs.index_buffer.format = Regs::IndexFormat::UnsignedInt; | ||
| 646 | } | ||
| 647 | } | 675 | } |
| 648 | } | 676 | } |
| 649 | 677 | ||
| 650 | LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), | 678 | ProcessDraw(instance_count); |
| 651 | regs.vertex_buffer.count); | ||
| 652 | |||
| 653 | ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); | ||
| 654 | |||
| 655 | // Both instance configuration registers can not be set at the same time. | ||
| 656 | ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || | ||
| 657 | regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, | ||
| 658 | "Illegal combination of instancing parameters"); | ||
| 659 | |||
| 660 | ProcessTopologyOverride(); | ||
| 661 | |||
| 662 | const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count; | ||
| 663 | if (ShouldExecute()) { | ||
| 664 | rasterizer->Draw(is_indexed, instance_count); | ||
| 665 | } | ||
| 666 | |||
| 667 | if (is_indexed) { | ||
| 668 | regs.index_buffer.count = 0; | ||
| 669 | } else { | ||
| 670 | regs.vertex_buffer.count = 0; | ||
| 671 | } | ||
| 672 | 679 | ||
| 673 | deferred_draw_method.clear(); | 680 | deferred_draw_method.clear(); |
| 674 | inline_index_draw_indexes.clear(); | 681 | inline_index_draw_indexes.clear(); |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index bd23ebc12..a948fcb14 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -3143,6 +3143,8 @@ private: | |||
| 3143 | /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro) | 3143 | /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro) |
| 3144 | void ProcessTopologyOverride(); | 3144 | void ProcessTopologyOverride(); |
| 3145 | 3145 | ||
| 3146 | void ProcessDraw(u32 instance_count = 1); | ||
| 3147 | |||
| 3146 | void ProcessDeferredDraw(); | 3148 | void ProcessDeferredDraw(); |
| 3147 | 3149 | ||
| 3148 | /// Returns a query's value or an empty object if the value will be deferred through a cache. | 3150 | /// Returns a query's value or an empty object if the value will be deferred through a cache. |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 9f05a7a18..6ab68892c 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -305,14 +305,19 @@ void RasterizerVulkan::Clear() { | |||
| 305 | } | 305 | } |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) { | 308 | if (regs.clear_surface.R && regs.clear_surface.G && regs.clear_surface.B && |
| 309 | const VkClearAttachment attachment{ | 309 | regs.clear_surface.A) { |
| 310 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | 310 | scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) { |
| 311 | .colorAttachment = color_attachment, | 311 | const VkClearAttachment attachment{ |
| 312 | .clearValue = clear_value, | 312 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, |
| 313 | }; | 313 | .colorAttachment = color_attachment, |
| 314 | cmdbuf.ClearAttachments(attachment, clear_rect); | 314 | .clearValue = clear_value, |
| 315 | }); | 315 | }; |
| 316 | cmdbuf.ClearAttachments(attachment, clear_rect); | ||
| 317 | }); | ||
| 318 | } else { | ||
| 319 | UNIMPLEMENTED_MSG("Unimplemented Clear only the specified channel"); | ||
| 320 | } | ||
| 316 | } | 321 | } |
| 317 | 322 | ||
| 318 | if (!use_depth && !use_stencil) { | 323 | if (!use_depth && !use_stencil) { |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 305ad8aee..6ad7efbdf 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -1782,17 +1782,17 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, | |||
| 1782 | 1782 | ||
| 1783 | const auto& resolution = runtime.resolution; | 1783 | const auto& resolution = runtime.resolution; |
| 1784 | 1784 | ||
| 1785 | u32 width = 0; | 1785 | u32 width = std::numeric_limits<u32>::max(); |
| 1786 | u32 height = 0; | 1786 | u32 height = std::numeric_limits<u32>::max(); |
| 1787 | for (size_t index = 0; index < NUM_RT; ++index) { | 1787 | for (size_t index = 0; index < NUM_RT; ++index) { |
| 1788 | const ImageView* const color_buffer = color_buffers[index]; | 1788 | const ImageView* const color_buffer = color_buffers[index]; |
| 1789 | if (!color_buffer) { | 1789 | if (!color_buffer) { |
| 1790 | renderpass_key.color_formats[index] = PixelFormat::Invalid; | 1790 | renderpass_key.color_formats[index] = PixelFormat::Invalid; |
| 1791 | continue; | 1791 | continue; |
| 1792 | } | 1792 | } |
| 1793 | width = std::max(width, is_rescaled ? resolution.ScaleUp(color_buffer->size.width) | 1793 | width = std::min(width, is_rescaled ? resolution.ScaleUp(color_buffer->size.width) |
| 1794 | : color_buffer->size.width); | 1794 | : color_buffer->size.width); |
| 1795 | height = std::max(height, is_rescaled ? resolution.ScaleUp(color_buffer->size.height) | 1795 | height = std::min(height, is_rescaled ? resolution.ScaleUp(color_buffer->size.height) |
| 1796 | : color_buffer->size.height); | 1796 | : color_buffer->size.height); |
| 1797 | attachments.push_back(color_buffer->RenderTarget()); | 1797 | attachments.push_back(color_buffer->RenderTarget()); |
| 1798 | renderpass_key.color_formats[index] = color_buffer->format; | 1798 | renderpass_key.color_formats[index] = color_buffer->format; |
| @@ -1804,9 +1804,9 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, | |||
| 1804 | } | 1804 | } |
| 1805 | const size_t num_colors = attachments.size(); | 1805 | const size_t num_colors = attachments.size(); |
| 1806 | if (depth_buffer) { | 1806 | if (depth_buffer) { |
| 1807 | width = std::max(width, is_rescaled ? resolution.ScaleUp(depth_buffer->size.width) | 1807 | width = std::min(width, is_rescaled ? resolution.ScaleUp(depth_buffer->size.width) |
| 1808 | : depth_buffer->size.width); | 1808 | : depth_buffer->size.width); |
| 1809 | height = std::max(height, is_rescaled ? resolution.ScaleUp(depth_buffer->size.height) | 1809 | height = std::min(height, is_rescaled ? resolution.ScaleUp(depth_buffer->size.height) |
| 1810 | : depth_buffer->size.height); | 1810 | : depth_buffer->size.height); |
| 1811 | attachments.push_back(depth_buffer->RenderTarget()); | 1811 | attachments.push_back(depth_buffer->RenderTarget()); |
| 1812 | renderpass_key.depth_format = depth_buffer->format; | 1812 | renderpass_key.depth_format = depth_buffer->format; |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 195074bf2..927dd1069 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -819,6 +819,7 @@ void Config::ReadUIGamelistValues() { | |||
| 819 | qt_config->beginGroup(QStringLiteral("UIGameList")); | 819 | qt_config->beginGroup(QStringLiteral("UIGameList")); |
| 820 | 820 | ||
| 821 | ReadBasicSetting(UISettings::values.show_add_ons); | 821 | ReadBasicSetting(UISettings::values.show_add_ons); |
| 822 | ReadBasicSetting(UISettings::values.show_compat); | ||
| 822 | ReadBasicSetting(UISettings::values.game_icon_size); | 823 | ReadBasicSetting(UISettings::values.game_icon_size); |
| 823 | ReadBasicSetting(UISettings::values.folder_icon_size); | 824 | ReadBasicSetting(UISettings::values.folder_icon_size); |
| 824 | ReadBasicSetting(UISettings::values.row_1_text_id); | 825 | ReadBasicSetting(UISettings::values.row_1_text_id); |
| @@ -1414,6 +1415,7 @@ void Config::SaveUIGamelistValues() { | |||
| 1414 | qt_config->beginGroup(QStringLiteral("UIGameList")); | 1415 | qt_config->beginGroup(QStringLiteral("UIGameList")); |
| 1415 | 1416 | ||
| 1416 | WriteBasicSetting(UISettings::values.show_add_ons); | 1417 | WriteBasicSetting(UISettings::values.show_add_ons); |
| 1418 | WriteBasicSetting(UISettings::values.show_compat); | ||
| 1417 | WriteBasicSetting(UISettings::values.game_icon_size); | 1419 | WriteBasicSetting(UISettings::values.game_icon_size); |
| 1418 | WriteBasicSetting(UISettings::values.folder_icon_size); | 1420 | WriteBasicSetting(UISettings::values.folder_icon_size); |
| 1419 | WriteBasicSetting(UISettings::values.row_1_text_id); | 1421 | WriteBasicSetting(UISettings::values.row_1_text_id); |
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 48f71b53c..92e6da6ee 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp | |||
| @@ -72,6 +72,7 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent) | |||
| 72 | 72 | ||
| 73 | // Force game list reload if any of the relevant settings are changed. | 73 | // Force game list reload if any of the relevant settings are changed. |
| 74 | connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); | 74 | connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); |
| 75 | connect(ui->show_compat, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); | ||
| 75 | connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 76 | connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |
| 76 | &ConfigureUi::RequestGameListUpdate); | 77 | &ConfigureUi::RequestGameListUpdate); |
| 77 | connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), | 78 | connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), |
| @@ -109,6 +110,7 @@ void ConfigureUi::ApplyConfiguration() { | |||
| 109 | UISettings::values.theme = | 110 | UISettings::values.theme = |
| 110 | ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); | 111 | ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); |
| 111 | UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); | 112 | UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); |
| 113 | UISettings::values.show_compat = ui->show_compat->isChecked(); | ||
| 112 | UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt(); | 114 | UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt(); |
| 113 | UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt(); | 115 | UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt(); |
| 114 | UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); | 116 | UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); |
| @@ -129,6 +131,7 @@ void ConfigureUi::SetConfiguration() { | |||
| 129 | ui->language_combobox->setCurrentIndex( | 131 | ui->language_combobox->setCurrentIndex( |
| 130 | ui->language_combobox->findData(UISettings::values.language)); | 132 | ui->language_combobox->findData(UISettings::values.language)); |
| 131 | ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); | 133 | ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); |
| 134 | ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); | ||
| 132 | ui->game_icon_size_combobox->setCurrentIndex( | 135 | ui->game_icon_size_combobox->setCurrentIndex( |
| 133 | ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue())); | 136 | ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue())); |
| 134 | ui->folder_icon_size_combobox->setCurrentIndex( | 137 | ui->folder_icon_size_combobox->setCurrentIndex( |
diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui index a50df7f6f..f0b719ba3 100644 --- a/src/yuzu/configuration/configure_ui.ui +++ b/src/yuzu/configuration/configure_ui.ui | |||
| @@ -77,6 +77,13 @@ | |||
| 77 | <item> | 77 | <item> |
| 78 | <layout class="QVBoxLayout" name="GeneralVerticalLayout"> | 78 | <layout class="QVBoxLayout" name="GeneralVerticalLayout"> |
| 79 | <item> | 79 | <item> |
| 80 | <widget class="QCheckBox" name="show_compat"> | ||
| 81 | <property name="text"> | ||
| 82 | <string>Show Compatibility List</string> | ||
| 83 | </property> | ||
| 84 | </widget> | ||
| 85 | </item> | ||
| 86 | <item> | ||
| 80 | <widget class="QCheckBox" name="show_add_ons"> | 87 | <widget class="QCheckBox" name="show_add_ons"> |
| 81 | <property name="text"> | 88 | <property name="text"> |
| 82 | <string>Show Add-Ons Column</string> | 89 | <string>Show Add-Ons Column</string> |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index b127badc2..d6adfca16 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -335,6 +335,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid | |||
| 335 | RetranslateUI(); | 335 | RetranslateUI(); |
| 336 | 336 | ||
| 337 | tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons); | 337 | tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons); |
| 338 | tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat); | ||
| 338 | item_model->setSortRole(GameListItemPath::SortRole); | 339 | item_model->setSortRole(GameListItemPath::SortRole); |
| 339 | 340 | ||
| 340 | connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons); | 341 | connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons); |
| @@ -786,6 +787,7 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) { | |||
| 786 | 787 | ||
| 787 | // Update the columns in case UISettings has changed | 788 | // Update the columns in case UISettings has changed |
| 788 | tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons); | 789 | tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons); |
| 790 | tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat); | ||
| 789 | 791 | ||
| 790 | // Delete any rows that might already exist if we're repopulating | 792 | // Delete any rows that might already exist if we're repopulating |
| 791 | item_model->removeRows(0, item_model->rowCount()); | 793 | item_model->removeRows(0, item_model->rowCount()); |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 753797efc..4f5b2a99d 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -129,6 +129,9 @@ struct Values { | |||
| 129 | Settings::Setting<bool> favorites_expanded{true, "favorites_expanded"}; | 129 | Settings::Setting<bool> favorites_expanded{true, "favorites_expanded"}; |
| 130 | QVector<u64> favorited_ids; | 130 | QVector<u64> favorited_ids; |
| 131 | 131 | ||
| 132 | // Compatibility List | ||
| 133 | Settings::Setting<bool> show_compat{false, "show_compat"}; | ||
| 134 | |||
| 132 | bool configuration_applied; | 135 | bool configuration_applied; |
| 133 | bool reset_to_defaults; | 136 | bool reset_to_defaults; |
| 134 | Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"}; | 137 | Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"}; |