diff --git a/FSR3UnityPlugin.cpp b/FSR3UnityPlugin.cpp index fbf4074..6c0af06 100644 --- a/FSR3UnityPlugin.cpp +++ b/FSR3UnityPlugin.cpp @@ -33,6 +33,11 @@ static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data); struct FSR3Feature { ffx::Context upscalingContext; + + uint32_t upscaleSizeWidth; + uint32_t upscaleSizeHeight; + uint32_t flags; + FSR3TextureTable textureTable; }; @@ -139,7 +144,7 @@ extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_InitApi() extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_ShutdownApi() { - // TODO: destroy any remaining FSR3Contexts? + // TODO: destroy any remaining FSR3Features? s_BackendDesc.device = nullptr; } @@ -163,16 +168,32 @@ extern "C" uint32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_CreateFeatu return AllocateFeatureSlot(); } -extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetRenderResolutionFromQualityMode(FSR3Quality qualityMode, uint32_t displayWidth, uint32_t displayHeight, uint32_t* renderWidth, uint32_t* renderHeight) +extern "C" float UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetUpscaleRatioFromQualityMode(FSR3Quality qualityMode) { - // TODO: implement - return false; + switch (qualityMode) + { + case FSR3Quality::qQuality: + return 1.5f; + case FSR3Quality::qBalanced: + return 1.7f; + case FSR3Quality::qPerformance: + return 2.0f; + case FSR3Quality::qUltraPerformance: + return 3.0f; + default: + return 1.0f; + } } -extern "C" float UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetUpscaleRatioFromQualityMode(FSR3Quality qualityMode) +extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetRenderResolutionFromQualityMode(FSR3Quality qualityMode, uint32_t displayWidth, uint32_t displayHeight, uint32_t* renderWidth, uint32_t* renderHeight) { - // TODO: implement - return 1.0f; + if (renderWidth == nullptr || renderHeight == nullptr) + return false; + + float ratio = AMDUP_GetUpscaleRatioFromQualityMode(qualityMode); + *renderWidth = (uint32_t)roundf(displayWidth / ratio); + *renderHeight = (uint32_t)roundf(displayHeight / ratio); + return true; } extern "C" int32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetBaseEventId() @@ -183,19 +204,74 @@ extern "C" int32_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API AMDUP_GetBaseEvent // Plugin function to handle a specific rendering event static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) { + if (s_GraphicsD3D12 == nullptr || s_BackendDesc.device == nullptr) + return; + // User rendering code switch (eventID) { case BaseEventId + FSR3PluginEvent::eDestroyFeature: { uint32_t featureSlot = (uint32_t)(int64_t)data; - // TODO: destroy FSR3Context at feature slot index + if (featureSlot < 0 || featureSlot >= s_Features.size()) + return; + + auto& feature = s_Features[featureSlot]; + ffx::DestroyContext(feature.upscalingContext); + FreeFeatureSlot(featureSlot); break; } case BaseEventId + FSR3PluginEvent::eExecute: { auto* params = (FSR3CommandExecutionData*)data; + if (params->featureSlot < 0 || params->featureSlot >= s_Features.size()) + return; + + auto& feature = s_Features[params->featureSlot]; + + UnityGraphicsD3D12RecordingState state; + s_GraphicsD3D12->CommandRecordingState(&state); + + ffx::DispatchDescUpscale dispatchUpscale{}; + dispatchUpscale.commandList = state.commandList; + + dispatchUpscale.color = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.colorInput, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); + dispatchUpscale.depth = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.depth, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); + dispatchUpscale.motionVectors = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.motionVectors, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); + dispatchUpscale.exposure = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.exposureTexture, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); + dispatchUpscale.reactive = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.reactiveMask, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); + dispatchUpscale.transparencyAndComposition = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.transparencyMask, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); + dispatchUpscale.output = ffxApiGetResourceDX12((ID3D12Resource*)feature.textureTable.colorInput, FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ); // TODO: shouldn't this be FFX_API_RESOURCE_STATE_UNORDERED_ACCESS? + + dispatchUpscale.jitterOffset.x = params->jitterOffsetX; // TODO: might need to negate these + dispatchUpscale.jitterOffset.y = params->jitterOffsetY; + dispatchUpscale.motionVectorScale.x = params->MVScaleX; + dispatchUpscale.motionVectorScale.y = params->MVScaleY; + dispatchUpscale.reset = params->reset; + dispatchUpscale.enableSharpening = params->enableSharpening; + dispatchUpscale.sharpness = params->sharpness; + dispatchUpscale.frameTimeDelta = params->frameTimeDelta; + dispatchUpscale.preExposure = params->preExposure; + dispatchUpscale.renderSize.width = params->renderSizeWidth; + dispatchUpscale.renderSize.height = params->renderSizeHeight; + dispatchUpscale.upscaleSize.width = feature.upscaleSizeWidth; + dispatchUpscale.upscaleSize.height = feature.upscaleSizeHeight; + dispatchUpscale.cameraFovAngleVertical = params->cameraFovAngleVertical; + + // TODO: it's possible that Unity already does this flip, check! + if (feature.flags & FFX_UPSCALE_ENABLE_DEPTH_INVERTED) + { + dispatchUpscale.cameraFar = params->cameraNear; + dispatchUpscale.cameraNear = params->cameraFar; + } + else + { + dispatchUpscale.cameraFar = params->cameraFar; + dispatchUpscale.cameraNear = params->cameraNear; + } + + ffx::Dispatch(feature.upscalingContext, dispatchUpscale); break; } case BaseEventId + FSR3PluginEvent::ePostExecute: @@ -205,14 +281,14 @@ static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data) } case BaseEventId + FSR3PluginEvent::eInit: { - if (s_BackendDesc.device == nullptr) - return; - auto* params = (FSR3CommandInitializationData*)data; if (params->featureSlot < 0 || params->featureSlot >= s_Features.size()) return; auto& feature = s_Features[params->featureSlot]; + feature.upscaleSizeWidth = params->displaySizeWidth; + feature.upscaleSizeHeight = params->displaySizeHeight; + feature.flags = params->flags; ffx::CreateContextDescUpscale createUpscaling; createUpscaling.maxUpscaleSize = { params->displaySizeWidth, params->displaySizeHeight }; @@ -230,16 +306,26 @@ static void UNITY_INTERFACE_API OnSetTextureEvent(int eventID, void* data) auto* params = (UnityRenderingExtTextureUpdateParamsV2*)data; uint32_t featureSlot = (params->userData >> 16) & 0xFFFF; - uint32_t textureSlot = (params->userData >> 1) & 0x7FFF; // TODO: could just use as numeric index to calculate a pointer offset + uint32_t textureSlot = (params->userData >> 1) & 0x7FFF; uint32_t clearTextureTable = params->userData & 0x1; - // TODO: should be able to just cast params->textureID directly to a D3D12Resource* + if (featureSlot < 0 || featureSlot >= s_Features.size()) + return; + + auto& feature = s_Features[featureSlot]; + if (clearTextureTable) + { + memset(&feature.textureTable, 0, sizeof(FSR3TextureTable)); + } // User rendering code switch (eventID) { case kUnityRenderingExtEventUpdateTextureBeginV2: { + // 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 + *(((intptr_t*)&feature.textureTable) + textureSlot) = params->textureID; break; } case kUnityRenderingExtEventUpdateTextureEndV2: