Compare commits

..

3 Commits

Author SHA1 Message Date
Marcos Vitali
cd94dc484a Initialize polygon_offset in the constructor. 2018-11-23 10:38:06 -03:00
Marcos Vitali
ddeb7809f7 Clang Format fixes. 2018-11-23 10:10:48 -03:00
Marcos Vitali
33ba10591e GPU States: Implement Polygon Offset. This is used in SMO all the time. 2018-11-23 03:01:33 -03:00
45 changed files with 2803 additions and 3731 deletions

View File

@@ -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 "Get-ChildItem ${SRCS}/* -Include *.cpp,*.h -Recurse | Foreach {${CLANG_FORMAT} -i $_.fullname}"
COMMAND powershell.exe -Command "${CLANG_FORMAT} -i @(Get-ChildItem -Recurse ${SRCS}/* -Include \'*.h\', \'*.cpp\')"
COMMENT ${CCOMMENT})
elseif(MINGW)
add_custom_target(clang-format

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -25,6 +25,23 @@
namespace Common {
int CurrentThreadId() {
#ifdef _MSC_VER
return GetCurrentThreadId();
#elif defined __APPLE__
return mach_thread_self();
#else
return 0;
#endif
}
#ifdef _WIN32
// Supporting functions
void SleepCurrentThread(int ms) {
Sleep(ms);
}
#endif
#ifdef _MSC_VER
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
@@ -45,7 +62,7 @@ void SwitchCurrentThread() {
// This is implemented much nicer in upcoming msvc++, see:
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
void SetCurrentThreadName(const char* name) {
void SetCurrentThreadName(const char* szThreadName) {
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push, 8)
@@ -58,7 +75,7 @@ void SetCurrentThreadName(const char* name) {
#pragma pack(pop)
info.dwType = 0x1000;
info.szName = name;
info.szName = szThreadName;
info.dwThreadID = -1; // dwThreadID;
info.dwFlags = 0;
@@ -90,6 +107,10 @@ void SetCurrentThreadAffinity(u32 mask) {
}
#ifndef _WIN32
void SleepCurrentThread(int ms) {
usleep(1000 * ms);
}
void SwitchCurrentThread() {
usleep(1000 * 1);
}
@@ -97,15 +118,15 @@ void SwitchCurrentThread() {
// MinGW with the POSIX threading model does not support pthread_setname_np
#if !defined(_WIN32) || defined(_MSC_VER)
void SetCurrentThreadName(const char* name) {
void SetCurrentThreadName(const char* szThreadName) {
#ifdef __APPLE__
pthread_setname_np(name);
pthread_setname_np(szThreadName);
#elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
pthread_set_name_np(pthread_self(), name);
pthread_set_name_np(pthread_self(), szThreadName);
#elif defined(__NetBSD__)
pthread_setname_np(pthread_self(), "%s", (void*)name);
pthread_setname_np(pthread_self(), "%s", (void*)szThreadName);
#else
pthread_setname_np(pthread_self(), name);
pthread_setname_np(pthread_self(), szThreadName);
#endif
}
#endif

View File

@@ -13,8 +13,15 @@
namespace Common {
int CurrentThreadId();
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
void SetCurrentThreadAffinity(u32 mask);
class Event {
public:
Event() : is_set(false) {}
void Set() {
std::lock_guard<std::mutex> lk(mutex);
if (!is_set) {
@@ -46,14 +53,14 @@ public:
}
private:
bool is_set = false;
bool is_set;
std::condition_variable condvar;
std::mutex mutex;
};
class Barrier {
public:
explicit Barrier(std::size_t count_) : count(count_) {}
explicit Barrier(std::size_t count_) : count(count_), waiting(0), generation(0) {}
/// Blocks until all "count" threads have called Sync()
void Sync() {
@@ -73,13 +80,12 @@ public:
private:
std::condition_variable condvar;
std::mutex mutex;
std::size_t count;
std::size_t waiting = 0;
std::size_t generation = 0; // Incremented once each time the barrier is used
const std::size_t count;
std::size_t waiting;
std::size_t generation; // Incremented once each time the barrier is used
};
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
void SetCurrentThreadAffinity(u32 mask);
void SleepCurrentThread(int ms);
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
void SetCurrentThreadName(const char* name);

View File

@@ -12,8 +12,6 @@ add_library(core STATIC
core_timing.h
core_timing_util.cpp
core_timing_util.h
cpu_core_manager.cpp
cpu_core_manager.h
crypto/aes_util.cpp
crypto/aes_util.h
crypto/encryption_layer.cpp
@@ -158,8 +156,6 @@ add_library(core STATIC
hle/service/am/applets/applets.h
hle/service/am/applets/software_keyboard.cpp
hle/service/am/applets/software_keyboard.h
hle/service/am/applets/stub_applet.cpp
hle/service/am/applets/stub_applet.h
hle/service/am/idle.cpp
hle/service/am/idle.h
hle/service/am/omm.cpp

View File

@@ -14,7 +14,6 @@
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/cpu_core_manager.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
@@ -29,6 +28,7 @@
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
#include "core/perf_stats.h"
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "frontend/applets/software_keyboard.h"
#include "video_core/debug_utils/debug_utils.h"
@@ -71,22 +71,64 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
return vfs->OpenFile(path, FileSys::Mode::Read);
}
/// Runs a CPU core while the system is powered on
void RunCpuCore(Cpu& cpu_state) {
while (Core::System::GetInstance().IsPoweredOn()) {
cpu_state.RunLoop(true);
}
}
} // Anonymous namespace
struct System::Impl {
Cpu& CurrentCpuCore() {
return cpu_core_manager.GetCurrentCore();
if (Settings::values.use_multi_core) {
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
ASSERT(search != thread_to_cpu.end());
ASSERT(search->second);
return *search->second;
}
// Otherwise, use single-threaded mode active_core variable
return *cpu_cores[active_core];
}
ResultStatus RunLoop(bool tight_loop) {
status = ResultStatus::Success;
cpu_core_manager.RunLoop(tight_loop);
// Update thread_to_cpu in case Core 0 is run from a different host thread
thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
// execute. Otherwise, get out of the loop function.
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
tight_loop = false;
} else {
return ResultStatus::Success;
}
}
}
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
cpu_cores[active_core]->RunLoop(tight_loop);
if (Settings::values.use_multi_core) {
// Cores 1-3 are run on other threads in this mode
break;
}
}
if (GDBStub::IsServerEnabled()) {
GDBStub::SetCpuStepFlag(false);
}
return status;
}
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
ResultStatus Init(Frontend::EmuWindow& emu_window) {
LOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init();
@@ -103,6 +145,12 @@ struct System::Impl {
auto main_process = Kernel::Process::Create(kernel, "main");
kernel.MakeCurrentProcess(main_process.get());
cpu_barrier = std::make_unique<CpuBarrier>();
cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index);
}
telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>();
@@ -116,8 +164,17 @@ struct System::Impl {
gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
cpu_core_manager.Initialize(system);
is_powered_on = true;
// Create threads for CPU cores 1-3, and build thread_to_cpu map
// CPU core 0 is run on the main thread
thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
if (Settings::values.use_multi_core) {
for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
cpu_core_threads[index] =
std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1]));
thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get();
}
}
LOG_DEBUG(Core, "Initialized OK");
// Reset counters and set time origin to current frame
@@ -127,8 +184,7 @@ struct System::Impl {
return ResultStatus::Success;
}
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath) {
ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
if (!app_loader) {
@@ -145,7 +201,7 @@ struct System::Impl {
return ResultStatus::ErrorSystemMode;
}
ResultStatus init_result{Init(system, emu_window)};
ResultStatus init_result{Init(emu_window)};
if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
@@ -175,8 +231,6 @@ struct System::Impl {
Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
perf_results.frametime * 1000.0);
is_powered_on = false;
// Shutdown emulation session
renderer.reset();
GDBStub::Shutdown();
@@ -186,7 +240,19 @@ struct System::Impl {
gpu_core.reset();
// Close all CPU/threading state
cpu_core_manager.Shutdown();
cpu_barrier->NotifyEnd();
if (Settings::values.use_multi_core) {
for (auto& thread : cpu_core_threads) {
thread->join();
thread.reset();
}
}
thread_to_cpu.clear();
for (auto& cpu_core : cpu_cores) {
cpu_core.reset();
}
cpu_exclusive_monitor.reset();
cpu_barrier.reset();
// Shutdown kernel and core timing
kernel.Shutdown();
@@ -223,8 +289,11 @@ struct System::Impl {
std::unique_ptr<VideoCore::RendererBase> renderer;
std::unique_ptr<Tegra::GPU> gpu_core;
std::shared_ptr<Tegra::DebugContext> debug_context;
CpuCoreManager cpu_core_manager;
bool is_powered_on = false;
std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor;
std::unique_ptr<CpuBarrier> cpu_barrier;
std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
std::size_t active_core{}; ///< Active core, only used in single thread mode
/// Frontend applets
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
@@ -238,6 +307,9 @@ struct System::Impl {
ResultStatus status = ResultStatus::Success;
std::string status_details = "";
/// Map of guest threads to CPU cores
std::map<std::thread::id, Cpu*> thread_to_cpu;
Core::PerfStats perf_stats;
Core::FrameLimiter frame_limiter;
};
@@ -262,15 +334,17 @@ System::ResultStatus System::SingleStep() {
}
void System::InvalidateCpuInstructionCaches() {
impl->cpu_core_manager.InvalidateAllInstructionCaches();
for (auto& cpu : impl->cpu_cores) {
cpu->ArmInterface().ClearInstructionCache();
}
}
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
return impl->Load(*this, emu_window, filepath);
return impl->Load(emu_window, filepath);
}
bool System::IsPoweredOn() const {
return impl->is_powered_on;
return impl->cpu_barrier && impl->cpu_barrier->IsAlive();
}
void System::PrepareReschedule() {
@@ -334,20 +408,21 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
}
Cpu& System::CpuCore(std::size_t core_index) {
return impl->cpu_core_manager.GetCore(core_index);
ASSERT(core_index < NUM_CPU_CORES);
return *impl->cpu_cores[core_index];
}
const Cpu& System::CpuCore(std::size_t core_index) const {
ASSERT(core_index < NUM_CPU_CORES);
return impl->cpu_core_manager.GetCore(core_index);
return *impl->cpu_cores[core_index];
}
ExclusiveMonitor& System::Monitor() {
return impl->cpu_core_manager.GetExclusiveMonitor();
return *impl->cpu_exclusive_monitor;
}
const ExclusiveMonitor& System::Monitor() const {
return impl->cpu_core_manager.GetExclusiveMonitor();
return *impl->cpu_exclusive_monitor;
}
Tegra::GPU& System::GPU() {
@@ -431,7 +506,7 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons
}
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
return impl->Init(*this, emu_window);
return impl->Init(emu_window);
}
void System::Shutdown() {

View File

@@ -1,142 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/cpu_core_manager.h"
#include "core/gdbstub/gdbstub.h"
#include "core/settings.h"
namespace Core {
namespace {
void RunCpuCore(const System& system, Cpu& cpu_state) {
while (system.IsPoweredOn()) {
cpu_state.RunLoop(true);
}
}
} // Anonymous namespace
CpuCoreManager::CpuCoreManager() = default;
CpuCoreManager::~CpuCoreManager() = default;
void CpuCoreManager::Initialize(System& system) {
barrier = std::make_unique<CpuBarrier>();
exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
for (std::size_t index = 0; index < cores.size(); ++index) {
cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index);
}
// Create threads for CPU cores 1-3, and build thread_to_cpu map
// CPU core 0 is run on the main thread
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
if (!Settings::values.use_multi_core) {
return;
}
for (std::size_t index = 0; index < core_threads.size(); ++index) {
core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
std::ref(*cores[index + 1]));
thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
}
}
void CpuCoreManager::Shutdown() {
barrier->NotifyEnd();
if (Settings::values.use_multi_core) {
for (auto& thread : core_threads) {
thread->join();
thread.reset();
}
}
thread_to_cpu.clear();
for (auto& cpu_core : cores) {
cpu_core.reset();
}
exclusive_monitor.reset();
barrier.reset();
}
Cpu& CpuCoreManager::GetCore(std::size_t index) {
return *cores.at(index);
}
const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
return *cores.at(index);
}
ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
return *exclusive_monitor;
}
const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
return *exclusive_monitor;
}
Cpu& CpuCoreManager::GetCurrentCore() {
if (Settings::values.use_multi_core) {
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
ASSERT(search != thread_to_cpu.end());
ASSERT(search->second);
return *search->second;
}
// Otherwise, use single-threaded mode active_core variable
return *cores[active_core];
}
const Cpu& CpuCoreManager::GetCurrentCore() const {
if (Settings::values.use_multi_core) {
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
ASSERT(search != thread_to_cpu.end());
ASSERT(search->second);
return *search->second;
}
// Otherwise, use single-threaded mode active_core variable
return *cores[active_core];
}
void CpuCoreManager::RunLoop(bool tight_loop) {
// Update thread_to_cpu in case Core 0 is run from a different host thread
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
// execute. Otherwise, get out of the loop function.
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
tight_loop = false;
} else {
return;
}
}
}
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
cores[active_core]->RunLoop(tight_loop);
if (Settings::values.use_multi_core) {
// Cores 1-3 are run on other threads in this mode
break;
}
}
if (GDBStub::IsServerEnabled()) {
GDBStub::SetCpuStepFlag(false);
}
}
void CpuCoreManager::InvalidateAllInstructionCaches() {
for (auto& cpu : cores) {
cpu->ArmInterface().ClearInstructionCache();
}
}
} // namespace Core

