You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
5.7 KiB
176 lines
5.7 KiB
#pragma once
|
|
#include <stdint.h>
|
|
|
|
#include <vector>
|
|
#include <queue>
|
|
#include <mutex>
|
|
|
|
#include "UnityPluginAPI/IUnityInterface.h"
|
|
|
|
#include "FSR3UnityTypes.h"
|
|
|
|
template<typename TFeature> class UpscalerGraphicsDevice
|
|
{
|
|
public:
|
|
virtual bool Init() = 0; // Called by AMDUP_InitAPI, does FidelityFX library loading
|
|
|
|
void Shutdown()
|
|
{
|
|
// Called by AMDUP_ShutdownAPI, destroys all features, cleans up internal resources
|
|
size_t numFeatures = 0;
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
|
numFeatures = m_Features.size();
|
|
}
|
|
|
|
for (uint32_t slot = 0; slot < numFeatures; ++slot)
|
|
{
|
|
DestroyFeature(slot);
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
|
|
|
DoShutdown();
|
|
}
|
|
|
|
uint32_t CreateFeatureSlot()
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
|
return AllocateFeatureSlot();
|
|
}
|
|
|
|
virtual bool InitFeature(const FSR3CommandInitializationData* initData)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
|
|
|
// Called by FSR3PluginEvent::eInit event
|
|
if (initData->featureSlot < 0 || initData->featureSlot >= m_Features.size())
|
|
return false;
|
|
|
|
auto& feature = m_Features[initData->featureSlot];
|
|
return InitFeature(feature, initData);
|
|
}
|
|
|
|
void DestroyFeature(uint32_t featureSlot)
|
|
{
|
|
// Called by FSR3PluginEvent::eDestroyFeature event and Shutdown
|
|
uint64_t dispatchFrameValue = 0;
|
|
{
|
|
// We need to lock the features list while we're accessing it, but we also can't hold the lock while blocking the main/render thread at the same time.
|
|
// Otherwise we're very likely to create a deadlock. So instead we only lock for as long as is necessary to grab the data we need from the feature.
|
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
|
|
|
if (featureSlot < 0 || featureSlot >= m_Features.size())
|
|
return;
|
|
|
|
auto& feature = m_Features[featureSlot];
|
|
if (!IsValidFeature(feature))
|
|
return;
|
|
|
|
dispatchFrameValue = feature.dispatchFrameValue;
|
|
}
|
|
|
|
// If there's still an upscale dispatch executing on the current frame, wait until rendering is finished before destroying its context.
|
|
AwaitEndOfFrame(dispatchFrameValue);
|
|
|
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
|
|
|
DestroyContext(m_Features[featureSlot]);
|
|
FreeFeatureSlot(featureSlot);
|
|
}
|
|
|
|
virtual void ClearTextureTable(uint32_t featureSlot)
|
|
{
|
|
if (featureSlot < 0 || featureSlot >= m_Features.size())
|
|
return;
|
|
|
|
memset(&m_Features[featureSlot].textureTable, 0, sizeof(FSR3TextureTable));
|
|
}
|
|
|
|
virtual void SetTextureSlot(uint32_t featureSlot, uint32_t textureSlot, UnityTextureID textureID)
|
|
{
|
|
if (featureSlot < 0 || featureSlot >= m_Features.size())
|
|
return;
|
|
|
|
// We organized the texture table struct to be ordered the same as the texture slot enum
|
|
// This way we can use the texture slot value simply as a pointer offset into the texture table
|
|
FSR3TextureDesc* textureDesc = ((FSR3TextureDesc*)&m_Features[featureSlot].textureTable) + textureSlot;
|
|
SetTexture(textureDesc, textureID);
|
|
}
|
|
|
|
virtual void Execute(const FSR3CommandExecutionData* execData)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
|
|
|
// Called by FSR3PluginEvent::eExecute event
|
|
if (execData->featureSlot < 0 || execData->featureSlot >= m_Features.size())
|
|
return;
|
|
|
|
auto& feature = m_Features[execData->featureSlot];
|
|
if (!IsValidFeature(feature))
|
|
return;
|
|
|
|
Execute(feature, execData);
|
|
}
|
|
|
|
virtual void PostExecute(const FSR3CommandExecutionData* execData)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
|
|
|
// Called by FSR3PluginEvent::ePostExecute event
|
|
if (execData->featureSlot < 0 || execData->featureSlot >= m_Features.size())
|
|
return;
|
|
|
|
auto& feature = m_Features[execData->featureSlot];
|
|
if (!IsValidFeature(feature))
|
|
return;
|
|
|
|
PostExecute(feature, execData);
|
|
}
|
|
|
|
protected:
|
|
virtual bool IsValidFeature(TFeature& feature) = 0;
|
|
|
|
virtual bool InitFeature(TFeature& feature, const FSR3CommandInitializationData* initData) = 0;
|
|
virtual void SetTexture(FSR3TextureDesc* textureDesc, UnityTextureID textureID) = 0;
|
|
virtual void Execute(TFeature& feature, const FSR3CommandExecutionData* execData) = 0;
|
|
virtual void PostExecute(TFeature& feature, const FSR3CommandExecutionData* execData) { }
|
|
|
|
virtual void AwaitEndOfFrame(uint64_t frameValue) = 0;
|
|
virtual void DestroyContext(TFeature& feature) = 0;
|
|
|
|
virtual void DoShutdown() = 0;
|
|
|
|
private:
|
|
uint32_t AllocateFeatureSlot()
|
|
{
|
|
if (m_FeatureSlots.empty())
|
|
{
|
|
// Create a new feature if there are no free slots
|
|
uint32_t featureSlot = (uint32_t)m_Features.size();
|
|
m_Features.push_back(std::move(TFeature()));
|
|
memset(&m_Features[featureSlot], 0, sizeof(TFeature));
|
|
return featureSlot;
|
|
}
|
|
|
|
// Reallocate an existing free slot
|
|
uint32_t featureSlot = m_FeatureSlots.front();
|
|
m_FeatureSlots.pop();
|
|
return featureSlot;
|
|
}
|
|
|
|
void FreeFeatureSlot(uint32_t featureSlot)
|
|
{
|
|
// Prevent duplicate free slots
|
|
auto& slots = m_FeatureSlots._Get_container();
|
|
if (std::find(slots.begin(), slots.end(), featureSlot) != slots.end())
|
|
return;
|
|
|
|
m_FeatureSlots.push(featureSlot);
|
|
memset(&m_Features[featureSlot], 0, sizeof(TFeature));
|
|
}
|
|
|
|
std::vector<TFeature> m_Features;
|
|
std::queue<uint32_t> m_FeatureSlots;
|
|
std::mutex m_Mutex;
|
|
};
|