Compare commits

..

53 Commits

Author SHA1 Message Date
Lioncash
ac966e4213 kernel/handle_table: Amend reference to CTR-OS in Create()
Another hold-over from Citra.
2018-12-04 01:50:44 -05:00
Lioncash
312690b450 kernel/svc: Implement the resource limit svcGetInfo option
Allows a process to register the resource limit as part of its handle
table.
2018-12-04 01:50:30 -05:00
Mat M
adc4d332fc Merge pull request #1852 from VPeruS/fix-format-string
[Kernel::CreateThread] Match format specifiers to LOG_TRACE's arguments
2018-12-03 22:25:29 -05:00
V.Kalyuzhny
b330b495dc [Kernel::CreateThread] Match format specifiers to LOG_TRACE's arguments 2018-12-04 05:13:50 +02:00
bunnei
9f1ac96afa Merge pull request #1840 from lioncash/info
svc: Reorganize svcGetInfo, handle more error cases for existing implemented info categories
2018-12-03 18:46:22 -05:00
bunnei
76525013c0 Merge pull request #1842 from lioncash/slot
yuzu/configuration: Minor clean-up related changes
2018-12-03 17:12:01 -05:00
bunnei
f6b22d9251 Merge pull request #1835 from lioncash/cache-global
filesystem: De-globalize registered_cache_union
2018-12-03 17:11:26 -05:00
bunnei
8a12daac8c Merge pull request #1822 from ReinUsesLisp/glsl-scope
gl_shader_decompiler: Introduce a scoped object and style changes
2018-12-03 17:10:02 -05:00
bunnei
ef69b4b830 Merge pull request #1803 from DarkLordZach/k-able-event
kernel: Divide Event into ReadableEvent and WritableEvent
2018-12-03 17:05:57 -05:00
bunnei
f7d5f72944 Merge pull request #1833 from lioncash/clean
service/fsp_srv: Implement CleanDirectoryRecursively
2018-12-03 17:04:05 -05:00
bunnei
118f402382 Merge pull request #1839 from lioncash/init
service/audio/audout_u: Amend constructor initialization list order
2018-12-03 17:03:00 -05:00
bunnei
a238cdb5ca Merge pull request #1841 from ogniK5377/npad-mode-fix
Fixed crash with SetNpadMode
2018-12-03 17:02:40 -05:00
Sebastian Valle
1ad158b2bb Merge pull request #1843 from lioncash/table
hle/service: Update function tables for erpt:c and usb's IClientEpSession
2018-12-03 12:21:28 -05:00
Lioncash
6306e54f45 service/usb: Update function table
Updates the function table for IClientEpSession based off information
provided by SwitchBrew.
2018-12-02 15:49:40 -05:00
Lioncash
f933b3370e service/erpt: Update function table
Updates the function table according to information provided by
SwitchBrew.
2018-12-02 15:46:44 -05:00
Lioncash
195cad9635 yuzu/configuration: Make slots private where applicable
These slots are only ever attached to event handling mechanisms within
the class itself, they're never used externally. Because of this, we can
make the functions private.

This also removes redundant usages of the private access specifier.
2018-12-02 14:18:36 -05:00
Lioncash
eabfb7730d yuzu/configuration: Add missing override specifiers to configuration-related classes
Resolves trivial compiler warnings.
2018-12-02 14:18:36 -05:00
Lioncash
f3253d0f14 yuzu/configuration/configure_input: Default destructor in the cpp file
The previous code could potentially be a compilation issue waiting to
occur, given we forward declare the type for a std::unique_ptr. If the
complete definition of the forward declared type isn't visible in a
translation unit that the class is used in, then it would fail to
compile.

Defaulting the destructor in a cpp file ensures the std::unique_ptr's
destructor is only invoked where its complete type is known.
2018-12-02 14:18:26 -05:00
David Marcec
a9223c8182 Fixed crash with SetNpadMode
fixed crash due to handheld
2018-12-03 02:45:08 +11:00
Lioncash
7fe27de26e svc: Use the current process' handle table for retrieving the process instance to act upon
The kernel uses the handle table of the current process to retrieve the
process that should be used to retrieve certain information. To someone
not familiar with the kernel, this might raise the question of "Ok,
sounds nice, but doesn't this make it impossible to retrieve information
about the current process?".

