Migrating from FSR 3.0 to FSR 3.1

The new API for FSR 3.1 changes how applications interact with FSR in a few ways: * Upscaling and frame generation are separated. * Custom backends are no longer supported. * Backends are created in tandem with the effect context and their lifetimes are tied together. * All calls are done using ABI-stable structs with support for future extensions. See [Introduction to FidelityFX API](../docs/getting-started/ffx-api.md) for more detailed information about the new API.

API setup

Setup your build system to include headers in ffx-api/include and to link against one of the amd_fidelityfx_dx12 or amd_fidelityfx_vk libraries. In source files, include `ffx_api/ffx_api.h` for the C api or `ffx_api/ffx_api.hpp` for C++ convenience utilities. For upscaling, include `ffx_api/ffx_fsr_upscale.h` (or `.hpp`) and for frame generation, include `ffx_api/ffx_fg.h` (or `.hpp`). For backend creation and the frame generation swapchain, you will also need one of `ffx_api/dx12/ffx_api_dx12.h` or `ffx_api/vk/ffx_api_vk.h` (or `.hpp`).

Context creation

Instead of calling `ffxFsr3ContextCreate`, call `ffxCreateContext`. `ffxCreateContextDescFsrUpscale` takes a subset of parameters from `FfxFsr3ContextDescription`, except that flags now are prefixed `FFX_FSR_` instead of `FFX_FSR3_`. A backend creation description must be passed in the `pNext` field of the `header` in `ffxCreateContextDescFsrUpscale`. This can be either a `ffxCreateBackendDX12Desc` or a `ffxCreateBackendVKDesc`. The `type` field on the `header` of each structure must be set to the associated type id. In the C headers, these are adjacent to their associated types. When using the C++ namespaced types, structure types are initialized by the constructor. For frame generation, a separate context has to be created, as well as one for the frame generation swapchain (backend specific). For memory allocation, a set of callbacks can be passed. If set to `NULL`, the system `malloc` and `free` are used.

Querying Information from FSR

The functions `ffxFsr3GetUpscaleRatioFromQualityMode`, `ffxFsr3GetRenderResolutionFromQualityMode`, `ffxFsr3GetJitterPhaseCount` and `ffxFsr3GetJitterOffset` are replaced with structs passed to the `ffxQuery` function. Pointer parameters to these query functions are struct members in the new API.

Configuring FSR

`ffxFsr3ConfigureFrameGeneration` is replaced by `ffxConfigure` with the frame generation context. The configuration structure is nearly identical. A new optional callback context has been added. See the comparison table for details.

Dispatching FSR

All dispatches are done using the `ffxDispatch` function. Resources are passed in a new struct `FfxApiResource`, which is very similar to `FfxResource`, but with more platform stability. With DirectX, a helper function `ffxApiGetResourceDX12` can be used to fill the resource description. When using frame generation, a new preparation dispatch must be called every frame. This can be placed at the same location as the upscaling dispatch and takes a subset of the upscaling resources.

Comparison

The following section shows FSR 3.0 code patterns and their FSR 3.1 equivalents.

Context names

FSR 3.0

```c FfxFsr3Context fsr3Context; ```

FSR 3.1 / FFX API C

```c ffxContext upscalingContext, framegenContext; ```

FFX API C++

```c++ ffx::Context upscalingContext, framegenContext; ```

Context creation (upscaling only)

FSR 3.0

```c FfxFsr3ContextDescription fsr3ContextDesc = {0}; // create backend interface ... // fill fsr3ContextDesc ... fsr3ContextDesc.flags |= FFX_FSR3_ENABLE_UPSCALING_ONLY; ffxFsr3ContextCreate(&fsr3Context, &fsr3ContextDesc); ```

FSR 3.1 / FFX API C

```c ffxCreateContextDescFsrUpscale fsrContextDesc = {0}; fsrContextDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FSR_UPSCALE; // fill fsrContextDesc ... // backend interface desc ... fsrContextDesc.header.pNext = &backendDesc.header; ffxCreateContext(&upscalingContext, &fsrContextDesc.header, NULL); ```

FFX API C++

```c++ ffx::CreateContextDescFsrUpscale fsrContextDesc{}; // fill fsrContextDesc ... // backend interface desc ... ffx::CreateContext(&upscalingContext, nullptr, fsrContextDesc, backendDesc); ```

DX12 backend creation

FSR 3.0

```c FfxFsr3ContextDescription fsr3ContextDesc = {0}; // create backend interface (DX12) size_t scratchBufferSize = ffxGetScratchMemorySizeDX12(1); void* scratchBuffer = malloc(scrathBufferSize); memset(scratchBuffer, 0, scrathBufferSize); errorCode = ffxGetInterfaceDX12(&fsr3ContextDesc.backendInterfaceUpscaling, ffxGetDeviceDX12(dx12Device), scratchBuffer, scratchBufferSize, 1); assert(errorCode == FFX_OK); ```

FSR 3.1 / FFX API C

```c ffxCreateContextDescFsrUpscale fsrContextDesc = {0}; // fill fsrContextDesc ... // backend interface desc (dx12) ffxCreateBackendDX12Desc backendDesc = {0}; backendDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12; backendDesc.device = dx12Device; fsrContextDesc.header.pNext = &backendDesc.header; // create context and backend ffxCreateContext(&upscalingContext, &fsrContextDesc.header, NULL); ```

FFX API C++

```c++ ffx::CreateContextDescFsrUpscale fsrContextDesc{}; // fill fsrContextDesc ... // backend interface desc (dx12) ffx::CreateBackendDX12Desc backendDesc{}; backendDesc.device = dx12Device; ffx::CreateContext(&upscalingContext, nullptr, fsrContextDesc, backendDesc); ```

Context creation (upscale + framegen)

FSR 3.0

```c FfxFsr3ContextDescription fsr3ContextDesc = {0}; // create backend interface (x3) ... // fill fsr3ContextDesc ... ffxFsr3ContextCreate(&fsr3Context, &fsr3ContextDesc); ```

FSR 3.1 / FFX API C

```c ffxCreateContextDescFsrUpscale fsrContextDesc = {0}; fsrContextDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FSR_UPSCALE; // fill fsrContextDesc ... // backend interface desc ... fsrContextDesc.header.pNext = &backendDesc.header; ffxCreateContext(&upscalingContext, &fsrContextDesc.header, NULL); ffxCreateContextDescFsrFrameGeneneration fgContextDesc = {0}; // fill fgContextDesc ... // backend interface desc ... fgContextDesc.header.pNext = &backendDesc.header; ffxCreateContext(&frameGenContext, &fgContextDesc.header, NULL); ```

FFX API C++

```c++ ffx::CreateContextDescFsrUpscale fsrContextDesc{}; // fill fsrContextDesc ... // backend interface desc ... ffx::CreateContext(&upscalingContext, nullptr, fsrContextDesc, backendDesc); ffx::CreateContextDescFsrFrameGen fgContextDesc{}; // fill fgContextDesc ... // backend interface desc ... ffx::CreateContext(&frameGenContext, nullptr, fgContextDesc, backendDesc); ```

Query upscale ratio / render resolution

FSR 3.0

```c float upscaleRatio = ffxFsr3GetUpscaleRatioFromQualityMode(FFX_FSR3_QUALITY_MODE_BALANCED); uint32_t renderWidth, renderHeight; ffxFsr3GetRenderResolutionFromQualityMode(&renderWidth, &renderHeight, displayWidth, displayHeight, FFX_FSR3_QUALITY_MODE_BALANCED); ```

FSR 3.1 / FFX API C

```c float upscaleRatio; struct ffxQueryDescFsrGetUpscaleRatioFromQualityMode queryDesc1 = {0}; queryDesc1.header.type = FFX_API_QUERY_DESC_TYPE_FSR_GETUPSCALERATIOFROMQUALITYMODE; queryDesc1.qualityMode = FFX_FSR_QUALITY_MODE_BALANCED; queryDesc1.pOutUpscaleRatio = &upscaleRatio; ffxQuery(&fsrContext, &queryDesc1.header); uint32_t renderWidth, renderHeight; struct ffxQueryDescFsrGetRenderResolutionFromQualityMode queryDesc2 = {0}; queryDesc2.header.type = FFX_API_QUERY_DESC_TYPE_FSR_GETRENDERRESOLUTIONFROMQUALITYMODE; queryDesc2.displayWidth = displayWidth; queryDesc2.displayHeight = displayHeight; queryDesc2.qualityMode = FFX_FSR_QUALITY_MODE_BALANCED; queryDesc2.pOutRenderWidth = &renderWidth; queryDesc2.pOutRenderHeight = &renderHeight; ffxQuery(&fsrContext, &queryDesc2.header); ```

FFX API C++

