Compare commits

...

31 Commits

Author SHA1 Message Date
Lioncash
f4b98a857b game_list: Upper-case containsAllWords to ContainsAllWords()
This makes it consistent with most of the other private utility
functions.
2018-07-18 00:15:48 -04:00
Lioncash
c8f3fc9a4b game_list: Make containsAllWords a const member function
This doesn't actually modify the internal class state, so it can be a
const member function. While we're at it, amend the function to take
its arguments by const reference.
2018-07-18 00:13:04 -04:00
bunnei
8e28af6f89 Merge pull request #675 from Subv/stencil
GPU: Added register definitions for the stencil parameters.
2018-07-17 15:53:00 -07:00
Subv
3d3b10adc7 GPU: Added register definitions for the stencil parameters. 2018-07-17 15:00:21 -05:00
Zach Hilman
69bfe075b5 General Filesystem and Save Data Fixes (#670) 2018-07-17 12:42:15 -07:00
bunnei
88a3140c9b Merge pull request #671 from MerryMage/clear-exclusive-state
scheduler: Clear exclusive state when switching contexts
2018-07-17 07:33:32 -07:00
bunnei
519035db3d Merge pull request #672 from SciresM/to_address_fix
svc:: Fix bug in svcWaitForAddress
2018-07-17 07:32:42 -07:00
bunnei
5f119bed56 Merge pull request #673 from bunnei/fix-buffer-queue-evt
nvflinger: Fix for BufferQueue event handling.
2018-07-17 07:07:57 -07:00
bunnei
170e19d4ea nvflinger: Fix for BufferQueue event handling. 2018-07-17 00:26:23 -04:00
Michael Scire
3b885691a1 Kernel/Arbiter: Fix bug in WaitIfLessThan 2018-07-16 20:55:53 -06:00
MerryMage
56cc1c11ec scheduler: Clear exclusive state when switching contexts 2018-07-16 11:24:00 +01:00
bunnei
f00ca69a81 Merge pull request #669 from lioncash/dynarmic
externals: Update dynarmic to dfdec79
2018-07-15 18:36:32 -07:00
Lioncash
0722adb471 externals: Update dynarmic to dfdec79 2018-07-15 16:11:45 -04:00
bunnei
068668780c Merge pull request #668 from jroweboy/controller-lag
HID: Update controllers less often
2018-07-15 13:06:28 -07:00
bunnei
04b9cde4f5 Merge pull request #664 from jroweboy/logging-stuff
Minor logging improvements
2018-07-15 12:58:52 -07:00
James Rowe
7d209b3c9f HID: Update controllers less often 2018-07-15 13:47:41 -06:00
James Rowe
497b81558e Logging: Dump all logs in the queue on close in debug mode 2018-07-15 13:02:09 -06:00
bunnei
98762e9601 Merge pull request #666 from bunnei/g8r8
gl_rasterizer_cache: Implement texture format G8R8.
2018-07-15 10:09:36 -07:00
bunnei
3a96670f2d gl_rasterizer_cache: Implement texture format G8R8. 2018-07-15 01:33:42 -04:00
bunnei
aaec0b7e70 Merge pull request #665 from bunnei/fix-z24-s8
gl_rasterizer_cache: Fix incorrect offset in ConvertS8Z24ToZ24S8.
2018-07-14 22:18:55 -07:00
bunnei
f8ab956189 Merge pull request #659 from bunnei/depth16
gl_rasterizer_cache: Implement depth format Z16_UNORM.
2018-07-14 21:39:23 -07:00
bunnei
3145114190 gl_rasterizer_cache: Fix incorrect offset in ConvertS8Z24ToZ24S8. 2018-07-15 00:02:05 -04:00
bunnei
e21190f47f gl_rasterizer_cache: Implement depth format Z16_UNORM. 2018-07-14 23:43:28 -04:00
bunnei
2cb3fdca86 Merge pull request #598 from bunnei/makedonecurrent
OpenGL: Use MakeCurrent/DoneCurrent for multithreaded rendering.
2018-07-14 20:18:11 -07:00
bunnei
c324a378ac Merge pull request #663 from Subv/bsd
Services/BSD: Corrected the return for StartMonitoring according to SwIPC
2018-07-14 19:40:34 -07:00
bunnei
fd1f5c5414 Merge pull request #662 from Subv/delete_file
FileSys: Append the requested path to the filesystem base path in DeleteFile
2018-07-14 13:11:58 -07:00
James Rowe
6daebaaa57 Logging: Don't lock the queue for the duration of the write 2018-07-14 11:57:13 -06:00
Subv
b07f4d6afb Services/BSD: Corrected the return for StartMonitoring according to SwIPC. 2018-07-14 12:34:07 -05:00
bunnei
ad0166a982 Merge pull request #661 from ogniK5377/assert-nit
No need to use ASSERT_MSG with an empty assert message
2018-07-14 09:12:21 -07:00
David Marcec
a7d6c0d6ea No need to use ASSERT_MSG with an empty message 2018-07-14 23:13:16 +10:00
bunnei
05cb10530f OpenGL: Use MakeCurrent/DoneCurrent for multithreaded rendering. 2018-07-14 02:50:35 -04:00
47 changed files with 444 additions and 278 deletions

View File

@@ -5,6 +5,7 @@
#include <algorithm>
#include <array>
#include <chrono>
#include <climits>
#include <condition_variable>
#include <memory>
#include <thread>
@@ -83,8 +84,10 @@ private:
}
};
while (true) {
std::unique_lock<std::mutex> lock(message_mutex);
message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); });
{
std::unique_lock<std::mutex> lock(message_mutex);
message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); });
}
if (!running) {
break;
}
@@ -92,7 +95,7 @@ private:
}
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case
// where a system is repeatedly spamming logs even on close.
constexpr int MAX_LOGS_TO_WRITE = 100;
const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100;
int logs_written = 0;
while (logs_written++ < MAX_LOGS_TO_WRITE && message_queue.Pop(entry)) {
write_logs(entry);
@@ -282,4 +285,4 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
Impl::Instance().PushEntry(std::move(entry));
}
} // namespace Log
} // namespace Log

