Compare commits
21 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
531c25386e | ||
|
|
e59126809c | ||
|
|
1f6fe062ca | ||
|
|
ed542a7309 | ||
|
|
ef2d5ab0c1 | ||
|
|
59f4ff4659 | ||
|
|
5a28dce9eb | ||
|
|
8d4899d6ea | ||
|
|
95144cc39c | ||
|
|
8b4443c966 | ||
|
|
5ba71369ac | ||
|
|
5d529698c9 | ||
|
|
5b9bcbf438 | ||
|
|
2b082e2710 | ||
|
|
de580ccdd5 | ||
|
|
e52a87b98a | ||
|
|
0905dc1ff4 | ||
|
|
636ad34707 | ||
|
|
7fc516cc1a | ||
|
|
83aa38b239 | ||
|
|
c03795300a |
@@ -192,11 +192,6 @@ private:
|
||||
static_assert(position < 8 * sizeof(T), "Invalid position");
|
||||
static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
|
||||
static_assert(bits > 0, "Invalid number of bits");
|
||||
static_assert(std::is_pod<T>::value, "Invalid base type");
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField");
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
|
||||
static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
|
||||
"BitField must be trivially copyable");
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,8 @@ add_library(core STATIC
|
||||
file_sys/errors.h
|
||||
file_sys/filesystem.cpp
|
||||
file_sys/filesystem.h
|
||||
file_sys/partition_filesystem.cpp
|
||||
file_sys/partition_filesystem.h
|
||||
file_sys/path_parser.cpp
|
||||
file_sys/path_parser.h
|
||||
file_sys/program_metadata.cpp
|
||||
|
||||
125
src/core/file_sys/partition_filesystem.cpp
Normal file
125
src/core/file_sys/partition_filesystem.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cinttypes>
|
||||
#include <utility>
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/partition_filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, size_t offset) {
|
||||
FileUtil::IOFile file(file_path, "rb");
|
||||
if (!file.IsOpen())
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
// At least be as large as the header
|
||||
if (file.GetSize() < sizeof(Header))
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
// For cartridges, HFSs can get very large, so we need to calculate the size up to
|
||||
// the actual content itself instead of just blindly reading in the entire file.
|
||||
Header pfs_header;
|
||||
if (!file.ReadBytes(&pfs_header, sizeof(Header)))
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
bool is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0);
|
||||
size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
|
||||
size_t metadata_size =
|
||||
sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size;
|
||||
|
||||
// Actually read in now...
|
||||
file.Seek(offset, SEEK_SET);
|
||||
std::vector<u8> file_data(metadata_size);
|
||||
|
||||
if (!file.ReadBytes(file_data.data(), metadata_size))
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
Loader::ResultStatus result = Load(file_data);
|
||||
if (result != Loader::ResultStatus::Success)
|
||||
LOG_ERROR(Service_FS, "Failed to load PFS from file %s!", file_path.c_str());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Loader::ResultStatus PartitionFilesystem::Load(const std::vector<u8>& file_data, size_t offset) {
|
||||
size_t total_size = file_data.size() - offset;
|
||||
if (total_size < sizeof(Header))
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
memcpy(&pfs_header, &file_data[offset], sizeof(Header));
|
||||
is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0);
|
||||
|
||||
size_t entries_offset = offset + sizeof(Header);
|
||||
size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
|
||||
size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size);
|
||||
for (u16 i = 0; i < pfs_header.num_entries; i++) {
|
||||
FileEntry entry;
|
||||
|
||||
memcpy(&entry.fs_entry, &file_data[entries_offset + (i * entry_size)], sizeof(FSEntry));
|
||||
entry.name = std::string(reinterpret_cast<const char*>(
|
||||
&file_data[strtab_offset + entry.fs_entry.strtab_offset]));
|
||||
pfs_entries.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
content_offset = strtab_offset + pfs_header.strtab_size;
|
||||
|
||||
return Loader::ResultStatus::Success;
|
||||
}
|
||||
|
||||
u32 PartitionFilesystem::GetNumEntries() const {
|
||||
return pfs_header.num_entries;
|
||||
}
|
||||
|
||||
u64 PartitionFilesystem::GetEntryOffset(int index) const {
|
||||
if (index > GetNumEntries())
|
||||
return 0;
|
||||
|
||||
return content_offset + pfs_entries[index].fs_entry.offset;
|
||||
}
|
||||
|
||||
u64 PartitionFilesystem::GetEntrySize(int index) const {
|
||||
if (index > GetNumEntries())
|
||||
return 0;
|
||||
|
||||
return pfs_entries[index].fs_entry.size;
|
||||
}
|
||||
|
||||
std::string PartitionFilesystem::GetEntryName(int index) const {
|
||||
if (index > GetNumEntries())
|
||||
return "";
|
||||
|
||||
return pfs_entries[index].name;
|
||||
}
|
||||
|
||||
u64 PartitionFilesystem::GetFileOffset(const std::string& name) const {
|
||||
for (u32 i = 0; i < pfs_header.num_entries; i++) {
|
||||
if (pfs_entries[i].name == name)
|
||||
return content_offset + pfs_entries[i].fs_entry.offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 PartitionFilesystem::GetFileSize(const std::string& name) const {
|
||||
for (u32 i = 0; i < pfs_header.num_entries; i++) {
|
||||
if (pfs_entries[i].name == name)
|
||||
return pfs_entries[i].fs_entry.size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PartitionFilesystem::Print() const {
|
||||
NGLOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic.data());
|
||||
NGLOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries);
|
||||
for (u32 i = 0; i < pfs_header.num_entries; i++) {
|
||||
NGLOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i,
|
||||
pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size,
|
||||
GetFileOffset(pfs_entries[i].name));
|
||||
}
|
||||
}
|
||||
} // namespace FileSys
|
||||
87
src/core/file_sys/partition_filesystem.h
Normal file
87
src/core/file_sys/partition_filesystem.h
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
|
||||
namespace Loader {
|
||||
enum class ResultStatus;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
/**
|
||||
* Helper which implements an interface to parse PFS/HFS filesystems.
|
||||
* Data can either be loaded from a file path or data with an offset into it.
|
||||
*/
|
||||
class PartitionFilesystem {
|
||||
public:
|
||||
Loader::ResultStatus Load(const std::string& file_path, size_t offset = 0);
|
||||
Loader::ResultStatus Load(const std::vector<u8>& file_data, size_t offset = 0);
|
||||
|
||||
u32 GetNumEntries() const;
|
||||
u64 GetEntryOffset(int index) const;
|
||||
u64 GetEntrySize(int index) const;
|
||||
std::string GetEntryName(int index) const;
|
||||
u64 GetFileOffset(const std::string& name) const;
|
||||
u64 GetFileSize(const std::string& name) const;
|
||||
|
||||
void Print() const;
|
||||
|
||||
private:
|
||||
struct Header {
|
||||
std::array<char, 4> magic;
|
||||
u32_le num_entries;
|
||||
u32_le strtab_size;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
};
|
||||
|
||||
static_assert(sizeof(Header) == 0x10, "PFS/HFS header structure size is wrong");
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct FSEntry {
|
||||
u64_le offset;
|
||||
u64_le size;
|
||||
u32_le strtab_offset;
|
||||
};
|
||||
|
||||
static_assert(sizeof(FSEntry) == 0x14, "FS entry structure size is wrong");
|
||||
|
||||
struct PFSEntry {
|
||||
FSEntry fs_entry;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
};
|
||||
|
||||
static_assert(sizeof(PFSEntry) == 0x18, "PFS entry structure size is wrong");
|
||||
|
||||
struct HFSEntry {
|
||||
FSEntry fs_entry;
|
||||
u32_le hash_region_size;
|
||||
INSERT_PADDING_BYTES(0x8);
|
||||
std::array<char, 0x20> hash;
|
||||
};
|
||||
|
||||
static_assert(sizeof(HFSEntry) == 0x40, "HFS entry structure size is wrong");
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct FileEntry {
|
||||
FSEntry fs_entry;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
Header pfs_header;
|
||||
bool is_hfs;
|
||||
size_t content_offset;
|
||||
|
||||
std::vector<FileEntry> pfs_entries;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
@@ -861,14 +861,14 @@ static const FunctionDef SVC_Table[] = {
|
||||
{0x2B, nullptr, "FlushDataCache"},
|
||||
{0x2C, nullptr, "MapPhysicalMemory"},
|
||||
{0x2D, nullptr, "UnmapPhysicalMemory"},
|
||||
{0x2E, nullptr, "Unknown"},
|
||||
{0x2E, nullptr, "GetNextThreadInfo"},
|
||||
{0x2F, nullptr, "GetLastThreadInfo"},
|
||||
{0x30, nullptr, "GetResourceLimitLimitValue"},
|
||||
{0x31, nullptr, "GetResourceLimitCurrentValue"},
|
||||
{0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
|
||||
{0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
|
||||
{0x34, nullptr, "Unknown"},
|
||||
{0x35, nullptr, "Unknown"},
|
||||
{0x34, nullptr, "WaitForAddress"},
|
||||
{0x35, nullptr, "SignalToAddress"},
|
||||
{0x36, nullptr, "Unknown"},
|
||||
{0x37, nullptr, "Unknown"},
|
||||
{0x38, nullptr, "Unknown"},
|
||||
@@ -876,7 +876,7 @@ static const FunctionDef SVC_Table[] = {
|
||||
{0x3A, nullptr, "Unknown"},
|
||||
{0x3B, nullptr, "Unknown"},
|
||||
{0x3C, nullptr, "DumpInfo"},
|
||||
{0x3D, nullptr, "Unknown"},
|
||||
{0x3D, nullptr, "DumpInfoNew"},
|
||||
{0x3E, nullptr, "Unknown"},
|
||||
{0x3F, nullptr, "Unknown"},
|
||||
{0x40, nullptr, "CreateSession"},
|
||||
@@ -887,9 +887,9 @@ static const FunctionDef SVC_Table[] = {
|
||||
{0x45, nullptr, "CreateEvent"},
|
||||
{0x46, nullptr, "Unknown"},
|
||||
{0x47, nullptr, "Unknown"},
|
||||
{0x48, nullptr, "Unknown"},
|
||||
{0x49, nullptr, "Unknown"},
|
||||
{0x4A, nullptr, "Unknown"},
|
||||
{0x48, nullptr, "AllocateUnsafeMemory"},
|
||||
{0x49, nullptr, "FreeUnsafeMemory"},
|
||||
{0x4A, nullptr, "SetUnsafeAllocationLimit"},
|
||||
{0x4B, nullptr, "CreateJitMemory"},
|
||||
{0x4C, nullptr, "MapJitMemory"},
|
||||
{0x4D, nullptr, "SleepSystem"},
|
||||
@@ -926,7 +926,7 @@ static const FunctionDef SVC_Table[] = {
|
||||
{0x6C, nullptr, "SetHardwareBreakPoint"},
|
||||
{0x6D, nullptr, "GetDebugThreadParam"},
|
||||
{0x6E, nullptr, "Unknown"},
|
||||
{0x6F, nullptr, "Unknown"},
|
||||
{0x6F, nullptr, "GetMemoryInfo"},
|
||||
{0x70, nullptr, "CreatePort"},
|
||||
{0x71, nullptr, "ManageNamedPort"},
|
||||
{0x72, nullptr, "ConnectToPort"},
|
||||
|
||||
@@ -38,7 +38,10 @@ class IProfile final : public ServiceFramework<IProfile> {
|
||||
public:
|
||||
IProfile() : ServiceFramework("IProfile") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Get"},
|
||||
{1, &IProfile::GetBase, "GetBase"},
|
||||
{10, nullptr, "GetImageSize"},
|
||||
{11, nullptr, "LoadImage"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -59,6 +62,11 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
|
||||
{1, &IManagerForApplication::GetAccountId, "GetAccountId"},
|
||||
{2, nullptr, "EnsureIdTokenCacheAsync"},
|
||||
{3, nullptr, "LoadIdTokenCache"},
|
||||
{130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
|
||||
{150, nullptr, "CreateAuthorizationRequest"},
|
||||
{160, nullptr, "StoreOpenContext"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ SET::SET() : ServiceFramework("set") {
|
||||
{5, nullptr, "GetAvailableLanguageCodes2"},
|
||||
{6, nullptr, "GetAvailableLanguageCodeCount2"},
|
||||
{7, nullptr, "GetKeyCodeMap"},
|
||||
{8, nullptr, "GetQuestFlag"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,15 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") {
|
||||
{21, nullptr, "GetEticketDeviceKey"},
|
||||
{22, nullptr, "GetSpeakerParameter"},
|
||||
{23, nullptr, "GetLcdVendorId"},
|
||||
{24, nullptr, "GetEciDeviceCertificate2"},
|
||||
{25, nullptr, "GetEciDeviceKey2"},
|
||||
{26, nullptr, "GetAmiiboKey"},
|
||||
{27, nullptr, "GetAmiiboEcqvCertificate"},
|
||||
{28, nullptr, "GetAmiiboEcdsaCertificate"},
|
||||
{29, nullptr, "GetAmiiboEcqvBlsKey"},
|
||||
{30, nullptr, "GetAmiiboEcqvBlsCertificate"},
|
||||
{31, nullptr, "GetAmiiboEcqvBlsRootCertificate"},
|
||||
{32, nullptr, "GetUnknownId"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
|
||||
{2, nullptr, "GetNetworkSettings"},
|
||||
{3, nullptr, "GetFirmwareVersion"},
|
||||
{4, nullptr, "GetFirmwareVersion2"},
|
||||
{5, nullptr, "GetFirmwareVersionDigest"},
|
||||
{7, nullptr, "GetLockScreenFlag"},
|
||||
{8, nullptr, "SetLockScreenFlag"},
|
||||
{9, nullptr, "GetBacklightSettings"},
|
||||
@@ -159,6 +160,15 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
|
||||
{138, nullptr, "GetWebInspectorFlag"},
|
||||
{139, nullptr, "GetAllowedSslHosts"},
|
||||
{140, nullptr, "GetHostFsMountPoint"},
|
||||
{141, nullptr, "GetRequiresRunRepairTimeReviser"},
|
||||
{142, nullptr, "SetRequiresRunRepairTimeReviser"},
|
||||
{143, nullptr, "SetBlePairingSettings"},
|
||||
{144, nullptr, "GetBlePairingSettings"},
|
||||
{145, nullptr, "GetConsoleSixAxisSensorAngularVelocityTimeBias"},
|
||||
{146, nullptr, "SetConsoleSixAxisSensorAngularVelocityTimeBias"},
|
||||
{147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"},
|
||||
{148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"},
|
||||
{149, nullptr, "GetRebootlessSystemUpdateVersion"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -79,9 +79,34 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
|
||||
{0, &BSD::RegisterClient, "RegisterClient"},
|
||||
{1, &BSD::StartMonitoring, "StartMonitoring"},
|
||||
{2, &BSD::Socket, "Socket"},
|
||||
{3, nullptr, "SocketExempt"},
|
||||
{4, nullptr, "Open"},
|
||||
{5, nullptr, "Select"},
|
||||
{6, nullptr, "Poll"},
|
||||
{7, nullptr, "Sysctl"},
|
||||
{8, nullptr, "Recv"},
|
||||
{9, nullptr, "RecvFrom"},
|
||||
{10, nullptr, "Send"},
|
||||
{11, &BSD::SendTo, "SendTo"},
|
||||
{12, nullptr, "Accept"},
|
||||
{13, nullptr, "Bind"},
|
||||
{14, &BSD::Connect, "Connect"},
|
||||
{15, nullptr, "GetPeerName"},
|
||||
{16, nullptr, "GetSockName"},
|
||||
{17, nullptr, "GetSockOpt"},
|
||||
{18, nullptr, "Listen"},
|
||||
{19, nullptr, "Ioctl"},
|
||||
{20, nullptr, "Fcntl"},
|
||||
{21, nullptr, "SetSockOpt"},
|
||||
{22, nullptr, "Shutdown"},
|
||||
{23, nullptr, "ShutdownAllSockets"},
|
||||
{24, nullptr, "Write"},
|
||||
{25, nullptr, "Read"},
|
||||
{26, &BSD::Close, "Close"},
|
||||
{27, nullptr, "DuplicateSocket"},
|
||||
{28, nullptr, "GetResourceStatistics"},
|
||||
{29, nullptr, "RecvMMsg"},
|
||||
{30, nullptr, "SendMMsg"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
|
||||
{7, nullptr, "GetNameInfo"},
|
||||
{8, nullptr, "RequestCancelHandle"},
|
||||
{9, nullptr, "CancelSocketCall"},
|
||||
{11, nullptr, "ClearDnsIpServerAddressArray"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module),
|
||||
{23, nullptr, "GetSplWaitEvent"},
|
||||
{24, nullptr, "SetSharedData"},
|
||||
{25, nullptr, "GetSharedData"},
|
||||
{26, nullptr, "ImportSslRsaKey"},
|
||||
{27, nullptr, "SecureExpModWithSslKey"},
|
||||
{28, nullptr, "ImportEsRsaKey"},
|
||||
{29, nullptr, "SecureExpModWithEsKey"},
|
||||
{30, nullptr, "EncryptManuRsaKeyForImport"},
|
||||
{31, nullptr, "GetPackage2Hash"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,11 @@ public:
|
||||
ISystemClock() : ServiceFramework("ISystemClock") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
|
||||
{2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}};
|
||||
{1, nullptr, "SetCurrentTime"},
|
||||
{2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
|
||||
{3, nullptr, "SetSystemClockContext"},
|
||||
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,17 @@ TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time)
|
||||
{2, &TIME_S::GetStandardSteadyClock, "GetStandardSteadyClock"},
|
||||
{3, &TIME_S::GetTimeZoneService, "GetTimeZoneService"},
|
||||
{4, &TIME_S::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
|
||||
{5, nullptr, "GetEphemeralNetworkSystemClock"},
|
||||
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
|
||||
{100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
|
||||
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
|
||||
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
|
||||
{400, nullptr, "GetClockSnapshot"},
|
||||
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
|
||||
{500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
|
||||
{501, nullptr, "CalculateSpanBetween"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,17 @@ TIME_U::TIME_U(std::shared_ptr<Module> time) : Module::Interface(std::move(time)
|
||||
{2, &TIME_U::GetStandardSteadyClock, "GetStandardSteadyClock"},
|
||||
{3, &TIME_U::GetTimeZoneService, "GetTimeZoneService"},
|
||||
{4, &TIME_U::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
|
||||
{5, nullptr, "GetEphemeralNetworkSystemClock"},
|
||||
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
|
||||
{100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
|
||||
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
|
||||
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
|
||||
{400, nullptr, "GetClockSnapshot"},
|
||||
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
|
||||
{500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
|
||||
{501, nullptr, "CalculateSpanBetween"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -580,7 +580,48 @@ public:
|
||||
ISystemDisplayService() : ServiceFramework("ISystemDisplayService") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{1200, nullptr, "GetZOrderCountMin"},
|
||||
{1202, nullptr, "GetZOrderCountMax"},
|
||||
{1203, nullptr, "GetDisplayLogicalResolution"},
|
||||
{1204, nullptr, "SetDisplayMagnification"},
|
||||
{2201, nullptr, "SetLayerPosition"},
|
||||
{2203, nullptr, "SetLayerSize"},
|
||||
{2204, nullptr, "GetLayerZ"},
|
||||
{2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
|
||||
{2207, nullptr, "SetLayerVisibility"},
|
||||
{2209, nullptr, "SetLayerAlpha"},
|
||||
{2312, nullptr, "CreateStrayLayer"},
|
||||
{2400, nullptr, "OpenIndirectLayer"},
|
||||
{2401, nullptr, "CloseIndirectLayer"},
|
||||
{2402, nullptr, "FlipIndirectLayer"},
|
||||
{3000, nullptr, "ListDisplayModes"},
|
||||
{3001, nullptr, "ListDisplayRgbRanges"},
|
||||
{3002, nullptr, "ListDisplayContentTypes"},
|
||||
{3200, nullptr, "GetDisplayMode"},
|
||||
{3201, nullptr, "SetDisplayMode"},
|
||||
{3202, nullptr, "GetDisplayUnderscan"},
|
||||
{3203, nullptr, "SetDisplayUnderscan"},
|
||||
{3204, nullptr, "GetDisplayContentType"},
|
||||
{3205, nullptr, "SetDisplayContentType"},
|
||||
{3206, nullptr, "GetDisplayRgbRange"},
|
||||
{3207, nullptr, "SetDisplayRgbRange"},
|
||||
{3208, nullptr, "GetDisplayCmuMode"},
|
||||
{3209, nullptr, "SetDisplayCmuMode"},
|
||||
{3210, nullptr, "GetDisplayContrastRatio"},
|
||||
{3211, nullptr, "SetDisplayContrastRatio"},
|
||||
{3214, nullptr, "GetDisplayGamma"},
|
||||
{3215, nullptr, "SetDisplayGamma"},
|
||||
{3216, nullptr, "GetDisplayCmuLuma"},
|
||||
{3217, nullptr, "SetDisplayCmuLuma"},
|
||||
{8225, nullptr, "GetSharedBufferMemoryHandleId"},
|
||||
{8250, nullptr, "OpenSharedLayer"},
|
||||
{8251, nullptr, "CloseSharedLayer"},
|
||||
{8252, nullptr, "ConnectSharedLayer"},
|
||||
{8253, nullptr, "DisconnectSharedLayer"},
|
||||
{8254, nullptr, "AcquireSharedFrameBuffer"},
|
||||
{8255, nullptr, "PresentSharedFrameBuffer"},
|
||||
{8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
|
||||
{8257, nullptr, "FillSharedFrameBufferColor"},
|
||||
{8258, nullptr, "CancelSharedFrameBuffer"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -603,10 +644,72 @@ public:
|
||||
explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{200, nullptr, "AllocateProcessHeapBlock"},
|
||||
{201, nullptr, "FreeProcessHeapBlock"},
|
||||
{1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"},
|
||||
{1102, nullptr, "GetDisplayResolution"},
|
||||
{2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"},
|
||||
{2011, nullptr, "DestroyManagedLayer"},
|
||||
{2050, nullptr, "CreateIndirectLayer"},
|
||||
{2051, nullptr, "DestroyIndirectLayer"},
|
||||
{2052, nullptr, "CreateIndirectProducerEndPoint"},
|
||||
{2053, nullptr, "DestroyIndirectProducerEndPoint"},
|
||||
{2054, nullptr, "CreateIndirectConsumerEndPoint"},
|
||||
{2055, nullptr, "DestroyIndirectConsumerEndPoint"},
|
||||
{2300, nullptr, "AcquireLayerTexturePresentingEvent"},
|
||||
{2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
|
||||
{2302, nullptr, "GetDisplayHotplugEvent"},
|
||||
{2402, nullptr, "GetDisplayHotplugState"},
|
||||
{2501, nullptr, "GetCompositorErrorInfo"},
|
||||
{2601, nullptr, "GetDisplayErrorEvent"},
|
||||
{4201, nullptr, "SetDisplayAlpha"},
|
||||
{4203, nullptr, "SetDisplayLayerStack"},
|
||||
{4205, nullptr, "SetDisplayPowerState"},
|
||||
{4206, nullptr, "SetDefaultDisplay"},
|
||||
{6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
|
||||
{6001, nullptr, "RemoveFromLayerStack"},
|
||||
{6002, nullptr, "SetLayerVisibility"},
|
||||
{6003, nullptr, "SetLayerConfig"},
|
||||
{6004, nullptr, "AttachLayerPresentationTracer"},
|
||||
{6005, nullptr, "DetachLayerPresentationTracer"},
|
||||
{6006, nullptr, "StartLayerPresentationRecording"},
|
||||
{6007, nullptr, "StopLayerPresentationRecording"},
|
||||
{6008, nullptr, "StartLayerPresentationFenceWait"},
|
||||
{6009, nullptr, "StopLayerPresentationFenceWait"},
|
||||
{6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"},
|
||||
{7000, nullptr, "SetContentVisibility"},
|
||||
{8000, nullptr, "SetConductorLayer"},
|
||||
{8100, nullptr, "SetIndirectProducerFlipOffset"},
|
||||
{8200, nullptr, "CreateSharedBufferStaticStorage"},
|
||||
{8201, nullptr, "CreateSharedBufferTransferMemory"},
|
||||
{8202, nullptr, "DestroySharedBuffer"},
|
||||
{8203, nullptr, "BindSharedLowLevelLayerToManagedLayer"},
|
||||
{8204, nullptr, "BindSharedLowLevelLayerToIndirectLayer"},
|
||||
{8207, nullptr, "UnbindSharedLowLevelLayer"},
|
||||
{8208, nullptr, "ConnectSharedLowLevelLayerToSharedBuffer"},
|
||||
{8209, nullptr, "DisconnectSharedLowLevelLayerFromSharedBuffer"},
|
||||
{8210, nullptr, "CreateSharedLayer"},
|
||||
{8211, nullptr, "DestroySharedLayer"},
|
||||
{8216, nullptr, "AttachSharedLayerToLowLevelLayer"},
|
||||
{8217, nullptr, "ForceDetachSharedLayerFromLowLevelLayer"},
|
||||
{8218, nullptr, "StartDetachSharedLayerFromLowLevelLayer"},
|
||||
{8219, nullptr, "FinishDetachSharedLayerFromLowLevelLayer"},
|
||||
{8220, nullptr, "GetSharedLayerDetachReadyEvent"},
|
||||
{8221, nullptr, "GetSharedLowLevelLayerSynchronizedEvent"},
|
||||
{8222, nullptr, "CheckSharedLowLevelLayerSynchronized"},
|
||||
{8223, nullptr, "RegisterSharedBufferImporterAruid"},
|
||||
{8224, nullptr, "UnregisterSharedBufferImporterAruid"},
|
||||
{8227, nullptr, "CreateSharedBufferProcessHeap"},
|
||||
{8228, nullptr, "GetSharedLayerLayerStacks"},
|
||||
{8229, nullptr, "SetSharedLayerLayerStacks"},
|
||||
{8291, nullptr, "PresentDetachedSharedFrameBufferToLowLevelLayer"},
|
||||
{8292, nullptr, "FillDetachedSharedFrameBufferColor"},
|
||||
{8293, nullptr, "GetDetachedSharedFrameBufferImage"},
|
||||
{8294, nullptr, "SetDetachedSharedFrameBufferImage"},
|
||||
{8295, nullptr, "CopyDetachedSharedFrameBufferImage"},
|
||||
{8296, nullptr, "SetDetachedSharedFrameBufferSubImage"},
|
||||
{8297, nullptr, "GetSharedFrameBufferContentParameter"},
|
||||
{8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -825,13 +928,21 @@ IApplicationDisplayService::IApplicationDisplayService(
|
||||
"GetIndirectDisplayTransactionService"},
|
||||
{1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
|
||||
{1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
|
||||
{1011, nullptr, "OpenDefaultDisplay"},
|
||||
{1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
|
||||
{1101, nullptr, "SetDisplayEnabled"},
|
||||
{1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
|
||||
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
|
||||
{2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
|
||||
{2021, nullptr, "CloseLayer"},
|
||||
{2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
|
||||
{2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
|
||||
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
|
||||
{2102, nullptr, "ConvertScalingMode"},
|
||||
{2450, nullptr, "GetIndirectLayerImageMap"},
|
||||
{2451, nullptr, "GetIndirectLayerImageCropMap"},
|
||||
{2460, nullptr, "GetIndirectLayerImageRequiredMemoryInfo"},
|
||||
{5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
|
||||
{5203, nullptr, "GetDisplayVsyncEventForDebug"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger>
|
||||
: Module::Interface(std::move(module), "vi:u", std::move(nv_flinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &VI_U::GetDisplayService, "GetDisplayService"},
|
||||
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "common/bit_field.h"
|
||||
@@ -12,14 +13,10 @@ namespace Tegra {
|
||||
namespace Shader {
|
||||
|
||||
struct Register {
|
||||
Register() = default;
|
||||
constexpr Register() = default;
|
||||
|
||||
constexpr Register(u64 value) : value(value) {}
|
||||
|
||||
constexpr u64 GetIndex() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr operator u64() const {
|
||||
return value;
|
||||
}
|
||||
@@ -43,13 +40,13 @@ struct Register {
|
||||
}
|
||||
|
||||
private:
|
||||
u64 value;
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
union Attribute {
|
||||
Attribute() = default;
|
||||
|
||||
constexpr Attribute(u64 value) : value(value) {}
|
||||
constexpr explicit Attribute(u64 value) : value(value) {}
|
||||
|
||||
enum class Index : u64 {
|
||||
Position = 7,
|
||||
@@ -68,7 +65,20 @@ union Attribute {
|
||||
} fmt28;
|
||||
|
||||
BitField<39, 8, u64> reg;
|
||||
u64 value;
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
union Sampler {
|
||||
Sampler() = default;
|
||||
|
||||
constexpr explicit Sampler(u64 value) : value(value) {}
|
||||
|
||||
enum class Index : u64 {
|
||||
Sampler_0 = 8,
|
||||
};
|
||||
|
||||
BitField<36, 13, Index> index;
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
union Uniform {
|
||||
@@ -238,7 +248,7 @@ union OpCode {
|
||||
BitField<55, 9, Id> op3;
|
||||
BitField<52, 12, Id> op4;
|
||||
BitField<51, 13, Id> op5;
|
||||
u64 value;
|
||||
u64 value{};
|
||||
};
|
||||
static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size");
|
||||
|
||||
@@ -280,6 +290,7 @@ enum class SubOp : u64 {
|
||||
Lg2 = 0x3,
|
||||
Rcp = 0x4,
|
||||
Rsq = 0x5,
|
||||
Min = 0x8,
|
||||
};
|
||||
|
||||
union Instruction {
|
||||
@@ -295,15 +306,25 @@ union Instruction {
|
||||
BitField<20, 8, Register> gpr20;
|
||||
BitField<20, 7, SubOp> sub_op;
|
||||
BitField<28, 8, Register> gpr28;
|
||||
BitField<36, 13, u64> imm36;
|
||||
BitField<39, 8, Register> gpr39;
|
||||
|
||||
union {
|
||||
BitField<20, 19, u64> imm20;
|
||||
BitField<45, 1, u64> negate_b;
|
||||
BitField<46, 1, u64> abs_a;
|
||||
BitField<48, 1, u64> negate_a;
|
||||
BitField<49, 1, u64> abs_b;
|
||||
BitField<50, 1, u64> abs_d;
|
||||
BitField<56, 1, u64> negate_imm;
|
||||
|
||||
float GetImm20() const {
|
||||
float result{};
|
||||
u32 imm{static_cast<u32>(imm20)};
|
||||
imm <<= 12;
|
||||
imm |= negate_imm ? 0x80000000 : 0;
|
||||
std::memcpy(&result, &imm, sizeof(imm));
|
||||
return result;
|
||||
}
|
||||
} alu;
|
||||
|
||||
union {
|
||||
@@ -311,11 +332,13 @@ union Instruction {
|
||||
BitField<49, 1, u64> negate_c;
|
||||
} ffma;
|
||||
|
||||
BitField<61, 1, u64> is_b_imm;
|
||||
BitField<60, 1, u64> is_b_gpr;
|
||||
BitField<59, 1, u64> is_c_gpr;
|
||||
|
||||
Attribute attribute;
|
||||
Uniform uniform;
|
||||
Sampler sampler;
|
||||
|
||||
u64 hex;
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ using Tegra::Shader::Attribute;
|
||||
using Tegra::Shader::Instruction;
|
||||
using Tegra::Shader::OpCode;
|
||||
using Tegra::Shader::Register;
|
||||
using Tegra::Shader::Sampler;
|
||||
using Tegra::Shader::SubOp;
|
||||
using Tegra::Shader::Uniform;
|
||||
|
||||
@@ -155,23 +156,27 @@ private:
|
||||
|
||||
/// Generates code representing an input attribute register.
|
||||
std::string GetInputAttribute(Attribute::Index attribute) {
|
||||
declr_input_attribute.insert(attribute);
|
||||
switch (attribute) {
|
||||
case Attribute::Index::Position:
|
||||
return "position";
|
||||
default:
|
||||
const u32 index{static_cast<u32>(attribute) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)};
|
||||
if (attribute >= Attribute::Index::Attribute_0) {
|
||||
declr_input_attribute.insert(attribute);
|
||||
return "input_attribute_" + std::to_string(index);
|
||||
}
|
||||
|
||||
const u32 index{static_cast<u32>(attribute) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)};
|
||||
if (attribute >= Attribute::Index::Attribute_0) {
|
||||
return "input_attribute_" + std::to_string(index);
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled input attribute: 0x%02x", index);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
/// Generates code representing an output attribute register.
|
||||
std::string GetOutputAttribute(Attribute::Index attribute) {
|
||||
switch (attribute) {
|
||||
case Attribute::Index::Position:
|
||||
return "gl_Position";
|
||||
return "position";
|
||||
default:
|
||||
const u32 index{static_cast<u32>(attribute) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)};
|
||||
@@ -180,22 +185,42 @@ private:
|
||||
return "output_attribute_" + std::to_string(index);
|
||||
}
|
||||
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled output attribute: 0x%02x", index);
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates code representing an immediate value
|
||||
static std::string GetImmediate(const Instruction& instr) {
|
||||
return std::to_string(instr.alu.GetImm20());
|
||||
}
|
||||
|
||||
/// Generates code representing a temporary (GPR) register.
|
||||
std::string GetRegister(const Register& reg) {
|
||||
return *declr_register.insert("register_" + std::to_string(reg)).first;
|
||||
std::string GetRegister(const Register& reg, unsigned elem = 0) {
|
||||
if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
|
||||
// GPRs 0-3 are output color for the fragment shader
|
||||
return std::string{"color."} + "rgba"[(reg + elem) & 3];
|
||||
}
|
||||
|
||||
return *declr_register.insert("register_" + std::to_string(reg + elem)).first;
|
||||
}
|
||||
|
||||
/// Generates code representing a uniform (C buffer) register.
|
||||
std::string GetUniform(const Uniform& reg) {
|
||||
declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset, stage);
|
||||
declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index),
|
||||
static_cast<unsigned>(reg.offset), stage);
|
||||
return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
|
||||
}
|
||||
|
||||
/// Generates code representing a texture sampler.
|
||||
std::string GetSampler(const Sampler& sampler) const {
|
||||
// TODO(Subv): Support more than just texture sampler 0
|
||||
ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported");
|
||||
const unsigned index{static_cast<unsigned>(sampler.index.Value()) -
|
||||
static_cast<unsigned>(Sampler::Index::Sampler_0)};
|
||||
return "tex[" + std::to_string(index) + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds code that calls a subroutine.
|
||||
* @param subroutine the subroutine to call.
|
||||
@@ -217,12 +242,13 @@ private:
|
||||
* @param value the code representing the value to assign.
|
||||
*/
|
||||
void SetDest(u64 elem, const std::string& reg, const std::string& value,
|
||||
u64 dest_num_components, u64 value_num_components) {
|
||||
u64 dest_num_components, u64 value_num_components, bool is_abs = false) {
|
||||
std::string swizzle = ".";
|
||||
swizzle += "xyzw"[elem];
|
||||
|
||||
std::string dest = reg + (dest_num_components != 1 ? swizzle : "");
|
||||
std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : "");
|
||||
src = is_abs ? "abs(" + src + ")" : src;
|
||||
|
||||
shader.AddLine(dest + " = " + src + ";");
|
||||
}
|
||||
@@ -240,8 +266,6 @@ private:
|
||||
|
||||
switch (OpCode::GetInfo(instr.opcode).type) {
|
||||
case OpCode::Type::Arithmetic: {
|
||||
ASSERT(!instr.alu.abs_d);
|
||||
|
||||
std::string dest = GetRegister(instr.gpr0);
|
||||
std::string op_a = instr.alu.negate_a ? "-" : "";
|
||||
op_a += GetRegister(instr.gpr8);
|
||||
@@ -250,63 +274,109 @@ private:
|
||||
}
|
||||
|
||||
std::string op_b = instr.alu.negate_b ? "-" : "";
|
||||
if (instr.is_b_gpr) {
|
||||
op_b += GetRegister(instr.gpr20);
|
||||
|
||||
if (instr.is_b_imm) {
|
||||
op_b += GetImmediate(instr);
|
||||
} else {
|
||||
op_b += GetUniform(instr.uniform);
|
||||
if (instr.is_b_gpr) {
|
||||
op_b += GetRegister(instr.gpr20);
|
||||
} else {
|
||||
op_b += GetUniform(instr.uniform);
|
||||
}
|
||||
}
|
||||
|
||||
if (instr.alu.abs_b) {
|
||||
op_b = "abs(" + op_b + ")";
|
||||
}
|
||||
|
||||
switch (instr.opcode.EffectiveOpCode()) {
|
||||
case OpCode::Id::FMUL_C:
|
||||
case OpCode::Id::FMUL_R: {
|
||||
SetDest(0, dest, op_a + " * " + op_b, 1, 1);
|
||||
case OpCode::Id::FMUL_R:
|
||||
case OpCode::Id::FMUL_IMM: {
|
||||
SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FADD_C:
|
||||
case OpCode::Id::FADD_R: {
|
||||
SetDest(0, dest, op_a + " + " + op_b, 1, 1);
|
||||
case OpCode::Id::FADD_R:
|
||||
case OpCode::Id::FADD_IMM: {
|
||||
SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::MUFU: {
|
||||
switch (instr.sub_op) {
|
||||
case SubOp::Cos:
|
||||
SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Sin:
|
||||
SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Ex2:
|
||||
SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Lg2:
|
||||
SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Rcp:
|
||||
SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Rsq:
|
||||
SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Min:
|
||||
SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {}",
|
||||
static_cast<unsigned>(instr.sub_op.Value()));
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: 0x%02x (%s): 0x%08x",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
|
||||
throw DecompileFail("Unhandled instruction");
|
||||
break;
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::Ffma: {
|
||||
ASSERT_MSG(!instr.ffma.negate_b, "untested");
|
||||
ASSERT_MSG(!instr.ffma.negate_c, "untested");
|
||||
|
||||
std::string dest = GetRegister(instr.gpr0);
|
||||
std::string op_a = GetRegister(instr.gpr8);
|
||||
|
||||
std::string op_b = instr.ffma.negate_b ? "-" : "";
|
||||
op_b += GetUniform(instr.uniform);
|
||||
|
||||
std::string op_c = instr.ffma.negate_c ? "-" : "";
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
|
||||
switch (instr.opcode.EffectiveOpCode()) {
|
||||
case OpCode::Id::FFMA_CR: {
|
||||
SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
|
||||
op_b += GetUniform(instr.uniform);
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FFMA_RR: {
|
||||
op_b += GetRegister(instr.gpr20);
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FFMA_RC: {
|
||||
op_b += GetRegister(instr.gpr39);
|
||||
op_c += GetUniform(instr.uniform);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FFMA_IMM: {
|
||||
op_b += GetImmediate(instr);
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled arithmetic FFMA instruction: 0x%02x (%s): 0x%08x",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
|
||||
throw DecompileFail("Unhandled instruction");
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::Memory: {
|
||||
@@ -315,22 +385,33 @@ private:
|
||||
|
||||
switch (instr.opcode.EffectiveOpCode()) {
|
||||
case OpCode::Id::LD_A: {
|
||||
ASSERT(instr.attribute.fmt20.size == 0);
|
||||
ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
|
||||
SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::ST_A: {
|
||||
ASSERT(instr.attribute.fmt20.size == 0);
|
||||
ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
|
||||
SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: 0x%02x (%s): 0x%08x",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
|
||||
throw DecompileFail("Unhandled instruction");
|
||||
case OpCode::Id::TEXS: {
|
||||
ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
|
||||
const std::string op_a = GetRegister(instr.gpr8);
|
||||
const std::string op_b = GetRegister(instr.gpr20);
|
||||
const std::string sampler = GetSampler(instr.sampler);
|
||||
const std::string coord = "vec2(" + op_a + ", " + op_b + ")";
|
||||
const std::string texture = "texture(" + sampler + ", " + coord + ")";
|
||||
for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
|
||||
SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -342,14 +423,18 @@ private:
|
||||
offset = PROGRAM_END - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
|
||||
throw DecompileFail("Unhandled instruction");
|
||||
case OpCode::Id::IPA: {
|
||||
const auto& attribute = instr.attribute.fmt28;
|
||||
std::string dest = GetRegister(instr.gpr0);
|
||||
SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -514,7 +599,7 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code,
|
||||
GLSLGenerator generator(subroutines, program_code, main_offset, stage);
|
||||
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
|
||||
} catch (const DecompileFail& exception) {
|
||||
LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", exception.what());
|
||||
NGLOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
@@ -27,10 +27,13 @@ out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
out vec4 position;
|
||||
|
||||
void main() {
|
||||
exec_shader();
|
||||
}
|
||||
|
||||
gl_Position = position;
|
||||
}
|
||||
)";
|
||||
out += program.first;
|
||||
return {out, program.second};
|
||||
@@ -46,6 +49,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo
|
||||
.get_value_or({});
|
||||
out += R"(
|
||||
|
||||
in vec4 position;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D tex[32];
|
||||
|
||||
@@ -86,8 +86,15 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) {
|
||||
|
||||
inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
|
||||
switch (wrap_mode) {
|
||||
case Tegra::Texture::WrapMode::Wrap:
|
||||
return GL_REPEAT;
|
||||
case Tegra::Texture::WrapMode::ClampToEdge:
|
||||
return GL_CLAMP_TO_EDGE;
|
||||
case Tegra::Texture::WrapMode::ClampOGL:
|
||||
// TODO(Subv): GL_CLAMP was removed as of OpenGL 3.1, to implement GL_CLAMP, we can use
|
||||
// GL_CLAMP_TO_BORDER to get the border color of the texture, and then sample the edge to
|
||||
// manually mix them. However the shader part of this is not yet implemented.
|
||||
return GL_CLAMP_TO_BORDER;
|
||||
}
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}",
|
||||
static_cast<u32>(wrap_mode));
|
||||
|
||||
Reference in New Issue
Block a user