No, it doesn't, because HandleTable instances in the kernel have the
notion of a "pseudo-handle", where certain values allow the kernel to
lookup objects outside of a given handle table. Currently, there's only
a pseudo-handle for the current process (0xFFFF8001) and a pseudo-handle
for the current thread (0xFFFF8000), so to retrieve the current process,
one would just pass 0xFFFF8001 into svcGetInfo.

The lookup itself in the handle table would be something like:

template <typename T>
T* Lookup(Handle handle) {
    if (handle == PSEUDO_HANDLE_CURRENT_PROCESS) {
        return CurrentProcess();
    }

    if (handle == PSUEDO_HANDLE_CURRENT_THREAD) {
        return CurrentThread();
    }

    return static_cast<T*>(&objects[handle]);
}

which, as is shown, allows accessing the current process or current
thread, even if those two objects aren't actually within the HandleTable
instance.
2018-12-02 03:41:49 -05:00
Lioncash
6712e7402c svc: Reorganize svcGetInfo, handle more error cases for existing implemented info categories
Our implementation of svcGetInfo was slightly incorrect in that we
weren't doing proper error checking everywhere. Instead, reorganize it
to be similar to how the kernel seems to do it.
2018-12-02 03:40:10 -05:00
bunnei
7ce17b2cf6 Merge pull request #1827 from ReinUsesLisp/clip-and-shader
gl_rasterizer: Enable clip distances when set in register and in shader
2018-12-01 23:51:47 -05:00
bunnei
80aa124b1d Merge pull request #1825 from ReinUsesLisp/shader-pipeline-cache
gl_shader_manager: Update pipeline when programs have changed
2018-12-01 23:48:55 -05:00
bunnei
a6805e58ce Merge pull request #1795 from ReinUsesLisp/vc-cleanup
video_core: Minor style changes
2018-12-01 23:46:18 -05:00
bunnei
0e9be7be37 Merge pull request #1823 from bunnei/fix-surface-copy
gl_rasterizer_cache: Fix several surface copy issues.
2018-12-01 23:44:32 -05:00
Lioncash
db4523f1ec filesystem: De-globalize registered_cache_union
We can just return a new instance of this when it's requested. This only
ever holds pointers to the existing registed caches, so it's not a large
object. Plus, this also gets rid of the need to keep around a separate
member function just to properly clear out the union.

Gets rid of one of five globals in the filesystem code.
2018-12-01 23:43:23 -05:00
bunnei
c5e781e72a Merge pull request #1832 from Simek/remove-game-list-border
UI: Remove border from Game List
2018-12-01 22:26:34 -05:00
bunnei
97e73591e3 Merge pull request #1830 from Subv/vi_ub
Services/VI: Dereferencing an uninitialized std::optional is undefined behavior.
2018-12-01 22:25:10 -05:00
Lioncash
0ccaaafca3 file_sys: Override missing mutating functions to be stubbed out for ReadOnlyVfsDirectory by default
Ensures that read only indeed means read only.
2018-11-30 23:52:56 -05:00
Lioncash
a7d9fe993a service/fsp_srv: Implement CleanDirectoryRecursively
This is the same behavior-wise as DeleteDirectoryRecursively, with the
only difference being that it doesn't delete the top level directory in
the hierarchy, so given:

root_dir/
  - some_dir/
    - File.txt
  - OtherFile.txt

The end result is just:

