diff options
Diffstat (limited to '')
54 files changed, 802 insertions, 706 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 23e5d3f10..2e59894ab 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -8,7 +8,7 @@ #include "audio_core/codec.h" #include "common/assert.h" #include "common/logging/log.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/writable_event.h" #include "core/memory.h" namespace AudioCore { @@ -72,7 +72,7 @@ private: EffectInStatus info{}; }; AudioRenderer::AudioRenderer(AudioRendererParameter params, - Kernel::SharedPtr<Kernel::Event> buffer_event) + Kernel::SharedPtr<Kernel::WritableEvent> buffer_event) : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), effects(params.effect_count) { diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index 71ba4be40..7826881bf 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h @@ -15,7 +15,7 @@ #include "core/hle/kernel/object.h" namespace Kernel { -class Event; +class WritableEvent; } namespace AudioCore { @@ -208,7 +208,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size class AudioRenderer { public: - AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event); + AudioRenderer(AudioRendererParameter params, + Kernel::SharedPtr<Kernel::WritableEvent> buffer_event); ~AudioRenderer(); std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params); @@ -224,7 +225,7 @@ private: class VoiceState; AudioRendererParameter worker_params; - Kernel::SharedPtr<Kernel::Event> buffer_event; + Kernel::SharedPtr<Kernel::WritableEvent> buffer_event; std::vector<VoiceState> voices; std::vector<EffectState> effects; std::unique_ptr<AudioOut> audio_out; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e1f21a764..73aec8ab0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -97,8 +97,6 @@ add_library(core STATIC hle/kernel/client_session.cpp hle/kernel/client_session.h hle/kernel/errors.h - hle/kernel/event.cpp - hle/kernel/event.h hle/kernel/handle_table.cpp hle/kernel/handle_table.h hle/kernel/hle_ipc.cpp @@ -111,6 +109,8 @@ add_library(core STATIC hle/kernel/object.h hle/kernel/process.cpp hle/kernel/process.h + hle/kernel/readable_event.cpp + hle/kernel/readable_event.h hle/kernel/resource_limit.cpp hle/kernel/resource_limit.h hle/kernel/scheduler.cpp @@ -133,6 +133,8 @@ add_library(core STATIC hle/kernel/vm_manager.h hle/kernel/wait_object.cpp hle/kernel/wait_object.h + hle/kernel/writable_event.cpp + hle/kernel/writable_event.h hle/lock.cpp hle/lock.h hle/result.h diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 7b584de7f..e33327ef0 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -384,6 +384,28 @@ bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { return success; } +bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) { + auto dir = GetSubdirectory(name); + if (dir == nullptr) { + return false; + } + + bool success = true; + for (const auto& file : dir->GetFiles()) { + if (!dir->DeleteFile(file->GetName())) { + success = false; + } + } + + for (const auto& sdir : dir->GetSubdirectories()) { + if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) { + success = false; + } + } + + return success; +} + bool VfsDirectory::Copy(std::string_view src, std::string_view dest) { const auto f1 = GetFile(src); auto f2 = CreateFile(dest); @@ -431,10 +453,34 @@ std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name) return nullptr; } +std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) { + return nullptr; +} + +std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) { + return nullptr; +} + +std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) { + return nullptr; +} + +std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) { + return nullptr; +} + bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) { return false; } +bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { + return false; +} + +bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) { + return false; +} + bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) { return false; } diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 002f99d4e..e5641b255 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -245,12 +245,18 @@ public: // any failure. virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path); - // Deletes the subdirectory with name and returns true on success. + // Deletes the subdirectory with the given name and returns true on success. virtual bool DeleteSubdirectory(std::string_view name) = 0; - // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes - // the subdirectory. Returns true on success. + + // Deletes all subdirectories and files within the provided directory and then deletes + // the directory itself. Returns true on success. virtual bool DeleteSubdirectoryRecursive(std::string_view name); - // Returnes whether or not the file with name name was deleted successfully. + + // Deletes all subdirectories and files within the provided directory. + // Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory. + virtual bool CleanSubdirectoryRecursive(std::string_view name); + + // Returns whether or not the file with name name was deleted successfully. virtual bool DeleteFile(std::string_view name) = 0; // Returns whether or not this directory was renamed to name. @@ -276,7 +282,13 @@ public: bool IsReadable() const override; std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; + std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override; + std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override; + std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override; + std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override; bool DeleteSubdirectory(std::string_view name) override; + bool DeleteSubdirectoryRecursive(std::string_view name) override; + bool CleanSubdirectoryRecursive(std::string_view name) override; bool DeleteFile(std::string_view name) override; bool Rename(std::string_view name) override; }; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 68d5376cb..61ce7d7e4 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -15,13 +15,14 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/writable_event.h" #include "core/memory.h" namespace Kernel { @@ -36,11 +37,9 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s boost::range::remove_erase(connected_sessions, server_session); } -SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, - const std::string& reason, u64 timeout, - WakeupCallback&& callback, - Kernel::SharedPtr<Kernel::Event> event) { - +SharedPtr<WritableEvent> HLERequestContext::SleepClientThread( + SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback, + SharedPtr<WritableEvent> writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. thread->SetWakeupCallback([context = *this, callback]( ThreadWakeupReason reason, SharedPtr<Thread> thread, @@ -51,23 +50,25 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, return true; }); - if (!event) { + auto& kernel = Core::System::GetInstance().Kernel(); + if (!writable_event) { // Create event if not provided - auto& kernel = Core::System::GetInstance().Kernel(); - event = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); + const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "HLE Pause Event: " + reason); + writable_event = pair.writable; } - event->Clear(); + const auto readable_event{writable_event->GetReadableEvent()}; + writable_event->Clear(); thread->SetStatus(ThreadStatus::WaitHLEEvent); - thread->SetWaitObjects({event}); - event->AddWaitingThread(thread); + thread->SetWaitObjects({readable_event}); + readable_event->AddWaitingThread(thread); if (timeout > 0) { thread->WakeAfterDelay(timeout); } - return event; + return writable_event; } HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index a38e34b74..e5c0610cd 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -24,10 +24,11 @@ class ServiceFrameworkBase; namespace Kernel { class Domain; -class Event; class HandleTable; class HLERequestContext; class Process; +class ReadableEvent; +class WritableEvent; /** * Interface implemented by HLE Session handlers. @@ -119,12 +120,13 @@ public: * @param callback Callback to be invoked when the thread is resumed. This callback must write * the entire command response once again, regardless of the state of it before this function * was called. - * @param event Event to use to wake up the thread. If unspecified, an event will be created. + * @param writable_event Event to use to wake up the thread. If unspecified, an event will be + * created. * @returns Event that when signaled will resume the thread and call the callback function. */ - SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, - u64 timeout, WakeupCallback&& callback, - Kernel::SharedPtr<Kernel::Event> event = nullptr); + SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, + u64 timeout, WakeupCallback&& callback, + SharedPtr<WritableEvent> writable_event = nullptr); /// Populates this context with data from the requesting process/thread. ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index c9f4d0bb3..69082ce3e 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -33,9 +33,9 @@ enum class HandleType : u32 { }; enum class ResetType { - OneShot, - Sticky, - Pulse, + OneShot, ///< Reset automatically on object acquisition + Sticky, ///< Never reset automatically + Pulse, ///< Reset automatically on wakeup }; class Object : NonCopyable { diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/readable_event.cpp index 8967e602e..92e16b4e6 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -4,46 +4,37 @@ #include <algorithm> #include "common/assert.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/object.h" +#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/writable_event.h" namespace Kernel { -Event::Event(KernelCore& kernel) : WaitObject{kernel} {} -Event::~Event() = default; +ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {} +ReadableEvent::~ReadableEvent() = default; -SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) { - SharedPtr<Event> evt(new Event(kernel)); - - evt->signaled = false; - evt->reset_type = reset_type; - evt->name = std::move(name); - - return evt; -} - -bool Event::ShouldWait(Thread* thread) const { +bool ReadableEvent::ShouldWait(Thread* thread) const { return !signaled; } -void Event::Acquire(Thread* thread) { +void ReadableEvent::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); if (reset_type == ResetType::OneShot) signaled = false; } -void Event::Signal() { +void ReadableEvent::Signal() { signaled = true; WakeupAllWaitingThreads(); } -void Event::Clear() { +void ReadableEvent::Clear() { signaled = false; } -void Event::WakeupAllWaitingThreads() { +void ReadableEvent::WakeupAllWaitingThreads() { WaitObject::WakeupAllWaitingThreads(); if (reset_type == ResetType::Pulse) diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h new file mode 100644 index 000000000..b1f1f4871 --- /dev/null +++ b/src/core/hle/kernel/readable_event.h @@ -0,0 +1,55 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/wait_object.h" + +namespace Kernel { + +class KernelCore; +class WritableEvent; + +class ReadableEvent final : public WaitObject { + friend class WritableEvent; + +public: + ~ReadableEvent() override; + + std::string GetTypeName() const override { + return "ReadableEvent"; + } + std::string GetName() const override { + return name; + } + + ResetType GetResetType() const { + return reset_type; + } + + static const HandleType HANDLE_TYPE = HandleType::Event; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + bool ShouldWait(Thread* thread) const override; + void Acquire(Thread* thread) override; + + void WakeupAllWaitingThreads() override; + + void Clear(); + +private: + explicit ReadableEvent(KernelCore& kernel); + + void Signal(); + + ResetType reset_type; + bool signaled; + + std::string name; ///< Name of event (optional) +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 3339777c1..051b09d00 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -20,17 +20,18 @@ #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_wrap.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -1361,7 +1362,7 @@ static ResultCode ResetSignal(Handle handle) { LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); - auto event = handle_table.Get<Event>(handle); + auto event = handle_table.Get<ReadableEvent>(handle); ASSERT(event != nullptr); @@ -1524,7 +1525,7 @@ static ResultCode ClearEvent(Handle handle) { LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); - SharedPtr<Event> evt = handle_table.Get<Event>(handle); + SharedPtr<ReadableEvent> evt = handle_table.Get<ReadableEvent>(handle); if (evt == nullptr) { LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp new file mode 100644 index 000000000..a58ea6ec8 --- /dev/null +++ b/src/core/hle/kernel/writable_event.cpp @@ -0,0 +1,52 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include "common/assert.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" +#include "core/hle/kernel/writable_event.h" + +namespace Kernel { + +WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {} +WritableEvent::~WritableEvent() = default; + +EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_type, + std::string name) { + SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel)); + SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel)); + + writable_event->name = name + ":Writable"; + writable_event->readable = readable_event; + readable_event->name = name + ":Readable"; + readable_event->signaled = false; + readable_event->reset_type = reset_type; + + return {std::move(readable_event), std::move(writable_event)}; +} + +SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const { + return readable; +} + +ResetType WritableEvent::GetResetType() const { + return readable->reset_type; +} + +void WritableEvent::Signal() { + readable->Signal(); +} + +void WritableEvent::Clear() { + readable->Clear(); +} + +bool WritableEvent::IsSignaled() const { + return readable->signaled; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/writable_event.h index 27d6126b0..fc57d18d7 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/writable_event.h @@ -11,20 +11,29 @@ namespace Kernel { class KernelCore; +class ReadableEvent; +class WritableEvent; -class Event final : public WaitObject { +struct EventPair { + SharedPtr<ReadableEvent> readable; + SharedPtr<WritableEvent> writable; +}; + +class WritableEvent final : public Object { public: + ~WritableEvent() override; + /** * Creates an event * @param kernel The kernel instance to create this event under. * @param reset_type ResetType describing how to create event * @param name Optional name of event */ - static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type, - std::string name = "Unknown"); + static EventPair CreateEventPair(KernelCore& kernel, ResetType reset_type, + std::string name = "Unknown"); std::string GetTypeName() const override { - return "Event"; + return "WritableEvent"; } std::string GetName() const override { return name; @@ -35,25 +44,19 @@ public: return HANDLE_TYPE; } - ResetType GetResetType() const { - return reset_type; - } - - bool ShouldWait(Thread* thread) const override; - void Acquire(Thread* thread) override; + SharedPtr<ReadableEvent> GetReadableEvent() const; - void WakeupAllWaitingThreads() override; + ResetType GetResetType() const; void Signal(); void Clear(); + bool IsSignaled() const; private: - explicit Event(KernelCore& kernel); - ~Event() override; + explicit WritableEvent(KernelCore& kernel); - ResetType reset_type; ///< Current ResetType + SharedPtr<ReadableEvent> readable; - bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) }; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d595c37b0..3a7b6da84 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -9,9 +9,11 @@ #include "audio_core/audio_renderer.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" @@ -208,8 +210,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - launchable_event = - Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); + launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + "ISelfController:LaunchableEvent"); } ISelfController::~ISelfController() = default; @@ -295,11 +297,11 @@ void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); - launchable_event->Signal(); + launchable_event.writable->Signal(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(launchable_event); + rb.PushCopyObjects(launchable_event.readable); } void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { @@ -348,36 +350,38 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c AppletMessageQueue::AppletMessageQueue() { auto& kernel = Core::System::GetInstance().Kernel(); - on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, - "AMMessageQueue:OnMessageRecieved"); - on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "AMMessageQueue:OperationModeChanged"); + on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + "AMMessageQueue:OnMessageRecieved"); + on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged"); } AppletMessageQueue::~AppletMessageQueue() = default; -const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const { - return on_new_message; +const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent() + const { + return on_new_message.readable; } -const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const { - return on_operation_mode_changed; +const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() + const { + return on_operation_mode_changed.readable; } void AppletMessageQueue::PushMessage(AppletMessage msg) { messages.push(msg); - on_new_message->Signal(); + on_new_message.writable->Signal(); } AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { if (messages.empty()) { - on_new_message->Clear(); + on_new_message.writable->Clear(); return AppletMessage::NoMessage; } auto msg = messages.front(); messages.pop(); if (messages.empty()) { - on_new_message->Clear(); + on_new_message.writable->Clear(); } return msg; } @@ -389,7 +393,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const { void AppletMessageQueue::OperationModeChanged() { PushMessage(AppletMessage::OperationModeChanged); PushMessage(AppletMessage::PerformanceModeChanged); - on_operation_mode_changed->Signal(); + on_operation_mode_changed.writable->Signal(); } ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) @@ -426,9 +430,6 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q // clang-format on RegisterHandlers(functions); - - auto& kernel = Core::System::GetInstance().Kernel(); - event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event"); } ICommonStateGetter::~ICommonStateGetter() = default; @@ -564,8 +565,8 @@ private: void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); + applet->GetBroker().SignalStateChanged(); const auto event = applet->GetBroker().GetStateChangedEvent(); - event->Signal(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 44c1bcde5..34c45fadf 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -6,12 +6,9 @@ #include <memory> #include <queue> +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/service.h" -namespace Kernel { -class Event; -} - namespace Service { namespace NVFlinger { class NVFlinger; @@ -52,8 +49,8 @@ public: AppletMessageQueue(); ~AppletMessageQueue(); - const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const; - const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const; + const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const; + const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const; void PushMessage(AppletMessage msg); AppletMessage PopMessage(); std::size_t GetMessageCount() const; @@ -61,8 +58,8 @@ public: private: std::queue<AppletMessage> messages; - Kernel::SharedPtr<Kernel::Event> on_new_message; - Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed; + Kernel::EventPair on_new_message; + Kernel::EventPair on_operation_mode_changed; }; class IWindowController final : public ServiceFramework<IWindowController> { @@ -122,7 +119,7 @@ private: void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); std::shared_ptr<NVFlinger::NVFlinger> nvflinger; - Kernel::SharedPtr<Kernel::Event> launchable_event; + Kernel::EventPair launchable_event; u32 idle_time_detection_extension = 0; }; @@ -151,7 +148,6 @@ private: void GetBootMode(Kernel::HLERequestContext& ctx); void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); - Kernel::SharedPtr<Kernel::Event> event; std::shared_ptr<AppletMessageQueue> msg_queue; }; diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index becbadd06..47da35537 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -5,8 +5,9 @@ #include <cstring> #include "common/assert.h" #include "core/core.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" @@ -14,11 +15,11 @@ namespace Service::AM::Applets { AppletDataBroker::AppletDataBroker() { auto& kernel = Core::System::GetInstance().Kernel(); - state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "ILibraryAppletAccessor:StateChangedEvent"); - pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "ILibraryAppletAccessor:PopDataOutEvent"); - pop_interactive_out_data_event = Kernel::Event::Create( + state_changed_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent"); + pop_out_data_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopDataOutEvent"); + pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair( kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); } @@ -66,7 +67,7 @@ void AppletDataBroker::PushNormalDataFromGame(IStorage storage) { void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) { out_channel.push(std::make_unique<IStorage>(storage)); - pop_out_data_event->Signal(); + pop_out_data_event.writable->Signal(); } void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { @@ -75,23 +76,23 @@ void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) { out_interactive_channel.push(std::make_unique<IStorage>(storage)); - pop_interactive_out_data_event->Signal(); + pop_interactive_out_data_event.writable->Signal(); } void AppletDataBroker::SignalStateChanged() const { - state_changed_event->Signal(); + state_changed_event.writable->Signal(); } -Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetNormalDataEvent() const { - return pop_out_data_event; +Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const { + return pop_out_data_event.readable; } -Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetInteractiveDataEvent() const { - return pop_interactive_out_data_event; +Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { + return pop_interactive_out_data_event.readable; } -Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetStateChangedEvent() const { - return state_changed_event; +Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const { + return state_changed_event.readable; } Applet::Applet() = default; diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index f65ea119c..b0a8913c3 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -8,13 +8,10 @@ #include <queue> #include "common/swap.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/writable_event.h" union ResultCode; -namespace Kernel { -class Event; -} - namespace Service::AM { class IStorage; @@ -40,9 +37,9 @@ public: void SignalStateChanged() const; - Kernel::SharedPtr<Kernel::Event> GetNormalDataEvent() const; - Kernel::SharedPtr<Kernel::Event> GetInteractiveDataEvent() const; - Kernel::SharedPtr<Kernel::Event> GetStateChangedEvent() const; + Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const; + Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const; + Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const; private: // Queues are named from applet's perspective @@ -59,13 +56,13 @@ private: // PopInteractiveDataToGame and PushInteractiveDataFromApplet std::queue<std::unique_ptr<IStorage>> out_interactive_channel; - Kernel::SharedPtr<Kernel::Event> state_changed_event; + Kernel::EventPair state_changed_event; // Signaled on PushNormalDataFromApplet - Kernel::SharedPtr<Kernel::Event> pop_out_data_event; + Kernel::EventPair pop_out_data_event; // Signaled on PushInteractiveDataFromApplet - Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event; + Kernel::EventPair pop_interactive_out_data_event; }; class Applet { diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index b160c8bee..0417fdb92 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -13,8 +13,10 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/aoc/aoc_u.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" @@ -61,8 +63,8 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - aoc_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, - "GetAddOnContentListChanged:Event"); + aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + "GetAddOnContentListChanged:Event"); } AOC_U::~AOC_U() = default; @@ -144,7 +146,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(aoc_change_event); + rb.PushCopyObjects(aoc_change_event.readable); } void InstallInterfaces(SM::ServiceManager& service_manager) { diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 68d94fdaa..5effea730 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h @@ -6,6 +6,10 @@ #include "core/hle/service/service.h" +namespace Kernel { +class WritableEvent; +} + namespace Service::AOC { class AOC_U final : public ServiceFramework<AOC_U> { @@ -21,7 +25,7 @@ private: void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); std::vector<u64> add_on_content; - Kernel::SharedPtr<Kernel::Event> aoc_change_event; + Kernel::EventPair aoc_change_event; }; /// Registers all AOC services with the specified service manager. diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 2ee9bc273..dc6a6b188 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -13,8 +13,10 @@ #include "common/swap.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/audio/audout_u.h" #include "core/memory.h" @@ -46,8 +48,8 @@ class IAudioOut final : public ServiceFramework<IAudioOut> { public: IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name, std::string&& unique_name) - : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params), - device_name(std::move(device_name)) { + : ServiceFramework("IAudioOut"), audio_core(audio_core), + device_name(std::move(device_name)), audio_params(audio_params) { static const FunctionInfo functions[] = { {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, @@ -67,11 +69,12 @@ public: // This is the event handle used to check if the audio buffer was released auto& kernel = Core::System::GetInstance().Kernel(); - buffer_event = - Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); + buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + "IAudioOutBufferReleased"); stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, - std::move(unique_name), [=]() { buffer_event->Signal(); }); + std::move(unique_name), + [=]() { buffer_event.writable->Signal(); }); } private: @@ -121,7 +124,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(buffer_event); + rb.PushCopyObjects(buffer_event.readable); } void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { @@ -187,8 +190,8 @@ private: AudoutParams audio_params{}; - /// This is the evend handle used to check if the audio buffer was released - Kernel::SharedPtr<Kernel::Event> buffer_event; + /// This is the event handle used to check if the audio buffer was released + Kernel::EventPair buffer_event; }; void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 1c418a9bb..945259c7d 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -12,8 +12,10 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/audio/audren_u.h" namespace Service::Audio { @@ -41,14 +43,14 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - system_event = - Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent"); - renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event); + system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + "IAudioRenderer:SystemEvent"); + renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable); } private: void UpdateAudioCallback() { - system_event->Signal(); + system_event.writable->Signal(); } void GetSampleRate(Kernel::HLERequestContext& ctx) { @@ -112,7 +114,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(system_event); + rb.PushCopyObjects(system_event.readable); } void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { @@ -135,7 +137,7 @@ private: rb.Push(rendering_time_limit_percent); } - Kernel::SharedPtr<Kernel::Event> system_event; + Kernel::EventPair system_event; std::unique_ptr<AudioCore::AudioRenderer> renderer; u32 rendering_time_limit_percent = 100; }; @@ -162,8 +164,8 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "IAudioOutBufferReleasedEvent"); + buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "IAudioOutBufferReleasedEvent"); } private: @@ -207,11 +209,11 @@ private: void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_Audio, "(STUBBED) called"); - buffer_event->Signal(); + buffer_event.writable->Signal(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(buffer_event); + rb.PushCopyObjects(buffer_event.readable); } void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { @@ -222,7 +224,7 @@ private: rb.Push<u32>(1); } - Kernel::SharedPtr<Kernel::Event> buffer_event; + Kernel::EventPair buffer_event; }; // namespace Audio diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index 2eadcdd05..5704ca0ab 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -4,8 +4,10 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/btdrv/btdrv.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" @@ -30,20 +32,22 @@ public: }; // clang-format on RegisterHandlers(functions); + + auto& kernel = Core::System::GetInstance().Kernel(); + register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "BT:RegisterEvent"); } private: void RegisterEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_BTM, "(STUBBED) called"); - auto& kernel = Core::System::GetInstance().Kernel(); - register_event = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "BT:RegisterEvent"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(register_event); + rb.PushCopyObjects(register_event.readable); } - Kernel::SharedPtr<Kernel::Event> register_event; + + Kernel::EventPair register_event; }; class BtDrv final : public ServiceFramework<BtDrv> { diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index 463a79351..ef7398a23 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -6,8 +6,10 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/btm/btm.h" #include "core/hle/service/service.h" @@ -53,53 +55,55 @@ public: }; // clang-format on RegisterHandlers(functions); + + auto& kernel = Core::System::GetInstance().Kernel(); + scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "IBtmUserCore:ScanEvent"); + connection_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent"); + service_discovery = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery"); + config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "IBtmUserCore:ConfigEvent"); } private: void GetScanEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_BTM, "(STUBBED) called"); - auto& kernel = Core::System::GetInstance().Kernel(); - scan_event = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ScanEvent"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(scan_event); + rb.PushCopyObjects(scan_event.readable); } + void GetConnectionEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_BTM, "(STUBBED) called"); - auto& kernel = Core::System::GetInstance().Kernel(); - connection_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "IBtmUserCore:ConnectionEvent"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(connection_event); + rb.PushCopyObjects(connection_event.readable); } + void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_BTM, "(STUBBED) called"); - auto& kernel = Core::System::GetInstance().Kernel(); - service_discovery = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(service_discovery); + rb.PushCopyObjects(service_discovery.readable); } + void GetConfigEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_BTM, "(STUBBED) called"); - auto& kernel = Core::System::GetInstance().Kernel(); - config_event = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConfigEvent"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(config_event); + rb.PushCopyObjects(config_event.readable); } - Kernel::SharedPtr<Kernel::Event> scan_event; - Kernel::SharedPtr<Kernel::Event> connection_event; - Kernel::SharedPtr<Kernel::Event> service_discovery; - Kernel::SharedPtr<Kernel::Event> config_event; + + Kernel::EventPair scan_event; + Kernel::EventPair connection_event; + Kernel::EventPair service_discovery; + Kernel::EventPair config_event; }; class BTM_USR final : public ServiceFramework<BTM_USR> { diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp index ee11cd78e..d9b32954e 100644 --- a/src/core/hle/service/erpt/erpt.cpp +++ b/src/core/hle/service/erpt/erpt.cpp @@ -17,11 +17,13 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "SubmitContext"}, {1, nullptr, "CreateReport"}, - {2, nullptr, "Unknown1"}, - {3, nullptr, "Unknown2"}, - {4, nullptr, "Unknown3"}, - {5, nullptr, "Unknown4"}, - {6, nullptr, "Unknown5"}, + {2, nullptr, "SetInitialLaunchSettingsCompletionTime"}, + {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"}, + {4, nullptr, "UpdatePowerOnTime"}, + {5, nullptr, "UpdateAwakeTime"}, + {6, nullptr, "SubmitMultipleCategoryContext"}, + {7, nullptr, "UpdateApplicationLaunchTime"}, + {8, nullptr, "ClearApplicationLaunchTime"}, }; // clang-format on diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index dbef3b2e4..b1490e6fa 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -113,6 +113,18 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str return RESULT_SUCCESS; } +ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const { + const std::string sanitized_path(FileUtil::SanitizePath(path)); + auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path)); + + if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) { + // TODO(DarkLordZach): Find a better error code for this + return ResultCode(-1); + } + + return RESULT_SUCCESS; +} + ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, const std::string& dest_path_) const { std::string src_path(FileUtil::SanitizePath(src_path_)); diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 93bf1b793..965414be0 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -113,6 +113,18 @@ public: ResultCode DeleteDirectoryRecursively(const std::string& path) const; /** + * Cleans the specified directory. This is similar to DeleteDirectoryRecursively, + * in that it deletes all the contents of the specified directory, however, this + * function does *not* delete the directory itself. It only deletes everything + * within it. + * + * @param path Path relative to the archive. + * + * @return Result of the operation. + */ + ResultCode CleanDirectoryRecursively(const std::string& path) const; + + /** * Rename a File specified by its path * @param src_path Source path relative to the archive * @param dest_path Destination path relative to the archive diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 99d9ebc39..694ec40ec 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -291,7 +291,7 @@ public: {10, &IFileSystem::Commit, "Commit"}, {11, nullptr, "GetFreeSpaceSize"}, {12, nullptr, "GetTotalSpaceSize"}, - {13, nullptr, "CleanDirectoryRecursively"}, + {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, {14, nullptr, "GetFileTimeStampRaw"}, {15, nullptr, "QueryEntry"}, }; @@ -361,6 +361,16 @@ public: rb.Push(backend.DeleteDirectoryRecursively(name)); } + void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. Directory: {}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CleanDirectoryRecursively(name)); + } + void RenameFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 22e87a50a..d6829d0b8 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -12,7 +12,9 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/frontend/input.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/settings.h" @@ -167,8 +169,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { void Controller_NPad::OnInit() { auto& kernel = Core::System::GetInstance().Kernel(); - styleset_changed_event = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); + styleset_changed_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); if (!IsControllerActivated()) { return; @@ -494,7 +496,7 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { had_controller_update = true; } if (had_controller_update) { - styleset_changed_event->Signal(); + styleset_changed_event.writable->Signal(); } } } @@ -509,7 +511,7 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { } void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { - styleset_changed_event->Signal(); + styleset_changed_event.writable->Signal(); hold_type = joy_hold_type; } @@ -518,8 +520,9 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { } void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { - ASSERT(npad_id < shared_memory_entries.size()); - shared_memory_entries[npad_id].pad_assignment = assignment_mode; + const std::size_t npad_index = NPadIdToIndex(npad_id); + ASSERT(npad_index < shared_memory_entries.size()); + shared_memory_entries[npad_index].pad_assignment = assignment_mode; } void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, @@ -538,11 +541,11 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, last_processed_vibration = vibrations.back(); } -Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { +Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const { // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should // be signalled at least once, and signaled after a new controller is connected? - styleset_changed_event->Signal(); - return styleset_changed_event; + styleset_changed_event.writable->Signal(); + return styleset_changed_event.readable; } Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index abff6544d..29851f16a 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -8,7 +8,8 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "core/frontend/input.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/settings.h" @@ -108,7 +109,7 @@ public: void VibrateController(const std::vector<u32>& controller_ids, const std::vector<Vibration>& vibrations); - Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; + Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const; Vibration GetLastVibration() const; void AddNewController(NPadControllerType controller); @@ -303,7 +304,7 @@ private: sticks; std::vector<u32> supported_npad_id_types{}; NpadHoldType hold_type{NpadHoldType::Vertical}; - Kernel::SharedPtr<Kernel::Event> styleset_changed_event; + Kernel::EventPair styleset_changed_event; Vibration last_processed_vibration{}; std::array<ControllerHolder, 10> connected_controllers{}; bool can_controllers_vibrate{true}; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 46496e9bb..2ec38c726 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -13,8 +13,9 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/irs.h" #include "core/hle/service/hid/xcd.h" diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index ff9170c24..d5df112a0 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -7,7 +7,9 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/nfp/nfp.h" @@ -23,8 +25,8 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) { auto& kernel = Core::System::GetInstance().Kernel(); - nfc_tag_load = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected"); + nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "IUser:NFCTagDetected"); } Module::Interface::~Interface() = default; @@ -63,10 +65,10 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - deactivate_event = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); - availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "IUser:AvailabilityChangeEvent"); + deactivate_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); + availability_change_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent"); } private: @@ -164,7 +166,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(deactivate_event); + rb.PushCopyObjects(deactivate_event.readable); } void StopDetection(Kernel::HLERequestContext& ctx) { @@ -173,7 +175,7 @@ private: switch (device_state) { case DeviceState::TagFound: case DeviceState::TagNearby: - deactivate_event->Signal(); + deactivate_event.writable->Signal(); device_state = DeviceState::Initialized; break; case DeviceState::SearchingForTag: @@ -264,7 +266,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(availability_change_event); + rb.PushCopyObjects(availability_change_event.readable); } void GetRegisterInfo(Kernel::HLERequestContext& ctx) { @@ -319,8 +321,8 @@ private: const u32 npad_id{0}; // Player 1 controller State state{State::NonInitialized}; DeviceState device_state{DeviceState::Initialized}; - Kernel::SharedPtr<Kernel::Event> deactivate_event; - Kernel::SharedPtr<Kernel::Event> availability_change_event; + Kernel::EventPair deactivate_event; + Kernel::EventPair availability_change_event; const Module::Interface& nfp_interface; }; @@ -339,12 +341,14 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { } std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); - nfc_tag_load->Signal(); + nfc_tag_load.writable->Signal(); return true; } -const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { - return nfc_tag_load; + +const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const { + return nfc_tag_load.readable; } + const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { return amiibo; } diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 5c0ae8a54..a1817e991 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -6,7 +6,8 @@ #include <array> #include <vector> -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/service.h" namespace Service::NFP { @@ -33,11 +34,11 @@ public: void CreateUserInterface(Kernel::HLERequestContext& ctx); bool LoadAmiibo(const std::vector<u8>& buffer); - const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; + const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const; const AmiiboFile& GetAmiiboBuffer() const; private: - Kernel::SharedPtr<Kernel::Event> nfc_tag_load{}; + Kernel::EventPair nfc_tag_load{}; AmiiboFile amiibo{}; protected: diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index dee391201..60479bb45 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -4,7 +4,9 @@ #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/nifm/nifm.h" #include "core/hle/service/service.h" @@ -56,8 +58,10 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1"); - event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2"); + event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "IRequest:Event1"); + event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "IRequest:Event2"); } private: @@ -88,7 +92,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 2}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(event1, event2); + rb.PushCopyObjects(event1.readable, event2.readable); } void Cancel(Kernel::HLERequestContext& ctx) { @@ -105,7 +109,7 @@ private: rb.Push(RESULT_SUCCESS); } - Kernel::SharedPtr<Kernel::Event> event1, event2; + Kernel::EventPair event1, event2; }; class INetworkProfile final : public ServiceFramework<INetworkProfile> { diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 1bbccd444..0dabcd23b 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -6,7 +6,9 @@ #include <ctime> #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/nim/nim.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" @@ -138,19 +140,18 @@ public: RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - finished_event = - Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, - "IEnsureNetworkClockAvailabilityService:FinishEvent"); + finished_event = Kernel::WritableEvent::CreateEventPair( + kernel, Kernel::ResetType::OneShot, + "IEnsureNetworkClockAvailabilityService:FinishEvent"); } private: - Kernel::SharedPtr<Kernel::Event> finished_event; + Kernel::EventPair finished_event; void StartTask(Kernel::HLERequestContext& ctx) { // No need to connect to the internet, just finish the task straight away. LOG_DEBUG(Service_NIM, "called"); - - finished_event->Signal(); + finished_event.writable->Signal(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -160,7 +161,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(finished_event); + rb.PushCopyObjects(finished_event.readable); } void GetResult(Kernel::HLERequestContext& ctx) { @@ -172,8 +173,7 @@ private: void Cancel(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NIM, "called"); - - finished_event->Clear(); + finished_event.writable->Clear(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index ff76e0524..3b9ab4b14 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -6,7 +6,9 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -69,7 +71,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(query_event); + rb.PushCopyObjects(query_event.readable); rb.Push<u32>(0); } @@ -127,7 +129,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) RegisterHandlers(functions); auto& kernel = Core::System::GetInstance().Kernel(); - query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event"); + query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, + "NVDRV::query_event"); } NVDRV::~NVDRV() = default; diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 5a1e4baa7..fe311b069 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -5,10 +5,13 @@ #pragma once #include <memory> -#include "core/hle/kernel/event.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/service.h" +namespace Kernel { +class WritableEvent; +} + namespace Service::Nvidia { class NVDRV final : public ServiceFramework<NVDRV> { @@ -31,7 +34,7 @@ private: u64 pid{}; - Kernel::SharedPtr<Kernel::Event> query_event; + Kernel::EventPair query_event; }; } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 172a1a441..fc07d9bb8 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -7,14 +7,17 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvflinger/buffer_queue.h" namespace Service::NVFlinger { BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { auto& kernel = Core::System::GetInstance().Kernel(); - buffer_wait_event = - Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); + buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, + "BufferQueue NativeHandle"); } BufferQueue::~BufferQueue() = default; @@ -28,7 +31,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) buffer.status = Buffer::Status::Free; queue.emplace_back(buffer); - buffer_wait_event->Signal(); + buffer_wait_event.writable->Signal(); } std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { @@ -87,7 +90,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) { ASSERT(itr->status == Buffer::Status::Acquired); itr->status = Buffer::Status::Free; - buffer_wait_event->Signal(); + buffer_wait_event.writable->Signal(); } u32 BufferQueue::Query(QueryType type) { @@ -104,4 +107,12 @@ u32 BufferQueue::Query(QueryType type) { return 0; } +Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { + return buffer_wait_event.writable; +} + +Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const { + return buffer_wait_event.readable; +} + } // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 8cff5eb71..b171f256c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -10,7 +10,8 @@ #include "common/common_funcs.h" #include "common/math_util.h" #include "common/swap.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/writable_event.h" namespace CoreTiming { struct EventType; @@ -86,16 +87,16 @@ public: return id; } - Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const { - return buffer_wait_event; - } + Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const; + + Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const; private: u32 id; u64 layer_id; std::vector<Buffer> queue; - Kernel::SharedPtr<Kernel::Event> buffer_wait_event; + Kernel::EventPair buffer_wait_event; }; } // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 214e6d1b3..05af2d593 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -13,6 +13,9 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" @@ -83,9 +86,8 @@ u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) { return layer.buffer_queue->GetId(); } -Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { - const auto& display = GetDisplay(display_id); - return display.vsync_event; +Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) { + return GetDisplay(display_id).vsync_event.readable; } std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { @@ -117,7 +119,7 @@ Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { void NVFlinger::Compose() { for (auto& display : displays) { // Trigger vsync for this display at the end of drawing - SCOPE_EXIT({ display.vsync_event->Signal(); }); + SCOPE_EXIT({ display.vsync_event.writable->Signal(); }); // Don't do anything for displays without layers. if (display.layers.empty()) @@ -164,7 +166,8 @@ Layer::~Layer() = default; Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { auto& kernel = Core::System::GetInstance().Kernel(); - vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event"); + vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse, + fmt::format("Display VSync Event {}", id)); } Display::~Display() = default; diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 3dc69e69b..9abba555b 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -10,12 +10,17 @@ #include <vector> #include "common/common_types.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/object.h" namespace CoreTiming { struct EventType; } +namespace Kernel { +class ReadableEvent; +class WritableEvent; +} // namespace Kernel + namespace Service::Nvidia { class Module; } @@ -40,7 +45,7 @@ struct Display { std::string name; std::vector<Layer> layers; - Kernel::SharedPtr<Kernel::Event> vsync_event; + Kernel::EventPair vsync_event; }; class NVFlinger final { @@ -61,7 +66,7 @@ public: u32 GetBufferQueueId(u64 display_id, u64 layer_id); /// Gets the vsync event for the specified display. - Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); + Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id); /// Obtains a buffer queue identified by the id. std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index f082a63bc..58a9845fc 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp @@ -73,7 +73,7 @@ public: {3, nullptr, "Populate"}, {4, nullptr, "PostBufferAsync"}, {5, nullptr, "GetXferReport"}, - {6, nullptr, "Unknown2"}, + {6, nullptr, "PostBufferMultiAsync"}, {7, nullptr, "Unknown3"}, {8, nullptr, "Unknown4"}, }; diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 5120abfff..311b0c765 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -18,7 +18,8 @@ #include "common/swap.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -542,12 +543,14 @@ private: // Repeat TransactParcel DequeueBuffer when a buffer is available auto buffer_queue = nv_flinger->GetBufferQueue(id); std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); + ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer."); + IGBPDequeueBufferResponseParcel response{*slot}; ctx.WriteBuffer(response.Serialize()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); }, - buffer_queue->GetBufferWaitEvent()); + buffer_queue->GetWritableBufferWaitEvent()); } } else if (transaction == TransactionId::RequestBuffer) { IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index d3b3ed1f0..25bb7604a 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -42,6 +42,7 @@ public: static constexpr std::size_t NumVertexArrays = 32; static constexpr std::size_t NumVertexAttributes = 32; static constexpr std::size_t NumTextureSamplers = 32; + static constexpr std::size_t NumClipDistances = 8; static constexpr std::size_t MaxShaderProgram = 6; static constexpr std::size_t MaxShaderStage = 5; // Maximum number of const buffers per shader stage. diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a44bbfae8..9e93bd609 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -88,19 +88,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo state.texture_units[i].sampler = texture_samplers[i].sampler.handle; } - GLint ext_num; - glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num); - for (GLint i = 0; i < ext_num; i++) { - const std::string_view extension{ - reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))}; - - if (extension == "GL_ARB_direct_state_access") { - has_ARB_direct_state_access = true; - } else if (extension == "GL_ARB_multi_bind") { - has_ARB_multi_bind = true; - } - } - OpenGLState::ApplyDefaultState(); // Create render framebuffer @@ -295,6 +282,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; u32 current_texture_bindpoint = 0; + std::array<bool, Maxwell::NumClipDistances> clip_distances{}; for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { const auto& shader_config = gpu.regs.shader_config[index]; @@ -355,12 +343,22 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader, primitive_mode, current_texture_bindpoint); + // Workaround for Intel drivers. + // When a clip distance is enabled but not set in the shader it crops parts of the screen + // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the + // clip distances only when it's written by a shader stage. + for (std::size_t i = 0; i < Maxwell::NumClipDistances; ++i) { + clip_distances[i] |= shader->GetShaderEntries().clip_distances[i]; + } + // When VertexA is enabled, we have dual vertex shaders if (program == Maxwell::ShaderProgram::VertexA) { // VertexB was combined with VertexA, so we skip the VertexB iteration index++; } } + + SyncClipEnabled(clip_distances); } std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { @@ -443,7 +441,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us // TODO(bunnei): Figure out how the below register works. According to envytools, this should be // used to enable multiple render targets. However, it is left unset on all games that I have // tested. - ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); + UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0); // Bind the framebuffer surfaces current_state.draw.draw_framebuffer = framebuffer.handle; @@ -642,7 +640,6 @@ void RasterizerOpenGL::DrawArrays() { SyncCullMode(); SyncPrimitiveRestart(); SyncScissorTest(state); - SyncClipEnabled(); // Alpha Testing is synced on shaders. SyncTransformFeedback(); SyncPointState(); @@ -1019,20 +1016,23 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; } -void RasterizerOpenGL::SyncClipEnabled() { +void RasterizerOpenGL::SyncClipEnabled( + const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - state.clip_distance[0] = regs.clip_distance_enabled.c0 != 0; - state.clip_distance[1] = regs.clip_distance_enabled.c1 != 0; - state.clip_distance[2] = regs.clip_distance_enabled.c2 != 0; - state.clip_distance[3] = regs.clip_distance_enabled.c3 != 0; - state.clip_distance[4] = regs.clip_distance_enabled.c4 != 0; - state.clip_distance[5] = regs.clip_distance_enabled.c5 != 0; - state.clip_distance[6] = regs.clip_distance_enabled.c6 != 0; - state.clip_distance[7] = regs.clip_distance_enabled.c7 != 0; + const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{ + regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0, + regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0, + regs.clip_distance_enabled.c4 != 0, regs.clip_distance_enabled.c5 != 0, + regs.clip_distance_enabled.c6 != 0, regs.clip_distance_enabled.c7 != 0}; + + for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) { + state.clip_distance[i] = reg_state[i] && clip_mask[i]; + } } void RasterizerOpenGL::SyncClipCoef() { - UNREACHABLE(); + UNIMPLEMENTED(); } void RasterizerOpenGL::SyncCullMode() { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 7ec9746b1..988fa3e27 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -60,20 +60,6 @@ public: bool AccelerateDrawBatch(bool is_indexed) override; void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override; - /// OpenGL shader generated for a given Maxwell register state - struct MaxwellShader { - /// OpenGL shader resource - OGLProgram shader; - }; - - struct VertexShader { - OGLShader shader; - }; - - struct FragmentShader { - OGLShader shader; - }; - /// Maximum supported size that a constbuffer can have in bytes. static constexpr std::size_t MaxConstbufferSize = 0x10000; static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, @@ -142,7 +128,8 @@ private: void SyncViewport(OpenGLState& current_state); /// Syncs the clip enabled status to match the guest state - void SyncClipEnabled(); + void SyncClipEnabled( + const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& clip_mask); /// Syncs the clip coefficients to match the guest state void SyncClipCoef(); @@ -193,9 +180,6 @@ private: /// but are needed for correct emulation void CheckExtensions(); - bool has_ARB_direct_state_access = false; - bool has_ARB_multi_bind = false; - OpenGLState state; RasterizerCacheOpenGL res_cache; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index dde2f468d..5f4cdd119 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -405,138 +405,6 @@ void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params, } } -MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64)); -static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, - GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0, - GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { - MICROPROFILE_SCOPE(OpenGL_BlitSurface); - - const auto& src_params{src_surface->GetSurfaceParams()}; - const auto& dst_params{dst_surface->GetSurfaceParams()}; - - OpenGLState prev_state{OpenGLState::GetCurState()}; - SCOPE_EXIT({ prev_state.Apply(); }); - - OpenGLState state; - state.draw.read_framebuffer = read_fb_handle; - state.draw.draw_framebuffer = draw_fb_handle; - // Set sRGB enabled if the destination surfaces need it - state.framebuffer_srgb.enabled = dst_params.srgb_conversion; - state.ApplyFramebufferState(); - - u32 buffers{}; - - if (src_params.type == SurfaceType::ColorTexture) { - switch (src_params.target) { - case SurfaceTarget::Texture2D: - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, - GL_TEXTURE_2D, src_surface->Texture().handle, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - 0, 0); - break; - case SurfaceTarget::TextureCubemap: - glFramebufferTexture2D( - GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, - static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), - src_surface->Texture().handle, 0); - glFramebufferTexture2D( - GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); - break; - case SurfaceTarget::Texture2DArray: - glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, - src_surface->Texture().handle, 0, 0); - glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); - break; - case SurfaceTarget::Texture3D: - glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, - SurfaceTargetToGL(src_params.target), - src_surface->Texture().handle, 0, 0); - glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - SurfaceTargetToGL(src_params.target), 0, 0, 0); - break; - default: - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, - GL_TEXTURE_2D, src_surface->Texture().handle, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - 0, 0); - break; - } - - switch (dst_params.target) { - case SurfaceTarget::Texture2D: - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, - GL_TEXTURE_2D, dst_surface->Texture().handle, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - 0, 0); - break; - case SurfaceTarget::TextureCubemap: - glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, - static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), - dst_surface->Texture().handle, 0); - glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); - break; - case SurfaceTarget::Texture2DArray: - glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, - dst_surface->Texture().handle, 0, 0); - glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); - break; - - case SurfaceTarget::Texture3D: - glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, - SurfaceTargetToGL(dst_params.target), - dst_surface->Texture().handle, 0, 0); - glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - SurfaceTargetToGL(dst_params.target), 0, 0, 0); - break; - default: - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, - GL_TEXTURE_2D, dst_surface->Texture().handle, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - 0, 0); - break; - } - - buffers = GL_COLOR_BUFFER_BIT; - } else if (src_params.type == SurfaceType::Depth) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, - GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - src_surface->Texture().handle, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, - GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - dst_surface->Texture().handle, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - - buffers = GL_DEPTH_BUFFER_BIT; - } else if (src_params.type == SurfaceType::DepthStencil) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, - GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - src_surface->Texture().handle, 0); - - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, - GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - dst_surface->Texture().handle, 0); - - buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - } - - const auto& rect{src_params.GetRect()}; - glBlitFramebuffer(rect.left, rect.bottom, rect.right, rect.top, rect.left, rect.bottom, - rect.right, rect.top, buffers, - buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); - - return true; -} - static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) { const auto& src_params{src_surface->GetSurfaceParams()}; const auto& dst_params{dst_surface->GetSurfaceParams()}; @@ -841,9 +709,10 @@ void CachedSurface::LoadGLBuffer() { const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; gl_buffer[0].assign(texture_src_data, texture_src_data_end); } - for (u32 i = 0; i < params.max_mip_level; i++) + for (u32 i = 0; i < params.max_mip_level; i++) { ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), params.MipHeight(i), params.MipDepth(i)); + } } MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); @@ -1163,7 +1032,10 @@ void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface) { const auto& src_params{src_surface->GetSurfaceParams()}; const auto& dst_params{dst_surface->GetSurfaceParams()}; - FlushRegion(src_params.addr, dst_params.MemorySize()); + + // Flush enough memory for both the source and destination surface + FlushRegion(src_params.addr, std::max(src_params.MemorySize(), dst_params.MemorySize())); + LoadSurface(dst_surface); } @@ -1189,20 +1061,9 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, return new_surface; } - // If the format is the same, just do a framebuffer blit. This is significantly faster than - // using PBOs. The is also likely less accurate, as textures will be converted rather than - // reinterpreted. When use_accurate_gpu_emulation setting is enabled, perform a more accurate - // surface copy, where pixels are reinterpreted as a new format (without conversion). This - // code path uses OpenGL PBOs and is quite slow. - const bool is_blit{old_params.pixel_format == new_params.pixel_format}; - switch (new_params.target) { case SurfaceTarget::Texture2D: - if (is_blit) { - BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle); - } else { - CopySurface(old_surface, new_surface, copy_pbo.handle); - } + CopySurface(old_surface, new_surface, copy_pbo.handle); break; case SurfaceTarget::Texture3D: AccurateCopySurface(old_surface, new_surface); diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 0c4524d5c..d235bfcd4 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -201,14 +201,53 @@ private: } }; +template <typename T> +class ShaderScopedScope { +public: + explicit ShaderScopedScope(T& writer, std::string_view begin_expr, std::string end_expr) + : writer(writer), end_expr(std::move(end_expr)) { + + if (begin_expr.empty()) { + writer.AddLine('{'); + } else { + writer.AddExpression(begin_expr); + writer.AddLine(" {"); + } + ++writer.scope; + } + + ShaderScopedScope(const ShaderScopedScope&) = delete; + + ~ShaderScopedScope() { + --writer.scope; + if (end_expr.empty()) { + writer.AddLine('}'); + } else { + writer.AddExpression("} "); + writer.AddExpression(end_expr); + writer.AddLine(';'); + } + } + + ShaderScopedScope& operator=(const ShaderScopedScope&) = delete; + +private: + T& writer; + std::string end_expr; +}; + class ShaderWriter { public: - void AddLine(std::string_view text) { + void AddExpression(std::string_view text) { DEBUG_ASSERT(scope >= 0); if (!text.empty()) { AppendIndentation(); } shader_source += text; + } + + void AddLine(std::string_view text) { + AddExpression(text); AddNewLine(); } @@ -228,6 +267,11 @@ public: return std::move(shader_source); } + ShaderScopedScope<ShaderWriter> Scope(std::string_view begin_expr = {}, + std::string end_expr = {}) { + return ShaderScopedScope(*this, begin_expr, end_expr); + } + int scope = 0; private: @@ -311,7 +355,7 @@ public: // Default - do nothing return value; default: - UNIMPLEMENTED_MSG("Unimplemented conversion size: {}", static_cast<u32>(size)); + UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size)); } } @@ -525,6 +569,7 @@ public: ((header.vtg.clip_distances >> index) & 1) == 0, "Shader is setting gl_ClipDistance{} without enabling it in the header", index); + clip_distances[index] = true; fixed_pipeline_output_attributes_used.insert(attribute); shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';'); break; @@ -602,6 +647,11 @@ public: return used_samplers; } + /// Returns an array of the used clip distances. + const std::array<bool, Maxwell::NumClipDistances>& GetClipDistances() const { + return clip_distances; + } + /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if /// necessary. std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, @@ -810,14 +860,12 @@ private: } if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) { - shader.AddLine('{'); - ++shader.scope; + const auto scope = shader.Scope(); + // This avoids optimizations of constant propagation and keeps the code as the original // Sadly using the precise keyword causes "linking" errors on fragment shaders. shader.AddLine("precise float tmp = " + src + ';'); shader.AddLine(dest + " = tmp;"); - --shader.scope; - shader.AddLine('}'); } else { shader.AddLine(dest + " = " + src + ';'); } @@ -975,6 +1023,7 @@ private: const std::string& suffix; const Tegra::Shader::Header& header; std::unordered_set<Attribute::Index> fixed_pipeline_output_attributes_used; + std::array<bool, Maxwell::NumClipDistances> clip_distances{}; u64 local_memory_size; }; @@ -997,7 +1046,8 @@ public: /// Returns entries in the shader that are useful for external functions ShaderEntries GetEntries() const { - return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length}; + return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), regs.GetClipDistances(), + shader_length}; } private: @@ -1293,15 +1343,7 @@ private: regs.SetRegisterToInteger(dest, true, 0, result, 1, 1); } - void WriteTexsInstruction(const Instruction& instr, const std::string& coord, - const std::string& texture) { - // Add an extra scope and declare the texture coords inside to prevent - // overwriting them in case they are used as outputs of the texs instruction. - shader.AddLine('{'); - ++shader.scope; - shader.AddLine(coord); - shader.AddLine("vec4 texture_tmp = " + texture + ';'); - + void WriteTexsInstruction(const Instruction& instr, const std::string& texture) { // TEXS has two destination registers and a swizzle. The first two elements in the swizzle // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 @@ -1313,19 +1355,17 @@ private: if (written_components < 2) { // Write the first two swizzle components to gpr0 and gpr0+1 - regs.SetRegisterToFloat(instr.gpr0, component, "texture_tmp", 1, 4, false, + regs.SetRegisterToFloat(instr.gpr0, component, texture, 1, 4, false, written_components % 2); } else { ASSERT(instr.texs.HasTwoDestinations()); // Write the rest of the swizzle components to gpr28 and gpr28+1 - regs.SetRegisterToFloat(instr.gpr28, component, "texture_tmp", 1, 4, false, + regs.SetRegisterToFloat(instr.gpr28, component, texture, 1, 4, false, written_components % 2); } ++written_components; } - --shader.scope; - shader.AddLine('}'); } static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { @@ -1348,12 +1388,10 @@ private: * top. */ void EmitPushToFlowStack(u32 target) { - shader.AddLine('{'); - ++shader.scope; + const auto scope = shader.Scope(); + shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;"); shader.AddLine("flow_stack_top++;"); - --shader.scope; - shader.AddLine('}'); } /* @@ -1361,13 +1399,11 @@ private: * popped address and decrementing the stack top. */ void EmitPopFromFlowStack() { - shader.AddLine('{'); - ++shader.scope; + const auto scope = shader.Scope(); + shader.AddLine("flow_stack_top--;"); shader.AddLine("jmp_to = flow_stack[flow_stack_top];"); shader.AddLine("break;"); - --shader.scope; - shader.AddLine('}'); } /// Writes the output values from a fragment shader to the corresponding GLSL output variables. @@ -2279,8 +2315,7 @@ private: UNIMPLEMENTED_IF(instr.conversion.selector); UNIMPLEMENTED_IF_MSG(instr.generates_cc, "Condition codes generation in I2F is not implemented"); - - std::string op_a{}; + std::string op_a; if (instr.is_b_gpr) { op_a = @@ -2436,10 +2471,7 @@ private: case OpCode::Id::LD_C: { UNIMPLEMENTED_IF(instr.ld_c.unknown != 0); - // Add an extra scope and declare the index register inside to prevent - // overwriting it in case it is used as an output of the LD instruction. - shader.AddLine("{"); - ++shader.scope; + const auto scope = shader.Scope(); shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);"); @@ -2465,19 +2497,13 @@ private: UNIMPLEMENTED_MSG("Unhandled type: {}", static_cast<unsigned>(instr.ld_c.type.Value())); } - - --shader.scope; - shader.AddLine("}"); break; } case OpCode::Id::LD_L: { UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}", static_cast<unsigned>(instr.ld_l.unknown.Value())); - // Add an extra scope and declare the index register inside to prevent - // overwriting it in case it is used as an output of the LD instruction. - shader.AddLine('{'); - ++shader.scope; + const auto scope = shader.Scope(); std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + std::to_string(instr.smem_imm.Value()) + ')'; @@ -2494,9 +2520,6 @@ private: UNIMPLEMENTED_MSG("LD_L Unhandled type: {}", static_cast<unsigned>(instr.ldst_sl.type.Value())); } - - --shader.scope; - shader.AddLine('}'); break; } case OpCode::Id::ST_A: { @@ -2531,10 +2554,7 @@ private: UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}", static_cast<unsigned>(instr.st_l.unknown.Value())); - // Add an extra scope and declare the index register inside to prevent - // overwriting it in case it is used as an output of the LD instruction. - shader.AddLine('{'); - ++shader.scope; + const auto scope = shader.Scope(); std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + std::to_string(instr.smem_imm.Value()) + ')'; @@ -2549,14 +2569,10 @@ private: UNIMPLEMENTED_MSG("ST_L Unhandled type: {}", static_cast<unsigned>(instr.ldst_sl.type.Value())); } - - --shader.scope; - shader.AddLine('}'); break; } case OpCode::Id::TEX: { Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; - std::string coord; const bool is_array = instr.tex.array != 0; UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), @@ -2589,21 +2605,23 @@ private: bool depth_compare_extra = false; + const auto scope = shader.Scope(); + switch (num_coordinates) { case 1: { const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); if (is_array) { if (depth_compare) { - coord = "vec3 coords = vec3(" + x + ", " + depth_value + ", " + - array_elem + ");"; + shader.AddLine("vec3 coords = vec3(" + x + ", " + depth_value + ", " + + array_elem + ");"); } else { - coord = "vec2 coords = vec2(" + x + ", " + array_elem + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + array_elem + ");"); } } else { if (depth_compare) { - coord = "vec2 coords = vec2(" + x + ", " + depth_value + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + depth_value + ");"); } else { - coord = "float coords = " + x + ';'; + shader.AddLine("float coords = " + x + ';'); } } break; @@ -2614,17 +2632,18 @@ private: regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1); if (is_array) { if (depth_compare) { - coord = "vec4 coords = vec4(" + x + ", " + y + ", " + depth_value + - ", " + array_elem + ");"; + shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + + depth_value + ", " + array_elem + ");"); } else { - coord = "vec3 coords = vec3(" + x + ", " + y + ", " + array_elem + ");"; + shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + + array_elem + ");"); } } else { if (depth_compare) { - coord = - "vec3 coords = vec3(" + x + ", " + y + ", " + depth_value + ");"; + shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + + depth_value + ");"); } else { - coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); } } break; @@ -2637,14 +2656,14 @@ private: regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2); if (is_array) { depth_compare_extra = depth_compare; - coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + - array_elem + ");"; + shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + + array_elem + ");"); } else { if (depth_compare) { - coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + - depth_value + ");"; + shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + + depth_value + ");"); } else { - coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"); } } break; @@ -2656,7 +2675,7 @@ private: // Fallback to interpreting as a 2D texture for now const std::string x = regs.GetRegisterAsFloat(instr.gpr8); const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); - coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); texture_type = Tegra::Shader::TextureType::Texture2D; } @@ -2665,79 +2684,61 @@ private: // Add an extra scope and declare the texture coords inside to prevent // overwriting them in case they are used as outputs of the texs instruction. - shader.AddLine('{'); - ++shader.scope; - shader.AddLine(coord); - std::string texture; - - switch (instr.tex.GetTextureProcessMode()) { - case Tegra::Shader::TextureProcessMode::None: { - if (!depth_compare_extra) { - texture = "texture(" + sampler + ", coords)"; - } else { - texture = "texture(" + sampler + ", coords, " + depth_value + ')'; - } - break; - } - case Tegra::Shader::TextureProcessMode::LZ: { - if (!depth_compare_extra) { - texture = "textureLod(" + sampler + ", coords, 0.0)"; - } else { - texture = "texture(" + sampler + ", coords, " + depth_value + ')'; - } - break; - } - case Tegra::Shader::TextureProcessMode::LB: - case Tegra::Shader::TextureProcessMode::LBA: { - // TODO: Figure if A suffix changes the equation at all. - if (!depth_compare_extra) { - texture = "texture(" + sampler + ", coords, " + lod_value + ')'; - } else { - texture = "texture(" + sampler + ", coords, " + depth_value + ')'; - LOG_WARNING(HW_GPU, - "OpenGL Limitation: can't set bias value along depth compare"); - } - break; - } - case Tegra::Shader::TextureProcessMode::LL: - case Tegra::Shader::TextureProcessMode::LLA: { - // TODO: Figure if A suffix changes the equation at all. - if (!depth_compare_extra) { - texture = "textureLod(" + sampler + ", coords, " + lod_value + ')'; - } else { - texture = "texture(" + sampler + ", coords, " + depth_value + ')'; - LOG_WARNING(HW_GPU, - "OpenGL Limitation: can't set lod value along depth compare"); - } - break; - } - default: { - if (!depth_compare_extra) { - texture = "texture(" + sampler + ", coords)"; - } else { - texture = "texture(" + sampler + ", coords, " + depth_value + ')'; + const std::string texture = [&]() { + switch (instr.tex.GetTextureProcessMode()) { + case Tegra::Shader::TextureProcessMode::None: + if (depth_compare_extra) { + return "texture(" + sampler + ", coords, " + depth_value + ')'; + } + return "texture(" + sampler + ", coords)"; + case Tegra::Shader::TextureProcessMode::LZ: + if (depth_compare_extra) { + return "texture(" + sampler + ", coords, " + depth_value + ')'; + } + return "textureLod(" + sampler + ", coords, 0.0)"; + case Tegra::Shader::TextureProcessMode::LB: + case Tegra::Shader::TextureProcessMode::LBA: + // TODO: Figure if A suffix changes the equation at all. + if (depth_compare_extra) { + LOG_WARNING( + HW_GPU, + "OpenGL Limitation: can't set bias value along depth compare"); + return "texture(" + sampler + ", coords, " + depth_value + ')'; + } + return "texture(" + sampler + ", coords, " + lod_value + ')'; + case Tegra::Shader::TextureProcessMode::LL: + case Tegra::Shader::TextureProcessMode::LLA: + // TODO: Figure if A suffix changes the equation at all. + if (depth_compare_extra) { + LOG_WARNING( + HW_GPU, + "OpenGL Limitation: can't set lod value along depth compare"); + return "texture(" + sampler + ", coords, " + depth_value + ')'; + } + return "textureLod(" + sampler + ", coords, " + lod_value + ')'; + default: + UNIMPLEMENTED_MSG("Unhandled texture process mode {}", + static_cast<u32>(instr.tex.GetTextureProcessMode())); + if (depth_compare_extra) { + return "texture(" + sampler + ", coords, " + depth_value + ')'; + } + return "texture(" + sampler + ", coords)"; } - UNIMPLEMENTED_MSG("Unhandled texture process mode {}", - static_cast<u32>(instr.tex.GetTextureProcessMode())); - } - } - if (!depth_compare) { - shader.AddLine("vec4 texture_tmp = " + texture + ';'); + }(); + + if (depth_compare) { + regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); + } else { std::size_t dest_elem{}; for (std::size_t elem = 0; elem < 4; ++elem) { if (!instr.tex.IsComponentEnabled(elem)) { // Skip disabled components continue; } - regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, - dest_elem); + regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); ++dest_elem; } - } else { - regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); } - --shader.scope; - shader.AddLine('}'); break; } case OpCode::Id::TEXS: { @@ -2747,26 +2748,28 @@ private: UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), "NODEP is not implemented"); + const auto scope = shader.Scope(); + const bool depth_compare = instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); u32 num_coordinates = TextureCoordinates(texture_type); const auto process_mode = instr.texs.GetTextureProcessMode(); - std::string lod_value; - std::string coord; u32 lod_offset = 0; if (process_mode == Tegra::Shader::TextureProcessMode::LL) { if (num_coordinates > 2) { - lod_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); + shader.AddLine("float lod_value = " + + regs.GetRegisterAsFloat(instr.gpr20.Value() + 1) + ';'); lod_offset = 2; } else { - lod_value = regs.GetRegisterAsFloat(instr.gpr20); + shader.AddLine("float lod_value = " + regs.GetRegisterAsFloat(instr.gpr20) + + ';'); lod_offset = 1; } } switch (num_coordinates) { case 1: { - coord = "float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';'; + shader.AddLine("float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';'); break; } case 2: { @@ -2776,13 +2779,14 @@ private: const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); const std::string y = regs.GetRegisterAsFloat(instr.gpr20); const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); - coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + - ");"; + shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + + index + ");"); } else { const std::string index = regs.GetRegisterAsInteger(instr.gpr8); const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); const std::string y = regs.GetRegisterAsFloat(instr.gpr20); - coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; + shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + index + + ");"); } } else { if (lod_offset != 0) { @@ -2792,12 +2796,13 @@ private: regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset); - coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + + ");"); } else { const std::string x = regs.GetRegisterAsFloat(instr.gpr8); const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); - coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); } } else { if (depth_compare) { @@ -2805,11 +2810,12 @@ private: const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); const std::string z = regs.GetRegisterAsFloat(instr.gpr20); - coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + + ");"); } else { const std::string x = regs.GetRegisterAsFloat(instr.gpr8); const std::string y = regs.GetRegisterAsFloat(instr.gpr20); - coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); } } } @@ -2819,7 +2825,7 @@ private: const std::string x = regs.GetRegisterAsFloat(instr.gpr8); const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); const std::string z = regs.GetRegisterAsFloat(instr.gpr20); - coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"); break; } default: @@ -2829,42 +2835,37 @@ private: // Fallback to interpreting as a 2D texture for now const std::string x = regs.GetRegisterAsFloat(instr.gpr8); const std::string y = regs.GetRegisterAsFloat(instr.gpr20); - coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); texture_type = Tegra::Shader::TextureType::Texture2D; is_array = false; } const std::string sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); - std::string texture; - switch (process_mode) { - case Tegra::Shader::TextureProcessMode::None: { - texture = "texture(" + sampler + ", coords)"; - break; - } - case Tegra::Shader::TextureProcessMode::LZ: { - if (depth_compare && is_array) { - texture = "texture(" + sampler + ", coords)"; - } else { - texture = "textureLod(" + sampler + ", coords, 0.0)"; + + std::string texture = [&]() { + switch (process_mode) { + case Tegra::Shader::TextureProcessMode::None: + return "texture(" + sampler + ", coords)"; + case Tegra::Shader::TextureProcessMode::LZ: + if (depth_compare && is_array) { + return "texture(" + sampler + ", coords)"; + } else { + return "textureLod(" + sampler + ", coords, 0.0)"; + } + break; + case Tegra::Shader::TextureProcessMode::LL: + return "textureLod(" + sampler + ", coords, lod_value)"; + default: + UNIMPLEMENTED_MSG("Unhandled texture process mode {}", + static_cast<u32>(instr.texs.GetTextureProcessMode())); + return "texture(" + sampler + ", coords)"; } - break; - } - case Tegra::Shader::TextureProcessMode::LL: { - texture = "textureLod(" + sampler + ", coords, " + lod_value + ')'; - break; - } - default: { - texture = "texture(" + sampler + ", coords)"; - UNIMPLEMENTED_MSG("Unhandled texture process mode {}", - static_cast<u32>(instr.texs.GetTextureProcessMode())); - } - } - if (!depth_compare) { - WriteTexsInstruction(instr, coord, texture); - } else { - WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); + }(); + if (depth_compare) { + texture = "vec4(" + texture + ')'; } + WriteTexsInstruction(instr, texture); break; } case OpCode::Id::TLDS: { @@ -2883,15 +2884,12 @@ private: u32 extra_op_offset = 0; - // Scope to avoid variable name overlaps. - shader.AddLine('{'); - ++shader.scope; - std::string coords; + ShaderScopedScope scope = shader.Scope(); switch (texture_type) { case Tegra::Shader::TextureType::Texture1D: { const std::string x = regs.GetRegisterAsInteger(instr.gpr8); - coords = "float coords = " + x + ';'; + shader.AddLine("float coords = " + x + ';'); break; } case Tegra::Shader::TextureType::Texture2D: { @@ -2900,7 +2898,7 @@ private: const std::string x = regs.GetRegisterAsInteger(instr.gpr8); const std::string y = regs.GetRegisterAsInteger(instr.gpr20); // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");"); - coords = "ivec2 coords = ivec2(" + x + ", " + y + ");"; + shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");"); extra_op_offset = 1; break; } @@ -2909,35 +2907,29 @@ private: } const std::string sampler = GetSampler(instr.sampler, texture_type, is_array, false); - std::string texture = "texelFetch(" + sampler + ", coords, 0)"; - switch (instr.tlds.GetTextureProcessMode()) { - case Tegra::Shader::TextureProcessMode::LZ: { - texture = "texelFetch(" + sampler + ", coords, 0)"; - break; - } - case Tegra::Shader::TextureProcessMode::LL: { - shader.AddLine( - "float lod = " + - regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';'); - texture = "texelFetch(" + sampler + ", coords, lod)"; - break; - } - default: { - texture = "texelFetch(" + sampler + ", coords, 0)"; - UNIMPLEMENTED_MSG("Unhandled texture process mode {}", - static_cast<u32>(instr.tlds.GetTextureProcessMode())); - } - } - WriteTexsInstruction(instr, coords, texture); - --shader.scope; - shader.AddLine('}'); + const std::string texture = [&]() { + switch (instr.tlds.GetTextureProcessMode()) { + case Tegra::Shader::TextureProcessMode::LZ: + return "texelFetch(" + sampler + ", coords, 0)"; + case Tegra::Shader::TextureProcessMode::LL: + shader.AddLine( + "float lod = " + + regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';'); + return "texelFetch(" + sampler + ", coords, lod)"; + default: + UNIMPLEMENTED_MSG("Unhandled texture process mode {}", + static_cast<u32>(instr.tlds.GetTextureProcessMode())); + return "texelFetch(" + sampler + ", coords, 0)"; + } + }(); + + WriteTexsInstruction(instr, texture); break; } case OpCode::Id::TLD4: { ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); ASSERT(instr.tld4.array == 0); - std::string coord; UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), "NODEP is not implemented"); @@ -2954,10 +2946,7 @@ private: if (depth_compare) num_coordinates += 1; - // Add an extra scope and declare the texture coords inside to prevent - // overwriting them in case they are used as outputs of the texs instruction. - shader.AddLine('{'); - ++shader.scope; + const auto scope = shader.Scope(); switch (num_coordinates) { case 2: { @@ -2988,23 +2977,19 @@ private: const std::string texture = "textureGather(" + sampler + ", coords, " + std::to_string(instr.tld4.component) + ')'; - if (!depth_compare) { - shader.AddLine("vec4 texture_tmp = " + texture + ';'); + if (depth_compare) { + regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); + } else { std::size_t dest_elem{}; for (std::size_t elem = 0; elem < 4; ++elem) { if (!instr.tex.IsComponentEnabled(elem)) { // Skip disabled components continue; } - regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, - dest_elem); + regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); ++dest_elem; } - } else { - regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); } - --shader.scope; - shader.AddLine('}'); break; } case OpCode::Id::TLD4S: { @@ -3015,10 +3000,7 @@ private: instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), "AOFFI is not implemented"); - // Scope to avoid variable name overlaps. - shader.AddLine('{'); - ++shader.scope; - std::string coords; + const auto scope = shader.Scope(); const bool depth_compare = instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); @@ -3027,33 +3009,29 @@ private: // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. const std::string sampler = GetSampler( instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); - if (!depth_compare) { - coords = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; - } else { + if (depth_compare) { // Note: TLD4S coordinate encoding works just like TEXS's const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); - coords = "vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");"; - } - const std::string texture = "textureGather(" + sampler + ", coords, " + - std::to_string(instr.tld4s.component) + ')'; - - if (!depth_compare) { - WriteTexsInstruction(instr, coords, texture); + shader.AddLine("vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");"); } else { - WriteTexsInstruction(instr, coords, "vec4(" + texture + ')'); + shader.AddLine("vec2 coords = vec2(" + op_a + ", " + op_b + ");"); } - --shader.scope; - shader.AddLine('}'); + std::string texture = "textureGather(" + sampler + ", coords, " + + std::to_string(instr.tld4s.component) + ')'; + if (depth_compare) { + texture = "vec4(" + texture + ')'; + } + WriteTexsInstruction(instr, texture); break; } case OpCode::Id::TXQ: { UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), "NODEP is not implemented"); - ++shader.scope; - shader.AddLine('{'); - // TODO: the new commits on the texture refactor, change the way samplers work. + const auto scope = shader.Scope(); + + // TODO: The new commits on the texture refactor, change the way samplers work. // Sadly, not all texture instructions specify the type of texture their sampler // uses. This must be fixed at a later instance. const std::string sampler = @@ -3064,7 +3042,8 @@ private: regs.GetRegisterAsInteger(instr.gpr8) + ')'; const std::string mip_level = "textureQueryLevels(" + sampler + ')'; shader.AddLine("ivec2 sizes = " + texture + ';'); - regs.SetRegisterToInteger(instr.gpr0, true, 0, "sizes.x", 1, 1); + + regs.SetRegisterToInteger(instr.gpr0.Value() + 0, true, 0, "sizes.x", 1, 1); regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1); regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1); regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1); @@ -3075,8 +3054,6 @@ private: static_cast<u32>(instr.txq.query_type.Value())); } } - --shader.scope; - shader.AddLine('}'); break; } case OpCode::Id::TMML: { @@ -3091,17 +3068,18 @@ private: const std::string sampler = GetSampler(instr.sampler, texture_type, is_array, false); - // TODO: add coordinates for different samplers once other texture types are + const auto scope = shader.Scope(); + + // TODO: Add coordinates for different samplers once other texture types are // implemented. - std::string coord; switch (texture_type) { case Tegra::Shader::TextureType::Texture1D: { - coord = "float coords = " + x + ';'; + shader.AddLine("float coords = " + x + ';'); break; } case Tegra::Shader::TextureType::Texture2D: { const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); - coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); break; } default: @@ -3109,22 +3087,15 @@ private: // Fallback to interpreting as a 2D texture for now const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); - coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); texture_type = Tegra::Shader::TextureType::Texture2D; } - // Add an extra scope and declare the texture coords inside to prevent - // overwriting them in case they are used as outputs of the texs instruction. - shader.AddLine('{'); - ++shader.scope; - shader.AddLine(coord); + const std::string texture = "textureQueryLod(" + sampler + ", coords)"; - const std::string tmp = "vec2 tmp = " + texture + "*vec2(256.0, 256.0);"; - shader.AddLine(tmp); + shader.AddLine("vec2 tmp = " + texture + " * vec2(256.0, 256.0);"); regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1); regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1); - --shader.scope; - shader.AddLine('}'); break; } default: { diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index b425d98ae..4fa6d7612 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -163,6 +163,7 @@ private: struct ShaderEntries { std::vector<ConstBufferEntry> const_buffer_entries; std::vector<SamplerEntry> texture_samplers; + std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> clip_distances; std::size_t shader_length; }; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index b757f5f44..4970aafed 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -60,6 +60,17 @@ public: } void ApplyTo(OpenGLState& state) { + UpdatePipeline(); + state.draw.shader_program = 0; + state.draw.program_pipeline = pipeline.handle; + state.geometry_shaders.enabled = (gs != 0); + } + +private: + void UpdatePipeline() { + // Avoid updating the pipeline when values have no changed + if (old_vs == vs && old_fs == fs && old_gs == gs) + return; // Workaround for AMD bug glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, @@ -68,14 +79,16 @@ public: glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vs); glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, gs); glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs); - state.draw.shader_program = 0; - state.draw.program_pipeline = pipeline.handle; - state.geometry_shaders.enabled = (gs != 0); + + // Update the old values + old_vs = vs; + old_fs = fs; + old_gs = gs; } -private: OGLPipeline pipeline; GLuint vs{}, fs{}, gs{}; + GLuint old_vs{}, old_fs{}, old_gs{}; }; } // namespace OpenGL::GLShader diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 0c831c9f4..96c57fe97 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -7,10 +7,10 @@ #include "common/assert.h" #include "core/core.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" @@ -154,7 +154,7 @@ QString WaitTreeWaitObject::GetText() const { std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) { switch (object.GetHandleType()) { case Kernel::HandleType::Event: - return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object)); + return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object)); case Kernel::HandleType::Timer: return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object)); case Kernel::HandleType::Thread: @@ -332,7 +332,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { return list; } -WaitTreeEvent::WaitTreeEvent(const Kernel::Event& object) : WaitTreeWaitObject(object) {} +WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeWaitObject(object) {} WaitTreeEvent::~WaitTreeEvent() = default; std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const { @@ -340,7 +340,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const { list.push_back(std::make_unique<WaitTreeText>( tr("reset type = %1") - .arg(GetResetTypeQString(static_cast<const Kernel::Event&>(object).GetResetType())))); + .arg(GetResetTypeQString( + static_cast<const Kernel::ReadableEvent&>(object).GetResetType())))); return list; } diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h index 331f89885..492fb6ac9 100644 --- a/src/yuzu/debugger/wait_tree.h +++ b/src/yuzu/debugger/wait_tree.h @@ -17,8 +17,8 @@ class EmuThread; namespace Kernel { +class ReadableEvent; class WaitObject; -class Event; class Thread; class Timer; } // namespace Kernel @@ -144,7 +144,7 @@ public: class WaitTreeEvent : public WaitTreeWaitObject { Q_OBJECT public: - explicit WaitTreeEvent(const Kernel::Event& object); + explicit WaitTreeEvent(const Kernel::ReadableEvent& object); ~WaitTreeEvent() override; std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 11a8c390b..b52a50915 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -214,6 +214,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent) tree_view->setEditTriggers(QHeaderView::NoEditTriggers); tree_view->setUniformRowHeights(true); tree_view->setContextMenuPolicy(Qt::CustomContextMenu); + tree_view->setStyleSheet("QTreeView{ border: none; }"); item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1); item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name")); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 6e7d300a0..22c207a3a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -518,6 +518,8 @@ void GMainWindow::OnDisplayTitleBars(bool show) { QStringList GMainWindow::GetUnsupportedGLExtensions() { QStringList unsupported_ext; + if (!GLAD_GL_ARB_direct_state_access) + unsupported_ext.append("ARB_direct_state_access"); if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev"); if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 2d6f8cced..a557f2884 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -111,6 +111,8 @@ void EmuWindow_SDL2::Fullscreen() { bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { std::vector<std::string> unsupported_ext; + if (!GLAD_GL_ARB_direct_state_access) + unsupported_ext.push_back("ARB_direct_state_access"); if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) |