View File

@@ -1,59 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <map>
#include <memory>
#include <thread>
namespace Core {
class Cpu;
class CpuBarrier;
class ExclusiveMonitor;
class System;
class CpuCoreManager {
public:
CpuCoreManager();
CpuCoreManager(const CpuCoreManager&) = delete;
CpuCoreManager(CpuCoreManager&&) = delete;
~CpuCoreManager();
CpuCoreManager& operator=(const CpuCoreManager&) = delete;
CpuCoreManager& operator=(CpuCoreManager&&) = delete;
void Initialize(System& system);
void Shutdown();
Cpu& GetCore(std::size_t index);
const Cpu& GetCore(std::size_t index) const;
Cpu& GetCurrentCore();
const Cpu& GetCurrentCore() const;
ExclusiveMonitor& GetExclusiveMonitor();
const ExclusiveMonitor& GetExclusiveMonitor() const;
void RunLoop(bool tight_loop);
void InvalidateAllInstructionCaches();
private:
static constexpr std::size_t NUM_CPU_CORES = 4;
std::unique_ptr<ExclusiveMonitor> exclusive_monitor;
std::unique_ptr<CpuBarrier> barrier;
std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores;
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads;
std::size_t active_core{}; ///< Active core, only used in single thread mode
/// Map of guest threads to CPU cores
std::map<std::thread::id, Cpu*> thread_to_cpu;
};
} // namespace Core