```c++ float upscaleRatio; ffx::QueryDescFsrGetUpscaleRatioFromQualityMode queryDesc1{}; queryDesc1.qualityMode = FFX_FSR_QUALITY_MODE_BALANCED; queryDesc1.pOutUpscaleRatio = &upscaleRatio; ffx::Query(fsrContext, queryDesc1); uint32_t renderWidth, renderHeight; ffx::QueryDescFsrGetRenderResolutionFromQualityMode queryDesc2{}; queryDesc2.displayWidth = displayWidth; queryDesc2.displayHeight = displayHeight; queryDesc2.qualityMode = FFX_FSR_QUALITY_MODE_BALANCED; queryDesc2.pOutRenderWidth = &renderWidth; queryDesc2.pOutRenderHeight = &renderHeight; ffx::Query(fsrContext, queryDesc2); ```

Query Jitter count / offset

FSR 3.0

```c int32_t jitterCount = ffxFsr3GetJitterPhaseCount(renderWidth, displayWidth); float jitterX, jitterY; ffxFsr3GetJitterOffset(&jitterX, &jitterY, jitterIndex, jitterCount); ```

FSR 3.1 / FFX API C

```c int32_t jitterCount; struct ffxQueryDescFsrGetJitterPhaseCount queryDesc1 = {0}; queryDesc1.header.type = FFX_API_QUERY_DESC_TYPE_FSR_GETJITTERPHASECOUNT; queryDesc1.renderWidth = renderWidth; queryDesc1.displayWidth = displayWidth; queryDesc1.pOutPhaseCount = &jitterCount; ffxQuery(&fsrContext, &queryDesc1.header); float jitterX, jitterY; struct ffxQueryDescFsrGetJitterOffset queryDesc2 = {0}; queryDesc2.header.type = FFX_API_QUERY_DESC_TYPE_FSR_GETJITTEROFFSET; queryDesc2.index = jitterIndex; queryDesc2.phaseCount = jitterCount; queryDesc2.pOutX = &jitterX; queryDesc2.pOutY = &jitterY; ffxQuery(&fsrContext, &queryDesc2.header); ```

FFX API C++

```c++ int32_t jitterCount; ffx::QueryDescFsrGetJitterPhaseCount queryDesc1{}; queryDesc1.renderWidth = renderWidth; queryDesc1.displayWidth = displayWidth; queryDesc1.pOutPhaseCount = &jitterCount; ffx::Query(fsrContext, queryDesc1); float jitterX, jitterY; ffxQueryDescFsrGetJitterOffset queryDesc2{}; queryDesc2.index = jitterIndex; queryDesc2.phaseCount = jitterCount; queryDesc2.pOutX = &jitterX; queryDesc2.pOutY = &jitterY; ffx::Query(fsrContext, queryDesc2); ```

Configure FrameGen

FSR 3.0

```c FfxFrameGenerationConfig config = {0}; // fill config ... ffxFsr3ConfigureFrameGeneration(&fsr3Context, &config); ```

FSR 3.1 / FFX API C

```c struct ffxConfigureDescFrameGeneration config = {0}; config.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION; // fill config ... ffxConfigure(&fsrContext, &config); ```

FFX API C++

```c++ ffx::ConfigureDescFrameGeneration config{}; // fill config ... ffxConfigure(fsrContext, config); ```

Present callback

FSR 3.0

```c FfxErrorCode myPresentCallback(const FfxPresentCallbackDescription* params, void* userCtx) // note: pre-3.1 does not have user context pointer { // pre-presentation work, e.g. UI return FFX_OK; } // ... FfxFrameGenerationConfig config; config.presentCallback = myPresentCallback; config.presentCallbackContext = &myEngineContext; ```

FSR 3.1 / FFX API C

```c ffxReturnCode_t myPresentCallback(struct ffxCallbackDescFrameGenerationPresent* params, void* pUserCtx) { // pre-presentation work, e.g. UI return FFX_API_RETURN_OK; } // ... struct ffxConfigureDescFrameGeneration config; config.presentCallback = myPresentCallback; config.presentCallbackUserContext = &myEngineContext; ```

FFX API C++

```c++ extern "C" ffxReturnCode_t myPresentCallback(ffxCallbackDescFrameGenerationPresent* params, void* pUserCtx) { // pre-presentation work, e.g. UI return FFX_API_RETURN_OK; } // ... ffx::ConfigureDescFrameGeneration config; config.presentCallback = myPresentCallback; config.presentCallbackUserContext = &myEngineContext; ```

