Fixed TAA bug where the frameIndex was a mismatch in renderer frontend/backend. Backported from VR branch

This commit is contained in:
Robert Beckebans 2024-10-23 15:41:42 +02:00
parent b9669d3788
commit d6dabb6869
9 changed files with 106 additions and 96 deletions

View file

@ -411,67 +411,7 @@ idCVar r_centerX( "r_centerX", "0", CVAR_FLOAT, "projection matrix center adjust
idCVar r_centerY( "r_centerY", "0", CVAR_FLOAT, "projection matrix center adjust" );
idCVar r_centerScale( "r_centerScale", "1", CVAR_FLOAT, "projection matrix center adjust" );
inline float sgn( float a )
{
if( a > 0.0f )
{
return ( 1.0f );
}
if( a < 0.0f )
{
return ( -1.0f );
}
return ( 0.0f );
}
// clipPlane is a plane in camera space.
void ModifyProjectionMatrix( viewDef_t* viewDef, const idPlane& clipPlane )
{
static float s_flipMatrix[16] =
{
// convert from our coordinate system (looking down X)
// to OpenGL's coordinate system (looking down -Z)
0, 0, -1, 0,
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 0, 1
};
idMat4 flipMatrix;
memcpy( &flipMatrix, &( s_flipMatrix[0] ), sizeof( float ) * 16 );
idVec4 vec = clipPlane.ToVec4();// * flipMatrix;
idPlane newPlane( vec[0], vec[1], vec[2], vec[3] );
// Calculate the clip-space corner point opposite the clipping plane
// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
// transform it into camera space by multiplying it
// by the inverse of the projection matrix
//idVec4 q;
//q.x = (sgn(newPlane[0]) + viewDef->projectionMatrix[8]) / viewDef->projectionMatrix[0];
//q.y = (sgn(newPlane[1]) + viewDef->projectionMatrix[9]) / viewDef->projectionMatrix[5];
//q.z = -1.0F;
//q.w = (1.0F + viewDef->projectionMatrix[10]) / viewDef->projectionMatrix[14];
idMat4 unprojection;
R_MatrixFullInverse( viewDef->projectionMatrix, ( float* )&unprojection );
idVec4 q = unprojection * idVec4( sgn( newPlane[0] ), sgn( newPlane[1] ), 1.0f, 1.0f );
// Calculate the scaled plane vector
idVec4 c = newPlane.ToVec4() * ( 2.0f / ( q * newPlane.ToVec4() ) );
float matrix[16];
std::memcpy( matrix, viewDef->projectionMatrix, sizeof( float ) * 16 );
// Replace the third row of the projection matrix
matrix[2] = c[0];
matrix[6] = c[1];
matrix[10] = c[2] + 1.0f;
matrix[14] = c[3];
memcpy( viewDef->projectionMatrix, matrix, sizeof( float ) * 16 );
}
#if !defined( DMAP )
@ -484,7 +424,7 @@ void R_SetupProjectionMatrix( viewDef_t* viewDef, bool doJitter )
if( R_UseTemporalAA() && doJitter && !( viewDef->renderView.rdflags & RDF_IRRADIANCE ) )
{
idVec2 jitter = tr.backend.GetCurrentPixelOffset();
idVec2 jitter = tr.backend.GetCurrentPixelOffset( viewDef->taaFrameCount );
jitterx = jitter.x;
jittery = jitter.y;
}
@ -717,6 +657,68 @@ void R_MatrixFullInverse( const float a[16], float r[16] )
// RB end
// SP begin
inline float sgn( float a )
{
if( a > 0.0f )
{
return ( 1.0f );
}
if( a < 0.0f )
{
return ( -1.0f );
}
return ( 0.0f );
}
// clipPlane is a plane in camera space.
void ModifyProjectionMatrix( viewDef_t* viewDef, const idPlane& clipPlane )
{
static float s_flipMatrix[16] =
{
// convert from our coordinate system (looking down X)
// to OpenGL's coordinate system (looking down -Z)
0, 0, -1, 0,
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 0, 1
};
idMat4 flipMatrix;
memcpy( &flipMatrix, &( s_flipMatrix[0] ), sizeof( float ) * 16 );
idVec4 vec = clipPlane.ToVec4();// * flipMatrix;
idPlane newPlane( vec[0], vec[1], vec[2], vec[3] );
// Calculate the clip-space corner point opposite the clipping plane
// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
// transform it into camera space by multiplying it
// by the inverse of the projection matrix
//idVec4 q;
//q.x = (sgn(newPlane[0]) + viewDef->projectionMatrix[8]) / viewDef->projectionMatrix[0];
//q.y = (sgn(newPlane[1]) + viewDef->projectionMatrix[9]) / viewDef->projectionMatrix[5];
//q.z = -1.0F;
//q.w = (1.0F + viewDef->projectionMatrix[10]) / viewDef->projectionMatrix[14];
idMat4 unprojection;
R_MatrixFullInverse( viewDef->projectionMatrix, ( float* )&unprojection );
idVec4 q = unprojection * idVec4( sgn( newPlane[0] ), sgn( newPlane[1] ), 1.0f, 1.0f );
// Calculate the scaled plane vector
idVec4 c = newPlane.ToVec4() * ( 2.0f / ( q * newPlane.ToVec4() ) );
float matrix[16];
std::memcpy( matrix, viewDef->projectionMatrix, sizeof( float ) * 16 );
// Replace the third row of the projection matrix
matrix[2] = c[0];
matrix[6] = c[1];
matrix[10] = c[2] + 1.0f;
matrix[14] = c[3];
memcpy( viewDef->projectionMatrix, matrix, sizeof( float ) * 16 );
}
/*
=====================
R_ObliqueProjection - adjust near plane of previously set projection matrix to perform an oblique projection

View file

@ -261,7 +261,7 @@ void SsaoPass::Render(
SsaoConstants ssaoConstants = {};
ssaoConstants.viewportOrigin = idVec2( viewDef->viewport.x1, viewDef->viewport.y1 );
ssaoConstants.viewportSize = idVec2( viewDef->viewport.GetWidth(), viewDef->viewport.GetHeight() );
ssaoConstants.pixelOffset = tr.backend.GetCurrentPixelOffset();
ssaoConstants.pixelOffset = tr.backend.GetCurrentPixelOffset( viewDef->taaFrameCount );
// RB: this actually should work but it only works with the old SSAO method ...
//ssaoConstants.matClipToView = viewDef->unprojectionToCameraRenderMatrix;

View file

@ -84,18 +84,9 @@ void TemporalAntiAliasingPass::Init(
}
}
//std::vector<ShaderMacro> MotionVectorMacros;
//MotionVectorMacros.push_back( ShaderMacro( "USE_STENCIL", useStencil ? "1" : "0" ) );
//m_MotionVectorPS = shaderFactory->CreateShader( "donut/passes/motion_vectors_ps.hlsl", "main", &MotionVectorMacros, nvrhi::ShaderType::Pixel );
auto taaMotionVectorsShaderInfo = renderProgManager.GetProgramInfo( BUILTIN_TAA_MOTION_VECTORS );
m_MotionVectorPS = taaMotionVectorsShaderInfo.ps;
//std::vector<ShaderMacro> ResolveMacros;
//ResolveMacros.push_back( ShaderMacro( "SAMPLE_COUNT", std::to_string( unresolvedColorDesc.sampleCount ) ) );
//ResolveMacros.push_back( ShaderMacro( "USE_CATMULL_ROM_FILTER", params.useCatmullRomFilter ? "1" : "0" ) );
//m_TemporalAntiAliasingCS = shaderFactory->CreateShader( "donut/passes/taa_cs.hlsl", "main", &ResolveMacros, nvrhi::ShaderType::Compute );
switch( r_antiAliasing.GetInteger() )
{
#if ID_MSAA
@ -221,12 +212,12 @@ void TemporalAntiAliasingPass::TemporalResolve(
taaConstants.inputViewSize = idVec2( viewportInput.width() + 1, viewportInput.height() + 1 );
taaConstants.outputViewOrigin = idVec2( viewportOutput.minX, viewportOutput.minY );
taaConstants.outputViewSize = idVec2( viewportOutput.width() + 1, viewportOutput.height() + 1 );
taaConstants.inputPixelOffset = GetCurrentPixelOffset();
taaConstants.inputPixelOffset = GetCurrentPixelOffset( viewDef->taaFrameCount );
taaConstants.outputTextureSizeInv = idVec2( 1.0f, 1.0f ) / idVec2( float( renderSystem->GetWidth() ), float( renderSystem->GetHeight() ) );
taaConstants.inputOverOutputViewSize = taaConstants.inputViewSize / taaConstants.outputViewSize;
taaConstants.outputOverInputViewSize = taaConstants.outputViewSize / taaConstants.inputViewSize;
taaConstants.clampingFactor = params.enableHistoryClamping ? params.clampingFactor : -1.f;
taaConstants.newFrameWeight = feedbackIsValid ? params.newFrameWeight : 1.f;
taaConstants.clampingFactor = params.enableHistoryClamping ? params.clampingFactor : -1.0f;
taaConstants.newFrameWeight = feedbackIsValid ? params.newFrameWeight : 1.0f;
taaConstants.pqC = idMath::ClampFloat( 1e-4f, 1e8f, params.maxRadiance );
taaConstants.invPqC = 1.f / taaConstants.pqC;
commandList->writeBuffer( m_TemporalAntiAliasingCB, &taaConstants, sizeof( taaConstants ) );
@ -275,7 +266,7 @@ static float VanDerCorput( size_t base, size_t index )
return ret;
}
idVec2 TemporalAntiAliasingPass::GetCurrentPixelOffset()
idVec2 TemporalAntiAliasingPass::GetCurrentPixelOffset( int frameIndex )
{
switch( r_taaJitter.GetInteger() )
{
@ -288,11 +279,11 @@ idVec2 TemporalAntiAliasingPass::GetCurrentPixelOffset()
idVec2( -0.3125f, 0.3125f ), idVec2( -0.4375f, 0.0625f ), idVec2( 0.1875f, 0.4375f ), idVec2( 0.4375f, -0.4375f )
};
return offsets[m_FrameIndex % 8];
return offsets[frameIndex % 8];
}
case( int )TemporalAntiAliasingJitter::Halton:
{
uint32_t index = ( m_FrameIndex % 16 ) + 1;
uint32_t index = ( frameIndex % 16 ) + 1;
return idVec2{ VanDerCorput( 2, index ), VanDerCorput( 3, index ) } - idVec2( 0.5f, 0.5f );
}
case( int )TemporalAntiAliasingJitter::R2:
@ -301,7 +292,7 @@ idVec2 TemporalAntiAliasingPass::GetCurrentPixelOffset()
}
case( int )TemporalAntiAliasingJitter::WhiteNoise:
{
std::mt19937 rng( m_FrameIndex );
std::mt19937 rng( frameIndex );
std::uniform_real_distribution<float> dist( -0.5f, 0.5f );
return idVec2{ dist( rng ), dist( rng ) };
}

View file

@ -116,12 +116,6 @@ public:
const viewDef_t* viewDef,
const CreateParameters& params );
void RenderMotionVectors(
nvrhi::ICommandList* commandList,
const viewDef_t* viewDef,
const viewDef_t* viewDefPrevious,
idVec3 preViewTranslationDifference = vec3_zero );
void TemporalResolve(
nvrhi::ICommandList* commandList,
const TemporalAntiAliasingParameters& params,
@ -129,7 +123,7 @@ public:
const viewDef_t* viewDef );
void AdvanceFrame();
idVec2 GetCurrentPixelOffset();
idVec2 GetCurrentPixelOffset( int frameIndex );
uint32_t GetFrameIndex() const
{

View file

@ -4865,11 +4865,11 @@ void idRenderBackend::TemporalAAPass( const viewDef_t* _viewDef )
renderLog.CloseMainBlock();
}
idVec2 idRenderBackend::GetCurrentPixelOffset() const
idVec2 idRenderBackend::GetCurrentPixelOffset( int frameIndex ) const
{
if( taaPass )
{
return taaPass->GetCurrentPixelOffset();
return taaPass->GetCurrentPixelOffset( frameIndex );
}
return idVec2( 0, 0 );
@ -5309,6 +5309,8 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
resolutionScale.SetCurrentGPUFrameTime( commonLocal.GetRendererGPUMicroseconds() );
// make sure the swapchains and rendertargets have the size requested
// by the window system
ResizeImages();
if( cmds->commandId == RC_NOP && !cmds->next )
@ -5319,7 +5321,6 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
if( renderSystem->GetStereo3DMode() != STEREO3D_OFF )
{
StereoRenderExecuteBackEndCommands( cmds );
//renderLog.EndFrame();
return;
}
@ -5440,7 +5441,7 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
break;
default:
common->Error( "RB_ExecuteBackEndCommands: bad commandId" );
common->Error( "ExecuteBackEndCommands: bad commandId" );
break;
}
}
@ -5459,8 +5460,6 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
common->Printf( "3d: %i, 2d: %i, SetBuf: %i, CpyRenders: %i, CpyFrameBuf: %i\n", c_draw3d, c_draw2d, c_setBuffers, c_copyRenders, pc.c_copyFrameBuffer );
pc.c_copyFrameBuffer = 0;
}
//renderLog.EndFrame();
}
@ -5482,7 +5481,23 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
OPTICK_GPU_CONTEXT( ( void* ) commandList->getNativeObject( commandObject ) );
//OPTICK_GPU_EVENT( "DrawView" ); // SRS - now in DrawView() for 3D vs. GUI
renderLog.OpenBlock( "Render_DrawViewInternal", colorRed );
// ugly but still faster than building the string
if( !_viewDef->viewEntitys || _viewDef->is2Dgui )
{
renderLog.OpenBlock( "Render_DrawView2D", colorRed );
}
else if( stereoEye == -1 )
{
renderLog.OpenBlock( "Render_DrawView3D_LeftEye", colorRed );
}
else if( stereoEye == 1 )
{
renderLog.OpenBlock( "Render_DrawView3D_RightEye", colorRed );
}
else if( stereoEye == 0 )
{
renderLog.OpenBlock( "Render_DrawView3D", colorRed );
}
//-------------------------------------------------
// guis can wind up referencing purged images that need to be loaded.
@ -5860,6 +5875,7 @@ Experimental feature
*/
void idRenderBackend::MotionBlur()
{
#if 0
if( !viewDef->viewEntitys )
{
// 3D views only
@ -5958,6 +5974,7 @@ void idRenderBackend::MotionBlur()
globalImages->currentDepthImage->Bind();
DrawElementsWithCounters( &unitSquareSurface );
#endif
}
/*

View file

@ -218,7 +218,7 @@ private:
public:
uint64 GL_GetCurrentState() const;
idVec2 GetCurrentPixelOffset() const;
idVec2 GetCurrentPixelOffset( int frameIndex ) const;
nvrhi::ICommandList* GL_GetCommandList() const
{

View file

@ -481,7 +481,7 @@ struct calcEnvprobeParms_t
idStr filename;
// output
halfFloat_t* outBuffer; // HDR R11G11B11F packed octahedron atlas
halfFloat_t* outBuffer; // HDR RGB16F packed octahedron atlas
int time; // execution time in milliseconds
};
@ -505,7 +505,7 @@ struct calcLightGridPointParms_t
SphericalHarmonicsT<idVec3, 4> shRadiance; // L4 Spherical Harmonics
#endif
halfFloat_t* outBuffer; // HDR R11G11B11F octahedron LIGHTGRID_IRRADIANCE_SIZE^2
halfFloat_t* outBuffer; // HDR RGB16F octahedron LIGHTGRID_IRRADIANCE_SIZE^2
int time; // execution time in milliseconds
};
// RB end
@ -631,6 +631,8 @@ struct viewDef_t
idVec4 radianceImageBlends; // blending weights
Framebuffer* targetRender; // SP: The framebuffer to render to
int taaFrameCount; // RB: so we have the same frame index in frontend and backend
};

View file

@ -295,7 +295,7 @@ idCVar r_useLightGrid( "r_useLightGrid", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_N
idCVar r_exposure( "r_exposure", "0.5", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "HDR exposure or LDR brightness [-4.0 .. 4.0]", -4.0f, 4.0f );
idCVar r_useTemporalAA( "r_useTemporalAA", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_NEW, "only disable for debugging" );
idCVar r_taaJitter( "r_taaJitter", "3", CVAR_RENDERER | CVAR_INTEGER | CVAR_NEW, "0: None, 1: MSAA, 2: Halton, 3: R2 Sequence, 4: White Noise" );
idCVar r_taaJitter( "r_taaJitter", "1", CVAR_RENDERER | CVAR_INTEGER | CVAR_NEW, "0: None, 1: MSAA, 2: Halton, 3: R2 Sequence, 4: White Noise" );
idCVar r_taaEnableHistoryClamping( "r_taaEnableHistoryClamping", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_NEW, "" );
idCVar r_taaClampingFactor( "r_taaClampingFactor", "1.0", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
idCVar r_taaNewFrameWeight( "r_taaNewFrameWeight", "0.1", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
@ -2584,6 +2584,7 @@ int idRenderSystemLocal::GetWidth() const
{
return glConfig.nativeScreenWidth >> 1;
}
return glConfig.nativeScreenWidth;
}

View file

@ -680,6 +680,9 @@ void R_RenderView( viewDef_t* parms )
tr.viewDef = parms;
// use this same frame index for the projection matrix jittering here and in the backend!
tr.viewDef->taaFrameCount = tr.frameCount;
// setup the matrix for world space to eye space
R_SetupViewMatrix( tr.viewDef );