View File

@@ -26,11 +26,6 @@ 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);
@@ -62,15 +57,6 @@ 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
@@ -84,30 +70,6 @@ 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;
}
@@ -352,25 +314,18 @@ 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");

View File

@@ -71,6 +71,10 @@ 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
@@ -256,36 +260,6 @@ 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.
*
@@ -435,27 +409,6 @@ 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;
@@ -646,7 +599,8 @@ 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 += fmt::format("{:x}", thread->GetThreadID());
val += ",";
}
}
val.pop_back();
@@ -837,15 +791,11 @@ 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) {
u128 r = FpuRead(id, current_thread);
LongToGdbHex(reply, r[0]);
LongToGdbHex(reply + 16, r[1]);
LongToGdbHex(reply, RegRead(id, current_thread));
} else if (id == FPCR_REGISTER) {
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));
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread));
} else {
LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread));
}
SendReply(reinterpret_cast<char*>(reply));
@@ -872,18 +822,13 @@ static void ReadRegisters() {
bufptr += 8;
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]);
for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) {
LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
}
bufptr += 32 * 32;
r = FpuRead(FPCR_REGISTER, current_thread);
IntToGdbHex(bufptr, static_cast<u32>(r[0]));
LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread));
bufptr += 8;
@@ -908,12 +853,14 @@ 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) {
FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread);
RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
} else if (id == FPCR_REGISTER) {
} else if (id == FPCR_REGISTER + 1) {
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread);
} else {
RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
}
// Update ARM context, skipping scheduler - no running threads at this point
// Update Unicorn context skipping scheduler, no running threads at this point
Core::System::GetInstance()
.ArmInterface(current_core)
.LoadContext(current_thread->GetContext());
@@ -938,13 +885,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(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);
RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread);
} else {
UNIMPLEMENTED();
}
}
// Update ARM context, skipping scheduler - no running threads at this point
// Update Unicorn context skipping scheduler, no running threads at this point
Core::System::GetInstance()
.ArmInterface(current_core)
.LoadContext(current_thread->GetContext());
@@ -970,6 +917,12 @@ 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");
}
@@ -1014,7 +967,7 @@ void Break(bool is_memory_break) {
static void Step() {
if (command_length > 1) {
RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
// Update ARM context, skipping scheduler - no running threads at this point
// Update Unicorn context skipping scheduler, no running threads at this point
Core::System::GetInstance()
.ArmInterface(current_core)
.LoadContext(current_thread->GetContext());
@@ -1057,7 +1010,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});
@@ -1368,15 +1321,13 @@ void SetCpuStepFlag(bool is_step) {
}
void SendTrap(Kernel::Thread* thread, int trap) {
if (!send_trap) {
return;
if (send_trap) {
if (!halt_loop || current_thread == thread) {
current_thread = thread;
SendSignal(thread, trap);
}
halt_loop = true;
send_trap = false;
}
if (!halt_loop || current_thread == thread) {
current_thread = thread;
SendSignal(thread, trap);
}
halt_loop = true;
send_trap = false;
}
}; // namespace GDBStub

View File

@@ -6,6 +6,8 @@
#include <cinttypes>
#include <cstring>
#include <stack>
#include "applets/applets.h"
#include "applets/software_keyboard.h"
#include "audio_core/audio_renderer.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
@@ -16,9 +18,6 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/applets/software_keyboard.h"
#include "core/hle/service/am/applets/stub_applet.h"
#include "core/hle/service/am/idle.h"
#include "core/hle/service/am/omm.h"
#include "core/hle/service/am/spsm.h"
@@ -483,15 +482,11 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
rb.Push(RESULT_SUCCESS);
if (Settings::values.use_docked_mode) {
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));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
} else {
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.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
}
LOG_DEBUG(Service_AM, "called");
@@ -766,9 +761,8 @@ static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
case AppletId::SoftwareKeyboard:
return std::make_shared<Applets::SoftwareKeyboard>();
default:
LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
static_cast<u32>(id));
return std::make_shared<Applets::StubApplet>();
UNREACHABLE_MSG("Unimplemented AppletId [{:08X}]!", static_cast<u32>(id));
return nullptr;
}
}

View File

@@ -1,70 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <string>
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/stub_applet.h"
namespace Service::AM::Applets {
static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) {
std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
"called (STUBBED), during {} recieved normal data with size={:08X}, data={}",
prefix, data.size(), Common::HexVectorToString(data));
}
storage = broker.PopInteractiveDataToApplet();
for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
"called (STUBBED), during {} recieved interactive data with size={:08X}, data={}",
prefix, data.size(), Common::HexVectorToString(data));
}
}
StubApplet::StubApplet() = default;
StubApplet::~StubApplet() = default;
void StubApplet::Initialize() {
LOG_WARNING(Service_AM, "called (STUBBED)");
Applet::Initialize();
LogCurrentStorage(broker, "Initialize");
}
bool StubApplet::TransactionComplete() const {
LOG_WARNING(Service_AM, "called (STUBBED)");
return true;
}
ResultCode StubApplet::GetStatus() const {
LOG_WARNING(Service_AM, "called (STUBBED)");
return RESULT_SUCCESS;
}
void StubApplet::ExecuteInteractive() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "ExecuteInteractive");
broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
broker.SignalStateChanged();
}
void StubApplet::Execute() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "Execute");
broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
broker.SignalStateChanged();
}
} // namespace Service::AM::Applets

View File

@@ -1,24 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/service/am/applets/applets.h"
namespace Service::AM::Applets {
class StubApplet final : public Applet {
public:
StubApplet();
~StubApplet() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
};
} // namespace Service::AM::Applets

View File

@@ -341,10 +341,6 @@ 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");
@@ -395,7 +391,6 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
bis_factory = nullptr;
save_data_factory = nullptr;
sdmc_factory = nullptr;
ClearUnionContents();
}
auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),

View File

@@ -49,7 +49,6 @@ 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();

View File

@@ -5,8 +5,6 @@
#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
namespace Service::Nvidia::Devices {
@@ -35,8 +33,6 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
return ZBCQueryTable(input, output);
case IoctlCommand::IocFlushL2:
return FlushL2(input, output);
case IoctlCommand::IocGetGpuTime:
return GetGpuTime(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
@@ -173,13 +169,4 @@ u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& outp
return 0;
}
u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlGetGpuTime params{};
std::memcpy(&params, input.data(), input.size());
params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks());
std::memcpy(output.data(), &params, output.size());
return 0;
}
} // namespace Service::Nvidia::Devices

View File

@@ -156,11 +156,6 @@ private:
};
static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size");
struct IoctlGetGpuTime {
u64_le gpu_time;
};
static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size");
u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
@@ -169,7 +164,6 @@ private:
u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices

View File

@@ -63,17 +63,6 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
}
ResultCode ServiceManager::UnregisterService(const 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) {
@@ -138,52 +127,13 @@ 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, &SM::RegisterService, "RegisterService"},
{0x00000003, &SM::UnregisterService, "UnregisterService"},
{0x00000002, nullptr, "RegisterService"},
{0x00000003, nullptr, "UnregisterService"},
};
RegisterHandlers(functions);
}