root_dir/
2018-11-30 20:17:28 -05:00
Bartosz Kaszubowski
5f07ca3dce remove border from GameList 2018-11-30 23:35:08 +01:00
Subv
583bd20f02 Services/VI: Dereferencing an uninitialized std::optional is undefined behavior.
Assert that it is not empty before using it in the DequeueBuffer wait callback.
2018-11-30 16:06:49 -05:00
bunnei
0f43564d09 gl_rasterizer_cache: Update AccurateCopySurface to flush complete source surface.
- Fixes issues with Breath of the Wild with use_accurate_gpu_emulation setting.
2018-11-29 20:10:11 -05:00
ReinUsesLisp
2908d30274 gl_rasterizer: Enable clip distances when set in register and in shader 2018-11-29 16:58:20 -03:00
ReinUsesLisp
e8620eaa9a gl_shader_manager: Update pipeline when programs have changed 2018-11-29 16:26:42 -03:00
Zach Hilman
170d707850 hle_ipc: Refactor SleepClientThread to avoid ReadableEvent 2018-11-29 09:14:20 -05:00
Zach Hilman
a342bcc9b1 kernel/event: Reference ReadableEvent from WritableEvent 2018-11-29 08:48:40 -05:00
Zach Hilman
ff610103b5 core: Port all current usages of Event to Readable/WritableEvent 2018-11-29 08:45:41 -05:00
Zach Hilman
a56fc84e7a hle_ipc: Use event pair for SleepClientThread 2018-11-29 08:42:26 -05:00
Zach Hilman
c61d2a2841 kernel: Add named event table
Used to store ReadableEvents of all events on the system.
2018-11-29 08:42:26 -05:00
Zach Hilman
c713383816 kernel: Divide Event into ReadableEvent and WritableEvent
More hardware accurate. On the actual system, there is a differentiation between the signaler and signalee, they form a client/server relationship much like ServerPort and ClientPort.
2018-11-29 08:42:26 -05:00
Zach Hilman
d92989e787 kernel/object: Add descriptions to ResetTypes 2018-11-29 08:42:26 -05:00
bunnei
3d3cc35ee7 gl_rasterizer_cache: Remove BlitSurface and replace with more accurate copy.
- BlitSurface with different texture targets is inherently broken.
- When target is the same, we can just use FastCopySurface.
- Fixes rendering issues with Breath of the Wild.
2018-11-28 21:56:21 -05:00
ReinUsesLisp
eb700afcf0 gl_shader_decompiler: Remove texture temporal in TLD4 2018-11-28 23:46:16 -03:00
ReinUsesLisp
8d58e5da71 gl_shader_decompiler: Flip negated if else statement 2018-11-28 23:46:16 -03:00
ReinUsesLisp
f4abebd731 gl_shader_decompiler: Use GLSL scope on instructions unrelated to textures 2018-11-28 23:46:14 -03:00
ReinUsesLisp
78fc8f6b66 gl_shader_decompiler: Move texture code generation into lambdas 2018-11-28 23:45:53 -03:00
ReinUsesLisp
ab13b628d0 gl_shader_decompiler: Clean up texture instructions 2018-11-28 23:45:53 -03:00
ReinUsesLisp
6a642022dd gl_shader_decompiler: Scope GLSL variables with a scoped object 2018-11-28 23:45:51 -03:00
ReinUsesLisp
037449668e gl_rasterizer: Signal UNIMPLEMENTED when rt_separate_frag_data is not zero 2018-11-28 21:26:22 -03:00
ReinUsesLisp
653d7a3f0d gl_rasterizer_cache: Use brackets for two-line single-expresion blocks 2018-11-28 21:18:14 -03:00
ReinUsesLisp
432a9872ed gl_rasterizer: Remove unused struct declarations 2018-11-28 21:18:13 -03:00
ReinUsesLisp
22c7c710b4 gl_rasterizer: Remove extension booleans 2018-11-28 21:18:13 -03:00
71 changed files with 976 additions and 820 deletions

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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

View File

