Merge pull request #127 from Mauler125/amd-anti-lag

AMD Anti-Lag 2 Low Latency
This commit is contained in:
Kawe Mazidjatari 2024-09-15 12:18:38 +02:00 committed by GitHub
commit 7d7c31d4a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 527 additions and 52 deletions

View File

@ -70,6 +70,33 @@ NVIDIA NvAPI
// the above Disclaimer (as applicable) and U.S. Government End Users Notice.
////////////////////////////////////////////////////////////////////////////
************************************************************************************
AMD Anti-Lag 2
************************************************************************************
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// SPDX License Identifier: MIT
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////
************************************************************************************
Google protocol buffers
************************************************************************************

View File

@ -16,6 +16,7 @@ add_subdirectory( vphysics )
add_subdirectory( ebisusdk )
add_subdirectory( codecs )
add_subdirectory( geforce )
add_subdirectory( radeon )
set( FOLDER_CONTEXT "Protocols" )
add_subdirectory( protoc )

View File

@ -91,6 +91,7 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
"datacache"
"EbisuSDK"
"GFSDK"
"RDSDK"
"localize"

View File

@ -44,6 +44,8 @@
#include "thirdparty/nvapi/pclstats.h"
#include "thirdparty/nvapi/nvapi.h"
#include "thirdparty/nvapi/nvapi_lite_common.h"
#include "thirdparty/fidelityfx/ffx_antilag2_dx11.h"
#endif // !DEDICATED && !PLUGINSDK

View File

@ -79,7 +79,7 @@ void FrameStageNotify_Post(const ClientFrameStage_t frameStage)
case ClientFrameStage_t::FRAME_RENDER_START:
break;
case ClientFrameStage_t::FRAME_RENDER_END:
GFX_SetLatencyMarker(D3D11Device(), SIMULATION_END, MaterialSystem()->GetCurrentFrameCount());
GeForce_SetLatencyMarker(D3D11Device(), SIMULATION_END, MaterialSystem()->GetCurrentFrameCount());
break;
case ClientFrameStage_t::FRAME_NET_FULL_FRAME_UPDATE_ON_REMOVE:
break;

View File

@ -17,7 +17,7 @@ static ConVar r_drawWorldMeshesDepthAtTheEnd("r_drawWorldMeshesDepthAtTheEnd", "
void* R_DrawDepthOfField(const float scalar)
{
GFX_SetLatencyMarker(D3D11Device(), RENDERSUBMIT_START, MaterialSystem()->GetCurrentFrameCount());
GeForce_SetLatencyMarker(D3D11Device(), RENDERSUBMIT_START, MaterialSystem()->GetCurrentFrameCount());
return V_DrawDepthOfField(scalar);
}

View File

@ -48,7 +48,7 @@ void Host_CountRealTimePackets()
{
v_Host_CountRealTimePackets();
#ifndef DEDICATED
GFX_SetLatencyMarker(D3D11Device(), SIMULATION_START, MaterialSystem()->GetCurrentFrameCount());
GeForce_SetLatencyMarker(D3D11Device(), SIMULATION_START, MaterialSystem()->GetCurrentFrameCount());
#endif // !DEDICATED
}

View File

@ -23,7 +23,7 @@ bool Input_Event(const InputEvent_t& inputEvent, const int noKeyUpCheck)
if (runTriggerMarker && (inputEvent.m_nType != IE_ButtonReleased || keyInfo.m_bTrapKeyUp))
{
GFX_SetLatencyMarker(D3D11Device(), TRIGGER_FLASH, MaterialSystem()->GetCurrentFrameCount());
GeForce_SetLatencyMarker(D3D11Device(), TRIGGER_FLASH, MaterialSystem()->GetCurrentFrameCount());
}
return v_Input_Event(inputEvent, noKeyUpCheck);

View File

@ -23,6 +23,7 @@
#include "windows/id3dx.h"
#include "client/vengineclient_impl.h"
#include "geforce/reflex.h"
#include "radeon/antilag.h"
#endif // !DEDICATED
#include "filesystem/filesystem.h"
constexpr char DFS_ENABLE_PATH[] = "/vpk/enable.txt";
@ -179,15 +180,41 @@ void CEngineAPI::PumpMessages()
//-----------------------------------------------------------------------------
static void GFX_NVN_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
GFX_MarkLowLatencyParametersOutOfDate();
GeForce_MarkLowLatencyParametersOutOfDate();
}
static ConVar fps_max_gfx("fps_max_gfx", "0", FCVAR_RELEASE, "Frame rate limiter using NVIDIA Reflex Low Latency SDK. -1 indicates the use of desktop refresh. 0 is disabled.", true, -1.f, true, 295.f, GFX_NVN_Changed_f);
static void GFX_FFX_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData)
{
const ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName());
Radeon_EnableLowLatencySDK(pConVarRef->GetBool());
}
static ConVar fps_max_low_latency("fps_max_low_latency", "0", FCVAR_RELEASE, "Frame rate limiter using Low Latency SDK. -1 indicates the use of desktop refresh. 0 is disabled.", true, -1.f, true, 295.f, GFX_NVN_Changed_f);
static ConVar gfx_nvnUseLowLatency("gfx_nvnUseLowLatency", "1", FCVAR_RELEASE | FCVAR_ARCHIVE, "Enables NVIDIA Reflex Low Latency SDK.", GFX_NVN_Changed_f);
static ConVar gfx_nvnUseLowLatencyBoost("gfx_nvnUseLowLatencyBoost", "0", FCVAR_RELEASE | FCVAR_ARCHIVE, "Enables NVIDIA Reflex Low Latency Boost.", GFX_NVN_Changed_f);
// NOTE: defaulted to 0 as it causes rubber banding on some hardware.
static ConVar gfx_nvnUseMarkersToOptimize("gfx_nvnUseMarkersToOptimize", "0", FCVAR_RELEASE, "Use NVIDIA Reflex Low Latency markers to optimize (requires Low Latency Boost to be enabled).", GFX_NVN_Changed_f);
static ConVar gfx_ffxUseLowLatency("gfx_ffxUseLowLatency", "1", FCVAR_RELEASE | FCVAR_ARCHIVE, "Enables AMD Anti-Lag 2 Low Latency SDK.", GFX_FFX_Changed_f);
static float NormalizeFrameRate(const float fpsMax)
{
if (fpsMax != -1.0f)
return fpsMax;
const float globalFps = fps_max->GetFloat();
// Make sure the global fps limiter is 'unlimited'
// before we let the low-latency frame limiter cap
// it to the desktop's refresh rate; not adhering
// to this will result in a major performance drop.
if (globalFps == 0.0f)
return g_pGame->GetTVRefreshRate();
else
return 0.0f; // Don't let the low-latency SDK limit the frame rate.
}
#endif // !DEDICATED
void CEngineAPI::UpdateLowLatencyParameters()
@ -197,23 +224,9 @@ void CEngineAPI::UpdateLowLatencyParameters()
const bool bUseLowLatencyBoost = gfx_nvnUseLowLatencyBoost.GetBool();
const bool bUseMarkersToOptimize = gfx_nvnUseMarkersToOptimize.GetBool();
float fpsMax = fps_max_gfx.GetFloat();
const float fpsMax = NormalizeFrameRate(fps_max_low_latency.GetFloat());
if (fpsMax == -1.0f)
{
const float globalFps = fps_max->GetFloat();
// Make sure the global fps limiter is 'unlimited'
// before we let the gfx frame limiter cap it to
// the desktop's refresh rate; not adhering to
// this will result in a major performance drop.
if (globalFps == 0.0f)
fpsMax = g_pGame->GetTVRefreshRate();
else
fpsMax = 0.0f; // Don't let NVIDIA limit the frame rate.
}
GFX_UpdateLowLatencyParameters(D3D11Device(), bUseLowLatencyMode,
GeForce_UpdateLowLatencyParameters(D3D11Device(), bUseLowLatencyMode,
bUseLowLatencyBoost, bUseMarkersToOptimize, fpsMax);
#endif // !DEDICATED
}
@ -221,14 +234,20 @@ void CEngineAPI::UpdateLowLatencyParameters()
void CEngineAPI::RunLowLatencyFrame()
{
#ifndef DEDICATED
if (GFX_IsLowLatencySDKEnabled())
if (GeForce_IsLowLatencySDKEnabled())
{
if (GFX_HasPendingLowLatencyParameterUpdates())
if (GeForce_HasPendingLowLatencyParameterUpdates())
{
UpdateLowLatencyParameters();
}
GFX_RunLowLatencyFrame(D3D11Device());
GeForce_RunLowLatencyFrame(D3D11Device());
}
if (Radeon_IsLowLatencySDKAvailable())
{
const float maxFps = NormalizeFrameRate(fps_max_low_latency.GetFloat());
Radeon_RunLowLatencyFrame((unsigned int)maxFps);
}
#endif // !DEDICATED
}
@ -266,7 +285,7 @@ bool CEngineAPI::MainLoop()
if (g_pEngine->Frame())
{
#ifndef DEDICATED
// Only run reflex if we ran an actual engine frame.
// Only run low-latency if we ran an actual engine frame.
bRunLowLatency = true;
#endif // !DEDICATED
}