View File

@@ -94,4 +94,11 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
bool Filter::CheckMessage(Class log_class, Level level) const {
return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
}
bool Filter::IsDebug() const {
return std::any_of(class_levels.begin(), class_levels.end(), [](const Level& l) {
return static_cast<u8>(l) <= static_cast<u8>(Level::Debug);
});
}
} // namespace Log

View File

@@ -47,6 +47,9 @@ public:
/// Matches class/level combination against the filter, returning true if it passed.
bool CheckMessage(Class log_class, Level level) const;
/// Returns true if any logging classes are set to debug
bool IsDebug() const;
private:
std::array<Level, (size_t)Class::Count> class_levels;
};

View File

@@ -116,6 +116,8 @@ public:
*/
virtual void LoadContext(const ThreadContext& ctx) = 0;
virtual void ClearExclusiveState() = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0;
};

View File

@@ -226,6 +226,10 @@ void ARM_Dynarmic::ClearInstructionCache() {
jit->ClearCache();
}
void ARM_Dynarmic::ClearExclusiveState() {
jit->ClearExclusiveState();
}
void ARM_Dynarmic::PageTableChanged() {
jit = MakeJit(cb);
current_page_table = Memory::GetCurrentPageTable();

View File

@@ -39,6 +39,7 @@ public:
void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void PageTableChanged() override;

View File

@@ -263,6 +263,8 @@ void ARM_Unicorn::PrepareReschedule() {
CHECKED(uc_emu_stop(uc));
}
void ARM_Unicorn::ClearExclusiveState() {}
void ARM_Unicorn::ClearInstructionCache() {}
void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {

View File

@@ -31,6 +31,7 @@ public:
void SaveContext(ThreadContext& ctx) override;
void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ClearExclusiveState() override;
void ExecuteInstructions(int num_instructions);
void Run() override;
void Step() override;

View File

@@ -12,6 +12,8 @@ namespace ErrCodes {
enum {
NotFound = 1,
SaveDataNotFound = 1002,
SdCardNotFound = 2001,
RomFSNotFound = 2520,
};
}

View File

@@ -167,35 +167,4 @@ public:
virtual ResultVal<EntryType> GetEntryType(const std::string& path) const = 0;
};
class FileSystemFactory : NonCopyable {
public:
virtual ~FileSystemFactory() {}
/**
* Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
*/
virtual std::string GetName() const = 0;
/**
* Tries to open the archive of this type with the specified path
* @param path Path to the archive
* @return An ArchiveBackend corresponding operating specified archive path.
*/
virtual ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) = 0;
/**
* Deletes the archive contents and then re-creates the base folder
* @param path Path to the archive
* @return ResultCode of the operation, 0 on success
*/
virtual ResultCode Format(const Path& path) = 0;
/**
* Retrieves the format info about the archive with the specified path
* @param path Path to the archive
* @return Format information about the archive or error code
*/
virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0;
};
} // namespace FileSys

View File

