diff --git a/.gitignore b/.gitignore
index f03a6be..9f08bd0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,6 @@ Temp/
UserSettings/
Builds/
screenshot-*.png
+.vs
+Tools/PSSRPlugin/Prospero_Debug/
+*.user
diff --git a/Tools/PSSRPlugin/PSSRPlugin.vcxproj b/Tools/PSSRPlugin/PSSRPlugin.vcxproj
new file mode 100644
index 0000000..90c8248
--- /dev/null
+++ b/Tools/PSSRPlugin/PSSRPlugin.vcxproj
@@ -0,0 +1,89 @@
+
+
+
+
+ Debug
+ Prospero
+
+
+ Release
+ Prospero
+
+
+
+ {cfc8c665-7287-4dac-9016-2d97e70b63be}
+
+
+
+
+ DynamicLibrary
+
+
+ DynamicLibrary
+
+
+ v143
+
+
+ v143
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions);
+ true
+
+
+ NonAslr
+
+
+ -lSceSysmodule_stub_weak;-lScePsml;-lScePsml_stub_weak;-lSceAgcGnmp;-lSceAgc;-lSceAgcCore;-lSceAgcGpuAddress;-lSceVideoOut_stub_weak;-lSceAgcDriver_stub_weak;-lSceAgc_stub_weak
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions);
+ Level2
+
+
+ -lSceSysmodule_stub_weak;-lScePsml;-lScePsml_stub_weak;-lSceAgcGnmp;-lSceAgc;-lSceAgcCore;-lSceAgcGpuAddress;-lSceVideoOut_stub_weak;-lSceAgcDriver_stub_weak;-lSceAgc_stub_weak
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tools/PSSRPlugin/PSSRPlugin.vcxproj.filters b/Tools/PSSRPlugin/PSSRPlugin.vcxproj.filters
new file mode 100644
index 0000000..c4b069f
--- /dev/null
+++ b/Tools/PSSRPlugin/PSSRPlugin.vcxproj.filters
@@ -0,0 +1,51 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cxx;cc;s;asm
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;pssli
+
+
+ {5FAE8098-8EE5-44A0-ABB6-C797B807CDE6}
+ pssl;scu
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphics.h b/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphics.h
new file mode 100644
index 0000000..7d04119
--- /dev/null
+++ b/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphics.h
@@ -0,0 +1,64 @@
+// Unity Native Plugin API copyright © 2015 Unity Technologies ApS
+//
+// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
+//
+// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions.
+
+#pragma once
+#include "IUnityInterface.h"
+
+// Has to match the GfxDeviceRenderer enum
+typedef enum UnityGfxRenderer
+{
+ //kUnityGfxRendererOpenGL = 0, // Legacy OpenGL, removed
+ //kUnityGfxRendererD3D9 = 1, // Direct3D 9, removed
+ kUnityGfxRendererD3D11 = 2, // Direct3D 11
+ kUnityGfxRendererNull = 4, // "null" device (used in batch mode)
+ //kUnityGfxRendererOpenGLES20 = 8, // OpenGL ES 2.0, removed
+ kUnityGfxRendererOpenGLES30 = 11, // OpenGL ES 3.0
+ //kUnityGfxRendererGXM = 12, // PlayStation Vita, removed
+ kUnityGfxRendererPS4 = 13, // PlayStation 4
+ kUnityGfxRendererXboxOne = 14, // Xbox One
+ kUnityGfxRendererMetal = 16, // iOS Metal
+ kUnityGfxRendererOpenGLCore = 17, // OpenGL core
+ kUnityGfxRendererD3D12 = 18, // Direct3D 12
+ kUnityGfxRendererVulkan = 21, // Vulkan
+ kUnityGfxRendererNvn = 22, // Nintendo Switch NVN API
+ kUnityGfxRendererXboxOneD3D12 = 23, // MS XboxOne Direct3D 12
+ kUnityGfxRendererGameCoreXboxOne = 24, // GameCore Xbox One
+ kUnityGfxRendererGameCoreXboxSeries = 25, // GameCore XboxSeries
+ kUnityGfxRendererPS5 = 26, // PS5
+ kUnityGfxRendererPS5NGGC = 27, // PS5 NGGC
+
+ kUnityGfxRendererReservedCFE = 29
+} UnityGfxRenderer;
+
+typedef enum UnityGfxDeviceEventType
+{
+ kUnityGfxDeviceEventInitialize = 0,
+ kUnityGfxDeviceEventShutdown = 1,
+ kUnityGfxDeviceEventBeforeReset = 2,
+ kUnityGfxDeviceEventAfterReset = 3,
+} UnityGfxDeviceEventType;
+
+typedef void (UNITY_INTERFACE_API * IUnityGraphicsDeviceEventCallback)(UnityGfxDeviceEventType eventType);
+
+// Should only be used on the rendering thread unless noted otherwise.
+UNITY_DECLARE_INTERFACE(IUnityGraphics)
+{
+ UnityGfxRenderer(UNITY_INTERFACE_API * GetRenderer)(); // Thread safe
+
+ // This callback will be called when graphics device is created, destroyed, reset, etc.
+ // It is possible to miss the kUnityGfxDeviceEventInitialize event in case plugin is loaded at a later time,
+ // when the graphics device is already created.
+ void(UNITY_INTERFACE_API * RegisterDeviceEventCallback)(IUnityGraphicsDeviceEventCallback callback);
+ void(UNITY_INTERFACE_API * UnregisterDeviceEventCallback)(IUnityGraphicsDeviceEventCallback callback);
+ int(UNITY_INTERFACE_API * ReserveEventIDRange)(int count); // reserves 'count' event IDs. Plugins should use the result as a base index when issuing events back and forth to avoid event id clashes.
+};
+UNITY_REGISTER_INTERFACE_GUID(0x7CBA0A9CA4DDB544ULL, 0x8C5AD4926EB17B11ULL, IUnityGraphics)
+
+
+// Certain Unity APIs (GL.IssuePluginEvent, CommandBuffer.IssuePluginEvent) can callback into native plugins.
+// Provide them with an address to a function of this signature.
+typedef void (UNITY_INTERFACE_API * UnityRenderingEvent)(int eventId);
+typedef void (UNITY_INTERFACE_API * UnityRenderingEventAndData)(int eventId, void* data);
diff --git a/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphicsAgcPS5.h b/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphicsAgcPS5.h
new file mode 100644
index 0000000..8f5b9ae
--- /dev/null
+++ b/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphicsAgcPS5.h
@@ -0,0 +1,32 @@
+// Unity Native Plugin API copyright © 2021 Unity Technologies ApS
+//
+// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
+//
+// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions.
+
+#pragma once
+#if UNITY
+#include "Runtime/PluginInterface/Headers/IUnityInterface.h"
+#else
+#include "IUnityInterface.h"
+#endif
+#include
+#include
+#include
+
+// Should only be used on the rendering thread unless noted otherwise.
+UNITY_DECLARE_INTERFACE(IUnityGraphicsAgcPS5)
+{
+ void *(UNITY_INTERFACE_API * AllocateGPUMemory)(size_t size, int alignment);
+ void(UNITY_INTERFACE_API * ReleaseGPUMemory)(void *data);
+
+ void* (UNITY_INTERFACE_API * AllocateContiguousPhysicalGPUMemory)(size_t size, int alignment);
+ void(UNITY_INTERFACE_API * ReleaseContiguousPhysicalGPUMemory)(void* data);
+
+ void(UNITY_INTERFACE_API * SubmitGraphics)(sce::Agc::PacketAddress dcbGpuAddr, uint32_t dcbSizeInDwords);
+
+ int (UNITY_INTERFACE_API * GetCurrentRenderTargetNum)();
+ void (UNITY_INTERFACE_API * GetCurrentRenderTarget)(sce::Agc::CxRenderTarget *renderTarget, int index);
+ void (UNITY_INTERFACE_API * GetCurrentDepthRenderTarget)(sce::Agc::CxDepthRenderTarget *depthRenderTarget);
+};
+UNITY_REGISTER_INTERFACE_GUID(0xE55C42913A8F419DULL, 0x872AB8A995684235ULL, IUnityGraphicsAgcPS5)
diff --git a/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphicsPS5.h b/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphicsPS5.h
new file mode 100644
index 0000000..8da3a8e
--- /dev/null
+++ b/Tools/PSSRPlugin/UnityPluginAPI/IUnityGraphicsPS5.h
@@ -0,0 +1,21 @@
+// Unity Native Plugin API copyright © 2020 Unity Technologies ApS
+//
+// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
+//
+// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions.
+
+#pragma once
+#include "IUnityInterface.h"
+
+// Should only be used on the rendering thread unless noted otherwise.
+UNITY_DECLARE_INTERFACE(IUnityGraphicsPS5)
+{
+ void* (UNITY_INTERFACE_API * GetGfxContext)();
+
+ void *(UNITY_INTERFACE_API * AllocateGPUMemory)(size_t size, int alignment);
+ void(UNITY_INTERFACE_API * ReleaseGPUMemory)(void *data);
+
+ void *(UNITY_INTERFACE_API * GetCurrentRenderTarget)(int index);
+ void *(UNITY_INTERFACE_API * GetCurrentDepthRenderTarget)();
+};
+UNITY_REGISTER_INTERFACE_GUID(0x74a62b5d78f14e8ULL, 0xa60947365e5561ceULL, IUnityGraphicsPS5)
diff --git a/Tools/PSSRPlugin/UnityPluginAPI/IUnityInterface.h b/Tools/PSSRPlugin/UnityPluginAPI/IUnityInterface.h
new file mode 100644
index 0000000..c58be02
--- /dev/null
+++ b/Tools/PSSRPlugin/UnityPluginAPI/IUnityInterface.h
@@ -0,0 +1,209 @@
+// Unity Native Plugin API copyright © 2015 Unity Technologies ApS
+//
+// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
+//
+// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions.
+
+#pragma once
+
+// Unity native plugin API
+// Compatible with C99
+
+#if defined(__CYGWIN32__)
+ #define UNITY_INTERFACE_API __stdcall
+ #define UNITY_INTERFACE_EXPORT __declspec(dllexport)
+#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WINAPI_FAMILY)
+ #define UNITY_INTERFACE_API __stdcall
+ #define UNITY_INTERFACE_EXPORT __declspec(dllexport)
+#elif defined(__ORBIS__) || defined(__PROSPERO__)
+ #define UNITY_INTERFACE_API
+ #define UNITY_INTERFACE_EXPORT __declspec(dllexport)
+#elif defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(LUMIN)
+ #define UNITY_INTERFACE_API
+ #define UNITY_INTERFACE_EXPORT __attribute__ ((visibility ("default")))
+#else
+ #define UNITY_INTERFACE_API
+ #define UNITY_INTERFACE_EXPORT
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// IUnityInterface is a registry of interfaces we choose to expose to plugins.
+//
+// USAGE:
+// ---------
+// To retrieve an interface a user can do the following from a plugin, assuming they have the header file for the interface:
+//
+// IMyInterface * ptr = registry->Get();
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Unity Interface GUID
+// Ensures global uniqueness.
+//
+// Template specialization is used to produce a means of looking up a GUID from its interface type at compile time.
+// The net result should compile down to passing around the GUID.
+//
+// UNITY_REGISTER_INTERFACE_GUID should be placed in the header file of any interface definition outside of all namespaces.
+// The interface structure and the registration GUID are all that is required to expose the interface to other systems.
+struct UnityInterfaceGUID
+{
+#ifdef __cplusplus
+ UnityInterfaceGUID(unsigned long long high, unsigned long long low)
+ : m_GUIDHigh(high)
+ , m_GUIDLow(low)
+ {
+ }
+
+ UnityInterfaceGUID(const UnityInterfaceGUID& other)
+ {
+ m_GUIDHigh = other.m_GUIDHigh;
+ m_GUIDLow = other.m_GUIDLow;
+ }
+
+ UnityInterfaceGUID& operator=(const UnityInterfaceGUID& other)
+ {
+ m_GUIDHigh = other.m_GUIDHigh;
+ m_GUIDLow = other.m_GUIDLow;
+ return *this;
+ }
+
+ bool Equals(const UnityInterfaceGUID& other) const { return m_GUIDHigh == other.m_GUIDHigh && m_GUIDLow == other.m_GUIDLow; }
+ bool LessThan(const UnityInterfaceGUID& other) const { return m_GUIDHigh < other.m_GUIDHigh || (m_GUIDHigh == other.m_GUIDHigh && m_GUIDLow < other.m_GUIDLow); }
+#endif
+ unsigned long long m_GUIDHigh;
+ unsigned long long m_GUIDLow;
+};
+#ifdef __cplusplus
+inline bool operator==(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return left.Equals(right); }
+inline bool operator!=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !left.Equals(right); }
+inline bool operator<(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return left.LessThan(right); }
+inline bool operator>(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return right.LessThan(left); }
+inline bool operator>=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !operator<(left, right); }
+inline bool operator<=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !operator>(left, right); }
+#else
+typedef struct UnityInterfaceGUID UnityInterfaceGUID;
+#endif
+
+
+#ifdef __cplusplus
+ #define UNITY_DECLARE_INTERFACE(NAME) \
+ struct NAME : IUnityInterface
+
+// Generic version of GetUnityInterfaceGUID to allow us to specialize it
+// per interface below. The generic version has no actual implementation
+// on purpose.
+//
+// If you get errors about return values related to this method then
+// you have forgotten to include UNITY_REGISTER_INTERFACE_GUID with
+// your interface, or it is not visible at some point when you are
+// trying to retrieve or add an interface.
+template
+inline const UnityInterfaceGUID GetUnityInterfaceGUID();
+
+// This is the macro you provide in your public interface header
+// outside of a namespace to allow us to map between type and GUID
+// without the user having to worry about it when attempting to
+// add or retrieve and interface from the registry.
+ #define UNITY_REGISTER_INTERFACE_GUID(HASHH, HASHL, TYPE) \
+ template<> \
+ inline const UnityInterfaceGUID GetUnityInterfaceGUID() \
+ { \
+ return UnityInterfaceGUID(HASHH,HASHL); \
+ }
+
+// Same as UNITY_REGISTER_INTERFACE_GUID but allows the interface to live in
+// a particular namespace. As long as the namespace is visible at the time you call
+// GetUnityInterfaceGUID< INTERFACETYPE >() or you explicitly qualify it in the template
+// calls this will work fine, only the macro here needs to have the additional parameter
+ #define UNITY_REGISTER_INTERFACE_GUID_IN_NAMESPACE(HASHH, HASHL, TYPE, NAMESPACE) \
+ const UnityInterfaceGUID TYPE##_GUID(HASHH, HASHL); \
+ template<> \
+ inline const UnityInterfaceGUID GetUnityInterfaceGUID< NAMESPACE :: TYPE >() \
+ { \
+ return UnityInterfaceGUID(HASHH,HASHL); \
+ }
+
+// These macros allow for C compatibility in user code.
+ #define UNITY_GET_INTERFACE_GUID(TYPE) GetUnityInterfaceGUID< TYPE >()
+
+
+#else
+ #define UNITY_DECLARE_INTERFACE(NAME) \
+ typedef struct NAME NAME; \
+ struct NAME
+
+// NOTE: This has the downside that one some compilers it will not get stripped from all compilation units that
+// can see a header containing this constant. However, it's only for C compatibility and thus should have
+// minimal impact.
+ #define UNITY_REGISTER_INTERFACE_GUID(HASHH, HASHL, TYPE) \
+ const UnityInterfaceGUID TYPE##_GUID = {HASHH, HASHL};
+
+// In general namespaces are going to be a problem for C code any interfaces we expose in a namespace are
+// not going to be usable from C.
+ #define UNITY_REGISTER_INTERFACE_GUID_IN_NAMESPACE(HASHH, HASHL, TYPE, NAMESPACE)
+
+// These macros allow for C compatibility in user code.
+ #define UNITY_GET_INTERFACE_GUID(TYPE) TYPE##_GUID
+#endif
+
+// Using this in user code rather than INTERFACES->Get() will be C compatible for those places in plugins where
+// this may be needed. Unity code itself does not need this.
+#define UNITY_GET_INTERFACE(INTERFACES, TYPE) (TYPE*)INTERFACES->GetInterfaceSplit (UNITY_GET_INTERFACE_GUID(TYPE).m_GUIDHigh, UNITY_GET_INTERFACE_GUID(TYPE).m_GUIDLow);
+
+
+#ifdef __cplusplus
+struct IUnityInterface
+{
+};
+#else
+typedef void IUnityInterface;
+#endif
+
+
+typedef struct IUnityInterfaces
+{
+ // Returns an interface matching the guid.
+ // Returns nullptr if the given interface is unavailable in the active Unity runtime.
+ IUnityInterface* (UNITY_INTERFACE_API * GetInterface)(UnityInterfaceGUID guid);
+
+ // Registers a new interface.
+ void(UNITY_INTERFACE_API * RegisterInterface)(UnityInterfaceGUID guid, IUnityInterface * ptr);
+
+ // Split APIs for C
+ IUnityInterface* (UNITY_INTERFACE_API * GetInterfaceSplit)(unsigned long long guidHigh, unsigned long long guidLow);
+ void(UNITY_INTERFACE_API * RegisterInterfaceSplit)(unsigned long long guidHigh, unsigned long long guidLow, IUnityInterface * ptr);
+
+#ifdef __cplusplus
+ // Helper for GetInterface.
+ template
+ INTERFACE* Get()
+ {
+ return static_cast(GetInterface(GetUnityInterfaceGUID()));
+ }
+
+ // Helper for RegisterInterface.
+ template
+ void Register(IUnityInterface* ptr)
+ {
+ RegisterInterface(GetUnityInterfaceGUID(), ptr);
+ }
+
+#endif
+} IUnityInterfaces;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// If exported by a plugin, this function will be called when the plugin is loaded.
+void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces);
+// If exported by a plugin, this function will be called when the plugin is about to be unloaded.
+void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload();
+
+#ifdef __cplusplus
+}
+#endif
+
+struct RenderSurfaceBase;
+typedef struct RenderSurfaceBase* UnityRenderBuffer;
+typedef unsigned int UnityTextureID;
diff --git a/Tools/PSSRPlugin/UnityPluginAPI/IUnityLog.h b/Tools/PSSRPlugin/UnityPluginAPI/IUnityLog.h
new file mode 100644
index 0000000..c537585
--- /dev/null
+++ b/Tools/PSSRPlugin/UnityPluginAPI/IUnityLog.h
@@ -0,0 +1,37 @@
+// Unity Native Plugin API copyright © 2015 Unity Technologies ApS
+//
+// Licensed under the Unity Companion License for Unity - dependent projects--see[Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
+//
+// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.Please review the license for details on these and other terms and conditions.
+
+#pragma once
+#include "IUnityInterface.h"
+
+/// The type of the log message
+enum UnityLogType
+{
+ /// UnityLogType used for Errors.
+ kUnityLogTypeError = 0,
+ /// UnityLogType used for Warnings.
+ kUnityLogTypeWarning = 2,
+ /// UnityLogType used for regular log messages.
+ kUnityLogTypeLog = 3,
+ /// UnityLogType used for Exceptions.
+ kUnityLogTypeException = 4,
+};
+
+#define UNITY_WRAP_CODE(CODE_) do { CODE_; } while (0)
+#define UNITY_LOG(PTR_, MSG_) UNITY_WRAP_CODE((PTR_)->Log(kUnityLogTypeLog, MSG_, __FILE__, __LINE__))
+#define UNITY_LOG_WARNING(PTR_, MSG_) UNITY_WRAP_CODE((PTR_)->Log(kUnityLogTypeWarning, MSG_, __FILE__, __LINE__))
+#define UNITY_LOG_ERROR(PTR_, MSG_) UNITY_WRAP_CODE((PTR_)->Log(kUnityLogTypeError, MSG_, __FILE__, __LINE__))
+
+UNITY_DECLARE_INTERFACE(IUnityLog)
+{
+ // Writes information message to Unity log.
+ // \param type type log channel type which defines importance of the message.
+ // \param message UTF-8 null terminated string.
+ // \param fileName UTF-8 null terminated string with file name of the point where message is generated.
+ // \param fileLine integer file line number of the point where message is generated.
+ void(UNITY_INTERFACE_API * Log)(UnityLogType type, const char* message, const char *fileName, const int fileLine);
+};
+UNITY_REGISTER_INTERFACE_GUID(0x9E7507fA5B444D5DULL, 0x92FB979515EA83FCULL, IUnityLog)
diff --git a/Tools/PSSRPlugin/common.h b/Tools/PSSRPlugin/common.h
new file mode 100644
index 0000000..6e20506
--- /dev/null
+++ b/Tools/PSSRPlugin/common.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#define PSML_EXPORT __declspec (dllexport)
diff --git a/Tools/PSSRPlugin/mfsr.cpp b/Tools/PSSRPlugin/mfsr.cpp
new file mode 100644
index 0000000..f01200f
--- /dev/null
+++ b/Tools/PSSRPlugin/mfsr.cpp
@@ -0,0 +1,86 @@
+#include "common.h"
+#include
+#include
+
+using namespace sce::Psml;
+
+struct MfsrCommandInitializationData
+{
+ MfsrProfile profile;
+ uint16_t outputColorWidth;
+ uint16_t outputColorHeight;
+};
+
+struct MfsrCommandExecutionData
+{
+
+};
+
+struct MfsrTextureTable
+{
+ sce::Agc::Core::Texture* colorInput;
+ sce::Agc::Core::Texture* colorOutput;
+ sce::Agc::Core::Texture* depth;
+ sce::Agc::Core::Texture* exposureTexture;
+ sce::Agc::Core::Texture* motionVectors;
+ sce::Agc::Core::Texture* reactiveMask;
+};
+
+PSML_EXPORT bool CreateMfsrContext(const MfsrCommandInitializationData* initSettings, MfsrContext* context, MfsrSharedResources* sharedResources)
+{
+ int res = initMfsr();
+ if (res != SCE_OK && res != SCE_PSML_MFSR_ERROR_ALREADY_INITIALIZED)
+ {
+ // TODO: log error code
+ return false;
+ }
+
+ // TODO: figure out what the exact purpose of the shared resources is exactly.
+ // Does it map one-to-one with the MfsrContext or do we only ever need a single shared resources instance?
+ // This affects how we should model the internal data and the interface exposed to C#.
+ //
+ // Seems to be shared between all contexts. Just use a fixed MfsrProfile as Quality is the only one that exists right now anyway.
+ // See also: https://p.siedev.net/resources/documents/SDK/9.000/PSML_MFSR-Overview/0002.html#__document_toc_00000011
+ MfsrSharedResourcesInitParameters resParams;
+ resParams.init();
+ resParams.m_profile = initSettings->profile;
+
+ createMfsrSharedResources(sharedResources, &resParams); // TODO: handle error
+
+ MfsrContextInitParameters initParams;
+ initParams.init();
+ initParams.m_profile = initSettings->profile;
+ initParams.m_outputColorWidth = initSettings->outputColorWidth;
+ initParams.m_outputColorHeight = initSettings->outputColorHeight;
+ // TODO: allocate buffers for previous frames
+
+ createMfsrContext(context, &initParams); // TODO: handle error
+
+ return true;
+}
+
+PSML_EXPORT void DestroyMfsrContext(MfsrContext context, MfsrSharedResources sharedResources)
+{
+ releaseMfsrContext(context);
+ releaseMfsrSharedResources(sharedResources);
+}
+
+PSML_EXPORT void ExecuteMfsr(sce::Agc::DrawCommandBuffer* cmd, MfsrContext context, const MfsrTextureTable* textures) // TODO: add dispatch params (initData & executeData)
+{
+ // TODO: flushing cache on input textures equivalent to SyncCacheOp::kFlushWritesToGl2 may be necessary, depending on what Unity does or doesn't do internally.
+ // This means basically invalidating all write caches, making sure that dispatchMfsr() gets to see all the latest data when it reads from the input textures.
+ // See technote: https://p.siedev.net/technotes/view/644/1
+
+ DispatchMfsrParameters dispatchParams;
+ dispatchParams.init(); // TODO: might want to reuse these params as init() is relatively expensive
+ dispatchParams.m_color = textures->colorInput;
+ dispatchParams.m_outputColor = textures->colorOutput;
+ dispatchParams.m_depth = textures->depth;
+ dispatchParams.m_exposure = textures->exposureTexture;
+ dispatchParams.m_motionVectors = textures->motionVectors;
+ dispatchParams.m_reactiveMask = textures->reactiveMask;
+ // TODO: add data from initData & executeData
+ // TODO: where exactly do the shared resources feature in all this?
+
+ dispatchMfsr(context, cmd, &dispatchParams); // TODO: handle error
+}
diff --git a/Tools/PSSRPlugin/prx.cpp b/Tools/PSSRPlugin/prx.cpp
new file mode 100644
index 0000000..a738e53
--- /dev/null
+++ b/Tools/PSSRPlugin/prx.cpp
@@ -0,0 +1,36 @@
+#include
+#include
+
+// We need to provide an export to force the expected stub library to be generated
+__declspec (dllexport) void dummy()
+{
+ if (sceSysmoduleLoadModule(SCE_SYSMODULE_PSML) != SCE_OK)
+ {
+ return;
+ }
+
+ sce::Psml::initMfsr(); // TODO: probably returns an error code if PSSR is not supported (0 is okay, SCE_PSML_MFSR_ERROR_ALREADY_INITIALIZED is also okay, everything else is error)
+
+ sce::Psml::MfsrSharedResourcesInitParameters resParams;
+ resParams.init();
+
+ sce::Psml::MfsrSharedResources sharedResources;
+ sce::Psml::createMfsrSharedResources(&sharedResources, &resParams); // TODO: handle error
+
+ sce::Psml::MfsrContextInitParameters initParams;
+ initParams.init();
+
+ sce::Psml::MfsrContext context;
+ sce::Psml::createMfsrContext(&context, &initParams); // TODO: handle error
+
+ sce::Psml::DispatchMfsrParameters dispatchParams;
+ dispatchParams.init(); // TOOD: get this stuff from Unity
+
+ sce::Psml::dispatchMfsr(context, nullptr, &dispatchParams); // TODO: get command buffer pointer from Unity
+
+ sce::Psml::releaseMfsrContext(context);
+ context = nullptr;
+
+ sce::Psml::releaseMfsrSharedResources(sharedResources);
+ sharedResources = nullptr;
+}
diff --git a/Tools/PSSRPlugin/psml.cpp b/Tools/PSSRPlugin/psml.cpp
new file mode 100644
index 0000000..c1d78d7
--- /dev/null
+++ b/Tools/PSSRPlugin/psml.cpp
@@ -0,0 +1,7 @@
+#include "common.h"
+#include
+
+PSML_EXPORT bool Load()
+{
+ return sceSysmoduleLoadModule(SCE_SYSMODULE_PSML) == SCE_SYSMODULE_LOADED;
+}
diff --git a/Tools/PSSRPlugin/pssrplugin.cpp b/Tools/PSSRPlugin/pssrplugin.cpp
new file mode 100644
index 0000000..f842404
--- /dev/null
+++ b/Tools/PSSRPlugin/pssrplugin.cpp
@@ -0,0 +1,464 @@
+#include "common.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "UnityPluginAPI/IUnityInterface.h"
+#include "UnityPluginAPI/IUnityLog.h"
+#include "UnityPluginAPI/IUnityGraphics.h"
+
+#include "UnityPluginAPI/IUnityGraphicsPS5.h"
+#include "UnityPluginAPI/IUnityGraphicsAgcPS5.h"
+
+using namespace sce::Agc;
+using namespace sce::Psml;
+
+static IUnityInterfaces* s_UnityInterfaces = nullptr;
+static IUnityLog* s_Log = nullptr;
+static IUnityGraphics* s_Graphics = nullptr;
+static IUnityGraphicsPS5* s_GraphicsPS5 = nullptr; // Old Gnmp-based graphics API
+static IUnityGraphicsAgcPS5* s_GraphicsAgcPS5 = nullptr; // New Agc-based graphics API (NGGC)
+static UnityGfxRenderer s_RendererType = kUnityGfxRendererNull;
+
+MfsrPhysicalMemoryBlock* s_mfsrSharedResourcesMemoryBlocks = nullptr;
+MfsrSharedResources s_mfsrSharedResources = nullptr;
+
+// Just use a single context for now to keep things simple
+// "Multiple contexts (up to 4) can be generated to perform multiple MFSR processes within an application."
+static bool s_mfsrInitialized = false;
+static Core::BasicContext s_AgcContext;
+static MfsrPhysicalMemoryBlock* s_mfsrMemoryBlocks = nullptr;
+static MfsrContext s_mfsrContext = nullptr;
+static Core::Texture s_outputColorTexture;
+
+static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType);
+static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data);
+
+// Unity plugin load event
+extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
+{
+ s_UnityInterfaces = unityInterfaces;
+ s_Log = unityInterfaces->Get();
+ s_Graphics = unityInterfaces->Get();
+
+ s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
+
+ // Run OnGraphicsDeviceEvent(initialize) manually on plugin load
+ // to not miss the event in case the graphics device is already initialized
+ OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
+}
+
+// Unity plugin unload event
+extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
+{
+ s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
+}
+
+// Freely defined function to pass a callback to plugin-specific scripts
+extern "C" UnityRenderingEventAndData UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API GetRenderEventAndDataFunc()
+{
+ return OnRenderEventAndData;
+}
+
+static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
+{
+ switch (eventType)
+ {
+ case kUnityGfxDeviceEventInitialize:
+ {
+ s_RendererType = s_Graphics->GetRenderer();
+ if (s_RendererType != kUnityGfxRendererPS5 && s_RendererType != kUnityGfxRendererPS5NGGC)
+ {
+ return;
+ }
+
+ s_GraphicsPS5 = s_UnityInterfaces->Get();
+ s_GraphicsAgcPS5 = s_UnityInterfaces->Get();
+ if (s_GraphicsPS5 == nullptr && s_GraphicsAgcPS5 == nullptr)
+ {
+ UNITY_LOG_ERROR(s_Log, "Could not obtain PS5 Graphics interface!");
+ return;
+ }
+
+ // Yeah just don't do the stuff below. It makes Unity act weirdly.
+ //UnityD3D12PluginEventConfig config;
+ //config.graphicsQueueAccess = kUnityD3D12GraphicsQueueAccess_DontCare;
+ //config.flags = kUnityD3D12EventConfigFlag_ModifiesCommandBuffersState;
+ //config.ensureActiveRenderTextureIsBound = true; // TODO: not entirely sure if this is necessary
+ //s_GraphicsD3D12->ConfigureEvent(1, &config);
+
+ //config.graphicsQueueAccess = kUnityD3D12GraphicsQueueAccess_DontCare;
+ //config.flags = 0;
+ //config.ensureActiveRenderTextureIsBound = false;
+ //s_GraphicsD3D12->ConfigureEvent(2, &config);
+
+ break;
+ }
+ case kUnityGfxDeviceEventShutdown:
+ {
+ s_GraphicsPS5 = nullptr;
+ s_GraphicsAgcPS5 = nullptr;
+ s_RendererType = kUnityGfxRendererNull;
+ break;
+ }
+ case kUnityGfxDeviceEventBeforeReset:
+ {
+ //TODO: user Direct3D 9 code
+ break;
+ }
+ case kUnityGfxDeviceEventAfterReset:
+ {
+ //TODO: user Direct3D 9 code
+ break;
+ }
+ };
+}
+
+extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API InitPssr()
+{
+ // Check if we're running on PS5 Pro
+ if (!sceKernelIsTrinityMode())
+ {
+ UNITY_LOG_ERROR(s_Log, "Kernel is not running in Trinity mode, PSML is not supported!");
+ return false;
+ }
+
+ // Load PSML module
+ if (sceSysmoduleIsLoaded(SCE_SYSMODULE_PSML) != SCE_SYSMODULE_LOADED)
+ {
+ int res = sceSysmoduleLoadModule(SCE_SYSMODULE_PSML);
+ if (res < SCE_OK)
+ {
+ std::stringstream msg;
+ msg << "Failed to load PSML sysmodule, error code = " << res;
+ UNITY_LOG_ERROR(s_Log, msg.str().c_str());
+ return false;
+ }
+ }
+
+ // Initialize MFSR
+ int res = initMfsr();
+ if (res != SCE_OK && res != SCE_PSML_MFSR_ERROR_ALREADY_INITIALIZED)
+ {
+ std::stringstream msg;
+ msg << "Failed to initialize MFSR, error code = " << res;
+ UNITY_LOG_ERROR(s_Log, msg.str().c_str());
+ return false;
+ }
+
+ // TODO: do some idempotence here, make sure we don't create shared resources twice
+
+ // Set up MFSR shared resources
+ {
+ // Get required physical memory blocks sizeAlign for initializing MFSR shared resources
+ MfsrSharedResourcesInitParameters mfsrSharedResourcesInitParameters;
+ mfsrSharedResourcesInitParameters.init();
+ mfsrSharedResourcesInitParameters.m_profile = MfsrProfile::kQuality;
+
+ MfsrSharedResourcesInitRequirement mfsrSharedResourcesInitRequirement;
+ getMfsrSharedResourcesInitRequirement(&mfsrSharedResourcesInitRequirement, &mfsrSharedResourcesInitParameters);
+
+ // Allocate physical memory blocks for MFSR shared resource and setup shared resources init param
+ s_mfsrSharedResourcesMemoryBlocks = new MfsrPhysicalMemoryBlock[mfsrSharedResourcesInitRequirement.m_physicalMemoryBlockCount];
+
+ size_t blockSize = mfsrSharedResourcesInitRequirement.m_physicalMemoryBlockSize;
+ size_t blockAlign = mfsrSharedResourcesInitRequirement.m_physicalMemoryBlockAlignment;
+
+ size_t m_mfsrSharedResourcesMemorySize = mfsrSharedResourcesInitRequirement.m_physicalMemoryBlockCount * blockSize;
+ off_t m_mfsrSharedResourcesMemoryAddress;
+ sceKernelAllocateMainDirectMemory(m_mfsrSharedResourcesMemorySize, blockAlign, SCE_KERNEL_MTYPE_C_SHARED, &m_mfsrSharedResourcesMemoryAddress);
+
+ for (uint32_t i = 0; i < mfsrSharedResourcesInitRequirement.m_physicalMemoryBlockCount; i++)
+ {
+ s_mfsrSharedResourcesMemoryBlocks[i].m_size = blockSize;
+ s_mfsrSharedResourcesMemoryBlocks[i].m_offset = m_mfsrSharedResourcesMemoryAddress + blockSize * i;
+ }
+
+ mfsrSharedResourcesInitParameters.m_physicalMemoryBlocks = s_mfsrSharedResourcesMemoryBlocks;
+ mfsrSharedResourcesInitParameters.m_physicalMemoryBlockCount = mfsrSharedResourcesInitRequirement.m_physicalMemoryBlockCount;
+
+ // Create MFSR shared resources with the memory
+ createMfsrSharedResources(&s_mfsrSharedResources, &mfsrSharedResourcesInitParameters);
+ }
+
+ s_mfsrInitialized = true;
+
+ // Set up command buffer
+ if (s_RendererType == kUnityGfxRendererPS5NGGC && s_GraphicsAgcPS5 != nullptr)
+ {
+ const size_t agcContextSize = 128 * 1024;
+ s_AgcContext.m_dcb.init(s_GraphicsAgcPS5->AllocateGPUMemory(agcContextSize, Alignment::kCommandBuffer), agcContextSize);
+ s_AgcContext.m_bdr.init(&s_AgcContext.m_dcb, &s_AgcContext.m_dcb);
+ s_AgcContext.m_sb.init(256, &s_AgcContext.m_dcb, &s_AgcContext.m_dcb);
+ }
+
+ UNITY_LOG(s_Log, "PSSR plugin initialized");
+ return true;
+}
+
+extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API ReleasePssr()
+{
+ s_mfsrInitialized = false;
+
+ if (s_GraphicsAgcPS5 != nullptr && s_AgcContext.m_dcb.m_bottom != nullptr)
+ {
+ s_GraphicsAgcPS5->ReleaseGPUMemory(s_AgcContext.m_dcb.m_bottom);
+ s_AgcContext.m_dcb.clear();
+ }
+
+ if (s_mfsrSharedResources != nullptr)
+ {
+ releaseMfsrSharedResources(s_mfsrSharedResources);
+ s_mfsrSharedResources = nullptr;
+ }
+
+ if (s_mfsrSharedResourcesMemoryBlocks != nullptr)
+ {
+ delete[] s_mfsrSharedResourcesMemoryBlocks;
+ s_mfsrSharedResourcesMemoryBlocks = nullptr;
+ }
+}
+
+typedef struct pssr_init_params_s
+{
+ uint32_t displayWidth;
+ uint32_t displayHeight;
+ uint32_t maxRenderWidth;
+ uint32_t maxRenderHeight;
+} pssr_init_params_t;
+
+typedef struct pssr_dispatch_params_s
+{
+ sce::Agc::Core::Texture* color;
+ sce::Agc::Core::Texture* depth;
+ sce::Agc::Core::Texture* motionVectors;
+ sce::Agc::Core::Texture* exposure;
+ sce::Agc::Core::Texture* reactiveMask;
+ sce::Agc::Core::Texture* outputColor;
+
+ uint32_t renderWidth;
+ uint32_t renderHeight;
+
+ Vector2f jitter;
+ Vector2f motionVectorScale;
+
+ Matrix4f camProjection;
+ Vector3f camForward;
+ Vector3f camUp;
+ Vector3f camRight;
+ Vector3d camPosition;
+ float pad;
+
+ float camNear;
+ float camFar;
+ float preExposure;
+ uint32_t resetHistory;
+
+} pssr_dispatch_params_t;
+
+extern "C" int32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API CreatePssrContext(const pssr_init_params_t* params, Core::Texture** outputColorTexture)
+{
+ MfsrContextInitParameters initParams = {};
+ initParams.init();
+ initParams.m_outputColorWidth = params->displayWidth;
+ initParams.m_outputColorHeight = params->displayHeight;
+ initParams.m_sharedResources = s_mfsrSharedResources;
+
+ // Keep a copy of the previous depth internally
+ MfsrKeepCopyTextureSpec depthCopySpec = {};
+ depthCopySpec.m_width = params->maxRenderWidth;
+ depthCopySpec.m_height = params->maxRenderHeight;
+ depthCopySpec.m_bytesPerPixel = 4; // R32_SFloat
+ initParams.m_maxSizeDepthForKeepCopy = &depthCopySpec;
+
+ // Keep a copy of the previous motion vectors internally
+ MfsrKeepCopyTextureSpec mvCopySpec = {};
+ mvCopySpec.m_width = params->maxRenderWidth;
+ mvCopySpec.m_height = params->maxRenderHeight;
+ mvCopySpec.m_bytesPerPixel = 4; // R16G16_SFloat
+ initParams.m_maxSizeMotionVectorsForKeepCopy = &mvCopySpec;
+
+ // Song and dance to set up memory used by this MFSR context
+ {
+ MfsrContextInitRequirement mfsrInitRequirement = {};
+ getMfsrContextInitRequirement(&mfsrInitRequirement, &initParams);
+
+ s_mfsrMemoryBlocks = new MfsrPhysicalMemoryBlock[mfsrInitRequirement.m_physicalMemoryBlockCount];
+
+ size_t size = mfsrInitRequirement.m_physicalMemoryBlockSize;
+ size_t align = mfsrInitRequirement.m_physicalMemoryBlockAlignment;
+
+ size_t m_mfsrMemorySize = mfsrInitRequirement.m_physicalMemoryBlockCount * size;
+ off_t m_mfsrMemoryPhysicalAddress;
+ sceKernelAllocateMainDirectMemory(m_mfsrMemorySize, align, SCE_KERNEL_MTYPE_C_SHARED, &m_mfsrMemoryPhysicalAddress);
+
+ for (uint32_t i = 0; i < mfsrInitRequirement.m_physicalMemoryBlockCount; i++)
+ {
+ s_mfsrMemoryBlocks[i].m_size = size;
+ s_mfsrMemoryBlocks[i].m_offset = m_mfsrMemoryPhysicalAddress + mfsrInitRequirement.m_physicalMemoryBlockSize * i;
+ }
+
+ initParams.m_sharedResources = s_mfsrSharedResources;
+ initParams.m_physicalMemoryBlocks = s_mfsrMemoryBlocks;
+ initParams.m_physicalMemoryBlockCount = mfsrInitRequirement.m_physicalMemoryBlockCount;
+ }
+
+ // Set up output color texture with the correct specifications (k11_11_10Float with tile mode kStandard256B)
+ {
+ Core::TextureSpec texSpec;
+ texSpec.init();
+ texSpec.setAllowNullptr(true);
+ texSpec.m_width = params->displayWidth;
+ texSpec.m_height = params->displayHeight;
+ texSpec.m_format = { Core::TypedFormat::k11_11_10Float, Core::Swizzle::kRGB1_R3S34 };
+ texSpec.setTileMode(Core::Texture::TileMode::kStandard256B);
+
+ SizeAlign sizeAlign = Core::getSize(&texSpec);
+ if (s_GraphicsPS5 != nullptr)
+ {
+ texSpec.m_dataAddress = s_GraphicsPS5->AllocateGPUMemory(sizeAlign.m_size, MfsrAlignment::kOutputTexture);
+ }
+ else if (s_GraphicsAgcPS5 != nullptr)
+ {
+ texSpec.m_dataAddress = s_GraphicsAgcPS5->AllocateGPUMemory(sizeAlign.m_size, MfsrAlignment::kOutputTexture);
+ }
+
+ int res = Core::initialize(&s_outputColorTexture, &texSpec);
+ if (res != SCE_OK)
+ {
+ std::stringstream msg;
+ msg << "Failed to create MFSR output color texture, error code = " << res;
+ UNITY_LOG_ERROR(s_Log, msg.str().c_str());
+ return res;
+ }
+
+ if (outputColorTexture != nullptr)
+ {
+ *outputColorTexture = &s_outputColorTexture;
+ }
+ }
+
+ // Finally, create the actual MFSR context
+ int res = createMfsrContext(&s_mfsrContext, &initParams);
+ if (res != SCE_OK)
+ {
+ std::stringstream msg;
+ msg << "Failed to create MFSR context, error code = " << res;
+ UNITY_LOG_ERROR(s_Log, msg.str().c_str());
+ return res;
+ }
+
+ UNITY_LOG(s_Log, "Created PSSR context!");
+ return SCE_OK;
+}
+
+// Plugin function to handle a specific rendering event
+static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data)
+{
+ if (!s_mfsrInitialized)
+ return;
+
+ if (s_RendererType == kUnityGfxRendererPS5 && s_GraphicsPS5 == nullptr)
+ return;
+
+ if (s_RendererType == kUnityGfxRendererPS5NGGC && s_GraphicsAgcPS5 == nullptr)
+ return;
+
+ // User rendering code
+ switch (eventID)
+ {
+ case 0: // Initialize PSSR
+ {
+ auto* params = (pssr_init_params_t*)data;
+ CreatePssrContext(params, nullptr);
+ break;
+ }
+ case 1: // Execute PSSR
+ {
+ if (s_mfsrContext == nullptr)
+ break;
+
+ // TODO: how do get command buffer from PS5 graphics interface? :thinking:
+ // I guess we're hoping that s_GraphicsAgcPS5->SubmitGraphics is smart enough to add the submit pointer to the currently recording command list (which seems to be the case, phew!)
+ auto* params = (pssr_dispatch_params_t*)data;
+
+ sce::Agc::DrawCommandBuffer* cmd = nullptr;
+ if (s_RendererType == kUnityGfxRendererPS5)
+ {
+ auto* gfxc = (sce::Agc::Gnmp::LightweightGfxContext*)s_GraphicsPS5->GetGfxContext();
+ cmd = &gfxc->m_agcCtx.m_dcb;
+ }
+ else if (s_RendererType == kUnityGfxRendererPS5NGGC)
+ {
+ Core::BasicContext& ctx = s_AgcContext.reset();
+ cmd = &ctx.m_dcb;
+ }
+
+ cmd->pushMarker("Dispatch MFSR");
+
+ DispatchMfsrParameters dispatchParams = {};
+ dispatchParams.init();
+ dispatchParams.m_outputColor = params->outputColor;
+ dispatchParams.m_color = params->color;
+ dispatchParams.m_motionVectors = params->motionVectors;
+ dispatchParams.m_prevDepth = nullptr; // MFSR context keeps a copy of the previous depth internally
+ dispatchParams.m_depth = params->depth;
+ dispatchParams.m_exposure = params->exposure;
+ dispatchParams.m_reactiveMask = params->reactiveMask;
+ dispatchParams.m_prevMotionVectors = nullptr; // MFSR context keeps a copy of the previous motion vectors internally
+ dispatchParams.m_preExposure = params->preExposure;
+ dispatchParams.m_projectionNoJitter = params->camProjection;
+ dispatchParams.m_camForward = params->camForward;
+ dispatchParams.m_camUp = params->camUp;
+ dispatchParams.m_camRight = params->camRight;
+ dispatchParams.m_camPosD = params->camPosition;
+ dispatchParams.m_nearZ = params->camNear;
+ dispatchParams.m_farZ = params->camFar;
+ dispatchParams.m_renderWidth = params->renderWidth;
+ dispatchParams.m_renderHeight = params->renderHeight;
+ dispatchParams.m_jitter = params->jitter;
+ dispatchParams.m_motionVectorScale = params->motionVectorScale;
+ dispatchParams.m_reset = params->resetHistory != 0;
+ dispatchParams.m_flags = MfsrOptionFlags::kReverseDepth; // TODO: make flags available as plugin input
+
+ dispatchMfsr(s_mfsrContext, cmd, &dispatchParams);
+
+ cmd->popMarker();
+
+ if (s_RendererType == kUnityGfxRendererPS5NGGC)
+ {
+ s_GraphicsAgcPS5->SubmitGraphics(cmd->getSubmitPointer(), cmd->getSubmitSize());
+ }
+ break;
+ }
+ case 2: // Destroy PSSR context
+ {
+ // TODO: release color input texture
+
+ // TODO: this still crashes often due to race conditions between dispatch above and release here
+ // The main cause will be that the MFSR context is released before the already dispatched commands are executed on the GPU
+ // Just adding mutexes everywhere is not going to fix that
+ // A cheap but slightly dirty solution would be to run this code only at EndOfFrame from Unity
+ //
+ // Another issue is that we reuse the same static s_mfsrContext pointer when recreating the MFSR context, which can lead to situations where dispatch uses the wrong context object
+ // Multi-buffering those pointers will help with that
+ if (s_mfsrContext != nullptr)
+ {
+ releaseMfsrContext(s_mfsrContext);
+ s_mfsrContext = nullptr;
+ }
+
+ if (s_mfsrMemoryBlocks != nullptr)
+ {
+ delete[] s_mfsrMemoryBlocks;
+ s_mfsrMemoryBlocks = nullptr;
+ }
+
+ UNITY_LOG(s_Log, "Destroyed PSSR context");
+ break;
+ }
+ }
+}