diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/core.cpp | 28 | ||||
-rw-r--r-- | src/core/core.h | 12 | ||||
-rw-r--r-- | src/core/hle/kernel/resource_limit.cpp | 46 | ||||
-rw-r--r-- | src/core/hle/kernel/resource_limit.h | 26 | ||||
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 4 | ||||
-rw-r--r-- | src/core/hle/service/service.cpp | 52 | ||||
-rw-r--r-- | src/core/hle/service/service.h | 2 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.cpp | 4 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.h | 6 | ||||
-rw-r--r-- | src/video_core/engines/shader_bytecode.h | 52 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 13 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_resource_manager.h | 39 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 131 |
13 files changed, 311 insertions, 104 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 6204bcaaa..633740992 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -407,7 +407,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; } @@ -541,7 +541,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/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/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 7cd125f05..e6c2fd367 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -13,6 +13,9 @@ 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) {} @@ -106,6 +109,8 @@ union OpCode { FSETP_R = 0x5BB, FSETP_C = 0x4BB, + FSETP_IMM = 0x36B, + FSETP_NEG_IMM = 0x37B, EXIT = 0xE30, KIL = 0xE33, @@ -121,6 +126,7 @@ union OpCode { Ffma, Flow, Memory, + FloatPredicate, Unknown, }; @@ -161,6 +167,9 @@ union OpCode { case Id::FSETP_C: case Id::KIL: return op4; + case Id::FSETP_IMM: + case Id::FSETP_NEG_IMM: + return Id::FSETP_IMM; } switch (op5) { @@ -238,8 +247,9 @@ union OpCode { 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::FSETP_C] = {Type::FloatPredicate, "fsetp_c"}; + info_table[Id::FSETP_R] = {Type::FloatPredicate, "fsetp_r"}; + info_table[Id::FSETP_IMM] = {Type::FloatPredicate, "fsetp_imm"}; info_table[Id::EXIT] = {Type::Trivial, "exit"}; info_table[Id::IPA] = {Type::Trivial, "ipa"}; info_table[Id::KIL] = {Type::Flow, "kil"}; @@ -283,7 +293,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 { @@ -305,7 +331,11 @@ union Instruction { OpCode opcode; 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; @@ -343,6 +373,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; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 3f6c87c9d..ced2b8247 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -670,7 +670,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 @@ -684,6 +685,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, @@ -701,15 +706,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_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..2395945c3 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -220,6 +220,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 +278,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,10 +331,24 @@ 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]}; 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"); + + if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) { + shader.AddLine("if (" + GetPredicateCondition(instr) + ')'); + shader.AddLine('{'); + ++shader.scope; + } + switch (OpCode::GetInfo(instr.opcode).type) { case OpCode::Type::Arithmetic: { std::string dest = GetRegister(instr.gpr0); @@ -450,14 +512,70 @@ private: } 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()) { 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); @@ -476,6 +594,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 +729,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 +748,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; |