@@ -11,28 +11,17 @@
namespace FileSys {
RomFS_Factory::RomFS_Factory(Loader::AppLoader& app_loader) {
RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
// Load the RomFS from the app
if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) {
LOG_ERROR(Service_FS, "Unable to read RomFS!");
}
}
ResultVal<std::unique_ptr<FileSystemBackend>> RomFS_Factory::Open(const Path& path) {
ResultVal<std::unique_ptr<FileSystemBackend>> RomFSFactory::Open(u64 title_id) {
// TODO(DarkLordZach): Use title id.
auto archive = std::make_unique<RomFS_FileSystem>(romfs_file, data_offset, data_size);
return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
}
ResultCode RomFS_Factory::Format(const Path& path) {
LOG_ERROR(Service_FS, "Unimplemented Format archive {}", GetName());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
ResultVal<ArchiveFormatInfo> RomFS_Factory::GetFormatInfo(const Path& path) const {
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
} // namespace FileSys

View File

@@ -15,16 +15,11 @@
namespace FileSys {
/// File system interface to the RomFS archive
class RomFS_Factory final : public FileSystemFactory {
class RomFSFactory {
public:
explicit RomFS_Factory(Loader::AppLoader& app_loader);
explicit RomFSFactory(Loader::AppLoader& app_loader);
std::string GetName() const override {
return "ArchiveFactory_RomFS";
}
ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path) override;
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
ResultVal<std::unique_ptr<FileSystemBackend>> Open(u64 title_id);
private:
std::shared_ptr<FileUtil::IOFile> romfs_file;

View File

@@ -12,11 +12,49 @@
namespace FileSys {
SaveData_Factory::SaveData_Factory(std::string nand_directory)
std::string SaveDataDescriptor::DebugInfo() {
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]",
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
}
SaveDataFactory::SaveDataFactory(std::string nand_directory)
: nand_directory(std::move(nand_directory)) {}
ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path& path) {
std::string save_directory = GetFullPath();
ResultVal<std::unique_ptr<FileSystemBackend>> SaveDataFactory::Open(SaveDataSpaceId space,
SaveDataDescriptor meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataDescriptor, type is "
"SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
meta.zero_1);
}
if (meta.zero_2 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataDescriptor, type is "
"SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
meta.zero_2);
}
if (meta.zero_3 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataDescriptor, type is "
"SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
meta.zero_3);
}
}
if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataDescriptor, type is SystemSaveData but title_id is "
"non-zero ({:016X}).",
meta.title_id);
}
std::string save_directory =
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
// TODO(DarkLordZach): Try to not create when opening, there are dedicated create save methods.
// But, user_ids don't match so this works for now.
if (!FileUtil::Exists(save_directory)) {
// TODO(bunnei): This is a work-around to always create a save data directory if it does not
@@ -26,6 +64,12 @@ ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path&
FileUtil::CreateFullPath(save_directory);
}
// TODO(DarkLordZach): For some reason, CreateFullPath doesn't create the last bit. Should be
// fixed with VFS.
if (!FileUtil::IsDirectory(save_directory)) {
FileUtil::CreateDir(save_directory);
}
// Return an error if the save data doesn't actually exist.
if (!FileUtil::IsDirectory(save_directory)) {
// TODO(Subv): Find out correct error code.
@@ -36,28 +80,35 @@ ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path&
return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
}
ResultCode SaveData_Factory::Format(const Path& path) {
LOG_WARNING(Service_FS, "Format archive {}", GetName());
// Create the save data directory.
if (!FileUtil::CreateFullPath(GetFullPath())) {
// TODO(Subv): Find the correct error code.
return ResultCode(-1);
std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
u128 user_id, u64 save_id) const {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData && title_id == 0)
title_id = Core::CurrentProcess()->program_id;
std::string prefix;
switch (space) {
case SaveDataSpaceId::NandSystem:
prefix = nand_directory + "system/save/";
break;
case SaveDataSpaceId::NandUser:
prefix = nand_directory + "user/save/";
break;
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
}
return RESULT_SUCCESS;
}
ResultVal<ArchiveFormatInfo> SaveData_Factory::GetFormatInfo(const Path& path) const {
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
std::string SaveData_Factory::GetFullPath() const {
u64 title_id = Core::CurrentProcess()->program_id;
// TODO(Subv): Somehow obtain this value.
u32 user = 0;
return fmt::format("{}save/{:016X}/{:08X}/", nand_directory, title_id, user);
switch (type) {
case SaveDataType::SystemSaveData:
return fmt::format("{}{:016X}/{:016X}{:016X}", prefix, save_id, user_id[1], user_id[0]);
case SaveDataType::SaveData:
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", prefix, 0, user_id[1], user_id[0],
title_id);
default:
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
}
}
} // namespace FileSys

View File

@@ -12,22 +12,50 @@
namespace FileSys {
/// File system interface to the SaveData archive
class SaveData_Factory final : public FileSystemFactory {
public:
explicit SaveData_Factory(std::string nand_directory);
enum class SaveDataSpaceId : u8 {
NandSystem = 0,
NandUser = 1,
SdCard = 2,
TemporaryStorage = 3,
};
std::string GetName() const override {
return "SaveData_Factory";
}
ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path) override;
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
enum class SaveDataType : u8 {
SystemSaveData = 0,
SaveData = 1,
BcatDeliveryCacheStorage = 2,
DeviceSaveData = 3,
TemporaryStorage = 4,
CacheStorage = 5,
};
struct SaveDataDescriptor {
u64_le title_id;
u128 user_id;
u64_le save_id;
SaveDataType type;
INSERT_PADDING_BYTES(7);
u64_le zero_1;
u64_le zero_2;
u64_le zero_3;
std::string DebugInfo();
};
static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size.");
/// File system interface to the SaveData archive
class SaveDataFactory {
public:
explicit SaveDataFactory(std::string nand_directory);
ResultVal<std::unique_ptr<FileSystemBackend>> Open(SaveDataSpaceId space,
SaveDataDescriptor meta);
private:
std::string nand_directory;
std::string sd_directory;
std::string GetFullPath() const;
std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id,
u64 save_id) const;
};
} // namespace FileSys

View File

@@ -12,9 +12,9 @@
namespace FileSys {
SDMC_Factory::SDMC_Factory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {}
SDMCFactory::SDMCFactory(std::string sd_directory) : sd_directory(std::move(sd_directory)) {}
ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& path) {
ResultVal<std::unique_ptr<FileSystemBackend>> SDMCFactory::Open() {
// Create the SD Card directory if it doesn't already exist.
if (!FileUtil::IsDirectory(sd_directory)) {
FileUtil::CreateFullPath(sd_directory);
@@ -24,16 +24,4 @@ ResultVal<std::unique_ptr<FileSystemBackend>> SDMC_Factory::Open(const Path& pat
return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive));
}
ResultCode SDMC_Factory::Format(const Path& path) {
LOG_ERROR(Service_FS, "Unimplemented Format archive {}", GetName());
// TODO(Subv): Find the right error code for this
return ResultCode(-1);
}
ResultVal<ArchiveFormatInfo> SDMC_Factory::GetFormatInfo(const Path& path) const {
LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive {}", GetName());
// TODO(bunnei): Find the right error code for this
return ResultCode(-1);
}
} // namespace FileSys

View File

@@ -13,16 +13,11 @@
namespace FileSys {
/// File system interface to the SDCard archive
class SDMC_Factory final : public FileSystemFactory {
class SDMCFactory {
public:
explicit SDMC_Factory(std::string sd_directory);
explicit SDMCFactory(std::string sd_directory);
std::string GetName() const override {
return "SDMC_Factory";
}
ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path) override;
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
ResultVal<std::unique_ptr<FileSystemBackend>> Open();
private:
std::string sd_directory;

View File

@@ -115,7 +115,7 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu
s32 updated_value;
if (waiting_threads.size() == 0) {
updated_value = value - 1;
} else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) {
} else if (num_to_wake <= 0 || waiting_threads.size() <= static_cast<u32>(num_to_wake)) {
updated_value = value + 1;
} else {
updated_value = value;
@@ -140,7 +140,9 @@ ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool
s32 cur_value = static_cast<s32>(Memory::Read32(address));
if (cur_value < value) {
Memory::Write32(address, static_cast<u32>(cur_value - 1));
if (should_decrement) {
Memory::Write32(address, static_cast<u32>(cur_value - 1));
}
} else {
return ERR_INVALID_STATE;
}

View File

@@ -29,7 +29,8 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
const std::string& reason, u64 timeout,
WakeupCallback&& callback) {
WakeupCallback&& callback,
Kernel::SharedPtr<Kernel::Event> event) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
thread->wakeup_callback =
@@ -41,7 +42,12 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
return true;
};
auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
if (!event) {
// Create event if not provided
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
}
event->Clear();
thread->status = THREADSTATUS_WAIT_HLE_EVENT;
thread->wait_objects = {event};
event->AddWaitingThread(thread);
@@ -214,8 +220,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
(sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32);
ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented");
ASSERT_MSG(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
ASSERT_MSG(move_objects.size() == handle_descriptor_header->num_handles_to_move);
ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
// We don't make a distinction between copy and move handles when translating since HLE
// services don't deal with handles directly. However, the guest applications might check

View File

@@ -118,10 +118,12 @@ 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.
* @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);
u64 timeout, WakeupCallback&& callback,
Kernel::SharedPtr<Kernel::Event> event = nullptr);
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);

View File

@@ -85,6 +85,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
cpu_core->LoadContext(new_thread->context);
cpu_core->SetTlsAddress(new_thread->GetTLSAddress());
cpu_core->ClearExclusiveState();
} else {
current_thread = nullptr;
// Note: We do not reset the current process and current page table when idling because

View File

@@ -4,9 +4,11 @@
#include <cinttypes>
#include <stack>
#include "core/core.h"
#include "core/file_sys/filesystem.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
@@ -614,25 +616,14 @@ void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u128 uid = rp.PopRaw<u128>();
u128 uid = rp.PopRaw<u128>(); // What does this do?
LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
IPC::ResponseBuilder rb{ctx, 4};
FileSys::Path unused;
auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData, unused);
if (savedata.Failed()) {
// Create the save data and return an error indicating that the operation was performed.
FileSystem::FormatFileSystem(FileSystem::Type::SaveData);
// TODO(Subv): Find out the correct error code for this.
rb.Push(ResultCode(ErrorModule::FS, 40));
} else {
rb.Push(RESULT_SUCCESS);
}
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(0);
}
} // namespace Service::AM
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.

View File

@@ -4,6 +4,7 @@
#include <boost/container/flat_map.hpp>
#include "common/file_util.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/filesystem.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.h"
@@ -16,57 +17,77 @@ namespace Service::FileSystem {
* Map of registered file systems, identified by type. Once an file system is registered here, it
* is never removed until UnregisterFileSystems is called.
*/
static boost::container::flat_map<Type, std::unique_ptr<FileSys::FileSystemFactory>> filesystem_map;
static std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type) {
auto result = filesystem_map.emplace(type, std::move(factory));
bool inserted = result.second;
ASSERT_MSG(inserted, "Tried to register more than one system with same id code");
auto& filesystem = result.first->second;
LOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}", filesystem->GetName(),
static_cast<u32>(type));
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
romfs_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered RomFS");
return RESULT_SUCCESS;
}
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
FileSys::Path& path) {
LOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type));
auto itr = filesystem_map.find(type);
if (itr == filesystem_map.end()) {
// TODO(bunnei): Find a better error code for this
return ResultCode(-1);
}
return itr->second->Open(path);
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second save data");
save_data_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered save data");
return RESULT_SUCCESS;
}
ResultCode FormatFileSystem(Type type) {
LOG_TRACE(Service_FS, "Formatting FileSystem with type={}", static_cast<u32>(type));
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
sdmc_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered SDMC");
return RESULT_SUCCESS;
}
auto itr = filesystem_map.find(type);
if (itr == filesystem_map.end()) {
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id) {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id);
if (romfs_factory == nullptr) {
// TODO(bunnei): Find a better error code for this
return ResultCode(-1);
}
FileSys::Path unused;
return itr->second->Format(unused);
return romfs_factory->Open(title_id);
}
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData(
FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct) {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
static_cast<u8>(space), SaveStructDebugInfo(save_struct));
if (save_data_factory == nullptr) {
return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SaveDataNotFound);
}
return save_data_factory->Open(space, save_struct);
}
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC() {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound);
}
return sdmc_factory->Open();
}
void RegisterFileSystems() {
filesystem_map.clear();
romfs_factory = nullptr;
save_data_factory = nullptr;
sdmc_factory = nullptr;
std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX);
auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory));
RegisterFileSystem(std::move(savedata), Type::SaveData);
auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
save_data_factory = std::move(savedata);
auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory));
RegisterFileSystem(std::move(sdcard), Type::SDMC);
auto sdcard = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
sdmc_factory = std::move(sdcard);
}
void InstallInterfaces(SM::ServiceManager& service_manager) {

View File

@@ -6,12 +6,13 @@
#include <memory>
#include "common/common_types.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/sdmc_factory.h"
#include "core/hle/result.h"
namespace FileSys {
class FileSystemBackend;
class FileSystemFactory;
class Path;
} // namespace FileSys
namespace Service {
@@ -22,35 +23,20 @@ class ServiceManager;
namespace FileSystem {
/// Supported FileSystem types
enum class Type {
RomFS = 1,
SaveData = 2,
SDMC = 3,
};
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
/**
* Registers a FileSystem, instances of which can later be opened using its IdCode.
* @param factory FileSystem backend interface to use
* @param type Type used to access this type of FileSystem
*/
ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type);
// TODO(DarkLordZach): BIS Filesystem
// ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
/**
* Opens a file system
* @param type Type of the file system to open
* @param path Path to the file system, used with Binary paths
* @return FileSys::FileSystemBackend interface to the file system
*/
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
FileSys::Path& path);
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id);
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData(
FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct);
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC();
/**
* Formats a file system
* @param type Type of the file system to format
* @return ResultCode of the operation
*/
ResultCode FormatFileSystem(Type type);
// TODO(DarkLordZach): BIS Filesystem
// ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS();
/// Registers all Filesystem services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);

