diff options
72 files changed, 961 insertions, 401 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b625743ea..c6fc5dd9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -218,11 +218,11 @@ if(ENABLE_QT) | |||
| 218 | set(QT_VERSION 5.15) | 218 | set(QT_VERSION 5.15) |
| 219 | 219 | ||
| 220 | # Check for system Qt on Linux, fallback to bundled Qt | 220 | # Check for system Qt on Linux, fallback to bundled Qt |
| 221 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | 221 | if (UNIX AND NOT APPLE) |
| 222 | if (NOT YUZU_USE_BUNDLED_QT) | 222 | if (NOT YUZU_USE_BUNDLED_QT) |
| 223 | find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus Multimedia) | 223 | find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus Multimedia) |
| 224 | endif() | 224 | endif() |
| 225 | if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) | 225 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT)) |
| 226 | # Check for dependencies, then enable bundled Qt download | 226 | # Check for dependencies, then enable bundled Qt download |
| 227 | 227 | ||
| 228 | # Check that the system GLIBCXX version is compatible | 228 | # Check that the system GLIBCXX version is compatible |
| @@ -323,7 +323,7 @@ if(ENABLE_QT) | |||
| 323 | 323 | ||
| 324 | set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH") | 324 | set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH") |
| 325 | endif() | 325 | endif() |
| 326 | if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT) | 326 | if (UNIX AND NOT APPLE AND YUZU_USE_BUNDLED_QT) |
| 327 | find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) | 327 | find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) |
| 328 | else() | 328 | else() |
| 329 | find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) | 329 | find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH}) |
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 18fde8bd6..3bb111748 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -86,13 +86,13 @@ public: | |||
| 86 | u32 num_domain_objects{}; | 86 | u32 num_domain_objects{}; |
| 87 | const bool always_move_handles{ | 87 | const bool always_move_handles{ |
| 88 | (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0}; | 88 | (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0}; |
| 89 | if (!ctx.Session()->GetSessionRequestManager()->IsDomain() || always_move_handles) { | 89 | if (!ctx.GetManager()->IsDomain() || always_move_handles) { |
| 90 | num_handles_to_move = num_objects_to_move; | 90 | num_handles_to_move = num_objects_to_move; |
| 91 | } else { | 91 | } else { |
| 92 | num_domain_objects = num_objects_to_move; | 92 | num_domain_objects = num_objects_to_move; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | if (ctx.Session()->GetSessionRequestManager()->IsDomain()) { | 95 | if (ctx.GetManager()->IsDomain()) { |
| 96 | raw_data_size += | 96 | raw_data_size += |
| 97 | static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects); | 97 | static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects); |
| 98 | ctx.write_size += num_domain_objects; | 98 | ctx.write_size += num_domain_objects; |
| @@ -125,8 +125,7 @@ public: | |||
| 125 | if (!ctx.IsTipc()) { | 125 | if (!ctx.IsTipc()) { |
| 126 | AlignWithPadding(); | 126 | AlignWithPadding(); |
| 127 | 127 | ||
| 128 | if (ctx.Session()->GetSessionRequestManager()->IsDomain() && | 128 | if (ctx.GetManager()->IsDomain() && ctx.HasDomainMessageHeader()) { |
| 129 | ctx.HasDomainMessageHeader()) { | ||
| 130 | IPC::DomainMessageHeader domain_header{}; | 129 | IPC::DomainMessageHeader domain_header{}; |
| 131 | domain_header.num_objects = num_domain_objects; | 130 | domain_header.num_objects = num_domain_objects; |
| 132 | PushRaw(domain_header); | 131 | PushRaw(domain_header); |
| @@ -146,18 +145,18 @@ public: | |||
| 146 | 145 | ||
| 147 | template <class T> | 146 | template <class T> |
| 148 | void PushIpcInterface(std::shared_ptr<T> iface) { | 147 | void PushIpcInterface(std::shared_ptr<T> iface) { |
| 149 | if (context->Session()->GetSessionRequestManager()->IsDomain()) { | 148 | if (context->GetManager()->IsDomain()) { |
| 150 | context->AddDomainObject(std::move(iface)); | 149 | context->AddDomainObject(std::move(iface)); |
| 151 | } else { | 150 | } else { |
| 152 | kernel.CurrentProcess()->GetResourceLimit()->Reserve( | 151 | kernel.CurrentProcess()->GetResourceLimit()->Reserve( |
| 153 | Kernel::LimitableResource::Sessions, 1); | 152 | Kernel::LimitableResource::Sessions, 1); |
| 154 | 153 | ||
| 155 | auto* session = Kernel::KSession::Create(kernel); | 154 | auto* session = Kernel::KSession::Create(kernel); |
| 156 | session->Initialize(nullptr, iface->GetServiceName(), | 155 | session->Initialize(nullptr, iface->GetServiceName()); |
| 157 | std::make_shared<Kernel::SessionRequestManager>(kernel)); | 156 | iface->RegisterSession(&session->GetServerSession(), |
| 157 | std::make_shared<Kernel::SessionRequestManager>(kernel)); | ||
| 158 | 158 | ||
| 159 | context->AddMoveObject(&session->GetClientSession()); | 159 | context->AddMoveObject(&session->GetClientSession()); |
| 160 | iface->ClientConnected(&session->GetServerSession()); | ||
| 161 | } | 160 | } |
| 162 | } | 161 | } |
| 163 | 162 | ||
| @@ -387,7 +386,7 @@ public: | |||
| 387 | 386 | ||
| 388 | template <class T> | 387 | template <class T> |
| 389 | std::weak_ptr<T> PopIpcInterface() { | 388 | std::weak_ptr<T> PopIpcInterface() { |
| 390 | ASSERT(context->Session()->GetSessionRequestManager()->IsDomain()); | 389 | ASSERT(context->GetManager()->IsDomain()); |
| 391 | ASSERT(context->GetDomainMessageHeader().input_object_count > 0); | 390 | ASSERT(context->GetDomainMessageHeader().input_object_count > 0); |
| 392 | return context->GetDomainHandler<T>(Pop<u32>() - 1); | 391 | return context->GetDomainHandler<T>(Pop<u32>() - 1); |
| 393 | } | 392 | } |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index e4f43a053..fd354d484 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "core/hle/kernel/k_auto_object.h" | 16 | #include "core/hle/kernel/k_auto_object.h" |
| 17 | #include "core/hle/kernel/k_handle_table.h" | 17 | #include "core/hle/kernel/k_handle_table.h" |
| 18 | #include "core/hle/kernel/k_process.h" | 18 | #include "core/hle/kernel/k_process.h" |
| 19 | #include "core/hle/kernel/k_server_port.h" | ||
| 19 | #include "core/hle/kernel/k_server_session.h" | 20 | #include "core/hle/kernel/k_server_session.h" |
| 20 | #include "core/hle/kernel/k_thread.h" | 21 | #include "core/hle/kernel/k_thread.h" |
| 21 | #include "core/hle/kernel/kernel.h" | 22 | #include "core/hle/kernel/kernel.h" |
| @@ -35,7 +36,21 @@ SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* se | |||
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | SessionRequestHandler::~SessionRequestHandler() { | 38 | SessionRequestHandler::~SessionRequestHandler() { |
| 38 | kernel.ReleaseServiceThread(service_thread); | 39 | kernel.ReleaseServiceThread(service_thread.lock()); |
| 40 | } | ||
| 41 | |||
| 42 | void SessionRequestHandler::AcceptSession(KServerPort* server_port) { | ||
| 43 | auto* server_session = server_port->AcceptSession(); | ||
| 44 | ASSERT(server_session != nullptr); | ||
| 45 | |||
| 46 | RegisterSession(server_session, std::make_shared<SessionRequestManager>(kernel)); | ||
| 47 | } | ||
| 48 | |||
| 49 | void SessionRequestHandler::RegisterSession(KServerSession* server_session, | ||
| 50 | std::shared_ptr<SessionRequestManager> manager) { | ||
| 51 | manager->SetSessionHandler(shared_from_this()); | ||
| 52 | service_thread.lock()->RegisterServerSession(server_session, manager); | ||
| 53 | server_session->Close(); | ||
| 39 | } | 54 | } |
| 40 | 55 | ||
| 41 | SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {} | 56 | SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {} |
| @@ -92,7 +107,7 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses | |||
| 92 | } | 107 | } |
| 93 | 108 | ||
| 94 | // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs | 109 | // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs |
| 95 | context.SetSessionRequestManager(server_session->GetSessionRequestManager()); | 110 | ASSERT(context.GetManager().get() == this); |
| 96 | 111 | ||
| 97 | // If there is a DomainMessageHeader, then this is CommandType "Request" | 112 | // If there is a DomainMessageHeader, then this is CommandType "Request" |
| 98 | const auto& domain_message_header = context.GetDomainMessageHeader(); | 113 | const auto& domain_message_header = context.GetDomainMessageHeader(); |
| @@ -130,31 +145,6 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses | |||
| 130 | return ResultSuccess; | 145 | return ResultSuccess; |
| 131 | } | 146 | } |
| 132 | 147 | ||
| 133 | Result SessionRequestManager::QueueSyncRequest(KSession* parent, | ||
| 134 | std::shared_ptr<HLERequestContext>&& context) { | ||
| 135 | // Ensure we have a session request handler | ||
| 136 | if (this->HasSessionRequestHandler(*context)) { | ||
| 137 | if (auto strong_ptr = this->GetServiceThread().lock()) { | ||
| 138 | strong_ptr->QueueSyncRequest(*parent, std::move(context)); | ||
| 139 | } else { | ||
| 140 | ASSERT_MSG(false, "strong_ptr is nullptr!"); | ||
| 141 | } | ||
| 142 | } else { | ||
| 143 | ASSERT_MSG(false, "handler is invalid!"); | ||
| 144 | } | ||
| 145 | |||
| 146 | return ResultSuccess; | ||
| 147 | } | ||
| 148 | |||
| 149 | void SessionRequestHandler::ClientConnected(KServerSession* session) { | ||
| 150 | session->GetSessionRequestManager()->SetSessionHandler(shared_from_this()); | ||
| 151 | |||
| 152 | // Ensure our server session is tracked globally. | ||
| 153 | kernel.RegisterServerObject(session); | ||
| 154 | } | ||
| 155 | |||
| 156 | void SessionRequestHandler::ClientDisconnected(KServerSession* session) {} | ||
| 157 | |||
| 158 | HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, | 148 | HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, |
| 159 | KServerSession* server_session_, KThread* thread_) | 149 | KServerSession* server_session_, KThread* thread_) |
| 160 | : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} { | 150 | : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} { |
| @@ -214,7 +204,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 | |||
| 214 | // Padding to align to 16 bytes | 204 | // Padding to align to 16 bytes |
| 215 | rp.AlignWithPadding(); | 205 | rp.AlignWithPadding(); |
| 216 | 206 | ||
| 217 | if (Session()->GetSessionRequestManager()->IsDomain() && | 207 | if (GetManager()->IsDomain() && |
| 218 | ((command_header->type == IPC::CommandType::Request || | 208 | ((command_header->type == IPC::CommandType::Request || |
| 219 | command_header->type == IPC::CommandType::RequestWithContext) || | 209 | command_header->type == IPC::CommandType::RequestWithContext) || |
| 220 | !incoming)) { | 210 | !incoming)) { |
| @@ -223,7 +213,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 | |||
| 223 | if (incoming || domain_message_header) { | 213 | if (incoming || domain_message_header) { |
| 224 | domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); | 214 | domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); |
| 225 | } else { | 215 | } else { |
| 226 | if (Session()->GetSessionRequestManager()->IsDomain()) { | 216 | if (GetManager()->IsDomain()) { |
| 227 | LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); | 217 | LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); |
| 228 | } | 218 | } |
| 229 | } | 219 | } |
| @@ -316,12 +306,11 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa | |||
| 316 | // Write the domain objects to the command buffer, these go after the raw untranslated data. | 306 | // Write the domain objects to the command buffer, these go after the raw untranslated data. |
| 317 | // TODO(Subv): This completely ignores C buffers. | 307 | // TODO(Subv): This completely ignores C buffers. |
| 318 | 308 | ||
| 319 | if (server_session->GetSessionRequestManager()->IsDomain()) { | 309 | if (GetManager()->IsDomain()) { |
| 320 | current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); | 310 | current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); |
| 321 | for (auto& object : outgoing_domain_objects) { | 311 | for (auto& object : outgoing_domain_objects) { |
| 322 | server_session->GetSessionRequestManager()->AppendDomainHandler(std::move(object)); | 312 | GetManager()->AppendDomainHandler(std::move(object)); |
| 323 | cmd_buf[current_offset++] = static_cast<u32_le>( | 313 | cmd_buf[current_offset++] = static_cast<u32_le>(GetManager()->DomainHandlerCount()); |
| 324 | server_session->GetSessionRequestManager()->DomainHandlerCount()); | ||
| 325 | } | 314 | } |
| 326 | } | 315 | } |
| 327 | 316 | ||
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 1083638a9..67da8e7e1 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -45,11 +45,13 @@ class KAutoObject; | |||
| 45 | class KernelCore; | 45 | class KernelCore; |
| 46 | class KEvent; | 46 | class KEvent; |
| 47 | class KHandleTable; | 47 | class KHandleTable; |
| 48 | class KServerPort; | ||
| 48 | class KProcess; | 49 | class KProcess; |
| 49 | class KServerSession; | 50 | class KServerSession; |
| 50 | class KThread; | 51 | class KThread; |
| 51 | class KReadableEvent; | 52 | class KReadableEvent; |
| 52 | class KSession; | 53 | class KSession; |
| 54 | class SessionRequestManager; | ||
| 53 | class ServiceThread; | 55 | class ServiceThread; |
| 54 | 56 | ||
| 55 | enum class ThreadWakeupReason; | 57 | enum class ThreadWakeupReason; |
| @@ -76,19 +78,9 @@ public: | |||
| 76 | virtual Result HandleSyncRequest(Kernel::KServerSession& session, | 78 | virtual Result HandleSyncRequest(Kernel::KServerSession& session, |
| 77 | Kernel::HLERequestContext& context) = 0; | 79 | Kernel::HLERequestContext& context) = 0; |
| 78 | 80 | ||
| 79 | /** | 81 | void AcceptSession(KServerPort* server_port); |
| 80 | * Signals that a client has just connected to this HLE handler and keeps the | 82 | void RegisterSession(KServerSession* server_session, |
| 81 | * associated ServerSession alive for the duration of the connection. | 83 | std::shared_ptr<SessionRequestManager> manager); |
| 82 | * @param server_session Owning pointer to the ServerSession associated with the connection. | ||
| 83 | */ | ||
| 84 | void ClientConnected(KServerSession* session); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Signals that a client has just disconnected from this HLE handler and releases the | ||
| 88 | * associated ServerSession. | ||
| 89 | * @param server_session ServerSession associated with the connection. | ||
| 90 | */ | ||
| 91 | void ClientDisconnected(KServerSession* session); | ||
| 92 | 84 | ||
| 93 | std::weak_ptr<ServiceThread> GetServiceThread() const { | 85 | std::weak_ptr<ServiceThread> GetServiceThread() const { |
| 94 | return service_thread; | 86 | return service_thread; |
| @@ -170,7 +162,6 @@ public: | |||
| 170 | 162 | ||
| 171 | Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context); | 163 | Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context); |
| 172 | Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context); | 164 | Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context); |
| 173 | Result QueueSyncRequest(KSession* parent, std::shared_ptr<HLERequestContext>&& context); | ||
| 174 | 165 | ||
| 175 | private: | 166 | private: |
| 176 | bool convert_to_domain{}; | 167 | bool convert_to_domain{}; |
| @@ -350,11 +341,11 @@ public: | |||
| 350 | 341 | ||
| 351 | template <typename T> | 342 | template <typename T> |
| 352 | std::shared_ptr<T> GetDomainHandler(std::size_t index) const { | 343 | std::shared_ptr<T> GetDomainHandler(std::size_t index) const { |
| 353 | return std::static_pointer_cast<T>(manager.lock()->DomainHandler(index).lock()); | 344 | return std::static_pointer_cast<T>(GetManager()->DomainHandler(index).lock()); |
| 354 | } | 345 | } |
| 355 | 346 | ||
| 356 | void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) { | 347 | void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) { |
| 357 | manager = std::move(manager_); | 348 | manager = manager_; |
| 358 | } | 349 | } |
| 359 | 350 | ||
| 360 | std::string Description() const; | 351 | std::string Description() const; |
| @@ -363,6 +354,10 @@ public: | |||
| 363 | return *thread; | 354 | return *thread; |
| 364 | } | 355 | } |
| 365 | 356 | ||
| 357 | std::shared_ptr<SessionRequestManager> GetManager() const { | ||
| 358 | return manager.lock(); | ||
| 359 | } | ||
| 360 | |||
| 366 | private: | 361 | private: |
| 367 | friend class IPC::ResponseBuilder; | 362 | friend class IPC::ResponseBuilder; |
| 368 | 363 | ||
| @@ -396,7 +391,7 @@ private: | |||
| 396 | u32 handles_offset{}; | 391 | u32 handles_offset{}; |
| 397 | u32 domain_offset{}; | 392 | u32 domain_offset{}; |
| 398 | 393 | ||
| 399 | std::weak_ptr<SessionRequestManager> manager; | 394 | std::weak_ptr<SessionRequestManager> manager{}; |
| 400 | 395 | ||
| 401 | KernelCore& kernel; | 396 | KernelCore& kernel; |
| 402 | Core::Memory::Memory& memory; | 397 | Core::Memory::Memory& memory; |
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index 3cb22ff4d..eaa2e094c 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp | |||
| @@ -58,8 +58,7 @@ bool KClientPort::IsSignaled() const { | |||
| 58 | return num_sessions < max_sessions; | 58 | return num_sessions < max_sessions; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | Result KClientPort::CreateSession(KClientSession** out, | 61 | Result KClientPort::CreateSession(KClientSession** out) { |
| 62 | std::shared_ptr<SessionRequestManager> session_manager) { | ||
| 63 | // Reserve a new session from the resource limit. | 62 | // Reserve a new session from the resource limit. |
| 64 | KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), | 63 | KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), |
| 65 | LimitableResource::Sessions); | 64 | LimitableResource::Sessions); |
| @@ -104,7 +103,7 @@ Result KClientPort::CreateSession(KClientSession** out, | |||
| 104 | } | 103 | } |
| 105 | 104 | ||
| 106 | // Initialize the session. | 105 | // Initialize the session. |
| 107 | session->Initialize(this, parent->GetName(), session_manager); | 106 | session->Initialize(this, parent->GetName()); |
| 108 | 107 | ||
| 109 | // Commit the session reservation. | 108 | // Commit the session reservation. |
| 110 | session_reservation.Commit(); | 109 | session_reservation.Commit(); |
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index e17eff28f..81046fb86 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h | |||
| @@ -52,8 +52,7 @@ public: | |||
| 52 | void Destroy() override; | 52 | void Destroy() override; |
| 53 | bool IsSignaled() const override; | 53 | bool IsSignaled() const override; |
| 54 | 54 | ||
| 55 | Result CreateSession(KClientSession** out, | 55 | Result CreateSession(KClientSession** out); |
| 56 | std::shared_ptr<SessionRequestManager> session_manager = nullptr); | ||
| 57 | 56 | ||
| 58 | private: | 57 | private: |
| 59 | std::atomic<s32> num_sessions{}; | 58 | std::atomic<s32> num_sessions{}; |
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index 7a5a9dc2a..77d00ae2c 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp | |||
| @@ -57,12 +57,6 @@ Result KPort::EnqueueSession(KServerSession* session) { | |||
| 57 | 57 | ||
| 58 | server.EnqueueSession(session); | 58 | server.EnqueueSession(session); |
| 59 | 59 | ||
| 60 | if (auto session_ptr = server.GetSessionRequestHandler().lock()) { | ||
| 61 | session_ptr->ClientConnected(server.AcceptSession()); | ||
| 62 | } else { | ||
| 63 | ASSERT(false); | ||
| 64 | } | ||
| 65 | |||
| 66 | return ResultSuccess; | 60 | return ResultSuccess; |
| 67 | } | 61 | } |
| 68 | 62 | ||
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp index e968f26ad..16968ba97 100644 --- a/src/core/hle/kernel/k_server_port.cpp +++ b/src/core/hle/kernel/k_server_port.cpp | |||
| @@ -61,12 +61,6 @@ void KServerPort::Destroy() { | |||
| 61 | 61 | ||
| 62 | // Close our reference to our parent. | 62 | // Close our reference to our parent. |
| 63 | parent->Close(); | 63 | parent->Close(); |
| 64 | |||
| 65 | // Release host emulation members. | ||
| 66 | session_handler.reset(); | ||
| 67 | |||
| 68 | // Ensure that the global list tracking server objects does not hold on to a reference. | ||
| 69 | kernel.UnregisterServerObject(this); | ||
| 70 | } | 64 | } |
| 71 | 65 | ||
| 72 | bool KServerPort::IsSignaled() const { | 66 | bool KServerPort::IsSignaled() const { |
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index fd4f4bd20..5fc7ee683 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h | |||
| @@ -27,24 +27,6 @@ public: | |||
| 27 | 27 | ||
| 28 | void Initialize(KPort* parent_port_, std::string&& name_); | 28 | void Initialize(KPort* parent_port_, std::string&& name_); |
| 29 | 29 | ||
| 30 | /// Whether or not this server port has an HLE handler available. | ||
| 31 | bool HasSessionRequestHandler() const { | ||
| 32 | return !session_handler.expired(); | ||
| 33 | } | ||
| 34 | |||
| 35 | /// Gets the HLE handler for this port. | ||
| 36 | SessionRequestHandlerWeakPtr GetSessionRequestHandler() const { | ||
| 37 | return session_handler; | ||
| 38 | } | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port | ||
| 42 | * will inherit a reference to this handler. | ||
| 43 | */ | ||
| 44 | void SetSessionHandler(SessionRequestHandlerWeakPtr&& handler) { | ||
| 45 | session_handler = std::move(handler); | ||
| 46 | } | ||
| 47 | |||
| 48 | void EnqueueSession(KServerSession* pending_session); | 30 | void EnqueueSession(KServerSession* pending_session); |
| 49 | 31 | ||
| 50 | KServerSession* AcceptSession(); | 32 | KServerSession* AcceptSession(); |
| @@ -65,7 +47,6 @@ private: | |||
| 65 | void CleanupSessions(); | 47 | void CleanupSessions(); |
| 66 | 48 | ||
| 67 | SessionList session_list; | 49 | SessionList session_list; |
| 68 | SessionRequestHandlerWeakPtr session_handler; | ||
| 69 | KPort* parent{}; | 50 | KPort* parent{}; |
| 70 | }; | 51 | }; |
| 71 | 52 | ||
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index faf03fcc8..aa1941f01 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <tuple> | 4 | #include <tuple> |
| @@ -33,12 +33,10 @@ KServerSession::KServerSession(KernelCore& kernel_) | |||
| 33 | 33 | ||
| 34 | KServerSession::~KServerSession() = default; | 34 | KServerSession::~KServerSession() = default; |
| 35 | 35 | ||
| 36 | void KServerSession::Initialize(KSession* parent_session_, std::string&& name_, | 36 | void KServerSession::Initialize(KSession* parent_session_, std::string&& name_) { |
| 37 | std::shared_ptr<SessionRequestManager> manager_) { | ||
| 38 | // Set member variables. | 37 | // Set member variables. |
| 39 | parent = parent_session_; | 38 | parent = parent_session_; |
| 40 | name = std::move(name_); | 39 | name = std::move(name_); |
| 41 | manager = manager_; | ||
| 42 | } | 40 | } |
| 43 | 41 | ||
| 44 | void KServerSession::Destroy() { | 42 | void KServerSession::Destroy() { |
| @@ -47,18 +45,99 @@ void KServerSession::Destroy() { | |||
| 47 | this->CleanupRequests(); | 45 | this->CleanupRequests(); |
| 48 | 46 | ||
| 49 | parent->Close(); | 47 | parent->Close(); |
| 50 | |||
| 51 | // Release host emulation members. | ||
| 52 | manager.reset(); | ||
| 53 | |||
| 54 | // Ensure that the global list tracking server objects does not hold on to a reference. | ||
| 55 | kernel.UnregisterServerObject(this); | ||
| 56 | } | 48 | } |
| 57 | 49 | ||
| 58 | void KServerSession::OnClientClosed() { | 50 | void KServerSession::OnClientClosed() { |
| 59 | if (manager && manager->HasSessionHandler()) { | 51 | KScopedLightLock lk{m_lock}; |
| 60 | manager->SessionHandler().ClientDisconnected(this); | 52 | |
| 53 | // Handle any pending requests. | ||
| 54 | KSessionRequest* prev_request = nullptr; | ||
| 55 | while (true) { | ||
| 56 | // Declare variables for processing the request. | ||
| 57 | KSessionRequest* request = nullptr; | ||
| 58 | KEvent* event = nullptr; | ||
| 59 | KThread* thread = nullptr; | ||
| 60 | bool cur_request = false; | ||
| 61 | bool terminate = false; | ||
| 62 | |||
| 63 | // Get the next request. | ||
| 64 | { | ||
| 65 | KScopedSchedulerLock sl{kernel}; | ||
| 66 | |||
| 67 | if (m_current_request != nullptr && m_current_request != prev_request) { | ||
| 68 | // Set the request, open a reference as we process it. | ||
| 69 | request = m_current_request; | ||
| 70 | request->Open(); | ||
| 71 | cur_request = true; | ||
| 72 | |||
| 73 | // Get thread and event for the request. | ||
| 74 | thread = request->GetThread(); | ||
| 75 | event = request->GetEvent(); | ||
| 76 | |||
| 77 | // If the thread is terminating, handle that. | ||
| 78 | if (thread->IsTerminationRequested()) { | ||
| 79 | request->ClearThread(); | ||
| 80 | request->ClearEvent(); | ||
| 81 | terminate = true; | ||
| 82 | } | ||
| 83 | |||
| 84 | prev_request = request; | ||
| 85 | } else if (!m_request_list.empty()) { | ||
| 86 | // Pop the request from the front of the list. | ||
| 87 | request = std::addressof(m_request_list.front()); | ||
| 88 | m_request_list.pop_front(); | ||
| 89 | |||
| 90 | // Get thread and event for the request. | ||
| 91 | thread = request->GetThread(); | ||
| 92 | event = request->GetEvent(); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | // If there are no requests, we're done. | ||
| 97 | if (request == nullptr) { | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | |||
| 101 | // All requests must have threads. | ||
| 102 | ASSERT(thread != nullptr); | ||
| 103 | |||
| 104 | // Ensure that we close the request when done. | ||
| 105 | SCOPE_EXIT({ request->Close(); }); | ||
| 106 | |||
| 107 | // If we're terminating, close a reference to the thread and event. | ||
| 108 | if (terminate) { | ||
| 109 | thread->Close(); | ||
| 110 | if (event != nullptr) { | ||
| 111 | event->Close(); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | // If we need to, reply. | ||
| 116 | if (event != nullptr && !cur_request) { | ||
| 117 | // There must be no mappings. | ||
| 118 | ASSERT(request->GetSendCount() == 0); | ||
| 119 | ASSERT(request->GetReceiveCount() == 0); | ||
| 120 | ASSERT(request->GetExchangeCount() == 0); | ||
| 121 | |||
| 122 | // // Get the process and page table. | ||
| 123 | // KProcess *client_process = thread->GetOwnerProcess(); | ||
| 124 | // auto &client_pt = client_process->GetPageTable(); | ||
| 125 | |||
| 126 | // // Reply to the request. | ||
| 127 | // ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(), | ||
| 128 | // ResultSessionClosed); | ||
| 129 | |||
| 130 | // // Unlock the buffer. | ||
| 131 | // // NOTE: Nintendo does not check the result of this. | ||
| 132 | // client_pt.UnlockForIpcUserBuffer(request->GetAddress(), request->GetSize()); | ||
| 133 | |||
| 134 | // Signal the event. | ||
| 135 | event->Signal(); | ||
| 136 | } | ||
| 61 | } | 137 | } |
| 138 | |||
| 139 | // Notify. | ||
| 140 | this->NotifyAvailable(ResultSessionClosed); | ||
| 62 | } | 141 | } |
| 63 | 142 | ||
| 64 | bool KServerSession::IsSignaled() const { | 143 | bool KServerSession::IsSignaled() const { |
| @@ -73,24 +152,6 @@ bool KServerSession::IsSignaled() const { | |||
| 73 | return !m_request_list.empty() && m_current_request == nullptr; | 152 | return !m_request_list.empty() && m_current_request == nullptr; |
| 74 | } | 153 | } |
| 75 | 154 | ||
| 76 | Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { | ||
| 77 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; | ||
| 78 | auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread); | ||
| 79 | |||
| 80 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | ||
| 81 | |||
| 82 | return manager->QueueSyncRequest(parent, std::move(context)); | ||
| 83 | } | ||
| 84 | |||
| 85 | Result KServerSession::CompleteSyncRequest(HLERequestContext& context) { | ||
| 86 | Result result = manager->CompleteSyncRequest(this, context); | ||
| 87 | |||
| 88 | // The calling thread is waiting for this request to complete, so wake it up. | ||
| 89 | context.GetThread().EndWait(result); | ||
| 90 | |||
| 91 | return result; | ||
| 92 | } | ||
| 93 | |||
| 94 | Result KServerSession::OnRequest(KSessionRequest* request) { | 155 | Result KServerSession::OnRequest(KSessionRequest* request) { |
| 95 | // Create the wait queue. | 156 | // Create the wait queue. |
| 96 | ThreadQueueImplForKServerSessionRequest wait_queue{kernel}; | 157 | ThreadQueueImplForKServerSessionRequest wait_queue{kernel}; |
| @@ -105,24 +166,16 @@ Result KServerSession::OnRequest(KSessionRequest* request) { | |||
| 105 | // Check that we're not terminating. | 166 | // Check that we're not terminating. |
| 106 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested); | 167 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested); |
| 107 | 168 | ||
| 108 | if (manager) { | 169 | // Get whether we're empty. |
| 109 | // HLE request. | 170 | const bool was_empty = m_request_list.empty(); |
| 110 | auto& memory{kernel.System().Memory()}; | ||
| 111 | this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory); | ||
| 112 | } else { | ||
| 113 | // Non-HLE request. | ||
| 114 | |||
| 115 | // Get whether we're empty. | ||
| 116 | const bool was_empty = m_request_list.empty(); | ||
| 117 | 171 | ||
| 118 | // Add the request to the list. | 172 | // Add the request to the list. |
| 119 | request->Open(); | 173 | request->Open(); |
| 120 | m_request_list.push_back(*request); | 174 | m_request_list.push_back(*request); |
| 121 | 175 | ||
| 122 | // If we were empty, signal. | 176 | // If we were empty, signal. |
| 123 | if (was_empty) { | 177 | if (was_empty) { |
| 124 | this->NotifyAvailable(); | 178 | this->NotifyAvailable(); |
| 125 | } | ||
| 126 | } | 179 | } |
| 127 | 180 | ||
| 128 | // If we have a request event, this is asynchronous, and we don't need to wait. | 181 | // If we have a request event, this is asynchronous, and we don't need to wait. |
| @@ -136,7 +189,7 @@ Result KServerSession::OnRequest(KSessionRequest* request) { | |||
| 136 | return GetCurrentThread(kernel).GetWaitResult(); | 189 | return GetCurrentThread(kernel).GetWaitResult(); |
| 137 | } | 190 | } |
| 138 | 191 | ||
| 139 | Result KServerSession::SendReply() { | 192 | Result KServerSession::SendReply(bool is_hle) { |
| 140 | // Lock the session. | 193 | // Lock the session. |
| 141 | KScopedLightLock lk{m_lock}; | 194 | KScopedLightLock lk{m_lock}; |
| 142 | 195 | ||
| @@ -171,13 +224,18 @@ Result KServerSession::SendReply() { | |||
| 171 | Result result = ResultSuccess; | 224 | Result result = ResultSuccess; |
| 172 | if (!closed) { | 225 | if (!closed) { |
| 173 | // If we're not closed, send the reply. | 226 | // If we're not closed, send the reply. |
| 174 | Core::Memory::Memory& memory{kernel.System().Memory()}; | 227 | if (is_hle) { |
| 175 | KThread* server_thread{GetCurrentThreadPointer(kernel)}; | 228 | // HLE servers write directly to a pointer to the thread command buffer. Therefore |
| 176 | UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | 229 | // the reply has already been written in this case. |
| 230 | } else { | ||
| 231 | Core::Memory::Memory& memory{kernel.System().Memory()}; | ||
| 232 | KThread* server_thread{GetCurrentThreadPointer(kernel)}; | ||
| 233 | UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | ||
| 177 | 234 | ||
| 178 | auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); | 235 | auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); |
| 179 | auto* dst_msg_buffer = memory.GetPointer(client_message); | 236 | auto* dst_msg_buffer = memory.GetPointer(client_message); |
| 180 | std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); | 237 | std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); |
| 238 | } | ||
| 181 | } else { | 239 | } else { |
| 182 | result = ResultSessionClosed; | 240 | result = ResultSessionClosed; |
| 183 | } | 241 | } |
| @@ -223,7 +281,8 @@ Result KServerSession::SendReply() { | |||
| 223 | return result; | 281 | return result; |
| 224 | } | 282 | } |
| 225 | 283 | ||
| 226 | Result KServerSession::ReceiveRequest() { | 284 | Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context, |
| 285 | std::weak_ptr<SessionRequestManager> manager) { | ||
| 227 | // Lock the session. | 286 | // Lock the session. |
| 228 | KScopedLightLock lk{m_lock}; | 287 | KScopedLightLock lk{m_lock}; |
| 229 | 288 | ||
| @@ -267,12 +326,22 @@ Result KServerSession::ReceiveRequest() { | |||
| 267 | 326 | ||
| 268 | // Receive the message. | 327 | // Receive the message. |
| 269 | Core::Memory::Memory& memory{kernel.System().Memory()}; | 328 | Core::Memory::Memory& memory{kernel.System().Memory()}; |
| 270 | KThread* server_thread{GetCurrentThreadPointer(kernel)}; | 329 | if (out_context != nullptr) { |
| 271 | UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | 330 | // HLE request. |
| 331 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))}; | ||
| 332 | *out_context = std::make_shared<HLERequestContext>(kernel, memory, this, client_thread); | ||
| 333 | (*out_context)->SetSessionRequestManager(manager); | ||
| 334 | (*out_context) | ||
| 335 | ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), | ||
| 336 | cmd_buf); | ||
| 337 | } else { | ||
| 338 | KThread* server_thread{GetCurrentThreadPointer(kernel)}; | ||
| 339 | UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | ||
| 272 | 340 | ||
| 273 | auto* src_msg_buffer = memory.GetPointer(client_message); | 341 | auto* src_msg_buffer = memory.GetPointer(client_message); |
| 274 | auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); | 342 | auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); |
| 275 | std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); | 343 | std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); |
| 344 | } | ||
| 276 | 345 | ||
| 277 | // We succeeded. | 346 | // We succeeded. |
| 278 | return ResultSuccess; | 347 | return ResultSuccess; |
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 188aef4af..6e189af8b 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| @@ -16,21 +16,11 @@ | |||
| 16 | #include "core/hle/kernel/k_synchronization_object.h" | 16 | #include "core/hle/kernel/k_synchronization_object.h" |
| 17 | #include "core/hle/result.h" | 17 | #include "core/hle/result.h" |
| 18 | 18 | ||
| 19 | namespace Core::Memory { | ||
| 20 | class Memory; | ||
| 21 | } | ||
| 22 | |||
| 23 | namespace Core::Timing { | ||
| 24 | class CoreTiming; | ||
| 25 | struct EventType; | ||
| 26 | } // namespace Core::Timing | ||
| 27 | |||
| 28 | namespace Kernel { | 19 | namespace Kernel { |
| 29 | 20 | ||
| 30 | class HLERequestContext; | 21 | class HLERequestContext; |
| 31 | class KernelCore; | 22 | class KernelCore; |
| 32 | class KSession; | 23 | class KSession; |
| 33 | class SessionRequestHandler; | ||
| 34 | class SessionRequestManager; | 24 | class SessionRequestManager; |
| 35 | class KThread; | 25 | class KThread; |
| 36 | 26 | ||
| @@ -46,8 +36,7 @@ public: | |||
| 46 | 36 | ||
| 47 | void Destroy() override; | 37 | void Destroy() override; |
| 48 | 38 | ||
| 49 | void Initialize(KSession* parent_session_, std::string&& name_, | 39 | void Initialize(KSession* parent_session_, std::string&& name_); |
| 50 | std::shared_ptr<SessionRequestManager> manager_); | ||
| 51 | 40 | ||
| 52 | KSession* GetParent() { | 41 | KSession* GetParent() { |
| 53 | return parent; | 42 | return parent; |
| @@ -60,32 +49,20 @@ public: | |||
| 60 | bool IsSignaled() const override; | 49 | bool IsSignaled() const override; |
| 61 | void OnClientClosed(); | 50 | void OnClientClosed(); |
| 62 | 51 | ||
| 63 | /// Gets the session request manager, which forwards requests to the underlying service | ||
| 64 | std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() { | ||
| 65 | return manager; | ||
| 66 | } | ||
| 67 | |||
| 68 | /// TODO: flesh these out to match the real kernel | 52 | /// TODO: flesh these out to match the real kernel |
| 69 | Result OnRequest(KSessionRequest* request); | 53 | Result OnRequest(KSessionRequest* request); |
| 70 | Result SendReply(); | 54 | Result SendReply(bool is_hle = false); |
| 71 | Result ReceiveRequest(); | 55 | Result ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context = nullptr, |
| 56 | std::weak_ptr<SessionRequestManager> manager = {}); | ||
| 57 | |||
| 58 | Result SendReplyHLE() { | ||
| 59 | return SendReply(true); | ||
| 60 | } | ||
| 72 | 61 | ||
| 73 | private: | 62 | private: |
| 74 | /// Frees up waiting client sessions when this server session is about to die | 63 | /// Frees up waiting client sessions when this server session is about to die |
| 75 | void CleanupRequests(); | 64 | void CleanupRequests(); |
| 76 | 65 | ||
| 77 | /// Queues a sync request from the emulated application. | ||
| 78 | Result QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); | ||
| 79 | |||
| 80 | /// Completes a sync request from the emulated application. | ||
| 81 | Result CompleteSyncRequest(HLERequestContext& context); | ||
| 82 | |||
| 83 | /// This session's HLE request handlers; if nullptr, this is not an HLE server | ||
| 84 | std::shared_ptr<SessionRequestManager> manager; | ||
| 85 | |||
| 86 | /// When set to True, converts the session to a domain at the end of the command | ||
| 87 | bool convert_to_domain{}; | ||
| 88 | |||
| 89 | /// KSession that owns this KServerSession | 66 | /// KSession that owns this KServerSession |
| 90 | KSession* parent{}; | 67 | KSession* parent{}; |
| 91 | 68 | ||
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index ee05aa282..7a6534ac3 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp | |||
| @@ -13,8 +13,7 @@ KSession::KSession(KernelCore& kernel_) | |||
| 13 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {} | 13 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {} |
| 14 | KSession::~KSession() = default; | 14 | KSession::~KSession() = default; |
| 15 | 15 | ||
| 16 | void KSession::Initialize(KClientPort* port_, const std::string& name_, | 16 | void KSession::Initialize(KClientPort* port_, const std::string& name_) { |
| 17 | std::shared_ptr<SessionRequestManager> manager_) { | ||
| 18 | // Increment reference count. | 17 | // Increment reference count. |
| 19 | // Because reference count is one on creation, this will result | 18 | // Because reference count is one on creation, this will result |
| 20 | // in a reference count of two. Thus, when both server and client are closed | 19 | // in a reference count of two. Thus, when both server and client are closed |
| @@ -26,7 +25,7 @@ void KSession::Initialize(KClientPort* port_, const std::string& name_, | |||
| 26 | KAutoObject::Create(std::addressof(client)); | 25 | KAutoObject::Create(std::addressof(client)); |
| 27 | 26 | ||
| 28 | // Initialize our sub sessions. | 27 | // Initialize our sub sessions. |
| 29 | server.Initialize(this, name_ + ":Server", manager_); | 28 | server.Initialize(this, name_ + ":Server"); |
| 30 | client.Initialize(this, name_ + ":Client"); | 29 | client.Initialize(this, name_ + ":Client"); |
| 31 | 30 | ||
| 32 | // Set state and name. | 31 | // Set state and name. |
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index c6ead403b..93e5e6f71 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h | |||
| @@ -21,8 +21,7 @@ public: | |||
| 21 | explicit KSession(KernelCore& kernel_); | 21 | explicit KSession(KernelCore& kernel_); |
| 22 | ~KSession() override; | 22 | ~KSession() override; |
| 23 | 23 | ||
| 24 | void Initialize(KClientPort* port_, const std::string& name_, | 24 | void Initialize(KClientPort* port_, const std::string& name_); |
| 25 | std::shared_ptr<SessionRequestManager> manager_ = nullptr); | ||
| 26 | 25 | ||
| 27 | void Finalize() override; | 26 | void Finalize() override; |
| 28 | 27 | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index eda4e9e1c..47b760a9c 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -67,7 +67,6 @@ struct KernelCore::Impl { | |||
| 67 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | 67 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); |
| 68 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); | 68 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); |
| 69 | global_handle_table->Initialize(KHandleTable::MaxTableSize); | 69 | global_handle_table->Initialize(KHandleTable::MaxTableSize); |
| 70 | default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread"); | ||
| 71 | 70 | ||
| 72 | is_phantom_mode_for_singlecore = false; | 71 | is_phantom_mode_for_singlecore = false; |
| 73 | 72 | ||
| @@ -93,6 +92,8 @@ struct KernelCore::Impl { | |||
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | RegisterHostThread(); | 94 | RegisterHostThread(); |
| 95 | |||
| 96 | default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread"); | ||
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | void InitializeCores() { | 99 | void InitializeCores() { |
| @@ -191,17 +192,6 @@ struct KernelCore::Impl { | |||
| 191 | } | 192 | } |
| 192 | 193 | ||
| 193 | void CloseServices() { | 194 | void CloseServices() { |
| 194 | // Close all open server sessions and ports. | ||
| 195 | std::unordered_set<KAutoObject*> server_objects_; | ||
| 196 | { | ||
| 197 | std::scoped_lock lk(server_objects_lock); | ||
| 198 | server_objects_ = server_objects; | ||
| 199 | server_objects.clear(); | ||
| 200 | } | ||
| 201 | for (auto* server_object : server_objects_) { | ||
| 202 | server_object->Close(); | ||
| 203 | } | ||
| 204 | |||
| 205 | // Ensures all service threads gracefully shutdown. | 195 | // Ensures all service threads gracefully shutdown. |
| 206 | ClearServiceThreads(); | 196 | ClearServiceThreads(); |
| 207 | } | 197 | } |
| @@ -419,6 +409,8 @@ struct KernelCore::Impl { | |||
| 419 | return this_id; | 409 | return this_id; |
| 420 | } | 410 | } |
| 421 | 411 | ||
| 412 | static inline thread_local bool is_phantom_mode_for_singlecore{false}; | ||
| 413 | |||
| 422 | bool IsPhantomModeForSingleCore() const { | 414 | bool IsPhantomModeForSingleCore() const { |
| 423 | return is_phantom_mode_for_singlecore; | 415 | return is_phantom_mode_for_singlecore; |
| 424 | } | 416 | } |
| @@ -775,24 +767,21 @@ struct KernelCore::Impl { | |||
| 775 | return {}; | 767 | return {}; |
| 776 | } | 768 | } |
| 777 | 769 | ||
| 778 | KClientPort* port = &search->second(system.ServiceManager(), system); | 770 | return &search->second(system.ServiceManager(), system); |
| 779 | RegisterServerObject(&port->GetParent()->GetServerPort()); | ||
| 780 | return port; | ||
| 781 | } | 771 | } |
| 782 | 772 | ||
| 783 | void RegisterServerObject(KAutoObject* server_object) { | 773 | void RegisterNamedServiceHandler(std::string name, KServerPort* server_port) { |
| 784 | std::scoped_lock lk(server_objects_lock); | 774 | auto search = service_interface_handlers.find(name); |
| 785 | server_objects.insert(server_object); | 775 | if (search == service_interface_handlers.end()) { |
| 786 | } | 776 | return; |
| 777 | } | ||
| 787 | 778 | ||
| 788 | void UnregisterServerObject(KAutoObject* server_object) { | 779 | search->second(system.ServiceManager(), server_port); |
| 789 | std::scoped_lock lk(server_objects_lock); | ||
| 790 | server_objects.erase(server_object); | ||
| 791 | } | 780 | } |
| 792 | 781 | ||
| 793 | std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel, | 782 | std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel, |
| 794 | const std::string& name) { | 783 | const std::string& name) { |
| 795 | auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, 1, name); | 784 | auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, name); |
| 796 | 785 | ||
| 797 | service_threads_manager.QueueWork( | 786 | service_threads_manager.QueueWork( |
| 798 | [this, service_thread]() { service_threads.emplace(service_thread); }); | 787 | [this, service_thread]() { service_threads.emplace(service_thread); }); |
| @@ -822,7 +811,6 @@ struct KernelCore::Impl { | |||
| 822 | service_thread_barrier.Sync(); | 811 | service_thread_barrier.Sync(); |
| 823 | } | 812 | } |
| 824 | 813 | ||
| 825 | std::mutex server_objects_lock; | ||
| 826 | std::mutex registered_objects_lock; | 814 | std::mutex registered_objects_lock; |
| 827 | std::mutex registered_in_use_objects_lock; | 815 | std::mutex registered_in_use_objects_lock; |
| 828 | 816 | ||
| @@ -853,8 +841,8 @@ struct KernelCore::Impl { | |||
| 853 | /// Map of named ports managed by the kernel, which can be retrieved using | 841 | /// Map of named ports managed by the kernel, which can be retrieved using |
| 854 | /// the ConnectToPort SVC. | 842 | /// the ConnectToPort SVC. |
| 855 | std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory; | 843 | std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory; |
| 844 | std::unordered_map<std::string, ServiceInterfaceHandlerFn> service_interface_handlers; | ||
| 856 | NamedPortTable named_ports; | 845 | NamedPortTable named_ports; |
| 857 | std::unordered_set<KAutoObject*> server_objects; | ||
| 858 | std::unordered_set<KAutoObject*> registered_objects; | 846 | std::unordered_set<KAutoObject*> registered_objects; |
| 859 | std::unordered_set<KAutoObject*> registered_in_use_objects; | 847 | std::unordered_set<KAutoObject*> registered_in_use_objects; |
| 860 | 848 | ||
| @@ -903,7 +891,6 @@ struct KernelCore::Impl { | |||
| 903 | 891 | ||
| 904 | bool is_multicore{}; | 892 | bool is_multicore{}; |
| 905 | std::atomic_bool is_shutting_down{}; | 893 | std::atomic_bool is_shutting_down{}; |
| 906 | bool is_phantom_mode_for_singlecore{}; | ||
| 907 | u32 single_core_thread_id{}; | 894 | u32 single_core_thread_id{}; |
| 908 | 895 | ||
| 909 | std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; | 896 | std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; |
| @@ -1070,16 +1057,17 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory& | |||
| 1070 | impl->service_interface_factory.emplace(std::move(name), factory); | 1057 | impl->service_interface_factory.emplace(std::move(name), factory); |
| 1071 | } | 1058 | } |
| 1072 | 1059 | ||
| 1073 | KClientPort* KernelCore::CreateNamedServicePort(std::string name) { | 1060 | void KernelCore::RegisterInterfaceForNamedService(std::string name, |
| 1074 | return impl->CreateNamedServicePort(std::move(name)); | 1061 | ServiceInterfaceHandlerFn&& handler) { |
| 1062 | impl->service_interface_handlers.emplace(std::move(name), handler); | ||
| 1075 | } | 1063 | } |
| 1076 | 1064 | ||
| 1077 | void KernelCore::RegisterServerObject(KAutoObject* server_object) { | 1065 | KClientPort* KernelCore::CreateNamedServicePort(std::string name) { |
| 1078 | impl->RegisterServerObject(server_object); | 1066 | return impl->CreateNamedServicePort(std::move(name)); |
| 1079 | } | 1067 | } |
| 1080 | 1068 | ||
| 1081 | void KernelCore::UnregisterServerObject(KAutoObject* server_object) { | 1069 | void KernelCore::RegisterNamedServiceHandler(std::string name, KServerPort* server_port) { |
| 1082 | impl->UnregisterServerObject(server_object); | 1070 | impl->RegisterNamedServiceHandler(std::move(name), server_port); |
| 1083 | } | 1071 | } |
| 1084 | 1072 | ||
| 1085 | void KernelCore::RegisterKernelObject(KAutoObject* object) { | 1073 | void KernelCore::RegisterKernelObject(KAutoObject* object) { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2549503fc..caca60586 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -48,6 +48,7 @@ class KPort; | |||
| 48 | class KProcess; | 48 | class KProcess; |
| 49 | class KResourceLimit; | 49 | class KResourceLimit; |
| 50 | class KScheduler; | 50 | class KScheduler; |
| 51 | class KServerPort; | ||
| 51 | class KServerSession; | 52 | class KServerSession; |
| 52 | class KSession; | 53 | class KSession; |
| 53 | class KSessionRequest; | 54 | class KSessionRequest; |
| @@ -67,6 +68,8 @@ class TimeManager; | |||
| 67 | using ServiceInterfaceFactory = | 68 | using ServiceInterfaceFactory = |
| 68 | std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; | 69 | std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; |
| 69 | 70 | ||
| 71 | using ServiceInterfaceHandlerFn = std::function<void(Service::SM::ServiceManager&, KServerPort*)>; | ||
| 72 | |||
| 70 | namespace Init { | 73 | namespace Init { |
| 71 | struct KSlabResourceCounts; | 74 | struct KSlabResourceCounts; |
| 72 | } | 75 | } |
| @@ -196,16 +199,14 @@ public: | |||
| 196 | /// Registers a named HLE service, passing a factory used to open a port to that service. | 199 | /// Registers a named HLE service, passing a factory used to open a port to that service. |
| 197 | void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory); | 200 | void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory); |
| 198 | 201 | ||
| 202 | /// Registers a setup function for the named HLE service. | ||
| 203 | void RegisterInterfaceForNamedService(std::string name, ServiceInterfaceHandlerFn&& handler); | ||
| 204 | |||
| 199 | /// Opens a port to a service previously registered with RegisterNamedService. | 205 | /// Opens a port to a service previously registered with RegisterNamedService. |
| 200 | KClientPort* CreateNamedServicePort(std::string name); | 206 | KClientPort* CreateNamedServicePort(std::string name); |
| 201 | 207 | ||
| 202 | /// Registers a server session or port with the gobal emulation state, to be freed on shutdown. | 208 | /// Accepts a session on a port created by CreateNamedServicePort. |
| 203 | /// This is necessary because we do not emulate processes for HLE sessions and ports. | 209 | void RegisterNamedServiceHandler(std::string name, KServerPort* server_port); |
| 204 | void RegisterServerObject(KAutoObject* server_object); | ||
| 205 | |||
| 206 | /// Unregisters a server session or port previously registered with RegisterServerSession when | ||
| 207 | /// it was destroyed during the current emulation session. | ||
| 208 | void UnregisterServerObject(KAutoObject* server_object); | ||
| 209 | 210 | ||
| 210 | /// Registers all kernel objects with the global emulation state, this is purely for tracking | 211 | /// Registers all kernel objects with the global emulation state, this is purely for tracking |
| 211 | /// leaks after emulation has been shutdown. | 212 | /// leaks after emulation has been shutdown. |
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index d23d76706..c8fe42537 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp | |||
| @@ -1,15 +1,18 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <condition_variable> | ||
| 5 | #include <functional> | 4 | #include <functional> |
| 5 | #include <map> | ||
| 6 | #include <mutex> | 6 | #include <mutex> |
| 7 | #include <thread> | 7 | #include <thread> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include <queue> | ||
| 10 | 9 | ||
| 11 | #include "common/scope_exit.h" | 10 | #include "common/scope_exit.h" |
| 12 | #include "common/thread.h" | 11 | #include "common/thread.h" |
| 12 | #include "core/hle/ipc_helpers.h" | ||
| 13 | #include "core/hle/kernel/hle_ipc.h" | ||
| 14 | #include "core/hle/kernel/k_event.h" | ||
| 15 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 13 | #include "core/hle/kernel/k_session.h" | 16 | #include "core/hle/kernel/k_session.h" |
| 14 | #include "core/hle/kernel/k_thread.h" | 17 | #include "core/hle/kernel/k_thread.h" |
| 15 | #include "core/hle/kernel/kernel.h" | 18 | #include "core/hle/kernel/kernel.h" |
| @@ -19,101 +22,198 @@ namespace Kernel { | |||
| 19 | 22 | ||
| 20 | class ServiceThread::Impl final { | 23 | class ServiceThread::Impl final { |
| 21 | public: | 24 | public: |
| 22 | explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); | 25 | explicit Impl(KernelCore& kernel, const std::string& service_name); |
| 23 | ~Impl(); | 26 | ~Impl(); |
| 24 | 27 | ||
| 25 | void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); | 28 | void WaitAndProcessImpl(); |
| 29 | void SessionClosed(KServerSession* server_session, | ||
| 30 | std::shared_ptr<SessionRequestManager> manager); | ||
| 31 | void LoopProcess(); | ||
| 32 | |||
| 33 | void RegisterServerSession(KServerSession* session, | ||
| 34 | std::shared_ptr<SessionRequestManager> manager); | ||
| 26 | 35 | ||
| 27 | private: | 36 | private: |
| 28 | std::vector<std::jthread> threads; | 37 | KernelCore& kernel; |
| 29 | std::queue<std::function<void()>> requests; | 38 | |
| 30 | std::mutex queue_mutex; | 39 | std::jthread m_thread; |
| 31 | std::condition_variable_any condition; | 40 | std::mutex m_session_mutex; |
| 32 | const std::string service_name; | 41 | std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions; |
| 42 | KEvent* m_wakeup_event; | ||
| 43 | KProcess* m_process; | ||
| 44 | std::atomic<bool> m_shutdown_requested; | ||
| 45 | const std::string m_service_name; | ||
| 33 | }; | 46 | }; |
| 34 | 47 | ||
| 35 | ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) | 48 | void ServiceThread::Impl::WaitAndProcessImpl() { |
| 36 | : service_name{name} { | 49 | // Create local list of waitable sessions. |
| 37 | for (std::size_t i = 0; i < num_threads; ++i) { | 50 | std::vector<KSynchronizationObject*> objs; |
| 38 | threads.emplace_back([this, &kernel](std::stop_token stop_token) { | 51 | std::vector<std::shared_ptr<SessionRequestManager>> managers; |
| 39 | Common::SetCurrentThreadName(std::string{service_name}.c_str()); | ||
| 40 | 52 | ||
| 41 | // Wait for first request before trying to acquire a render context | 53 | { |
| 42 | { | 54 | // Lock to get the set. |
| 43 | std::unique_lock lock{queue_mutex}; | 55 | std::scoped_lock lk{m_session_mutex}; |
| 44 | condition.wait(lock, stop_token, [this] { return !requests.empty(); }); | ||
| 45 | } | ||
| 46 | 56 | ||
| 47 | if (stop_token.stop_requested()) { | 57 | // Reserve the needed quantity. |
| 48 | return; | 58 | objs.reserve(m_sessions.size() + 1); |
| 49 | } | 59 | managers.reserve(m_sessions.size()); |
| 50 | 60 | ||
| 51 | // Allocate a dummy guest thread for this host thread. | 61 | // Copy to our local list. |
| 52 | kernel.RegisterHostThread(); | 62 | for (const auto& [session, manager] : m_sessions) { |
| 63 | objs.push_back(session); | ||
| 64 | managers.push_back(manager); | ||
| 65 | } | ||
| 53 | 66 | ||
| 54 | while (true) { | 67 | // Insert the wakeup event at the end. |
| 55 | std::function<void()> task; | 68 | objs.push_back(&m_wakeup_event->GetReadableEvent()); |
| 69 | } | ||
| 56 | 70 | ||
| 57 | { | 71 | // Wait on the list of sessions. |
| 58 | std::unique_lock lock{queue_mutex}; | 72 | s32 index{-1}; |
| 59 | condition.wait(lock, stop_token, [this] { return !requests.empty(); }); | 73 | Result rc = KSynchronizationObject::Wait(kernel, &index, objs.data(), |
| 74 | static_cast<s32>(objs.size()), -1); | ||
| 75 | ASSERT(!rc.IsFailure()); | ||
| 76 | |||
| 77 | // If this was the wakeup event, clear it and finish. | ||
| 78 | if (index >= static_cast<s64>(objs.size() - 1)) { | ||
| 79 | m_wakeup_event->Clear(); | ||
| 80 | return; | ||
| 81 | } | ||
| 60 | 82 | ||
| 61 | if (stop_token.stop_requested()) { | 83 | // This event is from a server session. |
| 62 | return; | 84 | auto* server_session = static_cast<KServerSession*>(objs[index]); |
| 63 | } | 85 | auto& manager = managers[index]; |
| 64 | 86 | ||
| 65 | if (requests.empty()) { | 87 | // Fetch the HLE request context. |
| 66 | continue; | 88 | std::shared_ptr<HLERequestContext> context; |
| 67 | } | 89 | rc = server_session->ReceiveRequest(&context, manager); |
| 68 | 90 | ||
| 69 | task = std::move(requests.front()); | 91 | // If the session was closed, handle that. |
| 70 | requests.pop(); | 92 | if (rc == ResultSessionClosed) { |
| 71 | } | 93 | SessionClosed(server_session, manager); |
| 72 | 94 | ||
| 73 | task(); | 95 | // Finish. |
| 74 | } | 96 | return; |
| 75 | }); | ||
| 76 | } | 97 | } |
| 98 | |||
| 99 | // TODO: handle other cases | ||
| 100 | ASSERT(rc == ResultSuccess); | ||
| 101 | |||
| 102 | // Perform the request. | ||
| 103 | Result service_rc = manager->CompleteSyncRequest(server_session, *context); | ||
| 104 | |||
| 105 | // Reply to the client. | ||
| 106 | rc = server_session->SendReplyHLE(); | ||
| 107 | |||
| 108 | if (rc == ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) { | ||
| 109 | SessionClosed(server_session, manager); | ||
| 110 | return; | ||
| 111 | } | ||
| 112 | |||
| 113 | // TODO: handle other cases | ||
| 114 | ASSERT(rc == ResultSuccess); | ||
| 115 | ASSERT(service_rc == ResultSuccess); | ||
| 77 | } | 116 | } |
| 78 | 117 | ||
| 79 | void ServiceThread::Impl::QueueSyncRequest(KSession& session, | 118 | void ServiceThread::Impl::SessionClosed(KServerSession* server_session, |
| 80 | std::shared_ptr<HLERequestContext>&& context) { | 119 | std::shared_ptr<SessionRequestManager> manager) { |
| 81 | { | 120 | { |
| 82 | std::unique_lock lock{queue_mutex}; | 121 | // Lock to get the set. |
| 122 | std::scoped_lock lk{m_session_mutex}; | ||
| 123 | |||
| 124 | // Erase the session. | ||
| 125 | ASSERT(m_sessions.erase(server_session) == 1); | ||
| 126 | } | ||
| 83 | 127 | ||
| 84 | auto* server_session{&session.GetServerSession()}; | 128 | // Close our reference to the server session. |
| 129 | server_session->Close(); | ||
| 130 | } | ||
| 85 | 131 | ||
| 86 | // Open a reference to the session to ensure it is not closes while the service request | 132 | void ServiceThread::Impl::LoopProcess() { |
| 87 | // completes asynchronously. | 133 | Common::SetCurrentThreadName(m_service_name.c_str()); |
| 88 | server_session->Open(); | ||
| 89 | 134 | ||
| 90 | requests.emplace([server_session, context{std::move(context)}]() { | 135 | kernel.RegisterHostThread(); |
| 91 | // Close the reference. | ||
| 92 | SCOPE_EXIT({ server_session->Close(); }); | ||
| 93 | 136 | ||
| 94 | // Complete the service request. | 137 | while (!m_shutdown_requested.load()) { |
| 95 | server_session->CompleteSyncRequest(*context); | 138 | WaitAndProcessImpl(); |
| 96 | }); | ||
| 97 | } | 139 | } |
| 98 | condition.notify_one(); | 140 | } |
| 141 | |||
| 142 | void ServiceThread::Impl::RegisterServerSession(KServerSession* server_session, | ||
| 143 | std::shared_ptr<SessionRequestManager> manager) { | ||
| 144 | // Open the server session. | ||
| 145 | server_session->Open(); | ||
| 146 | |||
| 147 | { | ||
| 148 | // Lock to get the set. | ||
| 149 | std::scoped_lock lk{m_session_mutex}; | ||
| 150 | |||
| 151 | // Insert the session and manager. | ||
| 152 | m_sessions[server_session] = manager; | ||
| 153 | } | ||
| 154 | |||
| 155 | // Signal the wakeup event. | ||
| 156 | m_wakeup_event->Signal(); | ||
| 99 | } | 157 | } |
| 100 | 158 | ||
| 101 | ServiceThread::Impl::~Impl() { | 159 | ServiceThread::Impl::~Impl() { |
| 102 | condition.notify_all(); | 160 | // Shut down the processing thread. |
| 103 | for (auto& thread : threads) { | 161 | m_shutdown_requested.store(true); |
| 104 | thread.request_stop(); | 162 | m_wakeup_event->Signal(); |
| 105 | thread.join(); | 163 | m_thread.join(); |
| 164 | |||
| 165 | // Lock mutex. | ||
| 166 | m_session_mutex.lock(); | ||
| 167 | |||
| 168 | // Close all remaining sessions. | ||
| 169 | for (const auto& [server_session, manager] : m_sessions) { | ||
| 170 | server_session->Close(); | ||
| 106 | } | 171 | } |
| 172 | |||
| 173 | // Destroy remaining managers. | ||
| 174 | m_sessions.clear(); | ||
| 175 | |||
| 176 | // Close event. | ||
| 177 | m_wakeup_event->GetReadableEvent().Close(); | ||
| 178 | m_wakeup_event->Close(); | ||
| 179 | |||
| 180 | // Close process. | ||
| 181 | m_process->Close(); | ||
| 182 | } | ||
| 183 | |||
| 184 | ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name) | ||
| 185 | : kernel{kernel_}, m_service_name{service_name} { | ||
| 186 | // Initialize process. | ||
| 187 | m_process = KProcess::Create(kernel); | ||
| 188 | KProcess::Initialize(m_process, kernel.System(), service_name, | ||
| 189 | KProcess::ProcessType::KernelInternal, kernel.GetSystemResourceLimit()); | ||
| 190 | |||
| 191 | // Reserve a new event from the process resource limit | ||
| 192 | KScopedResourceReservation event_reservation(m_process, LimitableResource::Events); | ||
| 193 | ASSERT(event_reservation.Succeeded()); | ||
| 194 | |||
| 195 | // Initialize event. | ||
| 196 | m_wakeup_event = KEvent::Create(kernel); | ||
| 197 | m_wakeup_event->Initialize(m_process); | ||
| 198 | |||
| 199 | // Commit the event reservation. | ||
| 200 | event_reservation.Commit(); | ||
| 201 | |||
| 202 | // Register the event. | ||
| 203 | KEvent::Register(kernel, m_wakeup_event); | ||
| 204 | |||
| 205 | // Start thread. | ||
| 206 | m_thread = std::jthread([this] { LoopProcess(); }); | ||
| 107 | } | 207 | } |
| 108 | 208 | ||
| 109 | ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name) | 209 | ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name) |
| 110 | : impl{std::make_unique<Impl>(kernel, num_threads, name)} {} | 210 | : impl{std::make_unique<Impl>(kernel, name)} {} |
| 111 | 211 | ||
| 112 | ServiceThread::~ServiceThread() = default; | 212 | ServiceThread::~ServiceThread() = default; |
| 113 | 213 | ||
| 114 | void ServiceThread::QueueSyncRequest(KSession& session, | 214 | void ServiceThread::RegisterServerSession(KServerSession* session, |
| 115 | std::shared_ptr<HLERequestContext>&& context) { | 215 | std::shared_ptr<SessionRequestManager> manager) { |
| 116 | impl->QueueSyncRequest(session, std::move(context)); | 216 | impl->RegisterServerSession(session, manager); |
| 117 | } | 217 | } |
| 118 | 218 | ||
| 119 | } // namespace Kernel | 219 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h index c5896f2bd..fb4325531 100644 --- a/src/core/hle/kernel/service_thread.h +++ b/src/core/hle/kernel/service_thread.h | |||
| @@ -11,13 +11,15 @@ namespace Kernel { | |||
| 11 | class HLERequestContext; | 11 | class HLERequestContext; |
| 12 | class KernelCore; | 12 | class KernelCore; |
| 13 | class KSession; | 13 | class KSession; |
| 14 | class SessionRequestManager; | ||
| 14 | 15 | ||
| 15 | class ServiceThread final { | 16 | class ServiceThread final { |
| 16 | public: | 17 | public: |
| 17 | explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); | 18 | explicit ServiceThread(KernelCore& kernel, const std::string& name); |
| 18 | ~ServiceThread(); | 19 | ~ServiceThread(); |
| 19 | 20 | ||
| 20 | void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); | 21 | void RegisterServerSession(KServerSession* session, |
| 22 | std::shared_ptr<SessionRequestManager> manager); | ||
| 21 | 23 | ||
| 22 | private: | 24 | private: |
| 23 | class Impl; | 25 | class Impl; |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 319c9f572..ecac97a52 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "core/hle/kernel/k_memory_block.h" | 24 | #include "core/hle/kernel/k_memory_block.h" |
| 25 | #include "core/hle/kernel/k_memory_layout.h" | 25 | #include "core/hle/kernel/k_memory_layout.h" |
| 26 | #include "core/hle/kernel/k_page_table.h" | 26 | #include "core/hle/kernel/k_page_table.h" |
| 27 | #include "core/hle/kernel/k_port.h" | ||
| 27 | #include "core/hle/kernel/k_process.h" | 28 | #include "core/hle/kernel/k_process.h" |
| 28 | #include "core/hle/kernel/k_readable_event.h" | 29 | #include "core/hle/kernel/k_readable_event.h" |
| 29 | #include "core/hle/kernel/k_resource_limit.h" | 30 | #include "core/hle/kernel/k_resource_limit.h" |
| @@ -382,9 +383,9 @@ static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_n | |||
| 382 | 383 | ||
| 383 | // Create a session. | 384 | // Create a session. |
| 384 | KClientSession* session{}; | 385 | KClientSession* session{}; |
| 385 | R_TRY(port->CreateSession(std::addressof(session), | 386 | R_TRY(port->CreateSession(std::addressof(session))); |
| 386 | std::make_shared<SessionRequestManager>(kernel))); | 387 | |
| 387 | port->Close(); | 388 | kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort()); |
| 388 | 389 | ||
| 389 | // Register the session in the table, close the extra reference. | 390 | // Register the session in the table, close the extra reference. |
| 390 | handle_table.Register(*out, session); | 391 | handle_table.Register(*out, session); |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5db6588e4..5ab41c0c4 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -99,6 +99,12 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se | |||
| 99 | ServiceFrameworkBase::~ServiceFrameworkBase() { | 99 | ServiceFrameworkBase::~ServiceFrameworkBase() { |
| 100 | // Wait for other threads to release access before destroying | 100 | // Wait for other threads to release access before destroying |
| 101 | const auto guard = LockService(); | 101 | const auto guard = LockService(); |
| 102 | |||
| 103 | if (named_port != nullptr) { | ||
| 104 | named_port->GetClientPort().Close(); | ||
| 105 | named_port->GetServerPort().Close(); | ||
| 106 | named_port = nullptr; | ||
| 107 | } | ||
| 102 | } | 108 | } |
| 103 | 109 | ||
| 104 | void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { | 110 | void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { |
| @@ -113,15 +119,16 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) | |||
| 113 | Kernel::KClientPort& ServiceFrameworkBase::CreatePort() { | 119 | Kernel::KClientPort& ServiceFrameworkBase::CreatePort() { |
| 114 | const auto guard = LockService(); | 120 | const auto guard = LockService(); |
| 115 | 121 | ||
| 116 | ASSERT(!service_registered); | 122 | if (named_port == nullptr) { |
| 123 | ASSERT(!service_registered); | ||
| 117 | 124 | ||
| 118 | auto* port = Kernel::KPort::Create(kernel); | 125 | named_port = Kernel::KPort::Create(kernel); |
| 119 | port->Initialize(max_sessions, false, service_name); | 126 | named_port->Initialize(max_sessions, false, service_name); |
| 120 | port->GetServerPort().SetSessionHandler(shared_from_this()); | ||
| 121 | 127 | ||
| 122 | service_registered = true; | 128 | service_registered = true; |
| 129 | } | ||
| 123 | 130 | ||
| 124 | return port->GetClientPort(); | 131 | return named_port->GetClientPort(); |
| 125 | } | 132 | } |
| 126 | 133 | ||
| 127 | void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { | 134 | void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { |
| @@ -199,7 +206,6 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, | |||
| 199 | switch (ctx.GetCommandType()) { | 206 | switch (ctx.GetCommandType()) { |
| 200 | case IPC::CommandType::Close: | 207 | case IPC::CommandType::Close: |
| 201 | case IPC::CommandType::TIPC_Close: { | 208 | case IPC::CommandType::TIPC_Close: { |
| 202 | session.Close(); | ||
| 203 | IPC::ResponseBuilder rb{ctx, 2}; | 209 | IPC::ResponseBuilder rb{ctx, 2}; |
| 204 | rb.Push(ResultSuccess); | 210 | rb.Push(ResultSuccess); |
| 205 | result = IPC::ERR_REMOTE_PROCESS_DEAD; | 211 | result = IPC::ERR_REMOTE_PROCESS_DEAD; |
| @@ -244,6 +250,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system | |||
| 244 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); | 250 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); |
| 245 | 251 | ||
| 246 | system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory); | 252 | system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory); |
| 253 | system.Kernel().RegisterInterfaceForNamedService("sm:", SM::ServiceManager::SessionHandler); | ||
| 247 | 254 | ||
| 248 | Account::InstallInterfaces(system); | 255 | Account::InstallInterfaces(system); |
| 249 | AM::InstallInterfaces(*sm, *nv_flinger, system); | 256 | AM::InstallInterfaces(*sm, *nv_flinger, system); |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index ec9deeee4..22e2119d7 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -20,6 +20,7 @@ class System; | |||
| 20 | namespace Kernel { | 20 | namespace Kernel { |
| 21 | class HLERequestContext; | 21 | class HLERequestContext; |
| 22 | class KClientPort; | 22 | class KClientPort; |
| 23 | class KPort; | ||
| 23 | class KServerSession; | 24 | class KServerSession; |
| 24 | class ServiceThread; | 25 | class ServiceThread; |
| 25 | } // namespace Kernel | 26 | } // namespace Kernel |
| @@ -98,6 +99,9 @@ protected: | |||
| 98 | /// Identifier string used to connect to the service. | 99 | /// Identifier string used to connect to the service. |
| 99 | std::string service_name; | 100 | std::string service_name; |
| 100 | 101 | ||
| 102 | /// Port used by ManageNamedPort. | ||
| 103 | Kernel::KPort* named_port{}; | ||
| 104 | |||
| 101 | private: | 105 | private: |
| 102 | template <typename T> | 106 | template <typename T> |
| 103 | friend class ServiceFramework; | 107 | friend class ServiceFramework; |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index cb6c0e96f..84720094f 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -23,7 +23,13 @@ constexpr Result ERR_INVALID_NAME(ErrorModule::SM, 6); | |||
| 23 | constexpr Result ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); | 23 | constexpr Result ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); |
| 24 | 24 | ||
| 25 | ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {} | 25 | ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {} |
| 26 | ServiceManager::~ServiceManager() = default; | 26 | |
| 27 | ServiceManager::~ServiceManager() { | ||
| 28 | for (auto& [name, port] : service_ports) { | ||
| 29 | port->GetClientPort().Close(); | ||
| 30 | port->GetServerPort().Close(); | ||
| 31 | } | ||
| 32 | } | ||
| 27 | 33 | ||
| 28 | void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { | 34 | void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { |
| 29 | controller_interface->InvokeRequest(context); | 35 | controller_interface->InvokeRequest(context); |
| @@ -43,6 +49,10 @@ Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core | |||
| 43 | return self.sm_interface->CreatePort(); | 49 | return self.sm_interface->CreatePort(); |
| 44 | } | 50 | } |
| 45 | 51 | ||
| 52 | void ServiceManager::SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port) { | ||
| 53 | self.sm_interface->AcceptSession(server_port); | ||
| 54 | } | ||
| 55 | |||
| 46 | Result ServiceManager::RegisterService(std::string name, u32 max_sessions, | 56 | Result ServiceManager::RegisterService(std::string name, u32 max_sessions, |
| 47 | Kernel::SessionRequestHandlerPtr handler) { | 57 | Kernel::SessionRequestHandlerPtr handler) { |
| 48 | 58 | ||
| @@ -53,7 +63,11 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions, | |||
| 53 | return ERR_ALREADY_REGISTERED; | 63 | return ERR_ALREADY_REGISTERED; |
| 54 | } | 64 | } |
| 55 | 65 | ||
| 56 | registered_services.emplace(std::move(name), handler); | 66 | auto* port = Kernel::KPort::Create(kernel); |
| 67 | port->Initialize(ServerSessionCountMax, false, name); | ||
| 68 | |||
| 69 | service_ports.emplace(name, port); | ||
| 70 | registered_services.emplace(name, handler); | ||
| 57 | 71 | ||
| 58 | return ResultSuccess; | 72 | return ResultSuccess; |
| 59 | } | 73 | } |
| @@ -68,24 +82,20 @@ Result ServiceManager::UnregisterService(const std::string& name) { | |||
| 68 | } | 82 | } |
| 69 | 83 | ||
| 70 | registered_services.erase(iter); | 84 | registered_services.erase(iter); |
| 85 | service_ports.erase(name); | ||
| 86 | |||
| 71 | return ResultSuccess; | 87 | return ResultSuccess; |
| 72 | } | 88 | } |
| 73 | 89 | ||
| 74 | ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) { | 90 | ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) { |
| 75 | CASCADE_CODE(ValidateServiceName(name)); | 91 | CASCADE_CODE(ValidateServiceName(name)); |
| 76 | auto it = registered_services.find(name); | 92 | auto it = service_ports.find(name); |
| 77 | if (it == registered_services.end()) { | 93 | if (it == service_ports.end()) { |
| 78 | LOG_ERROR(Service_SM, "Server is not registered! service={}", name); | 94 | LOG_ERROR(Service_SM, "Server is not registered! service={}", name); |
| 79 | return ERR_SERVICE_NOT_REGISTERED; | 95 | return ERR_SERVICE_NOT_REGISTERED; |
| 80 | } | 96 | } |
| 81 | 97 | ||
| 82 | auto* port = Kernel::KPort::Create(kernel); | 98 | return it->second; |
| 83 | |||
| 84 | port->Initialize(ServerSessionCountMax, false, name); | ||
| 85 | auto handler = it->second; | ||
| 86 | port->GetServerPort().SetSessionHandler(std::move(handler)); | ||
| 87 | |||
| 88 | return port; | ||
| 89 | } | 99 | } |
| 90 | 100 | ||
| 91 | /** | 101 | /** |
| @@ -144,24 +154,20 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& | |||
| 144 | 154 | ||
| 145 | // Find the named port. | 155 | // Find the named port. |
| 146 | auto port_result = service_manager.GetServicePort(name); | 156 | auto port_result = service_manager.GetServicePort(name); |
| 147 | if (port_result.Failed()) { | 157 | auto service = service_manager.GetService<Kernel::SessionRequestHandler>(name); |
| 158 | if (port_result.Failed() || !service) { | ||
| 148 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw); | 159 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw); |
| 149 | return port_result.Code(); | 160 | return port_result.Code(); |
| 150 | } | 161 | } |
| 151 | auto& port = port_result.Unwrap(); | 162 | auto& port = port_result.Unwrap(); |
| 152 | SCOPE_EXIT({ | ||
| 153 | port->GetClientPort().Close(); | ||
| 154 | port->GetServerPort().Close(); | ||
| 155 | }); | ||
| 156 | 163 | ||
| 157 | // Create a new session. | 164 | // Create a new session. |
| 158 | Kernel::KClientSession* session{}; | 165 | Kernel::KClientSession* session{}; |
| 159 | if (const auto result = port->GetClientPort().CreateSession( | 166 | if (const auto result = port->GetClientPort().CreateSession(&session); result.IsError()) { |
| 160 | std::addressof(session), std::make_shared<Kernel::SessionRequestManager>(kernel)); | ||
| 161 | result.IsError()) { | ||
| 162 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); | 167 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); |
| 163 | return result; | 168 | return result; |
| 164 | } | 169 | } |
| 170 | service->AcceptSession(&port->GetServerPort()); | ||
| 165 | 171 | ||
| 166 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); | 172 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); |
| 167 | 173 | ||
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 878decc6f..02a5dde9e 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -51,6 +51,7 @@ private: | |||
| 51 | class ServiceManager { | 51 | class ServiceManager { |
| 52 | public: | 52 | public: |
| 53 | static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system); | 53 | static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system); |
| 54 | static void SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port); | ||
| 54 | 55 | ||
| 55 | explicit ServiceManager(Kernel::KernelCore& kernel_); | 56 | explicit ServiceManager(Kernel::KernelCore& kernel_); |
| 56 | ~ServiceManager(); | 57 | ~ServiceManager(); |
| @@ -78,6 +79,7 @@ private: | |||
| 78 | 79 | ||
| 79 | /// Map of registered services, retrieved using GetServicePort. | 80 | /// Map of registered services, retrieved using GetServicePort. |
| 80 | std::unordered_map<std::string, Kernel::SessionRequestHandlerPtr> registered_services; | 81 | std::unordered_map<std::string, Kernel::SessionRequestHandlerPtr> registered_services; |
| 82 | std::unordered_map<std::string, Kernel::KPort*> service_ports; | ||
| 81 | 83 | ||
| 82 | /// Kernel context | 84 | /// Kernel context |
| 83 | Kernel::KernelCore& kernel; | 85 | Kernel::KernelCore& kernel; |
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp index 46a8439d8..69e0fe808 100644 --- a/src/core/hle/service/sm/sm_controller.cpp +++ b/src/core/hle/service/sm/sm_controller.cpp | |||
| @@ -15,10 +15,9 @@ | |||
| 15 | namespace Service::SM { | 15 | namespace Service::SM { |
| 16 | 16 | ||
| 17 | void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { | 17 | void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { |
| 18 | ASSERT_MSG(!ctx.Session()->GetSessionRequestManager()->IsDomain(), | 18 | ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Session is already a domain"); |
| 19 | "Session is already a domain"); | ||
| 20 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); | 19 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); |
| 21 | ctx.Session()->GetSessionRequestManager()->ConvertToDomainOnRequestEnd(); | 20 | ctx.GetManager()->ConvertToDomainOnRequestEnd(); |
| 22 | 21 | ||
| 23 | IPC::ResponseBuilder rb{ctx, 3}; | 22 | IPC::ResponseBuilder rb{ctx, 3}; |
| 24 | rb.Push(ResultSuccess); | 23 | rb.Push(ResultSuccess); |
| @@ -29,9 +28,7 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { | |||
| 29 | LOG_DEBUG(Service, "called"); | 28 | LOG_DEBUG(Service, "called"); |
| 30 | 29 | ||
| 31 | auto& process = *ctx.GetThread().GetOwnerProcess(); | 30 | auto& process = *ctx.GetThread().GetOwnerProcess(); |
| 32 | auto& parent_session = *ctx.Session()->GetParent(); | 31 | auto session_manager = ctx.GetManager(); |
| 33 | auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager(); | ||
| 34 | auto& session_handler = session_manager->SessionHandler(); | ||
| 35 | 32 | ||
| 36 | // FIXME: this is duplicated from the SVC, it should just call it instead | 33 | // FIXME: this is duplicated from the SVC, it should just call it instead |
| 37 | // once this is a proper process | 34 | // once this is a proper process |
| @@ -46,13 +43,14 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { | |||
| 46 | ASSERT(session != nullptr); | 43 | ASSERT(session != nullptr); |
| 47 | 44 | ||
| 48 | // Initialize the session. | 45 | // Initialize the session. |
| 49 | session->Initialize(nullptr, parent_session.GetName(), session_manager); | 46 | session->Initialize(nullptr, ""); |
| 50 | 47 | ||
| 51 | // Commit the session reservation. | 48 | // Commit the session reservation. |
| 52 | session_reservation.Commit(); | 49 | session_reservation.Commit(); |
| 53 | 50 | ||
| 54 | // Register the session. | 51 | // Register with manager. |
| 55 | session_handler.ClientConnected(&session->GetServerSession()); | 52 | session_manager->SessionHandler().RegisterSession(&session->GetServerSession(), |
| 53 | session_manager); | ||
| 56 | 54 | ||
| 57 | // We succeeded. | 55 | // We succeeded. |
| 58 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 56 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 7d5d37bbc..1e1c42cea 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp | |||
| @@ -11,6 +11,10 @@ | |||
| 11 | #include "core/internal_network/network_interface.h" | 11 | #include "core/internal_network/network_interface.h" |
| 12 | #include "core/internal_network/socket_proxy.h" | 12 | #include "core/internal_network/socket_proxy.h" |
| 13 | 13 | ||
| 14 | #if YUZU_UNIX | ||
| 15 | #include <sys/socket.h> | ||
| 16 | #endif | ||
| 17 | |||
| 14 | namespace Network { | 18 | namespace Network { |
| 15 | 19 | ||
| 16 | ProxySocket::ProxySocket(RoomNetwork& room_network_) noexcept : room_network{room_network_} {} | 20 | ProxySocket::ProxySocket(RoomNetwork& room_network_) noexcept : room_network{room_network_} {} |
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index bcdd60db9..545d69c7e 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -224,6 +224,7 @@ add_library(shader_recompiler STATIC | |||
| 224 | ir_opt/lower_fp16_to_fp32.cpp | 224 | ir_opt/lower_fp16_to_fp32.cpp |
| 225 | ir_opt/lower_int64_to_int32.cpp | 225 | ir_opt/lower_int64_to_int32.cpp |
| 226 | ir_opt/passes.h | 226 | ir_opt/passes.h |
| 227 | ir_opt/position_pass.cpp | ||
| 227 | ir_opt/rescaling_pass.cpp | 228 | ir_opt/rescaling_pass.cpp |
| 228 | ir_opt/ssa_rewrite_pass.cpp | 229 | ir_opt/ssa_rewrite_pass.cpp |
| 229 | ir_opt/texture_pass.cpp | 230 | ir_opt/texture_pass.cpp |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 01f9abc71..3b0176bf6 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -450,6 +450,9 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I | |||
| 450 | if (program.info.uses_rescaling_uniform) { | 450 | if (program.info.uses_rescaling_uniform) { |
| 451 | header += "PARAM scaling[1]={program.local[0..0]};"; | 451 | header += "PARAM scaling[1]={program.local[0..0]};"; |
| 452 | } | 452 | } |
| 453 | if (program.info.uses_render_area) { | ||
| 454 | header += "PARAM render_area[1]={program.local[1..1]};"; | ||
| 455 | } | ||
| 453 | header += "TEMP "; | 456 | header += "TEMP "; |
| 454 | for (size_t index = 0; index < ctx.reg_alloc.NumUsedRegisters(); ++index) { | 457 | for (size_t index = 0; index < ctx.reg_alloc.NumUsedRegisters(); ++index) { |
| 455 | header += fmt::format("R{},", index); | 458 | header += fmt::format("R{},", index); |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp index 2fc2a0ac6..5bfdecc09 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp | |||
| @@ -43,6 +43,10 @@ void EmitBitCastU64F64(EmitContext&, IR::Inst& inst, const IR::Value& value) { | |||
| 43 | Alias(inst, value); | 43 | Alias(inst, value); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void EmitBitCastS32F32(EmitContext&, IR::Inst& inst, const IR::Value& value) { | ||
| 47 | Alias(inst, value); | ||
| 48 | } | ||
| 49 | |||
| 46 | void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { | 50 | void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) { |
| 47 | Alias(inst, value); | 51 | Alias(inst, value); |
| 48 | } | 52 | } |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index 7e8f37563..0a7d42dda 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp | |||
| @@ -396,6 +396,10 @@ void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) { | |||
| 396 | ctx.Add("MOV.F {}.x,scaling[0].z;", inst); | 396 | ctx.Add("MOV.F {}.x,scaling[0].z;", inst); |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | void EmitRenderArea(EmitContext& ctx, IR::Inst& inst) { | ||
| 400 | ctx.Add("MOV.F {},render_area[0];", inst); | ||
| 401 | } | ||
| 402 | |||
| 399 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset) { | 403 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset) { |
| 400 | ctx.Add("MOV.U {},lmem[{}].x;", inst, word_offset); | 404 | ctx.Add("MOV.U {},lmem[{}].x;", inst, word_offset); |
| 401 | } | 405 | } |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h index 8b0ac3031..d645fd532 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h +++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h | |||
| @@ -73,6 +73,7 @@ void EmitSampleId(EmitContext& ctx, IR::Inst& inst); | |||
| 73 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); | 73 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); |
| 74 | void EmitYDirection(EmitContext& ctx, IR::Inst& inst); | 74 | void EmitYDirection(EmitContext& ctx, IR::Inst& inst); |
| 75 | void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst); | 75 | void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst); |
| 76 | void EmitRenderArea(EmitContext& ctx, IR::Inst& inst); | ||
| 76 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset); | 77 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset); |
| 77 | void EmitWriteLocal(EmitContext& ctx, ScalarU32 word_offset, ScalarU32 value); | 78 | void EmitWriteLocal(EmitContext& ctx, ScalarU32 word_offset, ScalarU32 value); |
| 78 | void EmitUndefU1(EmitContext& ctx, IR::Inst& inst); | 79 | void EmitUndefU1(EmitContext& ctx, IR::Inst& inst); |
| @@ -195,6 +196,7 @@ void EmitSelectF64(EmitContext& ctx, ScalarS32 cond, Register true_value, Regist | |||
| 195 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 196 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 196 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 197 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 197 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 198 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 199 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | ||
| 198 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 200 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 199 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 201 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
| 200 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); | 202 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value); |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp index 1be4a0f59..8e5e6cf1f 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp | |||
| @@ -48,6 +48,10 @@ void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value) | |||
| 48 | ctx.AddU64("{}=doubleBitsToUint64({});", inst, value); | 48 | ctx.AddU64("{}=doubleBitsToUint64({});", inst, value); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | ||
| 52 | ctx.AddF32("{}=ftoi({});", inst, value); | ||
| 53 | } | ||
| 54 | |||
| 51 | void EmitBitCastF16U16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { | 55 | void EmitBitCastF16U16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) { |
| 52 | NotImplemented(); | 56 | NotImplemented(); |
| 53 | } | 57 | } |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index fad8d1e30..d7c845469 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp | |||
| @@ -416,6 +416,10 @@ void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) { | |||
| 416 | ctx.AddF32("{}=scaling.z;", inst); | 416 | ctx.AddF32("{}=scaling.z;", inst); |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | void EmitRenderArea(EmitContext& ctx, IR::Inst& inst) { | ||
| 420 | ctx.AddF32x4("{}=render_area;", inst); | ||
| 421 | } | ||
| 422 | |||
| 419 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset) { | 423 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset) { |
| 420 | ctx.AddU32("{}=lmem[{}];", inst, word_offset); | 424 | ctx.AddU32("{}=lmem[{}];", inst, word_offset); |
| 421 | } | 425 | } |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h index 639691ba6..96e683b5e 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h +++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h | |||
| @@ -87,6 +87,7 @@ void EmitSampleId(EmitContext& ctx, IR::Inst& inst); | |||
| 87 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); | 87 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); |
| 88 | void EmitYDirection(EmitContext& ctx, IR::Inst& inst); | 88 | void EmitYDirection(EmitContext& ctx, IR::Inst& inst); |
| 89 | void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst); | 89 | void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst); |
| 90 | void EmitRenderArea(EmitContext& ctx, IR::Inst& inst); | ||
| 90 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset); | 91 | void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, std::string_view word_offset); |
| 91 | void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_view value); | 92 | void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_view value); |
| 92 | void EmitUndefU1(EmitContext& ctx, IR::Inst& inst); | 93 | void EmitUndefU1(EmitContext& ctx, IR::Inst& inst); |
| @@ -229,6 +230,7 @@ void EmitSelectF64(EmitContext& ctx, IR::Inst& inst, std::string_view cond, | |||
| 229 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst); | 230 | void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst); |
| 230 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 231 | void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 231 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 232 | void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 233 | void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | ||
| 232 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst); | 234 | void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst); |
| 233 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 235 | void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
| 234 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, std::string_view value); | 236 | void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, std::string_view value); |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index c767a9dc3..5d01ec0cd 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | |||
| @@ -358,6 +358,9 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile | |||
| 358 | if (info.uses_rescaling_uniform) { | 358 | if (info.uses_rescaling_uniform) { |
| 359 | header += "layout(location=0) uniform vec4 scaling;"; | 359 | header += "layout(location=0) uniform vec4 scaling;"; |
| 360 | } | 360 | } |
| 361 | if (info.uses_render_area) { | ||
| 362 | header += "layout(location=1) uniform vec4 render_area;"; | ||
| 363 | } | ||
| 361 | DefineConstantBuffers(bindings); | 364 | DefineConstantBuffers(bindings); |
| 362 | DefineConstantBufferIndirect(); | 365 | DefineConstantBufferIndirect(); |
| 363 | DefineStorageBuffers(bindings); | 366 | DefineStorageBuffers(bindings); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 7567b6fc9..937881484 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -23,8 +23,12 @@ struct RescalingLayout { | |||
| 23 | alignas(16) std::array<u32, NUM_IMAGE_SCALING_WORDS> rescaling_images; | 23 | alignas(16) std::array<u32, NUM_IMAGE_SCALING_WORDS> rescaling_images; |
| 24 | u32 down_factor; | 24 | u32 down_factor; |
| 25 | }; | 25 | }; |
| 26 | struct RenderAreaLayout { | ||
| 27 | std::array<f32, 4> render_area; | ||
| 28 | }; | ||
| 26 | constexpr u32 RESCALING_LAYOUT_WORDS_OFFSET = offsetof(RescalingLayout, rescaling_textures); | 29 | constexpr u32 RESCALING_LAYOUT_WORDS_OFFSET = offsetof(RescalingLayout, rescaling_textures); |
| 27 | constexpr u32 RESCALING_LAYOUT_DOWN_FACTOR_OFFSET = offsetof(RescalingLayout, down_factor); | 30 | constexpr u32 RESCALING_LAYOUT_DOWN_FACTOR_OFFSET = offsetof(RescalingLayout, down_factor); |
| 31 | constexpr u32 RENDERAREA_LAYOUT_OFFSET = offsetof(RenderAreaLayout, render_area); | ||
| 28 | 32 | ||
| 29 | [[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, | 33 | [[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, |
| 30 | IR::Program& program, Bindings& bindings); | 34 | IR::Program& program, Bindings& bindings); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp index c4ca28d11..50daacd95 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp | |||
| @@ -18,6 +18,10 @@ void EmitBitCastU64F64(EmitContext&) { | |||
| 18 | throw NotImplementedException("SPIR-V Instruction"); | 18 | throw NotImplementedException("SPIR-V Instruction"); |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | void EmitBitCastS32F32(EmitContext&) { | ||
| 22 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 23 | } | ||
| 24 | |||
| 21 | void EmitBitCastF16U16(EmitContext&) { | 25 | void EmitBitCastF16U16(EmitContext&) { |
| 22 | throw NotImplementedException("SPIR-V Instruction"); | 26 | throw NotImplementedException("SPIR-V Instruction"); |
| 23 | } | 27 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 2c68aba39..a4751b42d 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | |||
| @@ -353,7 +353,6 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { | |||
| 353 | case IR::Attribute::TessellationEvaluationPointV: | 353 | case IR::Attribute::TessellationEvaluationPointV: |
| 354 | return ctx.OpLoad(ctx.F32[1], | 354 | return ctx.OpLoad(ctx.F32[1], |
| 355 | ctx.OpAccessChain(ctx.input_f32, ctx.tess_coord, ctx.Const(1U))); | 355 | ctx.OpAccessChain(ctx.input_f32, ctx.tess_coord, ctx.Const(1U))); |
| 356 | |||
| 357 | default: | 356 | default: |
| 358 | throw NotImplementedException("Read attribute {}", attr); | 357 | throw NotImplementedException("Read attribute {}", attr); |
| 359 | } | 358 | } |
| @@ -537,6 +536,17 @@ Id EmitResolutionDownFactor(EmitContext& ctx) { | |||
| 537 | } | 536 | } |
| 538 | } | 537 | } |
| 539 | 538 | ||
| 539 | Id EmitRenderArea(EmitContext& ctx) { | ||
| 540 | if (ctx.profile.unified_descriptor_binding) { | ||
| 541 | const Id pointer_type{ctx.TypePointer(spv::StorageClass::PushConstant, ctx.F32[4])}; | ||
| 542 | const Id index{ctx.Const(ctx.render_are_member_index)}; | ||
| 543 | const Id pointer{ctx.OpAccessChain(pointer_type, ctx.render_area_push_constant, index)}; | ||
| 544 | return ctx.OpLoad(ctx.F32[4], pointer); | ||
| 545 | } else { | ||
| 546 | throw NotImplementedException("SPIR-V Instruction"); | ||
| 547 | } | ||
| 548 | } | ||
| 549 | |||
| 540 | Id EmitLoadLocal(EmitContext& ctx, Id word_offset) { | 550 | Id EmitLoadLocal(EmitContext& ctx, Id word_offset) { |
| 541 | const Id pointer{ctx.OpAccessChain(ctx.private_u32, ctx.local_memory, word_offset)}; | 551 | const Id pointer{ctx.OpAccessChain(ctx.private_u32, ctx.local_memory, word_offset)}; |
| 542 | return ctx.OpLoad(ctx.U32[1], pointer); | 552 | return ctx.OpLoad(ctx.U32[1], pointer); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 984d072b4..7070c8fda 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h | |||
| @@ -76,6 +76,7 @@ Id EmitSampleId(EmitContext& ctx); | |||
| 76 | Id EmitIsHelperInvocation(EmitContext& ctx); | 76 | Id EmitIsHelperInvocation(EmitContext& ctx); |
| 77 | Id EmitYDirection(EmitContext& ctx); | 77 | Id EmitYDirection(EmitContext& ctx); |
| 78 | Id EmitResolutionDownFactor(EmitContext& ctx); | 78 | Id EmitResolutionDownFactor(EmitContext& ctx); |
| 79 | Id EmitRenderArea(EmitContext& ctx); | ||
| 79 | Id EmitLoadLocal(EmitContext& ctx, Id word_offset); | 80 | Id EmitLoadLocal(EmitContext& ctx, Id word_offset); |
| 80 | void EmitWriteLocal(EmitContext& ctx, Id word_offset, Id value); | 81 | void EmitWriteLocal(EmitContext& ctx, Id word_offset, Id value); |
| 81 | Id EmitUndefU1(EmitContext& ctx); | 82 | Id EmitUndefU1(EmitContext& ctx); |
| @@ -177,7 +178,8 @@ Id EmitSelectF64(EmitContext& ctx, Id cond, Id true_value, Id false_value); | |||
| 177 | void EmitBitCastU16F16(EmitContext& ctx); | 178 | void EmitBitCastU16F16(EmitContext& ctx); |
| 178 | Id EmitBitCastU32F32(EmitContext& ctx, Id value); | 179 | Id EmitBitCastU32F32(EmitContext& ctx, Id value); |
| 179 | void EmitBitCastU64F64(EmitContext& ctx); | 180 | void EmitBitCastU64F64(EmitContext& ctx); |
| 180 | void EmitBitCastF16U16(EmitContext& ctx); | 181 | void EmitBitCastS32F32(EmitContext& ctx); |
| 182 | void EmitBitCastF16U16(EmitContext&); | ||
| 181 | Id EmitBitCastF32U32(EmitContext& ctx, Id value); | 183 | Id EmitBitCastF32U32(EmitContext& ctx, Id value); |
| 182 | void EmitBitCastF64U64(EmitContext& ctx); | 184 | void EmitBitCastF64U64(EmitContext& ctx); |
| 183 | Id EmitPackUint2x32(EmitContext& ctx, Id value); | 185 | Id EmitPackUint2x32(EmitContext& ctx, Id value); |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index aecc4c612..c26ad8f93 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -473,6 +473,7 @@ EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_inf | |||
| 473 | DefineAttributeMemAccess(program.info); | 473 | DefineAttributeMemAccess(program.info); |
| 474 | DefineGlobalMemoryFunctions(program.info); | 474 | DefineGlobalMemoryFunctions(program.info); |
| 475 | DefineRescalingInput(program.info); | 475 | DefineRescalingInput(program.info); |
| 476 | DefineRenderArea(program.info); | ||
| 476 | } | 477 | } |
| 477 | 478 | ||
| 478 | EmitContext::~EmitContext() = default; | 479 | EmitContext::~EmitContext() = default; |
| @@ -982,6 +983,36 @@ void EmitContext::DefineRescalingInputUniformConstant() { | |||
| 982 | } | 983 | } |
| 983 | } | 984 | } |
| 984 | 985 | ||
| 986 | void EmitContext::DefineRenderArea(const Info& info) { | ||
| 987 | if (!info.uses_render_area) { | ||
| 988 | return; | ||
| 989 | } | ||
| 990 | |||
| 991 | if (profile.unified_descriptor_binding) { | ||
| 992 | boost::container::static_vector<Id, 1> members{}; | ||
| 993 | u32 member_index{0}; | ||
| 994 | |||
| 995 | members.push_back(F32[4]); | ||
| 996 | render_are_member_index = member_index++; | ||
| 997 | |||
| 998 | const Id push_constant_struct{TypeStruct(std::span(members.data(), members.size()))}; | ||
| 999 | Decorate(push_constant_struct, spv::Decoration::Block); | ||
| 1000 | Name(push_constant_struct, "RenderAreaInfo"); | ||
| 1001 | |||
| 1002 | MemberDecorate(push_constant_struct, render_are_member_index, spv::Decoration::Offset, 0); | ||
| 1003 | MemberName(push_constant_struct, render_are_member_index, "render_area"); | ||
| 1004 | |||
| 1005 | const Id pointer_type{TypePointer(spv::StorageClass::PushConstant, push_constant_struct)}; | ||
| 1006 | render_area_push_constant = | ||
| 1007 | AddGlobalVariable(pointer_type, spv::StorageClass::PushConstant); | ||
| 1008 | Name(render_area_push_constant, "render_area_push_constants"); | ||
| 1009 | |||
| 1010 | if (profile.supported_spirv >= 0x00010400) { | ||
| 1011 | interfaces.push_back(render_area_push_constant); | ||
| 1012 | } | ||
| 1013 | } | ||
| 1014 | } | ||
| 1015 | |||
| 985 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | 1016 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { |
| 986 | if (info.constant_buffer_descriptors.empty()) { | 1017 | if (info.constant_buffer_descriptors.empty()) { |
| 987 | return; | 1018 | return; |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index bc25b8b84..c86e50911 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h | |||
| @@ -243,6 +243,9 @@ public: | |||
| 243 | u32 texture_rescaling_index{}; | 243 | u32 texture_rescaling_index{}; |
| 244 | u32 image_rescaling_index{}; | 244 | u32 image_rescaling_index{}; |
| 245 | 245 | ||
| 246 | Id render_area_push_constant{}; | ||
| 247 | u32 render_are_member_index{}; | ||
| 248 | |||
| 246 | Id local_memory{}; | 249 | Id local_memory{}; |
| 247 | 250 | ||
| 248 | Id shared_memory_u8{}; | 251 | Id shared_memory_u8{}; |
| @@ -318,6 +321,7 @@ private: | |||
| 318 | void DefineRescalingInput(const Info& info); | 321 | void DefineRescalingInput(const Info& info); |
| 319 | void DefineRescalingInputPushConstant(); | 322 | void DefineRescalingInputPushConstant(); |
| 320 | void DefineRescalingInputUniformConstant(); | 323 | void DefineRescalingInputUniformConstant(); |
| 324 | void DefineRenderArea(const Info& info); | ||
| 321 | 325 | ||
| 322 | void DefineInputs(const IR::Program& program); | 326 | void DefineInputs(const IR::Program& program); |
| 323 | void DefineOutputs(const IR::Program& program); | 327 | void DefineOutputs(const IR::Program& program); |
diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h index 9729d48c6..402f2664f 100644 --- a/src/shader_recompiler/environment.h +++ b/src/shader_recompiler/environment.h | |||
| @@ -22,6 +22,10 @@ public: | |||
| 22 | 22 | ||
| 23 | [[nodiscard]] virtual TextureType ReadTextureType(u32 raw_handle) = 0; | 23 | [[nodiscard]] virtual TextureType ReadTextureType(u32 raw_handle) = 0; |
| 24 | 24 | ||
| 25 | [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; | ||
| 26 | |||
| 27 | [[nodiscard]] virtual u32 ReadViewportTransformState() = 0; | ||
| 28 | |||
| 25 | [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; | 29 | [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; |
| 26 | 30 | ||
| 27 | [[nodiscard]] virtual u32 LocalMemorySize() const = 0; | 31 | [[nodiscard]] virtual u32 LocalMemorySize() const = 0; |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 11086ed8c..d4425f06d 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -378,6 +378,14 @@ F32 IREmitter::ResolutionDownFactor() { | |||
| 378 | return Inst<F32>(Opcode::ResolutionDownFactor); | 378 | return Inst<F32>(Opcode::ResolutionDownFactor); |
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | F32 IREmitter::RenderAreaWidth() { | ||
| 382 | return F32(CompositeExtract(Inst<Value>(Opcode::RenderArea), 0)); | ||
| 383 | } | ||
| 384 | |||
| 385 | F32 IREmitter::RenderAreaHeight() { | ||
| 386 | return F32(CompositeExtract(Inst<Value>(Opcode::RenderArea), 1)); | ||
| 387 | } | ||
| 388 | |||
| 381 | U32 IREmitter::LaneId() { | 389 | U32 IREmitter::LaneId() { |
| 382 | return Inst<U32>(Opcode::LaneId); | 390 | return Inst<U32>(Opcode::LaneId); |
| 383 | } | 391 | } |
| @@ -684,6 +692,11 @@ IR::U32 IREmitter::BitCast<IR::U32, IR::F32>(const IR::F32& value) { | |||
| 684 | } | 692 | } |
| 685 | 693 | ||
| 686 | template <> | 694 | template <> |
| 695 | IR::S32 IREmitter::BitCast<IR::S32, IR::F32>(const IR::F32& value) { | ||
| 696 | return Inst<IR::S32>(Opcode::BitCastS32F32, value); | ||
| 697 | } | ||
| 698 | |||
| 699 | template <> | ||
| 687 | IR::F32 IREmitter::BitCast<IR::F32, IR::U32>(const IR::U32& value) { | 700 | IR::F32 IREmitter::BitCast<IR::F32, IR::U32>(const IR::U32& value) { |
| 688 | return Inst<IR::F32>(Opcode::BitCastF32U32, value); | 701 | return Inst<IR::F32>(Opcode::BitCastF32U32, value); |
| 689 | } | 702 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 25839a371..f163c18d9 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -103,6 +103,9 @@ public: | |||
| 103 | 103 | ||
| 104 | [[nodiscard]] F32 ResolutionDownFactor(); | 104 | [[nodiscard]] F32 ResolutionDownFactor(); |
| 105 | 105 | ||
| 106 | [[nodiscard]] F32 RenderAreaWidth(); | ||
| 107 | [[nodiscard]] F32 RenderAreaHeight(); | ||
| 108 | |||
| 106 | [[nodiscard]] U32 LaneId(); | 109 | [[nodiscard]] U32 LaneId(); |
| 107 | 110 | ||
| 108 | [[nodiscard]] U32 LoadGlobalU8(const U64& address); | 111 | [[nodiscard]] U32 LoadGlobalU8(const U64& address); |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h index 752879a18..e70d7745c 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.h +++ b/src/shader_recompiler/frontend/ir/opcodes.h | |||
| @@ -37,6 +37,7 @@ constexpr Type U8{Type::U8}; | |||
| 37 | constexpr Type U16{Type::U16}; | 37 | constexpr Type U16{Type::U16}; |
| 38 | constexpr Type U32{Type::U32}; | 38 | constexpr Type U32{Type::U32}; |
| 39 | constexpr Type U64{Type::U64}; | 39 | constexpr Type U64{Type::U64}; |
| 40 | constexpr Type S32{Type::S32}; | ||
| 40 | constexpr Type F16{Type::F16}; | 41 | constexpr Type F16{Type::F16}; |
| 41 | constexpr Type F32{Type::F32}; | 42 | constexpr Type F32{Type::F32}; |
| 42 | constexpr Type F64{Type::F64}; | 43 | constexpr Type F64{Type::F64}; |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 86410ddfc..88aa077ee 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -63,6 +63,7 @@ OPCODE(SampleId, U32, | |||
| 63 | OPCODE(IsHelperInvocation, U1, ) | 63 | OPCODE(IsHelperInvocation, U1, ) |
| 64 | OPCODE(YDirection, F32, ) | 64 | OPCODE(YDirection, F32, ) |
| 65 | OPCODE(ResolutionDownFactor, F32, ) | 65 | OPCODE(ResolutionDownFactor, F32, ) |
| 66 | OPCODE(RenderArea, F32x4, ) | ||
| 66 | 67 | ||
| 67 | // Undefined | 68 | // Undefined |
| 68 | OPCODE(UndefU1, U1, ) | 69 | OPCODE(UndefU1, U1, ) |
| @@ -173,6 +174,7 @@ OPCODE(SelectF64, F64, U1, | |||
| 173 | OPCODE(BitCastU16F16, U16, F16, ) | 174 | OPCODE(BitCastU16F16, U16, F16, ) |
| 174 | OPCODE(BitCastU32F32, U32, F32, ) | 175 | OPCODE(BitCastU32F32, U32, F32, ) |
| 175 | OPCODE(BitCastU64F64, U64, F64, ) | 176 | OPCODE(BitCastU64F64, U64, F64, ) |
| 177 | OPCODE(BitCastS32F32, S32, F32, ) | ||
| 176 | OPCODE(BitCastF16U16, F16, U16, ) | 178 | OPCODE(BitCastF16U16, F16, U16, ) |
| 177 | OPCODE(BitCastF32U32, F32, U32, ) | 179 | OPCODE(BitCastF32U32, F32, U32, ) |
| 178 | OPCODE(BitCastF64U64, F64, U64, ) | 180 | OPCODE(BitCastF64U64, F64, U64, ) |
diff --git a/src/shader_recompiler/frontend/ir/type.h b/src/shader_recompiler/frontend/ir/type.h index 04c8c4ddb..5a7c706ad 100644 --- a/src/shader_recompiler/frontend/ir/type.h +++ b/src/shader_recompiler/frontend/ir/type.h | |||
| @@ -24,21 +24,22 @@ enum class Type { | |||
| 24 | U16 = 1 << 7, | 24 | U16 = 1 << 7, |
| 25 | U32 = 1 << 8, | 25 | U32 = 1 << 8, |
| 26 | U64 = 1 << 9, | 26 | U64 = 1 << 9, |
| 27 | F16 = 1 << 10, | 27 | S32 = 1 << 10, |
| 28 | F32 = 1 << 11, | 28 | F16 = 1 << 11, |
| 29 | F64 = 1 << 12, | 29 | F32 = 1 << 12, |
| 30 | U32x2 = 1 << 13, | 30 | F64 = 1 << 13, |
| 31 | U32x3 = 1 << 14, | 31 | U32x2 = 1 << 14, |
| 32 | U32x4 = 1 << 15, | 32 | U32x3 = 1 << 15, |
| 33 | F16x2 = 1 << 16, | 33 | U32x4 = 1 << 16, |
| 34 | F16x3 = 1 << 17, | 34 | F16x2 = 1 << 17, |
| 35 | F16x4 = 1 << 18, | 35 | F16x3 = 1 << 18, |
| 36 | F32x2 = 1 << 19, | 36 | F16x4 = 1 << 19, |
| 37 | F32x3 = 1 << 20, | 37 | F32x2 = 1 << 20, |
| 38 | F32x4 = 1 << 21, | 38 | F32x3 = 1 << 21, |
| 39 | F64x2 = 1 << 22, | 39 | F32x4 = 1 << 22, |
| 40 | F64x3 = 1 << 23, | 40 | F64x2 = 1 << 23, |
| 41 | F64x4 = 1 << 24, | 41 | F64x3 = 1 << 24, |
| 42 | F64x4 = 1 << 25, | ||
| 42 | }; | 43 | }; |
| 43 | DECLARE_ENUM_FLAG_OPERATORS(Type) | 44 | DECLARE_ENUM_FLAG_OPERATORS(Type) |
| 44 | 45 | ||
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp index 346169328..30ba12316 100644 --- a/src/shader_recompiler/frontend/ir/value.cpp +++ b/src/shader_recompiler/frontend/ir/value.cpp | |||
| @@ -23,6 +23,8 @@ Value::Value(u16 value) noexcept : type{Type::U16}, imm_u16{value} {} | |||
| 23 | 23 | ||
| 24 | Value::Value(u32 value) noexcept : type{Type::U32}, imm_u32{value} {} | 24 | Value::Value(u32 value) noexcept : type{Type::U32}, imm_u32{value} {} |
| 25 | 25 | ||
| 26 | Value::Value(s32 value) noexcept : type{Type::S32}, imm_s32{value} {} | ||
| 27 | |||
| 26 | Value::Value(f32 value) noexcept : type{Type::F32}, imm_f32{value} {} | 28 | Value::Value(f32 value) noexcept : type{Type::F32}, imm_f32{value} {} |
| 27 | 29 | ||
| 28 | Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {} | 30 | Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {} |
| @@ -69,6 +71,7 @@ bool Value::operator==(const Value& other) const { | |||
| 69 | return imm_u16 == other.imm_u16; | 71 | return imm_u16 == other.imm_u16; |
| 70 | case Type::U32: | 72 | case Type::U32: |
| 71 | case Type::F32: | 73 | case Type::F32: |
| 74 | case Type::S32: | ||
| 72 | return imm_u32 == other.imm_u32; | 75 | return imm_u32 == other.imm_u32; |
| 73 | case Type::U64: | 76 | case Type::U64: |
| 74 | case Type::F64: | 77 | case Type::F64: |
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index 6a673ca05..e8bbb93a5 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h | |||
| @@ -44,6 +44,7 @@ public: | |||
| 44 | explicit Value(u8 value) noexcept; | 44 | explicit Value(u8 value) noexcept; |
| 45 | explicit Value(u16 value) noexcept; | 45 | explicit Value(u16 value) noexcept; |
| 46 | explicit Value(u32 value) noexcept; | 46 | explicit Value(u32 value) noexcept; |
| 47 | explicit Value(s32 value) noexcept; | ||
| 47 | explicit Value(f32 value) noexcept; | 48 | explicit Value(f32 value) noexcept; |
| 48 | explicit Value(u64 value) noexcept; | 49 | explicit Value(u64 value) noexcept; |
| 49 | explicit Value(f64 value) noexcept; | 50 | explicit Value(f64 value) noexcept; |
| @@ -66,6 +67,7 @@ public: | |||
| 66 | [[nodiscard]] u8 U8() const; | 67 | [[nodiscard]] u8 U8() const; |
| 67 | [[nodiscard]] u16 U16() const; | 68 | [[nodiscard]] u16 U16() const; |
| 68 | [[nodiscard]] u32 U32() const; | 69 | [[nodiscard]] u32 U32() const; |
| 70 | [[nodiscard]] s32 S32() const; | ||
| 69 | [[nodiscard]] f32 F32() const; | 71 | [[nodiscard]] f32 F32() const; |
| 70 | [[nodiscard]] u64 U64() const; | 72 | [[nodiscard]] u64 U64() const; |
| 71 | [[nodiscard]] f64 F64() const; | 73 | [[nodiscard]] f64 F64() const; |
| @@ -85,6 +87,7 @@ private: | |||
| 85 | u8 imm_u8; | 87 | u8 imm_u8; |
| 86 | u16 imm_u16; | 88 | u16 imm_u16; |
| 87 | u32 imm_u32; | 89 | u32 imm_u32; |
| 90 | s32 imm_s32; | ||
| 88 | f32 imm_f32; | 91 | f32 imm_f32; |
| 89 | u64 imm_u64; | 92 | u64 imm_u64; |
| 90 | f64 imm_f64; | 93 | f64 imm_f64; |
| @@ -266,6 +269,7 @@ using U8 = TypedValue<Type::U8>; | |||
| 266 | using U16 = TypedValue<Type::U16>; | 269 | using U16 = TypedValue<Type::U16>; |
| 267 | using U32 = TypedValue<Type::U32>; | 270 | using U32 = TypedValue<Type::U32>; |
| 268 | using U64 = TypedValue<Type::U64>; | 271 | using U64 = TypedValue<Type::U64>; |
| 272 | using S32 = TypedValue<Type::S32>; | ||
| 269 | using F16 = TypedValue<Type::F16>; | 273 | using F16 = TypedValue<Type::F16>; |
| 270 | using F32 = TypedValue<Type::F32>; | 274 | using F32 = TypedValue<Type::F32>; |
| 271 | using F64 = TypedValue<Type::F64>; | 275 | using F64 = TypedValue<Type::F64>; |
| @@ -377,6 +381,14 @@ inline u32 Value::U32() const { | |||
| 377 | return imm_u32; | 381 | return imm_u32; |
| 378 | } | 382 | } |
| 379 | 383 | ||
| 384 | inline s32 Value::S32() const { | ||
| 385 | if (IsIdentity()) { | ||
| 386 | return inst->Arg(0).S32(); | ||
| 387 | } | ||
| 388 | DEBUG_ASSERT(type == Type::S32); | ||
| 389 | return imm_s32; | ||
| 390 | } | ||
| 391 | |||
| 380 | inline f32 Value::F32() const { | 392 | inline f32 Value::F32() const { |
| 381 | if (IsIdentity()) { | 393 | if (IsIdentity()) { |
| 382 | return inst->Arg(0).F32(); | 394 | return inst->Arg(0).F32(); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index b58741d4d..b7162f719 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp | |||
| @@ -220,6 +220,8 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 220 | 220 | ||
| 221 | Optimization::ConstantPropagationPass(program); | 221 | Optimization::ConstantPropagationPass(program); |
| 222 | 222 | ||
| 223 | Optimization::PositionPass(env, program); | ||
| 224 | |||
| 223 | Optimization::GlobalMemoryToStorageBufferPass(program); | 225 | Optimization::GlobalMemoryToStorageBufferPass(program); |
| 224 | Optimization::TexturePass(env, program); | 226 | Optimization::TexturePass(env, program); |
| 225 | 227 | ||
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index 6ff8e4266..24f609d69 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h | |||
| @@ -17,6 +17,7 @@ void LowerFp16ToFp32(IR::Program& program); | |||
| 17 | void LowerInt64ToInt32(IR::Program& program); | 17 | void LowerInt64ToInt32(IR::Program& program); |
| 18 | void RescalingPass(IR::Program& program); | 18 | void RescalingPass(IR::Program& program); |
| 19 | void SsaRewritePass(IR::Program& program); | 19 | void SsaRewritePass(IR::Program& program); |
| 20 | void PositionPass(Environment& env, IR::Program& program); | ||
| 20 | void TexturePass(Environment& env, IR::Program& program); | 21 | void TexturePass(Environment& env, IR::Program& program); |
| 21 | void VerificationPass(const IR::Program& program); | 22 | void VerificationPass(const IR::Program& program); |
| 22 | 23 | ||
diff --git a/src/shader_recompiler/ir_opt/position_pass.cpp b/src/shader_recompiler/ir_opt/position_pass.cpp new file mode 100644 index 000000000..3c20b7189 --- /dev/null +++ b/src/shader_recompiler/ir_opt/position_pass.cpp | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <boost/container/small_vector.hpp> | ||
| 5 | |||
| 6 | #include "shader_recompiler/frontend/ir/basic_block.h" | ||
| 7 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | ||
| 8 | #include "shader_recompiler/frontend/ir/value.h" | ||
| 9 | #include "shader_recompiler/ir_opt/passes.h" | ||
| 10 | |||
| 11 | namespace Shader::Optimization { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | struct PositionInst { | ||
| 15 | IR::Inst* inst; | ||
| 16 | IR::Block* block; | ||
| 17 | IR::Attribute attr; | ||
| 18 | }; | ||
| 19 | using PositionInstVector = boost::container::small_vector<PositionInst, 24>; | ||
| 20 | } // Anonymous namespace | ||
| 21 | |||
| 22 | void PositionPass(Environment& env, IR::Program& program) { | ||
| 23 | if (env.ShaderStage() != Stage::VertexB || env.ReadViewportTransformState()) { | ||
| 24 | return; | ||
| 25 | } | ||
| 26 | |||
| 27 | Info& info{program.info}; | ||
| 28 | info.uses_render_area = true; | ||
| 29 | |||
| 30 | PositionInstVector to_replace; | ||
| 31 | for (IR::Block* const block : program.post_order_blocks) { | ||
| 32 | for (IR::Inst& inst : block->Instructions()) { | ||
| 33 | switch (inst.GetOpcode()) { | ||
| 34 | case IR::Opcode::SetAttribute: { | ||
| 35 | const IR::Attribute attr{inst.Arg(0).Attribute()}; | ||
| 36 | switch (attr) { | ||
| 37 | case IR::Attribute::PositionX: | ||
| 38 | case IR::Attribute::PositionY: { | ||
| 39 | to_replace.push_back(PositionInst{.inst = &inst, .block = block, .attr = attr}); | ||
| 40 | break; | ||
| 41 | } | ||
| 42 | default: | ||
| 43 | break; | ||
| 44 | } | ||
| 45 | break; | ||
| 46 | } | ||
| 47 | default: | ||
| 48 | break; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | for (PositionInst& position_inst : to_replace) { | ||
| 54 | IR::IREmitter ir{*position_inst.block, | ||
| 55 | IR::Block::InstructionList::s_iterator_to(*position_inst.inst)}; | ||
| 56 | const IR::F32 value(position_inst.inst->Arg(1)); | ||
| 57 | const IR::F32F64 scale(ir.Imm32(2.f)); | ||
| 58 | const IR::F32 negative_one{ir.Imm32(-1.f)}; | ||
| 59 | switch (position_inst.attr) { | ||
| 60 | case IR::Attribute::PositionX: { | ||
| 61 | position_inst.inst->SetArg( | ||
| 62 | 1, | ||
| 63 | ir.FPFma(value, ir.FPMul(ir.FPRecip(ir.RenderAreaWidth()), scale), negative_one)); | ||
| 64 | break; | ||
| 65 | } | ||
| 66 | case IR::Attribute::PositionY: { | ||
| 67 | position_inst.inst->SetArg( | ||
| 68 | 1, | ||
| 69 | ir.FPFma(value, ir.FPMul(ir.FPRecip(ir.RenderAreaHeight()), scale), negative_one)); | ||
| 70 | break; | ||
| 71 | } | ||
| 72 | default: | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } // namespace Shader::Optimization | ||
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index e8be58357..9eff84a3d 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include <boost/container/small_vector.hpp> | 8 | #include <boost/container/small_vector.hpp> |
| 9 | 9 | ||
| 10 | #include "common/settings.h" | ||
| 10 | #include "shader_recompiler/environment.h" | 11 | #include "shader_recompiler/environment.h" |
| 11 | #include "shader_recompiler/frontend/ir/basic_block.h" | 12 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 12 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" | 13 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" |
| @@ -363,6 +364,14 @@ TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) { | |||
| 363 | return env.ReadTextureType(lhs_raw | rhs_raw); | 364 | return env.ReadTextureType(lhs_raw | rhs_raw); |
| 364 | } | 365 | } |
| 365 | 366 | ||
| 367 | TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) { | ||
| 368 | const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index}; | ||
| 369 | const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset}; | ||
| 370 | const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset)}; | ||
| 371 | const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)}; | ||
| 372 | return env.ReadTexturePixelFormat(lhs_raw | rhs_raw); | ||
| 373 | } | ||
| 374 | |||
| 366 | class Descriptors { | 375 | class Descriptors { |
| 367 | public: | 376 | public: |
| 368 | explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, | 377 | explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, |
| @@ -451,6 +460,38 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | |||
| 451 | ir.FPMul(IR::F32(ir.CompositeExtract(coord, 1)), | 460 | ir.FPMul(IR::F32(ir.CompositeExtract(coord, 1)), |
| 452 | ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); | 461 | ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); |
| 453 | } | 462 | } |
| 463 | |||
| 464 | void PathTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { | ||
| 465 | const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; | ||
| 466 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||
| 467 | auto get_max_value = [pixel_format]() -> float { | ||
| 468 | switch (pixel_format) { | ||
| 469 | case TexturePixelFormat::A8B8G8R8_SNORM: | ||
| 470 | case TexturePixelFormat::R8G8_SNORM: | ||
| 471 | case TexturePixelFormat::R8_SNORM: | ||
| 472 | return 1.f / std::numeric_limits<char>::max(); | ||
| 473 | case TexturePixelFormat::R16G16B16A16_SNORM: | ||
| 474 | case TexturePixelFormat::R16G16_SNORM: | ||
| 475 | case TexturePixelFormat::R16_SNORM: | ||
| 476 | return 1.f / std::numeric_limits<short>::max(); | ||
| 477 | default: | ||
| 478 | throw InvalidArgument("Invalid texture pixel format"); | ||
| 479 | } | ||
| 480 | }; | ||
| 481 | |||
| 482 | const IR::Value new_inst{&*block.PrependNewInst(it, inst)}; | ||
| 483 | const IR::F32 x(ir.CompositeExtract(new_inst, 0)); | ||
| 484 | const IR::F32 y(ir.CompositeExtract(new_inst, 1)); | ||
| 485 | const IR::F32 z(ir.CompositeExtract(new_inst, 2)); | ||
| 486 | const IR::F32 w(ir.CompositeExtract(new_inst, 3)); | ||
| 487 | const IR::F16F32F64 max_value(ir.Imm32(get_max_value())); | ||
| 488 | const IR::Value converted = | ||
| 489 | ir.CompositeConstruct(ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(x)), max_value), | ||
| 490 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(y)), max_value), | ||
| 491 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(z)), max_value), | ||
| 492 | ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(w)), max_value)); | ||
| 493 | inst.ReplaceUsesWith(converted); | ||
| 494 | } | ||
| 454 | } // Anonymous namespace | 495 | } // Anonymous namespace |
| 455 | 496 | ||
| 456 | void TexturePass(Environment& env, IR::Program& program) { | 497 | void TexturePass(Environment& env, IR::Program& program) { |
| @@ -597,6 +638,14 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 597 | } else { | 638 | } else { |
| 598 | inst->SetArg(0, IR::Value{}); | 639 | inst->SetArg(0, IR::Value{}); |
| 599 | } | 640 | } |
| 641 | |||
| 642 | if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && | ||
| 643 | inst->GetOpcode() == IR::Opcode::ImageFetch && flags.type == TextureType::Buffer) { | ||
| 644 | const auto pixel_format = ReadTexturePixelFormat(env, cbuf); | ||
| 645 | if (pixel_format != TexturePixelFormat::OTHER) { | ||
| 646 | PathTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); | ||
| 647 | } | ||
| 648 | } | ||
| 600 | } | 649 | } |
| 601 | } | 650 | } |
| 602 | 651 | ||
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 81097bf1a..f31e1f821 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -29,6 +29,16 @@ enum class TextureType : u32 { | |||
| 29 | }; | 29 | }; |
| 30 | constexpr u32 NUM_TEXTURE_TYPES = 9; | 30 | constexpr u32 NUM_TEXTURE_TYPES = 9; |
| 31 | 31 | ||
| 32 | enum class TexturePixelFormat : u32 { | ||
| 33 | A8B8G8R8_SNORM, | ||
| 34 | R8_SNORM, | ||
| 35 | R8G8_SNORM, | ||
| 36 | R16G16B16A16_SNORM, | ||
| 37 | R16G16_SNORM, | ||
| 38 | R16_SNORM, | ||
| 39 | OTHER | ||
| 40 | }; | ||
| 41 | |||
| 32 | enum class ImageFormat : u32 { | 42 | enum class ImageFormat : u32 { |
| 33 | Typeless, | 43 | Typeless, |
| 34 | R8_UINT, | 44 | R8_UINT, |
| @@ -182,6 +192,7 @@ struct Info { | |||
| 182 | bool uses_shadow_lod{}; | 192 | bool uses_shadow_lod{}; |
| 183 | bool uses_rescaling_uniform{}; | 193 | bool uses_rescaling_uniform{}; |
| 184 | bool uses_cbuf_indirect{}; | 194 | bool uses_cbuf_indirect{}; |
| 195 | bool uses_render_area{}; | ||
| 185 | 196 | ||
| 186 | IR::Type used_constant_buffer_types{}; | 197 | IR::Type used_constant_buffer_types{}; |
| 187 | IR::Type used_storage_buffer_types{}; | 198 | IR::Type used_storage_buffer_types{}; |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 08f4d69ab..6af4ae793 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -29,17 +29,17 @@ constexpr std::array PROGRAM_LUT{ | |||
| 29 | [[nodiscard]] GLenum GetTextureBufferFormat(GLenum gl_format) { | 29 | [[nodiscard]] GLenum GetTextureBufferFormat(GLenum gl_format) { |
| 30 | switch (gl_format) { | 30 | switch (gl_format) { |
| 31 | case GL_RGBA8_SNORM: | 31 | case GL_RGBA8_SNORM: |
| 32 | return GL_RGBA8; | 32 | return GL_RGBA8I; |
| 33 | case GL_R8_SNORM: | 33 | case GL_R8_SNORM: |
| 34 | return GL_R8; | 34 | return GL_R8I; |
| 35 | case GL_RGBA16_SNORM: | 35 | case GL_RGBA16_SNORM: |
| 36 | return GL_RGBA16; | 36 | return GL_RGBA16I; |
| 37 | case GL_R16_SNORM: | 37 | case GL_R16_SNORM: |
| 38 | return GL_R16; | 38 | return GL_R16I; |
| 39 | case GL_RG16_SNORM: | 39 | case GL_RG16_SNORM: |
| 40 | return GL_RG16; | 40 | return GL_RG16I; |
| 41 | case GL_RG8_SNORM: | 41 | case GL_RG8_SNORM: |
| 42 | return GL_RG8; | 42 | return GL_RG8I; |
| 43 | default: | 43 | default: |
| 44 | return gl_format; | 44 | return gl_format; |
| 45 | } | 45 | } |
| @@ -96,9 +96,6 @@ GLuint Buffer::View(u32 offset, u32 size, PixelFormat format) { | |||
| 96 | texture.Create(GL_TEXTURE_BUFFER); | 96 | texture.Create(GL_TEXTURE_BUFFER); |
| 97 | const GLenum gl_format{MaxwellToGL::GetFormatTuple(format).internal_format}; | 97 | const GLenum gl_format{MaxwellToGL::GetFormatTuple(format).internal_format}; |
| 98 | const GLenum texture_format{GetTextureBufferFormat(gl_format)}; | 98 | const GLenum texture_format{GetTextureBufferFormat(gl_format)}; |
| 99 | if (texture_format != gl_format) { | ||
| 100 | LOG_WARNING(Render_OpenGL, "Emulating SNORM texture buffer with UNORM."); | ||
| 101 | } | ||
| 102 | glTextureBufferRange(texture.handle, texture_format, buffer.handle, offset, size); | 99 | glTextureBufferRange(texture.handle, texture_format, buffer.handle, offset, size); |
| 103 | views.push_back({ | 100 | views.push_back({ |
| 104 | .offset = offset, | 101 | .offset = offset, |
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index 1d20a79ec..c115dabe1 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp | |||
| @@ -503,6 +503,17 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { | |||
| 503 | float_image_scaling_mask, down_factor, 0.0f); | 503 | float_image_scaling_mask, down_factor, 0.0f); |
| 504 | } | 504 | } |
| 505 | } | 505 | } |
| 506 | if (info.uses_render_area) { | ||
| 507 | const auto render_area_width(static_cast<GLfloat>(regs.surface_clip.width)); | ||
| 508 | const auto render_area_height(static_cast<GLfloat>(regs.surface_clip.height)); | ||
| 509 | if (use_assembly) { | ||
| 510 | glProgramLocalParameter4fARB(AssemblyStage(stage), 1, render_area_width, | ||
| 511 | render_area_height, 0.0f, 0.0f); | ||
| 512 | } else { | ||
| 513 | glProgramUniform4f(source_programs[stage].handle, 1, render_area_width, | ||
| 514 | render_area_height, 0.0f, 0.0f); | ||
| 515 | } | ||
| 516 | } | ||
| 506 | }}; | 517 | }}; |
| 507 | if constexpr (Spec::enabled_stages[0]) { | 518 | if constexpr (Spec::enabled_stages[0]) { |
| 508 | prepare_stage(0); | 519 | prepare_stage(0); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 1590b21de..72e314d39 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -618,6 +618,16 @@ void RasterizerOpenGL::SyncViewport() { | |||
| 618 | } | 618 | } |
| 619 | flags[Dirty::Viewport0 + index] = false; | 619 | flags[Dirty::Viewport0 + index] = false; |
| 620 | 620 | ||
| 621 | if (!regs.viewport_scale_offset_enbled) { | ||
| 622 | const auto x = static_cast<GLfloat>(regs.surface_clip.x); | ||
| 623 | const auto y = static_cast<GLfloat>(regs.surface_clip.y); | ||
| 624 | const auto width = static_cast<GLfloat>(regs.surface_clip.width); | ||
| 625 | const auto height = static_cast<GLfloat>(regs.surface_clip.height); | ||
| 626 | glViewportIndexedf(static_cast<GLuint>(index), x, y, width != 0.0f ? width : 1.0f, | ||
| 627 | height != 0.0f ? height : 1.0f); | ||
| 628 | continue; | ||
| 629 | } | ||
| 630 | |||
| 621 | const auto& src = regs.viewport_transform[index]; | 631 | const auto& src = regs.viewport_transform[index]; |
| 622 | GLfloat x = conv(src.translate_x - src.scale_x); | 632 | GLfloat x = conv(src.translate_x - src.scale_x); |
| 623 | GLfloat y = conv(src.translate_y - src.scale_y); | 633 | GLfloat y = conv(src.translate_y - src.scale_y); |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index e94cfdb1a..977709518 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -49,7 +49,7 @@ using VideoCommon::LoadPipelines; | |||
| 49 | using VideoCommon::SerializePipeline; | 49 | using VideoCommon::SerializePipeline; |
| 50 | using Context = ShaderContext::Context; | 50 | using Context = ShaderContext::Context; |
| 51 | 51 | ||
| 52 | constexpr u32 CACHE_VERSION = 6; | 52 | constexpr u32 CACHE_VERSION = 7; |
| 53 | 53 | ||
| 54 | template <typename Container> | 54 | template <typename Container> |
| 55 | auto MakeSpan(Container& container) { | 55 | auto MakeSpan(Container& container) { |
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index b24f3424a..b7843e995 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h | |||
| @@ -68,13 +68,15 @@ public: | |||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | vk::PipelineLayout CreatePipelineLayout(VkDescriptorSetLayout descriptor_set_layout) const { | 70 | vk::PipelineLayout CreatePipelineLayout(VkDescriptorSetLayout descriptor_set_layout) const { |
| 71 | using Shader::Backend::SPIRV::RenderAreaLayout; | ||
| 71 | using Shader::Backend::SPIRV::RescalingLayout; | 72 | using Shader::Backend::SPIRV::RescalingLayout; |
| 72 | const u32 size_offset = is_compute ? sizeof(RescalingLayout::down_factor) : 0u; | 73 | const u32 size_offset = is_compute ? sizeof(RescalingLayout::down_factor) : 0u; |
| 73 | const VkPushConstantRange range{ | 74 | const VkPushConstantRange range{ |
| 74 | .stageFlags = static_cast<VkShaderStageFlags>( | 75 | .stageFlags = static_cast<VkShaderStageFlags>( |
| 75 | is_compute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_ALL_GRAPHICS), | 76 | is_compute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_ALL_GRAPHICS), |
| 76 | .offset = 0, | 77 | .offset = 0, |
| 77 | .size = static_cast<u32>(sizeof(RescalingLayout)) - size_offset, | 78 | .size = static_cast<u32>(sizeof(RescalingLayout)) - size_offset + |
| 79 | static_cast<u32>(sizeof(RenderAreaLayout)), | ||
| 78 | }; | 80 | }; |
| 79 | return device->GetLogical().CreatePipelineLayout({ | 81 | return device->GetLogical().CreatePipelineLayout({ |
| 80 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | 82 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
| @@ -167,6 +169,12 @@ private: | |||
| 167 | u32 image_bit{1u}; | 169 | u32 image_bit{1u}; |
| 168 | }; | 170 | }; |
| 169 | 171 | ||
| 172 | class RenderAreaPushConstant { | ||
| 173 | public: | ||
| 174 | bool uses_render_area{}; | ||
| 175 | std::array<f32, 4> words{}; | ||
| 176 | }; | ||
| 177 | |||
| 170 | inline void PushImageDescriptors(TextureCache& texture_cache, | 178 | inline void PushImageDescriptors(TextureCache& texture_cache, |
| 171 | UpdateDescriptorQueue& update_descriptor_queue, | 179 | UpdateDescriptorQueue& update_descriptor_queue, |
| 172 | const Shader::Info& info, RescalingPushConstant& rescaling, | 180 | const Shader::Info& info, RescalingPushConstant& rescaling, |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index c3f66c8a3..1aa116cea 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -31,6 +31,7 @@ namespace { | |||
| 31 | using boost::container::small_vector; | 31 | using boost::container::small_vector; |
| 32 | using boost::container::static_vector; | 32 | using boost::container::static_vector; |
| 33 | using Shader::ImageBufferDescriptor; | 33 | using Shader::ImageBufferDescriptor; |
| 34 | using Shader::Backend::SPIRV::RENDERAREA_LAYOUT_OFFSET; | ||
| 34 | using Shader::Backend::SPIRV::RESCALING_LAYOUT_DOWN_FACTOR_OFFSET; | 35 | using Shader::Backend::SPIRV::RESCALING_LAYOUT_DOWN_FACTOR_OFFSET; |
| 35 | using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET; | 36 | using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET; |
| 36 | using Tegra::Texture::TexturePair; | 37 | using Tegra::Texture::TexturePair; |
| @@ -433,12 +434,19 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { | |||
| 433 | update_descriptor_queue.Acquire(); | 434 | update_descriptor_queue.Acquire(); |
| 434 | 435 | ||
| 435 | RescalingPushConstant rescaling; | 436 | RescalingPushConstant rescaling; |
| 437 | RenderAreaPushConstant render_area; | ||
| 436 | const VkSampler* samplers_it{samplers.data()}; | 438 | const VkSampler* samplers_it{samplers.data()}; |
| 437 | const VideoCommon::ImageViewInOut* views_it{views.data()}; | 439 | const VideoCommon::ImageViewInOut* views_it{views.data()}; |
| 438 | const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE { | 440 | const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE { |
| 439 | buffer_cache.BindHostStageBuffers(stage); | 441 | buffer_cache.BindHostStageBuffers(stage); |
| 440 | PushImageDescriptors(texture_cache, update_descriptor_queue, stage_infos[stage], rescaling, | 442 | PushImageDescriptors(texture_cache, update_descriptor_queue, stage_infos[stage], rescaling, |
| 441 | samplers_it, views_it); | 443 | samplers_it, views_it); |
| 444 | const auto& info{stage_infos[0]}; | ||
| 445 | if (info.uses_render_area) { | ||
| 446 | render_area.uses_render_area = true; | ||
| 447 | render_area.words = {static_cast<float>(regs.surface_clip.width), | ||
| 448 | static_cast<float>(regs.surface_clip.height)}; | ||
| 449 | } | ||
| 442 | }}; | 450 | }}; |
| 443 | if constexpr (Spec::enabled_stages[0]) { | 451 | if constexpr (Spec::enabled_stages[0]) { |
| 444 | prepare_stage(0); | 452 | prepare_stage(0); |
| @@ -455,10 +463,11 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { | |||
| 455 | if constexpr (Spec::enabled_stages[4]) { | 463 | if constexpr (Spec::enabled_stages[4]) { |
| 456 | prepare_stage(4); | 464 | prepare_stage(4); |
| 457 | } | 465 | } |
| 458 | ConfigureDraw(rescaling); | 466 | ConfigureDraw(rescaling, render_area); |
| 459 | } | 467 | } |
| 460 | 468 | ||
| 461 | void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling) { | 469 | void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling, |
| 470 | const RenderAreaPushConstant& render_area) { | ||
| 462 | texture_cache.UpdateRenderTargets(false); | 471 | texture_cache.UpdateRenderTargets(false); |
| 463 | scheduler.RequestRenderpass(texture_cache.GetFramebuffer()); | 472 | scheduler.RequestRenderpass(texture_cache.GetFramebuffer()); |
| 464 | 473 | ||
| @@ -474,7 +483,9 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling) { | |||
| 474 | const bool bind_pipeline{scheduler.UpdateGraphicsPipeline(this)}; | 483 | const bool bind_pipeline{scheduler.UpdateGraphicsPipeline(this)}; |
| 475 | const void* const descriptor_data{update_descriptor_queue.UpdateData()}; | 484 | const void* const descriptor_data{update_descriptor_queue.UpdateData()}; |
| 476 | scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(), | 485 | scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(), |
| 477 | is_rescaling, update_rescaling](vk::CommandBuffer cmdbuf) { | 486 | is_rescaling, update_rescaling, |
| 487 | uses_render_area = render_area.uses_render_area, | ||
| 488 | render_area_data = render_area.words](vk::CommandBuffer cmdbuf) { | ||
| 478 | if (bind_pipeline) { | 489 | if (bind_pipeline) { |
| 479 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); | 490 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| 480 | } | 491 | } |
| @@ -488,6 +499,11 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling) { | |||
| 488 | RESCALING_LAYOUT_DOWN_FACTOR_OFFSET, sizeof(scale_down_factor), | 499 | RESCALING_LAYOUT_DOWN_FACTOR_OFFSET, sizeof(scale_down_factor), |
| 489 | &scale_down_factor); | 500 | &scale_down_factor); |
| 490 | } | 501 | } |
| 502 | if (uses_render_area) { | ||
| 503 | cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_ALL_GRAPHICS, | ||
| 504 | RENDERAREA_LAYOUT_OFFSET, sizeof(render_area_data), | ||
| 505 | &render_area_data); | ||
| 506 | } | ||
| 491 | if (!descriptor_set_layout) { | 507 | if (!descriptor_set_layout) { |
| 492 | return; | 508 | return; |
| 493 | } | 509 | } |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 85602592b..6bf577d25 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h | |||
| @@ -62,6 +62,7 @@ class Device; | |||
| 62 | class PipelineStatistics; | 62 | class PipelineStatistics; |
| 63 | class RenderPassCache; | 63 | class RenderPassCache; |
| 64 | class RescalingPushConstant; | 64 | class RescalingPushConstant; |
| 65 | class RenderAreaPushConstant; | ||
| 65 | class Scheduler; | 66 | class Scheduler; |
| 66 | class UpdateDescriptorQueue; | 67 | class UpdateDescriptorQueue; |
| 67 | 68 | ||
| @@ -119,7 +120,8 @@ private: | |||
| 119 | template <typename Spec> | 120 | template <typename Spec> |
| 120 | void ConfigureImpl(bool is_indexed); | 121 | void ConfigureImpl(bool is_indexed); |
| 121 | 122 | ||
| 122 | void ConfigureDraw(const RescalingPushConstant& rescaling); | 123 | void ConfigureDraw(const RescalingPushConstant& rescaling, |
| 124 | const RenderAreaPushConstant& render_are); | ||
| 123 | 125 | ||
| 124 | void MakePipeline(VkRenderPass render_pass); | 126 | void MakePipeline(VkRenderPass render_pass); |
| 125 | 127 | ||
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 13d5a1f67..b42e5be1e 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -53,7 +53,7 @@ using VideoCommon::FileEnvironment; | |||
| 53 | using VideoCommon::GenericEnvironment; | 53 | using VideoCommon::GenericEnvironment; |
| 54 | using VideoCommon::GraphicsEnvironment; | 54 | using VideoCommon::GraphicsEnvironment; |
| 55 | 55 | ||
| 56 | constexpr u32 CACHE_VERSION = 6; | 56 | constexpr u32 CACHE_VERSION = 7; |
| 57 | 57 | ||
| 58 | template <typename Container> | 58 | template <typename Container> |
| 59 | auto MakeSpan(Container& container) { | 59 | auto MakeSpan(Container& container) { |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index d94dbf873..f79fa8313 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -683,6 +683,22 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg | |||
| 683 | if (!state_tracker.TouchViewports()) { | 683 | if (!state_tracker.TouchViewports()) { |
| 684 | return; | 684 | return; |
| 685 | } | 685 | } |
| 686 | if (!regs.viewport_scale_offset_enbled) { | ||
| 687 | const auto x = static_cast<float>(regs.surface_clip.x); | ||
| 688 | const auto y = static_cast<float>(regs.surface_clip.y); | ||
| 689 | const auto width = static_cast<float>(regs.surface_clip.width); | ||
| 690 | const auto height = static_cast<float>(regs.surface_clip.height); | ||
| 691 | VkViewport viewport{ | ||
| 692 | .x = x, | ||
| 693 | .y = y, | ||
| 694 | .width = width != 0.0f ? width : 1.0f, | ||
| 695 | .height = height != 0.0f ? height : 1.0f, | ||
| 696 | .minDepth = 0.0f, | ||
| 697 | .maxDepth = 1.0f, | ||
| 698 | }; | ||
| 699 | scheduler.Record([viewport](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewport); }); | ||
| 700 | return; | ||
| 701 | } | ||
| 686 | const bool is_rescaling{texture_cache.IsRescaling()}; | 702 | const bool is_rescaling{texture_cache.IsRescaling()}; |
| 687 | const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; | 703 | const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; |
| 688 | const std::array viewports{ | 704 | const std::array viewports{ |
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index fbabb3219..37bb76b72 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "video_core/engines/kepler_compute.h" | 19 | #include "video_core/engines/kepler_compute.h" |
| 20 | #include "video_core/memory_manager.h" | 20 | #include "video_core/memory_manager.h" |
| 21 | #include "video_core/shader_environment.h" | 21 | #include "video_core/shader_environment.h" |
| 22 | #include "video_core/texture_cache/format_lookup_table.h" | ||
| 22 | #include "video_core/textures/texture.h" | 23 | #include "video_core/textures/texture.h" |
| 23 | 24 | ||
| 24 | namespace VideoCommon { | 25 | namespace VideoCommon { |
| @@ -33,7 +34,7 @@ static u64 MakeCbufKey(u32 index, u32 offset) { | |||
| 33 | return (static_cast<u64>(index) << 32) | offset; | 34 | return (static_cast<u64>(index) << 32) | offset; |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 36 | static Shader::TextureType ConvertType(const Tegra::Texture::TICEntry& entry) { | 37 | static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& entry) { |
| 37 | switch (entry.texture_type) { | 38 | switch (entry.texture_type) { |
| 38 | case Tegra::Texture::TextureType::Texture1D: | 39 | case Tegra::Texture::TextureType::Texture1D: |
| 39 | return Shader::TextureType::Color1D; | 40 | return Shader::TextureType::Color1D; |
| @@ -59,6 +60,26 @@ static Shader::TextureType ConvertType(const Tegra::Texture::TICEntry& entry) { | |||
| 59 | } | 60 | } |
| 60 | } | 61 | } |
| 61 | 62 | ||
| 63 | static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) { | ||
| 64 | switch (PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type, | ||
| 65 | entry.a_type, entry.srgb_conversion)) { | ||
| 66 | case VideoCore::Surface::PixelFormat::A8B8G8R8_SNORM: | ||
| 67 | return Shader::TexturePixelFormat::A8B8G8R8_SNORM; | ||
| 68 | case VideoCore::Surface::PixelFormat::R8_SNORM: | ||
| 69 | return Shader::TexturePixelFormat::R8_SNORM; | ||
| 70 | case VideoCore::Surface::PixelFormat::R8G8_SNORM: | ||
| 71 | return Shader::TexturePixelFormat::R8G8_SNORM; | ||
| 72 | case VideoCore::Surface::PixelFormat::R16G16B16A16_SNORM: | ||
| 73 | return Shader::TexturePixelFormat::R16G16B16A16_SNORM; | ||
| 74 | case VideoCore::Surface::PixelFormat::R16G16_SNORM: | ||
| 75 | return Shader::TexturePixelFormat::R16G16_SNORM; | ||
| 76 | case VideoCore::Surface::PixelFormat::R16_SNORM: | ||
| 77 | return Shader::TexturePixelFormat::R16_SNORM; | ||
| 78 | default: | ||
| 79 | return Shader::TexturePixelFormat::OTHER; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 62 | static std::string_view StageToPrefix(Shader::Stage stage) { | 83 | static std::string_view StageToPrefix(Shader::Stage stage) { |
| 63 | switch (stage) { | 84 | switch (stage) { |
| 64 | case Shader::Stage::VertexB: | 85 | case Shader::Stage::VertexB: |
| @@ -178,22 +199,31 @@ void GenericEnvironment::Dump(u64 hash) { | |||
| 178 | void GenericEnvironment::Serialize(std::ofstream& file) const { | 199 | void GenericEnvironment::Serialize(std::ofstream& file) const { |
| 179 | const u64 code_size{static_cast<u64>(CachedSize())}; | 200 | const u64 code_size{static_cast<u64>(CachedSize())}; |
| 180 | const u64 num_texture_types{static_cast<u64>(texture_types.size())}; | 201 | const u64 num_texture_types{static_cast<u64>(texture_types.size())}; |
| 202 | const u64 num_texture_pixel_formats{static_cast<u64>(texture_pixel_formats.size())}; | ||
| 181 | const u64 num_cbuf_values{static_cast<u64>(cbuf_values.size())}; | 203 | const u64 num_cbuf_values{static_cast<u64>(cbuf_values.size())}; |
| 182 | 204 | ||
| 183 | file.write(reinterpret_cast<const char*>(&code_size), sizeof(code_size)) | 205 | file.write(reinterpret_cast<const char*>(&code_size), sizeof(code_size)) |
| 184 | .write(reinterpret_cast<const char*>(&num_texture_types), sizeof(num_texture_types)) | 206 | .write(reinterpret_cast<const char*>(&num_texture_types), sizeof(num_texture_types)) |
| 207 | .write(reinterpret_cast<const char*>(&num_texture_pixel_formats), | ||
| 208 | sizeof(num_texture_pixel_formats)) | ||
| 185 | .write(reinterpret_cast<const char*>(&num_cbuf_values), sizeof(num_cbuf_values)) | 209 | .write(reinterpret_cast<const char*>(&num_cbuf_values), sizeof(num_cbuf_values)) |
| 186 | .write(reinterpret_cast<const char*>(&local_memory_size), sizeof(local_memory_size)) | 210 | .write(reinterpret_cast<const char*>(&local_memory_size), sizeof(local_memory_size)) |
| 187 | .write(reinterpret_cast<const char*>(&texture_bound), sizeof(texture_bound)) | 211 | .write(reinterpret_cast<const char*>(&texture_bound), sizeof(texture_bound)) |
| 188 | .write(reinterpret_cast<const char*>(&start_address), sizeof(start_address)) | 212 | .write(reinterpret_cast<const char*>(&start_address), sizeof(start_address)) |
| 189 | .write(reinterpret_cast<const char*>(&cached_lowest), sizeof(cached_lowest)) | 213 | .write(reinterpret_cast<const char*>(&cached_lowest), sizeof(cached_lowest)) |
| 190 | .write(reinterpret_cast<const char*>(&cached_highest), sizeof(cached_highest)) | 214 | .write(reinterpret_cast<const char*>(&cached_highest), sizeof(cached_highest)) |
| 215 | .write(reinterpret_cast<const char*>(&viewport_transform_state), | ||
| 216 | sizeof(viewport_transform_state)) | ||
| 191 | .write(reinterpret_cast<const char*>(&stage), sizeof(stage)) | 217 | .write(reinterpret_cast<const char*>(&stage), sizeof(stage)) |
| 192 | .write(reinterpret_cast<const char*>(code.data()), code_size); | 218 | .write(reinterpret_cast<const char*>(code.data()), code_size); |
| 193 | for (const auto& [key, type] : texture_types) { | 219 | for (const auto& [key, type] : texture_types) { |
| 194 | file.write(reinterpret_cast<const char*>(&key), sizeof(key)) | 220 | file.write(reinterpret_cast<const char*>(&key), sizeof(key)) |
| 195 | .write(reinterpret_cast<const char*>(&type), sizeof(type)); | 221 | .write(reinterpret_cast<const char*>(&type), sizeof(type)); |
| 196 | } | 222 | } |
| 223 | for (const auto& [key, format] : texture_pixel_formats) { | ||
| 224 | file.write(reinterpret_cast<const char*>(&key), sizeof(key)) | ||
| 225 | .write(reinterpret_cast<const char*>(&format), sizeof(format)); | ||
| 226 | } | ||
| 197 | for (const auto& [key, type] : cbuf_values) { | 227 | for (const auto& [key, type] : cbuf_values) { |
| 198 | file.write(reinterpret_cast<const char*>(&key), sizeof(key)) | 228 | file.write(reinterpret_cast<const char*>(&key), sizeof(key)) |
| 199 | .write(reinterpret_cast<const char*>(&type), sizeof(type)); | 229 | .write(reinterpret_cast<const char*>(&type), sizeof(type)); |
| @@ -237,15 +267,13 @@ std::optional<u64> GenericEnvironment::TryFindSize() { | |||
| 237 | return std::nullopt; | 267 | return std::nullopt; |
| 238 | } | 268 | } |
| 239 | 269 | ||
| 240 | Shader::TextureType GenericEnvironment::ReadTextureTypeImpl(GPUVAddr tic_addr, u32 tic_limit, | 270 | Tegra::Texture::TICEntry GenericEnvironment::ReadTextureInfo(GPUVAddr tic_addr, u32 tic_limit, |
| 241 | bool via_header_index, u32 raw) { | 271 | bool via_header_index, u32 raw) { |
| 242 | const auto handle{Tegra::Texture::TexturePair(raw, via_header_index)}; | 272 | const auto handle{Tegra::Texture::TexturePair(raw, via_header_index)}; |
| 243 | const GPUVAddr descriptor_addr{tic_addr + handle.first * sizeof(Tegra::Texture::TICEntry)}; | 273 | const GPUVAddr descriptor_addr{tic_addr + handle.first * sizeof(Tegra::Texture::TICEntry)}; |
| 244 | Tegra::Texture::TICEntry entry; | 274 | Tegra::Texture::TICEntry entry; |
| 245 | gpu_memory->ReadBlock(descriptor_addr, &entry, sizeof(entry)); | 275 | gpu_memory->ReadBlock(descriptor_addr, &entry, sizeof(entry)); |
| 246 | const Shader::TextureType result{ConvertType(entry)}; | 276 | return entry; |
| 247 | texture_types.emplace(raw, result); | ||
| 248 | return result; | ||
| 249 | } | 277 | } |
| 250 | 278 | ||
| 251 | GraphicsEnvironment::GraphicsEnvironment(Tegra::Engines::Maxwell3D& maxwell3d_, | 279 | GraphicsEnvironment::GraphicsEnvironment(Tegra::Engines::Maxwell3D& maxwell3d_, |
| @@ -305,8 +333,27 @@ u32 GraphicsEnvironment::ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) { | |||
| 305 | Shader::TextureType GraphicsEnvironment::ReadTextureType(u32 handle) { | 333 | Shader::TextureType GraphicsEnvironment::ReadTextureType(u32 handle) { |
| 306 | const auto& regs{maxwell3d->regs}; | 334 | const auto& regs{maxwell3d->regs}; |
| 307 | const bool via_header_index{regs.sampler_binding == Maxwell::SamplerBinding::ViaHeaderBinding}; | 335 | const bool via_header_index{regs.sampler_binding == Maxwell::SamplerBinding::ViaHeaderBinding}; |
| 308 | return ReadTextureTypeImpl(regs.tex_header.Address(), regs.tex_header.limit, via_header_index, | 336 | auto entry = |
| 309 | handle); | 337 | ReadTextureInfo(regs.tex_header.Address(), regs.tex_header.limit, via_header_index, handle); |
| 338 | const Shader::TextureType result{ConvertTextureType(entry)}; | ||
| 339 | texture_types.emplace(handle, result); | ||
| 340 | return result; | ||
| 341 | } | ||
| 342 | |||
| 343 | Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handle) { | ||
| 344 | const auto& regs{maxwell3d->regs}; | ||
| 345 | const bool via_header_index{regs.sampler_binding == Maxwell::SamplerBinding::ViaHeaderBinding}; | ||
| 346 | auto entry = | ||
| 347 | ReadTextureInfo(regs.tex_header.Address(), regs.tex_header.limit, via_header_index, handle); | ||
| 348 | const Shader::TexturePixelFormat result(ConvertTexturePixelFormat(entry)); | ||
| 349 | texture_pixel_formats.emplace(handle, result); | ||
| 350 | return result; | ||
| 351 | } | ||
| 352 | |||
| 353 | u32 GraphicsEnvironment::ReadViewportTransformState() { | ||
| 354 | const auto& regs{maxwell3d->regs}; | ||
| 355 | viewport_transform_state = regs.viewport_scale_offset_enbled; | ||
| 356 | return viewport_transform_state; | ||
| 310 | } | 357 | } |
| 311 | 358 | ||
| 312 | ComputeEnvironment::ComputeEnvironment(Tegra::Engines::KeplerCompute& kepler_compute_, | 359 | ComputeEnvironment::ComputeEnvironment(Tegra::Engines::KeplerCompute& kepler_compute_, |
| @@ -337,21 +384,41 @@ u32 ComputeEnvironment::ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) { | |||
| 337 | Shader::TextureType ComputeEnvironment::ReadTextureType(u32 handle) { | 384 | Shader::TextureType ComputeEnvironment::ReadTextureType(u32 handle) { |
| 338 | const auto& regs{kepler_compute->regs}; | 385 | const auto& regs{kepler_compute->regs}; |
| 339 | const auto& qmd{kepler_compute->launch_description}; | 386 | const auto& qmd{kepler_compute->launch_description}; |
| 340 | return ReadTextureTypeImpl(regs.tic.Address(), regs.tic.limit, qmd.linked_tsc != 0, handle); | 387 | auto entry = ReadTextureInfo(regs.tic.Address(), regs.tic.limit, qmd.linked_tsc != 0, handle); |
| 388 | const Shader::TextureType result{ConvertTextureType(entry)}; | ||
| 389 | texture_types.emplace(handle, result); | ||
| 390 | return result; | ||
| 391 | } | ||
| 392 | |||
| 393 | Shader::TexturePixelFormat ComputeEnvironment::ReadTexturePixelFormat(u32 handle) { | ||
| 394 | const auto& regs{kepler_compute->regs}; | ||
| 395 | const auto& qmd{kepler_compute->launch_description}; | ||
| 396 | auto entry = ReadTextureInfo(regs.tic.Address(), regs.tic.limit, qmd.linked_tsc != 0, handle); | ||
| 397 | const Shader::TexturePixelFormat result(ConvertTexturePixelFormat(entry)); | ||
| 398 | texture_pixel_formats.emplace(handle, result); | ||
| 399 | return result; | ||
| 400 | } | ||
| 401 | |||
| 402 | u32 ComputeEnvironment::ReadViewportTransformState() { | ||
| 403 | return viewport_transform_state; | ||
| 341 | } | 404 | } |
| 342 | 405 | ||
| 343 | void FileEnvironment::Deserialize(std::ifstream& file) { | 406 | void FileEnvironment::Deserialize(std::ifstream& file) { |
| 344 | u64 code_size{}; | 407 | u64 code_size{}; |
| 345 | u64 num_texture_types{}; | 408 | u64 num_texture_types{}; |
| 409 | u64 num_texture_pixel_formats{}; | ||
| 346 | u64 num_cbuf_values{}; | 410 | u64 num_cbuf_values{}; |
| 347 | file.read(reinterpret_cast<char*>(&code_size), sizeof(code_size)) | 411 | file.read(reinterpret_cast<char*>(&code_size), sizeof(code_size)) |
| 348 | .read(reinterpret_cast<char*>(&num_texture_types), sizeof(num_texture_types)) | 412 | .read(reinterpret_cast<char*>(&num_texture_types), sizeof(num_texture_types)) |
| 413 | .read(reinterpret_cast<char*>(&num_texture_pixel_formats), | ||
| 414 | sizeof(num_texture_pixel_formats)) | ||
| 349 | .read(reinterpret_cast<char*>(&num_cbuf_values), sizeof(num_cbuf_values)) | 415 | .read(reinterpret_cast<char*>(&num_cbuf_values), sizeof(num_cbuf_values)) |
| 350 | .read(reinterpret_cast<char*>(&local_memory_size), sizeof(local_memory_size)) | 416 | .read(reinterpret_cast<char*>(&local_memory_size), sizeof(local_memory_size)) |
| 351 | .read(reinterpret_cast<char*>(&texture_bound), sizeof(texture_bound)) | 417 | .read(reinterpret_cast<char*>(&texture_bound), sizeof(texture_bound)) |
| 352 | .read(reinterpret_cast<char*>(&start_address), sizeof(start_address)) | 418 | .read(reinterpret_cast<char*>(&start_address), sizeof(start_address)) |
| 353 | .read(reinterpret_cast<char*>(&read_lowest), sizeof(read_lowest)) | 419 | .read(reinterpret_cast<char*>(&read_lowest), sizeof(read_lowest)) |
| 354 | .read(reinterpret_cast<char*>(&read_highest), sizeof(read_highest)) | 420 | .read(reinterpret_cast<char*>(&read_highest), sizeof(read_highest)) |
| 421 | .read(reinterpret_cast<char*>(&viewport_transform_state), sizeof(viewport_transform_state)) | ||
| 355 | .read(reinterpret_cast<char*>(&stage), sizeof(stage)); | 422 | .read(reinterpret_cast<char*>(&stage), sizeof(stage)); |
| 356 | code = std::make_unique<u64[]>(Common::DivCeil(code_size, sizeof(u64))); | 423 | code = std::make_unique<u64[]>(Common::DivCeil(code_size, sizeof(u64))); |
| 357 | file.read(reinterpret_cast<char*>(code.get()), code_size); | 424 | file.read(reinterpret_cast<char*>(code.get()), code_size); |
| @@ -362,6 +429,13 @@ void FileEnvironment::Deserialize(std::ifstream& file) { | |||
| 362 | .read(reinterpret_cast<char*>(&type), sizeof(type)); | 429 | .read(reinterpret_cast<char*>(&type), sizeof(type)); |
| 363 | texture_types.emplace(key, type); | 430 | texture_types.emplace(key, type); |
| 364 | } | 431 | } |
| 432 | for (size_t i = 0; i < num_texture_pixel_formats; ++i) { | ||
| 433 | u32 key; | ||
| 434 | Shader::TexturePixelFormat format; | ||
| 435 | file.read(reinterpret_cast<char*>(&key), sizeof(key)) | ||
| 436 | .read(reinterpret_cast<char*>(&format), sizeof(format)); | ||
| 437 | texture_pixel_formats.emplace(key, format); | ||
| 438 | } | ||
| 365 | for (size_t i = 0; i < num_cbuf_values; ++i) { | 439 | for (size_t i = 0; i < num_cbuf_values; ++i) { |
| 366 | u64 key; | 440 | u64 key; |
| 367 | u32 value; | 441 | u32 value; |
| @@ -409,6 +483,18 @@ Shader::TextureType FileEnvironment::ReadTextureType(u32 handle) { | |||
| 409 | return it->second; | 483 | return it->second; |
| 410 | } | 484 | } |
| 411 | 485 | ||
| 486 | Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) { | ||
| 487 | const auto it{texture_pixel_formats.find(handle)}; | ||
| 488 | if (it == texture_pixel_formats.end()) { | ||
| 489 | throw Shader::LogicError("Uncached read texture pixel format"); | ||
| 490 | } | ||
| 491 | return it->second; | ||
| 492 | } | ||
| 493 | |||
| 494 | u32 FileEnvironment::ReadViewportTransformState() { | ||
| 495 | return viewport_transform_state; | ||
| 496 | } | ||
| 497 | |||
| 412 | u32 FileEnvironment::LocalMemorySize() const { | 498 | u32 FileEnvironment::LocalMemorySize() const { |
| 413 | return local_memory_size; | 499 | return local_memory_size; |
| 414 | } | 500 | } |
diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h index 8b3b8e9f5..bb55b029f 100644 --- a/src/video_core/shader_environment.h +++ b/src/video_core/shader_environment.h | |||
| @@ -63,14 +63,15 @@ public: | |||
| 63 | protected: | 63 | protected: |
| 64 | std::optional<u64> TryFindSize(); | 64 | std::optional<u64> TryFindSize(); |
| 65 | 65 | ||
| 66 | Shader::TextureType ReadTextureTypeImpl(GPUVAddr tic_addr, u32 tic_limit, bool via_header_index, | 66 | Tegra::Texture::TICEntry ReadTextureInfo(GPUVAddr tic_addr, u32 tic_limit, |
| 67 | u32 raw); | 67 | bool via_header_index, u32 raw); |
| 68 | 68 | ||
| 69 | Tegra::MemoryManager* gpu_memory{}; | 69 | Tegra::MemoryManager* gpu_memory{}; |
| 70 | GPUVAddr program_base{}; | 70 | GPUVAddr program_base{}; |
| 71 | 71 | ||
| 72 | std::vector<u64> code; | 72 | std::vector<u64> code; |
| 73 | std::unordered_map<u32, Shader::TextureType> texture_types; | 73 | std::unordered_map<u32, Shader::TextureType> texture_types; |
| 74 | std::unordered_map<u32, Shader::TexturePixelFormat> texture_pixel_formats; | ||
| 74 | std::unordered_map<u64, u32> cbuf_values; | 75 | std::unordered_map<u64, u32> cbuf_values; |
| 75 | 76 | ||
| 76 | u32 local_memory_size{}; | 77 | u32 local_memory_size{}; |
| @@ -85,6 +86,8 @@ protected: | |||
| 85 | u32 cached_highest = 0; | 86 | u32 cached_highest = 0; |
| 86 | u32 initial_offset = 0; | 87 | u32 initial_offset = 0; |
| 87 | 88 | ||
| 89 | u32 viewport_transform_state = 1; | ||
| 90 | |||
| 88 | bool has_unbound_instructions = false; | 91 | bool has_unbound_instructions = false; |
| 89 | }; | 92 | }; |
| 90 | 93 | ||
| @@ -102,6 +105,10 @@ public: | |||
| 102 | 105 | ||
| 103 | Shader::TextureType ReadTextureType(u32 handle) override; | 106 | Shader::TextureType ReadTextureType(u32 handle) override; |
| 104 | 107 | ||
| 108 | Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | ||
| 109 | |||
| 110 | u32 ReadViewportTransformState() override; | ||
| 111 | |||
| 105 | private: | 112 | private: |
| 106 | Tegra::Engines::Maxwell3D* maxwell3d{}; | 113 | Tegra::Engines::Maxwell3D* maxwell3d{}; |
| 107 | size_t stage_index{}; | 114 | size_t stage_index{}; |
| @@ -120,6 +127,10 @@ public: | |||
| 120 | 127 | ||
| 121 | Shader::TextureType ReadTextureType(u32 handle) override; | 128 | Shader::TextureType ReadTextureType(u32 handle) override; |
| 122 | 129 | ||
| 130 | Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | ||
| 131 | |||
| 132 | u32 ReadViewportTransformState() override; | ||
| 133 | |||
| 123 | private: | 134 | private: |
| 124 | Tegra::Engines::KeplerCompute* kepler_compute{}; | 135 | Tegra::Engines::KeplerCompute* kepler_compute{}; |
| 125 | }; | 136 | }; |
| @@ -143,6 +154,10 @@ public: | |||
| 143 | 154 | ||
| 144 | [[nodiscard]] Shader::TextureType ReadTextureType(u32 handle) override; | 155 | [[nodiscard]] Shader::TextureType ReadTextureType(u32 handle) override; |
| 145 | 156 | ||
| 157 | [[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | ||
| 158 | |||
| 159 | [[nodiscard]] u32 ReadViewportTransformState() override; | ||
| 160 | |||
| 146 | [[nodiscard]] u32 LocalMemorySize() const override; | 161 | [[nodiscard]] u32 LocalMemorySize() const override; |
| 147 | 162 | ||
| 148 | [[nodiscard]] u32 SharedMemorySize() const override; | 163 | [[nodiscard]] u32 SharedMemorySize() const override; |
| @@ -156,6 +171,7 @@ public: | |||
| 156 | private: | 171 | private: |
| 157 | std::unique_ptr<u64[]> code; | 172 | std::unique_ptr<u64[]> code; |
| 158 | std::unordered_map<u32, Shader::TextureType> texture_types; | 173 | std::unordered_map<u32, Shader::TextureType> texture_types; |
| 174 | std::unordered_map<u32, Shader::TexturePixelFormat> texture_pixel_formats; | ||
| 159 | std::unordered_map<u64, u32> cbuf_values; | 175 | std::unordered_map<u64, u32> cbuf_values; |
| 160 | std::array<u32, 3> workgroup_size{}; | 176 | std::array<u32, 3> workgroup_size{}; |
| 161 | u32 local_memory_size{}; | 177 | u32 local_memory_size{}; |
| @@ -164,6 +180,7 @@ private: | |||
| 164 | u32 read_lowest{}; | 180 | u32 read_lowest{}; |
| 165 | u32 read_highest{}; | 181 | u32 read_highest{}; |
| 166 | u32 initial_offset{}; | 182 | u32 initial_offset{}; |
| 183 | u32 viewport_transform_state = 1; | ||
| 167 | }; | 184 | }; |
| 168 | 185 | ||
| 169 | void SerializePipeline(std::span<const char> key, std::span<const GenericEnvironment* const> envs, | 186 | void SerializePipeline(std::span<const char> key, std::span<const GenericEnvironment* const> envs, |
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 1223df5a0..e8c908b42 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -516,7 +516,6 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr | |||
| 516 | const u32 num_blocks_per_layer = NumBlocks(level_size, tile_size); | 516 | const u32 num_blocks_per_layer = NumBlocks(level_size, tile_size); |
| 517 | const u32 host_bytes_per_layer = num_blocks_per_layer * bytes_per_block; | 517 | const u32 host_bytes_per_layer = num_blocks_per_layer * bytes_per_block; |
| 518 | 518 | ||
| 519 | UNIMPLEMENTED_IF(info.tile_width_spacing > 0); | ||
| 520 | UNIMPLEMENTED_IF(copy.image_offset.x != 0); | 519 | UNIMPLEMENTED_IF(copy.image_offset.x != 0); |
| 521 | UNIMPLEMENTED_IF(copy.image_offset.y != 0); | 520 | UNIMPLEMENTED_IF(copy.image_offset.y != 0); |
| 522 | UNIMPLEMENTED_IF(copy.image_offset.z != 0); | 521 | UNIMPLEMENTED_IF(copy.image_offset.z != 0); |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 29d506c47..239f12382 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -315,7 +315,7 @@ target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) | |||
| 315 | if (NOT WIN32) | 315 | if (NOT WIN32) |
| 316 | target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) | 316 | target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) |
| 317 | endif() | 317 | endif() |
| 318 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | 318 | if (UNIX AND NOT APPLE) |
| 319 | target_link_libraries(yuzu PRIVATE Qt::DBus) | 319 | target_link_libraries(yuzu PRIVATE Qt::DBus) |
| 320 | endif() | 320 | endif() |
| 321 | 321 | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 927dd1069..343f3b8e5 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -820,6 +820,8 @@ void Config::ReadUIGamelistValues() { | |||
| 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.show_compat); |
| 823 | ReadBasicSetting(UISettings::values.show_size); | ||
| 824 | ReadBasicSetting(UISettings::values.show_types); | ||
| 823 | ReadBasicSetting(UISettings::values.game_icon_size); | 825 | ReadBasicSetting(UISettings::values.game_icon_size); |
| 824 | ReadBasicSetting(UISettings::values.folder_icon_size); | 826 | ReadBasicSetting(UISettings::values.folder_icon_size); |
| 825 | ReadBasicSetting(UISettings::values.row_1_text_id); | 827 | ReadBasicSetting(UISettings::values.row_1_text_id); |
| @@ -1416,6 +1418,8 @@ void Config::SaveUIGamelistValues() { | |||
| 1416 | 1418 | ||
| 1417 | WriteBasicSetting(UISettings::values.show_add_ons); | 1419 | WriteBasicSetting(UISettings::values.show_add_ons); |
| 1418 | WriteBasicSetting(UISettings::values.show_compat); | 1420 | WriteBasicSetting(UISettings::values.show_compat); |
| 1421 | WriteBasicSetting(UISettings::values.show_size); | ||
| 1422 | WriteBasicSetting(UISettings::values.show_types); | ||
| 1419 | WriteBasicSetting(UISettings::values.game_icon_size); | 1423 | WriteBasicSetting(UISettings::values.game_icon_size); |
| 1420 | WriteBasicSetting(UISettings::values.folder_icon_size); | 1424 | WriteBasicSetting(UISettings::values.folder_icon_size); |
| 1421 | WriteBasicSetting(UISettings::values.row_1_text_id); | 1425 | WriteBasicSetting(UISettings::values.row_1_text_id); |
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 92e6da6ee..2ebb80302 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp | |||
| @@ -73,6 +73,8 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent) | |||
| 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->show_compat, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); |
| 76 | connect(ui->show_size, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); | ||
| 77 | connect(ui->show_types, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); | ||
| 76 | connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 78 | connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |
| 77 | &ConfigureUi::RequestGameListUpdate); | 79 | &ConfigureUi::RequestGameListUpdate); |
| 78 | connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), | 80 | connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), |
| @@ -111,6 +113,8 @@ void ConfigureUi::ApplyConfiguration() { | |||
| 111 | ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); | 113 | ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); |
| 112 | UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); | 114 | UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); |
| 113 | UISettings::values.show_compat = ui->show_compat->isChecked(); | 115 | UISettings::values.show_compat = ui->show_compat->isChecked(); |
| 116 | UISettings::values.show_size = ui->show_size->isChecked(); | ||
| 117 | UISettings::values.show_types = ui->show_types->isChecked(); | ||
| 114 | UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt(); | 118 | UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt(); |
| 115 | UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt(); | 119 | UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt(); |
| 116 | UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); | 120 | UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); |
| @@ -132,6 +136,8 @@ void ConfigureUi::SetConfiguration() { | |||
| 132 | ui->language_combobox->findData(UISettings::values.language)); | 136 | ui->language_combobox->findData(UISettings::values.language)); |
| 133 | ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); | 137 | ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); |
| 134 | ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); | 138 | ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); |
| 139 | ui->show_size->setChecked(UISettings::values.show_size.GetValue()); | ||
| 140 | ui->show_types->setChecked(UISettings::values.show_types.GetValue()); | ||
| 135 | ui->game_icon_size_combobox->setCurrentIndex( | 141 | ui->game_icon_size_combobox->setCurrentIndex( |
| 136 | ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue())); | 142 | ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue())); |
| 137 | ui->folder_icon_size_combobox->setCurrentIndex( | 143 | ui->folder_icon_size_combobox->setCurrentIndex( |
diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui index f0b719ba3..10bb27312 100644 --- a/src/yuzu/configuration/configure_ui.ui +++ b/src/yuzu/configuration/configure_ui.ui | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | <x>0</x> | 7 | <x>0</x> |
| 8 | <y>0</y> | 8 | <y>0</y> |
| 9 | <width>363</width> | 9 | <width>363</width> |
| 10 | <height>507</height> | 10 | <height>562</height> |
| 11 | </rect> | 11 | </rect> |
| 12 | </property> | 12 | </property> |
| 13 | <property name="windowTitle"> | 13 | <property name="windowTitle"> |
| @@ -91,6 +91,20 @@ | |||
| 91 | </widget> | 91 | </widget> |
| 92 | </item> | 92 | </item> |
| 93 | <item> | 93 | <item> |
| 94 | <widget class="QCheckBox" name="show_size"> | ||
| 95 | <property name="text"> | ||
| 96 | <string>Show Size Column</string> | ||
| 97 | </property> | ||
| 98 | </widget> | ||
| 99 | </item> | ||
| 100 | <item> | ||
| 101 | <widget class="QCheckBox" name="show_types"> | ||
| 102 | <property name="text"> | ||
| 103 | <string>Show File Types Column</string> | ||
| 104 | </property> | ||
| 105 | </widget> | ||
| 106 | </item> | ||
| 107 | <item> | ||
| 94 | <layout class="QHBoxLayout" name="game_icon_size_qhbox_layout_2"> | 108 | <layout class="QHBoxLayout" name="game_icon_size_qhbox_layout_2"> |
| 95 | <item> | 109 | <item> |
| 96 | <widget class="QLabel" name="game_icon_size_label"> | 110 | <widget class="QLabel" name="game_icon_size_label"> |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index d6adfca16..5c33c1b0f 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -788,6 +788,8 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) { | |||
| 788 | // Update the columns in case UISettings has changed | 788 | // Update the columns in case UISettings has changed |
| 789 | 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); | 790 | tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat); |
| 791 | tree_view->setColumnHidden(COLUMN_FILE_TYPE, !UISettings::values.show_types); | ||
| 792 | tree_view->setColumnHidden(COLUMN_SIZE, !UISettings::values.show_size); | ||
| 791 | 793 | ||
| 792 | // Delete any rows that might already exist if we're repopulating | 794 | // Delete any rows that might already exist if we're repopulating |
| 793 | item_model->removeRows(0, item_model->rowCount()); | 795 | item_model->removeRows(0, item_model->rowCount()); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7b16d7f7e..59e56633a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | #ifdef __APPLE__ | 9 | #ifdef __APPLE__ |
| 10 | #include <unistd.h> // for chdir | 10 | #include <unistd.h> // for chdir |
| 11 | #endif | 11 | #endif |
| 12 | #ifdef __linux__ | 12 | #ifdef __unix__ |
| 13 | #include <csignal> | 13 | #include <csignal> |
| 14 | #include <sys/socket.h> | 14 | #include <sys/socket.h> |
| 15 | #endif | 15 | #endif |
| @@ -275,7 +275,7 @@ static void OverrideWindowsFont() { | |||
| 275 | #endif | 275 | #endif |
| 276 | 276 | ||
| 277 | bool GMainWindow::CheckDarkMode() { | 277 | bool GMainWindow::CheckDarkMode() { |
| 278 | #ifdef __linux__ | 278 | #ifdef __unix__ |
| 279 | const QPalette test_palette(qApp->palette()); | 279 | const QPalette test_palette(qApp->palette()); |
| 280 | const QColor text_color = test_palette.color(QPalette::Active, QPalette::Text); | 280 | const QColor text_color = test_palette.color(QPalette::Active, QPalette::Text); |
| 281 | const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); | 281 | const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); |
| @@ -283,7 +283,7 @@ bool GMainWindow::CheckDarkMode() { | |||
| 283 | #else | 283 | #else |
| 284 | // TODO: Windows | 284 | // TODO: Windows |
| 285 | return false; | 285 | return false; |
| 286 | #endif // __linux__ | 286 | #endif // __unix__ |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan) | 289 | GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan) |
| @@ -291,7 +291,7 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan | |||
| 291 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)}, | 291 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)}, |
| 292 | vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, | 292 | vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, |
| 293 | provider{std::make_unique<FileSys::ManualContentProvider>()} { | 293 | provider{std::make_unique<FileSys::ManualContentProvider>()} { |
| 294 | #ifdef __linux__ | 294 | #ifdef __unix__ |
| 295 | SetupSigInterrupts(); | 295 | SetupSigInterrupts(); |
| 296 | #endif | 296 | #endif |
| 297 | system->Initialize(); | 297 | system->Initialize(); |
| @@ -509,7 +509,7 @@ GMainWindow::~GMainWindow() { | |||
| 509 | delete render_window; | 509 | delete render_window; |
| 510 | } | 510 | } |
| 511 | 511 | ||
| 512 | #ifdef __linux__ | 512 | #ifdef __unix__ |
| 513 | ::close(sig_interrupt_fds[0]); | 513 | ::close(sig_interrupt_fds[0]); |
| 514 | ::close(sig_interrupt_fds[1]); | 514 | ::close(sig_interrupt_fds[1]); |
| 515 | #endif | 515 | #endif |
| @@ -1379,7 +1379,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) { | |||
| 1379 | } | 1379 | } |
| 1380 | 1380 | ||
| 1381 | void GMainWindow::SetupPrepareForSleep() { | 1381 | void GMainWindow::SetupPrepareForSleep() { |
| 1382 | #ifdef __linux__ | 1382 | #ifdef __unix__ |
| 1383 | auto bus = QDBusConnection::systemBus(); | 1383 | auto bus = QDBusConnection::systemBus(); |
| 1384 | if (bus.isConnected()) { | 1384 | if (bus.isConnected()) { |
| 1385 | const bool success = bus.connect( | 1385 | const bool success = bus.connect( |
| @@ -1393,7 +1393,7 @@ void GMainWindow::SetupPrepareForSleep() { | |||
| 1393 | } else { | 1393 | } else { |
| 1394 | LOG_WARNING(Frontend, "QDBusConnection system bus is not connected"); | 1394 | LOG_WARNING(Frontend, "QDBusConnection system bus is not connected"); |
| 1395 | } | 1395 | } |
| 1396 | #endif // __linux__ | 1396 | #endif // __unix__ |
| 1397 | } | 1397 | } |
| 1398 | 1398 | ||
| 1399 | void GMainWindow::OnPrepareForSleep(bool prepare_sleep) { | 1399 | void GMainWindow::OnPrepareForSleep(bool prepare_sleep) { |
| @@ -1415,7 +1415,7 @@ void GMainWindow::OnPrepareForSleep(bool prepare_sleep) { | |||
| 1415 | } | 1415 | } |
| 1416 | } | 1416 | } |
| 1417 | 1417 | ||
| 1418 | #ifdef __linux__ | 1418 | #ifdef __unix__ |
| 1419 | static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) { | 1419 | static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) { |
| 1420 | if (!QDBusConnection::sessionBus().isConnected()) { | 1420 | if (!QDBusConnection::sessionBus().isConnected()) { |
| 1421 | return {}; | 1421 | return {}; |
| @@ -1500,14 +1500,14 @@ void GMainWindow::OnSigInterruptNotifierActivated() { | |||
| 1500 | 1500 | ||
| 1501 | emit SigInterrupt(); | 1501 | emit SigInterrupt(); |
| 1502 | } | 1502 | } |
| 1503 | #endif // __linux__ | 1503 | #endif // __unix__ |
| 1504 | 1504 | ||
| 1505 | void GMainWindow::PreventOSSleep() { | 1505 | void GMainWindow::PreventOSSleep() { |
| 1506 | #ifdef _WIN32 | 1506 | #ifdef _WIN32 |
| 1507 | SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); | 1507 | SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); |
| 1508 | #elif defined(HAVE_SDL2) | 1508 | #elif defined(HAVE_SDL2) |
| 1509 | SDL_DisableScreenSaver(); | 1509 | SDL_DisableScreenSaver(); |
| 1510 | #ifdef __linux__ | 1510 | #ifdef __unix__ |
| 1511 | auto reply = HoldWakeLockLinux(winId()); | 1511 | auto reply = HoldWakeLockLinux(winId()); |
| 1512 | if (reply) { | 1512 | if (reply) { |
| 1513 | wake_lock = std::move(reply.value()); | 1513 | wake_lock = std::move(reply.value()); |
| @@ -1521,7 +1521,7 @@ void GMainWindow::AllowOSSleep() { | |||
| 1521 | SetThreadExecutionState(ES_CONTINUOUS); | 1521 | SetThreadExecutionState(ES_CONTINUOUS); |
| 1522 | #elif defined(HAVE_SDL2) | 1522 | #elif defined(HAVE_SDL2) |
| 1523 | SDL_EnableScreenSaver(); | 1523 | SDL_EnableScreenSaver(); |
| 1524 | #ifdef __linux__ | 1524 | #ifdef __unix__ |
| 1525 | if (!wake_lock.path().isEmpty()) { | 1525 | if (!wake_lock.path().isEmpty()) { |
| 1526 | ReleaseWakeLockLinux(wake_lock); | 1526 | ReleaseWakeLockLinux(wake_lock); |
| 1527 | } | 1527 | } |
| @@ -4070,7 +4070,7 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { | |||
| 4070 | } | 4070 | } |
| 4071 | 4071 | ||
| 4072 | void GMainWindow::changeEvent(QEvent* event) { | 4072 | void GMainWindow::changeEvent(QEvent* event) { |
| 4073 | #ifdef __linux__ | 4073 | #ifdef __unix__ |
| 4074 | // PaletteChange event appears to only reach so far into the GUI, explicitly asking to | 4074 | // PaletteChange event appears to only reach so far into the GUI, explicitly asking to |
| 4075 | // UpdateUITheme is a decent work around | 4075 | // UpdateUITheme is a decent work around |
| 4076 | if (event->type() == QEvent::PaletteChange) { | 4076 | if (event->type() == QEvent::PaletteChange) { |
| @@ -4085,7 +4085,7 @@ void GMainWindow::changeEvent(QEvent* event) { | |||
| 4085 | } | 4085 | } |
| 4086 | last_window_color = window_color; | 4086 | last_window_color = window_color; |
| 4087 | } | 4087 | } |
| 4088 | #endif // __linux__ | 4088 | #endif // __unix__ |
| 4089 | QWidget::changeEvent(event); | 4089 | QWidget::changeEvent(event); |
| 4090 | } | 4090 | } |
| 4091 | 4091 | ||
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index f7aa8e417..150ada84c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include "yuzu/compatibility_list.h" | 15 | #include "yuzu/compatibility_list.h" |
| 16 | #include "yuzu/hotkeys.h" | 16 | #include "yuzu/hotkeys.h" |
| 17 | 17 | ||
| 18 | #ifdef __linux__ | 18 | #ifdef __unix__ |
| 19 | #include <QVariant> | 19 | #include <QVariant> |
| 20 | #include <QtDBus/QDBusInterface> | 20 | #include <QtDBus/QDBusInterface> |
| 21 | #include <QtDBus/QtDBus> | 21 | #include <QtDBus/QtDBus> |
| @@ -255,7 +255,7 @@ private: | |||
| 255 | void changeEvent(QEvent* event) override; | 255 | void changeEvent(QEvent* event) override; |
| 256 | void closeEvent(QCloseEvent* event) override; | 256 | void closeEvent(QCloseEvent* event) override; |
| 257 | 257 | ||
| 258 | #ifdef __linux__ | 258 | #ifdef __unix__ |
| 259 | void SetupSigInterrupts(); | 259 | void SetupSigInterrupts(); |
| 260 | static void HandleSigInterrupt(int); | 260 | static void HandleSigInterrupt(int); |
| 261 | void OnSigInterruptNotifierActivated(); | 261 | void OnSigInterruptNotifierActivated(); |
| @@ -435,7 +435,7 @@ private: | |||
| 435 | // True if TAS recording dialog is visible | 435 | // True if TAS recording dialog is visible |
| 436 | bool is_tas_recording_dialog_active{}; | 436 | bool is_tas_recording_dialog_active{}; |
| 437 | 437 | ||
| 438 | #ifdef __linux__ | 438 | #ifdef __unix__ |
| 439 | QSocketNotifier* sig_interrupt_notifier; | 439 | QSocketNotifier* sig_interrupt_notifier; |
| 440 | static std::array<int, 3> sig_interrupt_fds; | 440 | static std::array<int, 3> sig_interrupt_fds; |
| 441 | 441 | ||
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 4f5b2a99d..452038cd9 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -132,6 +132,10 @@ struct Values { | |||
| 132 | // Compatibility List | 132 | // Compatibility List |
| 133 | Settings::Setting<bool> show_compat{false, "show_compat"}; | 133 | Settings::Setting<bool> show_compat{false, "show_compat"}; |
| 134 | 134 | ||
| 135 | // Size & File Types Column | ||
| 136 | Settings::Setting<bool> show_size{true, "show_size"}; | ||
| 137 | Settings::Setting<bool> show_types{true, "show_types"}; | ||
| 138 | |||
| 135 | bool configuration_applied; | 139 | bool configuration_applied; |
| 136 | bool reset_to_defaults; | 140 | bool reset_to_defaults; |
| 137 | Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"}; | 141 | Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"}; |