@@ -794,7 +794,7 @@ void KeyManager::DeriveBase() {
void KeyManager::DeriveETicket(PartitionDataManager& data) {
// ETicket keys
const auto es = Service::FileSystem::GetUnionContents()->GetEntry(
const auto es = Service::FileSystem::GetUnionContents().GetEntry(
0x0100000000000033, FileSys::ContentRecordType::Program);
if (es == nullptr)

View File

@@ -75,12 +75,12 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
const auto update = installed->GetEntry(update_tid, ContentRecordType::Program);
const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
if (update != nullptr && update->GetExeFS() != nullptr &&
update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
exefs = update->GetExeFS();
}
@@ -281,13 +281,13 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
const auto update = installed->GetEntryRaw(update_tid, type);
const auto update = installed.GetEntryRaw(update_tid, type);
if (update != nullptr) {
const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
new_nca->GetRomFS() != nullptr) {
LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
romfs = new_nca->GetRomFS();
}
} else if (update_raw != nullptr) {
@@ -329,8 +329,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
if (nacp != nullptr) {
out.insert_or_assign("Update", nacp->GetVersionString());
} else {
if (installed->HasEntry(update_tid, ContentRecordType::Program)) {
const auto meta_ver = installed->GetEntryVersion(update_tid);
if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
const auto meta_ver = installed.GetEntryVersion(update_tid);
if (meta_ver.value_or(0) == 0) {
out.insert_or_assign("Update", "");
} else {
@@ -383,14 +383,13 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
// DLC
const auto dlc_entries = installed->ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
std::vector<RegisteredCacheEntry> dlc_match;
dlc_match.reserve(dlc_entries.size());
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
[this, &installed](const RegisteredCacheEntry& entry) {
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
installed->GetEntry(entry)->GetStatus() ==
Loader::ResultStatus::Success;
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
});
if (!dlc_match.empty()) {
// Ensure sorted so DLC IDs show in order.
@@ -411,7 +410,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
const auto installed{Service::FileSystem::GetUnionContents()};
const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control);
const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr)
return {};

View File

@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
switch (storage) {
case StorageId::None:
res = Service::FileSystem::GetUnionContents()->GetEntry(title_id, type);
res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
break;
case StorageId::NandSystem:
res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -42,9 +42,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
u16 generation = next_generation++;
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
// CTR-OS doesn't use generation 0, so skip straight to 1.
if (next_generation >= (1 << 15))
// Horizon OS uses zero to represent an invalid handle, so skip to 1.
if (next_generation >= (1 << 15)) {
next_generation = 1;
}
generations[slot] = generation;
objects[slot] = std::move(obj);

View File

@@ -13,6 +13,7 @@
namespace Kernel {
enum KernelHandle : Handle {
InvalidHandle = 0,
CurrentThread = 0xFFFF8000,
CurrentProcess = 0xFFFF8001,
};

View File

@@ -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)

View File

@@ -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,

View File

@@ -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 {

View File

@@ -44,6 +44,10 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
return process;
}
SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
return resource_limit;
}
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
program_id = metadata.GetTitleID();
is_64bit_process = metadata.Is64BitProgram();

View File

@@ -171,14 +171,7 @@ public:
}
/// Gets the resource limit descriptor for this process
ResourceLimit& GetResourceLimit() {
return *resource_limit;
}
/// Gets the resource limit descriptor for this process
const ResourceLimit& GetResourceLimit() const {
return *resource_limit;
}
SharedPtr<ResourceLimit> GetResourceLimit() const;
/// Gets the default CPU ID for this process
u8 GetDefaultProcessorID() const {

View File

@@ -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)

View File

@@ -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

View File

@@ -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"
@@ -662,7 +663,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
TotalMemoryUsage = 6,
TotalHeapUsage = 7,
IsCurrentProcessBeingDebugged = 8,
ResourceHandleLimit = 9,
RegisterResourceLimit = 9,
IdleTickCount = 10,
RandomEntropy = 11,
PerformanceCounter = 0xF0000002,
@@ -682,37 +683,137 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
ThreadTickCount = 0xF0000002,
};
const auto* current_process = Core::CurrentProcess();
const auto& vm_manager = current_process->VMManager();
const auto info_id_type = static_cast<GetInfoType>(info_id);
switch (static_cast<GetInfoType>(info_id)) {
switch (info_id_type) {
case GetInfoType::AllowedCpuIdBitmask:
*result = current_process->GetAllowedProcessorMask();
break;
case GetInfoType::AllowedThreadPrioBitmask:
*result = current_process->GetAllowedThreadPriorityMask();
break;
case GetInfoType::MapRegionBaseAddr:
*result = vm_manager.GetMapRegionBaseAddress();
break;
case GetInfoType::MapRegionSize:
*result = vm_manager.GetMapRegionSize();
break;
case GetInfoType::HeapRegionBaseAddr:
*result = vm_manager.GetHeapRegionBaseAddress();
break;
case GetInfoType::HeapRegionSize:
*result = vm_manager.GetHeapRegionSize();
break;
case GetInfoType::ASLRRegionBaseAddr:
case GetInfoType::ASLRRegionSize:
case GetInfoType::NewMapRegionBaseAddr:
case GetInfoType::NewMapRegionSize:
case GetInfoType::TotalMemoryUsage:
*result = vm_manager.GetTotalMemoryUsage();
break;
case GetInfoType::TotalHeapUsage:
*result = vm_manager.GetTotalHeapUsage();
break;
case GetInfoType::IsVirtualAddressMemoryEnabled:
case GetInfoType::PersonalMmHeapUsage:
case GetInfoType::TitleId:
case GetInfoType::UserExceptionContextAddr: {
if (info_sub_id != 0) {
return ERR_INVALID_ENUM_VALUE;
}
const auto& current_process_handle_table = Core::CurrentProcess()->GetHandleTable();
const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle));
if (!process) {
return ERR_INVALID_HANDLE;
}
switch (info_id_type) {
case GetInfoType::AllowedCpuIdBitmask:
*result = process->GetAllowedProcessorMask();
return RESULT_SUCCESS;
case GetInfoType::AllowedThreadPrioBitmask:
*result = process->GetAllowedThreadPriorityMask();
return RESULT_SUCCESS;
case GetInfoType::MapRegionBaseAddr:
*result = process->VMManager().GetMapRegionBaseAddress();
return RESULT_SUCCESS;
case GetInfoType::MapRegionSize:
*result = process->VMManager().GetMapRegionSize();
return RESULT_SUCCESS;
case GetInfoType::HeapRegionBaseAddr:
*result = process->VMManager().GetHeapRegionBaseAddress();
return RESULT_SUCCESS;
case GetInfoType::HeapRegionSize:
*result = process->VMManager().GetHeapRegionSize();
return RESULT_SUCCESS;
case GetInfoType::ASLRRegionBaseAddr:
*result = process->VMManager().GetASLRRegionBaseAddress();
return RESULT_SUCCESS;
case GetInfoType::ASLRRegionSize:
*result = process->VMManager().GetASLRRegionSize();
return RESULT_SUCCESS;
case GetInfoType::NewMapRegionBaseAddr:
*result = process->VMManager().GetNewMapRegionBaseAddress();
return RESULT_SUCCESS;
case GetInfoType::NewMapRegionSize:
*result = process->VMManager().GetNewMapRegionSize();
return RESULT_SUCCESS;
case GetInfoType::TotalMemoryUsage:
*result = process->VMManager().GetTotalMemoryUsage();
return RESULT_SUCCESS;
case GetInfoType::TotalHeapUsage:
*result = process->VMManager().GetTotalHeapUsage();
return RESULT_SUCCESS;
case GetInfoType::IsVirtualAddressMemoryEnabled:
*result = process->IsVirtualMemoryEnabled();
return RESULT_SUCCESS;
case GetInfoType::TitleId:
*result = process->GetTitleID();
return RESULT_SUCCESS;
case GetInfoType::UserExceptionContextAddr:
LOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query user exception context address, returned 0");
*result = 0;
return RESULT_SUCCESS;
default:
break;
}
LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
return ERR_INVALID_ENUM_VALUE;
}
case GetInfoType::IsCurrentProcessBeingDebugged:
*result = 0;
break;
return RESULT_SUCCESS;
case GetInfoType::RegisterResourceLimit: {
if (handle != 0) {
return ERR_INVALID_HANDLE;
}
if (info_sub_id != 0) {
return ERR_INVALID_COMBINATION;
}
Process* const current_process = Core::CurrentProcess();
HandleTable& handle_table = current_process->GetHandleTable();
const auto resource_limit = current_process->GetResourceLimit();
if (!resource_limit) {
*result = KernelHandle::InvalidHandle;
// Yes, the kernel considers this a successful operation.
return RESULT_SUCCESS;
}
const auto table_result = handle_table.Create(resource_limit);
if (table_result.Failed()) {
return table_result.Code();
}
*result = *table_result;
return RESULT_SUCCESS;
}
case GetInfoType::RandomEntropy:
if (handle != 0) {
LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
@@ -726,37 +827,15 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
return ERR_INVALID_COMBINATION;
}
*result = current_process->GetRandomEntropy(info_sub_id);
*result = Core::CurrentProcess()->GetRandomEntropy(info_sub_id);
return RESULT_SUCCESS;
break;
case GetInfoType::ASLRRegionBaseAddr:
*result = vm_manager.GetASLRRegionBaseAddress();
break;
case GetInfoType::ASLRRegionSize:
*result = vm_manager.GetASLRRegionSize();
break;
case GetInfoType::NewMapRegionBaseAddr:
*result = vm_manager.GetNewMapRegionBaseAddress();
break;
case GetInfoType::NewMapRegionSize:
*result = vm_manager.GetNewMapRegionSize();
break;
case GetInfoType::IsVirtualAddressMemoryEnabled:
*result = current_process->IsVirtualMemoryEnabled();
break;
case GetInfoType::TitleId:
*result = current_process->GetTitleID();
break;
case GetInfoType::PrivilegedProcessId:
LOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
*result = 0;
break;
case GetInfoType::UserExceptionContextAddr:
LOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query user exception context address, returned 0");
*result = 0;
break;
return RESULT_SUCCESS;
case GetInfoType::ThreadTickCount: {
constexpr u64 num_cpus = 4;
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
@@ -766,7 +845,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
}
const auto thread =
current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
Core::CurrentProcess()->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
static_cast<Handle>(handle));
@@ -789,14 +868,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
}
*result = out_ticks;
break;
return RESULT_SUCCESS;
}
default:
LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
return ERR_INVALID_ENUM_VALUE;
}
return RESULT_SUCCESS;
}
/// Sets the thread activity
@@ -1042,7 +1120,7 @@ static void ExitProcess() {
static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
u32 priority, s32 processor_id) {
LOG_TRACE(Kernel_SVC,
"called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
"called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
entry_point, arg, stack_top, priority, processor_id, *out_handle);
@@ -1361,7 +1439,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 +1602,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;

View File

@@ -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

View File

@@ -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;
}
SharedPtr<ReadableEvent> GetReadableEvent() const;
bool ShouldWait(Thread* thread) const override;
void Acquire(Thread* thread) override;
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)
};

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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"
@@ -32,14 +34,14 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
std::vector<u64> add_on_content;
const auto rcu = FileSystem::GetUnionContents();
const auto list =
rcu->ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
[](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
add_on_content.erase(
std::remove_if(
add_on_content.begin(), add_on_content.end(),
[&rcu](u64 tid) {
return rcu->GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
Loader::ResultStatus::Success;
}),
add_on_content.end());
@@ -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) {

View File

@@ -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.

View File

@@ -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"
@@ -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) {

View File

@@ -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

View File

@@ -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> {

View File

@@ -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> {

View File

@@ -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

View File

@@ -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_));
@@ -329,20 +341,9 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
return sdmc_factory->Open();
}
std::shared_ptr<FileSys::RegisteredCacheUnion> registered_cache_union;
std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
if (registered_cache_union == nullptr) {
registered_cache_union =
std::make_shared<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
}
return registered_cache_union;
}
void ClearUnionContents() {
registered_cache_union = nullptr;
FileSys::RegisteredCacheUnion GetUnionContents() {
return FileSys::RegisteredCacheUnion{
{GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
}
FileSys::RegisteredCache* GetSystemNANDContents() {
@@ -395,7 +396,6 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
bis_factory = nullptr;
save_data_factory = nullptr;
sdmc_factory = nullptr;
ClearUnionContents();
}
auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),

View File

@@ -48,8 +48,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
void ClearUnionContents();
FileSys::RegisteredCacheUnion GetUnionContents();
FileSys::RegisteredCache* GetSystemNANDContents();
FileSys::RegisteredCache* GetUserNANDContents();
@@ -113,6 +112,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

View File

@@ -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};

View File

@@ -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 {

View File

@@ -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};

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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> {

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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"},
};

View File

@@ -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()};