View File

@@ -13,11 +13,21 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
namespace Service::FileSystem {
enum class StorageId : u8 {
None = 0,
Host = 1,
GameCard = 2,
NandSystem = 3,
NandUser = 4,
SdCard = 5
};
class IStorage final : public ServiceFramework<IStorage> {
public:
IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend)
@@ -487,17 +497,6 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
RegisterHandlers(functions);
}
void FSP_SRV::TryLoadRomFS() {
if (romfs) {
return;
}
FileSys::Path unused;
auto res = OpenFileSystem(Type::RomFS, unused);
if (res.Succeeded()) {
romfs = std::move(res.Unwrap());
}
}
void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
@@ -508,8 +507,7 @@ void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) {
void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
FileSys::Path unused;
auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap();
IFileSystem filesystem(OpenSDMC().Unwrap());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -519,23 +517,26 @@ void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto save_struct = rp.PopRaw<std::array<u8, 0x40>>();
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
u128 uid = rp.PopRaw<u128>();
LOG_WARNING(Service_FS, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
LOG_WARNING(Service_FS, "(STUBBED) called save_struct = {}, uid = {:016X}{:016X}",
save_struct.DebugInfo(), uid[1], uid[0]);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
// TODO(Subv): Read the input parameters and mount the requested savedata instead of always
// mounting the current process' savedata.
FileSys::Path unused;
auto filesystem = OpenFileSystem(Type::SaveData, unused);
auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
auto unk = rp.Pop<u32>();
LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
auto filesystem = OpenSaveData(space_id, save_struct);
if (filesystem.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
@@ -559,8 +560,8 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
TryLoadRomFS();
if (!romfs) {
auto romfs = OpenRomFS(Core::System::GetInstance().CurrentProcess()->program_id);
if (romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
@@ -568,8 +569,8 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
return;
}
// Attempt to open a StorageBackend interface to the RomFS
auto storage = romfs->OpenFile({}, {});
auto storage = romfs.Unwrap()->OpenFile({}, {});
if (storage.Failed()) {
LOG_CRITICAL(Service_FS, "no storage interface available!");
IPC::ResponseBuilder rb{ctx, 2};
@@ -583,8 +584,40 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
}
void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess");
OpenDataStorageByCurrentProcess(ctx);
IPC::RequestParser rp{ctx};
auto storage_id = rp.PopRaw<StorageId>();
auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}",
static_cast<u8>(storage_id), title_id);
if (title_id != Core::System::GetInstance().CurrentProcess()->program_id) {
LOG_CRITICAL(
Service_FS,
"Attempting to access RomFS of another title id (current={:016X}, requested={:016X}).",
Core::System::GetInstance().CurrentProcess()->program_id, title_id);
}
auto romfs = OpenRomFS(title_id);
if (romfs.Failed()) {
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::RomFSNotFound));
return;
}
auto storage = romfs.Unwrap()->OpenFile({}, {});
if (storage.Failed()) {
LOG_CRITICAL(Service_FS, "no storage interface available!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(storage.Code());
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap()));
}
} // namespace Service::FileSystem

View File

@@ -19,8 +19,6 @@ public:
~FSP_SRV() = default;
private:
void TryLoadRomFS();
void Initialize(Kernel::HLERequestContext& ctx);
void MountSdCard(Kernel::HLERequestContext& ctx);
void CreateSaveData(Kernel::HLERequestContext& ctx);

View File

@@ -18,9 +18,9 @@ namespace Service::HID {
// Updating period for each HID device.
// TODO(shinyquagsire23): These need better values.
constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 10000;
constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:

View File

@@ -13,8 +13,8 @@ namespace Service {
namespace NVFlinger {
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle");
native_handle->Signal();
buffer_wait_event =
Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
}
void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) {
@@ -26,10 +26,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) {
LOG_WARNING(Service, "Adding graphics buffer {}", slot);
queue.emplace_back(buffer);
if (buffer_wait_event) {
buffer_wait_event->Signal();
}
buffer_wait_event->Signal();
}
boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
@@ -48,8 +45,6 @@ boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
return boost::none;
}
buffer_wait_event = nullptr;
itr->status = Buffer::Status::Dequeued;
return itr->slot;
}
@@ -88,9 +83,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
ASSERT(itr->status == Buffer::Status::Acquired);
itr->status = Buffer::Status::Free;
if (buffer_wait_event) {
buffer_wait_event->Signal();
}
buffer_wait_event->Signal();
}
u32 BufferQueue::Query(QueryType type) {
@@ -106,10 +99,5 @@ u32 BufferQueue::Query(QueryType type) {
return 0;
}
void BufferQueue::SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event) {
ASSERT_MSG(!buffer_wait_event, "buffer_wait_event only supports a single waiting thread!");
buffer_wait_event = std::move(wait_event);
}
} // namespace NVFlinger
} // namespace Service

View File