View File

@@ -35,8 +35,6 @@ 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;
};
@@ -50,7 +48,6 @@ public:
ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
unsigned int max_sessions);
ResultCode UnregisterService(const std::string& name);
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);

View File

@@ -510,11 +510,7 @@ private:
if (transaction == TransactionId::Connect) {
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
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)};
IGBPConnectResponseParcel response{1280, 720};
ctx.WriteBuffer(response.Serialize());
} else if (transaction == TransactionId::SetPreallocatedBuffer) {
IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
@@ -696,15 +692,11 @@ private:
rb.Push(RESULT_SUCCESS);
if (Settings::values.use_docked_mode) {
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));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
} else {
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.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
}
rb.PushRaw<float>(60.0f);
@@ -909,15 +901,11 @@ private:
rb.Push(RESULT_SUCCESS);
if (Settings::values.use_docked_mode) {
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));
rb.Push(static_cast<u64>(DisplayResolution::DockedWidth));
rb.Push(static_cast<u64>(DisplayResolution::DockedHeight));
} else {
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));
rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth));
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight));
}
}
@@ -934,8 +922,6 @@ 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);

View File

@@ -403,7 +403,6 @@ struct Values {
bool use_gdbstub;
u16 gdbstub_port;
std::string program_args;
bool dump_exefs;
bool dump_nso;
// WebService

View File

@@ -590,10 +590,18 @@ public:
float clear_color[4];
float clear_depth;
INSERT_PADDING_WORDS(0x3);
s32 clear_stencil;
INSERT_PADDING_WORDS(0x17);
INSERT_PADDING_WORDS(0x7);
u32 polygon_offset_point_enable;
u32 polygon_offset_line_enable;
u32 polygon_offset_fill_enable;
INSERT_PADDING_WORDS(0xD);
std::array<ScissorTest, NumViewports> scissor_test;
@@ -631,16 +639,7 @@ public:
}
} zeta;
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);
INSERT_PADDING_WORDS(0x5B);
std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format;
@@ -761,7 +760,11 @@ public:
}
} tsc;
INSERT_PADDING_WORDS(0x3);
INSERT_PADDING_WORDS(0x1);
float polygon_offset_factor;
INSERT_PADDING_WORDS(0x1);
struct {
u32 tic_address_high;
@@ -786,7 +789,9 @@ public:
u32 framebuffer_srgb;
INSERT_PADDING_WORDS(0x12);
float polygon_offset_units;
INSERT_PADDING_WORDS(0x11);
union {
BitField<2, 1, u32> coord_origin;
@@ -863,7 +868,9 @@ public:
INSERT_PADDING_WORDS(0x7);
INSERT_PADDING_WORDS(0x20);
INSERT_PADDING_WORDS(0x1F);
float polygon_offset_clamp;
struct {
u32 is_instanced[NumVertexArrays];
@@ -1136,6 +1143,9 @@ ASSERT_REG_POSITION(vertex_buffer, 0x35D);
ASSERT_REG_POSITION(clear_color[0], 0x360);
ASSERT_REG_POSITION(clear_depth, 0x364);
ASSERT_REG_POSITION(clear_stencil, 0x368);
ASSERT_REG_POSITION(polygon_offset_point_enable, 0x370);
ASSERT_REG_POSITION(polygon_offset_line_enable, 0x371);
ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
ASSERT_REG_POSITION(scissor_test, 0x380);
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
@@ -1143,7 +1153,6 @@ 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);
@@ -1174,6 +1183,7 @@ ASSERT_REG_POSITION(point_size, 0x546);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
ASSERT_REG_POSITION(multisample_control, 0x54F);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(polygon_offset_factor, 0x55b);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
ASSERT_REG_POSITION(stencil_back_op_fail, 0x566);
@@ -1181,11 +1191,13 @@ ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567);
ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568);
ASSERT_REG_POSITION(stencil_back_func_func, 0x569);
ASSERT_REG_POSITION(framebuffer_srgb, 0x56E);
ASSERT_REG_POSITION(polygon_offset_units, 0x56F);
ASSERT_REG_POSITION(point_coord_replace, 0x581);
ASSERT_REG_POSITION(code_address, 0x582);
ASSERT_REG_POSITION(draw, 0x585);
ASSERT_REG_POSITION(primitive_restart, 0x591);
ASSERT_REG_POSITION(index_array, 0x5F2);
ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F);
ASSERT_REG_POSITION(instanced_arrays, 0x620);
ASSERT_REG_POSITION(cull, 0x646);
ASSERT_REG_POSITION(logic_op, 0x671);

View File