Dispatch upscaling (no fg)

FSR 3.0

```c // (context created with UPSCALING_ONLY flag) FfxFsr3DispatchUpscaleDescription params = {0}; // fill params ... ffxFsr3ContextDispatchUpscale(&fsr3Context, ¶ms); ```

FSR 3.1 / FFX API C

```c struct ffxDispatchDescFsrUpscale params = {0}; params.header.type = FFX_API_DISPATCH_DESC_TYPE_FSR_UPSCALE; // fill params ... ffxDispatch(&fsrContext, ¶ms); ```

FFX API C++

```c++ ffx::DispatchDescFsrUpscale params{}; // fill params ... ffx::Dispatch(fsrContext, params); ```

Dispatch upscaling and fg prepare

FSR 3.0

```c // dispatch upscaling and prepare resources for frame generation FfxFsr3DispatchUpscaleDescription params = {0}; // fill params ... ffxFsr3ContextDispatchUpscale(&fsr3Context, ¶ms); ```

FSR 3.1 / FFX API C

```c struct ffxDispatchDescFsrUpscale upscaleParams = {0}; upscaleParams.header.type = FFX_API_DISPATCH_DESC_TYPE_FSR_UPSCALE; struct ffxDispatchDescFrameGenerationPrepare frameGenParams = {0}; frameGenParams.header.type = FFX_API_DISPATCH_DESC_TYPE_FRAMEGENERATION_PREPARE; // fill both structs with params ... ffxDispatch(&fsrContext, &upscaleParams); ffxDispatch(&fgContext, &frameGenParams); ```

FFX API C++

```c++ ffx::DispatchDescFsrUpscale upscaleParams{}; ffx::DispatchDescFrameGenerationPrepare frameGenParams{}; // fill both structs with params ... ffx::Dispatch(fsrContext, upscaleParams); ffx::Dispatch(fgContext, frameGenParams); ```

Dispatch frame gen (no callback mode)

FSR 3.0

```c FfxFrameGenerationDispatchDescription fgDesc = {0}; ffxGetFrameinterpolationCommandlistDX12(ffxSwapChain, fgDesc.commandList); fgDesc.outputs[0] = ffxGetFrameinterpolationTextureDX12(ffxSwapChain); // other parameters ... ffxFsr3DispatchFrameGeneration(&fgDesc); ```

FSR 3.1 / FFX API C

```c struct ffxDispatchDescFrameGeneration dispatchFg = {0}; dispatchFg.header.type = FFX_API_DISPATCH_DESC_TYPE_FRAMEGENERATION; struct ffxQueryDescFrameGenerationSwapChainInterpolationCommandListDX12 queryCmdList = {0}; queryCmdList.header.type = FFX_API_QUERY_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_INTERPOLATIONCOMMANDLIST_DX12; queryCmdList.pOutCommandList = &dispatchFg.commandList; ffxQuery(&swapChainContext, &queryCmdList); struct ffxQueryDescFrameGenerationSwapChainInterpolationTextureDX12 queryFiTexture{}; queryFiTexture.header.type = FFX_API_QUERY_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_INTERPOLATIONTEXTURE_DX12; queryFiTexture.pOutTexture = &dispatchFg.outputs[0]; ffxQuery(&swapChainContext, &queryFiTexture); // other parameters ... ffxDispatch(&fgContext, &dispatchFg); ```

FFX API C++

```c++ ffx::DispatchDescFrameGeneration dispatchFg{}; ffx::QueryDescFrameGenerationSwapChainInterpolationCommandListDX12 queryCmdList{}; queryCmdList.pOutCommandList = &dispatchFg.commandList; ffx::Query(swapChainContext, queryCmdList); ffx::QueryDescFrameGenerationSwapChainInterpolationTextureDX12 queryFiTexture{}; queryFiTexture.pOutTexture = &dispatchFg.outputs[0]; ffx::Query(swapChainContext, queryFiTexture); // other parameters ... ffx::Dispatch(fgContext, dispatchFg); ```

Destroy context and backend

FSR 3.0

```c ffxFsr3ContextDestroy(&fsr3Context); // for each backend interface: free(backendInterface.scratchBuffer); ```

FSR 3.1 / FFX API C

```c ffxDestroyContext(&fsrContext, NULL); ```

FFX API C++

```c++ ffx::DestroyContext(fsrContext, nullptr); ```