@@ -77,14 +77,13 @@ public:
boost::optional<const Buffer&> AcquireBuffer();
void ReleaseBuffer(u32 slot);
u32 Query(QueryType type);
void SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event);
u32 GetId() const {
return id;
}
Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const {
return native_handle;
Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const {
return buffer_wait_event;
}
private:
@@ -92,9 +91,6 @@ private:
u64 layer_id;
std::vector<Buffer> queue;
Kernel::SharedPtr<Kernel::Event> native_handle;
/// Used to signal waiting thread when no buffers are available
Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
};

View File

@@ -152,9 +152,6 @@ void NVFlinger::Compose() {
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform);
buffer_queue->ReleaseBuffer(buffer->slot);
// TODO(Subv): Figure out when we should actually signal this event.
buffer_queue->GetNativeHandle()->Signal();
}
}

View File

@@ -19,10 +19,9 @@ void BSD::RegisterClient(Kernel::HLERequestContext& ctx) {
void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // bsd errno
}
void BSD::Socket(Kernel::HLERequestContext& ctx) {

View File

@@ -495,7 +495,7 @@ private:
ctx.WriteBuffer(response.Serialize());
} else {
// Wait the current thread until a buffer becomes available
auto wait_event = ctx.SleepClientThread(
ctx.SleepClientThread(
Kernel::GetCurrentThread(), "IHOSBinderDriver::DequeueBuffer", -1,
[=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
ThreadWakeupReason reason) {
@@ -506,8 +506,8 @@ private:
ctx.WriteBuffer(response.Serialize());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
});
buffer_queue->SetBufferWaitEvent(std::move(wait_event));
},
buffer_queue->GetBufferWaitEvent());
}
} else if (transaction == TransactionId::RequestBuffer) {
IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
@@ -565,7 +565,7 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(buffer_queue->GetNativeHandle());
rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent());
}
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;

View File

@@ -154,8 +154,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
// Register the RomFS if a ".romfs" file was found
if (!filepath_romfs.empty()) {
Service::FileSystem::RegisterFileSystem(std::make_unique<FileSys::RomFS_Factory>(*this),
Service::FileSystem::Type::RomFS);
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
}
is_loaded = true;

View File

@@ -277,8 +277,7 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
metadata.GetMainThreadStackSize());
if (nca->GetRomFsSize() > 0)
Service::FileSystem::RegisterFileSystem(std::make_unique<FileSys::RomFS_Factory>(*this),
Service::FileSystem::Type::RomFS);
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
is_loaded = true;
return ResultStatus::Success;

View File

