Fixed rendering of FFmpeg, Binkdec videos and Doomclassic modes #648 677

This commit is contained in:
Robert Beckebans 2022-06-04 13:37:00 +02:00
parent 987085a247
commit c0dd85bb80
20 changed files with 129 additions and 78 deletions

View file

@ -1,6 +0,0 @@
cd ..
del /s /q build
mkdir build
cd build
cmake -G "Visual Studio 15 Win64" -DWINDOWS10=OFF ../neo
pause

View file

@ -1,6 +0,0 @@
cd ..
del /s /q build
mkdir build
cd build
cmake -G "Visual Studio 15 Win64" -DWINDOWS10=ON ../neo
pause

View file

@ -1,6 +0,0 @@
cd ..
del /s /q build
mkdir build
cd build
cmake -G "Visual Studio 16" -A x64 ../neo
pause

View file

@ -2,5 +2,5 @@ cd ..
del /s /q build
mkdir build
cd build
cmake -G "Visual Studio 16" -A arm64 -D WINDOWS10=ON -D USE_INTRINSICS_SSE=OFF -D FFMPEG=OFF -D BINKDEC=ON ../neo
cmake -G "Visual Studio 16" -A arm64 -DUSE_INTRINSICS_SSE=OFF -DFFMPEG=OFF -DBINKDEC=ON ../neo
pause

View file

@ -1,6 +0,0 @@
cd ..
del /s /q build
mkdir build
cd build
cmake -G "Visual Studio 16" -A x64 -DWINDOWS10=ON -DUSE_VULKAN=ON -DSPIRV_SHADERC=OFF -DFFMPEG=ON ../neo
pause

View file

@ -0,0 +1,6 @@
cd ..
del /s /q build
mkdir build
cd build
cmake -G "Visual Studio 16" -A x64 -DFFMPEG=ON -DBINKDEC=OFF ../neo
pause

View file

