summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/core.cpp28
-rw-r--r--src/core/core.h12
-rw-r--r--src/core/hle/kernel/resource_limit.cpp46
-rw-r--r--src/core/hle/kernel/resource_limit.h26
-rw-r--r--src/core/hle/kernel/svc.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp45
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp2
-rw-r--r--src/core/hle/service/service.cpp52
-rw-r--r--src/core/hle/service/service.h2
-rw-r--r--src/core/hle/service/sm/sm.cpp4
-rw-r--r--src/core/hle/service/sm/sm.h6
-rw-r--r--src/core/hle/service/vi/vi.cpp34
-rw-r--r--src/video_core/engines/shader_bytecode.h438
-rw-r--r--src/video_core/memory_manager.cpp53
-rw-r--r--src/video_core/memory_manager.h6
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp23
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h14
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h39
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp184
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp3
-rw-r--r--src/video_core/textures/decoders.cpp3
-rw-r--r--src/video_core/textures/texture.h1
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp27
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h5
-rw-r--r--src/yuzu_cmd/yuzu.cpp12
33 files changed, 726 insertions, 371 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 9f5507a65..ee4af4dcc 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -12,10 +12,13 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h"
+#include "core/hle/service/sm/controller.h"
+#include "core/hle/service/sm/sm.h"
#include "core/hw/hw.h"
#include "core/loader/loader.h"
#include "core/memory_setup.h"
@@ -26,6 +29,8 @@ namespace Core {
/*static*/ System System::s_instance;
+System::~System() = default;
+
System::ResultStatus System::RunLoop(bool tight_loop) {
status = ResultStatus::Success;
if (!cpu_core) {
@@ -167,10 +172,12 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
telemetry_session = std::make_unique<Core::TelemetrySession>();
+ service_manager = std::make_shared<Service::SM::ServiceManager>();
+
HW::Init();
Kernel::Init(system_mode);
scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get());
- Service::Init();
+ Service::Init(service_manager);
GDBStub::Init();
if (!VideoCore::Init(emu_window)) {
@@ -200,17 +207,26 @@ void System::Shutdown() {
VideoCore::Shutdown();
GDBStub::Shutdown();
Service::Shutdown();
- scheduler = nullptr;
+ scheduler.reset();
Kernel::Shutdown();
HW::Shutdown();
- telemetry_session = nullptr;
- gpu_core = nullptr;
- cpu_core = nullptr;
+ service_manager.reset();
+ telemetry_session.reset();
+ gpu_core.reset();
+ cpu_core.reset();
CoreTiming::Shutdown();
- app_loader = nullptr;
+ app_loader.reset();
LOG_DEBUG(Core, "Shutdown OK");
}
+Service::SM::ServiceManager& System::ServiceManager() {
+ return *service_manager;
+}
+
+const Service::SM::ServiceManager& System::ServiceManager() const {
+ return *service_manager;
+}
+
} // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index f497dc022..f81cbfb3c 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -19,10 +19,16 @@
class EmuWindow;
class ARM_Interface;
+namespace Service::SM {
+class ServiceManager;
+}
+
namespace Core {
class System {
public:
+ ~System();
+
/**
* Gets the instance of the System singleton class.
* @returns Reference to the instance of the System singleton class.
@@ -137,6 +143,9 @@ public:
return *app_loader;
}
+ Service::SM::ServiceManager& ServiceManager();
+ const Service::SM::ServiceManager& ServiceManager() const;
+
void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) {
debug_context = std::move(context);
}
@@ -171,6 +180,9 @@ private:
/// When true, signals that a reschedule should happen
bool reschedule_pending{};
+ /// Service manager
+ std::shared_ptr<Service::SM::ServiceManager> service_manager;
+
/// Telemetry session for this emulation session
std::unique_ptr<Core::TelemetrySession> telemetry_session;
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 0149a3ed6..88ca8ad7e 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -34,57 +34,57 @@ SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory cat
}
}
-s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const {
+s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
switch (resource) {
- case COMMIT:
+ case ResourceType::Commit:
return current_commit;
- case THREAD:
+ case ResourceType::Thread:
return current_threads;
- case EVENT:
+ case ResourceType::Event:
return current_events;
- case MUTEX:
+ case ResourceType::Mutex:
return current_mutexes;
- case SEMAPHORE:
+ case ResourceType::Semaphore:
return current_semaphores;
- case TIMER:
+ case ResourceType::Timer:
return current_timers;
- case SHARED_MEMORY:
+ case ResourceType::SharedMemory:
return current_shared_mems;
- case ADDRESS_ARBITER:
+ case ResourceType::AddressArbiter:
return current_address_arbiters;
- case CPU_TIME:
+ case ResourceType::CPUTime:
return current_cpu_time;
default:
- LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
+ LOG_ERROR(Kernel, "Unknown resource type=%08X", static_cast<u32>(resource));
UNIMPLEMENTED();
return 0;
}
}
-u32 ResourceLimit::GetMaxResourceValue(u32 resource) const {
+u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
switch (resource) {
- case PRIORITY:
+ case ResourceType::Priority:
return max_priority;
- case COMMIT:
+ case ResourceType::Commit:
return max_commit;
- case THREAD:
+ case ResourceType::Thread:
return max_threads;
- case EVENT:
+ case ResourceType::Event:
return max_events;
- case MUTEX:
+ case ResourceType::Mutex:
return max_mutexes;
- case SEMAPHORE:
+ case ResourceType::Semaphore:
return max_semaphores;
- case TIMER:
+ case ResourceType::Timer:
return max_timers;
- case SHARED_MEMORY:
+ case ResourceType::SharedMemory:
return max_shared_mems;
- case ADDRESS_ARBITER:
+ case ResourceType::AddressArbiter:
return max_address_arbiters;
- case CPU_TIME:
+ case ResourceType::CPUTime:
return max_cpu_time;
default:
- LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
+ LOG_ERROR(Kernel, "Unknown resource type=%08X", static_cast<u32>(resource));
UNIMPLEMENTED();
return 0;
}
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 1a0ca11f1..cc689a27a 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -16,17 +16,17 @@ enum class ResourceLimitCategory : u8 {
OTHER = 3
};
-enum ResourceTypes {
- PRIORITY = 0,
- COMMIT = 1,
- THREAD = 2,
- EVENT = 3,
- MUTEX = 4,
- SEMAPHORE = 5,
- TIMER = 6,
- SHARED_MEMORY = 7,
- ADDRESS_ARBITER = 8,
- CPU_TIME = 9,
+enum class ResourceType {
+ Priority = 0,
+ Commit = 1,
+ Thread = 2,
+ Event = 3,
+ Mutex = 4,
+ Semaphore = 5,
+ Timer = 6,
+ SharedMemory = 7,
+ AddressArbiter = 8,
+ CPUTime = 9,
};
class ResourceLimit final : public Object {
@@ -60,14 +60,14 @@ public:
* @param resource Requested resource type
* @returns The current value of the resource type
*/
- s32 GetCurrentResourceValue(u32 resource) const;
+ s32 GetCurrentResourceValue(ResourceType resource) const;
/**
* Gets the max value for the specified resource.
* @param resource Requested resource type
* @returns The max value of the resource type
*/
- u32 GetMaxResourceValue(u32 resource) const;
+ u32 GetMaxResourceValue(ResourceType resource) const;
/// Name of resource limit object.
std::string name;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index a3015cf7a..c22da6e47 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -388,7 +388,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
// Note: The kernel uses the current process's resource limit instead of
// the one from the thread owner's resource limit.
SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
- if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) {
+ if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) {
return ERR_NOT_AUTHORIZED;
}
@@ -517,7 +517,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
}
SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
- if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) {
+ if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) {
return ERR_NOT_AUTHORIZED;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 61f22b1a5..aa6c7e8dc 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -13,7 +13,7 @@
namespace Service::Nvidia::Devices {
u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
- UNIMPLEMENTED();
+ UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 71e844959..8e7ca6123 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -27,6 +27,11 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vecto
case IoctlCommand::IocGetVaRegionsCommand:
return GetVARegions(input, output);
}
+
+ if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand)
+ return Remap(input, output);
+
+ UNIMPLEMENTED_MSG("Unimplemented ioctl command");
return 0;
}
@@ -56,6 +61,36 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
return 0;
}
+u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
+ size_t num_entries = input.size() / sizeof(IoctlRemapEntry);
+
+ NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries);
+
+ std::vector<IoctlRemapEntry> entries(num_entries);
+ std::memcpy(entries.data(), input.data(), input.size());
+
+ auto& gpu = Core::System::GetInstance().GPU();
+
+ for (const auto& entry : entries) {
+ NGLOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}",
+ entry.offset, entry.nvmap_handle, entry.pages);
+ Tegra::GPUVAddr offset = static_cast<Tegra::GPUVAddr>(entry.offset) << 0x10;
+
+ auto object = nvmap_dev->GetObject(entry.nvmap_handle);
+ ASSERT(object);
+
+ ASSERT(object->status == nvmap::Object::Status::Allocated);
+
+ u64 size = static_cast<u64>(entry.pages) << 0x10;
+ ASSERT(size <= object->size);
+
+ Tegra::GPUVAddr returned = gpu.memory_manager->MapBufferEx(object->addr, offset, size);
+ ASSERT(returned == offset);
+ }
+ std::memcpy(output.data(), entries.data(), output.size());
+ return 0;
+}
+
u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
IoctlMapBufferEx params{};
std::memcpy(&params, input.data(), input.size());
@@ -73,6 +108,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
auto object = nvmap_dev->GetObject(params.nvmap_handle);
ASSERT(object);
+ // We can only map objects that have already been assigned a CPU address.
+ ASSERT(object->status == nvmap::Object::Status::Allocated);
+
+ ASSERT(params.buffer_offset == 0);
+
+ // The real nvservices doesn't make a distinction between handles and ids, and
+ // object can only have one handle and it will be the same as its id. Assert that this is the
+ // case to prevent unexpected behavior.
+ ASSERT(object->id == params.nvmap_handle);
+
auto& gpu = Core::System::GetInstance().GPU();
if (params.flags & 1) {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index d86c3ebd9..f2dd0c3b3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -26,6 +26,7 @@ private:
enum class IoctlCommand : u32_le {
IocInitalizeExCommand = 0x40284109,
IocAllocateSpaceCommand = 0xC0184102,
+ IocRemapCommand = 0x00000014,
IocMapBufferExCommand = 0xC0284106,
IocBindChannelCommand = 0x40044101,
IocGetVaRegionsCommand = 0xC0404108,
@@ -54,6 +55,16 @@ private:
};
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
+ struct IoctlRemapEntry {
+ u16_le flags;
+ u16_le kind;
+ u32_le nvmap_handle;
+ INSERT_PADDING_WORDS(1);
+ u32_le offset;
+ u32_le pages;
+ };
+ static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
+
struct IoctlMapBufferEx {
u32_le flags; // bit0: fixed_offset, bit2: cacheable
u32_le kind; // -1 is default
@@ -91,6 +102,7 @@ private:
u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 660a0f665..6e1ba1ac7 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -18,7 +18,7 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<
case IoctlCommand::IocCtrlEventWaitCommand:
return IocCtrlEventWait(input, output);
}
- UNIMPLEMENTED();
+ UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 18ea12ef5..b715723d3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -25,7 +25,7 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
case IoctlCommand::IocZcullGetInfo:
return ZCullGetInfo(input, output);
}
- UNIMPLEMENTED();
+ UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index a16e90457..dab6d0533 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -40,7 +40,7 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u
}
}
- UNIMPLEMENTED();
+ UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
};
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 4bb1f57f6..dcf079d91 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -32,7 +32,7 @@ u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& o
return IocParam(input, output);
}
- UNIMPLEMENTED();
+ UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
}
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index c5490c1ae..08ce29677 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -145,7 +145,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
return ResultCode(ErrorModule::HIPC, ErrorDescription::RemoteProcessDead);
}
case IPC::CommandType::Control: {
- SM::g_service_manager->InvokeControlRequest(context);
+ Core::System::GetInstance().ServiceManager().InvokeControlRequest(context);
break;
}
case IPC::CommandType::Request: {
@@ -170,42 +170,40 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
}
/// Initialize ServiceManager
-void Init() {
+void Init(std::shared_ptr<SM::ServiceManager>& sm) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
// here and pass it into the respective InstallInterfaces functions.
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
- SM::g_service_manager = std::make_shared<SM::ServiceManager>();
- SM::ServiceManager::InstallInterfaces(SM::g_service_manager);
-
- Account::InstallInterfaces(*SM::g_service_manager);
- AM::InstallInterfaces(*SM::g_service_manager, nv_flinger);
- AOC::InstallInterfaces(*SM::g_service_manager);
- APM::InstallInterfaces(*SM::g_service_manager);
- Audio::InstallInterfaces(*SM::g_service_manager);
- Fatal::InstallInterfaces(*SM::g_service_manager);
- FileSystem::InstallInterfaces(*SM::g_service_manager);
- Friend::InstallInterfaces(*SM::g_service_manager);
- HID::InstallInterfaces(*SM::g_service_manager);
- LM::InstallInterfaces(*SM::g_service_manager);
- NFP::InstallInterfaces(*SM::g_service_manager);
- NIFM::InstallInterfaces(*SM::g_service_manager);
- NS::InstallInterfaces(*SM::g_service_manager);
- Nvidia::InstallInterfaces(*SM::g_service_manager);
- PCTL::InstallInterfaces(*SM::g_service_manager);
- Sockets::InstallInterfaces(*SM::g_service_manager);
- SPL::InstallInterfaces(*SM::g_service_manager);
- SSL::InstallInterfaces(*SM::g_service_manager);
- Time::InstallInterfaces(*SM::g_service_manager);
- VI::InstallInterfaces(*SM::g_service_manager, nv_flinger);
- Set::InstallInterfaces(*SM::g_service_manager);
+ SM::ServiceManager::InstallInterfaces(sm);
+
+ Account::InstallInterfaces(*sm);
+ AM::InstallInterfaces(*sm, nv_flinger);
+ AOC::InstallInterfaces(*sm);
+ APM::InstallInterfaces(*sm);
+ Audio::InstallInterfaces(*sm);
+ Fatal::InstallInterfaces(*sm);
+ FileSystem::InstallInterfaces(*sm);
+ Friend::InstallInterfaces(*sm);
+ HID::InstallInterfaces(*sm);
+ LM::InstallInterfaces(*sm);
+ NFP::InstallInterfaces(*sm);
+ NIFM::InstallInterfaces(*sm);
+ NS::InstallInterfaces(*sm);
+ Nvidia::InstallInterfaces(*sm);
+ PCTL::InstallInterfaces(*sm);
+ Sockets::InstallInterfaces(*sm);
+ SPL::InstallInterfaces(*sm);
+ SSL::InstallInterfaces(*sm);
+ Time::InstallInterfaces(*sm);
+ VI::InstallInterfaces(*sm, nv_flinger);
+ Set::InstallInterfaces(*sm);
LOG_DEBUG(Service, "initialized OK");
}
/// Shutdown ServiceManager
void Shutdown() {
- SM::g_service_manager = nullptr;
g_kernel_named_ports.clear();
LOG_DEBUG(Service, "shutdown OK");
}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 9c2e826da..fee841d46 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -178,7 +178,7 @@ private:
};
/// Initialize ServiceManager
-void Init();
+void Init(std::shared_ptr<SM::ServiceManager>& sm);
/// Shutdown ServiceManager
void Shutdown();
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 297a4f2c6..4578fc05f 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -14,6 +14,8 @@
namespace Service::SM {
+ServiceManager::~ServiceManager() = default;
+
void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
controller_interface->InvokeRequest(context);
}
@@ -72,7 +74,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToSer
return client_port->Connect();
}
-std::shared_ptr<ServiceManager> g_service_manager;
+SM::~SM() = default;
/**
* SM::Initialize service function
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 40421cfd5..13f5c4c28 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -23,7 +23,7 @@ namespace Service::SM {
class SM final : public ServiceFramework<SM> {
public:
SM(std::shared_ptr<ServiceManager> service_manager);
- ~SM() = default;
+ ~SM() override;
private:
void Initialize(Kernel::HLERequestContext& ctx);
@@ -44,6 +44,8 @@ class ServiceManager {
public:
static void InstallInterfaces(std::shared_ptr<ServiceManager> self);
+ ~ServiceManager();
+
ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
unsigned int max_sessions);
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
@@ -59,6 +61,4 @@ private:
std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services;
};
-extern std::shared_ptr<ServiceManager> g_service_manager;
-
} // namespace Service::SM
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index b697b5f73..36ae2215f 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -582,7 +582,7 @@ public:
{2203, nullptr, "SetLayerSize"},
{2204, nullptr, "GetLayerZ"},
{2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
- {2207, nullptr, "SetLayerVisibility"},
+ {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"},
{2209, nullptr, "SetLayerAlpha"},
{2312, nullptr, "CreateStrayLayer"},
{2400, nullptr, "OpenIndirectLayer"},
@@ -632,6 +632,16 @@ private:
IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
rb.Push(RESULT_SUCCESS);
}
+
+ void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ u64 layer_id = rp.Pop<u64>();
+ bool visibility = rp.Pop<bool>();
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x%x, visibility=%u", layer_id,
+ visibility);
+ }
};
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
@@ -663,7 +673,7 @@ public:
{4206, nullptr, "SetDefaultDisplay"},
{6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
{6001, nullptr, "RemoveFromLayerStack"},
- {6002, nullptr, "SetLayerVisibility"},
+ {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"},
{6003, nullptr, "SetLayerConfig"},
{6004, nullptr, "AttachLayerPresentationTracer"},
{6005, nullptr, "DetachLayerPresentationTracer"},
@@ -745,6 +755,16 @@ private:
rb.Push(RESULT_SUCCESS);
}
+ void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ u64 layer_id = rp.Pop<u64>();
+ bool visibility = rp.Pop<bool>();
+ IPC::ResponseBuilder rb = rp.MakeBuilder(2, 0, 0);
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x%x, visibility=%u", layer_id,
+ visibility);
+ }
+
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
};
@@ -815,15 +835,15 @@ private:
IPC::RequestParser rp{ctx};
u64 display_id = rp.Pop<u64>();
- IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0);
+ IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0);
rb.Push(RESULT_SUCCESS);
if (Settings::values.use_docked_mode) {
- rb.Push(static_cast<u32>(DisplayResolution::DockedWidth));
- rb.Push(static_cast<u32>(DisplayResolution::DockedHeight));
+ rb.Push(static_cast<u64>(DisplayResolution::DockedWidth));
+ rb.Push(static_cast<u64>(DisplayResolution::DockedHeight));
} else {
- rb.Push(static_cast<u32>(DisplayResolution::UndockedWidth));
- rb.Push(static_cast<u32>(DisplayResolution::UndockedHeight));
+ rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth));
+ rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight));
}
}
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 7cd125f05..5a006aee5 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -4,15 +4,24 @@
#pragma once
+#include <bitset>
#include <cstring>
#include <map>
#include <string>
+#include <vector>
+
+#include <boost/optional.hpp>
+
#include "common/bit_field.h"
+#include "common/common_types.h"
namespace Tegra {
namespace Shader {
struct Register {
+ // Register 255 is special cased to always be 0
+ static constexpr size_t ZeroIndex = 255;
+
constexpr Register() = default;
constexpr Register(u64 value) : value(value) {}
@@ -86,181 +95,12 @@ union Uniform {
BitField<34, 5, u64> index;
};
-union OpCode {
- enum class Id : u64 {
- TEXS = 0x6C,
- IPA = 0xE0,
- FMUL32_IMM = 0x1E,
- FFMA_IMM = 0x65,
- FFMA_CR = 0x93,
- FFMA_RC = 0xA3,
- FFMA_RR = 0xB3,
-
- FADD_C = 0x98B,
- FMUL_C = 0x98D,
- MUFU = 0xA10,
- FADD_R = 0xB8B,
- FMUL_R = 0xB8D,
- LD_A = 0x1DFB,
- ST_A = 0x1DFE,
-
- FSETP_R = 0x5BB,
- FSETP_C = 0x4BB,
- EXIT = 0xE30,
- KIL = 0xE33,
-
- FMUL_IMM = 0x70D,
- FMUL_IMM_x = 0x72D,
- FADD_IMM = 0x70B,
- FADD_IMM_x = 0x72B,
- };
-
- enum class Type {
- Trivial,
- Arithmetic,
- Ffma,
- Flow,
- Memory,
- Unknown,
- };
-
- struct Info {
- Type type;
- std::string name;
- };
-
- OpCode() = default;
-
- constexpr OpCode(Id value) : value(static_cast<u64>(value)) {}
-
- constexpr OpCode(u64 value) : value{value} {}
-
- constexpr Id EffectiveOpCode() const {
- switch (op1) {
- case Id::TEXS:
- return op1;
- }
-
- switch (op2) {
- case Id::IPA:
- case Id::FMUL32_IMM:
- return op2;
- }
-
- switch (op3) {
- case Id::FFMA_IMM:
- case Id::FFMA_CR:
- case Id::FFMA_RC:
- case Id::FFMA_RR:
- return op3;
- }
-
- switch (op4) {
- case Id::EXIT:
- case Id::FSETP_R:
- case Id::FSETP_C:
- case Id::KIL:
- return op4;
- }
-
- switch (op5) {
- case Id::MUFU:
- case Id::LD_A:
- case Id::ST_A:
- case Id::FADD_R:
- case Id::FADD_C:
- case Id::FMUL_R:
- case Id::FMUL_C:
- return op5;
-
- case Id::FMUL_IMM:
- case Id::FMUL_IMM_x:
- return Id::FMUL_IMM;
-
- case Id::FADD_IMM:
- case Id::FADD_IMM_x:
- return Id::FADD_IMM;
- }
-
- return static_cast<Id>(value);
- }
-
- static const Info& GetInfo(const OpCode& opcode) {
- static const std::map<Id, Info> info_table{BuildInfoTable()};
- const auto& search{info_table.find(opcode.EffectiveOpCode())};
- if (search != info_table.end()) {
- return search->second;
- }
-
- static const Info unknown{Type::Unknown, "UNK"};
- return unknown;
- }
-
- constexpr operator Id() const {
- return static_cast<Id>(value);
- }
-
- constexpr OpCode operator<<(size_t bits) const {
- return value << bits;
- }
-
- constexpr OpCode operator>>(size_t bits) const {
- return value >> bits;
- }
-
- template <typename T>
- constexpr u64 operator-(const T& oth) const {
- return value - oth;
- }
-
- constexpr u64 operator&(const OpCode& oth) const {
- return value & oth.value;
- }
-
- constexpr u64 operator~() const {
- return ~value;
- }
-
- static std::map<Id, Info> BuildInfoTable() {
- std::map<Id, Info> info_table;
- info_table[Id::TEXS] = {Type::Memory, "texs"};
- info_table[Id::LD_A] = {Type::Memory, "ld_a"};
- info_table[Id::ST_A] = {Type::Memory, "st_a"};
- info_table[Id::MUFU] = {Type::Arithmetic, "mufu"};
- info_table[Id::FFMA_IMM] = {Type::Ffma, "ffma_imm"};
- info_table[Id::FFMA_CR] = {Type::Ffma, "ffma_cr"};
- info_table[Id::FFMA_RC] = {Type::Ffma, "ffma_rc"};
- info_table[Id::FFMA_RR] = {Type::Ffma, "ffma_rr"};
- info_table[Id::FADD_R] = {Type::Arithmetic, "fadd_r"};
- info_table[Id::FADD_C] = {Type::Arithmetic, "fadd_c"};
- info_table[Id::FADD_IMM] = {Type::Arithmetic, "fadd_imm"};
- info_table[Id::FMUL_R] = {Type::Arithmetic, "fmul_r"};
- info_table[Id::FMUL_C] = {Type::Arithmetic, "fmul_c"};
- info_table[Id::FMUL_IMM] = {Type::Arithmetic, "fmul_imm"};
- info_table[Id::FMUL32_IMM] = {Type::Arithmetic, "fmul32_imm"};
- info_table[Id::FSETP_C] = {Type::Arithmetic, "fsetp_c"};
- info_table[Id::FSETP_R] = {Type::Arithmetic, "fsetp_r"};
- info_table[Id::EXIT] = {Type::Trivial, "exit"};
- info_table[Id::IPA] = {Type::Trivial, "ipa"};
- info_table[Id::KIL] = {Type::Flow, "kil"};
- return info_table;
- }
-
- BitField<57, 7, Id> op1;
- BitField<56, 8, Id> op2;
- BitField<55, 9, Id> op3;
- BitField<52, 12, Id> op4;
- BitField<51, 13, Id> op5;
- u64 value{};
-};
-static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size");
-
} // namespace Shader
} // namespace Tegra
namespace std {
-// TODO(bunne): The below is forbidden by the C++ standard, but works fine. See #330.
+// TODO(bunnei): The below is forbidden by the C++ standard, but works fine. See #330.
template <>
struct make_unsigned<Tegra::Shader::Attribute> {
using type = Tegra::Shader::Attribute;
@@ -271,11 +111,6 @@ struct make_unsigned<Tegra::Shader::Register> {
using type = Tegra::Shader::Register;
};
-template <>
-struct make_unsigned<Tegra::Shader::OpCode> {
- using type = Tegra::Shader::OpCode;
-};
-
} // namespace std
namespace Tegra {
@@ -283,7 +118,23 @@ namespace Shader {
enum class Pred : u64 {
UnusedIndex = 0x7,
- NeverExecute = 0xf,
+ NeverExecute = 0xF,
+};
+
+enum class PredCondition : u64 {
+ LessThan = 1,
+ Equal = 2,
+ LessEqual = 3,
+ GreaterThan = 4,
+ NotEqual = 5,
+ GreaterEqual = 6,
+ // TODO(Subv): Other condition types
+};
+
+enum class PredOperation : u64 {
+ And = 0,
+ Or = 1,
+ Xor = 2,
};
enum class SubOp : u64 {
@@ -298,18 +149,24 @@ enum class SubOp : u64 {
union Instruction {
Instruction& operator=(const Instruction& instr) {
- hex = instr.hex;
+ value = instr.value;
return *this;
}
- OpCode opcode;
+ constexpr Instruction(u64 value) : value{value} {}
+
BitField<0, 8, Register> gpr0;
BitField<8, 8, Register> gpr8;
- BitField<16, 4, Pred> pred;
+ union {
+ BitField<16, 4, Pred> full_pred;
+ BitField<16, 3, u64> pred_index;
+ } pred;
+ BitField<19, 1, u64> negate_pred;
BitField<20, 8, Register> gpr20;
BitField<20, 7, SubOp> sub_op;
BitField<28, 8, Register> gpr28;
BitField<39, 8, Register> gpr39;
+ BitField<48, 16, u64> opcode;
union {
BitField<20, 19, u64> imm20_19;
@@ -343,6 +200,20 @@ union Instruction {
BitField<49, 1, u64> negate_c;
} ffma;
+ union {
+ BitField<0, 3, u64> pred0;
+ BitField<3, 3, u64> pred3;
+ BitField<7, 1, u64> abs_a;
+ BitField<39, 3, u64> pred39;
+ BitField<42, 1, u64> neg_pred;
+ BitField<43, 1, u64> neg_a;
+ BitField<44, 1, u64> abs_b;
+ BitField<45, 2, PredOperation> op;
+ BitField<47, 1, u64> ftz;
+ BitField<48, 4, PredCondition> cond;
+ BitField<56, 1, u64> neg_b;
+ } fsetp;
+
BitField<61, 1, u64> is_b_imm;
BitField<60, 1, u64> is_b_gpr;
BitField<59, 1, u64> is_c_gpr;
@@ -351,11 +222,218 @@ union Instruction {
Uniform uniform;
Sampler sampler;
- u64 hex;
+ u64 value;
};
static_assert(sizeof(Instruction) == 0x8, "Incorrect structure size");
static_assert(std::is_standard_layout<Instruction>::value,
"Structure does not have standard layout");
+class OpCode {
+public:
+ enum class Id {
+ KIL,
+ LD_A,
+ ST_A,
+ TEXQ, // Texture Query
+ TEXS, // Texture Fetch with scalar/non-vec4 source/destinations
+ TLDS, // Texture Load with scalar/non-vec4 source/destinations
+ EXIT,
+ IPA,
+ FFMA_IMM, // Fused Multiply and Add
+ FFMA_CR,
+ FFMA_RC,
+ FFMA_RR,
+ FADD_C,
+ FADD_R,
+ FADD_IMM,
+ FMUL_C,
+ FMUL_R,
+ FMUL_IMM,
+ FMUL32_IMM,
+ MUFU, // Multi-Function Operator
+ RRO, // Range Reduction Operator
+ F2F_C,
+ F2F_R,
+ F2F_IMM,
+ F2I_C,
+ F2I_R,
+ F2I_IMM,
+ I2F_C,
+ I2F_R,
+ I2F_IMM,
+ LOP32I,
+ MOV_C,
+ MOV_R,
+ MOV_IMM,
+ MOV32I,
+ SHR_C,
+ SHR_R,
+ SHR_IMM,
+ FSETP_C, // Set Predicate
+ FSETP_R,
+ FSETP_IMM,
+ ISETP_C,
+ ISETP_IMM,
+ ISETP_R,
+ };
+
+ enum class Type {
+ Trivial,
+ Arithmetic,
+ Ffma,
+ Flow,
+ Memory,
+ FloatPredicate,
+ IntegerPredicate,
+ Unknown,
+ };
+
+ class Matcher {
+ public:
+ Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)
+ : name{name}, mask{mask}, expected{expected}, id{id}, type{type} {}
+
+ const char* GetName() const {
+ return name;
+ }
+
+ u16 GetMask() const {
+ return mask;
+ }
+
+ Id GetId() const {
+ return id;
+ }
+
+ Type GetType() const {
+ return type;
+ }
+
+ /**
+ * Tests to see if the given instruction is the instruction this matcher represents.
+ * @param instruction The instruction to test
+ * @returns true if the given instruction matches.
+ */
+ bool Matches(u16 instruction) const {
+ return (instruction & mask) == expected;
+ }
+
+ private:
+ const char* name;
+ u16 mask;
+ u16 expected;
+ Id id;
+ Type type;
+ };
+
+ static boost::optional<const Matcher&> Decode(Instruction instr) {
+ static const auto table{GetDecodeTable()};
+
+ const auto matches_instruction = [instr](const auto& matcher) {
+ return matcher.Matches(static_cast<u16>(instr.opcode));
+ };
+
+ auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
+ return iter != table.end() ? boost::optional<const Matcher&>(*iter) : boost::none;
+ }
+
+private:
+ struct Detail {
+ private:
+ static constexpr size_t opcode_bitsize = 16;
+
+ /**
+ * Generates the mask and the expected value after masking from a given bitstring.
+ * A '0' in a bitstring indicates that a zero must be present at that bit position.
+ * A '1' in a bitstring indicates that a one must be present at that bit position.
+ */
+ static auto GetMaskAndExpect(const char* const bitstring) {
+ u16 mask = 0, expect = 0;
+ for (size_t i = 0; i < opcode_bitsize; i++) {
+ const size_t bit_position = opcode_bitsize - i - 1;
+ switch (bitstring[i]) {
+ case '0':
+ mask |= 1 << bit_position;
+ break;
+ case '1':
+ expect |= 1 << bit_position;
+ mask |= 1 << bit_position;
+ break;
+ default:
+ // Ignore
+ break;
+ }
+ }
+ return std::make_tuple(mask, expect);
+ }
+
+ public:
+ /// Creates a matcher that can match and parse instructions based on bitstring.
+ static auto GetMatcher(const char* const bitstring, OpCode::Id op, OpCode::Type type,
+ const char* const name) {
+ const auto mask_expect = GetMaskAndExpect(bitstring);
+ return Matcher(name, std::get<0>(mask_expect), std::get<1>(mask_expect), op, type);
+ }
+ };
+
+ static std::vector<Matcher> GetDecodeTable() {
+ std::vector<Matcher> table = {
+#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
+ INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
+ INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
+ INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
+ INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"),
+ INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"),
+ INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
+ INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"),
+ INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
+ INST("001100101-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"),
+ INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"),
+ INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"),
+ INST("010110011-------", Id::FFMA_RR, Type::Ffma, "FFMA_RR"),
+ INST("0100110001011---", Id::FADD_C, Type::Arithmetic, "FADD_C"),
+ INST("0101110001011---", Id::FADD_R, Type::Arithmetic, "FADD_R"),
+ INST("0011100-01011---", Id::FADD_IMM, Type::Arithmetic, "FADD_IMM"),
+ INST("0100110001101---", Id::FMUL_C, Type::Arithmetic, "FMUL_C"),
+ INST("0101110001101---", Id::FMUL_R, Type::Arithmetic, "FMUL_R"),
+ INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"),
+ INST("00011110--------", Id::FMUL32_IMM, Type::Arithmetic, "FMUL32_IMM"),
+ INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
+ INST("0101110010010---", Id::RRO, Type::Arithmetic, "RRO"),
+ INST("0100110010101---", Id::F2F_C, Type::Arithmetic, "F2F_C"),
+ INST("0101110010101---", Id::F2F_R, Type::Arithmetic, "F2F_R"),
+ INST("0011100-10101---", Id::F2F_IMM, Type::Arithmetic, "F2F_IMM"),
+ INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
+ INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
+ INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
+ INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"),
+ INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"),
+ INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"),
+ INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
+ INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
+ INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
+ INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
+ INST("000000010000----", Id::MOV32I, Type::Arithmetic, "MOV32I"),
+ INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
+ INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
+ INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
+ INST("010010111011----", Id::FSETP_C, Type::FloatPredicate, "FSETP_C"),
+ INST("010110111011----", Id::FSETP_R, Type::FloatPredicate, "FSETP_R"),
+ INST("0011011-1011----", Id::FSETP_IMM, Type::FloatPredicate, "FSETP_IMM"),
+ INST("010010110110----", Id::ISETP_C, Type::IntegerPredicate, "ISETP_C"),
+ INST("010110110110----", Id::ISETP_R, Type::IntegerPredicate, "ISETP_R"),
+ INST("0011011-0110----", Id::ISETP_IMM, Type::IntegerPredicate, "ISETP_IMM"),
+ };
+#undef INST
+ std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) {
+ // If a matcher has more bits in its mask it is more specific, so it
+ // should come first.
+ return std::bitset<16>(a.GetMask()).count() > std::bitset<16>(b.GetMask()).count();
+ });
+
+ return table;
+ }
+};
+
} // namespace Shader
} // namespace Tegra
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 2789a4ca1..2e1edee03 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/alignment.h"
#include "common/assert.h"
#include "video_core/memory_manager.h"
@@ -11,7 +12,8 @@ PAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
boost::optional<PAddr> paddr = FindFreeBlock(size, align);
ASSERT(paddr);
- for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
+ ASSERT(PageSlot(*paddr + offset) == static_cast<u64>(PageStatus::Unmapped));
PageSlot(*paddr + offset) = static_cast<u64>(PageStatus::Allocated);
}
@@ -19,13 +21,8 @@ PAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
}
PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) {
- for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
- if (IsPageMapped(paddr + offset)) {
- return AllocateSpace(size, align);
- }
- }
-
- for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
+ ASSERT(PageSlot(paddr + offset) == static_cast<u64>(PageStatus::Unmapped));
PageSlot(paddr + offset) = static_cast<u64>(PageStatus::Allocated);
}
@@ -33,12 +30,11 @@ PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) {
}
PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) {
- vaddr &= ~Memory::PAGE_MASK;
-
- boost::optional<PAddr> paddr = FindFreeBlock(size);
+ boost::optional<PAddr> paddr = FindFreeBlock(size, PAGE_SIZE);
ASSERT(paddr);
- for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
+ ASSERT(PageSlot(*paddr + offset) == static_cast<u64>(PageStatus::Unmapped));
PageSlot(*paddr + offset) = vaddr + offset;
}
@@ -46,16 +42,10 @@ PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) {
}
PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) {
- vaddr &= ~Memory::PAGE_MASK;
- paddr &= ~Memory::PAGE_MASK;
+ ASSERT((paddr & PAGE_MASK) == 0);
- for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
- if (PageSlot(paddr + offset) != static_cast<u64>(PageStatus::Allocated)) {
- return MapBufferEx(vaddr, size);
- }
- }
-
- for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
+ ASSERT(PageSlot(paddr + offset) == static_cast<u64>(PageStatus::Allocated));
PageSlot(paddr + offset) = vaddr + offset;
}
@@ -63,23 +53,20 @@ PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) {
}
boost::optional<PAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
- PAddr paddr{};
- u64 free_space{};
- align = (align + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
+ PAddr paddr = 0;
+ u64 free_space = 0;
+ align = (align + PAGE_MASK) & ~PAGE_MASK;
while (paddr + free_space < MAX_ADDRESS) {
if (!IsPageMapped(paddr + free_space)) {
- free_space += Memory::PAGE_SIZE;
+ free_space += PAGE_SIZE;
if (free_space >= size) {
return paddr;
}
} else {
- paddr += free_space + Memory::PAGE_SIZE;
+ paddr += free_space + PAGE_SIZE;
free_space = 0;
- const u64 remainder{paddr % align};
- if (!remainder) {
- paddr = (paddr - remainder) + align;
- }
+ paddr = Common::AlignUp(paddr, align);
}
}
@@ -89,7 +76,7 @@ boost::optional<PAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
VAddr MemoryManager::PhysicalToVirtualAddress(PAddr paddr) {
VAddr base_addr = PageSlot(paddr);
ASSERT(base_addr != static_cast<u64>(PageStatus::Unmapped));
- return base_addr + (paddr & Memory::PAGE_MASK);
+ return base_addr + (paddr & PAGE_MASK);
}
bool MemoryManager::IsPageMapped(PAddr paddr) {
@@ -97,14 +84,14 @@ bool MemoryManager::IsPageMapped(PAddr paddr) {
}
VAddr& MemoryManager::PageSlot(PAddr paddr) {
- auto& block = page_table[(paddr >> (Memory::PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
+ auto& block = page_table[(paddr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
if (!block) {
block = std::make_unique<PageBlock>();
for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) {
(*block)[index] = static_cast<u64>(PageStatus::Unmapped);
}
}
- return (*block)[(paddr >> Memory::PAGE_BITS) & PAGE_BLOCK_MASK];
+ return (*block)[(paddr >> PAGE_BITS) & PAGE_BLOCK_MASK];
}
} // namespace Tegra
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 47da7acd6..b73e283f8 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -24,6 +24,10 @@ public:
PAddr MapBufferEx(VAddr vaddr, PAddr paddr, u64 size);
VAddr PhysicalToVirtualAddress(PAddr paddr);
+ static constexpr u64 PAGE_BITS = 16;
+ static constexpr u64 PAGE_SIZE = 1 << PAGE_BITS;
+ static constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
+
private:
boost::optional<PAddr> FindFreeBlock(u64 size, u64 align = 1);
bool IsPageMapped(PAddr paddr);
@@ -35,7 +39,7 @@ private:
};
static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
- static constexpr u64 PAGE_TABLE_BITS{14};
+ static constexpr u64 PAGE_TABLE_BITS{10};
static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};
static constexpr u64 PAGE_TABLE_MASK{PAGE_TABLE_SIZE - 1};
static constexpr u64 PAGE_BLOCK_BITS{14};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 170548528..2d4a0d6db 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -14,7 +14,6 @@
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
-#include "common/vector_math.h"
#include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/settings.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9ece415f7..03e02b52a 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -6,15 +6,10 @@
#include <array>
#include <cstddef>
-#include <cstring>
#include <memory>
-#include <unordered_map>
#include <vector>
#include <glad/glad.h>
-#include "common/bit_field.h"
#include "common/common_types.h"
-#include "common/hash.h"
-#include "common/vector_math.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 6c1c6775a..7410471cc 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -7,7 +7,6 @@
#include <cstring>
#include <iterator>
#include <memory>
-#include <unordered_set>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
@@ -20,7 +19,6 @@
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
-#include "common/vector_math.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "core/hle/kernel/process.h"
@@ -51,6 +49,7 @@ struct FormatTuple {
static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false, 1}, // ABGR8
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false, 1}, // B5G6R5
+ {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false, 1}, // A2B10G10R10
{GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
{GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT23
{GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT45
@@ -106,9 +105,9 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, VAddr b
static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
SurfaceParams::MaxPixelFormat>
morton_to_gl_fns = {
- MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
- MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
- MortonCopy<true, PixelFormat::DXT45>,
+ MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
+ MortonCopy<true, PixelFormat::A2B10G10R10>, MortonCopy<true, PixelFormat::DXT1>,
+ MortonCopy<true, PixelFormat::DXT23>, MortonCopy<true, PixelFormat::DXT45>,
};
static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
@@ -116,6 +115,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
gl_to_morton_fns = {
MortonCopy<false, PixelFormat::ABGR8>,
MortonCopy<false, PixelFormat::B5G6R5>,
+ MortonCopy<false, PixelFormat::A2B10G10R10>,
// TODO(Subv): Swizzling the DXT1/DXT23/DXT45 formats is not yet supported
nullptr,
nullptr,
@@ -672,7 +672,8 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
}
-enum MatchFlags {
+enum class MatchFlags {
+ None = 0,
Invalid = 1, // Flag that can be applied to other match types, invalid matches require
// validation before they can be used
Exact = 1 << 1, // Surfaces perfectly match
@@ -686,6 +687,10 @@ constexpr MatchFlags operator|(MatchFlags lhs, MatchFlags rhs) {
return static_cast<MatchFlags>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
+constexpr MatchFlags operator&(MatchFlags lhs, MatchFlags rhs) {
+ return static_cast<MatchFlags>(static_cast<int>(lhs) & static_cast<int>(rhs));
+}
+
/// Get the best surface match (and its match type) for the given flags
template <MatchFlags find_flags>
Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params,
@@ -703,15 +708,15 @@ Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params
: (params.res_scale <= surface->res_scale);
// validity will be checked in GetCopyableInterval
bool is_valid =
- find_flags & MatchFlags::Copy
+ (find_flags & MatchFlags::Copy) != MatchFlags::None
? true
: surface->IsRegionValid(validate_interval.value_or(params.GetInterval()));
- if (!(find_flags & MatchFlags::Invalid) && !is_valid)
+ if ((find_flags & MatchFlags::Invalid) == MatchFlags::None && !is_valid)
continue;
auto IsMatch_Helper = [&](auto check_type, auto match_fn) {
- if (!(find_flags & check_type))
+ if ((find_flags & check_type) == MatchFlags::None)
return;
bool matched;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 6861efe16..bf0fabb29 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -54,9 +54,10 @@ struct SurfaceParams {
enum class PixelFormat {
ABGR8 = 0,
B5G6R5 = 1,
- DXT1 = 2,
- DXT23 = 3,
- DXT45 = 4,
+ A2B10G10R10 = 2,
+ DXT1 = 3,
+ DXT23 = 4,
+ DXT45 = 5,
Max,
Invalid = 255,
@@ -88,6 +89,7 @@ struct SurfaceParams {
constexpr std::array<unsigned int, MaxPixelFormat> bpp_table = {
32, // ABGR8
16, // B5G6R5
+ 32, // A2B10G10R10
64, // DXT1
128, // DXT23
128, // DXT45
@@ -104,6 +106,8 @@ struct SurfaceParams {
switch (format) {
case Tegra::RenderTargetFormat::RGBA8_UNORM:
return PixelFormat::ABGR8;
+ case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
+ return PixelFormat::A2B10G10R10;
default:
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
@@ -127,6 +131,8 @@ struct SurfaceParams {
return PixelFormat::ABGR8;
case Tegra::Texture::TextureFormat::B5G6R5:
return PixelFormat::B5G6R5;
+ case Tegra::Texture::TextureFormat::A2B10G10R10:
+ return PixelFormat::A2B10G10R10;
case Tegra::Texture::TextureFormat::DXT1:
return PixelFormat::DXT1;
case Tegra::Texture::TextureFormat::DXT23:
@@ -146,6 +152,8 @@ struct SurfaceParams {
return Tegra::Texture::TextureFormat::A8R8G8B8;
case PixelFormat::B5G6R5:
return Tegra::Texture::TextureFormat::B5G6R5;
+ case PixelFormat::A2B10G10R10:
+ return Tegra::Texture::TextureFormat::A2B10G10R10;
case PixelFormat::DXT1:
return Tegra::Texture::TextureFormat::DXT1;
case PixelFormat::DXT23:
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 2f0e7ac1a..93f9172e7 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -14,13 +14,13 @@ class OGLTexture : private NonCopyable {
public:
OGLTexture() = default;
- OGLTexture(OGLTexture&& o) : handle(std::exchange(o.handle, 0)) {}
+ OGLTexture(OGLTexture&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLTexture() {
Release();
}
- OGLTexture& operator=(OGLTexture&& o) {
+ OGLTexture& operator=(OGLTexture&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
@@ -49,13 +49,13 @@ class OGLSampler : private NonCopyable {
public:
OGLSampler() = default;
- OGLSampler(OGLSampler&& o) : handle(std::exchange(o.handle, 0)) {}
+ OGLSampler(OGLSampler&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLSampler() {
Release();
}
- OGLSampler& operator=(OGLSampler&& o) {
+ OGLSampler& operator=(OGLSampler&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
@@ -84,13 +84,13 @@ class OGLShader : private NonCopyable {
public:
OGLShader() = default;
- OGLShader(OGLShader&& o) : handle(std::exchange(o.handle, 0)) {}
+ OGLShader(OGLShader&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLShader() {
Release();
}
- OGLShader& operator=(OGLShader&& o) {
+ OGLShader& operator=(OGLShader&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
@@ -118,13 +118,13 @@ class OGLProgram : private NonCopyable {
public:
OGLProgram() = default;
- OGLProgram(OGLProgram&& o) : handle(std::exchange(o.handle, 0)) {}
+ OGLProgram(OGLProgram&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLProgram() {
Release();
}
- OGLProgram& operator=(OGLProgram&& o) {
+ OGLProgram& operator=(OGLProgram&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
@@ -165,13 +165,12 @@ public:
class OGLPipeline : private NonCopyable {
public:
OGLPipeline() = default;
- OGLPipeline(OGLPipeline&& o) {
- handle = std::exchange<GLuint>(o.handle, 0);
- }
+ OGLPipeline(OGLPipeline&& o) noexcept : handle{std::exchange<GLuint>(o.handle, 0)} {}
+
~OGLPipeline() {
Release();
}
- OGLPipeline& operator=(OGLPipeline&& o) {
+ OGLPipeline& operator=(OGLPipeline&& o) noexcept {
handle = std::exchange<GLuint>(o.handle, 0);
return *this;
}
@@ -199,13 +198,13 @@ class OGLBuffer : private NonCopyable {
public:
OGLBuffer() = default;
- OGLBuffer(OGLBuffer&& o) : handle(std::exchange(o.handle, 0)) {}
+ OGLBuffer(OGLBuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLBuffer() {
Release();
}
- OGLBuffer& operator=(OGLBuffer&& o) {
+ OGLBuffer& operator=(OGLBuffer&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
@@ -234,12 +233,12 @@ class OGLSync : private NonCopyable {
public:
OGLSync() = default;
- OGLSync(OGLSync&& o) : handle(std::exchange(o.handle, nullptr)) {}
+ OGLSync(OGLSync&& o) noexcept : handle(std::exchange(o.handle, nullptr)) {}
~OGLSync() {
Release();
}
- OGLSync& operator=(OGLSync&& o) {
+ OGLSync& operator=(OGLSync&& o) noexcept {
Release();
handle = std::exchange(o.handle, nullptr);
return *this;
@@ -267,13 +266,13 @@ class OGLVertexArray : private NonCopyable {
public:
OGLVertexArray() = default;
- OGLVertexArray(OGLVertexArray&& o) : handle(std::exchange(o.handle, 0)) {}
+ OGLVertexArray(OGLVertexArray&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLVertexArray() {
Release();
}
- OGLVertexArray& operator=(OGLVertexArray&& o) {
+ OGLVertexArray& operator=(OGLVertexArray&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
@@ -302,13 +301,13 @@ class OGLFramebuffer : private NonCopyable {
public:
OGLFramebuffer() = default;
- OGLFramebuffer(OGLFramebuffer&& o) : handle(std::exchange(o.handle, 0)) {}
+ OGLFramebuffer(OGLFramebuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLFramebuffer() {
Release();
}
- OGLFramebuffer& operator=(OGLFramebuffer&& o) {
+ OGLFramebuffer& operator=(OGLFramebuffer&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index de137558d..086424395 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -97,11 +97,12 @@ private:
return exit_method;
for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
- const Instruction instr = {program_code[offset]};
- switch (instr.opcode.EffectiveOpCode()) {
- case OpCode::Id::EXIT: {
- return exit_method = ExitMethod::AlwaysEnd;
- }
+ if (const auto opcode = OpCode::Decode({program_code[offset]})) {
+ switch (opcode->GetId()) {
+ case OpCode::Id::EXIT: {
+ return exit_method = ExitMethod::AlwaysEnd;
+ }
+ }
}
}
return exit_method = ExitMethod::AlwaysReturn;
@@ -220,6 +221,8 @@ private:
/// Generates code representing a temporary (GPR) register.
std::string GetRegister(const Register& reg, unsigned elem = 0) {
+ if (reg == Register::ZeroIndex)
+ return "0";
if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
// GPRs 0-3 are output color for the fragment shader
return std::string{"color."} + "rgba"[(reg + elem) & 3];
@@ -276,6 +279,52 @@ private:
shader.AddLine(dest + " = " + src + ";");
}
+ /*
+ * Writes code that assigns a predicate boolean variable.
+ * @param pred The id of the predicate to write to.
+ * @param value The expression value to assign to the predicate.
+ */
+ void SetPredicate(u64 pred, const std::string& value) {
+ using Tegra::Shader::Pred;
+ // Can't assign to the constant predicate.
+ ASSERT(pred != static_cast<u64>(Pred::UnusedIndex));
+
+ std::string variable = 'p' + std::to_string(pred);
+ shader.AddLine(variable + " = " + value + ';');
+ declr_predicates.insert(std::move(variable));
+ }
+
+ /*
+ * Returns the condition to use in the 'if' for a predicated instruction.
+ * @param instr Instruction to generate the if condition for.
+ * @returns string containing the predicate condition.
+ */
+ std::string GetPredicateCondition(Instruction instr) const {
+ using Tegra::Shader::Pred;
+ ASSERT(instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex));
+
+ std::string variable =
+ 'p' + std::to_string(static_cast<u64>(instr.pred.pred_index.Value()));
+
+ if (instr.negate_pred) {
+ return "!(" + variable + ')';
+ }
+
+ return variable;
+ }
+
+ /*
+ * Returns whether the instruction at the specified offset is a 'sched' instruction.
+ * Sched instructions always appear before a sequence of 3 instructions.
+ */
+ bool IsSchedInstruction(u32 offset) const {
+ // sched instructions appear once every 4 instructions.
+ static constexpr size_t SchedPeriod = 4;
+ u32 absolute_offset = offset - main_offset;
+
+ return (absolute_offset % SchedPeriod) == 0;
+ }
+
/**
* Compiles a single instruction from Tegra to GLSL.
* @param offset the offset of the Tegra shader instruction.
@@ -283,11 +332,33 @@ private:
* + 1. If the current instruction always terminates the program, returns PROGRAM_END.
*/
u32 CompileInstr(u32 offset) {
+ // Ignore sched instructions when generating code.
+ if (IsSchedInstruction(offset)) {
+ return offset + 1;
+ }
+
const Instruction instr = {program_code[offset]};
+ const auto opcode = OpCode::Decode(instr);
+
+ // Decoding failure
+ if (!opcode) {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value);
+ UNREACHABLE();
+ }
+
+ shader.AddLine("// " + std::to_string(offset) + ": " + opcode->GetName());
- shader.AddLine("// " + std::to_string(offset) + ": " + OpCode::GetInfo(instr.opcode).name);
+ using Tegra::Shader::Pred;
+ ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
+ "NeverExecute predicate not implemented");
- switch (OpCode::GetInfo(instr.opcode).type) {
+ if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
+ shader.AddLine("if (" + GetPredicateCondition(instr) + ')');
+ shader.AddLine('{');
+ ++shader.scope;
+ }
+
+ switch (opcode->GetType()) {
case OpCode::Type::Arithmetic: {
std::string dest = GetRegister(instr.gpr0);
std::string op_a = instr.alu.negate_a ? "-" : "";
@@ -312,7 +383,7 @@ private:
op_b = "abs(" + op_b + ")";
}
- switch (instr.opcode.EffectiveOpCode()) {
+ switch (opcode->GetId()) {
case OpCode::Id::FMUL_C:
case OpCode::Id::FMUL_R:
case OpCode::Id::FMUL_IMM: {
@@ -354,16 +425,18 @@ private:
SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d);
break;
default:
- NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {}",
+ NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}",
static_cast<unsigned>(instr.sub_op.Value()));
UNREACHABLE();
}
break;
}
+ case OpCode::Id::RRO: {
+ NGLOG_DEBUG(HW_GPU, "Skipping RRO instruction");
+ break;
+ }
default: {
- NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {} ({}): {}",
- static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
- OpCode::GetInfo(instr.opcode).name, instr.hex);
+ NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", opcode->GetName());
UNREACHABLE();
}
}
@@ -375,7 +448,7 @@ private:
std::string op_b = instr.ffma.negate_b ? "-" : "";
std::string op_c = instr.ffma.negate_c ? "-" : "";
- switch (instr.opcode.EffectiveOpCode()) {
+ switch (opcode->GetId()) {
case OpCode::Id::FFMA_CR: {
op_b += GetUniform(instr.uniform);
op_c += GetRegister(instr.gpr39);
@@ -397,9 +470,7 @@ private:
break;
}
default: {
- NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {} ({}): {}",
- static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
- OpCode::GetInfo(instr.opcode).name, instr.hex);
+ NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->GetName());
UNREACHABLE();
}
}
@@ -411,7 +482,7 @@ private:
std::string gpr0 = GetRegister(instr.gpr0);
const Attribute::Index attribute = instr.attribute.fmt20.index;
- switch (instr.opcode.EffectiveOpCode()) {
+ switch (opcode->GetId()) {
case OpCode::Id::LD_A: {
ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
@@ -442,22 +513,76 @@ private:
break;
}
default: {
- NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {} ({}): {}",
- static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
- OpCode::GetInfo(instr.opcode).name, instr.hex);
+ NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName());
UNREACHABLE();
}
}
break;
}
+ case OpCode::Type::FloatPredicate: {
+ std::string op_a = instr.fsetp.neg_a ? "-" : "";
+ op_a += GetRegister(instr.gpr8);
+
+ if (instr.fsetp.abs_a) {
+ op_a = "abs(" + op_a + ')';
+ }
+
+ std::string op_b{};
+
+ if (instr.is_b_imm) {
+ if (instr.fsetp.neg_b) {
+ // Only the immediate version of fsetp has a neg_b bit.
+ op_b += '-';
+ }
+ op_b += '(' + GetImmediate19(instr) + ')';
+ } else {
+ if (instr.is_b_gpr) {
+ op_b += GetRegister(instr.gpr20);
+ } else {
+ op_b += GetUniform(instr.uniform);
+ }
+ }
+
+ if (instr.fsetp.abs_b) {
+ op_b = "abs(" + op_b + ')';
+ }
+
+ using Tegra::Shader::Pred;
+ ASSERT_MSG(instr.fsetp.pred0 == static_cast<u64>(Pred::UnusedIndex) &&
+ instr.fsetp.pred39 == static_cast<u64>(Pred::UnusedIndex),
+ "Compound predicates are not implemented");
+
+ // We can't use the constant predicate as destination.
+ ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
+ using Tegra::Shader::PredCondition;
+ switch (instr.fsetp.cond) {
+ case PredCondition::LessThan:
+ SetPredicate(instr.fsetp.pred3, '(' + op_a + ") < (" + op_b + ')');
+ break;
+ case PredCondition::Equal:
+ SetPredicate(instr.fsetp.pred3, '(' + op_a + ") == (" + op_b + ')');
+ break;
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})",
+ static_cast<unsigned>(instr.fsetp.cond.Value()), op_a, op_b);
+ UNREACHABLE();
+ }
+ break;
+ }
default: {
- switch (instr.opcode.EffectiveOpCode()) {
+ switch (opcode->GetId()) {
case OpCode::Id::EXIT: {
+ ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex),
+ "Predicated exits not implemented");
shader.AddLine("return true;");
offset = PROGRAM_END - 1;
break;
}
+ case OpCode::Id::KIL: {
+ shader.AddLine("discard;");
+ break;
+ }
case OpCode::Id::IPA: {
const auto& attribute = instr.attribute.fmt28;
std::string dest = GetRegister(instr.gpr0);
@@ -465,9 +590,7 @@ private:
break;
}
default: {
- NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {} ({}): {}",
- static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
- OpCode::GetInfo(instr.opcode).name, instr.hex);
+ NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName());
UNREACHABLE();
}
}
@@ -476,6 +599,12 @@ private:
}
}
+ // Close the predicate condition scope.
+ if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
+ --shader.scope;
+ shader.AddLine('}');
+ }
+
return offset + 1;
}
@@ -605,6 +734,12 @@ private:
declarations.AddNewLine();
++const_buffer_layout;
}
+
+ declarations.AddNewLine();
+ for (const auto& pred : declr_predicates) {
+ declarations.AddLine("bool " + pred + " = false;");
+ }
+ declarations.AddNewLine();
}
private:
@@ -618,6 +753,7 @@ private:
// Declarations
std::set<std::string> declr_register;
+ std::set<std::string> declr_predicates;
std::set<Attribute::Index> declr_input_attribute;
std::set<Attribute::Index> declr_output_attribute;
std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 5e78723a2..ab0acb20a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -9,13 +9,10 @@
#include <memory>
#include <glad/glad.h>
#include "common/assert.h"
-#include "common/bit_field.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
-#include "core/hw/hw.h"
-#include "core/hw/lcd.h"
#include "core/memory.h"
#include "core/settings.h"
#include "core/tracer/recorder.h"
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 4df687786..e0509f0ce 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -53,6 +53,7 @@ u32 BytesPerPixel(TextureFormat format) {
// In this case a 'pixel' actually refers to a 4x4 tile.
return 16;
case TextureFormat::A8R8G8B8:
+ case TextureFormat::A2B10G10R10:
return 4;
case TextureFormat::B5G6R5:
return 2;
@@ -78,6 +79,7 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width,
unswizzled_data.data(), true, block_height);
break;
case TextureFormat::A8R8G8B8:
+ case TextureFormat::A2B10G10R10:
case TextureFormat::B5G6R5:
CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
unswizzled_data.data(), true, block_height);
@@ -100,6 +102,7 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
case TextureFormat::DXT23:
case TextureFormat::DXT45:
case TextureFormat::A8R8G8B8:
+ case TextureFormat::A2B10G10R10:
case TextureFormat::B5G6R5:
// TODO(Subv): For the time being just forward the same data without any decoding.
rgba_data = texture_data;
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index 86e45aa88..dc004d361 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -15,6 +15,7 @@ namespace Texture {
enum class TextureFormat : u32 {
A8R8G8B8 = 0x8,
+ A2B10G10R10 = 0x9,
B5G6R5 = 0x15,
DXT1 = 0x24,
DXT23 = 0x25,
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index 1e4844b57..5fada74be 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -25,6 +25,8 @@ static Tegra::Texture::TextureFormat ConvertToTextureFormat(
switch (render_target_format) {
case Tegra::RenderTargetFormat::RGBA8_UNORM:
return Tegra::Texture::TextureFormat::A8R8G8B8;
+ case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
+ return Tegra::Texture::TextureFormat::A2B10G10R10;
default:
UNIMPLEMENTED_MSG("Unimplemented RT format");
}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 3d7cd06a4..36d40a9b5 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -56,7 +56,28 @@ void EmuWindow_SDL2::OnResize() {
UpdateCurrentFramebufferLayout(width, height);
}
-EmuWindow_SDL2::EmuWindow_SDL2() {
+void EmuWindow_SDL2::Fullscreen() {
+ if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) {
+ return;
+ }
+
+ NGLOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError());
+
+ // Try a different fullscreening method
+ NGLOG_INFO(Frontend, "Attempting to use borderless fullscreen...");
+ if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) {
+ return;
+ }
+
+ NGLOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError());
+
+ // Fallback algorithm: Maximise window.
+ // Works on all systems (unless something is seriously wrong), so no fallback for this one.
+ NGLOG_INFO(Frontend, "Falling back on a maximised window...");
+ SDL_MaximizeWindow(render_window);
+}
+
+EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
InputCommon::Init();
SDL_SetMainReady();
@@ -90,6 +111,10 @@ EmuWindow_SDL2::EmuWindow_SDL2() {
exit(1);
}
+ if (fullscreen) {
+ Fullscreen();
+ }
+
gl_context = SDL_GL_CreateContext(render_window);
if (gl_context == nullptr) {
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index 3664d2fbe..7d5cfffb6 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -12,7 +12,7 @@ struct SDL_Window;
class EmuWindow_SDL2 : public EmuWindow {
public:
- EmuWindow_SDL2();
+ explicit EmuWindow_SDL2(bool fullscreen);
~EmuWindow_SDL2();
/// Swap buffers to display the next frame
@@ -43,6 +43,9 @@ private:
/// Called by PollEvents when any event that may cause the window to be resized occurs
void OnResize();
+ /// Called when user passes the fullscreen parameter flag
+ void Fullscreen();
+
/// Called when a configuration change affects the minimal size of the window
void OnMinimalClientAreaChangeRequest(
const std::pair<unsigned, unsigned>& minimal_size) override;
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index a91140447..39603e881 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -50,6 +50,7 @@ static void PrintHelp(const char* argv0) {
std::cout << "Usage: " << argv0
<< " [options] <filename>\n"
"-g, --gdbport=NUMBER Enable gdb stub on port NUMBER\n"
+ "-f, --fullscreen Start in fullscreen mode\n"
"-h, --help Display this help and exit\n"
"-v, --version Output version information and exit\n";
}
@@ -76,15 +77,18 @@ int main(int argc, char** argv) {
#endif
std::string filepath;
+ bool fullscreen = false;
+
static struct option long_options[] = {
{"gdbport", required_argument, 0, 'g'},
+ {"fullscreen", no_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'v'},
{0, 0, 0, 0},
};
while (optind < argc) {
- char arg = getopt_long(argc, argv, "g:hv", long_options, &option_index);
+ char arg = getopt_long(argc, argv, "g:fhv", long_options, &option_index);
if (arg != -1) {
switch (arg) {
case 'g':
@@ -98,6 +102,10 @@ int main(int argc, char** argv) {
exit(1);
}
break;
+ case 'f':
+ fullscreen = true;
+ NGLOG_INFO(Frontend, "Starting in fullscreen mode...");
+ break;
case 'h':
PrintHelp(argv[0]);
return 0;
@@ -137,7 +145,7 @@ int main(int argc, char** argv) {
Settings::values.use_gdbstub = use_gdbstub;
Settings::Apply();
- std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>()};
+ std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen)};
Core::System& system{Core::System::GetInstance()};