@@ -153,7 +153,6 @@ enum class PredCondition : u64 {
NotEqual = 5,
GreaterEqual = 6,
LessThanWithNan = 9,
LessEqualWithNan = 11,
GreaterThanWithNan = 12,
NotEqualWithNan = 13,
GreaterEqualWithNan = 14,
@@ -262,7 +261,7 @@ enum class FlowCondition : u64 {
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
};
enum class ConditionCode : u64 {
enum class ControlCode : u64 {
F = 0,
LT = 1,
EQ = 2,
@@ -570,6 +569,7 @@ 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;
@@ -831,7 +831,7 @@ union Instruction {
union {
BitField<0, 3, u64> pred0;
BitField<3, 3, u64> pred3;
BitField<8, 5, ConditionCode> cc; // flag in cc
BitField<8, 5, ControlCode> cc; // flag in cc
BitField<39, 3, u64> pred39;
BitField<42, 1, u64> neg_pred39;
BitField<45, 4, PredOperation> op; // op with pred39
@@ -1235,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, ConditionCode> flow_condition_code;
BitField<0, 5, ControlCode> flow_control_code;
Attribute attribute;
Sampler sampler;

View File

@@ -98,9 +98,14 @@ 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
@@ -537,30 +542,6 @@ 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) {
@@ -572,14 +553,6 @@ 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) {
@@ -615,12 +588,12 @@ void RasterizerOpenGL::DrawArrays() {
SyncLogicOpState();
SyncCullMode();
SyncPrimitiveRestart();
SyncScissorTest(state);
SyncScissorTest();
// Alpha Testing is synced on shaders.
SyncTransformFeedback();
SyncPointState();
CheckAlphaTests();
SyncPolygonOffset();
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
@@ -842,7 +815,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
}
const u32 bias = config.mip_lod_bias.Value();
// Sign extend the 13-bit value.
constexpr u32 mask = 1U << (13 - 1);
const 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;
@@ -974,8 +947,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 = viewport_rect.GetWidth();
viewport.height = viewport_rect.GetHeight();
viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
viewport.depth_range_far = regs.viewports[i].depth_range_far;
viewport.depth_range_near = regs.viewports[i].depth_range_near;
}
@@ -1147,11 +1120,11 @@ void RasterizerOpenGL::SyncLogicOpState() {
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
}
void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
void RasterizerOpenGL::SyncScissorTest() {
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 = current_state.viewports[i].scissor;
auto& dst = state.viewports[i].scissor;
dst.enabled = (src.enable != 0);
if (dst.enabled == 0) {
return;
@@ -1179,6 +1152,16 @@ void RasterizerOpenGL::SyncPointState() {
state.point.size = regs.point_size;
}
void RasterizerOpenGL::SyncPolygonOffset() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0;
state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0;
state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0;
state.polygon_offset.units = regs.polygon_offset_units;
state.polygon_offset.factor = regs.polygon_offset_factor;
state.polygon_offset.clamp = regs.polygon_offset_clamp;
}
void RasterizerOpenGL::CheckAlphaTests() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;

View File

@@ -91,20 +91,19 @@ private:
void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
private:
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;
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;
};
/**
@@ -172,7 +171,7 @@ private:
void SyncMultiSampleState();
/// Syncs the scissor test state to match the guest state
void SyncScissorTest(OpenGLState& current_state);
void SyncScissorTest();
/// Syncs the transform feedback state to match the guest state
void SyncTransformFeedback();
@@ -183,11 +182,16 @@ private:
/// Syncs Color Mask
void SyncColorMask();
/// Syncs the polygon offsets
void SyncPolygonOffset();
/// Check asserts for alpha testing.
void CheckAlphaTests();
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;

View File

@@ -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, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
{GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U
{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,
{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,
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, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U_SRGB
{GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, 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;
return GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
}
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);
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
if (source_format.compressed) {
glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment,
static_cast<GLsizei>(src_params.size_in_bytes), nullptr);

View File

@@ -84,7 +84,6 @@ 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;

View File

@@ -30,7 +30,7 @@ public:
}
std::size_t GetSizeInBytes() const override {
return shader_length;
return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64);
}
// We do not have to flush this cache as things in it are never modified by us.
@@ -82,7 +82,6 @@ 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;

View File

@@ -34,17 +34,6 @@ 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;
@@ -95,8 +84,7 @@ struct Subroutine {
class ControlFlowAnalyzer {
public:
ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix)
: program_code(program_code), shader_coverage_begin(main_offset),
shader_coverage_end(main_offset + 1) {
: program_code(program_code) {
// Recursively finds all subroutines.
const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix);
@@ -108,16 +96,10 @@ 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) {
@@ -159,9 +141,6 @@ 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()) {
@@ -278,6 +257,14 @@ 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
@@ -384,7 +371,7 @@ public:
if (sets_cc) {
const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete.");
LOG_WARNING(HW_GPU, "Control Codes Imcomplete.");
}
}
@@ -467,25 +454,23 @@ public:
shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");");
}
std::string GetConditionCode(const Tegra::Shader::ConditionCode cc) const {
std::string GetControlCode(const Tegra::Shader::ControlCode cc) const {
switch (cc) {
case Tegra::Shader::ConditionCode::NEU:
case Tegra::Shader::ControlCode::NEU:
return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')';
default:
UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
UNIMPLEMENTED_MSG("Unimplemented Control Code: {}", static_cast<u32>(cc));
return "false";
}
}
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;
std::string GetInternalFlag(const InternalFlag ii) const {
const u32 code = static_cast<u32>(ii);
return "internalFlag_" + std::to_string(code) + suffix;
}
void SetInternalFlag(const InternalFlag flag, const std::string& value) const {
shader.AddLine(GetInternalFlag(flag) + " = " + value + ';');
void SetInternalFlag(const InternalFlag ii, const std::string& value) const {
shader.AddLine(GetInternalFlag(ii) + " = " + value + ';');
}
/**
@@ -636,8 +621,8 @@ private:
/// Generates declarations for internal flags.
void GenerateInternalFlags() {
for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
const InternalFlag code = static_cast<InternalFlag>(flag);
for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) {
const InternalFlag code = static_cast<InternalFlag>(ii);
declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
}
declarations.AddNewLine();
@@ -954,10 +939,9 @@ 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,
std::size_t shader_length)
u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix)
: subroutines(subroutines), program_code(program_code), main_offset(main_offset),
stage(stage), suffix(suffix), shader_length(shader_length) {
stage(stage), suffix(suffix) {
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
local_memory_size = header.GetLocalMemorySize();
regs.SetLocalMemory(local_memory_size);
@@ -970,7 +954,7 @@ public:
/// Returns entries in the shader that are useful for external functions
ShaderEntries GetEntries() const {
return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length};
return {regs.GetConstBuffersDeclarations(), regs.GetSamplers()};
}
private:
@@ -1075,17 +1059,11 @@ private:
const std::string& op_a, const std::string& op_b) const {
using Tegra::Shader::PredCondition;
static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = {
{PredCondition::LessThan, "<"},
{PredCondition::Equal, "=="},
{PredCondition::LessEqual, "<="},
{PredCondition::GreaterThan, ">"},
{PredCondition::NotEqual, "!="},
{PredCondition::GreaterEqual, ">="},
{PredCondition::LessThanWithNan, "<"},
{PredCondition::NotEqualWithNan, "!="},
{PredCondition::LessEqualWithNan, "<="},
{PredCondition::GreaterThanWithNan, ">"},
{PredCondition::GreaterEqualWithNan, ">="}};
{PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="},
{PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"},
{PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="},
{PredCondition::LessThanWithNan, "<"}, {PredCondition::NotEqualWithNan, "!="},
{PredCondition::GreaterThanWithNan, ">"}, {PredCondition::GreaterEqualWithNan, ">="}};
const auto& comparison{PredicateComparisonStrings.find(condition)};
UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonStrings.end(),
@@ -1094,7 +1072,6 @@ private:
std::string predicate{'(' + op_a + ") " + comparison->second + " (" + op_b + ')'};
if (condition == PredCondition::LessThanWithNan ||
condition == PredCondition::NotEqualWithNan ||
condition == PredCondition::LessEqualWithNan ||
condition == PredCondition::GreaterThanWithNan ||
condition == PredCondition::GreaterEqualWithNan) {
predicate += " || isnan(" + op_a + ") || isnan(" + op_b + ')';
@@ -1266,7 +1243,14 @@ private:
regs.SetRegisterToInteger(dest, true, 0, result, 1, 1);
}
void WriteTexsInstruction(const Instruction& instr, const std::string& texture) {
void WriteTexsInstruction(const Instruction& instr, const std::string& coord,
const std::string& texture) {
// Add an extra scope and declare the texture coords inside to prevent
// overwriting them in case they are used as outputs of the texs instruction.
shader.AddLine('{');
++shader.scope;
shader.AddLine(coord);
// TEXS has two destination registers and a swizzle. The first two elements in the swizzle
// go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
@@ -1289,6 +1273,9 @@ private:
++written_components;
}
--shader.scope;
shader.AddLine('}');
}
static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) {
@@ -1521,8 +1508,9 @@ 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,
"Condition codes generation in FMUL is not implemented");
"FMUL Generates an unhandled Control Code");
op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b);
@@ -1534,7 +1522,7 @@ private:
case OpCode::Id::FADD_R:
case OpCode::Id::FADD_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in FADD is not implemented");
"FADD Generates an unhandled Control Code");
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);
@@ -1584,7 +1572,7 @@ private:
case OpCode::Id::FMNMX_R:
case OpCode::Id::FMNMX_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in FMNMX is not implemented");
"FMNMX Generates an unhandled Control Code");
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);
@@ -1621,7 +1609,7 @@ private:
}
case OpCode::Id::FMUL32_IMM: {
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
"Condition codes generation in FMUL32 is not implemented");
"FMUL32 Generates an unhandled Control Code");
regs.SetRegisterToFloat(instr.gpr0, 0,
regs.GetRegisterAsFloat(instr.gpr8) + " * " +
@@ -1631,7 +1619,7 @@ private:
}
case OpCode::Id::FADD32I: {
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
"Condition codes generation in FADD32I is not implemented");
"FADD32 Generates an unhandled Control Code");
std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
std::string op_b = GetImmediate32(instr);
@@ -1666,8 +1654,7 @@ private:
switch (opcode->get().GetId()) {
case OpCode::Id::BFE_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in BFE is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "BFE Generates an unhandled Control Code");
std::string inner_shift =
'(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')';
@@ -1704,8 +1691,7 @@ private:
case OpCode::Id::SHR_C:
case OpCode::Id::SHR_R:
case OpCode::Id::SHR_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in SHR is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHR Generates an unhandled Control Code");
if (!instr.shift.is_signed) {
// Logical shift right
@@ -1720,8 +1706,8 @@ private:
case OpCode::Id::SHL_C:
case OpCode::Id::SHL_R:
case OpCode::Id::SHL_IMM:
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in SHL is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHL Generates an unhandled Control Code");
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
break;
default: {
@@ -1737,7 +1723,7 @@ private:
switch (opcode->get().GetId()) {
case OpCode::Id::IADD32I:
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
"Condition codes generation in IADD32I is not implemented");
"IADD32 Generates an unhandled Control Code");
if (instr.iadd32i.negate_a)
op_a = "-(" + op_a + ')';
@@ -1747,7 +1733,7 @@ private:
break;
case OpCode::Id::LOP32I: {
UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
"Condition codes generation in LOP32I is not implemented");
"LOP32I Generates an unhandled Control Code");
if (instr.alu.lop32i.invert_a)
op_a = "~(" + op_a + ')';
@@ -1786,7 +1772,7 @@ private:
case OpCode::Id::IADD_R:
case OpCode::Id::IADD_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in IADD is not implemented");
"IADD Generates an unhandled Control Code");
if (instr.alu_integer.negate_a)
op_a = "-(" + op_a + ')';
@@ -1802,7 +1788,7 @@ private:
case OpCode::Id::IADD3_R:
case OpCode::Id::IADD3_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in IADD3 is not implemented");
"IADD3 Generates an unhandled Control Code");
std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
@@ -1865,7 +1851,7 @@ private:
case OpCode::Id::ISCADD_R:
case OpCode::Id::ISCADD_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in ISCADD is not implemented");
"ISCADD Generates an unhandled Control Code");
if (instr.alu_integer.negate_a)
op_a = "-(" + op_a + ')';
@@ -1900,8 +1886,7 @@ private:
case OpCode::Id::LOP_C:
case OpCode::Id::LOP_R:
case OpCode::Id::LOP_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in LOP is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "LOP Generates an unhandled Control Code");
if (instr.alu.lop.invert_a)
op_a = "~(" + op_a + ')';
@@ -1917,7 +1902,7 @@ private:
case OpCode::Id::LOP3_R:
case OpCode::Id::LOP3_IMM: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in LOP3 is not implemented");
"LOP3 Generates an unhandled Control Code");
const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
std::string lut;
@@ -1936,7 +1921,7 @@ private:
case OpCode::Id::IMNMX_IMM: {
UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None);
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in IMNMX is not implemented");
"IMNMX Generates an unhandled Control Code");
const std::string condition =
GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0);
@@ -2109,8 +2094,7 @@ 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,
"Condition codes generation in FFMA is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "FFMA Generates an unhandled Control Code");
switch (opcode->get().GetId()) {
case OpCode::Id::FFMA_CR: {
@@ -2220,8 +2204,7 @@ 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,
"Condition codes generation in I2F is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "I2F Generates an unhandled Control Code");
std::string op_a{};
@@ -2251,8 +2234,7 @@ 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,
"Condition codes generation in F2F is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2F Generates an unhandled Control Code");
std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
if (instr.conversion.abs_a) {
@@ -2290,8 +2272,7 @@ 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,
"Condition codes generation in F2I is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2I Generates an unhandled Control Code");
std::string op_a{};
if (instr.is_b_gpr) {
@@ -2582,6 +2563,7 @@ private:
}
// TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias
// or lod.
std::string op_c;
const std::string sampler =
GetSampler(instr.sampler, texture_type, is_array, depth_compare);
@@ -2604,35 +2586,27 @@ private:
}
case Tegra::Shader::TextureProcessMode::LB:
case Tegra::Shader::TextureProcessMode::LBA: {
const std::string bias = [&]() {
if (depth_compare) {
if (is_array)
return regs.GetRegisterAsFloat(instr.gpr20.Value() + 2);
else
return regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
} else {
return regs.GetRegisterAsFloat(instr.gpr20);
}
}();
shader.AddLine("float bias = " + bias + ';');
if (depth_compare) {
if (is_array)
op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 2);
else
op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
} else {
op_c = regs.GetRegisterAsFloat(instr.gpr20);
}
// TODO: Figure if A suffix changes the equation at all.
texture = "texture(" + sampler + ", coords, bias)";
texture = "texture(" + sampler + ", coords, " + op_c + ')';
break;
}
case Tegra::Shader::TextureProcessMode::LL:
case Tegra::Shader::TextureProcessMode::LLA: {
const std::string lod = [&]() {
if (num_coordinates <= 2) {
return regs.GetRegisterAsFloat(instr.gpr20);
} else {
return regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
}
}();
shader.AddLine("float lod = " + lod + ';');
if (num_coordinates <= 2) {
op_c = regs.GetRegisterAsFloat(instr.gpr20);
} else {
op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
}
// TODO: Figure if A suffix changes the equation at all.
texture = "textureLod(" + sampler + ", coords, lod)";
texture = "textureLod(" + sampler + ", coords, " + op_c + ')';
break;
}
default: {
@@ -2659,6 +2633,7 @@ private:
break;
}
case OpCode::Id::TEXS: {
std::string coord;
Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
bool is_array{instr.texs.IsArrayTexture()};
@@ -2671,21 +2646,17 @@ private:
if (depth_compare)
num_coordinates += 1;
// Scope to avoid variable name overlaps.
shader.AddLine('{');
++shader.scope;
switch (num_coordinates) {
case 2: {
if (is_array) {
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + index + ");");
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
} else {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
}
break;
}
@@ -2695,13 +2666,13 @@ private:
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
index + ");");
coord =
"vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + ");";
} else {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");");
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
}
break;
}
@@ -2712,7 +2683,7 @@ private:
// Fallback to interpreting as a 2D texture for now
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
texture_type = Tegra::Shader::TextureType::Texture2D;
is_array = false;
}
@@ -2744,16 +2715,14 @@ private:
}
}
if (!depth_compare) {
WriteTexsInstruction(instr, texture);
WriteTexsInstruction(instr, coord, texture);
} else {
WriteTexsInstruction(instr, "vec4(" + texture + ')');
WriteTexsInstruction(instr, coord, "vec4(" + texture + ')');
}
shader.AddLine('}');
--shader.scope;
break;
}
case OpCode::Id::TLDS: {
std::string coord;
const Tegra::Shader::TextureType texture_type{instr.tlds.GetTextureType()};
const bool is_array{instr.tlds.IsArrayTexture()};
@@ -2767,16 +2736,12 @@ private:
UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ),
"MZ is not implemented");
u32 extra_op_offset = 0;
// Scope to avoid variable name overlaps.
shader.AddLine('{');
++shader.scope;
u32 op_c_offset = 0;
switch (texture_type) {
case Tegra::Shader::TextureType::Texture1D: {
const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
shader.AddLine("int coords = " + x + ';');
coord = "int coords = " + x + ';';
break;
}
case Tegra::Shader::TextureType::Texture2D: {
@@ -2784,8 +2749,8 @@ private:
const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
const std::string y = regs.GetRegisterAsInteger(instr.gpr20);
shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
extra_op_offset = 1;
coord = "ivec2 coords = ivec2(" + x + ", " + y + ");";
op_c_offset = 1;
break;
}
default:
@@ -2800,10 +2765,9 @@ private:
break;
}
case Tegra::Shader::TextureProcessMode::LL: {
shader.AddLine(
"float lod = " +
regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';');
texture = "texelFetch(" + sampler + ", coords, lod)";
const std::string op_c =
regs.GetRegisterAsInteger(instr.gpr20.Value() + op_c_offset);
texture = "texelFetch(" + sampler + ", coords, " + op_c + ')';
break;
}
default: {
@@ -2812,10 +2776,7 @@ private:
static_cast<u32>(instr.tlds.GetTextureProcessMode()));
}
}
WriteTexsInstruction(instr, texture);
--shader.scope;
shader.AddLine('}');
WriteTexsInstruction(instr, coord, texture);
break;
}
case OpCode::Id::TLD4: {
@@ -2838,23 +2799,18 @@ private:
if (depth_compare)
num_coordinates += 1;
// Add an extra scope and declare the texture coords inside to prevent
// overwriting them in case they are used as outputs of the texs instruction.
shader.AddLine('{');
++shader.scope;
switch (num_coordinates) {
case 2: {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
break;
}
case 3: {
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");");
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
break;
}
default:
@@ -2862,13 +2818,17 @@ private:
static_cast<u32>(num_coordinates));
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
texture_type = Tegra::Shader::TextureType::Texture2D;
}
const std::string sampler =
GetSampler(instr.sampler, texture_type, false, depth_compare);
// Add an extra scope and declare the texture coords inside to prevent
// overwriting them in case they are used as outputs of the texs instruction.
shader.AddLine("{");
++shader.scope;
shader.AddLine(coord);
const std::string texture = "textureGather(" + sampler + ", coords, " +
std::to_string(instr.tld4.component) + ')';
if (!depth_compare) {
@@ -2885,7 +2845,7 @@ private:
regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
}
--shader.scope;
shader.AddLine('}');
shader.AddLine("}");
break;
}
case OpCode::Id::TLD4S: {
@@ -2896,10 +2856,6 @@ private:
instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
"AOFFI is not implemented");
// Scope to avoid variable name overlaps.
shader.AddLine('{');
++shader.scope;
const bool depth_compare =
instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
@@ -2907,33 +2863,28 @@ private:
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
const std::string sampler = GetSampler(
instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare);
std::string coord;
if (!depth_compare) {
shader.AddLine("vec2 coords = vec2(" + op_a + ", " + op_b + ");");
coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
} else {
// Note: TLD4S coordinate encoding works just like TEXS's
shader.AddLine(
"float op_y = " + regs.GetRegisterAsFloat(instr.gpr8.Value() + 1) + ';');
shader.AddLine("vec3 coords = vec3(" + op_a + ", op_y, " + op_b + ");");
const std::string op_c = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
coord = "vec3 coords = vec3(" + op_a + ", " + op_c + ", " + op_b + ");";
}
const std::string texture = "textureGather(" + sampler + ", coords, " +
std::to_string(instr.tld4s.component) + ')';
if (!depth_compare) {
WriteTexsInstruction(instr, texture);
WriteTexsInstruction(instr, coord, texture);
} else {
WriteTexsInstruction(instr, "vec4(" + texture + ')');
WriteTexsInstruction(instr, coord, "vec4(" + texture + ')');
}
--shader.scope;
shader.AddLine('}');
break;
}
case OpCode::Id::TXQ: {
UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
"NODEP is not implemented");
++shader.scope;
shader.AddLine('{');
// TODO: the new commits on the texture refactor, change the way samplers work.
// Sadly, not all texture instructions specify the type of texture their sampler
// uses. This must be fixed at a later instance.
@@ -2941,14 +2892,8 @@ private:
GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false);
switch (instr.txq.query_type) {
case Tegra::Shader::TextureQueryType::Dimension: {
const std::string texture = "textureSize(" + sampler + ", " +
regs.GetRegisterAsInteger(instr.gpr8) + ')';
const std::string mip_level = "textureQueryLevels(" + sampler + ')';
shader.AddLine("ivec2 sizes = " + texture + ';');
regs.SetRegisterToInteger(instr.gpr0, true, 0, "sizes.x", 1, 1);
regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1);
regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1);
regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1);
const std::string texture = "textureQueryLevels(" + sampler + ')';
regs.SetRegisterToInteger(instr.gpr0, true, 0, texture, 1, 1);
break;
}
default: {
@@ -2956,8 +2901,6 @@ private:
static_cast<u32>(instr.txq.query_type.Value()));
}
}
--shader.scope;
shader.AddLine('}');
break;
}
case OpCode::Id::TMML: {
@@ -3140,8 +3083,7 @@ private:
break;
}
case OpCode::Type::PredicateSetRegister: {
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in PSET is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "PSET Generates an unhandled Control Code");
const std::string op_a =
GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
@@ -3200,14 +3142,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 condition_code = regs.GetConditionCode(instr.csetp.cc);
const std::string control_code = regs.GetControlCode(instr.csetp.cc);
if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) {
SetPredicate(instr.csetp.pred3,
'(' + condition_code + ") " + combiner + " (" + pred + ')');
'(' + control_code + ") " + combiner + " (" + pred + ')');
}
if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
SetPredicate(instr.csetp.pred0,
"!(" + condition_code + ") " + combiner + " (" + pred + ')');
"!(" + control_code + ") " + combiner + " (" + pred + ')');
}
break;
}
@@ -3338,8 +3280,7 @@ private:
case OpCode::Type::Xmad: {
UNIMPLEMENTED_IF(instr.xmad.sign_a);
UNIMPLEMENTED_IF(instr.xmad.sign_b);
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in XMAD is not implemented");
UNIMPLEMENTED_IF_MSG(instr.generates_cc, "XMAD Generates an unhandled Control Code");
std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)};
std::string op_b;
@@ -3431,9 +3372,9 @@ private:
default: {
switch (opcode->get().GetId()) {
case OpCode::Id::EXIT: {
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));
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));
if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
EmitFragmentOutputsWrite();
@@ -3465,9 +3406,9 @@ private:
case OpCode::Id::KIL: {
UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always);
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));
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));
// Enclose "discard" in a conditional, so that GLSL compilation does not complain
// about unexecuted instructions that may follow this.
@@ -3529,9 +3470,9 @@ private:
UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
"BRA with constant buffers are not implemented");
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 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 u32 target = offset + instr.bra.GetBranchTarget();
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
@@ -3574,9 +3515,9 @@ private:
break;
}
case OpCode::Id::SYNC: {
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));
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));
// The SYNC opcode jumps to the address previously set by the SSY opcode
EmitPopFromFlowStack();
@@ -3584,10 +3525,10 @@ private:
}
case OpCode::Id::BRK: {
// The BRK opcode jumps to the address previously set by the PBK opcode
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));
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));
}
EmitPopFromFlowStack();
break;
}
@@ -3598,9 +3539,6 @@ 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);
@@ -3620,6 +3558,10 @@ 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: {
@@ -3771,7 +3713,6 @@ private:
Maxwell3D::Regs::ShaderStage stage;
const std::string& suffix;
u64 local_memory_size;
std::size_t shader_length;
ShaderWriter shader;
ShaderWriter declarations;
@@ -3790,10 +3731,9 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
Maxwell3D::Regs::ShaderStage stage,
const std::string& suffix) {
try {
ControlFlowAnalyzer analyzer(program_code, main_offset, suffix);
const auto subroutines = analyzer.GetSubroutines();
GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix,
analyzer.GetShaderLength());
const auto subroutines =
ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
} catch (const DecompileFail& exception) {
LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());

View File

@@ -163,7 +163,6 @@ 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>;

View File

@@ -92,6 +92,13 @@ OpenGLState::OpenGLState() {
point.size = 1;
fragment_color_clamp.enabled = false;
polygon_offset.fill_enable = false;
polygon_offset.line_enable = false;
polygon_offset.point_enable = false;
polygon_offset.factor = 0.0f;
polygon_offset.units = 0.0f;
polygon_offset.clamp = 0.0f;
}
void OpenGLState::ApplyDefaultState() {
@@ -233,28 +240,6 @@ 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) {
@@ -264,9 +249,7 @@ 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, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height));
glViewportIndexedf(i, 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) {
@@ -294,7 +277,8 @@ 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(updated.x, updated.y, updated.width, updated.height);
glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y),
static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.height));
}
if (updated.depth_range_near != current.depth_range_near ||
updated.depth_range_far != current.depth_range_far) {
@@ -362,14 +346,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) {
glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
glBlendFuncSeparateiARB(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) {
glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
updated.a_equation);
glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
updated.a_equation);
}
}
@@ -406,6 +390,55 @@ void OpenGLState::ApplyLogicOp() const {
}
}
void OpenGLState::ApplyPolygonOffset() const {
const bool fill_enable_changed =
polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable;
const bool line_enable_changed =
polygon_offset.line_enable != cur_state.polygon_offset.line_enable;
const bool point_enable_changed =
polygon_offset.point_enable != cur_state.polygon_offset.point_enable;
const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor;
const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units;
const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp;
if (fill_enable_changed) {
if (polygon_offset.fill_enable) {
glEnable(GL_POLYGON_OFFSET_FILL);
} else {
glDisable(GL_POLYGON_OFFSET_FILL);
}
}
if (line_enable_changed) {
if (polygon_offset.line_enable) {
glEnable(GL_POLYGON_OFFSET_LINE);
} else {
glDisable(GL_POLYGON_OFFSET_LINE);
}
}
if (point_enable_changed) {
if (polygon_offset.point_enable) {
glEnable(GL_POLYGON_OFFSET_POINT);
} else {
glDisable(GL_POLYGON_OFFSET_POINT);
}
}
if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) &&
(factor_changed || units_changed || clamp_changed)) {
if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) {
glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp);
} else {
glPolygonOffset(polygon_offset.factor, polygon_offset.units);
UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0,
"Unimplemented Depth polygon offset clamp.");
}
}
}
void OpenGLState::ApplyTextures() const {
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
const auto& texture_unit = texture_units[i];
@@ -532,6 +565,7 @@ void OpenGLState::Apply() const {
ApplyLogicOp();
ApplyTextures();
ApplySamplers();
ApplyPolygonOffset();
cur_state = *this;
}

View File

@@ -156,10 +156,10 @@ public:
} draw;
struct viewport {
GLint x;
GLint y;
GLint width;
GLint height;
GLfloat x;
GLfloat y;
GLfloat width;
GLfloat height;
GLfloat depth_range_near; // GL_DEPTH_RANGE
GLfloat depth_range_far; // GL_DEPTH_RANGE
struct {
@@ -176,6 +176,15 @@ public:
float size; // GL_POINT_SIZE
} point;
struct {
bool point_enable;
bool line_enable;
bool fill_enable;
GLfloat units;
GLfloat factor;
GLfloat clamp;
} polygon_offset;
std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE
OpenGLState();
@@ -206,7 +215,6 @@ public:
OpenGLState& ResetBuffer(GLuint handle);
OpenGLState& ResetVertexArray(GLuint handle);
OpenGLState& ResetFramebuffer(GLuint handle);
void EmulateViewportWithScissor();
private:
static OpenGLState cur_state;
@@ -226,6 +234,7 @@ private:
void ApplyLogicOp() const;
void ApplyTextures() const;
void ApplySamplers() const;
void ApplyPolygonOffset() const;
};
} // namespace OpenGL

View File

@@ -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_4_3) {
if (!GLAD_GL_VERSION_3_3) {
return false;
}

View File

@@ -82,8 +82,8 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
: QString::fromStdU16String(parameters.submit_text),
QDialogButtonBox::AcceptRole);
connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject);
connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::Submit);
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::accept() {
void QtSoftwareKeyboardDialog::Submit() {
ok = true;
text = line_edit->text().toStdU16String();
QDialog::accept();
accept();
}
void QtSoftwareKeyboardDialog::reject() {
void QtSoftwareKeyboardDialog::Reject() {
ok = false;
text.clear();
QDialog::reject();
accept();
}
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 = std::move(out);
text_output = out;
emit MainWindowGetText(parameters);
}
void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message,
std::function<void()> finished_check) const {
this->finished_check = std::move(finished_check);
this->finished_check = finished_check;
emit MainWindowTextCheckDialog(error_message);
}

View File

@@ -33,8 +33,8 @@ public:
Core::Frontend::SoftwareKeyboardParameters parameters);
~QtSoftwareKeyboardDialog() override;
void accept() override;
void reject() override;
void Submit();
void Reject();
std::u16string GetText() const;
bool GetStatus() const;
@@ -70,10 +70,11 @@ signals:
void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const;
void MainWindowTextCheckDialog(std::u16string error_message) const;
private:
public slots:
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;
};

View File

@@ -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(4, 3);
fmt.setVersion(3, 3);
fmt.setProfile(QGLFormat::CoreProfile);
fmt.setSwapInterval(false);

View File

@@ -432,7 +432,6 @@ 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();
@@ -639,7 +638,6 @@ 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();

View File

@@ -34,7 +34,6 @@ 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);
}
@@ -44,7 +43,6 @@ 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;

View File

@@ -145,16 +145,6 @@
</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>

View File

@@ -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</string>
<string>Internal Resolution:(Currently does nothing.)</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>

View File

@@ -518,18 +518,32 @@ 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");
@@ -548,8 +562,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
render_window->MakeCurrent();
if (!gladLoadGL()) {
QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3 Core!"),
tr("Your GPU may not support OpenGL 4.3, or you do not "
QMessageBox::critical(this, tr("Error while initializing OpenGL 3.3 Core!"),
tr("Your GPU may not support OpenGL 3.3, or you do not "
"have the latest graphics driver."));
return false;
}

View File

@@ -366,7 +366,6 @@ 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

View File

@@ -206,8 +206,6 @@ 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

View File

@@ -111,18 +111,32 @@ 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");
@@ -143,7 +157,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
exit(1);
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
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);