@@ -115,7 +115,7 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>&
std::vector<u8> program_image;
for (int i = 0; i < nso_header.segments.size(); ++i) {
std::vector<u8> compressed_data(nso_header.segments_compressed_size[i]);
for (int j = 0; j < nso_header.segments_compressed_size[i]; ++j)
for (auto j = 0; j < nso_header.segments_compressed_size[i]; ++j)
compressed_data[j] = file_data[nso_header.segments[i].offset + j];
std::vector<u8> data = DecompressSegment(compressed_data, nso_header.segments[i]);
program_image.resize(nso_header.segments[i].location);

View File

@@ -520,7 +520,18 @@ public:
u32 enable[NumRenderTargets];
} blend;
INSERT_PADDING_WORDS(0xB);
struct {
u32 enable;
u32 front_op_fail;
u32 front_op_zfail;
u32 front_op_zpass;
u32 front_func_func;
u32 front_func_ref;
u32 front_func_mask;
u32 front_mask;
} stencil;
INSERT_PADDING_WORDS(0x3);
union {
BitField<4, 1, u32> triangle_rast_flip;
@@ -556,7 +567,17 @@ public:
}
} tic;
INSERT_PADDING_WORDS(0x21);
INSERT_PADDING_WORDS(0x5);
struct {
u32 enable;
u32 back_op_fail;
u32 back_op_zfail;
u32 back_op_zpass;
u32 back_func_func;
} stencil_two_side;
INSERT_PADDING_WORDS(0x17);
union {
BitField<2, 1, u32> coord_origin;
@@ -851,10 +872,12 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
ASSERT_REG_POSITION(depth_test_func, 0x4C3);
ASSERT_REG_POSITION(blend, 0x4CF);
ASSERT_REG_POSITION(stencil, 0x4E0);
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
ASSERT_REG_POSITION(vb_element_base, 0x50D);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(stencil_two_side, 0x565);
ASSERT_REG_POSITION(point_coord_replace, 0x581);
ASSERT_REG_POSITION(code_address, 0x582);
ASSERT_REG_POSITION(draw, 0x585);

View File

@@ -15,6 +15,7 @@
#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "core/hle/kernel/process.h"
#include "core/settings.h"
#include "video_core/engines/maxwell_3d.h"
@@ -22,6 +23,7 @@
#include "video_core/renderer_opengl/gl_shader_gen.h"
#include "video_core/renderer_opengl/maxwell_to_gl.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/video_core.h"
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
using PixelFormat = SurfaceParams::PixelFormat;
@@ -398,6 +400,8 @@ void RasterizerOpenGL::Clear() {
if (clear_mask == 0)
return;
ScopeAcquireGLContext acquire_context;
auto [dirty_color_surface, dirty_depth_surface] =
ConfigureFramebuffers(use_color_fb, use_depth_fb);
@@ -424,6 +428,8 @@ void RasterizerOpenGL::DrawArrays() {
MICROPROFILE_SCOPE(OpenGL_Drawing);
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
ScopeAcquireGLContext acquire_context;
auto [dirty_color_surface, dirty_depth_surface] =
ConfigureFramebuffers(true, regs.zeta.Address() != 0);

View File

@@ -105,6 +105,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
{GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8
// DepthStencil formats
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
@@ -112,6 +113,8 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
false}, // S8Z24
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, ComponentType::UNorm,
false}, // Z16
}};
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
@@ -194,8 +197,9 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
MortonCopy<true, PixelFormat::BC7U>, MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
MortonCopy<true, PixelFormat::Z24S8>, MortonCopy<true, PixelFormat::S8Z24>,
MortonCopy<true, PixelFormat::Z32F>,
MortonCopy<true, PixelFormat::G8R8>, MortonCopy<true, PixelFormat::Z24S8>,
MortonCopy<true, PixelFormat::S8Z24>, MortonCopy<true, PixelFormat::Z32F>,
MortonCopy<true, PixelFormat::Z16>,
};
static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
@@ -215,10 +219,12 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
nullptr,
nullptr,
nullptr,
MortonCopy<false, PixelFormat::ABGR8>,
nullptr,
MortonCopy<false, PixelFormat::G8R8>,
MortonCopy<false, PixelFormat::Z24S8>,
MortonCopy<false, PixelFormat::S8Z24>,
MortonCopy<false, PixelFormat::Z32F>,
MortonCopy<false, PixelFormat::Z16>,
};
// Allocate an uninitialized texture of appropriate size and format for the surface
@@ -271,9 +277,10 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
S8Z24 input_pixel{};
Z24S8 output_pixel{};
const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)};
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
const size_t offset{y * width + x};
const size_t offset{bpp * (y * width + x)};
std::memcpy(&input_pixel, &data[offset], sizeof(S8Z24));
output_pixel.s8.Assign(input_pixel.s8);
output_pixel.z24.Assign(input_pixel.z24);
@@ -281,6 +288,19 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
}
}
}
static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8)};
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
const size_t offset{bpp * (y * width + x)};
const u8 temp{data[offset]};
data[offset] = data[offset + 1];
data[offset + 1] = temp;
}
}
}
/**
* Helper function to perform software conversion (as needed) when loading a buffer from Switch
* memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with
@@ -301,6 +321,11 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma
// Convert the S8Z24 depth format to Z24S8, as OpenGL does not support S8Z24.
ConvertS8Z24ToZ24S8(data, width, height);
break;
case PixelFormat::G8R8:
// Convert the G8R8 color format to R8G8, as OpenGL does not support G8R8.
ConvertG8R8ToR8G8(data, width, height);
break;
}
}

View File

@@ -37,13 +37,15 @@ struct SurfaceParams {
DXN1 = 11, // This is also known as BC4
BC7U = 12,
ASTC_2D_4X4 = 13,
G8R8 = 14,
MaxColorFormat,
// DepthStencil formats
Z24S8 = 14,
S8Z24 = 15,
Z32F = 16,
Z24S8 = 15,
S8Z24 = 16,
Z32F = 17,
Z16 = 18,
MaxDepthStencilFormat,
@@ -95,9 +97,11 @@ struct SurfaceParams {
4, // DXN1
4, // BC7U
4, // ASTC_2D_4X4
1, // G8R8
1, // Z24S8
1, // S8Z24
1, // Z32F
1, // Z16
}};
ASSERT(static_cast<size_t>(format) < compression_factor_table.size());
@@ -123,9 +127,11 @@ struct SurfaceParams {
64, // DXN1
128, // BC7U
32, // ASTC_2D_4X4
16, // G8R8
32, // Z24S8
32, // S8Z24
32, // Z32F
16, // Z16
}};
ASSERT(static_cast<size_t>(format) < bpp_table.size());
@@ -143,6 +149,8 @@ struct SurfaceParams {
return PixelFormat::Z24S8;
case Tegra::DepthFormat::Z32_FLOAT:
return PixelFormat::Z32F;
case Tegra::DepthFormat::Z16_UNORM:
return PixelFormat::Z16;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
@@ -181,6 +189,8 @@ struct SurfaceParams {
return PixelFormat::A1B5G5R5;
case Tegra::Texture::TextureFormat::R8:
return PixelFormat::R8;
case Tegra::Texture::TextureFormat::G8R8:
return PixelFormat::G8R8;
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
return PixelFormat::RGBA16F;
case Tegra::Texture::TextureFormat::BF10GF11RF11:
@@ -218,6 +228,8 @@ struct SurfaceParams {
return Tegra::Texture::TextureFormat::A1B5G5R5;
case PixelFormat::R8:
return Tegra::Texture::TextureFormat::R8;
case PixelFormat::G8R8:
return Tegra::Texture::TextureFormat::G8R8;
case PixelFormat::RGBA16F:
return Tegra::Texture::TextureFormat::R16_G16_B16_A16;
case PixelFormat::R11FG11FB10F:
@@ -249,6 +261,8 @@ struct SurfaceParams {
return Tegra::DepthFormat::Z24_S8_UNORM;
case PixelFormat::Z32F:
return Tegra::DepthFormat::Z32_FLOAT;
case PixelFormat::Z16:
return Tegra::DepthFormat::Z16_UNORM;
default:
UNREACHABLE();
}
@@ -295,6 +309,7 @@ struct SurfaceParams {
static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
switch (format) {
case Tegra::DepthFormat::Z16_UNORM:
case Tegra::DepthFormat::S8_Z24_UNORM:
case Tegra::DepthFormat::Z24_S8_UNORM:
return ComponentType::UNorm;

View File

@@ -92,11 +92,24 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
return matrix;
}
ScopeAcquireGLContext::ScopeAcquireGLContext() {
if (Settings::values.use_multi_core) {
VideoCore::g_emu_window->MakeCurrent();
}
}
ScopeAcquireGLContext::~ScopeAcquireGLContext() {
if (Settings::values.use_multi_core) {
VideoCore::g_emu_window->DoneCurrent();
}
}
RendererOpenGL::RendererOpenGL() = default;
RendererOpenGL::~RendererOpenGL() = default;
/// Swap buffers (render frame)
void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) {
ScopeAcquireGLContext acquire_context;
Core::System::GetInstance().perf_stats.EndSystemFrame();
// Maintain the rasterizer's state as a priority
@@ -418,7 +431,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
/// Initialize the renderer
bool RendererOpenGL::Init() {
render_window->MakeCurrent();
ScopeAcquireGLContext acquire_context;
if (GLAD_GL_KHR_debug) {
glEnable(GL_DEBUG_OUTPUT);

View File

@@ -31,6 +31,13 @@ struct ScreenInfo {
TextureInfo texture;
};
/// Helper class to acquire/release OpenGL context within a given scope
class ScopeAcquireGLContext : NonCopyable {
public:
ScopeAcquireGLContext();
~ScopeAcquireGLContext();
};
class RendererOpenGL : public RendererBase {
public:
RendererOpenGL();

View File

@@ -62,6 +62,7 @@ u32 BytesPerPixel(TextureFormat format) {
return 4;
case TextureFormat::A1B5G5R5:
case TextureFormat::B5G6R5:
case TextureFormat::G8R8:
return 2;
case TextureFormat::R8:
return 1;
@@ -77,6 +78,8 @@ u32 BytesPerPixel(TextureFormat format) {
static u32 DepthBytesPerPixel(DepthFormat format) {
switch (format) {
case DepthFormat::Z16_UNORM:
return 2;
case DepthFormat::S8_Z24_UNORM:
case DepthFormat::Z24_S8_UNORM:
case DepthFormat::Z32_FLOAT:
@@ -110,6 +113,7 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width,
case TextureFormat::A1B5G5R5:
case TextureFormat::B5G6R5:
case TextureFormat::R8:
case TextureFormat::G8R8:
case TextureFormat::R16_G16_B16_A16:
case TextureFormat::R32_G32_B32_A32:
case TextureFormat::BF10GF11RF11:
@@ -133,6 +137,7 @@ std::vector<u8> UnswizzleDepthTexture(VAddr address, DepthFormat format, u32 wid
std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
switch (format) {
case DepthFormat::Z16_UNORM:
case DepthFormat::S8_Z24_UNORM:
case DepthFormat::Z24_S8_UNORM:
case DepthFormat::Z32_FLOAT:
@@ -164,6 +169,7 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
case TextureFormat::A1B5G5R5:
case TextureFormat::B5G6R5:
case TextureFormat::R8:
case TextureFormat::G8R8:
case TextureFormat::BF10GF11RF11:
case TextureFormat::R32_G32_B32_A32:
// TODO(Subv): For the time being just forward the same data without any decoding.

View File

@@ -20,7 +20,10 @@
EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {}
void EmuThread::run() {
render_window->MakeCurrent();
if (!Settings::values.use_multi_core) {
// Single core mode must acquire OpenGL context for entire emulation session
render_window->MakeCurrent();
}
MicroProfileOnThreadCreate("EmuThread");

View File

@@ -141,10 +141,12 @@ GameList::SearchField::SearchField(GameList* parent) : QWidget{parent} {
* @param userinput String containing all words getting checked
* @return true if the haystack contains all words of userinput
*/
bool GameList::containsAllWords(QString haystack, QString userinput) {
QStringList userinput_split = userinput.split(" ", QString::SplitBehavior::SkipEmptyParts);
bool GameList::ContainsAllWords(const QString& haystack, const QString& userinput) const {
const QStringList userinput_split =
userinput.split(' ', QString::SplitBehavior::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(),
[haystack](QString s) { return haystack.contains(s); });
[&haystack](const QString& s) { return haystack.contains(s); });
}
// Event in order to filter the gamelist after editing the searchfield
@@ -178,7 +180,7 @@ void GameList::onTextChanged(const QString& newText) {
// The search is case insensitive because of toLower()
// I decided not to use Qt::CaseInsensitive in containsAllWords to prevent
// multiple conversions of edit_filter_text for each game in the gamelist
if (containsAllWords(file_name.append(" ").append(file_title), edit_filter_text) ||
if (ContainsAllWords(file_name.append(' ').append(file_title), edit_filter_text) ||
(file_programmid.count() == 16 && edit_filter_text.contains(file_programmid))) {
tree_view->setRowHidden(i, root_index, false);
++result_count;

View File

@@ -89,7 +89,7 @@ private:
void PopupContextMenu(const QPoint& menu_location);
void RefreshGameDirectory();
bool containsAllWords(QString haystack, QString userinput);
bool ContainsAllWords(const QString& haystack, const QString& userinput) const;
SearchField* search_field;
GMainWindow* main_window = nullptr;

View File

@@ -374,6 +374,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
const Core::System::ResultStatus result{system.Load(render_window, filename.toStdString())};
render_window->DoneCurrent();
if (result != Core::System::ResultStatus::Success) {
switch (result) {
case Core::System::ResultStatus::ErrorGetLoader:
@@ -916,6 +918,7 @@ int main(int argc, char* argv[]) {
QCoreApplication::setApplicationName("yuzu");
QApplication::setAttribute(Qt::AA_X11InitThreads);
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
QApplication app(argc, argv);
// Qt changes the locale and causes issues in float conversion using std::to_string() when

View File

@@ -148,6 +148,11 @@ int main(int argc, char** argv) {
std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen)};
if (!Settings::values.use_multi_core) {
// Single core mode must acquire OpenGL context for entire emulation session
emu_window->MakeCurrent();
}
Core::System& system{Core::System::GetInstance()};
SCOPE_EXIT({ system.Shutdown(); });