View File

@@ -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.

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
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)";
}
}();
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 + ')';
}
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: {

View File

@@ -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;
};

View File

@@ -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

View File

@@ -16,15 +16,14 @@ class ConfigureAudio : public QWidget {
public:
explicit ConfigureAudio(QWidget* parent = nullptr);
~ConfigureAudio();
~ConfigureAudio() override;
void applyConfiguration();
void retranslateUi();
public slots:
private:
void updateAudioDevices(int sink_index);
private:
void setConfiguration();
void setOutputSinkFromSinkID();
void setAudioDeviceFromDeviceID();

View File

@@ -16,13 +16,12 @@ class ConfigureDebug : public QWidget {
public:
explicit ConfigureDebug(QWidget* parent = nullptr);
~ConfigureDebug();
~ConfigureDebug() override;
void applyConfiguration();
private:
void setConfiguration();
private:
std::unique_ptr<Ui::ConfigureDebug> ui;
};

View File

@@ -18,13 +18,12 @@ class ConfigureDialog : public QDialog {
public:
explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry);
~ConfigureDialog();
~ConfigureDialog() override;
void applyConfiguration();
private:
void setConfiguration();
private:
std::unique_ptr<Ui::ConfigureDialog> ui;
};

View File

@@ -16,7 +16,7 @@ class ConfigureGameList : public QWidget {
public:
explicit ConfigureGameList(QWidget* parent = nullptr);
~ConfigureGameList();
~ConfigureGameList() override;
void applyConfiguration();

View File

@@ -18,7 +18,7 @@ class ConfigureGeneral : public QWidget {
public:
explicit ConfigureGeneral(QWidget* parent = nullptr);
~ConfigureGeneral();
~ConfigureGeneral() override;
void PopulateHotkeyList(const HotkeyRegistry& registry);
void applyConfiguration();

View File

@@ -16,14 +16,13 @@ class ConfigureGraphics : public QWidget {
public:
explicit ConfigureGraphics(QWidget* parent = nullptr);
~ConfigureGraphics();
~ConfigureGraphics() override;
void applyConfiguration();
private:
void setConfiguration();
private:
std::unique_ptr<Ui::ConfigureGraphics> ui;
QColor bg_color;
};

View File

@@ -88,6 +88,8 @@ ConfigureInput::ConfigureInput(QWidget* parent)
[this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
}
ConfigureInput::~ConfigureInput() = default;
void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) {
if (ui->use_docked_mode->isChecked() && ui->handheld_connected->isChecked()) {
ui->handheld_connected->setChecked(false);

View File

@@ -25,6 +25,7 @@ class ConfigureInput : public QWidget {
public:
explicit ConfigureInput(QWidget* parent = nullptr);
~ConfigureInput() override;
/// Save all button configurations to settings file
void applyConfiguration();

View File

@@ -17,18 +17,17 @@ class ConfigureWeb : public QWidget {
public:
explicit ConfigureWeb(QWidget* parent = nullptr);
~ConfigureWeb();
~ConfigureWeb() override;
void applyConfiguration();
void retranslateUi();
public slots:
private:
void RefreshTelemetryID();
void OnLoginChanged();
void VerifyLogin();
void OnLoginVerified();
private:
void setConfiguration();
bool user_verified = true;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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"));

View File

@@ -97,11 +97,11 @@ GameListWorker::~GameListWorker() = default;
void GameListWorker::AddInstalledTitlesToGameList() {
const auto cache = Service::FileSystem::GetUnionContents();
const auto installed_games = cache->ListEntriesFilter(FileSys::TitleType::Application,
FileSys::ContentRecordType::Program);
const auto installed_games = cache.ListEntriesFilter(FileSys::TitleType::Application,
FileSys::ContentRecordType::Program);
for (const auto& game : installed_games) {
const auto file = cache->GetEntryUnparsed(game);
const auto file = cache.GetEntryUnparsed(game);
std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file);
if (!loader)
continue;
@@ -112,7 +112,7 @@ void GameListWorker::AddInstalledTitlesToGameList() {
loader->ReadProgramId(program_id);
const FileSys::PatchManager patch{program_id};
const auto control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control);
const auto control = cache.GetEntry(game.title_id, FileSys::ContentRecordType::Control);
if (control != nullptr)
GetMetadataFromControlNCA(patch, *control, icon, name);
@@ -141,11 +141,11 @@ void GameListWorker::AddInstalledTitlesToGameList() {
emit EntryReady(list);
}
const auto control_data = cache->ListEntriesFilter(FileSys::TitleType::Application,
FileSys::ContentRecordType::Control);
const auto control_data = cache.ListEntriesFilter(FileSys::TitleType::Application,
FileSys::ContentRecordType::Control);
for (const auto& entry : control_data) {
auto nca = cache->GetEntry(entry);
auto nca = cache.GetEntry(entry);
if (nca != nullptr) {
nca_control_map.insert_or_assign(entry.title_id, std::move(nca));
}

View File

@@ -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)
@@ -905,7 +907,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
}
const auto installed = Service::FileSystem::GetUnionContents();
auto romfs_title_id = SelectRomFSDumpTarget(*installed, program_id);
const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id);
if (!romfs_title_id) {
failed();
@@ -920,7 +922,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
if (*romfs_title_id == program_id) {
romfs = file;
} else {
romfs = installed->GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS();
romfs = installed.GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS();
}
const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);

View File

@@ -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)