Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f600f6eebd | |||
| c93ea96366 | |||
| 71b4a3b9f6 | |||
| 9dc0d13ba5 | |||
| 7222d9a4c3 | |||
| 9df8e924fb | |||
| 3ed8a1cac7 | |||
| 4a8eb6745e | |||
| 531c25386e | |||
| 174cba5c58 | |||
| e59126809c | |||
| 1f6fe062ca | |||
| ed542a7309 | |||
| ef2d5ab0c1 | |||
| 59f4ff4659 | |||
| 5a28dce9eb | |||
| 8d4899d6ea | |||
| 95144cc39c | |||
| 8b4443c966 | |||
| 5ba71369ac | |||
| 5d529698c9 | |||
| 5b9bcbf438 | |||
| 2b082e2710 | |||
| e52a87b98a | |||
| 0905dc1ff4 | |||
| 636ad34707 | |||
| 7fc516cc1a | |||
| 77bdc49343 | |||
| 1a1af3fda3 |
@@ -7,7 +7,7 @@ yuzu is an experimental open-source emulator for the Nintendo Switch from the cr
|
||||
|
||||
It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes.
|
||||
|
||||
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu does not run any commercial Switch games. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics.
|
||||
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu cannot play any commercial games without major problems. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics.
|
||||
|
||||
yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.
|
||||
|
||||
|
||||
@@ -192,11 +192,6 @@ private:
|
||||
static_assert(position < 8 * sizeof(T), "Invalid position");
|
||||
static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
|
||||
static_assert(bits > 0, "Invalid number of bits");
|
||||
static_assert(std::is_pod<T>::value, "Invalid base type");
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField");
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
|
||||
static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
|
||||
"BitField must be trivially copyable");
|
||||
#endif
|
||||
|
||||
@@ -861,14 +861,14 @@ static const FunctionDef SVC_Table[] = {
|
||||
{0x2B, nullptr, "FlushDataCache"},
|
||||
{0x2C, nullptr, "MapPhysicalMemory"},
|
||||
{0x2D, nullptr, "UnmapPhysicalMemory"},
|
||||
{0x2E, nullptr, "Unknown"},
|
||||
{0x2E, nullptr, "GetNextThreadInfo"},
|
||||
{0x2F, nullptr, "GetLastThreadInfo"},
|
||||
{0x30, nullptr, "GetResourceLimitLimitValue"},
|
||||
{0x31, nullptr, "GetResourceLimitCurrentValue"},
|
||||
{0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
|
||||
{0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
|
||||
{0x34, nullptr, "Unknown"},
|
||||
{0x35, nullptr, "Unknown"},
|
||||
{0x34, nullptr, "WaitForAddress"},
|
||||
{0x35, nullptr, "SignalToAddress"},
|
||||
{0x36, nullptr, "Unknown"},
|
||||
{0x37, nullptr, "Unknown"},
|
||||
{0x38, nullptr, "Unknown"},
|
||||
@@ -876,7 +876,7 @@ static const FunctionDef SVC_Table[] = {
|
||||
{0x3A, nullptr, "Unknown"},
|
||||
{0x3B, nullptr, "Unknown"},
|
||||
{0x3C, nullptr, "DumpInfo"},
|
||||
{0x3D, nullptr, "Unknown"},
|
||||
{0x3D, nullptr, "DumpInfoNew"},
|
||||
{0x3E, nullptr, "Unknown"},
|
||||
{0x3F, nullptr, "Unknown"},
|
||||
{0x40, nullptr, "CreateSession"},
|
||||
@@ -887,9 +887,9 @@ static const FunctionDef SVC_Table[] = {
|
||||
{0x45, nullptr, "CreateEvent"},
|
||||
{0x46, nullptr, "Unknown"},
|
||||
{0x47, nullptr, "Unknown"},
|
||||
{0x48, nullptr, "Unknown"},
|
||||
{0x49, nullptr, "Unknown"},
|
||||
{0x4A, nullptr, "Unknown"},
|
||||
{0x48, nullptr, "AllocateUnsafeMemory"},
|
||||
{0x49, nullptr, "FreeUnsafeMemory"},
|
||||
{0x4A, nullptr, "SetUnsafeAllocationLimit"},
|
||||
{0x4B, nullptr, "CreateJitMemory"},
|
||||
{0x4C, nullptr, "MapJitMemory"},
|
||||
{0x4D, nullptr, "SleepSystem"},
|
||||
@@ -926,7 +926,7 @@ static const FunctionDef SVC_Table[] = {
|
||||
{0x6C, nullptr, "SetHardwareBreakPoint"},
|
||||
{0x6D, nullptr, "GetDebugThreadParam"},
|
||||
{0x6E, nullptr, "Unknown"},
|
||||
{0x6F, nullptr, "Unknown"},
|
||||
{0x6F, nullptr, "GetMemoryInfo"},
|
||||
{0x70, nullptr, "CreatePort"},
|
||||
{0x71, nullptr, "ManageNamedPort"},
|
||||
{0x72, nullptr, "ConnectToPort"},
|
||||
|
||||
@@ -38,7 +38,10 @@ class IProfile final : public ServiceFramework<IProfile> {
|
||||
public:
|
||||
IProfile() : ServiceFramework("IProfile") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Get"},
|
||||
{1, &IProfile::GetBase, "GetBase"},
|
||||
{10, nullptr, "GetImageSize"},
|
||||
{11, nullptr, "LoadImage"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -59,6 +62,11 @@ public:
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
|
||||
{1, &IManagerForApplication::GetAccountId, "GetAccountId"},
|
||||
{2, nullptr, "EnsureIdTokenCacheAsync"},
|
||||
{3, nullptr, "LoadIdTokenCache"},
|
||||
{130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
|
||||
{150, nullptr, "CreateAuthorizationRequest"},
|
||||
{160, nullptr, "StoreOpenContext"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ SET::SET() : ServiceFramework("set") {
|
||||
{5, nullptr, "GetAvailableLanguageCodes2"},
|
||||
{6, nullptr, "GetAvailableLanguageCodeCount2"},
|
||||
{7, nullptr, "GetKeyCodeMap"},
|
||||
{8, nullptr, "GetQuestFlag"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,15 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") {
|
||||
{21, nullptr, "GetEticketDeviceKey"},
|
||||
{22, nullptr, "GetSpeakerParameter"},
|
||||
{23, nullptr, "GetLcdVendorId"},
|
||||
{24, nullptr, "GetEciDeviceCertificate2"},
|
||||
{25, nullptr, "GetEciDeviceKey2"},
|
||||
{26, nullptr, "GetAmiiboKey"},
|
||||
{27, nullptr, "GetAmiiboEcqvCertificate"},
|
||||
{28, nullptr, "GetAmiiboEcdsaCertificate"},
|
||||
{29, nullptr, "GetAmiiboEcqvBlsKey"},
|
||||
{30, nullptr, "GetAmiiboEcqvBlsCertificate"},
|
||||
{31, nullptr, "GetAmiiboEcqvBlsRootCertificate"},
|
||||
{32, nullptr, "GetUnknownId"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
|
||||
{2, nullptr, "GetNetworkSettings"},
|
||||
{3, nullptr, "GetFirmwareVersion"},
|
||||
{4, nullptr, "GetFirmwareVersion2"},
|
||||
{5, nullptr, "GetFirmwareVersionDigest"},
|
||||
{7, nullptr, "GetLockScreenFlag"},
|
||||
{8, nullptr, "SetLockScreenFlag"},
|
||||
{9, nullptr, "GetBacklightSettings"},
|
||||
@@ -159,6 +160,15 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
|
||||
{138, nullptr, "GetWebInspectorFlag"},
|
||||
{139, nullptr, "GetAllowedSslHosts"},
|
||||
{140, nullptr, "GetHostFsMountPoint"},
|
||||
{141, nullptr, "GetRequiresRunRepairTimeReviser"},
|
||||
{142, nullptr, "SetRequiresRunRepairTimeReviser"},
|
||||
{143, nullptr, "SetBlePairingSettings"},
|
||||
{144, nullptr, "GetBlePairingSettings"},
|
||||
{145, nullptr, "GetConsoleSixAxisSensorAngularVelocityTimeBias"},
|
||||
{146, nullptr, "SetConsoleSixAxisSensorAngularVelocityTimeBias"},
|
||||
{147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"},
|
||||
{148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"},
|
||||
{149, nullptr, "GetRebootlessSystemUpdateVersion"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -79,9 +79,34 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
|
||||
{0, &BSD::RegisterClient, "RegisterClient"},
|
||||
{1, &BSD::StartMonitoring, "StartMonitoring"},
|
||||
{2, &BSD::Socket, "Socket"},
|
||||
{3, nullptr, "SocketExempt"},
|
||||
{4, nullptr, "Open"},
|
||||
{5, nullptr, "Select"},
|
||||
{6, nullptr, "Poll"},
|
||||
{7, nullptr, "Sysctl"},
|
||||
{8, nullptr, "Recv"},
|
||||
{9, nullptr, "RecvFrom"},
|
||||
{10, nullptr, "Send"},
|
||||
{11, &BSD::SendTo, "SendTo"},
|
||||
{12, nullptr, "Accept"},
|
||||
{13, nullptr, "Bind"},
|
||||
{14, &BSD::Connect, "Connect"},
|
||||
{15, nullptr, "GetPeerName"},
|
||||
{16, nullptr, "GetSockName"},
|
||||
{17, nullptr, "GetSockOpt"},
|
||||
{18, nullptr, "Listen"},
|
||||
{19, nullptr, "Ioctl"},
|
||||
{20, nullptr, "Fcntl"},
|
||||
{21, nullptr, "SetSockOpt"},
|
||||
{22, nullptr, "Shutdown"},
|
||||
{23, nullptr, "ShutdownAllSockets"},
|
||||
{24, nullptr, "Write"},
|
||||
{25, nullptr, "Read"},
|
||||
{26, &BSD::Close, "Close"},
|
||||
{27, nullptr, "DuplicateSocket"},
|
||||
{28, nullptr, "GetResourceStatistics"},
|
||||
{29, nullptr, "RecvMMsg"},
|
||||
{30, nullptr, "SendMMsg"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
|
||||
{7, nullptr, "GetNameInfo"},
|
||||
{8, nullptr, "RequestCancelHandle"},
|
||||
{9, nullptr, "CancelSocketCall"},
|
||||
{11, nullptr, "ClearDnsIpServerAddressArray"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module),
|
||||
{23, nullptr, "GetSplWaitEvent"},
|
||||
{24, nullptr, "SetSharedData"},
|
||||
{25, nullptr, "GetSharedData"},
|
||||
{26, nullptr, "ImportSslRsaKey"},
|
||||
{27, nullptr, "SecureExpModWithSslKey"},
|
||||
{28, nullptr, "ImportEsRsaKey"},
|
||||
{29, nullptr, "SecureExpModWithEsKey"},
|
||||
{30, nullptr, "EncryptManuRsaKeyForImport"},
|
||||
{31, nullptr, "GetPackage2Hash"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,11 @@ public:
|
||||
ISystemClock() : ServiceFramework("ISystemClock") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
|
||||
{2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}};
|
||||
{1, nullptr, "SetCurrentTime"},
|
||||
{2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
|
||||
{3, nullptr, "SetSystemClockContext"},
|
||||
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,17 @@ TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time)
|
||||
{2, &TIME_S::GetStandardSteadyClock, "GetStandardSteadyClock"},
|
||||
{3, &TIME_S::GetTimeZoneService, "GetTimeZoneService"},
|
||||
{4, &TIME_S::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
|
||||
{5, nullptr, "GetEphemeralNetworkSystemClock"},
|
||||
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
|
||||
{100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
|
||||
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
|
||||
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
|
||||
{400, nullptr, "GetClockSnapshot"},
|
||||
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
|
||||
{500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
|
||||
{501, nullptr, "CalculateSpanBetween"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,17 @@ TIME_U::TIME_U(std::shared_ptr<Module> time) : Module::Interface(std::move(time)
|
||||
{2, &TIME_U::GetStandardSteadyClock, "GetStandardSteadyClock"},
|
||||
{3, &TIME_U::GetTimeZoneService, "GetTimeZoneService"},
|
||||
{4, &TIME_U::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
|
||||
{5, nullptr, "GetEphemeralNetworkSystemClock"},
|
||||
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
|
||||
{100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
|
||||
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
|
||||
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
|
||||
{400, nullptr, "GetClockSnapshot"},
|
||||
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
|
||||
{500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
|
||||
{501, nullptr, "CalculateSpanBetween"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -580,7 +580,48 @@ public:
|
||||
ISystemDisplayService() : ServiceFramework("ISystemDisplayService") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{1200, nullptr, "GetZOrderCountMin"},
|
||||
{1202, nullptr, "GetZOrderCountMax"},
|
||||
{1203, nullptr, "GetDisplayLogicalResolution"},
|
||||
{1204, nullptr, "SetDisplayMagnification"},
|
||||
{2201, nullptr, "SetLayerPosition"},
|
||||
{2203, nullptr, "SetLayerSize"},
|
||||
{2204, nullptr, "GetLayerZ"},
|
||||
{2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
|
||||
{2207, nullptr, "SetLayerVisibility"},
|
||||
{2209, nullptr, "SetLayerAlpha"},
|
||||
{2312, nullptr, "CreateStrayLayer"},
|
||||
{2400, nullptr, "OpenIndirectLayer"},
|
||||
{2401, nullptr, "CloseIndirectLayer"},
|
||||
{2402, nullptr, "FlipIndirectLayer"},
|
||||
{3000, nullptr, "ListDisplayModes"},
|
||||
{3001, nullptr, "ListDisplayRgbRanges"},
|
||||
{3002, nullptr, "ListDisplayContentTypes"},
|
||||
{3200, nullptr, "GetDisplayMode"},
|
||||
{3201, nullptr, "SetDisplayMode"},
|
||||
{3202, nullptr, "GetDisplayUnderscan"},
|
||||
{3203, nullptr, "SetDisplayUnderscan"},
|
||||
{3204, nullptr, "GetDisplayContentType"},
|
||||
{3205, nullptr, "SetDisplayContentType"},
|
||||
{3206, nullptr, "GetDisplayRgbRange"},
|
||||
{3207, nullptr, "SetDisplayRgbRange"},
|
||||
{3208, nullptr, "GetDisplayCmuMode"},
|
||||
{3209, nullptr, "SetDisplayCmuMode"},
|
||||
{3210, nullptr, "GetDisplayContrastRatio"},
|
||||
{3211, nullptr, "SetDisplayContrastRatio"},
|
||||
{3214, nullptr, "GetDisplayGamma"},
|
||||
{3215, nullptr, "SetDisplayGamma"},
|
||||
{3216, nullptr, "GetDisplayCmuLuma"},
|
||||
{3217, nullptr, "SetDisplayCmuLuma"},
|
||||
{8225, nullptr, "GetSharedBufferMemoryHandleId"},
|
||||
{8250, nullptr, "OpenSharedLayer"},
|
||||
{8251, nullptr, "CloseSharedLayer"},
|
||||
{8252, nullptr, "ConnectSharedLayer"},
|
||||
{8253, nullptr, "DisconnectSharedLayer"},
|
||||
{8254, nullptr, "AcquireSharedFrameBuffer"},
|
||||
{8255, nullptr, "PresentSharedFrameBuffer"},
|
||||
{8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
|
||||
{8257, nullptr, "FillSharedFrameBufferColor"},
|
||||
{8258, nullptr, "CancelSharedFrameBuffer"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -603,10 +644,72 @@ public:
|
||||
explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
|
||||
: ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{200, nullptr, "AllocateProcessHeapBlock"},
|
||||
{201, nullptr, "FreeProcessHeapBlock"},
|
||||
{1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"},
|
||||
{1102, nullptr, "GetDisplayResolution"},
|
||||
{2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"},
|
||||
{2011, nullptr, "DestroyManagedLayer"},
|
||||
{2050, nullptr, "CreateIndirectLayer"},
|
||||
{2051, nullptr, "DestroyIndirectLayer"},
|
||||
{2052, nullptr, "CreateIndirectProducerEndPoint"},
|
||||
{2053, nullptr, "DestroyIndirectProducerEndPoint"},
|
||||
{2054, nullptr, "CreateIndirectConsumerEndPoint"},
|
||||
{2055, nullptr, "DestroyIndirectConsumerEndPoint"},
|
||||
{2300, nullptr, "AcquireLayerTexturePresentingEvent"},
|
||||
{2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
|
||||
{2302, nullptr, "GetDisplayHotplugEvent"},
|
||||
{2402, nullptr, "GetDisplayHotplugState"},
|
||||
{2501, nullptr, "GetCompositorErrorInfo"},
|
||||
{2601, nullptr, "GetDisplayErrorEvent"},
|
||||
{4201, nullptr, "SetDisplayAlpha"},
|
||||
{4203, nullptr, "SetDisplayLayerStack"},
|
||||
{4205, nullptr, "SetDisplayPowerState"},
|
||||
{4206, nullptr, "SetDefaultDisplay"},
|
||||
{6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
|
||||
{6001, nullptr, "RemoveFromLayerStack"},
|
||||
{6002, nullptr, "SetLayerVisibility"},
|
||||
{6003, nullptr, "SetLayerConfig"},
|
||||
{6004, nullptr, "AttachLayerPresentationTracer"},
|
||||
{6005, nullptr, "DetachLayerPresentationTracer"},
|
||||
{6006, nullptr, "StartLayerPresentationRecording"},
|
||||
{6007, nullptr, "StopLayerPresentationRecording"},
|
||||
{6008, nullptr, "StartLayerPresentationFenceWait"},
|
||||
{6009, nullptr, "StopLayerPresentationFenceWait"},
|
||||
{6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"},
|
||||
{7000, nullptr, "SetContentVisibility"},
|
||||
{8000, nullptr, "SetConductorLayer"},
|
||||
{8100, nullptr, "SetIndirectProducerFlipOffset"},
|
||||
{8200, nullptr, "CreateSharedBufferStaticStorage"},
|
||||
{8201, nullptr, "CreateSharedBufferTransferMemory"},
|
||||
{8202, nullptr, "DestroySharedBuffer"},
|
||||
{8203, nullptr, "BindSharedLowLevelLayerToManagedLayer"},
|
||||
{8204, nullptr, "BindSharedLowLevelLayerToIndirectLayer"},
|
||||
{8207, nullptr, "UnbindSharedLowLevelLayer"},
|
||||
{8208, nullptr, "ConnectSharedLowLevelLayerToSharedBuffer"},
|
||||
{8209, nullptr, "DisconnectSharedLowLevelLayerFromSharedBuffer"},
|
||||
{8210, nullptr, "CreateSharedLayer"},
|
||||
{8211, nullptr, "DestroySharedLayer"},
|
||||
{8216, nullptr, "AttachSharedLayerToLowLevelLayer"},
|
||||
{8217, nullptr, "ForceDetachSharedLayerFromLowLevelLayer"},
|
||||
{8218, nullptr, "StartDetachSharedLayerFromLowLevelLayer"},
|
||||
{8219, nullptr, "FinishDetachSharedLayerFromLowLevelLayer"},
|
||||
{8220, nullptr, "GetSharedLayerDetachReadyEvent"},
|
||||
{8221, nullptr, "GetSharedLowLevelLayerSynchronizedEvent"},
|
||||
{8222, nullptr, "CheckSharedLowLevelLayerSynchronized"},
|
||||
{8223, nullptr, "RegisterSharedBufferImporterAruid"},
|
||||
{8224, nullptr, "UnregisterSharedBufferImporterAruid"},
|
||||
{8227, nullptr, "CreateSharedBufferProcessHeap"},
|
||||
{8228, nullptr, "GetSharedLayerLayerStacks"},
|
||||
{8229, nullptr, "SetSharedLayerLayerStacks"},
|
||||
{8291, nullptr, "PresentDetachedSharedFrameBufferToLowLevelLayer"},
|
||||
{8292, nullptr, "FillDetachedSharedFrameBufferColor"},
|
||||
{8293, nullptr, "GetDetachedSharedFrameBufferImage"},
|
||||
{8294, nullptr, "SetDetachedSharedFrameBufferImage"},
|
||||
{8295, nullptr, "CopyDetachedSharedFrameBufferImage"},
|
||||
{8296, nullptr, "SetDetachedSharedFrameBufferSubImage"},
|
||||
{8297, nullptr, "GetSharedFrameBufferContentParameter"},
|
||||
{8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -825,13 +928,21 @@ IApplicationDisplayService::IApplicationDisplayService(
|
||||
"GetIndirectDisplayTransactionService"},
|
||||
{1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
|
||||
{1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
|
||||
{1011, nullptr, "OpenDefaultDisplay"},
|
||||
{1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
|
||||
{1101, nullptr, "SetDisplayEnabled"},
|
||||
{1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
|
||||
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
|
||||
{2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
|
||||
{2021, nullptr, "CloseLayer"},
|
||||
{2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
|
||||
{2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
|
||||
{2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
|
||||
{2102, nullptr, "ConvertScalingMode"},
|
||||
{2450, nullptr, "GetIndirectLayerImageMap"},
|
||||
{2451, nullptr, "GetIndirectLayerImageCropMap"},
|
||||
{2460, nullptr, "GetIndirectLayerImageRequiredMemoryInfo"},
|
||||
{5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
|
||||
{5203, nullptr, "GetDisplayVsyncEventForDebug"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger>
|
||||
: Module::Interface(std::move(module), "vi:u", std::move(nv_flinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &VI_U::GetDisplayService, "GetDisplayService"},
|
||||
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -74,8 +74,6 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
||||
|
||||
regs.reg_array[method] = value;
|
||||
|
||||
#define MAXWELL3D_REG_INDEX(field_name) (offsetof(Regs, field_name) / sizeof(u32))
|
||||
|
||||
switch (method) {
|
||||
case MAXWELL3D_REG_INDEX(code_address.code_address_high):
|
||||
case MAXWELL3D_REG_INDEX(code_address.code_address_low): {
|
||||
@@ -136,7 +134,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
||||
break;
|
||||
}
|
||||
|
||||
#undef MAXWELL3D_REG_INDEX
|
||||
VideoCore::g_renderer->Rasterizer()->NotifyMaxwellRegisterChanged(method);
|
||||
|
||||
if (debug_context) {
|
||||
debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr);
|
||||
@@ -165,6 +163,7 @@ void Maxwell3D::ProcessQueryGet() {
|
||||
void Maxwell3D::DrawArrays() {
|
||||
LOG_DEBUG(HW_GPU, "called, topology=%d, count=%d", regs.draw.topology.Value(),
|
||||
regs.vertex_buffer.count);
|
||||
ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
|
||||
|
||||
auto debug_context = Core::System::GetInstance().GetGPUDebugContext();
|
||||
|
||||
@@ -176,7 +175,8 @@ void Maxwell3D::DrawArrays() {
|
||||
debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
|
||||
}
|
||||
|
||||
VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(false /*is_indexed*/);
|
||||
const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
|
||||
VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(is_indexed);
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
|
||||
@@ -221,7 +221,8 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
|
||||
ASSERT_MSG(tic_entry.header_version == Texture::TICHeaderVersion::BlockLinear,
|
||||
"TIC versions other than BlockLinear are unimplemented");
|
||||
|
||||
ASSERT_MSG(tic_entry.texture_type == Texture::TextureType::Texture2D,
|
||||
ASSERT_MSG((tic_entry.texture_type == Texture::TextureType::Texture2D) ||
|
||||
(tic_entry.texture_type == Texture::TextureType::Texture2DNoMipmap),
|
||||
"Texture types other than Texture2D are unimplemented");
|
||||
|
||||
auto r_type = tic_entry.r_type.Value();
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
namespace Tegra {
|
||||
namespace Engines {
|
||||
|
||||
#define MAXWELL3D_REG_INDEX(field_name) \
|
||||
(offsetof(Tegra::Engines::Maxwell3D::Regs, field_name) / sizeof(u32))
|
||||
|
||||
class Maxwell3D final {
|
||||
public:
|
||||
explicit Maxwell3D(MemoryManager& memory_manager);
|
||||
@@ -248,6 +251,52 @@ public:
|
||||
Patches = 0xe,
|
||||
};
|
||||
|
||||
enum class IndexFormat : u32 {
|
||||
UnsignedByte = 0x0,
|
||||
UnsignedShort = 0x1,
|
||||
UnsignedInt = 0x2,
|
||||
};
|
||||
|
||||
struct Blend {
|
||||
enum class Equation : u32 {
|
||||
Add = 1,
|
||||
Subtract = 2,
|
||||
ReverseSubtract = 3,
|
||||
Min = 4,
|
||||
Max = 5,
|
||||
};
|
||||
|
||||
enum class Factor : u32 {
|
||||
Zero = 0x1,
|
||||
One = 0x2,
|
||||
SourceColor = 0x3,
|
||||
OneMinusSourceColor = 0x4,
|
||||
SourceAlpha = 0x5,
|
||||
OneMinusSourceAlpha = 0x6,
|
||||
DestAlpha = 0x7,
|
||||
OneMinusDestAlpha = 0x8,
|
||||
DestColor = 0x9,
|
||||
OneMinusDestColor = 0xa,
|
||||
SourceAlphaSaturate = 0xb,
|
||||
Source1Color = 0x10,
|
||||
OneMinusSource1Color = 0x11,
|
||||
Source1Alpha = 0x12,
|
||||
OneMinusSource1Alpha = 0x13,
|
||||
ConstantColor = 0x61,
|
||||
OneMinusConstantColor = 0x62,
|
||||
ConstantAlpha = 0x63,
|
||||
OneMinusConstantAlpha = 0x64,
|
||||
};
|
||||
|
||||
u32 separate_alpha;
|
||||
Equation equation_rgb;
|
||||
Factor factor_source_rgb;
|
||||
Factor factor_dest_rgb;
|
||||
Equation equation_a;
|
||||
Factor factor_source_a;
|
||||
Factor factor_dest_a;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
INSERT_PADDING_WORDS(0x200);
|
||||
@@ -375,7 +424,42 @@ public:
|
||||
};
|
||||
} draw;
|
||||
|
||||
INSERT_PADDING_WORDS(0x139);
|
||||
INSERT_PADDING_WORDS(0x6B);
|
||||
|
||||
struct {
|
||||
u32 start_addr_high;
|
||||
u32 start_addr_low;
|
||||
u32 end_addr_high;
|
||||
u32 end_addr_low;
|
||||
IndexFormat format;
|
||||
u32 first;
|
||||
u32 count;
|
||||
|
||||
unsigned FormatSizeInBytes() const {
|
||||
switch (format) {
|
||||
case IndexFormat::UnsignedByte:
|
||||
return 1;
|
||||
case IndexFormat::UnsignedShort:
|
||||
return 2;
|
||||
case IndexFormat::UnsignedInt:
|
||||
return 4;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
GPUVAddr StartAddress() const {
|
||||
return static_cast<GPUVAddr>(
|
||||
(static_cast<GPUVAddr>(start_addr_high) << 32) | start_addr_low);
|
||||
}
|
||||
|
||||
GPUVAddr EndAddress() const {
|
||||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(end_addr_high) << 32) |
|
||||
end_addr_low);
|
||||
}
|
||||
} index_array;
|
||||
|
||||
INSERT_PADDING_WORDS(0xC7);
|
||||
|
||||
struct {
|
||||
u32 query_address_high;
|
||||
u32 query_address_low;
|
||||
@@ -410,7 +494,9 @@ public:
|
||||
}
|
||||
} vertex_array[NumVertexArrays];
|
||||
|
||||
INSERT_PADDING_WORDS(0x40);
|
||||
Blend blend;
|
||||
|
||||
INSERT_PADDING_WORDS(0x39);
|
||||
|
||||
struct {
|
||||
u32 limit_high;
|
||||
@@ -572,8 +658,10 @@ ASSERT_REG_POSITION(tsc, 0x557);
|
||||
ASSERT_REG_POSITION(tic, 0x55D);
|
||||
ASSERT_REG_POSITION(code_address, 0x582);
|
||||
ASSERT_REG_POSITION(draw, 0x585);
|
||||
ASSERT_REG_POSITION(index_array, 0x5F2);
|
||||
ASSERT_REG_POSITION(query, 0x6C0);
|
||||
ASSERT_REG_POSITION(vertex_array[0], 0x700);
|
||||
ASSERT_REG_POSITION(blend, 0x780);
|
||||
ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0);
|
||||
ASSERT_REG_POSITION(shader_config[0], 0x800);
|
||||
ASSERT_REG_POSITION(const_buffer, 0x8E0);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "common/bit_field.h"
|
||||
@@ -12,14 +13,10 @@ namespace Tegra {
|
||||
namespace Shader {
|
||||
|
||||
struct Register {
|
||||
Register() = default;
|
||||
constexpr Register() = default;
|
||||
|
||||
constexpr Register(u64 value) : value(value) {}
|
||||
|
||||
constexpr u64 GetIndex() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr operator u64() const {
|
||||
return value;
|
||||
}
|
||||
@@ -43,13 +40,13 @@ struct Register {
|
||||
}
|
||||
|
||||
private:
|
||||
u64 value;
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
union Attribute {
|
||||
Attribute() = default;
|
||||
|
||||
constexpr Attribute(u64 value) : value(value) {}
|
||||
constexpr explicit Attribute(u64 value) : value(value) {}
|
||||
|
||||
enum class Index : u64 {
|
||||
Position = 7,
|
||||
@@ -68,7 +65,20 @@ union Attribute {
|
||||
} fmt28;
|
||||
|
||||
BitField<39, 8, u64> reg;
|
||||
u64 value;
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
union Sampler {
|
||||
Sampler() = default;
|
||||
|
||||
constexpr explicit Sampler(u64 value) : value(value) {}
|
||||
|
||||
enum class Index : u64 {
|
||||
Sampler_0 = 8,
|
||||
};
|
||||
|
||||
BitField<36, 13, Index> index;
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
union Uniform {
|
||||
@@ -238,7 +248,7 @@ union OpCode {
|
||||
BitField<55, 9, Id> op3;
|
||||
BitField<52, 12, Id> op4;
|
||||
BitField<51, 13, Id> op5;
|
||||
u64 value;
|
||||
u64 value{};
|
||||
};
|
||||
static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size");
|
||||
|
||||
@@ -280,6 +290,7 @@ enum class SubOp : u64 {
|
||||
Lg2 = 0x3,
|
||||
Rcp = 0x4,
|
||||
Rsq = 0x5,
|
||||
Min = 0x8,
|
||||
};
|
||||
|
||||
union Instruction {
|
||||
@@ -295,15 +306,25 @@ union Instruction {
|
||||
BitField<20, 8, Register> gpr20;
|
||||
BitField<20, 7, SubOp> sub_op;
|
||||
BitField<28, 8, Register> gpr28;
|
||||
BitField<36, 13, u64> imm36;
|
||||
BitField<39, 8, Register> gpr39;
|
||||
|
||||
union {
|
||||
BitField<20, 19, u64> imm20;
|
||||
BitField<45, 1, u64> negate_b;
|
||||
BitField<46, 1, u64> abs_a;
|
||||
BitField<48, 1, u64> negate_a;
|
||||
BitField<49, 1, u64> abs_b;
|
||||
BitField<50, 1, u64> abs_d;
|
||||
BitField<56, 1, u64> negate_imm;
|
||||
|
||||
float GetImm20() const {
|
||||
float result{};
|
||||
u32 imm{static_cast<u32>(imm20)};
|
||||
imm <<= 12;
|
||||
imm |= negate_imm ? 0x80000000 : 0;
|
||||
std::memcpy(&result, &imm, sizeof(imm));
|
||||
return result;
|
||||
}
|
||||
} alu;
|
||||
|
||||
union {
|
||||
@@ -311,11 +332,13 @@ union Instruction {
|
||||
BitField<49, 1, u64> negate_c;
|
||||
} ffma;
|
||||
|
||||
BitField<61, 1, u64> is_b_imm;
|
||||
BitField<60, 1, u64> is_b_gpr;
|
||||
BitField<59, 1, u64> is_c_gpr;
|
||||
|
||||
Attribute attribute;
|
||||
Uniform uniform;
|
||||
Sampler sampler;
|
||||
|
||||
u64 hex;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,10 @@ namespace Tegra {
|
||||
|
||||
enum class RenderTargetFormat : u32 {
|
||||
NONE = 0x0,
|
||||
RGBA16_FLOAT = 0xCA,
|
||||
RGB10_A2_UNORM = 0xD1,
|
||||
RGBA8_UNORM = 0xD5,
|
||||
RGBA8_SRGB = 0xD6,
|
||||
};
|
||||
|
||||
class DebugContext;
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
virtual void DrawArrays() = 0;
|
||||
|
||||
/// Notify rasterizer that the specified Maxwell register has been changed
|
||||
virtual void NotifyMaxwellRegisterChanged(u32 id) = 0;
|
||||
virtual void NotifyMaxwellRegisterChanged(u32 method) = 0;
|
||||
|
||||
/// Notify rasterizer that all caches should be flushed to Switch memory
|
||||
virtual void FlushAll() = 0;
|
||||
|
||||
@@ -97,7 +97,6 @@ RasterizerOpenGL::RasterizerOpenGL() {
|
||||
state.draw.vertex_buffer = stream_buffer->GetHandle();
|
||||
|
||||
shader_program_manager = std::make_unique<GLShader::ProgramManager>();
|
||||
|
||||
state.draw.shader_program = 0;
|
||||
state.draw.vertex_array = hw_vao.handle;
|
||||
state.Apply();
|
||||
@@ -128,17 +127,6 @@ RasterizerOpenGL::~RasterizerOpenGL() {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) {
|
||||
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
|
||||
|
||||
if (is_indexed) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// TODO(bunnei): Add support for 1+ vertex arrays
|
||||
vs_input_size = regs.vertex_buffer.count * regs.vertex_array[0].stride;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
|
||||
MICROPROFILE_SCOPE(OpenGL_VAO);
|
||||
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
|
||||
@@ -150,6 +138,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
|
||||
|
||||
// TODO(bunnei): Add support for 1+ vertex arrays
|
||||
const auto& vertex_array{regs.vertex_array[0]};
|
||||
const auto& vertex_array_limit{regs.vertex_array_limit[0]};
|
||||
ASSERT_MSG(vertex_array.enable, "vertex array 0 is disabled?");
|
||||
ASSERT_MSG(!vertex_array.divisor, "vertex array 0 divisor is unimplemented!");
|
||||
for (unsigned index = 1; index < Maxwell::NumVertexArrays; ++index) {
|
||||
@@ -162,6 +151,10 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
|
||||
// to avoid OpenGL errors.
|
||||
for (unsigned index = 0; index < 16; ++index) {
|
||||
auto& attrib = regs.vertex_attrib_format[index];
|
||||
NGLOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
|
||||
index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
|
||||
attrib.offset.Value(), attrib.IsNormalized());
|
||||
|
||||
glVertexAttribPointer(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib),
|
||||
attrib.IsNormalized() ? GL_TRUE : GL_FALSE, vertex_array.stride,
|
||||
reinterpret_cast<GLvoid*>(buffer_offset + attrib.offset));
|
||||
@@ -170,7 +163,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
|
||||
}
|
||||
|
||||
// Copy vertex array data
|
||||
const u32 data_size{vertex_array.stride * regs.vertex_buffer.count};
|
||||
const u64 data_size{vertex_array_limit.LimitAddress() - vertex_array.StartAddress() + 1};
|
||||
const VAddr data_addr{memory_manager->PhysicalToVirtualAddress(vertex_array.StartAddress())};
|
||||
res_cache.FlushRegion(data_addr, data_size, nullptr);
|
||||
Memory::ReadBlock(data_addr, array_ptr, data_size);
|
||||
@@ -333,13 +326,18 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
|
||||
// Draw the vertex batch
|
||||
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
|
||||
AnalyzeVertexArray(is_indexed);
|
||||
const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
|
||||
const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count};
|
||||
|
||||
// TODO(bunnei): Add support for 1+ vertex arrays
|
||||
vs_input_size = vertex_num * regs.vertex_array[0].stride;
|
||||
|
||||
state.draw.vertex_buffer = stream_buffer->GetHandle();
|
||||
state.Apply();
|
||||
|
||||
size_t buffer_size = static_cast<size_t>(vs_input_size);
|
||||
if (is_indexed) {
|
||||
UNREACHABLE();
|
||||
buffer_size = Common::AlignUp(buffer_size, 4) + index_buffer_size;
|
||||
}
|
||||
|
||||
// Uniform space for the 5 shader stages
|
||||
@@ -354,9 +352,18 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
SetupVertexArray(buffer_ptr, buffer_offset);
|
||||
ptr_pos += vs_input_size;
|
||||
|
||||
// If indexed mode, copy the index buffer
|
||||
GLintptr index_buffer_offset = 0;
|
||||
if (is_indexed) {
|
||||
UNREACHABLE();
|
||||
ptr_pos = Common::AlignUp(ptr_pos, 4);
|
||||
|
||||
const auto& memory_manager = Core::System().GetInstance().GPU().memory_manager;
|
||||
const VAddr index_data_addr{
|
||||
memory_manager->PhysicalToVirtualAddress(regs.index_array.StartAddress())};
|
||||
Memory::ReadBlock(index_data_addr, &buffer_ptr[ptr_pos], index_buffer_size);
|
||||
|
||||
index_buffer_offset = buffer_offset + static_cast<GLintptr>(ptr_pos);
|
||||
ptr_pos += index_buffer_size;
|
||||
}
|
||||
|
||||
SetupShaders(buffer_ptr, buffer_offset, ptr_pos);
|
||||
@@ -366,11 +373,16 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
shader_program_manager->ApplyTo(state);
|
||||
state.Apply();
|
||||
|
||||
const GLenum primitive_mode{MaxwellToGL::PrimitiveTopology(regs.draw.topology)};
|
||||
if (is_indexed) {
|
||||
UNREACHABLE();
|
||||
const GLint index_min{static_cast<GLint>(regs.index_array.first)};
|
||||
const GLint index_max{static_cast<GLint>(regs.index_array.first + regs.index_array.count)};
|
||||
glDrawRangeElementsBaseVertex(primitive_mode, index_min, index_max, regs.index_array.count,
|
||||
MaxwellToGL::IndexFormat(regs.index_array.format),
|
||||
reinterpret_cast<const void*>(index_buffer_offset),
|
||||
-index_min);
|
||||
} else {
|
||||
glDrawArrays(MaxwellToGL::PrimitiveTopology(regs.draw.topology), 0,
|
||||
regs.vertex_buffer.count);
|
||||
glDrawArrays(primitive_mode, 0, regs.vertex_buffer.count);
|
||||
}
|
||||
|
||||
// Disable scissor test
|
||||
@@ -434,7 +446,32 @@ void RasterizerOpenGL::BindTextures() {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
|
||||
void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {
|
||||
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
|
||||
switch (method) {
|
||||
case MAXWELL3D_REG_INDEX(blend.separate_alpha):
|
||||
ASSERT_MSG(false, "unimplemented");
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(blend.equation_rgb):
|
||||
state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(blend.factor_source_rgb):
|
||||
state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(blend.factor_dest_rgb):
|
||||
state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(blend.equation_a):
|
||||
state.blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(blend.factor_source_a):
|
||||
state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
|
||||
break;
|
||||
case MAXWELL3D_REG_INDEX(blend.factor_dest_a):
|
||||
state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::FlushAll() {
|
||||
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
~RasterizerOpenGL() override;
|
||||
|
||||
void DrawArrays() override;
|
||||
void NotifyMaxwellRegisterChanged(u32 id) override;
|
||||
void NotifyMaxwellRegisterChanged(u32 method) override;
|
||||
void FlushAll() override;
|
||||
void FlushRegion(VAddr addr, u64 size) override;
|
||||
void InvalidateRegion(VAddr addr, u64 size) override;
|
||||
@@ -155,7 +155,6 @@ private:
|
||||
|
||||
GLsizeiptr vs_input_size;
|
||||
|
||||
void AnalyzeVertexArray(bool is_indexed);
|
||||
void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset);
|
||||
|
||||
std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> uniform_buffers;
|
||||
|
||||
@@ -87,6 +87,7 @@ struct SurfaceParams {
|
||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||
return PixelFormat::RGBA8;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
@@ -96,6 +97,7 @@ struct SurfaceParams {
|
||||
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||
return PixelFormat::RGBA8;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
@@ -108,6 +110,7 @@ struct SurfaceParams {
|
||||
case Tegra::Texture::TextureFormat::DXT1:
|
||||
return PixelFormat::DXT1;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ using Tegra::Shader::Attribute;
|
||||
using Tegra::Shader::Instruction;
|
||||
using Tegra::Shader::OpCode;
|
||||
using Tegra::Shader::Register;
|
||||
using Tegra::Shader::Sampler;
|
||||
using Tegra::Shader::SubOp;
|
||||
using Tegra::Shader::Uniform;
|
||||
|
||||
@@ -155,23 +156,27 @@ private:
|
||||
|
||||
/// Generates code representing an input attribute register.
|
||||
std::string GetInputAttribute(Attribute::Index attribute) {
|
||||
declr_input_attribute.insert(attribute);
|
||||
switch (attribute) {
|
||||
case Attribute::Index::Position:
|
||||
return "position";
|
||||
default:
|
||||
const u32 index{static_cast<u32>(attribute) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)};
|
||||
if (attribute >= Attribute::Index::Attribute_0) {
|
||||
declr_input_attribute.insert(attribute);
|
||||
return "input_attribute_" + std::to_string(index);
|
||||
}
|
||||
|
||||
const u32 index{static_cast<u32>(attribute) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)};
|
||||
if (attribute >= Attribute::Index::Attribute_0) {
|
||||
return "input_attribute_" + std::to_string(index);
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled input attribute: 0x%02x", index);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
/// Generates code representing an output attribute register.
|
||||
std::string GetOutputAttribute(Attribute::Index attribute) {
|
||||
switch (attribute) {
|
||||
case Attribute::Index::Position:
|
||||
return "gl_Position";
|
||||
return "position";
|
||||
default:
|
||||
const u32 index{static_cast<u32>(attribute) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)};
|
||||
@@ -180,22 +185,42 @@ private:
|
||||
return "output_attribute_" + std::to_string(index);
|
||||
}
|
||||
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled output attribute: 0x%02x", index);
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates code representing an immediate value
|
||||
static std::string GetImmediate(const Instruction& instr) {
|
||||
return std::to_string(instr.alu.GetImm20());
|
||||
}
|
||||
|
||||
/// Generates code representing a temporary (GPR) register.
|
||||
std::string GetRegister(const Register& reg) {
|
||||
return *declr_register.insert("register_" + std::to_string(reg)).first;
|
||||
std::string GetRegister(const Register& reg, unsigned elem = 0) {
|
||||
if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
|
||||
// GPRs 0-3 are output color for the fragment shader
|
||||
return std::string{"color."} + "rgba"[(reg + elem) & 3];
|
||||
}
|
||||
|
||||
return *declr_register.insert("register_" + std::to_string(reg + elem)).first;
|
||||
}
|
||||
|
||||
/// Generates code representing a uniform (C buffer) register.
|
||||
std::string GetUniform(const Uniform& reg) {
|
||||
declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset, stage);
|
||||
declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index),
|
||||
static_cast<unsigned>(reg.offset), stage);
|
||||
return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
|
||||
}
|
||||
|
||||
/// Generates code representing a texture sampler.
|
||||
std::string GetSampler(const Sampler& sampler) const {
|
||||
// TODO(Subv): Support more than just texture sampler 0
|
||||
ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported");
|
||||
const unsigned index{static_cast<unsigned>(sampler.index.Value()) -
|
||||
static_cast<unsigned>(Sampler::Index::Sampler_0)};
|
||||
return "tex[" + std::to_string(index) + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds code that calls a subroutine.
|
||||
* @param subroutine the subroutine to call.
|
||||
@@ -217,12 +242,13 @@ private:
|
||||
* @param value the code representing the value to assign.
|
||||
*/
|
||||
void SetDest(u64 elem, const std::string& reg, const std::string& value,
|
||||
u64 dest_num_components, u64 value_num_components) {
|
||||
u64 dest_num_components, u64 value_num_components, bool is_abs = false) {
|
||||
std::string swizzle = ".";
|
||||
swizzle += "xyzw"[elem];
|
||||
|
||||
std::string dest = reg + (dest_num_components != 1 ? swizzle : "");
|
||||
std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : "");
|
||||
src = is_abs ? "abs(" + src + ")" : src;
|
||||
|
||||
shader.AddLine(dest + " = " + src + ";");
|
||||
}
|
||||
@@ -240,8 +266,6 @@ private:
|
||||
|
||||
switch (OpCode::GetInfo(instr.opcode).type) {
|
||||
case OpCode::Type::Arithmetic: {
|
||||
ASSERT(!instr.alu.abs_d);
|
||||
|
||||
std::string dest = GetRegister(instr.gpr0);
|
||||
std::string op_a = instr.alu.negate_a ? "-" : "";
|
||||
op_a += GetRegister(instr.gpr8);
|
||||
@@ -250,63 +274,109 @@ private:
|
||||
}
|
||||
|
||||
std::string op_b = instr.alu.negate_b ? "-" : "";
|
||||
if (instr.is_b_gpr) {
|
||||
op_b += GetRegister(instr.gpr20);
|
||||
|
||||
if (instr.is_b_imm) {
|
||||
op_b += GetImmediate(instr);
|
||||
} else {
|
||||
op_b += GetUniform(instr.uniform);
|
||||
if (instr.is_b_gpr) {
|
||||
op_b += GetRegister(instr.gpr20);
|
||||
} else {
|
||||
op_b += GetUniform(instr.uniform);
|
||||
}
|
||||
}
|
||||
|
||||
if (instr.alu.abs_b) {
|
||||
op_b = "abs(" + op_b + ")";
|
||||
}
|
||||
|
||||
switch (instr.opcode.EffectiveOpCode()) {
|
||||
case OpCode::Id::FMUL_C:
|
||||
case OpCode::Id::FMUL_R: {
|
||||
SetDest(0, dest, op_a + " * " + op_b, 1, 1);
|
||||
case OpCode::Id::FMUL_R:
|
||||
case OpCode::Id::FMUL_IMM: {
|
||||
SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FADD_C:
|
||||
case OpCode::Id::FADD_R: {
|
||||
SetDest(0, dest, op_a + " + " + op_b, 1, 1);
|
||||
case OpCode::Id::FADD_R:
|
||||
case OpCode::Id::FADD_IMM: {
|
||||
SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::MUFU: {
|
||||
switch (instr.sub_op) {
|
||||
case SubOp::Cos:
|
||||
SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Sin:
|
||||
SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Ex2:
|
||||
SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Lg2:
|
||||
SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Rcp:
|
||||
SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Rsq:
|
||||
SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
case SubOp::Min:
|
||||
SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d);
|
||||
break;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {}",
|
||||
static_cast<unsigned>(instr.sub_op.Value()));
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: 0x%02x (%s): 0x%08x",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
|
||||
throw DecompileFail("Unhandled instruction");
|
||||
break;
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::Ffma: {
|
||||
ASSERT_MSG(!instr.ffma.negate_b, "untested");
|
||||
ASSERT_MSG(!instr.ffma.negate_c, "untested");
|
||||
|
||||
std::string dest = GetRegister(instr.gpr0);
|
||||
std::string op_a = GetRegister(instr.gpr8);
|
||||
|
||||
std::string op_b = instr.ffma.negate_b ? "-" : "";
|
||||
op_b += GetUniform(instr.uniform);
|
||||
|
||||
std::string op_c = instr.ffma.negate_c ? "-" : "";
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
|
||||
switch (instr.opcode.EffectiveOpCode()) {
|
||||
case OpCode::Id::FFMA_CR: {
|
||||
SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
|
||||
op_b += GetUniform(instr.uniform);
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FFMA_RR: {
|
||||
op_b += GetRegister(instr.gpr20);
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FFMA_RC: {
|
||||
op_b += GetRegister(instr.gpr39);
|
||||
op_c += GetUniform(instr.uniform);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FFMA_IMM: {
|
||||
op_b += GetImmediate(instr);
|
||||
op_c += GetRegister(instr.gpr39);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled arithmetic FFMA instruction: 0x%02x (%s): 0x%08x",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
|
||||
throw DecompileFail("Unhandled instruction");
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::Memory: {
|
||||
@@ -315,22 +385,33 @@ private:
|
||||
|
||||
switch (instr.opcode.EffectiveOpCode()) {
|
||||
case OpCode::Id::LD_A: {
|
||||
ASSERT(instr.attribute.fmt20.size == 0);
|
||||
ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
|
||||
SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::ST_A: {
|
||||
ASSERT(instr.attribute.fmt20.size == 0);
|
||||
ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
|
||||
SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: 0x%02x (%s): 0x%08x",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
|
||||
throw DecompileFail("Unhandled instruction");
|
||||
case OpCode::Id::TEXS: {
|
||||
ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
|
||||
const std::string op_a = GetRegister(instr.gpr8);
|
||||
const std::string op_b = GetRegister(instr.gpr20);
|
||||
const std::string sampler = GetSampler(instr.sampler);
|
||||
const std::string coord = "vec2(" + op_a + ", " + op_b + ")";
|
||||
const std::string texture = "texture(" + sampler + ", " + coord + ")";
|
||||
for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
|
||||
SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -342,14 +423,18 @@ private:
|
||||
offset = PROGRAM_END - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
|
||||
throw DecompileFail("Unhandled instruction");
|
||||
case OpCode::Id::IPA: {
|
||||
const auto& attribute = instr.attribute.fmt28;
|
||||
std::string dest = GetRegister(instr.gpr0);
|
||||
SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {} ({}): {}",
|
||||
static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
|
||||
OpCode::GetInfo(instr.opcode).name, instr.hex);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -514,7 +599,7 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code,
|
||||
GLSLGenerator generator(subroutines, program_code, main_offset, stage);
|
||||
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
|
||||
} catch (const DecompileFail& exception) {
|
||||
LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", exception.what());
|
||||
NGLOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
@@ -27,10 +27,13 @@ out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
out vec4 position;
|
||||
|
||||
void main() {
|
||||
exec_shader();
|
||||
}
|
||||
|
||||
gl_Position = position;
|
||||
}
|
||||
)";
|
||||
out += program.first;
|
||||
return {out, program.second};
|
||||
@@ -46,6 +49,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo
|
||||
.get_value_or({});
|
||||
out += R"(
|
||||
|
||||
in vec4 position;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D tex[32];
|
||||
|
||||
@@ -31,7 +31,7 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
|
||||
return GL_UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size=%s", attrib.SizeString().c_str());
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString());
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
@@ -40,7 +40,21 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
|
||||
return GL_FLOAT;
|
||||
}
|
||||
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type=%s", attrib.TypeString().c_str());
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum IndexFormat(Maxwell::IndexFormat index_format) {
|
||||
switch (index_format) {
|
||||
case Maxwell::IndexFormat::UnsignedByte:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case Maxwell::IndexFormat::UnsignedShort:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
case Maxwell::IndexFormat::UnsignedInt:
|
||||
return GL_UNSIGNED_INT;
|
||||
}
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented index_format={}", static_cast<u32>(index_format));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
@@ -52,7 +66,7 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
|
||||
case Maxwell::PrimitiveTopology::TriangleStrip:
|
||||
return GL_TRIANGLE_STRIP;
|
||||
}
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented primitive topology=%d", topology);
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
@@ -64,18 +78,90 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) {
|
||||
case Tegra::Texture::TextureFilter::Nearest:
|
||||
return GL_NEAREST;
|
||||
}
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode=%u",
|
||||
static_cast<u32>(filter_mode));
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}",
|
||||
static_cast<u32>(filter_mode));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
|
||||
switch (wrap_mode) {
|
||||
case Tegra::Texture::WrapMode::Wrap:
|
||||
return GL_REPEAT;
|
||||
case Tegra::Texture::WrapMode::ClampToEdge:
|
||||
return GL_CLAMP_TO_EDGE;
|
||||
case Tegra::Texture::WrapMode::ClampOGL:
|
||||
// TODO(Subv): GL_CLAMP was removed as of OpenGL 3.1, to implement GL_CLAMP, we can use
|
||||
// GL_CLAMP_TO_BORDER to get the border color of the texture, and then sample the edge to
|
||||
// manually mix them. However the shader part of this is not yet implemented.
|
||||
return GL_CLAMP_TO_BORDER;
|
||||
}
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode=%u", static_cast<u32>(wrap_mode));
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}",
|
||||
static_cast<u32>(wrap_mode));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
|
||||
switch (equation) {
|
||||
case Maxwell::Blend::Equation::Add:
|
||||
return GL_FUNC_ADD;
|
||||
case Maxwell::Blend::Equation::Subtract:
|
||||
return GL_FUNC_SUBTRACT;
|
||||
case Maxwell::Blend::Equation::ReverseSubtract:
|
||||
return GL_FUNC_REVERSE_SUBTRACT;
|
||||
case Maxwell::Blend::Equation::Min:
|
||||
return GL_MIN;
|
||||
case Maxwell::Blend::Equation::Max:
|
||||
return GL_MAX;
|
||||
}
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
|
||||
switch (factor) {
|
||||
case Maxwell::Blend::Factor::Zero:
|
||||
return GL_ZERO;
|
||||
case Maxwell::Blend::Factor::One:
|
||||
return GL_ONE;
|
||||
case Maxwell::Blend::Factor::SourceColor:
|
||||
return GL_SRC_COLOR;
|
||||
case Maxwell::Blend::Factor::OneMinusSourceColor:
|
||||
return GL_ONE_MINUS_SRC_COLOR;
|
||||
case Maxwell::Blend::Factor::SourceAlpha:
|
||||
return GL_SRC_ALPHA;
|
||||
case Maxwell::Blend::Factor::OneMinusSourceAlpha:
|
||||
return GL_ONE_MINUS_SRC_ALPHA;
|
||||
case Maxwell::Blend::Factor::DestAlpha:
|
||||
return GL_DST_ALPHA;
|
||||
case Maxwell::Blend::Factor::OneMinusDestAlpha:
|
||||
return GL_ONE_MINUS_DST_ALPHA;
|
||||
case Maxwell::Blend::Factor::DestColor:
|
||||
return GL_DST_COLOR;
|
||||
case Maxwell::Blend::Factor::OneMinusDestColor:
|
||||
return GL_ONE_MINUS_DST_COLOR;
|
||||
case Maxwell::Blend::Factor::SourceAlphaSaturate:
|
||||
return GL_SRC_ALPHA_SATURATE;
|
||||
case Maxwell::Blend::Factor::Source1Color:
|
||||
return GL_SRC1_COLOR;
|
||||
case Maxwell::Blend::Factor::OneMinusSource1Color:
|
||||
return GL_ONE_MINUS_SRC1_COLOR;
|
||||
case Maxwell::Blend::Factor::Source1Alpha:
|
||||
return GL_SRC1_ALPHA;
|
||||
case Maxwell::Blend::Factor::OneMinusSource1Alpha:
|
||||
return GL_ONE_MINUS_SRC1_ALPHA;
|
||||
case Maxwell::Blend::Factor::ConstantColor:
|
||||
return GL_CONSTANT_COLOR;
|
||||
case Maxwell::Blend::Factor::OneMinusConstantColor:
|
||||
return GL_ONE_MINUS_CONSTANT_COLOR;
|
||||
case Maxwell::Blend::Factor::ConstantAlpha:
|
||||
return GL_CONSTANT_ALPHA;
|
||||
case Maxwell::Blend::Factor::OneMinusConstantAlpha:
|
||||
return GL_ONE_MINUS_CONSTANT_ALPHA;
|
||||
}
|
||||
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@ namespace Tegra {
|
||||
namespace Texture {
|
||||
|
||||
enum class TextureFormat : u32 {
|
||||
A8R8G8B8 = 8,
|
||||
A8R8G8B8 = 0x8,
|
||||
DXT1 = 0x24,
|
||||
DXT23 = 0x25,
|
||||
DXT45 = 0x26,
|
||||
};
|
||||
|
||||
enum class TextureType : u32 {
|
||||
|
||||
Reference in New Issue
Block a user