@ -137,8 +137,8 @@ private:
#endif
#ifdef USE_BINKDEC
BinkHandle binkHandle;
cinData_t ImageForTimeBinkDec( int milliseconds );
bool InitFromBinkDecFile( const char* qpath, bool looping );
cinData_t ImageForTimeBinkDec( int milliseconds, nvrhi::ICommandList* commandList );
bool InitFromBinkDecFile( const char* qpath, bool looping, nvrhi::ICommandList* commandList );
void BinkDecReset();
YUVbuffer yuvBuffer;
@ -336,7 +336,7 @@ idCinematic::~idCinematic()
idCinematic::InitFromFile
==============
*/
bool idCinematic::InitFromFile( const char* qpath, bool looping )
bool idCinematic::InitFromFile( const char* qpath, bool looping, nvrhi::ICommandList* commandList )
{
return false; //Carl: this is just the abstract virtual method
}
@ -375,7 +375,7 @@ void idCinematic::ResetTime( int milliseconds )
idCinematic::ImageForTime
==============
*/
cinData_t idCinematic::ImageForTime( int milliseconds )
cinData_t idCinematic::ImageForTime( int milliseconds, nvrhi::ICommandList* commandList )
{
cinData_t c;
memset( &c, 0, sizeof( c ) );
@ -856,7 +856,7 @@ void idCinematicLocal::FFMPEGReset()
#endif
#ifdef USE_BINKDEC
bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping )
bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping, nvrhi::ICommandList* commandList )
{
looping = amilooping;
startTime = 0;
@ -925,7 +925,7 @@ bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping )
status = FMV_PLAY;
hasFrame = false; // SRS - Implemented hasFrame for BinkDec behaviour consistency with FFMPEG
framePos = -1;
ImageForTime( 0 ); // SRS - Was missing initial call to ImageForTime() - fixes validation errors when using Vulkan renderer
ImageForTime( 0, commandList ); // SRS - Was missing initial call to ImageForTime() - fixes validation errors when using Vulkan renderer
status = ( looping ) ? FMV_PLAY : FMV_IDLE; // SRS - Update status based on looping flag
return true;
@ -1009,7 +1009,7 @@ bool idCinematicLocal::InitFromFile( const char* qpath, bool amilooping, nvrhi::
animationLength = 0;
fileName = temp;
//idLib::Warning( "New filename: '%s'\n", fileName.c_str() );
return InitFromBinkDecFile( fileName.c_str(), amilooping );
return InitFromBinkDecFile( fileName.c_str(), amilooping, commandList );
#else
animationLength = 0;
return false;
@ -1181,7 +1181,7 @@ cinData_t idCinematicLocal::ImageForTime( int thisTime, nvrhi::ICommandList* com
#elif defined(USE_BINKDEC) // DG: libbinkdec support
if( !isRoQ )
{
return ImageForTimeBinkDec( thisTime );
return ImageForTimeBinkDec( thisTime, commandList );
}
#endif
@ -1505,7 +1505,7 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime, nvrhi::ICommandLis
#ifdef USE_BINKDEC
cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime, nvrhi::ICommandList* commandList )
{
cinData_t cinData;
int16_t* audioBuffer = NULL;
@ -1598,7 +1598,7 @@ cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
double invAspRat = double( CIN_HEIGHT ) / double( CIN_WIDTH );
idImage* imgs[3] = {imgY, imgCb, imgCr}; // that's the order of the channels in yuvBuffer[]
idImage* imgs[ 3 ] = { imgY, imgCb, imgCr }; // that's the order of the channels in yuvBuffer[]
for( int i = 0; i < 3; ++i )
{
// Note: img->UploadScratch() seems to assume 32bit per pixel data, but this is 8bit/pixel
@ -1632,6 +1632,9 @@ cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
#endif
}
#if defined( USE_NVRHI )
img->UploadScratch( yuvBuffer[i].data, w, h, commandList );
#else
if( img->GetUploadWidth() != w || img->GetUploadHeight() != h )
{
idImageOpts opts = img->GetOpts();
@ -1639,7 +1642,8 @@ cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
opts.height = h;
img->AllocImage( opts, TF_LINEAR, TR_REPEAT );
}
img->SubImageUpload( 0, 0, 0, 0, w, h, yuvBuffer[i].data );
img->SubImageUpload( 0, 0, 0, 0, w, h, yuvBuffer[i].data, commandList );
#endif
}
hasFrame = true;

View file

@ -84,7 +84,7 @@ public:
virtual ~idCinematic();
// returns false if it failed to load
virtual bool InitFromFile( const char* qpath, bool looping );
virtual bool InitFromFile( const char* qpath, bool looping, nvrhi::ICommandList* commandList );
// returns the length of the animation in milliseconds
virtual int AnimationLength();
@ -94,7 +94,7 @@ public:
// RB end
// the pointers in cinData_t will remain valid until the next UpdateForTime() call
virtual cinData_t ImageForTime( int milliseconds );
virtual cinData_t ImageForTime( int milliseconds, nvrhi::ICommandList* commandList );
// closes the file and frees all allocated memory
virtual void Close();

View file

@ -1194,7 +1194,6 @@ void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::IComma
if( opts.textureType != TT_CUBIC || usage != TD_LOOKUP_TABLE_RGBA )
{
GenerateCubeImage( pic, cols, TF_LINEAR, TD_LOOKUP_TABLE_RGBA, commandList );
return;
}
@ -1243,12 +1242,16 @@ void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::IComma
}
else
{
if( opts.textureType != TT_2D || usage != TD_LOOKUP_TABLE_RGBA )
#if defined( USE_NVRHI )
/*
if( opts.textureType != TT_2D )//|| usage != TD_LOOKUP_TABLE_RGBA )
{
GenerateImage( data, cols, rows, TF_LINEAR, TR_REPEAT, TD_LOOKUP_TABLE_RGBA, commandList );
return;
}
*/
if( opts.width != cols || opts.height != rows )
{
opts.width = cols;
@ -1257,30 +1260,48 @@ void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::IComma
AllocImage();
}
#if defined( USE_NVRHI )
int numChannels = 4;
int bytesPerPixel = numChannels;
if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 )
if( data != NULL && commandList != NULL )
{
bytesPerPixel = 1;
int numChannels = 4;
int bytesPerPixel = numChannels;
if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 || opts.format == FMT_LUM8 )
{
bytesPerPixel = 1;
}
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
bytesPerPixel = info.bytesPerBlock;
SetSamplerState( TF_LINEAR, TR_REPEAT );
int bufferW = opts.width;
if( IsCompressed() )
{
bufferW = ( opts.width + 3 ) & ~3;
}
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
commandList->writeTexture( texture, 0, 0, data, GetRowPitch( opts.format, opts.width ) );
//commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource );
commandList->commitBarriers();
}
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
bytesPerPixel = info.bytesPerBlock;
SetSamplerState( TF_LINEAR, TR_REPEAT );
int bufferW = opts.width;
if( IsCompressed() )
{
bufferW = ( opts.width + 3 ) & ~3;
}
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
commandList->writeTexture( texture, 0, 0, data, GetRowPitch( opts.format, opts.width ) );
commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource );
commandList->commitBarriers();
#else
if( opts.textureType != TT_2D || usage != TD_LOOKUP_TABLE_RGBA )
{
GenerateImage( data, cols, rows, TF_LINEAR, TR_REPEAT, TD_LOOKUP_TABLE_RGBA, commandList );
return;
}
if( opts.width != cols || opts.height != rows )
{
opts.width = cols;
opts.height = rows;
AllocImage();
}
SetSamplerState( TF_LINEAR, TR_REPEAT );
SubImageUpload( 0, 0, 0, 0, opts.width, opts.height, data );
#endif