View File

@ -502,6 +502,8 @@ void Script_RegisterCoreClientFunctions(CSquirrelVM* s)
// Purpose: console variables for scripts, these should not be used in engine/sdk code !!!
//---------------------------------------------------------------------------------
static ConVar settings_reflex("settings_reflex", "1", FCVAR_RELEASE, "Selected NVIDIA Reflex mode.", "0 = Off. 1 = On. 2 = On + Boost.");
static ConVar settings_antilag("settings_antilag", "1", FCVAR_RELEASE, "Selected AMD Anti-Lag mode.", "0 = Off. 1 = On.");
static ConVar serverbrowser_hideEmptyServers("serverbrowser_hideEmptyServers", "0", FCVAR_RELEASE, "Hide empty servers in the server browser.");
static ConVar serverbrowser_mapFilter("serverbrowser_mapFilter", "0", FCVAR_RELEASE, "Filter servers by map in the server browser.");
static ConVar serverbrowser_gamemodeFilter("serverbrowser_gamemodeFilter", "0", FCVAR_RELEASE, "Filter servers by gamemode in the server browser.");

View File

@ -20,7 +20,7 @@ static NvAPI_Status s_ReflexModeUpdateStatus = NvAPI_Status::NVAPI_OK;
// Purpose: enable/disable low latency SDK
// Input : enable -
//-----------------------------------------------------------------------------
void GFX_EnableLowLatencySDK(const bool enable)
void GeForce_EnableLowLatencySDK(const bool enable)
{
s_LowLatencySDKEnabled = enable;
}
@ -28,7 +28,7 @@ void GFX_EnableLowLatencySDK(const bool enable)
//-----------------------------------------------------------------------------
// Purpose: whether we should run the low latency SDK
//-----------------------------------------------------------------------------
bool GFX_IsLowLatencySDKEnabled(void)
bool GeForce_IsLowLatencySDKEnabled(void)
{
if (!s_LowLatencySDKEnabled)
return false;
@ -42,7 +42,7 @@ bool GFX_IsLowLatencySDKEnabled(void)
//-----------------------------------------------------------------------------
// Purpose: mark the parameters as out-of-date; force update next frame
//-----------------------------------------------------------------------------
void GFX_MarkLowLatencyParametersOutOfDate(void)
void GeForce_MarkLowLatencyParametersOutOfDate(void)
{
s_ReflexModeInfoUpToDate = false;
}
@ -50,7 +50,7 @@ void GFX_MarkLowLatencyParametersOutOfDate(void)
//-----------------------------------------------------------------------------
// Purpose: mark the parameters as up-to-date
//-----------------------------------------------------------------------------
void GFX_MarkLowLatencyParametersUpToDate(void)
void GeForce_MarkLowLatencyParametersUpToDate(void)
{
s_ReflexModeInfoUpToDate = true;
}
@ -58,7 +58,7 @@ void GFX_MarkLowLatencyParametersUpToDate(void)
//-----------------------------------------------------------------------------
// Purpose: has the user requested any changes to the low latency parameters?
//-----------------------------------------------------------------------------
bool GFX_HasPendingLowLatencyParameterUpdates(void)
bool GeForce_HasPendingLowLatencyParameterUpdates(void)
{
return s_ReflexModeInfoUpToDate == false;
}
@ -66,7 +66,7 @@ bool GFX_HasPendingLowLatencyParameterUpdates(void)
//-----------------------------------------------------------------------------
// Purpose: returns whether the call to 'NvAPI_D3D_SetSleepMode' was successful
//-----------------------------------------------------------------------------
bool GFX_ParameterUpdateWasSuccessful(void)
bool GeForce_ParameterUpdateWasSuccessful(void)
{
return s_ReflexModeUpdateStatus == NvAPI_Status::NVAPI_OK;
}
@ -79,7 +79,7 @@ bool GFX_ParameterUpdateWasSuccessful(void)
// useMarkersToOptimize -
// maxFramesPerSecond -
//-----------------------------------------------------------------------------
void GFX_UpdateLowLatencyParameters(IUnknown* const device, const bool useLowLatencyMode,
void GeForce_UpdateLowLatencyParameters(IUnknown* const device, const bool useLowLatencyMode,
const bool useLowLatencyBoost, const bool useMarkersToOptimize,
const float maxFramesPerSecond)
{
@ -97,18 +97,18 @@ void GFX_UpdateLowLatencyParameters(IUnknown* const device, const bool useLowLat
params.bUseMarkersToOptimize = useMarkersToOptimize;
s_ReflexModeUpdateStatus = NvAPI_D3D_SetSleepMode(device, &params);
GFX_MarkLowLatencyParametersUpToDate();
GeForce_MarkLowLatencyParametersUpToDate();
}
//-----------------------------------------------------------------------------
// Purpose: runs a frame of the low latency sdk
// Input : *device -
//-----------------------------------------------------------------------------
void GFX_RunLowLatencyFrame(IUnknown* const device)
void GeForce_RunLowLatencyFrame(IUnknown* const device)
{
Assert(device);
if (GFX_ParameterUpdateWasSuccessful())
if (GeForce_ParameterUpdateWasSuccessful())
NvAPI_D3D_Sleep(device);
}
@ -118,12 +118,12 @@ void GFX_RunLowLatencyFrame(IUnknown* const device)
// frameNumber -
// markerType -
//-----------------------------------------------------------------------------
void GFX_SetLatencyMarker(IUnknown* const device,
void GeForce_SetLatencyMarker(IUnknown* const device,
const NV_LATENCY_MARKER_TYPE markerType, const NvU64 frameID)
{
Assert(device);
if (GFX_ParameterUpdateWasSuccessful() && GFX_IsLowLatencySDKEnabled())
if (GeForce_ParameterUpdateWasSuccessful() && GeForce_IsLowLatencySDKEnabled())
{
NV_LATENCY_MARKER_PARAMS params = {};
params.version = NV_LATENCY_MARKER_PARAMS_VER1;

View File

@ -1,19 +1,19 @@
#ifndef GFSDK_REFLEX_H
#define GFSDK_REFLEX_H
void GFX_EnableLowLatencySDK(const bool enable);
bool GFX_IsLowLatencySDKEnabled(void);
void GeForce_EnableLowLatencySDK(const bool enable);
bool GeForce_IsLowLatencySDKEnabled(void);
void GFX_MarkLowLatencyParametersOutOfDate(void);
bool GFX_HasPendingLowLatencyParameterUpdates(void);
void GeForce_MarkLowLatencyParametersOutOfDate(void);
bool GeForce_HasPendingLowLatencyParameterUpdates(void);
void GFX_UpdateLowLatencyParameters(IUnknown* device, const bool useLowLatencyMode,
void GeForce_UpdateLowLatencyParameters(IUnknown* device, const bool useLowLatencyMode,
const bool useLowLatencyBoost, const bool useMarkersToOptimize,
const float maxFramesPerSecond);
void GFX_RunLowLatencyFrame(IUnknown* device);
void GeForce_RunLowLatencyFrame(IUnknown* device);
void GFX_SetLatencyMarker(IUnknown* device,
void GeForce_SetLatencyMarker(IUnknown* device,
const NV_LATENCY_MARKER_TYPE markerType, const NvU64 frameID);
#endif // GFSDK_REFLEX_H

View File

@ -27,7 +27,7 @@ LRESULT CInputSystem::WindowProc(void* unused, HWND hwnd, UINT uMsg, WPARAM wPar
{
if (PCLSTATS_IS_PING_MSG_ID(uMsg))
{
GFX_SetLatencyMarker(D3D11Device(), PC_LATENCY_PING, MaterialSystem()->GetCurrentFrameCount());
GeForce_SetLatencyMarker(D3D11Device(), PC_LATENCY_PING, MaterialSystem()->GetCurrentFrameCount());
}
}

View File

@ -12,6 +12,7 @@
#include "engine/cmodel_bsp.h"
#include "engine/sys_engine.h"
#include "geforce/reflex.h"
#include "radeon/antilag.h"
#ifndef MATERIALSYSTEM_NODX
#include "gameui/imgui_system.h"
#include "materialsystem/cmaterialglue.h"
@ -33,6 +34,10 @@ void CMaterialSystem::Disconnect(CMaterialSystem* thisptr)
CMaterialSystem__Disconnect(thisptr);
}
#ifndef MATERIALSYSTEM_NODX
static bool s_useLowLatency = false;
#endif
//-----------------------------------------------------------------------------
// Purpose: initialization of the material system
//-----------------------------------------------------------------------------
@ -49,10 +54,14 @@ InitReturnVal_t CMaterialSystem::Init(CMaterialSystem* thisptr)
return INIT_FAILED;
#else
// Initialize as usual.
GFX_EnableLowLatencySDK(!CommandLine()->CheckParm("-gfx_nvnDisableLowLatency"));
s_useLowLatency = !CommandLine()->CheckParm("-gfx_disableLowLatency");
if (GFX_IsLowLatencySDKEnabled())
GeForce_EnableLowLatencySDK(s_useLowLatency);
Radeon_EnableLowLatencySDK(s_useLowLatency);
if (s_useLowLatency)
{
Radeon_InitLowLatencySDK();
PCLSTATS_INIT(0);
}
@ -66,9 +75,10 @@ InitReturnVal_t CMaterialSystem::Init(CMaterialSystem* thisptr)
int CMaterialSystem::Shutdown(CMaterialSystem* thisptr)
{
#ifndef MATERIALSYSTEM_NODX
if (GFX_IsLowLatencySDKEnabled())
if (s_useLowLatency)
{
PCLSTATS_SHUTDOWN();
Radeon_ShutdownLowLatencySDK();
}
#endif

View File

@ -2,6 +2,7 @@
#define IMATERIALSYSTEM_H
#define NVIDIA_VENDOR_ID 0x10DE
#define AMD_VENDOR_ID 0x10EE
//-----------------------------------------------------------------------------
// Material adapter info..

13
src/radeon/CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
cmake_minimum_required( VERSION 3.16 )
add_module( "lib" "RDSDK" "vpc" ${FOLDER_CONTEXT} TRUE TRUE )
start_sources()
add_sources( SOURCE_GROUP "Runtime"
"antilag.cpp"
"antilag.h"
)
end_sources()
target_include_directories( ${PROJECT_NAME} PRIVATE "${ENGINE_SOURCE_DIR}/tier0/" "${ENGINE_SOURCE_DIR}/tier1/" )

68
src/radeon/antilag.cpp Normal file
View File

@ -0,0 +1,68 @@
//===========================================================================//
//
// Purpose: AMD Anti-Lag 2 utilities
//
//===========================================================================//
#include "antilag.h"
#include "mathlib/mathlib.h"
#include "materialsystem/cmaterialsystem.h"
static bool s_LowLatencySDKEnabled = false;
// This will be true if the call to 'AMD::AntiLag2DX11::Initialize' succeeds.
static bool s_LowLatencyAvailable = false;
static AMD::AntiLag2DX11::Context s_LowLatencyContext = {};
//-----------------------------------------------------------------------------
// Purpose: enable/disable low latency SDK
// Input : enable -
//-----------------------------------------------------------------------------
void Radeon_EnableLowLatencySDK(const bool enable)
{
s_LowLatencySDKEnabled = enable;
}
//-----------------------------------------------------------------------------
// Purpose: whether we should run the low latency SDK
//-----------------------------------------------------------------------------
bool Radeon_IsLowLatencySDKAvailable(void)
{
if (!s_LowLatencyAvailable)
return false;
const MaterialAdapterInfo_t& adapterInfo = g_pMaterialAdapterMgr->GetAdapterInfo();
// Only run on AMD display drivers; NVIDIA and Intel are not
// supported by AMD Anti-Lag 2.
return adapterInfo.m_VendorID == AMD_VENDOR_ID;
}
//-----------------------------------------------------------------------------
// Purpose: initialize the low latency SDK
//-----------------------------------------------------------------------------
bool Radeon_InitLowLatencySDK(void)
{
if (AMD::AntiLag2DX11::Initialize(&s_LowLatencyContext) == S_OK)
s_LowLatencyAvailable = true;
return s_LowLatencyAvailable;
}
//-----------------------------------------------------------------------------
// Purpose: shutdown the low latency SDK
//-----------------------------------------------------------------------------
void Radeon_ShutdownLowLatencySDK()
{
if (AMD::AntiLag2DX11::DeInitialize(&s_LowLatencyContext) == 0)
s_LowLatencyAvailable = false;
}
//-----------------------------------------------------------------------------
// Purpose: runs a frame of the low latency sdk
// Input : maxFPS -
//-----------------------------------------------------------------------------
void Radeon_RunLowLatencyFrame(const unsigned int maxFPS)
{
Assert(Radeon_IsLowLatencySDKAvailable());
AMD::AntiLag2DX11::Update(&s_LowLatencyContext, s_LowLatencySDKEnabled, maxFPS);
}

12
src/radeon/antilag.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef RDSDK_ANTILAG_H
#define RDSDK_ANTILAG_H
void Radeon_EnableLowLatencySDK(const bool enable);
bool Radeon_IsLowLatencySDKAvailable(void);
bool Radeon_InitLowLatencySDK();
void Radeon_ShutdownLowLatencySDK();
void Radeon_RunLowLatencyFrame(const unsigned int maxFPS);
#endif // RDSDK_ANTILAG_H

View File

@ -0,0 +1,23 @@
This file is part of the Anti-Lag 2 SDK.
Copyright (C) 2024 Advanced Micro Devices, Inc.
SPDX License Identifier: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,104 @@
# Anti-Lag 2 SDK
## Overview
Reducing latency from mouse click to image-on-screen is critical in delivering a satisfying gaming experience, especially for fast-paced and competitive games. This latency occurs at various stages of the system between the user providing input via the mouse and keyboard to finally seeing the results of those actions as photons reaching the eye. This is known as end-to-end system latency.
While some parts of the system are broadly out of the game developer's control such as the input peripheral latency, or the display latency, the bit in the middle - the game itself - is somewhat more controllable.
Obviously, a higher framerate will have a pretty-much linear impact on the game's latency, but this will typically require reducing image quality and resolution. The key factor here is how much latency exists between the user input being polled and the point at which the content is sent to the display. This is where Anti-Lag comes in.
### Anti-Lag 1
Anti-Lag 1 is a pure driver-based technology that introduces a carefully calculated delay into the driver-side processing of game's graphics commands, such that CPU and GPU frames are optimally aligned. This way the CPU frames are prevented from running too far ahead of GPU frames, and as a result the lag (input-to-image latency) is reduced.
### Anti-Lag 2
Anti-Lag 2 does a similar thing to the driver-based AntiLag 1, but the point of insertion of the delay is now at the optimal point inside the game's logic, just before the user controls (mouse/gamepad/keyboard) are sampled.
This allows for an optimal alignment of the game's internal processing pipeline (and not just the in-driver producer-consumer logic), achieving a significantly greater latency reduction.
In order to achieve this improved latency reduction, the game developer needs to integrate the Anti-Lag 2 SDK into their game and (optionally) expose the its controls in the game UI.
## Integration Guide
# DirectX®11
* Include the DirectX®11 header in your game: ffx_antilag2_dx11.h
* Declare a persistent `AMD::AntiLag2DX11::Context` object initialized with `= {}` or mem-zeroed.
* Call `AMD::AntiLag2DX11::Initialize(&context)`. If this function returns `S_OK`, then Anti-Lag 2 is present in your game.
* Call `AMD::AntiLag2DX11::Update(&context,true,0)` at the point just before the game polls for input. Specify true to enable Anti-Lag 2. False, to disable it. The second parameter is an optional framerate limiter. Specify zero to disable it.
* Call `AMD::AntiLag2DX11::DeInitialize(&context)` to clean up the references to the SDK on game exit.
# DirectX®12
* Include the DirectX®12 header in your game: ffx_antilag2_dx12.h
* Declare a persistent `AMD::AntiLag2DX12::Context` object initialized with `= {}` or mem-zeroed.
* Call `AMD::AntiLag2DX12::Initialize(&context,pDevice)` passing the DX12 device into this function. If this function returns `S_OK`, then Anti-Lag 2 is present in your game.
* Call `AMD::AntiLag2DX12::Update(&context,true,0)` at the point just before the game polls for input. Specify true to enable Anti-Lag 2. False, to disable it. The second parameter is an optional framerate limiter. Specify zero to disable it.
* Call `AMD::AntiLag2DX12::DeInitialize(&context)` to clean up the references to the SDK on game exit.
## FSR 3 Frame Generation Support
Anti-Lag 2 requires some special attention when FSR 3 frame generation is enabled. There are a couple of extra Anti-Lag 2 functions required to be called to let Anti-Lag 2 know whether the presented frames are interpolated or not.
Until Anti-Lag 2 is supported in the public open-source release of FSR 3 (which is coming soon), developers are advised to reach out to their Developer Technology contacts at AMD.
# Testing
Drivers supporting Anti-Lag 2 include a built-in Radeon Anti-Lag 2 Latency Monitor:
* Use the Alt+Shift+L hotkey to cycle through the modes which can display the FPS and latency onscreen.
* The three values displayed (from top to bottom) are FPS (yellow), latency [milliseconds] (white) and latency [gpu frames] (green). The latter is most useful to make sure Anti-Lag 2 was integrated correctly.
* Normally, the latency values will be white and green - but they can also be dark grey or light gray.
* Dark grey color means that the Update() function is not being called, which would mean that there is a problem with Anti-Lag 2 integration.
* Light grey color means that the values have not self-calibrated yet - that should resolve itself within a second or two. If it doesn't, that probably means there is a problem with the integration.
* When holding down the Right Ctrl key, Anti-Lag 2 is bypassed. In this case the green number (latency in frames) indicates the native (pre-Anti-Lag 2) game latency. Usually it would be close to an integer number 3, 4 or 5.
* When Anti-Lag 2 is active, the green number (latency in frames) should be between 1.0 and 2.0, or perhaps slightly higher than 2.0. If it is higher than 3 - then there could be a problem with integration.
* Both white and green numbers should roughly match the numbers measured by FLM (see below) when VSync is not used. In DirectX®11 though, if the game is not running in fullscreen exclusive mode - there might be a one frame discrepancy (FLM values will be one frame higher).
Another way to validate the SDK integration is to use the Frame Latency Meter (FLM) which can be downloaded, along with full source, here: https://github.com/GPUOpen-Tools/frame_latency_meter/releases. Full instructions on how to use this tool are included.
# Support
Hardware:
* RDNA™ 1-based products, including the AMD Radeon™ RX 5000 Series and newer.
Driver:
* Adrenalin Edition™ 24.6.1 and onwards for DirectX®11 support.
* Adrenalin Edition™ 24.7.1 and onwards for DirectX®12 support.
OS:
* Windows®10
* Windows®11
# Strings
Recommended UI text can be found here: https://gpuopen.com/fidelityfx-naming-guidelines/
<h2>Open source</h2>
AMD Anti-Lag 2 SDK is open source, and available under the MIT license.
For more information on the license terms please refer to [license](LICENSE.txt).
<h2>Disclaimer</h2>
The information contained herein is for informational purposes only, and is subject to change without notice. While every
precaution has been taken in the preparation of this document, it may contain technical inaccuracies, omissions and typographical
errors, and AMD is under no obligation to update or otherwise correct this information. Advanced Micro Devices, Inc. makes no
representations or warranties with respect to the accuracy or completeness of the contents of this document, and assumes no
liability of any kind, including the implied warranties of noninfringement, merchantability or fitness for particular purposes, with
respect to the operation or use of AMD hardware, software or other products described herein. No license, including implied or
arising by estoppel, to any intellectual property rights is granted by this document. Terms and limitations applicable to the purchase
or use of AMD's products are as set forth in a signed agreement between the parties or in AMD's Standard Terms and Conditions
of Sale.
AMD, the AMD Arrow logo, Radeon, Ryzen, CrossFire, RDNA and combinations thereof are trademarks of Advanced Micro Devices, Inc.
Other product names used in this publication are for identification purposes only and may be trademarks of their respective companies.
DirectX is a registered trademark of Microsoft Corporation in the US and other jurisdictions.
Vulkan and the Vulkan logo are registered trademarks of the Khronos Group Inc.
Microsoft is a registered trademark of Microsoft Corporation in the US and other jurisdictions.
Windows is a registered trademark of Microsoft Corporation in the US and other jurisdictions.
© 2023-2024 Advanced Micro Devices, Inc. All rights reserved.

View File

@ -0,0 +1,192 @@
// This file is part of the Anti-Lag 2.0 SDK.
//
// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
namespace AMD {
namespace AntiLag2DX11 {
struct Context;
// Initialize function - call this once before the Update function.
// context - Declare a persistent Context variable in your game code. Ensure the contents are zero'ed, and pass the address in to initialize it.
// Be sure to use the *same* context object everywhere when calling the Anti-Lag 2.0 SDK functions.
// A return value of S_OK indicates that Anti-Lag 2.0 is available on the system.
HRESULT Initialize( Context* context );
// DeInitialize function - call this on game exit.
// context - address of the game's context object.
// The return value is the reference count of the internal API. It should be 0.
ULONG DeInitialize( Context* context );
// Update function - call this just before the input to the game is polled.
// context - address of the game's context object.
// enable - enables or disables Anti-Lag 2.0.
// maxFPS - sets a framerate limit. Zero will disable the limiter.
HRESULT Update( Context* context, bool enable, unsigned int maxFPS );
//
// End of public API section.
// Private implementation details below.
//
// Forward declaration of the Anti-Lag 2.0 interface into the DX11 driver
class IAmdDxExtInterface
{
public:
virtual unsigned int AddRef() = 0;
virtual unsigned int Release() = 0;
protected:
IAmdDxExtInterface() {} // Default constructor disabled
virtual ~IAmdDxExtInterface() = 0 {}
};
// Structure version 1 for Anti-Lag 2.0:
struct APIData_v1
{
unsigned int uiSize;
unsigned int uiVersion;
unsigned int eMode;
const char* sControlStr;
unsigned int uiControlStrLength;
unsigned int maxFPS;
};
static_assert(sizeof(APIData_v1) == 32, "Check structure packing compiler settings.");
// Forward declaration of the Anti-Lag interface into the DX11 driver
struct IAmdDxExtAntiLagApi : public IAmdDxExtInterface
{
public:
virtual HRESULT UpdateAntiLagStateDx11( APIData_v1* pApiCallbackData ) = 0;
};
// Context structure for the SDK. Declare a persistent object of this type *once* in your game code.
// Ensure the contents are initialized to zero before calling Initialize() but do not modify these members directly after that.
struct Context
{
IAmdDxExtAntiLagApi* m_pAntiLagAPI = nullptr;
bool m_enabled = false;
unsigned int m_maxFPS = 0;
};
inline HRESULT Initialize( Context* context )
{
HRESULT hr = E_INVALIDARG;
if ( context && context->m_pAntiLagAPI == nullptr )
{
HMODULE hModule = GetModuleHandleA("amdxx64.dll"); // only 64 bit is supported
if ( hModule )
{
typedef HRESULT(__cdecl* PFNAmdDxExtCreate11)(ID3D11Device* pDevice, IAmdDxExtInterface** ppAntiLagApi);
PFNAmdDxExtCreate11 AmdDxExtCreate11 = static_cast<PFNAmdDxExtCreate11>((VOID*)GetProcAddress(hModule, "AmdDxExtCreate11"));
if ( AmdDxExtCreate11 )
{
*(__int64*)&context->m_pAntiLagAPI = 0xbf380ebc5ab4d0a6; // sets up the request identifier
hr = AmdDxExtCreate11( nullptr, (IAmdDxExtInterface**)&context->m_pAntiLagAPI );
if ( hr == S_OK )
{
APIData_v1 data = {};
data.uiSize = sizeof(data);
data.uiVersion = 1;
data.eMode = 2; // Anti-Lag 2.0 is disabled during initialization
data.sControlStr = nullptr;
data.uiControlStrLength = 0;
data.maxFPS = 0;
hr = context->m_pAntiLagAPI->UpdateAntiLagStateDx11( &data );
}
if ( hr != S_OK )
{
DeInitialize( context );
}
}
}
else
{
hr = E_HANDLE;
}
}
return hr;
}
inline ULONG DeInitialize( Context* context )
{
ULONG refCount = 0;
if ( context )
{
if ( context->m_pAntiLagAPI )
{
refCount = context->m_pAntiLagAPI->Release();
context->m_pAntiLagAPI = nullptr;
}
context->m_enabled = false;
}
return refCount;
}
inline HRESULT Update( Context* context, bool enabled, unsigned int maxFPS )
{
// This function needs to be called once per frame, before the user input
// is sampled - or optionally also when the UI settings are modified.
if ( context && context->m_pAntiLagAPI )
{
// Update the Anti-Lag 2.0 internal state only when necessary:
if ( context->m_enabled != enabled || context->m_maxFPS != maxFPS )
{
context->m_enabled = enabled;
context->m_maxFPS = maxFPS;
APIData_v1 data = {};
data.uiSize = sizeof(data);
data.uiVersion = 1;
data.eMode = enabled ? 1 : 2;
data.maxFPS = maxFPS;
static const char params[] = "delag_next_osd_supported_in_dxxp = 1";
data.sControlStr = params;
data.uiControlStrLength = _countof( params ) - 1;
// Only call the function with non-null arguments when setting state.
// Make sure not to set the state every frame.
context->m_pAntiLagAPI->UpdateAntiLagStateDx11( &data );
}
// Call the function with a nullptr to insert the latency-reducing delay.
// (if the state has not been set to 'enabled' this call will have no effect)
HRESULT hr = context->m_pAntiLagAPI->UpdateAntiLagStateDx11( nullptr );
if ( hr == S_OK || hr == S_FALSE )
{
return S_OK;
}
else
{
return hr;
}
}
else
{
return E_NOINTERFACE;
}
}
} // namespace AntiLag2DX11
} // namespace AMD

View File

@ -119,11 +119,11 @@ HRESULT __stdcall Present(IDXGISwapChain* pSwapChain, UINT nSyncInterval, UINT n
// for simulation start/end and render submit start. The render thread (here)
// continues after to finish the frame.
const NvU64 frameID = (NvU64)MaterialSystem()->GetCurrentFrameCount() - 1;
GFX_SetLatencyMarker(D3D11Device(), RENDERSUBMIT_END, frameID);
GeForce_SetLatencyMarker(D3D11Device(), RENDERSUBMIT_END, frameID);
GFX_SetLatencyMarker(D3D11Device(), PRESENT_START, frameID);
GeForce_SetLatencyMarker(D3D11Device(), PRESENT_START, frameID);
const HRESULT result = s_fnSwapChainPresent(pSwapChain, nSyncInterval, nFlags);
GFX_SetLatencyMarker(D3D11Device(), PRESENT_END, frameID);
GeForce_SetLatencyMarker(D3D11Device(), PRESENT_END, frameID);
return result;
}