Compare commits
32 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4e68bbb32 | ||
|
|
932fbd5a25 | ||
|
|
7d544c1b9d | ||
|
|
f7a1827aaa | ||
|
|
7c4fb09a7c | ||
|
|
d01bf170c4 | ||
|
|
e23543918b | ||
|
|
69a9bd8187 | ||
|
|
e65966bcfc | ||
|
|
67ff974387 | ||
|
|
b6b78203cc | ||
|
|
0d673a84b6 | ||
|
|
54c2a4cafc | ||
|
|
69b3f98d3a | ||
|
|
d57e00801d | ||
|
|
c9ac23683b | ||
|
|
74eb16521f | ||
|
|
8a5e6fce07 | ||
|
|
0368260c99 | ||
|
|
377c60645c | ||
|
|
54e74b3572 | ||
|
|
da6d4cde56 | ||
|
|
17d8e25cbf | ||
|
|
cfbae58b2b | ||
|
|
4dcdd3a837 | ||
|
|
3fa2b218ac | ||
|
|
fe2609cb77 | ||
|
|
c3becdbca7 | ||
|
|
60fecee1ec | ||
|
|
9359655712 | ||
|
|
af42320021 | ||
|
|
0080a8da58 |
@@ -377,7 +377,7 @@ if (CLANG_FORMAT)
|
||||
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
|
||||
if (WIN32)
|
||||
add_custom_target(clang-format
|
||||
COMMAND powershell.exe -Command "${CLANG_FORMAT} -i @(Get-ChildItem -Recurse ${SRCS}/* -Include \'*.h\', \'*.cpp\')"
|
||||
COMMAND powershell.exe -Command "Get-ChildItem ${SRCS}/* -Include *.cpp,*.h -Recurse | Foreach {${CLANG_FORMAT} -i $_.fullname}"
|
||||
COMMENT ${CCOMMENT})
|
||||
elseif(MINGW)
|
||||
add_custom_target(clang-format
|
||||
|
||||
2390
externals/glad/include/glad/glad.h
vendored
2390
externals/glad/include/glad/glad.h
vendored
File diff suppressed because one or more lines are too long
2549
externals/glad/src/glad.c
vendored
2549
externals/glad/src/glad.c
vendored
File diff suppressed because one or more lines are too long
@@ -41,6 +41,13 @@ __declspec(noinline, noreturn)
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define UNIMPLEMENTED_IF_MSG(_a_, ...) \
|
||||
do \
|
||||
if (!(_a_)) { \
|
||||
LOG_CRITICAL(Debug, "Unimplemented Code:\n" __VA_ARGS__); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!")
|
||||
#define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
|
||||
|
||||
@@ -52,8 +59,7 @@ __declspec(noinline, noreturn)
|
||||
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
|
||||
#endif
|
||||
|
||||
#define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!")
|
||||
#define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
|
||||
#define UNIMPLEMENTED() UNIMPLEMENTED_IF_MSG(false, "Unimplemented code!")
|
||||
#define UNIMPLEMENTED_MSG(...) UNIMPLEMENTED_IF_MSG(false, __VA_ARGS__)
|
||||
|
||||
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
|
||||
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
|
||||
#define UNIMPLEMENTED_IF(cond) UNIMPLEMENTED_IF_MSG(!(cond), "Unimplemented code!")
|
||||
|
||||
@@ -26,6 +26,11 @@ namespace FileSys {
|
||||
constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
|
||||
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
|
||||
|
||||
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
|
||||
"main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
|
||||
"subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
|
||||
};
|
||||
|
||||
struct NSOBuildHeader {
|
||||
u32_le magic;
|
||||
INSERT_PADDING_BYTES(0x3C);
|
||||
@@ -57,6 +62,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
if (exefs == nullptr)
|
||||
return exefs;
|
||||
|
||||
if (Settings::values.dump_exefs) {
|
||||
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
|
||||
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
|
||||
if (dump_dir != nullptr) {
|
||||
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
|
||||
VfsRawCopyD(exefs, exefs_dir);
|
||||
}
|
||||
}
|
||||
|
||||
const auto installed = Service::FileSystem::GetUnionContents();
|
||||
|
||||
// Game Updates
|
||||
@@ -70,6 +84,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
exefs = update->GetExeFS();
|
||||
}
|
||||
|
||||
// LayeredExeFS
|
||||
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
|
||||
if (load_dir != nullptr && load_dir->GetSize() > 0) {
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(
|
||||
patch_dirs.begin(), patch_dirs.end(),
|
||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
||||
|
||||
std::vector<VirtualDir> layers;
|
||||
layers.reserve(patch_dirs.size() + 1);
|
||||
for (const auto& subdir : patch_dirs) {
|
||||
auto exefs_dir = subdir->GetSubdirectory("exefs");
|
||||
if (exefs_dir != nullptr)
|
||||
layers.push_back(std::move(exefs_dir));
|
||||
}
|
||||
layers.push_back(exefs);
|
||||
|
||||
auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
|
||||
if (layered != nullptr) {
|
||||
LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
|
||||
exefs = std::move(layered);
|
||||
}
|
||||
}
|
||||
|
||||
return exefs;
|
||||
}
|
||||
|
||||
@@ -314,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
|
||||
if (IsDirValidAndNonEmpty(exefs_dir)) {
|
||||
bool ips = false;
|
||||
bool ipswitch = false;
|
||||
bool layeredfs = false;
|
||||
|
||||
for (const auto& file : exefs_dir->GetFiles()) {
|
||||
if (file->GetExtension() == "ips")
|
||||
if (file->GetExtension() == "ips") {
|
||||
ips = true;
|
||||
else if (file->GetExtension() == "pchtxt")
|
||||
} else if (file->GetExtension() == "pchtxt") {
|
||||
ipswitch = true;
|
||||
} else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(),
|
||||
file->GetName()) != EXEFS_FILE_NAMES.end()) {
|
||||
layeredfs = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ips)
|
||||
AppendCommaIfNotEmpty(types, "IPS");
|
||||
if (ipswitch)
|
||||
AppendCommaIfNotEmpty(types, "IPSwitch");
|
||||
if (layeredfs)
|
||||
AppendCommaIfNotEmpty(types, "LayeredExeFS");
|
||||
}
|
||||
if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
|
||||
AppendCommaIfNotEmpty(types, "LayeredFS");
|
||||
|
||||
@@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33;
|
||||
constexpr u32 UC_ARM64_REG_Q0 = 34;
|
||||
constexpr u32 FPCR_REGISTER = 66;
|
||||
|
||||
// TODO/WiP - Used while working on support for FPU
|
||||
constexpr u32 TODO_DUMMY_REG_997 = 997;
|
||||
constexpr u32 TODO_DUMMY_REG_998 = 998;
|
||||
|
||||
// For sample XML files see the GDB source /gdb/features
|
||||
// GDB also wants the l character at the start
|
||||
// This XML defines what the registers are for this specific ARM device
|
||||
@@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
|
||||
}
|
||||
}
|
||||
|
||||
static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) {
|
||||
if (!thread) {
|
||||
return u128{0};
|
||||
}
|
||||
|
||||
auto& thread_context = thread->GetContext();
|
||||
|
||||
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
return thread_context.vector_registers[id - UC_ARM64_REG_Q0];
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
return u128{thread_context.fpcr, 0};
|
||||
} else {
|
||||
return u128{0};
|
||||
}
|
||||
}
|
||||
|
||||
static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) {
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& thread_context = thread->GetContext();
|
||||
|
||||
if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
thread_context.fpcr = val[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns hex string character into the equivalent byte.
|
||||
*
|
||||
@@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) {
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a gdb-formatted hex string into a u128.
|
||||
*
|
||||
* @param src Pointer to hex string.
|
||||
*/
|
||||
static u128 GdbHexToU128(const u8* src) {
|
||||
u128 output;
|
||||
|
||||
for (int i = 0; i < 16; i += 2) {
|
||||
output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]);
|
||||
output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i += 2) {
|
||||
output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]);
|
||||
output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Read a byte from the gdb client.
|
||||
static u8 ReadByte() {
|
||||
u8 c;
|
||||
@@ -599,8 +646,7 @@ static void HandleQuery() {
|
||||
for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
|
||||
const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
|
||||
for (const auto& thread : threads) {
|
||||
val += fmt::format("{:x}", thread->GetThreadID());
|
||||
val += ",";
|
||||
val += fmt::format("{:x},", thread->GetThreadID());
|
||||
}
|
||||
}
|
||||
val.pop_back();
|
||||
@@ -791,11 +837,15 @@ static void ReadRegister() {
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(id, current_thread));
|
||||
u128 r = FpuRead(id, current_thread);
|
||||
LongToGdbHex(reply, r[0]);
|
||||
LongToGdbHex(reply + 16, r[1]);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread));
|
||||
} else {
|
||||
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread));
|
||||
u128 r = FpuRead(id, current_thread);
|
||||
IntToGdbHex(reply, static_cast<u32>(r[0]));
|
||||
} else if (id == FPCR_REGISTER + 1) {
|
||||
u128 r = FpuRead(id, current_thread);
|
||||
IntToGdbHex(reply, static_cast<u32>(r[0] >> 32));
|
||||
}
|
||||
|
||||
SendReply(reinterpret_cast<char*>(reply));
|
||||
@@ -822,13 +872,18 @@ static void ReadRegisters() {
|
||||
|
||||
bufptr += 8;
|
||||
|
||||
for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) {
|
||||
LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
|
||||
u128 r;
|
||||
|
||||
for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) {
|
||||
r = FpuRead(reg, current_thread);
|
||||
LongToGdbHex(bufptr + reg * 32, r[0]);
|
||||
LongToGdbHex(bufptr + reg * 32 + 16, r[1]);
|
||||
}
|
||||
|
||||
bufptr += 32 * 32;
|
||||
|
||||
LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread));
|
||||
r = FpuRead(FPCR_REGISTER, current_thread);
|
||||
IntToGdbHex(bufptr, static_cast<u32>(r[0]));
|
||||
|
||||
bufptr += 8;
|
||||
|
||||
@@ -853,14 +908,12 @@ static void WriteRegister() {
|
||||
} else if (id == PSTATE_REGISTER) {
|
||||
RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
|
||||
} else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
|
||||
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
|
||||
FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread);
|
||||
} else if (id == FPCR_REGISTER) {
|
||||
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else {
|
||||
RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
|
||||
} else if (id == FPCR_REGISTER + 1) {
|
||||
}
|
||||
|
||||
// Update Unicorn context skipping scheduler, no running threads at this point
|
||||
// Update ARM context, skipping scheduler - no running threads at this point
|
||||
Core::System::GetInstance()
|
||||
.ArmInterface(current_core)
|
||||
.LoadContext(current_thread->GetContext());
|
||||
@@ -885,13 +938,13 @@ static void WriteRegisters() {
|
||||
} else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
|
||||
RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == FPCR_REGISTER) {
|
||||
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
} else if (reg == FPCR_REGISTER + 1) {
|
||||
RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
// Update Unicorn context skipping scheduler, no running threads at this point
|
||||
// Update ARM context, skipping scheduler - no running threads at this point
|
||||
Core::System::GetInstance()
|
||||
.ArmInterface(current_core)
|
||||
.LoadContext(current_thread->GetContext());
|
||||
@@ -917,12 +970,6 @@ static void ReadMemory() {
|
||||
SendReply("E01");
|
||||
}
|
||||
|
||||
const auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||
if (addr < vm_manager.GetCodeRegionBaseAddress() ||
|
||||
addr >= vm_manager.GetMapRegionEndAddress()) {
|
||||
return SendReply("E00");
|
||||
}
|
||||
|
||||
if (!Memory::IsValidVirtualAddress(addr)) {
|
||||
return SendReply("E00");
|
||||
}
|
||||
@@ -967,7 +1014,7 @@ void Break(bool is_memory_break) {
|
||||
static void Step() {
|
||||
if (command_length > 1) {
|
||||
RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
|
||||
// Update Unicorn context skipping scheduler, no running threads at this point
|
||||
// Update ARM context, skipping scheduler - no running threads at this point
|
||||
Core::System::GetInstance()
|
||||
.ArmInterface(current_core)
|
||||
.LoadContext(current_thread->GetContext());
|
||||
@@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
|
||||
breakpoint.addr = addr;
|
||||
breakpoint.len = len;
|
||||
Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
|
||||
static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}};
|
||||
static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
|
||||
Memory::WriteBlock(addr, btrap.data(), btrap.size());
|
||||
Core::System::GetInstance().InvalidateCpuInstructionCaches();
|
||||
p.insert({addr, breakpoint});
|
||||
@@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool is_step) {
|
||||
}
|
||||
|
||||
void SendTrap(Kernel::Thread* thread, int trap) {
|
||||
if (send_trap) {
|
||||
if (!halt_loop || current_thread == thread) {
|
||||
current_thread = thread;
|
||||
SendSignal(thread, trap);
|
||||
}
|
||||
halt_loop = true;
|
||||
send_trap = false;
|
||||
if (!send_trap) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!halt_loop || current_thread == thread) {
|
||||
current_thread = thread;
|
||||
SendSignal(thread, trap);
|
||||
}
|
||||
halt_loop = true;
|
||||
send_trap = false;
|
||||
}
|
||||
}; // namespace GDBStub
|
||||
|
||||
@@ -483,11 +483,15 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
@@ -341,6 +341,10 @@ std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
|
||||
return registered_cache_union;
|
||||
}
|
||||
|
||||
void ClearUnionContents() {
|
||||
registered_cache_union = nullptr;
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents() {
|
||||
LOG_TRACE(Service_FS, "Opening System NAND Contents");
|
||||
|
||||
@@ -391,6 +395,7 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
|
||||
bis_factory = nullptr;
|
||||
save_data_factory = nullptr;
|
||||
sdmc_factory = nullptr;
|
||||
ClearUnionContents();
|
||||
}
|
||||
|
||||
auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
|
||||
|
||||
@@ -49,6 +49,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC();
|
||||
|
||||
std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
|
||||
void ClearUnionContents();
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents();
|
||||
FileSys::RegisteredCache* GetUserNANDContents();
|
||||
|
||||
@@ -88,6 +88,20 @@ void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
|
||||
// According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
|
||||
// retail hardware.
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||
: ServiceFramework(name), nvdrv(std::move(nvdrv)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
@@ -97,10 +111,10 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||
{3, &NVDRV::Initialize, "Initialize"},
|
||||
{4, &NVDRV::QueryEvent, "QueryEvent"},
|
||||
{5, nullptr, "MapSharedMem"},
|
||||
{6, nullptr, "GetStatus"},
|
||||
{6, &NVDRV::GetStatus, "GetStatus"},
|
||||
{7, nullptr, "ForceSetClientPID"},
|
||||
{8, &NVDRV::SetClientPID, "SetClientPID"},
|
||||
{9, nullptr, "DumpGraphicsMemoryInfo"},
|
||||
{9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
|
||||
{10, nullptr, "InitializeDevtools"},
|
||||
{11, &NVDRV::Ioctl, "Ioctl2"},
|
||||
{12, nullptr, "Ioctl3"},
|
||||
|
||||
@@ -24,6 +24,8 @@ private:
|
||||
void QueryEvent(Kernel::HLERequestContext& ctx);
|
||||
void SetClientPID(Kernel::HLERequestContext& ctx);
|
||||
void FinishInitialize(Kernel::HLERequestContext& ctx);
|
||||
void GetStatus(Kernel::HLERequestContext& ctx);
|
||||
void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Module> nvdrv;
|
||||
|
||||
|
||||
@@ -63,6 +63,17 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
|
||||
return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
|
||||
}
|
||||
|
||||
ResultCode ServiceManager::UnregisterService(std::string name) {
|
||||
CASCADE_CODE(ValidateServiceName(name));
|
||||
|
||||
const auto iter = registered_services.find(name);
|
||||
if (iter == registered_services.end())
|
||||
return ERR_SERVICE_NOT_REGISTERED;
|
||||
|
||||
registered_services.erase(iter);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
|
||||
const std::string& name) {
|
||||
|
||||
@@ -127,13 +138,52 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
void SM::RegisterService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto name_buf = rp.PopRaw<std::array<char, 8>>();
|
||||
const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
|
||||
const std::string name(name_buf.begin(), end);
|
||||
|
||||
const auto unk_bool = static_cast<bool>(rp.PopRaw<u32>());
|
||||
const auto session_count = rp.PopRaw<u32>();
|
||||
|
||||
LOG_DEBUG(Service_SM, "called with unk_bool={}", unk_bool);
|
||||
|
||||
auto handle = service_manager->RegisterService(name, session_count);
|
||||
if (handle.Failed()) {
|
||||
LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
|
||||
handle.Code().raw);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(handle.Code());
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(handle.Code());
|
||||
rb.PushMoveObjects(std::move(handle).Unwrap());
|
||||
}
|
||||
|
||||
void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto name_buf = rp.PopRaw<std::array<char, 8>>();
|
||||
const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
|
||||
|
||||
const std::string name(name_buf.begin(), end);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(service_manager->UnregisterService(name));
|
||||
}
|
||||
|
||||
SM::SM(std::shared_ptr<ServiceManager> service_manager)
|
||||
: ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0x00000000, &SM::Initialize, "Initialize"},
|
||||
{0x00000001, &SM::GetService, "GetService"},
|
||||
{0x00000002, nullptr, "RegisterService"},
|
||||
{0x00000003, nullptr, "UnregisterService"},
|
||||
{0x00000002, &SM::RegisterService, "RegisterService"},
|
||||
{0x00000003, &SM::UnregisterService, "UnregisterService"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ public:
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx);
|
||||
void GetService(Kernel::HLERequestContext& ctx);
|
||||
void RegisterService(Kernel::HLERequestContext& ctx);
|
||||
void UnregisterService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<ServiceManager> service_manager;
|
||||
};
|
||||
@@ -48,6 +50,7 @@ public:
|
||||
|
||||
ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
|
||||
unsigned int max_sessions);
|
||||
ResultCode UnregisterService(std::string name);
|
||||
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
|
||||
ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
|
||||
|
||||
|
||||
@@ -510,7 +510,11 @@ private:
|
||||
|
||||
if (transaction == TransactionId::Connect) {
|
||||
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
|
||||
IGBPConnectResponseParcel response{1280, 720};
|
||||
IGBPConnectResponseParcel response{
|
||||
static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
|
||||
Settings::values.resolution_factor),
|
||||
static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
|
||||
Settings::values.resolution_factor)};
|
||||
ctx.WriteBuffer(response.Serialize());
|
||||
} else if (transaction == TransactionId::SetPreallocatedBuffer) {
|
||||
IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
|
||||
@@ -692,11 +696,15 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
|
||||
rb.PushRaw<float>(60.0f);
|
||||
@@ -901,11 +909,15 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
if (Settings::values.use_docked_mode) {
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedWidth));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedHeight));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
} else {
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
|
||||
static_cast<u32>(Settings::values.resolution_factor));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -922,6 +934,8 @@ private:
|
||||
void ListDisplays(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
DisplayInfo display_info;
|
||||
display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
|
||||
display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
|
||||
ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -403,6 +403,7 @@ struct Values {
|
||||
bool use_gdbstub;
|
||||
u16 gdbstub_port;
|
||||
std::string program_args;
|
||||
bool dump_exefs;
|
||||
bool dump_nso;
|
||||
|
||||
// WebService
|
||||
|
||||
@@ -631,7 +631,16 @@ public:
|
||||
}
|
||||
} zeta;
|
||||
|
||||
INSERT_PADDING_WORDS(0x5B);
|
||||
INSERT_PADDING_WORDS(0x41);
|
||||
|
||||
union {
|
||||
BitField<0, 4, u32> stencil;
|
||||
BitField<4, 4, u32> unknown;
|
||||
BitField<8, 4, u32> scissor;
|
||||
BitField<12, 4, u32> viewport;
|
||||
} clear_flags;
|
||||
|
||||
INSERT_PADDING_WORDS(0x19);
|
||||
|
||||
std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format;
|
||||
|
||||
@@ -1134,6 +1143,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
|
||||
ASSERT_REG_POSITION(color_mask_common, 0x3E4);
|
||||
ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
|
||||
ASSERT_REG_POSITION(zeta, 0x3F8);
|
||||
ASSERT_REG_POSITION(clear_flags, 0x43E);
|
||||
ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
|
||||
ASSERT_REG_POSITION(rt_control, 0x487);
|
||||
ASSERT_REG_POSITION(zeta_width, 0x48a);
|
||||
|
||||
@@ -262,7 +262,7 @@ enum class FlowCondition : u64 {
|
||||
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
|
||||
};
|
||||
|
||||
enum class ControlCode : u64 {
|
||||
enum class ConditionCode : u64 {
|
||||
F = 0,
|
||||
LT = 1,
|
||||
EQ = 2,
|
||||
@@ -570,7 +570,6 @@ union Instruction {
|
||||
BitField<39, 2, u64> tab5cb8_2;
|
||||
BitField<41, 3, u64> tab5c68_1;
|
||||
BitField<44, 2, u64> tab5c68_0;
|
||||
BitField<47, 1, u64> cc;
|
||||
BitField<48, 1, u64> negate_b;
|
||||
} fmul;
|
||||
|
||||
@@ -832,7 +831,7 @@ union Instruction {
|
||||
union {
|
||||
BitField<0, 3, u64> pred0;
|
||||
BitField<3, 3, u64> pred3;
|
||||
BitField<8, 5, ControlCode> cc; // flag in cc
|
||||
BitField<8, 5, ConditionCode> cc; // flag in cc
|
||||
BitField<39, 3, u64> pred39;
|
||||
BitField<42, 1, u64> neg_pred39;
|
||||
BitField<45, 4, PredOperation> op; // op with pred39
|
||||
@@ -1236,7 +1235,7 @@ union Instruction {
|
||||
BitField<60, 1, u64> is_b_gpr;
|
||||
BitField<59, 1, u64> is_c_gpr;
|
||||
BitField<20, 24, s64> smem_imm;
|
||||
BitField<0, 5, ControlCode> flow_control_code;
|
||||
BitField<0, 5, ConditionCode> flow_condition_code;
|
||||
|
||||
Attribute attribute;
|
||||
Sampler sampler;
|
||||
|
||||
@@ -98,14 +98,9 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
|
||||
has_ARB_direct_state_access = true;
|
||||
} else if (extension == "GL_ARB_multi_bind") {
|
||||
has_ARB_multi_bind = true;
|
||||
} else if (extension == "GL_ARB_separate_shader_objects") {
|
||||
has_ARB_separate_shader_objects = true;
|
||||
} else if (extension == "GL_ARB_vertex_attrib_binding") {
|
||||
has_ARB_vertex_attrib_binding = true;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
|
||||
OpenGLState::ApplyDefaultState();
|
||||
|
||||
// Create render framebuffer
|
||||
@@ -542,6 +537,30 @@ void RasterizerOpenGL::Clear() {
|
||||
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
|
||||
use_stencil = true;
|
||||
clear_state.stencil.test_enabled = true;
|
||||
if (regs.clear_flags.stencil) {
|
||||
// Stencil affects the clear so fill it with the used masks
|
||||
clear_state.stencil.front.test_func = GL_ALWAYS;
|
||||
clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
|
||||
clear_state.stencil.front.action_stencil_fail = GL_KEEP;
|
||||
clear_state.stencil.front.action_depth_fail = GL_KEEP;
|
||||
clear_state.stencil.front.action_depth_pass = GL_KEEP;
|
||||
clear_state.stencil.front.write_mask = regs.stencil_front_mask;
|
||||
if (regs.stencil_two_side_enable) {
|
||||
clear_state.stencil.back.test_func = GL_ALWAYS;
|
||||
clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
|
||||
clear_state.stencil.back.action_stencil_fail = GL_KEEP;
|
||||
clear_state.stencil.back.action_depth_fail = GL_KEEP;
|
||||
clear_state.stencil.back.action_depth_pass = GL_KEEP;
|
||||
clear_state.stencil.back.write_mask = regs.stencil_back_mask;
|
||||
} else {
|
||||
clear_state.stencil.back.test_func = GL_ALWAYS;
|
||||
clear_state.stencil.back.test_mask = 0xFFFFFFFF;
|
||||
clear_state.stencil.back.write_mask = 0xFFFFFFFF;
|
||||
clear_state.stencil.back.action_stencil_fail = GL_KEEP;
|
||||
clear_state.stencil.back.action_depth_fail = GL_KEEP;
|
||||
clear_state.stencil.back.action_depth_pass = GL_KEEP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_color && !use_depth && !use_stencil) {
|
||||
@@ -553,6 +572,14 @@ void RasterizerOpenGL::Clear() {
|
||||
|
||||
ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
|
||||
regs.clear_buffers.RT.Value());
|
||||
if (regs.clear_flags.scissor) {
|
||||
SyncScissorTest(clear_state);
|
||||
}
|
||||
|
||||
if (regs.clear_flags.viewport) {
|
||||
clear_state.EmulateViewportWithScissor();
|
||||
}
|
||||
|
||||
clear_state.Apply();
|
||||
|
||||
if (use_color) {
|
||||
@@ -588,7 +615,7 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
SyncLogicOpState();
|
||||
SyncCullMode();
|
||||
SyncPrimitiveRestart();
|
||||
SyncScissorTest();
|
||||
SyncScissorTest(state);
|
||||
// Alpha Testing is synced on shaders.
|
||||
SyncTransformFeedback();
|
||||
SyncPointState();
|
||||
@@ -815,7 +842,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
|
||||
}
|
||||
const u32 bias = config.mip_lod_bias.Value();
|
||||
// Sign extend the 13-bit value.
|
||||
const u32 mask = 1U << (13 - 1);
|
||||
constexpr u32 mask = 1U << (13 - 1);
|
||||
const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
|
||||
if (lod_bias != bias_lod) {
|
||||
lod_bias = bias_lod;
|
||||
@@ -947,8 +974,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
||||
auto& viewport = current_state.viewports[i];
|
||||
viewport.x = viewport_rect.left;
|
||||
viewport.y = viewport_rect.bottom;
|
||||
viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
|
||||
viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
|
||||
viewport.width = viewport_rect.GetWidth();
|
||||
viewport.height = viewport_rect.GetHeight();
|
||||
viewport.depth_range_far = regs.viewports[i].depth_range_far;
|
||||
viewport.depth_range_near = regs.viewports[i].depth_range_near;
|
||||
}
|
||||
@@ -1120,11 +1147,11 @@ void RasterizerOpenGL::SyncLogicOpState() {
|
||||
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncScissorTest() {
|
||||
void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
|
||||
const auto& src = regs.scissor_test[i];
|
||||
auto& dst = state.viewports[i].scissor;
|
||||
auto& dst = current_state.viewports[i].scissor;
|
||||
dst.enabled = (src.enable != 0);
|
||||
if (dst.enabled == 0) {
|
||||
return;
|
||||
|
||||
@@ -91,19 +91,20 @@ private:
|
||||
void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
|
||||
|
||||
private:
|
||||
Tegra::Texture::TextureFilter mag_filter;
|
||||
Tegra::Texture::TextureFilter min_filter;
|
||||
Tegra::Texture::TextureMipmapFilter mip_filter;
|
||||
Tegra::Texture::WrapMode wrap_u;
|
||||
Tegra::Texture::WrapMode wrap_v;
|
||||
Tegra::Texture::WrapMode wrap_p;
|
||||
bool uses_depth_compare;
|
||||
Tegra::Texture::DepthCompareFunc depth_compare_func;
|
||||
GLvec4 border_color;
|
||||
float min_lod;
|
||||
float max_lod;
|
||||
float lod_bias;
|
||||
float max_anisotropic;
|
||||
Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest;
|
||||
Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest;
|
||||
Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None;
|
||||
Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge;
|
||||
Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge;
|
||||
Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge;
|
||||
bool uses_depth_compare = false;
|
||||
Tegra::Texture::DepthCompareFunc depth_compare_func =
|
||||
Tegra::Texture::DepthCompareFunc::Always;
|
||||
GLvec4 border_color = {};
|
||||
float min_lod = 0.0f;
|
||||
float max_lod = 16.0f;
|
||||
float lod_bias = 0.0f;
|
||||
float max_anisotropic = 1.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -171,7 +172,7 @@ private:
|
||||
void SyncMultiSampleState();
|
||||
|
||||
/// Syncs the scissor test state to match the guest state
|
||||
void SyncScissorTest();
|
||||
void SyncScissorTest(OpenGLState& current_state);
|
||||
|
||||
/// Syncs the transform feedback state to match the guest state
|
||||
void SyncTransformFeedback();
|
||||
@@ -187,8 +188,6 @@ private:
|
||||
|
||||
bool has_ARB_direct_state_access = false;
|
||||
bool has_ARB_multi_bind = false;
|
||||
bool has_ARB_separate_shader_objects = false;
|
||||
bool has_ARB_vertex_attrib_binding = false;
|
||||
|
||||
OpenGLState state;
|
||||
|
||||
|
||||
@@ -265,11 +265,11 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
|
||||
{GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // DXN2UNORM
|
||||
{GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM
|
||||
{GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
{GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // BC7U
|
||||
{GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8,
|
||||
ComponentType::Float, true}, // BC6H_UF16
|
||||
{GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
|
||||
{GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
|
||||
true}, // BC6H_UF16
|
||||
{GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
|
||||
true}, // BC6H_SF16
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
|
||||
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
|
||||
@@ -306,8 +306,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
|
||||
true}, // DXT23_SRGB
|
||||
{GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // DXT45_SRGB
|
||||
{GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
|
||||
ComponentType::UNorm, true}, // BC7U_SRGB
|
||||
{GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
|
||||
true}, // BC7U_SRGB
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
|
||||
@@ -346,7 +346,7 @@ static GLenum SurfaceTargetToGL(SurfaceTarget target) {
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
return GL_TEXTURE_CUBE_MAP;
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
return GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
|
||||
return GL_TEXTURE_CUBE_MAP_ARRAY;
|
||||
}
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
|
||||
UNREACHABLE();
|
||||
@@ -726,7 +726,7 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes);
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW);
|
||||
if (source_format.compressed) {
|
||||
glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment,
|
||||
static_cast<GLsizei>(src_params.size_in_bytes), nullptr);
|
||||
|
||||
@@ -84,6 +84,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
|
||||
}
|
||||
|
||||
entries = program_result.second;
|
||||
shader_length = entries.shader_length;
|
||||
|
||||
if (program_type != Maxwell::ShaderProgram::Geometry) {
|
||||
OGLShader shader;
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
}
|
||||
|
||||
std::size_t GetSizeInBytes() const override {
|
||||
return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64);
|
||||
return shader_length;
|
||||
}
|
||||
|
||||
// We do not have to flush this cache as things in it are never modified by us.
|
||||
@@ -82,6 +82,7 @@ private:
|
||||
u32 max_vertices, const std::string& debug_name);
|
||||
|
||||
VAddr addr;
|
||||
std::size_t shader_length;
|
||||
Maxwell::ShaderProgram program_type;
|
||||
GLShader::ShaderSetup setup;
|
||||
GLShader::ShaderEntries entries;
|
||||
|
||||
@@ -34,6 +34,17 @@ constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header);
|
||||
constexpr u32 MAX_GEOMETRY_BUFFERS = 6;
|
||||
constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested
|
||||
|
||||
static const char* INTERNAL_FLAG_NAMES[] = {"zero_flag", "sign_flag", "carry_flag",
|
||||
"overflow_flag"};
|
||||
|
||||
enum class InternalFlag : u64 {
|
||||
ZeroFlag = 0,
|
||||
SignFlag = 1,
|
||||
CarryFlag = 2,
|
||||
OverflowFlag = 3,
|
||||
Amount
|
||||
};
|
||||
|
||||
class DecompileFail : public std::runtime_error {
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
@@ -84,7 +95,8 @@ struct Subroutine {
|
||||
class ControlFlowAnalyzer {
|
||||
public:
|
||||
ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix)
|
||||
: program_code(program_code) {
|
||||
: program_code(program_code), shader_coverage_begin(main_offset),
|
||||
shader_coverage_end(main_offset + 1) {
|
||||
|
||||
// Recursively finds all subroutines.
|
||||
const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix);
|
||||
@@ -96,10 +108,16 @@ public:
|
||||
return std::move(subroutines);
|
||||
}
|
||||
|
||||
std::size_t GetShaderLength() const {
|
||||
return shader_coverage_end * sizeof(u64);
|
||||
}
|
||||
|
||||
private:
|
||||
const ProgramCode& program_code;
|
||||
std::set<Subroutine> subroutines;
|
||||
std::map<std::pair<u32, u32>, ExitMethod> exit_method_map;
|
||||
u32 shader_coverage_begin;
|
||||
u32 shader_coverage_end;
|
||||
|
||||
/// Adds and analyzes a new subroutine if it is not added yet.
|
||||
const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) {
|
||||
@@ -141,6 +159,9 @@ private:
|
||||
return exit_method;
|
||||
|
||||
for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
|
||||
shader_coverage_begin = std::min(shader_coverage_begin, offset);
|
||||
shader_coverage_end = std::max(shader_coverage_end, offset + 1);
|
||||
|
||||
const Instruction instr = {program_code[offset]};
|
||||
if (const auto opcode = OpCode::Decode(instr)) {
|
||||
switch (opcode->get().GetId()) {
|
||||
@@ -257,14 +278,6 @@ private:
|
||||
const std::string& suffix;
|
||||
};
|
||||
|
||||
enum class InternalFlag : u64 {
|
||||
ZeroFlag = 0,
|
||||
CarryFlag = 1,
|
||||
OverflowFlag = 2,
|
||||
NaNFlag = 3,
|
||||
Amount
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
|
||||
* of all registers (e.g. whether they are currently being used as Floats or Integers), and
|
||||
@@ -371,7 +384,7 @@ public:
|
||||
if (sets_cc) {
|
||||
const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
|
||||
SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
|
||||
LOG_WARNING(HW_GPU, "Control Codes Imcomplete.");
|
||||
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,23 +467,25 @@ public:
|
||||
shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");");
|
||||
}
|
||||
|
||||
std::string GetControlCode(const Tegra::Shader::ControlCode cc) const {
|
||||
std::string GetConditionCode(const Tegra::Shader::ConditionCode cc) const {
|
||||
switch (cc) {
|
||||
case Tegra::Shader::ControlCode::NEU:
|
||||
case Tegra::Shader::ConditionCode::NEU:
|
||||
return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented Control Code: {}", static_cast<u32>(cc));
|
||||
UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetInternalFlag(const InternalFlag ii) const {
|
||||
const u32 code = static_cast<u32>(ii);
|
||||
return "internalFlag_" + std::to_string(code) + suffix;
|
||||
std::string GetInternalFlag(const InternalFlag flag) const {
|
||||
const auto index = static_cast<u32>(flag);
|
||||
ASSERT(index < static_cast<u32>(InternalFlag::Amount));
|
||||
|
||||
return std::string(INTERNAL_FLAG_NAMES[index]) + '_' + suffix;
|
||||
}
|
||||
|
||||
void SetInternalFlag(const InternalFlag ii, const std::string& value) const {
|
||||
shader.AddLine(GetInternalFlag(ii) + " = " + value + ';');
|
||||
void SetInternalFlag(const InternalFlag flag, const std::string& value) const {
|
||||
shader.AddLine(GetInternalFlag(flag) + " = " + value + ';');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -621,8 +636,8 @@ private:
|
||||
|
||||
/// Generates declarations for internal flags.
|
||||
void GenerateInternalFlags() {
|
||||
for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) {
|
||||
const InternalFlag code = static_cast<InternalFlag>(ii);
|
||||
for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
|
||||
const InternalFlag code = static_cast<InternalFlag>(flag);
|
||||
declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
|
||||
}
|
||||
declarations.AddNewLine();
|
||||
@@ -939,9 +954,10 @@ private:
|
||||
class GLSLGenerator {
|
||||
public:
|
||||
GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
|
||||
u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix)
|
||||
u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix,
|
||||
std::size_t shader_length)
|
||||
: subroutines(subroutines), program_code(program_code), main_offset(main_offset),
|
||||
stage(stage), suffix(suffix) {
|
||||
stage(stage), suffix(suffix), shader_length(shader_length) {
|
||||
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
|
||||
local_memory_size = header.GetLocalMemorySize();
|
||||
regs.SetLocalMemory(local_memory_size);
|
||||
@@ -954,7 +970,7 @@ public:
|
||||
|
||||
/// Returns entries in the shader that are useful for external functions
|
||||
ShaderEntries GetEntries() const {
|
||||
return {regs.GetConstBuffersDeclarations(), regs.GetSamplers()};
|
||||
return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length};
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1505,9 +1521,8 @@ private:
|
||||
instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented",
|
||||
instr.fmul.tab5c68_0
|
||||
.Value()); // SMO typical sends 1 here which seems to be the default
|
||||
UNIMPLEMENTED_IF_MSG(instr.fmul.cc != 0, "FMUL cc is not implemented");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"FMUL Generates an unhandled Control Code");
|
||||
"Condition codes generation in FMUL is not implemented");
|
||||
|
||||
op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b);
|
||||
|
||||
@@ -1519,7 +1534,7 @@ private:
|
||||
case OpCode::Id::FADD_R:
|
||||
case OpCode::Id::FADD_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"FADD Generates an unhandled Control Code");
|
||||
"Condition codes generation in FADD is not implemented");
|
||||
|
||||
op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
|
||||
op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
|
||||
@@ -1569,7 +1584,7 @@ private:
|
||||
case OpCode::Id::FMNMX_R:
|
||||
case OpCode::Id::FMNMX_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"FMNMX Generates an unhandled Control Code");
|
||||
"Condition codes generation in FMNMX is not implemented");
|
||||
|
||||
op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
|
||||
op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
|
||||
@@ -1606,7 +1621,7 @@ private:
|
||||
}
|
||||
case OpCode::Id::FMUL32_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
|
||||
"FMUL32 Generates an unhandled Control Code");
|
||||
"Condition codes generation in FMUL32 is not implemented");
|
||||
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0,
|
||||
regs.GetRegisterAsFloat(instr.gpr8) + " * " +
|
||||
@@ -1616,7 +1631,7 @@ private:
|
||||
}
|
||||
case OpCode::Id::FADD32I: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
|
||||
"FADD32 Generates an unhandled Control Code");
|
||||
"Condition codes generation in FADD32I is not implemented");
|
||||
|
||||
std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
std::string op_b = GetImmediate32(instr);
|
||||
@@ -1651,7 +1666,8 @@ private:
|
||||
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::BFE_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "BFE Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in BFE is not implemented");
|
||||
|
||||
std::string inner_shift =
|
||||
'(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')';
|
||||
@@ -1688,7 +1704,8 @@ private:
|
||||
case OpCode::Id::SHR_C:
|
||||
case OpCode::Id::SHR_R:
|
||||
case OpCode::Id::SHR_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHR Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in SHR is not implemented");
|
||||
|
||||
if (!instr.shift.is_signed) {
|
||||
// Logical shift right
|
||||
@@ -1703,8 +1720,8 @@ private:
|
||||
case OpCode::Id::SHL_C:
|
||||
case OpCode::Id::SHL_R:
|
||||
case OpCode::Id::SHL_IMM:
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHL Generates an unhandled Control Code");
|
||||
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in SHL is not implemented");
|
||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
|
||||
break;
|
||||
default: {
|
||||
@@ -1720,7 +1737,7 @@ private:
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::IADD32I:
|
||||
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
|
||||
"IADD32 Generates an unhandled Control Code");
|
||||
"Condition codes generation in IADD32I is not implemented");
|
||||
|
||||
if (instr.iadd32i.negate_a)
|
||||
op_a = "-(" + op_a + ')';
|
||||
@@ -1730,7 +1747,7 @@ private:
|
||||
break;
|
||||
case OpCode::Id::LOP32I: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
|
||||
"LOP32I Generates an unhandled Control Code");
|
||||
"Condition codes generation in LOP32I is not implemented");
|
||||
|
||||
if (instr.alu.lop32i.invert_a)
|
||||
op_a = "~(" + op_a + ')';
|
||||
@@ -1769,7 +1786,7 @@ private:
|
||||
case OpCode::Id::IADD_R:
|
||||
case OpCode::Id::IADD_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"IADD Generates an unhandled Control Code");
|
||||
"Condition codes generation in IADD is not implemented");
|
||||
|
||||
if (instr.alu_integer.negate_a)
|
||||
op_a = "-(" + op_a + ')';
|
||||
@@ -1785,7 +1802,7 @@ private:
|
||||
case OpCode::Id::IADD3_R:
|
||||
case OpCode::Id::IADD3_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"IADD3 Generates an unhandled Control Code");
|
||||
"Condition codes generation in IADD3 is not implemented");
|
||||
|
||||
std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
|
||||
|
||||
@@ -1848,7 +1865,7 @@ private:
|
||||
case OpCode::Id::ISCADD_R:
|
||||
case OpCode::Id::ISCADD_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"ISCADD Generates an unhandled Control Code");
|
||||
"Condition codes generation in ISCADD is not implemented");
|
||||
|
||||
if (instr.alu_integer.negate_a)
|
||||
op_a = "-(" + op_a + ')';
|
||||
@@ -1883,7 +1900,8 @@ private:
|
||||
case OpCode::Id::LOP_C:
|
||||
case OpCode::Id::LOP_R:
|
||||
case OpCode::Id::LOP_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "LOP Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in LOP is not implemented");
|
||||
|
||||
if (instr.alu.lop.invert_a)
|
||||
op_a = "~(" + op_a + ')';
|
||||
@@ -1899,7 +1917,7 @@ private:
|
||||
case OpCode::Id::LOP3_R:
|
||||
case OpCode::Id::LOP3_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"LOP3 Generates an unhandled Control Code");
|
||||
"Condition codes generation in LOP3 is not implemented");
|
||||
|
||||
const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
|
||||
std::string lut;
|
||||
@@ -1918,7 +1936,7 @@ private:
|
||||
case OpCode::Id::IMNMX_IMM: {
|
||||
UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None);
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"IMNMX Generates an unhandled Control Code");
|
||||
"Condition codes generation in IMNMX is not implemented");
|
||||
|
||||
const std::string condition =
|
||||
GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0);
|
||||
@@ -2091,7 +2109,8 @@ private:
|
||||
instr.ffma.tab5980_0.Value()); // Seems to be 1 by default based on SMO
|
||||
UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented",
|
||||
instr.ffma.tab5980_1.Value());
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "FFMA Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in FFMA is not implemented");
|
||||
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::FFMA_CR: {
|
||||
@@ -2201,7 +2220,8 @@ private:
|
||||
case OpCode::Id::I2F_C: {
|
||||
UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
|
||||
UNIMPLEMENTED_IF(instr.conversion.selector);
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "I2F Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in I2F is not implemented");
|
||||
|
||||
std::string op_a{};
|
||||
|
||||
@@ -2231,7 +2251,8 @@ private:
|
||||
case OpCode::Id::F2F_R: {
|
||||
UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
|
||||
UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2F Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in F2F is not implemented");
|
||||
std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
|
||||
|
||||
if (instr.conversion.abs_a) {
|
||||
@@ -2269,7 +2290,8 @@ private:
|
||||
case OpCode::Id::F2I_R:
|
||||
case OpCode::Id::F2I_C: {
|
||||
UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2I Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in F2I is not implemented");
|
||||
std::string op_a{};
|
||||
|
||||
if (instr.is_b_gpr) {
|
||||
@@ -3118,7 +3140,8 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::PredicateSetRegister: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "PSET Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in PSET is not implemented");
|
||||
|
||||
const std::string op_a =
|
||||
GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
|
||||
@@ -3177,14 +3200,14 @@ private:
|
||||
const std::string pred =
|
||||
GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0);
|
||||
const std::string combiner = GetPredicateCombiner(instr.csetp.op);
|
||||
const std::string control_code = regs.GetControlCode(instr.csetp.cc);
|
||||
const std::string condition_code = regs.GetConditionCode(instr.csetp.cc);
|
||||
if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
SetPredicate(instr.csetp.pred3,
|
||||
'(' + control_code + ") " + combiner + " (" + pred + ')');
|
||||
'(' + condition_code + ") " + combiner + " (" + pred + ')');
|
||||
}
|
||||
if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
SetPredicate(instr.csetp.pred0,
|
||||
"!(" + control_code + ") " + combiner + " (" + pred + ')');
|
||||
"!(" + condition_code + ") " + combiner + " (" + pred + ')');
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3315,7 +3338,8 @@ private:
|
||||
case OpCode::Type::Xmad: {
|
||||
UNIMPLEMENTED_IF(instr.xmad.sign_a);
|
||||
UNIMPLEMENTED_IF(instr.xmad.sign_b);
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "XMAD Generates an unhandled Control Code");
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in XMAD is not implemented");
|
||||
|
||||
std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)};
|
||||
std::string op_b;
|
||||
@@ -3407,9 +3431,9 @@ private:
|
||||
default: {
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::EXIT: {
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T,
|
||||
"EXIT Control Code used: {}", static_cast<u32>(cc));
|
||||
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
|
||||
"EXIT condition code used: {}", static_cast<u32>(cc));
|
||||
|
||||
if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
|
||||
EmitFragmentOutputsWrite();
|
||||
@@ -3441,9 +3465,9 @@ private:
|
||||
case OpCode::Id::KIL: {
|
||||
UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always);
|
||||
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T,
|
||||
"KIL Control Code used: {}", static_cast<u32>(cc));
|
||||
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
|
||||
"KIL condition code used: {}", static_cast<u32>(cc));
|
||||
|
||||
// Enclose "discard" in a conditional, so that GLSL compilation does not complain
|
||||
// about unexecuted instructions that may follow this.
|
||||
@@ -3505,9 +3529,9 @@ private:
|
||||
UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
|
||||
"BRA with constant buffers are not implemented");
|
||||
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T,
|
||||
"BRA Control Code used: {}", static_cast<u32>(cc));
|
||||
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
|
||||
"BRA condition code used: {}", static_cast<u32>(cc));
|
||||
|
||||
const u32 target = offset + instr.bra.GetBranchTarget();
|
||||
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
|
||||
@@ -3550,9 +3574,9 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::SYNC: {
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T,
|
||||
"SYNC Control Code used: {}", static_cast<u32>(cc));
|
||||
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
|
||||
"SYNC condition code used: {}", static_cast<u32>(cc));
|
||||
|
||||
// The SYNC opcode jumps to the address previously set by the SSY opcode
|
||||
EmitPopFromFlowStack();
|
||||
@@ -3560,10 +3584,10 @@ private:
|
||||
}
|
||||
case OpCode::Id::BRK: {
|
||||
// The BRK opcode jumps to the address previously set by the PBK opcode
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
if (cc != Tegra::Shader::ControlCode::T) {
|
||||
UNIMPLEMENTED_MSG("BRK Control Code used: {}", static_cast<u32>(cc));
|
||||
}
|
||||
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
|
||||
UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T,
|
||||
"BRK condition code used: {}", static_cast<u32>(cc));
|
||||
|
||||
EmitPopFromFlowStack();
|
||||
break;
|
||||
}
|
||||
@@ -3574,6 +3598,9 @@ private:
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::VMAD: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in VMAD is not implemented");
|
||||
|
||||
const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1;
|
||||
const std::string op_a = GetVideoOperandA(instr);
|
||||
const std::string op_b = GetVideoOperandB(instr);
|
||||
@@ -3593,10 +3620,6 @@ private:
|
||||
regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
|
||||
instr.vmad.saturate == 1, 0, Register::Size::Word,
|
||||
instr.vmad.cc);
|
||||
if (instr.generates_cc) {
|
||||
UNIMPLEMENTED_MSG("VMAD Generates an unhandled Control Code");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::VSETP: {
|
||||
@@ -3748,6 +3771,7 @@ private:
|
||||
Maxwell3D::Regs::ShaderStage stage;
|
||||
const std::string& suffix;
|
||||
u64 local_memory_size;
|
||||
std::size_t shader_length;
|
||||
|
||||
ShaderWriter shader;
|
||||
ShaderWriter declarations;
|
||||
@@ -3766,9 +3790,10 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
|
||||
Maxwell3D::Regs::ShaderStage stage,
|
||||
const std::string& suffix) {
|
||||
try {
|
||||
const auto subroutines =
|
||||
ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
|
||||
GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);
|
||||
ControlFlowAnalyzer analyzer(program_code, main_offset, suffix);
|
||||
const auto subroutines = analyzer.GetSubroutines();
|
||||
GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix,
|
||||
analyzer.GetShaderLength());
|
||||
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
|
||||
} catch (const DecompileFail& exception) {
|
||||
LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
|
||||
|
||||
@@ -163,6 +163,7 @@ private:
|
||||
struct ShaderEntries {
|
||||
std::vector<ConstBufferEntry> const_buffer_entries;
|
||||
std::vector<SamplerEntry> texture_samplers;
|
||||
std::size_t shader_length;
|
||||
};
|
||||
|
||||
using ProgramResult = std::pair<std::string, ShaderEntries>;
|
||||
|
||||
@@ -233,6 +233,28 @@ void OpenGLState::ApplyStencilTest() const {
|
||||
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
|
||||
}
|
||||
}
|
||||
// Viewport does not affects glClearBuffer so emulate viewport using scissor test
|
||||
void OpenGLState::EmulateViewportWithScissor() {
|
||||
auto& current = viewports[0];
|
||||
if (current.scissor.enabled) {
|
||||
const GLint left = std::max(current.x, current.scissor.x);
|
||||
const GLint right =
|
||||
std::max(current.x + current.width, current.scissor.x + current.scissor.width);
|
||||
const GLint bottom = std::max(current.y, current.scissor.y);
|
||||
const GLint top =
|
||||
std::max(current.y + current.height, current.scissor.y + current.scissor.height);
|
||||
current.scissor.x = std::max(left, 0);
|
||||
current.scissor.y = std::max(bottom, 0);
|
||||
current.scissor.width = std::max(right - left, 0);
|
||||
current.scissor.height = std::max(top - bottom, 0);
|
||||
} else {
|
||||
current.scissor.enabled = true;
|
||||
current.scissor.x = current.x;
|
||||
current.scissor.y = current.y;
|
||||
current.scissor.width = current.width;
|
||||
current.scissor.height = current.height;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyViewport() const {
|
||||
if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
|
||||
@@ -242,7 +264,9 @@ void OpenGLState::ApplyViewport() const {
|
||||
const auto& updated = viewports[i];
|
||||
if (updated.x != current.x || updated.y != current.y ||
|
||||
updated.width != current.width || updated.height != current.height) {
|
||||
glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
|
||||
glViewportIndexedf(
|
||||
i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
|
||||
static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height));
|
||||
}
|
||||
if (updated.depth_range_near != current.depth_range_near ||
|
||||
updated.depth_range_far != current.depth_range_far) {
|
||||
@@ -270,8 +294,7 @@ void OpenGLState::ApplyViewport() const {
|
||||
const auto& updated = viewports[0];
|
||||
if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
|
||||
updated.height != current.height) {
|
||||
glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y),
|
||||
static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.height));
|
||||
glViewport(updated.x, updated.y, updated.width, updated.height);
|
||||
}
|
||||
if (updated.depth_range_near != current.depth_range_near ||
|
||||
updated.depth_range_far != current.depth_range_far) {
|
||||
@@ -339,14 +362,14 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
|
||||
if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
|
||||
updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
|
||||
updated.dst_a_func != current.dst_a_func) {
|
||||
glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func,
|
||||
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
|
||||
glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
|
||||
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
|
||||
}
|
||||
|
||||
if (blend_changed || updated.rgb_equation != current.rgb_equation ||
|
||||
updated.a_equation != current.a_equation) {
|
||||
glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
|
||||
updated.a_equation);
|
||||
glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
|
||||
updated.a_equation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -156,10 +156,10 @@ public:
|
||||
} draw;
|
||||
|
||||
struct viewport {
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
GLfloat width;
|
||||
GLfloat height;
|
||||
GLint x;
|
||||
GLint y;
|
||||
GLint width;
|
||||
GLint height;
|
||||
GLfloat depth_range_near; // GL_DEPTH_RANGE
|
||||
GLfloat depth_range_far; // GL_DEPTH_RANGE
|
||||
struct {
|
||||
@@ -206,6 +206,7 @@ public:
|
||||
OpenGLState& ResetBuffer(GLuint handle);
|
||||
OpenGLState& ResetVertexArray(GLuint handle);
|
||||
OpenGLState& ResetFramebuffer(GLuint handle);
|
||||
void EmulateViewportWithScissor();
|
||||
|
||||
private:
|
||||
static OpenGLState cur_state;
|
||||
|
||||
@@ -490,7 +490,7 @@ bool RendererOpenGL::Init() {
|
||||
Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model);
|
||||
Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version);
|
||||
|
||||
if (!GLAD_GL_VERSION_3_3) {
|
||||
if (!GLAD_GL_VERSION_4_3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,8 +82,8 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
|
||||
: QString::fromStdU16String(parameters.submit_text),
|
||||
QDialogButtonBox::AcceptRole);
|
||||
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::Submit);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::Reject);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject);
|
||||
layout->addWidget(header_label);
|
||||
layout->addWidget(sub_label);
|
||||
layout->addWidget(guide_label);
|
||||
@@ -96,16 +96,16 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
|
||||
|
||||
QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default;
|
||||
|
||||
void QtSoftwareKeyboardDialog::Submit() {
|
||||
void QtSoftwareKeyboardDialog::accept() {
|
||||
ok = true;
|
||||
text = line_edit->text().toStdU16String();
|
||||
accept();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void QtSoftwareKeyboardDialog::Reject() {
|
||||
void QtSoftwareKeyboardDialog::reject() {
|
||||
ok = false;
|
||||
text.clear();
|
||||
accept();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
std::u16string QtSoftwareKeyboardDialog::GetText() const {
|
||||
@@ -129,13 +129,13 @@ QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
|
||||
|
||||
void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out,
|
||||
Core::Frontend::SoftwareKeyboardParameters parameters) const {
|
||||
text_output = out;
|
||||
text_output = std::move(out);
|
||||
emit MainWindowGetText(parameters);
|
||||
}
|
||||
|
||||
void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message,
|
||||
std::function<void()> finished_check) const {
|
||||
this->finished_check = finished_check;
|
||||
this->finished_check = std::move(finished_check);
|
||||
emit MainWindowTextCheckDialog(error_message);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ public:
|
||||
Core::Frontend::SoftwareKeyboardParameters parameters);
|
||||
~QtSoftwareKeyboardDialog() override;
|
||||
|
||||
void Submit();
|
||||
void Reject();
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
std::u16string GetText() const;
|
||||
bool GetStatus() const;
|
||||
@@ -70,11 +70,10 @@ signals:
|
||||
void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const;
|
||||
void MainWindowTextCheckDialog(std::u16string error_message) const;
|
||||
|
||||
public slots:
|
||||
private:
|
||||
void MainWindowFinishedText(std::optional<std::u16string> text);
|
||||
void MainWindowFinishedCheckDialog();
|
||||
|
||||
private:
|
||||
mutable std::function<void(std::optional<std::u16string>)> text_output;
|
||||
mutable std::function<void()> finished_check;
|
||||
};
|
||||
|
||||
@@ -310,7 +310,7 @@ void GRenderWindow::InitRenderTarget() {
|
||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
||||
QGLFormat fmt;
|
||||
fmt.setVersion(3, 3);
|
||||
fmt.setVersion(4, 3);
|
||||
fmt.setProfile(QGLFormat::CoreProfile);
|
||||
fmt.setSwapInterval(false);
|
||||
|
||||
|
||||
@@ -432,6 +432,7 @@ void Config::ReadValues() {
|
||||
Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool();
|
||||
Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt();
|
||||
Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString();
|
||||
Settings::values.dump_exefs = qt_config->value("dump_exefs", false).toBool();
|
||||
Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool();
|
||||
qt_config->endGroup();
|
||||
|
||||
@@ -638,6 +639,7 @@ void Config::SaveValues() {
|
||||
qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub);
|
||||
qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port);
|
||||
qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args));
|
||||
qt_config->setValue("dump_exefs", Settings::values.dump_exefs);
|
||||
qt_config->setValue("dump_nso", Settings::values.dump_nso);
|
||||
qt_config->endGroup();
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ void ConfigureDebug::setConfiguration() {
|
||||
ui->toggle_console->setChecked(UISettings::values.show_console);
|
||||
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
|
||||
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
|
||||
ui->dump_exefs->setChecked(Settings::values.dump_exefs);
|
||||
ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
|
||||
}
|
||||
|
||||
@@ -43,6 +44,7 @@ void ConfigureDebug::applyConfiguration() {
|
||||
UISettings::values.show_console = ui->toggle_console->isChecked();
|
||||
Settings::values.log_filter = ui->log_filter_edit->text().toStdString();
|
||||
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
|
||||
Settings::values.dump_exefs = ui->dump_exefs->isChecked();
|
||||
Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked();
|
||||
Debugger::ToggleConsole();
|
||||
Log::Filter filter;
|
||||
|
||||
@@ -145,6 +145,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dump_exefs">
|
||||
<property name="whatsThis">
|
||||
<string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dump ExeFS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -23,31 +23,31 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_frame_limit">
|
||||
<property name="text">
|
||||
<string>Limit Speed Percent</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="frame_limit">
|
||||
<property name="suffix">
|
||||
<string>%</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_frame_limit">
|
||||
<property name="text">
|
||||
<string>Limit Speed Percent</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="frame_limit">
|
||||
<property name="suffix">
|
||||
<string>%</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="use_accurate_gpu_emulation">
|
||||
@@ -61,7 +61,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Internal Resolution:(Currently does nothing.)</string>
|
||||
<string>Internal Resolution</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -96,27 +96,27 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="bg_label">
|
||||
<property name="text">
|
||||
<string>Background Color:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bg_button">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="bg_label">
|
||||
<property name="text">
|
||||
<string>Background Color:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="bg_button">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -518,32 +518,18 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
|
||||
QStringList GMainWindow::GetUnsupportedGLExtensions() {
|
||||
QStringList unsupported_ext;
|
||||
|
||||
if (!GLAD_GL_ARB_program_interface_query)
|
||||
unsupported_ext.append("ARB_program_interface_query");
|
||||
if (!GLAD_GL_ARB_separate_shader_objects)
|
||||
unsupported_ext.append("ARB_separate_shader_objects");
|
||||
if (!GLAD_GL_ARB_vertex_attrib_binding)
|
||||
unsupported_ext.append("ARB_vertex_attrib_binding");
|
||||
if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
|
||||
unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev");
|
||||
if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
|
||||
unsupported_ext.append("ARB_texture_mirror_clamp_to_edge");
|
||||
if (!GLAD_GL_ARB_base_instance)
|
||||
unsupported_ext.append("ARB_base_instance");
|
||||
if (!GLAD_GL_ARB_texture_storage)
|
||||
unsupported_ext.append("ARB_texture_storage");
|
||||
if (!GLAD_GL_ARB_multi_bind)
|
||||
unsupported_ext.append("ARB_multi_bind");
|
||||
if (!GLAD_GL_ARB_copy_image)
|
||||
unsupported_ext.append("ARB_copy_image");
|
||||
|
||||
// Extensions required to support some texture formats.
|
||||
if (!GLAD_GL_EXT_texture_compression_s3tc)
|
||||
unsupported_ext.append("EXT_texture_compression_s3tc");
|
||||
if (!GLAD_GL_ARB_texture_compression_rgtc)
|
||||
unsupported_ext.append("ARB_texture_compression_rgtc");
|
||||
if (!GLAD_GL_ARB_texture_compression_bptc)
|
||||
unsupported_ext.append("ARB_texture_compression_bptc");
|
||||
if (!GLAD_GL_ARB_depth_buffer_float)
|
||||
unsupported_ext.append("ARB_depth_buffer_float");
|
||||
|
||||
@@ -562,8 +548,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
render_window->MakeCurrent();
|
||||
|
||||
if (!gladLoadGL()) {
|
||||
QMessageBox::critical(this, tr("Error while initializing OpenGL 3.3 Core!"),
|
||||
tr("Your GPU may not support OpenGL 3.3, or you do not "
|
||||
QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3 Core!"),
|
||||
tr("Your GPU may not support OpenGL 4.3, or you do not "
|
||||
"have the latest graphics driver."));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -366,6 +366,7 @@ void Config::ReadValues() {
|
||||
Settings::values.gdbstub_port =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689));
|
||||
Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", "");
|
||||
Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false);
|
||||
Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false);
|
||||
|
||||
// Web Service
|
||||
|
||||
@@ -206,6 +206,8 @@ log_filter = *:Trace
|
||||
# Port for listening to GDB connections.
|
||||
use_gdbstub=false
|
||||
gdbstub_port=24689
|
||||
# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
|
||||
dump_exefs=false
|
||||
# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them
|
||||
dump_nso=false
|
||||
|
||||
|
||||
@@ -111,32 +111,18 @@ void EmuWindow_SDL2::Fullscreen() {
|
||||
bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
|
||||
std::vector<std::string> unsupported_ext;
|
||||
|
||||
if (!GLAD_GL_ARB_program_interface_query)
|
||||
unsupported_ext.push_back("ARB_program_interface_query");
|
||||
if (!GLAD_GL_ARB_separate_shader_objects)
|
||||
unsupported_ext.push_back("ARB_separate_shader_objects");
|
||||
if (!GLAD_GL_ARB_vertex_attrib_binding)
|
||||
unsupported_ext.push_back("ARB_vertex_attrib_binding");
|
||||
if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
|
||||
unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev");
|
||||
if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
|
||||
unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
|
||||
if (!GLAD_GL_ARB_base_instance)
|
||||
unsupported_ext.push_back("ARB_base_instance");
|
||||
if (!GLAD_GL_ARB_texture_storage)
|
||||
unsupported_ext.push_back("ARB_texture_storage");
|
||||
if (!GLAD_GL_ARB_multi_bind)
|
||||
unsupported_ext.push_back("ARB_multi_bind");
|
||||
if (!GLAD_GL_ARB_copy_image)
|
||||
unsupported_ext.push_back("ARB_copy_image");
|
||||
|
||||
// Extensions required to support some texture formats.
|
||||
if (!GLAD_GL_EXT_texture_compression_s3tc)
|
||||
unsupported_ext.push_back("EXT_texture_compression_s3tc");
|
||||
if (!GLAD_GL_ARB_texture_compression_rgtc)
|
||||
unsupported_ext.push_back("ARB_texture_compression_rgtc");
|
||||
if (!GLAD_GL_ARB_texture_compression_bptc)
|
||||
unsupported_ext.push_back("ARB_texture_compression_bptc");
|
||||
if (!GLAD_GL_ARB_depth_buffer_float)
|
||||
unsupported_ext.push_back("ARB_depth_buffer_float");
|
||||
|
||||
@@ -157,7 +143,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
|
||||
Reference in New Issue
Block a user