View file

@ -1765,7 +1765,7 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
}
}
ts->cinematic = idCinematic::Alloc();
ts->cinematic->InitFromFile( token.c_str(), loop );
ts->cinematic->InitFromFile( token.c_str(), loop, NULL );
continue;
}
@ -1777,7 +1777,7 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
continue;
}
ts->cinematic = new( TAG_MATERIAL ) idSndWindow();
ts->cinematic->InitFromFile( token.c_str(), true );
ts->cinematic->InitFromFile( token.c_str(), true, NULL );
continue;
}

View file

@ -781,6 +781,38 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
desc[1].bindings[0].resourceHandle = commonPasses.m_LinearWrapSampler;
}
}
else if( type == BINDING_LAYOUT_BINK_VIDEO )
{
if( desc[0].bindings.empty() )
{
desc[0].bindings =
{
nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.ConstantBuffer() ),
nvrhi::BindingSetItem::Texture_SRV( 0, ( nvrhi::ITexture* )GetImageAt( 0 )->GetTextureID() ),
nvrhi::BindingSetItem::Texture_SRV( 1, ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID() ),
nvrhi::BindingSetItem::Texture_SRV( 2, ( nvrhi::ITexture* )GetImageAt( 2 )->GetTextureID() )
};
}
else
{
desc[0].bindings[0].resourceHandle = renderProgManager.ConstantBuffer();
desc[0].bindings[1].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 0 )->GetTextureID();
desc[0].bindings[2].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID();
desc[0].bindings[3].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 2 )->GetTextureID();
}
if( desc[1].bindings.empty() )
{
desc[1].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearWrapSampler )
};
}
else
{
desc[1].bindings[0].resourceHandle = commonPasses.m_LinearWrapSampler;
}
}
else if( type == BINDING_LAYOUT_TAA_MOTION_VECTORS )
{
if( desc[0].bindings.empty() )

View file

@ -2256,7 +2256,7 @@ void idRenderBackend::DBG_TestImage()
// SRS - Don't need calibrated time for testing cinematics, so just call ImageForTime( 0 ) for current system time
// This simplification allows cinematic test playback to work over both 2D and 3D background scenes
cin = tr.testVideo->ImageForTime( 0 /*viewDef->renderView.time[1] - tr.testVideoStartTime*/ );
cin = tr.testVideo->ImageForTime( 0 /*viewDef->renderView.time[1] - tr.testVideoStartTime*/, commandList );
if( cin.imageY != NULL )
{
image = cin.imageY;

View file

@ -284,7 +284,7 @@ void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, con
// offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?)
// We make no attempt to optimize for multiple identical cinematics being in view, or
// for cinematics going at a lower framerate than the renderer.
cin = texture->cinematic->ImageForTime( viewDef->renderView.time[0] + idMath::Ftoi( 1000.0f * viewDef->renderView.shaderParms[11] ) );
cin = texture->cinematic->ImageForTime( viewDef->renderView.time[0] + idMath::Ftoi( 1000.0f * viewDef->renderView.shaderParms[11] ), commandList );
if( cin.imageY != NULL )
{
GL_SelectTexture( 0 );

View file

@ -866,6 +866,7 @@ enum bindingLayoutType_t
BINDING_LAYOUT_POST_PROCESS_FINAL,
BINDING_LAYOUT_NORMAL_CUBE,
BINDING_LAYOUT_BLENDLIGHT,
BINDING_LAYOUT_BINK_VIDEO,
// NVRHI render passes specific
BINDING_LAYOUT_TAA_MOTION_VECTORS,

View file

@ -316,6 +316,15 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
bindingLayouts[BINDING_LAYOUT_NORMAL_CUBE] = { device->createBindingLayout( normalCubeBindingLayout ), samplerOneBindingLayout };
auto binkVideoBindingLayout = nvrhi::BindingLayoutDesc()
.setVisibility( nvrhi::ShaderType::All )
.addItem( nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ) )
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 0 ) ) // cube map
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 1 ) ) // cube map
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 2 ) ); // normal map
bindingLayouts[BINDING_LAYOUT_BINK_VIDEO] = { device->createBindingLayout( binkVideoBindingLayout ), samplerOneBindingLayout };
auto motionVectorsBindingLayout = nvrhi::BindingLayoutDesc()
.setVisibility( nvrhi::ShaderType::All )
.addItem( nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ) )
@ -505,9 +514,9 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
// RB end
{ BUILTIN_STEREO_DEGHOST, "builtin/VR/stereoDeGhost", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_STEREO_WARP, "builtin/VR/stereoWarp", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_BINK, "builtin/video/bink", "", { {"USE_SRGB", "0" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_BINK_SRGB, "builtin/video/bink", "_srgb", { {"USE_SRGB", "1" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_BINK_GUI, "builtin/video/bink_gui", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_BINK, "builtin/video/bink", "", { {"USE_SRGB", "0" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_BINK_VIDEO },
{ BUILTIN_BINK_SRGB, "builtin/video/bink", "_srgb", { {"USE_SRGB", "1" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_BINK_VIDEO },
{ BUILTIN_BINK_GUI, "builtin/video/bink_gui", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_BINK_VIDEO },
{ BUILTIN_STEREO_INTERLACE, "builtin/VR/stereoInterlace", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_MOTION_BLUR, "builtin/post/motionBlur", "", { { "VECTORS_ONLY", "1" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },

View file

@ -700,10 +700,12 @@ void R_TestVideo_f( const idCmdArgs& args )
tr.testImage = globalImages->ImageFromFile( "_scratch", TF_DEFAULT, TR_REPEAT, TD_DEFAULT );
tr.testVideo = idCinematic::Alloc();
tr.testVideo->InitFromFile( args.Argv( 1 ), true );
tr.testVideo->InitFromFile( args.Argv( 1 ), true, NULL );
cinData_t cin;
cin = tr.testVideo->ImageForTime( 0 );
// FIXME commandList
cin = tr.testVideo->ImageForTime( 0, NULL );
// SRS - Also handle ffmpeg and original RoQ decoders for test videos (using cin.image)
if( cin.imageY == NULL && cin.image == NULL )
{

View file

@ -38,7 +38,7 @@ SamplerState LinearSampler : register( s0 );
struct PS_IN {
float4 position : VPOS;
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};

View file

@ -39,8 +39,8 @@ struct VS_IN {
};
struct VS_OUT {
float4 position : POSITION;
float2 texcoord0 : TEXCOORD0;
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*

View file

@ -37,7 +37,7 @@ Texture2D t_Cb : register( t2 );
SamplerState LinearSampler : register( s0 );
struct PS_IN {
float4 position : VPOS;
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
float4 texcoord1 : TEXCOORD1_centroid;
float4 color : COLOR0;

View file

@ -41,9 +41,9 @@ struct VS_IN {
};
struct VS_OUT {
float4 position : POSITION;
float2 texcoord0 : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
float4 texcoord1 : TEXCOORD1_centroid;
float4 color : COLOR0;
};
// *INDENT-ON*