From 5aedf1451020bc6a58c35e7c9bce178b5337713e Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Fri, 28 Jun 2024 17:43:26 +0200 Subject: [PATCH 1/7] A small loading screen progressbar experiment --- neo/framework/Common.h | 9 ++-- neo/framework/Common_load.cpp | 84 +++++++++++++++++++++++++++++++++- neo/framework/Common_local.h | 19 ++++++-- neo/framework/common_frame.cpp | 26 ++++++++++- neo/renderer/ImageManager.cpp | 48 ++++++++++++++++++- neo/renderer/RenderBackend.cpp | 3 ++ neo/tools/compilers/main.cpp | 11 ++++- 7 files changed, 188 insertions(+), 12 deletions(-) diff --git a/neo/framework/Common.h b/neo/framework/Common.h index 9f6cf8c9..05fc690d 100644 --- a/neo/framework/Common.h +++ b/neo/framework/Common.h @@ -229,9 +229,12 @@ public: // DG end virtual void UpdateLevelLoadPacifier() = 0; - //virtual void UpdateLevelLoadPacifier( int mProgress ) = 0; - //virtual void UpdateLevelLoadPacifier( bool updateSecondary ) = 0; - //virtual void UpdateLevelLoadPacifier( bool updateSecondary, int Progress ) = 0; + // RB begin + virtual void LoadPacifierInfo( VERIFY_FORMAT_STRING const char* fmt, ... ) = 0; + virtual void LoadPacifierProgressTotal( int total ) = 0; + virtual void LoadPacifierProgressIncrement( int step ) = 0; + virtual bool LoadPacifierRunning() = 0; + // RB end // Checks for and removes command line "+set var arg" constructs. // If match is NULL, all set commands will be executed, otherwise diff --git a/neo/framework/Common_load.cpp b/neo/framework/Common_load.cpp index 873a99e5..3d3a7b84 100644 --- a/neo/framework/Common_load.cpp +++ b/neo/framework/Common_load.cpp @@ -772,7 +772,9 @@ void idCommonLocal::UpdateLevelLoadPacifier() } txtVal->SetStrokeInfo( true, 1.75f, 0.75f ); } + UpdateScreen( false ); + if( autoswapsRunning ) { renderSystem->BeginAutomaticBackgroundSwaps( icon ); @@ -780,6 +782,83 @@ void idCommonLocal::UpdateLevelLoadPacifier() } } +// RB begin +void idCommonLocal::LoadPacifierInfo( VERIFY_FORMAT_STRING const char* fmt, ... ) +{ + char msg[256]; + + va_list argptr; + va_start( argptr, fmt ); + idStr::vsnPrintf( msg, 256 - 1, fmt, argptr ); + msg[ sizeof( msg ) - 1 ] = '\0'; + va_end( argptr ); + + loadPacifierStatus = msg; + + //if( com_refreshOnPrint ) + //{ + // UpdateScreen( false ); + //} +} + +void idCommonLocal::LoadPacifierProgressTotal( int total ) +{ + loadPacifierCount = 0; + loadPacifierExpectedCount = total; + loadPacifierTics = 0; + loadPacifierNextTicCount = 0; +} + +void idCommonLocal::LoadPacifierProgressIncrement( int step ) +{ + loadPacifierCount += step; + + // don't refresh the UI with every step if there are e.g. 1300 steps + if( ( ( loadPacifierCount + 1 ) >= loadPacifierNextTicCount ) && loadPacifierExpectedCount > 0 ) + { + size_t ticsNeeded = ( size_t )( ( ( double )( loadPacifierCount + 1 ) / loadPacifierExpectedCount ) * 50.0 ); + + //do + //{ + //common->Printf( "*" ); + //} + //while( ++loadPacifierTics < ticsNeeded ); + loadPacifierTics = ticsNeeded; + + loadPacifierNextTicCount = ( size_t )( ( loadPacifierTics / 50.0 ) * loadPacifierExpectedCount ); + if( loadPacifierCount == ( loadPacifierExpectedCount - 1 ) ) + { + // reset + + //if( tics < 51 ) + //{ + // common->Printf( "*" ); + //} + //common->Printf( "\n" ); + + //stateUI.progress = 1; + + //loadPacifierCount = 0; + //loadPacifierExpectedCount = 0; + //loadPacifierTics = 0; + //loadPacifierNextTicCount = 0; + } + + UpdateLevelLoadPacifier(); + } + + if( loadPacifierCount >= loadPacifierExpectedCount ) + { + loadPacifierExpectedCount = 0; + } +} + +bool idCommonLocal::LoadPacifierRunning() +{ + return loadPacifierExpectedCount > 0; +} +// RB end + // foresthale 2014-05-30: loading progress pacifier for binarize operations only void idCommonLocal::LoadPacifierBinarizeFilename( const char* filename, const char* reason ) { @@ -817,8 +896,11 @@ void idCommonLocal::LoadPacifierBinarizeProgress( float progress ) // binarized for one filename, we don't give bogus estimates... loadPacifierBinarizeStartTime = Sys_Milliseconds(); } + loadPacifierBinarizeProgress = progress; - if( ( time - lastUpdateTime ) >= 16 ) + + // RB: update every 2 milliseconds have passed + if( ( time - lastUpdateTime ) >= 2 ) { lastUpdateTime = time; loadPacifierBinarizeActive = true; diff --git a/neo/framework/Common_local.h b/neo/framework/Common_local.h index 81dda291..fd04dcd9 100644 --- a/neo/framework/Common_local.h +++ b/neo/framework/Common_local.h @@ -157,9 +157,6 @@ public: virtual void UpdateScreen( bool captureToImage, bool releaseMouse = true ); // DG end virtual void UpdateLevelLoadPacifier(); // Indefinate -// virtual void UpdateLevelLoadPacifier( int mProgress ); -// virtual void UpdateLevelLoadPacifier( bool Secondary ); -// virtual void UpdateLevelLoadPacifier( bool updateSecondary, int mProgress ); virtual void StartupVariable( const char* match ); virtual void InitTool( const toolFlag_t tool, const idDict* dict, idEntity* entity ); virtual void WriteConfigToFile( const char* filename ); @@ -440,6 +437,13 @@ public: } // SRS end + // RB begin + virtual void LoadPacifierInfo( VERIFY_FORMAT_STRING const char* fmt, ... ); + virtual void LoadPacifierProgressTotal( int total ); + virtual void LoadPacifierProgressIncrement( int step ); + virtual bool LoadPacifierRunning(); + // RB end + // foresthale 2014-05-30: a special binarize pacifier has to be shown in // some cases, which includes filename and ETA information, note that // the progress function takes 0-1 float, not 0-100, and can be called @@ -655,6 +659,14 @@ private: int lastPacifierGuiTime; bool lastPacifierDialogState; + // RB begin + idStrStatic<256> loadPacifierStatus = "-"; + int loadPacifierCount = 0; + int loadPacifierExpectedCount = 0; + size_t loadPacifierTics = 0; + size_t loadPacifierNextTicCount = 0; + // RB end + // foresthale 2014-05-30: a special binarize pacifier has to be shown in some cases, which includes filename and ETA information bool loadPacifierBinarizeActive; int loadPacifierBinarizeStartTime; @@ -738,6 +750,7 @@ private: // called by Draw when the scene to scene wipe is still running void DrawWipeModel(); + void DrawLoadPacifierProgressbar(); // RB void StartWipe( const char* materialName, bool hold = false ); void CompleteWipe(); void ClearWipe(); diff --git a/neo/framework/common_frame.cpp b/neo/framework/common_frame.cpp index d8002881..418c6aea 100644 --- a/neo/framework/common_frame.cpp +++ b/neo/framework/common_frame.cpp @@ -234,6 +234,27 @@ void idCommonLocal::DrawWipeModel() renderSystem->DrawStretchPic( 0, 0, renderSystem->GetVirtualWidth(), renderSystem->GetVirtualHeight(), 0, 0, 1, 1, wipeMaterial ); } +// RB begin +void idCommonLocal::DrawLoadPacifierProgressbar() +{ + if( loadPacifierExpectedCount <= 0 ) + { + return; + } + + float loadPacifierProgress = float( loadPacifierCount ) / loadPacifierExpectedCount; + + // draw our basic overlay + renderSystem->SetColor( idVec4( 0.55f, 0.0f, 0.0f, 1.0f ) ); + renderSystem->DrawStretchPic( 0, renderSystem->GetVirtualHeight() - 64, renderSystem->GetVirtualWidth(), 16, 0, 0, 1, 1, whiteMaterial ); + //renderSystem->SetColor( idVec4( 0.0f, 0.5f, 0.8f, 1.0f ) ); + renderSystem->SetColor( colorGold ); + renderSystem->DrawStretchPic( 0, renderSystem->GetVirtualHeight() - 64, loadPacifierProgress * renderSystem->GetVirtualWidth(), 16, 0, 0, 1, 1, whiteMaterial ); + + renderSystem->DrawSmallStringExt( 0, renderSystem->GetVirtualHeight() - 64, loadPacifierStatus, idVec4( 1.0f, 1.0f, 1.0f, 1.0f ), true ); +} +// RB end + /* =============== idCommonLocal::Draw @@ -247,7 +268,7 @@ void idCommonLocal::Draw() Sys_Sleep( com_sleepDraw.GetInteger() ); } - if( loadPacifierBinarizeActive ) + if( loadPacifierBinarizeActive || LoadPacifierRunning() ) { // foresthale 2014-05-30: when binarizing an asset we show a special // overlay indicating progress @@ -261,6 +282,9 @@ void idCommonLocal::Draw() loadGUI->Render( renderSystem, Sys_Milliseconds() ); } + // draw general progress bar + DrawLoadPacifierProgressbar(); + // update our progress estimates int time = Sys_Milliseconds(); if( loadPacifierBinarizeProgress > 0.0f ) diff --git a/neo/renderer/ImageManager.cpp b/neo/renderer/ImageManager.cpp index 36ba68b7..961a17ff 100644 --- a/neo/renderer/ImageManager.cpp +++ b/neo/renderer/ImageManager.cpp @@ -333,7 +333,6 @@ idImage* idImageManager::AllocStandaloneImage( const char* name ) AllocDeferredImage Allocates an idDeferredImage to load images from memory, adds it to the hash chain - ============== */ idDeferredImage* idImageManager::AllocDeferredImage( const char* name ) @@ -861,6 +860,21 @@ void idImageManager::Preload( const idPreloadManifest& manifest, const bool& map int numLoaded = 0; //fileSystem->StartPreload( preloadImageFiles ); + + // count + int numPreload = 0; + for( int i = 0; i < manifest.NumResources(); i++ ) + { + const preloadEntry_s& p = manifest.GetPreloadByIndex( i ); + if( p.resType == PRELOAD_IMAGE && !ExcludePreloadImage( p.resourceName ) ) + { + numPreload++; + } + } + + common->LoadPacifierInfo( "Preloading images" ); + common->LoadPacifierProgressTotal( numPreload ); + for( int i = 0; i < manifest.NumResources(); i++ ) { const preloadEntry_s& p = manifest.GetPreloadByIndex( i ); @@ -868,6 +882,8 @@ void idImageManager::Preload( const idPreloadManifest& manifest, const bool& map { globalImages->ImageFromFile( p.resourceName, ( textureFilter_t )p.imgData.filter, ( textureRepeat_t )p.imgData.repeat, ( textureUsage_t )p.imgData.usage, ( cubeFiles_t )p.imgData.cubeMap ); numLoaded++; + + common->LoadPacifierProgressIncrement( 1 ); } } //fileSystem->StopPreload(); @@ -899,15 +915,26 @@ int idImageManager::LoadLevelImages( bool pacifier ) commandList = deviceManager->GetDevice()->createCommandList( params ); } - common->UpdateLevelLoadPacifier(); + //common->UpdateLevelLoadPacifier(); commandList->open(); + if( pacifier ) + { + common->LoadPacifierInfo( "Loading level images" ); + common->LoadPacifierProgressTotal( images.Num() ); + } + int loadCount = 0; for( int i = 0 ; i < images.Num() ; i++ ) { idImage* image = images[ i ]; + if( pacifier ) + { + common->LoadPacifierProgressIncrement( 1 ); + } + if( image->generatorFunction ) { continue; @@ -1012,6 +1039,11 @@ void idImageManager::PrintMemInfo( MemInfo_t* mi ) void idImageManager::LoadDeferredImages( nvrhi::ICommandList* _commandList ) { + if( insideLevelLoad ) + { + return; + } + #if !defined( DMAP ) if( !commandList ) { @@ -1033,10 +1065,22 @@ void idImageManager::LoadDeferredImages( nvrhi::ICommandList* _commandList ) thisCmdList->open(); } + bool preloadPacifier = common->LoadPacifierRunning(); + if( !preloadPacifier ) + { + common->LoadPacifierInfo( "Loading deferred images" ); + common->LoadPacifierProgressTotal( imagesToLoad.Num() ); + } + for( int i = 0; i < globalImages->imagesToLoad.Num(); i++ ) { // This is a "deferred" load of textures to the gpu. globalImages->imagesToLoad[i]->FinalizeImage( false, thisCmdList ); + + if( !preloadPacifier ) + { + common->LoadPacifierProgressIncrement( 1 ); + } } #else for( int i = 0; i < globalImages->imagesToLoad.Num(); i++ ) diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 3ac00ca5..0fa4eb7b 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -5320,6 +5320,9 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds ) GL_StartFrame(); void* textureId = globalImages->hierarchicalZbufferImage->GetTextureID(); + + // RB: we need to load all images left before rendering + // this can be expensive here because of the runtime image compression globalImages->LoadDeferredImages( commandList ); if( !ssaoPass && r_useNewSsaoPass.GetBool() ) diff --git a/neo/tools/compilers/main.cpp b/neo/tools/compilers/main.cpp index 253cc6c0..31966d94 100644 --- a/neo/tools/compilers/main.cpp +++ b/neo/tools/compilers/main.cpp @@ -670,7 +670,7 @@ public: // Initialize everything. // if the OS allows, pass argc/argv directly (without executable name) // otherwise pass the command line in a single string (without executable name) - virtual void Init( int argc, const char* const* argv, const char* cmdline ) { }; + virtual void Init( int argc, const char* const* argv, const char* cmdline ) {} // Shuts down everything. virtual void Shutdown() {} @@ -698,6 +698,13 @@ public: virtual void UpdateScreen( bool captureToImage, bool releaseMouse = true ); virtual void UpdateLevelLoadPacifier() {} + virtual void LoadPacifierInfo( VERIFY_FORMAT_STRING const char* fmt, ... ) {} + virtual void LoadPacifierProgressTotal( int total ) {} + virtual void LoadPacifierProgressIncrement( int step ) {} + virtual bool LoadPacifierRunning() + { + return false; + } // Checks for and removes command line "+set var arg" constructs. @@ -706,7 +713,7 @@ public: virtual void StartupVariable( const char* match ) {} // Begins redirection of console output to the given buffer. - virtual void BeginRedirect( char* buffer, int buffersize, void ( *flush )( const char* ) ) { }; + virtual void BeginRedirect( char* buffer, int buffersize, void ( *flush )( const char* ) ) {} // Stops redirection of console output. virtual void EndRedirect() {} From 134f3ec799f1ab8630ad3a2626a1e771c8565621 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Fri, 28 Jun 2024 22:26:56 +0200 Subject: [PATCH 2/7] Probably fixed VRAM memory leak when reloading maps. #904 --- neo/renderer/Image_load.cpp | 6 ++++++ neo/renderer/RenderBackend.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/neo/renderer/Image_load.cpp b/neo/renderer/Image_load.cpp index 6dbf48de..3296aff9 100644 --- a/neo/renderer/Image_load.cpp +++ b/neo/renderer/Image_load.cpp @@ -339,6 +339,12 @@ On exit, the idImage will have a valid OpenGL texture number that can be bound */ void idImage::FinalizeImage( bool fromBackEnd, nvrhi::ICommandList* commandList ) { + // RB: might have been called doubled by nested LoadDeferredImages + if( isLoaded ) + { + return; + } + // if we don't have a rendering context yet, just return //if( !tr.IsInitialized() ) //{ diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 0fa4eb7b..a18d3032 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -5323,7 +5323,7 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds ) // RB: we need to load all images left before rendering // this can be expensive here because of the runtime image compression - globalImages->LoadDeferredImages( commandList ); + //globalImages->LoadDeferredImages( commandList ); if( !ssaoPass && r_useNewSsaoPass.GetBool() ) { From 7a94a9c4663041e34dd987b188a911602ec85693 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Fri, 28 Jun 2024 22:34:46 +0200 Subject: [PATCH 3/7] Removed never called idDeferredImage code --- neo/renderer/Image.h | 40 ----------------------------------- neo/renderer/ImageManager.cpp | 20 ------------------ neo/renderer/Image_files.cpp | 20 ------------------ 3 files changed, 80 deletions(-) diff --git a/neo/renderer/Image.h b/neo/renderer/Image.h index 67159682..6cee7f3f 100644 --- a/neo/renderer/Image.h +++ b/neo/renderer/Image.h @@ -251,40 +251,6 @@ typedef enum CF_SINGLE, // SP: A single texture cubemap. All six sides in one image. } cubeFiles_t; -class idDeferredImage -{ -public: - idDeferredImage( const char* imageName ); - ~idDeferredImage(); - - idStr name; - byte* pic; - int width; - int height; - textureFilter_t textureFilter; - textureRepeat_t textureRepeat; - textureUsage_t textureUsage; -}; - -ID_INLINE idDeferredImage::idDeferredImage( const char* imageName ) - : name( imageName ) - , pic( nullptr ) - , width( 0 ) - , height( 0 ) - , textureFilter( TF_DEFAULT ) - , textureRepeat( TR_CLAMP ) - , textureUsage( TD_DEFAULT ) -{ -} - -ID_INLINE idDeferredImage::~idDeferredImage() -{ - if( pic ) - { - delete pic; - } -} - typedef void ( *ImageGeneratorFunction )( idImage* image, nvrhi::ICommandList* commandList ); #include "BinaryImage.h" @@ -666,8 +632,6 @@ public: idImage* AllocImage( const char* name ); idImage* AllocStandaloneImage( const char* name ); - idDeferredImage* AllocDeferredImage( const char* name ); - bool ExcludePreloadImage( const char* name ); idList images; @@ -676,10 +640,6 @@ public: // Transient list of images to load on the main thread to the gpu. Freed after images are loaded. idList imagesToLoad; - // Permanent images to load from memory instead of a file system. - idList deferredImages; - idHashIndex deferredImageHash; - bool insideLevelLoad; // don't actually load images now bool preloadingMapImages; // unless this is set diff --git a/neo/renderer/ImageManager.cpp b/neo/renderer/ImageManager.cpp index 961a17ff..6ba776a0 100644 --- a/neo/renderer/ImageManager.cpp +++ b/neo/renderer/ImageManager.cpp @@ -328,23 +328,6 @@ idImage* idImageManager::AllocStandaloneImage( const char* name ) return image; } -/* -============== -AllocDeferredImage - -Allocates an idDeferredImage to load images from memory, adds it to the hash chain -============== -*/ -idDeferredImage* idImageManager::AllocDeferredImage( const char* name ) -{ - idDeferredImage* image = new( TAG_IMAGE ) idDeferredImage( name ); - - int hash = idStr( name ).FileNameHash(); - deferredImageHash.Add( hash, deferredImages.Append( image ) ); - - return image; -} - /* ================== ImageFromFunction @@ -356,7 +339,6 @@ system to be completely regenerated if needed. */ idImage* idImageManager::ImageFromFunction( const char* _name, ImageGeneratorFunction generatorFunction ) { - // strip any .tga file extensions from anywhere in the _name idStr name = _name; name.Replace( ".tga", "" ); @@ -780,8 +762,6 @@ void idImageManager::Shutdown() { images.DeleteContents( true ); imageHash.Clear(); - deferredImages.DeleteContents( true ); - deferredImageHash.Clear(); commandList.Reset(); } diff --git a/neo/renderer/Image_files.cpp b/neo/renderer/Image_files.cpp index f9350bf9..2fc06228 100644 --- a/neo/renderer/Image_files.cpp +++ b/neo/renderer/Image_files.cpp @@ -1115,26 +1115,6 @@ retry: } } } - else - { - // Try loading from a deferred image hash list - int hash = name.FileNameHash(); - for( int i = globalImages->deferredImageHash.First( hash ); i != -1; i = globalImages->deferredImageHash.Next( i ) ) - { - idDeferredImage* image = globalImages->deferredImages[i]; - if( name.Icmp( image->name ) == 0 ) - { - if( pic && *pic == nullptr ) - { - *usage = image->textureUsage; - *width = image->width; - *height = image->height; - memcpy( *pic, image->pic, 4 * *width * *height ); - break; - } - } - } - } // RB end if( ( width && *width < 1 ) || ( height && *height < 1 ) ) From 1759ecb1ed0c68ac2b40ca0e9ab943d39c2413b7 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Fri, 28 Jun 2024 23:40:14 +0200 Subject: [PATCH 4/7] Show binarization indicator for 2D packed mipchain EXR files --- neo/framework/common_frame.cpp | 66 ++++++++++++++++++---------------- neo/renderer/BinaryImage.cpp | 2 ++ neo/renderer/ImageManager.cpp | 22 +++++++++--- neo/renderer/Image_load.cpp | 37 +++++++------------ 4 files changed, 68 insertions(+), 59 deletions(-) diff --git a/neo/framework/common_frame.cpp b/neo/framework/common_frame.cpp index 418c6aea..9ac7833e 100644 --- a/neo/framework/common_frame.cpp +++ b/neo/framework/common_frame.cpp @@ -285,40 +285,44 @@ void idCommonLocal::Draw() // draw general progress bar DrawLoadPacifierProgressbar(); - // update our progress estimates - int time = Sys_Milliseconds(); - if( loadPacifierBinarizeProgress > 0.0f ) + if( loadPacifierBinarizeActive ) { - loadPacifierBinarizeTimeLeft = ( 1.0 - loadPacifierBinarizeProgress ) * ( time - loadPacifierBinarizeStartTime ) * 0.001f / loadPacifierBinarizeProgress; - } - else - { - loadPacifierBinarizeTimeLeft = -1.0f; - } + // update our progress estimates + int time = Sys_Milliseconds(); + if( loadPacifierBinarizeProgress > 0.0f ) + { + loadPacifierBinarizeTimeLeft = ( 1.0 - loadPacifierBinarizeProgress ) * ( time - loadPacifierBinarizeStartTime ) * 0.001f / loadPacifierBinarizeProgress; + } + else + { + loadPacifierBinarizeTimeLeft = -1.0f; + } - // prepare our strings - const char* text; - if( loadPacifierBinarizeTimeLeft >= 99.5f ) - { - text = va( "Binarizing %3.0f%% ETA %2.0f minutes", loadPacifierBinarizeProgress * 100.0f, loadPacifierBinarizeTimeLeft / 60.0f ); - } - else if( loadPacifierBinarizeTimeLeft ) - { - text = va( "Binarizing %3.0f%% ETA %2.0f seconds", loadPacifierBinarizeProgress * 100.0f, loadPacifierBinarizeTimeLeft ); - } - else - { - text = va( "Binarizing %3.0f%%", loadPacifierBinarizeProgress * 100.0f ); - } + // prepare our strings + const char* text; + if( loadPacifierBinarizeTimeLeft >= 99.5f ) + { + text = va( "Binarizing %3.0f%% ETA %2.0f minutes", loadPacifierBinarizeProgress * 100.0f, loadPacifierBinarizeTimeLeft / 60.0f ); + } + else if( loadPacifierBinarizeTimeLeft ) + { + text = va( "Binarizing %3.0f%% ETA %2.0f seconds", loadPacifierBinarizeProgress * 100.0f, loadPacifierBinarizeTimeLeft ); + } + else + { + text = va( "Binarizing %3.0f%%", loadPacifierBinarizeProgress * 100.0f ); + } - // draw our basic overlay - renderSystem->SetColor( idVec4( 0.0f, 0.0f, 0.5f, 1.0f ) ); - renderSystem->DrawStretchPic( 0, renderSystem->GetVirtualHeight() - 48, renderSystem->GetVirtualWidth(), 48, 0, 0, 1, 1, whiteMaterial ); - renderSystem->SetColor( idVec4( 0.0f, 0.5f, 0.8f, 1.0f ) ); - renderSystem->DrawStretchPic( 0, renderSystem->GetVirtualHeight() - 48, loadPacifierBinarizeProgress * renderSystem->GetVirtualWidth(), 32, 0, 0, 1, 1, whiteMaterial ); - renderSystem->DrawSmallStringExt( 0, renderSystem->GetVirtualHeight() - 48, loadPacifierBinarizeFilename.c_str(), idVec4( 1.0f, 1.0f, 1.0f, 1.0f ), true ); - renderSystem->DrawSmallStringExt( 0, renderSystem->GetVirtualHeight() - 32, va( "%s %d/%d lvls", loadPacifierBinarizeInfo.c_str(), loadPacifierBinarizeMiplevel, loadPacifierBinarizeMiplevelTotal ), idVec4( 1.0f, 1.0f, 1.0f, 1.0f ), true ); - renderSystem->DrawSmallStringExt( 0, renderSystem->GetVirtualHeight() - 16, text, idVec4( 1.0f, 1.0f, 1.0f, 1.0f ), true ); + // draw our basic overlay + renderSystem->SetColor( idVec4( 0.0f, 0.0f, 0.0f, 0.75f ) ); + renderSystem->DrawStretchPic( 0, renderSystem->GetVirtualHeight() - 48, renderSystem->GetVirtualWidth(), 48, 0, 0, 1, 1, whiteMaterial ); + //renderSystem->SetColor( idVec4( 0.0f, 0.5f, 0.8f, 1.0f ) ); + renderSystem->SetColor( colorBrown ); + renderSystem->DrawStretchPic( 0, renderSystem->GetVirtualHeight() - 48, loadPacifierBinarizeProgress * renderSystem->GetVirtualWidth(), 16, 0, 0, 1, 1, whiteMaterial ); + renderSystem->DrawSmallStringExt( 0, renderSystem->GetVirtualHeight() - 48, loadPacifierBinarizeFilename.c_str(), idVec4( 1.0f, 1.0f, 1.0f, 1.0f ), true ); + renderSystem->DrawSmallStringExt( 0, renderSystem->GetVirtualHeight() - 32, va( "%s %d/%d lvls", loadPacifierBinarizeInfo.c_str(), loadPacifierBinarizeMiplevel, loadPacifierBinarizeMiplevelTotal ), idVec4( 1.0f, 1.0f, 1.0f, 1.0f ), true ); + renderSystem->DrawSmallStringExt( 0, renderSystem->GetVirtualHeight() - 16, text, idVec4( 1.0f, 1.0f, 1.0f, 1.0f ), true ); + } } else if( loadGUI != NULL ) { diff --git a/neo/renderer/BinaryImage.cpp b/neo/renderer/BinaryImage.cpp index 161a93ef..7cdae985 100644 --- a/neo/renderer/BinaryImage.cpp +++ b/neo/renderer/BinaryImage.cpp @@ -413,6 +413,8 @@ void idBinaryImage::Load2DAtlasMipchainFromMemory( int width, int height, const #endif } } + + common->LoadPacifierBinarizeProgressIncrement( rect.x * rect.y ); // RB end common->LoadPacifierBinarizeMiplevel( level + 1, numLevels ); diff --git a/neo/renderer/ImageManager.cpp b/neo/renderer/ImageManager.cpp index 6ba776a0..2aef086b 100644 --- a/neo/renderer/ImageManager.cpp +++ b/neo/renderer/ImageManager.cpp @@ -149,6 +149,7 @@ void R_ListImages_f( const idCmdArgs& args ) bool duplicated = false; bool overSized = false; bool sortByName = false; + bool deferred = false; if( args.Argc() == 1 ) { @@ -181,6 +182,10 @@ void R_ListImages_f( const idCmdArgs& args ) sorted = true; overSized = true; } + else if( idStr::Icmp( args.Argv( 1 ), "deferred" ) == 0 ) + { + deferred = true; + } else { failed = true; @@ -202,14 +207,23 @@ void R_ListImages_f( const idCmdArgs& args ) totalSize = 0; - idList< idImage* >& images = globalImages->images; - const int numImages = images.Num(); + const idList< idImage*, TAG_IDLIB_LIST_IMAGE >* images; + if( deferred ) + { + images = &globalImages->imagesToLoad; + } + else + { + images = &globalImages->images; + } + + const int numImages = images->Num(); sortedImage_t* sortedArray = ( sortedImage_t* )alloca( sizeof( sortedImage_t ) * numImages ); for( i = 0 ; i < numImages; i++ ) { - image = images[ i ]; + image = ( *images )[ i ]; if( uncompressedOnly ) { @@ -229,7 +243,7 @@ void R_ListImages_f( const idCmdArgs& args ) int j; for( j = i + 1 ; j < numImages ; j++ ) { - if( idStr::Icmp( image->GetName(), images[ j ]->GetName() ) == 0 ) + if( idStr::Icmp( image->GetName(), ( *images )[ j ]->GetName() ) == 0 ) { break; } diff --git a/neo/renderer/Image_load.cpp b/neo/renderer/Image_load.cpp index 3296aff9..20ac4ddd 100644 --- a/neo/renderer/Image_load.cpp +++ b/neo/renderer/Image_load.cpp @@ -635,37 +635,26 @@ void idImage::FinalizeImage( bool fromBackEnd, nvrhi::ICommandList* commandList DeriveOpts(); - // foresthale 2014-05-30: give a nice progress display when binarizing - commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() ); - if( opts.numLevels > 1 ) - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 * 4 / 3 ); - } - else - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 ); - } - - commonLocal.LoadPacifierBinarizeEnd(); - - // foresthale 2014-05-30: give a nice progress display when binarizing - commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() ); - if( opts.numLevels > 1 ) - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 * 4 / 3 ); - } - else - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 ); - } - // RB: convert to compressed DXT or whatever choosen target format if( cubeFiles == CF_2D_PACKED_MIPCHAIN ) { + commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() ); + commonLocal.LoadPacifierBinarizeProgressTotal( width * opts.height ); + im.Load2DAtlasMipchainFromMemory( width, opts.height, pic, opts.numLevels, opts.format, opts.colorFormat ); } else { + commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() ); + if( opts.numLevels > 1 ) + { + commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height * 4 / 3 ); + } + else + { + commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height ); + } + im.Load2DFromMemory( opts.width, opts.height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips ); } commonLocal.LoadPacifierBinarizeEnd(); From c3ecc7b8088e3dcc6263b3a1a1a0a0684b6e6ed6 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Sat, 29 Jun 2024 10:37:24 +0200 Subject: [PATCH 5/7] Refactored FinalizeImage back to ActuallyLoadImage --- neo/framework/Common_load.cpp | 9 +- neo/framework/Common_local.h | 16 +- neo/renderer/Image.h | 2 +- neo/renderer/ImageManager.cpp | 57 +- neo/renderer/Image_load.cpp | 681 ++++++++++----------- neo/renderer/NVRHI/RenderBackend_NVRHI.cpp | 2 +- neo/renderer/RenderPass.cpp | 2 +- 7 files changed, 376 insertions(+), 393 deletions(-) diff --git a/neo/framework/Common_load.cpp b/neo/framework/Common_load.cpp index 3d3a7b84..fc13666a 100644 --- a/neo/framework/Common_load.cpp +++ b/neo/framework/Common_load.cpp @@ -906,9 +906,6 @@ void idCommonLocal::LoadPacifierBinarizeProgress( float progress ) loadPacifierBinarizeActive = true; UpdateLevelLoadPacifier(); - - // TODO merge - //UpdateLevelLoadPacifier( true, progress ); } } @@ -937,7 +934,11 @@ void idCommonLocal::LoadPacifierBinarizeProgressTotal( int total ) void idCommonLocal::LoadPacifierBinarizeProgressIncrement( int step ) { loadPacifierBinarizeProgressCurrent += step; - LoadPacifierBinarizeProgress( ( float )loadPacifierBinarizeProgressCurrent / loadPacifierBinarizeProgressTotal ); + + if( loadPacifierBinarizeProgressTotal > 0 ) + { + LoadPacifierBinarizeProgress( ( float )loadPacifierBinarizeProgressCurrent / loadPacifierBinarizeProgressTotal ); + } } /* diff --git a/neo/framework/Common_local.h b/neo/framework/Common_local.h index fd04dcd9..7107b4c7 100644 --- a/neo/framework/Common_local.h +++ b/neo/framework/Common_local.h @@ -668,16 +668,16 @@ private: // RB end // foresthale 2014-05-30: a special binarize pacifier has to be shown in some cases, which includes filename and ETA information - bool loadPacifierBinarizeActive; - int loadPacifierBinarizeStartTime; - float loadPacifierBinarizeProgress; - float loadPacifierBinarizeTimeLeft; + bool loadPacifierBinarizeActive = false; + int loadPacifierBinarizeStartTime = 0; + float loadPacifierBinarizeProgress = 0.0f; + float loadPacifierBinarizeTimeLeft = 0.0f; idStr loadPacifierBinarizeFilename; idStr loadPacifierBinarizeInfo; - int loadPacifierBinarizeMiplevel; - int loadPacifierBinarizeMiplevelTotal; - int loadPacifierBinarizeProgressTotal; - int loadPacifierBinarizeProgressCurrent; + int loadPacifierBinarizeMiplevel = 0; + int loadPacifierBinarizeMiplevelTotal = 0; + int loadPacifierBinarizeProgressTotal = 0; + int loadPacifierBinarizeProgressCurrent = 0; bool showShellRequested; diff --git a/neo/renderer/Image.h b/neo/renderer/Image.h index 6cee7f3f..d7674a87 100644 --- a/neo/renderer/Image.h +++ b/neo/renderer/Image.h @@ -327,7 +327,7 @@ public: levelLoadReferenced = true; } - void FinalizeImage( bool fromBackEnd, nvrhi::ICommandList* commandList ); + void ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandList ); // Adds the image to the list of images to load on the main thread to the gpu. void DeferredLoadImage(); diff --git a/neo/renderer/ImageManager.cpp b/neo/renderer/ImageManager.cpp index 2aef086b..1210830e 100644 --- a/neo/renderer/ImageManager.cpp +++ b/neo/renderer/ImageManager.cpp @@ -3,6 +3,7 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2013-2024 Robert Beckebans Copyright (C) 2022 Stephen Pridham This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -198,12 +199,12 @@ void R_ListImages_f( const idCmdArgs& args ) if( failed ) { - idLib::Printf( "usage: listImages [ sorted | namesort | unloaded | duplicated | showOverSized ]\n" ); + common->Printf( "usage: listImages [ sorted | namesort | unloaded | duplicated | showOverSized ]\n" ); return; } const char* header = " -w-- -h-- filt -fmt-- wrap size --name-------\n"; - idLib::Printf( "\n%s", header ); + common->Printf( "\n%s", header ); totalSize = 0; @@ -262,7 +263,7 @@ void R_ListImages_f( const idCmdArgs& args ) } else { - idLib::Printf( "%4i:", i ); + common->Printf( "%4i:", i ); image->Print(); } totalSize += image->StorageSize(); @@ -282,13 +283,13 @@ void R_ListImages_f( const idCmdArgs& args ) partialSize = 0; for( i = 0 ; i < count ; i++ ) { - idLib::Printf( "%4i:", sortedArray[i].index ); + common->Printf( "%4i:", sortedArray[i].index ); sortedArray[i].image->Print(); partialSize += sortedArray[i].image->StorageSize(); if( ( ( i + 1 ) % 10 ) == 0 ) { - idLib::Printf( "-------- %5.1f of %5.1f megs --------\n", - partialSize / ( 1024 * 1024.0 ), totalSize / ( 1024 * 1024.0 ) ); + common->Printf( "-------- %5.1f of %5.1f megs --------\n", + partialSize / ( 1024 * 1024.0 ), totalSize / ( 1024 * 1024.0 ) ); } } } @@ -310,7 +311,7 @@ idImage* idImageManager::AllocImage( const char* name ) { if( strlen( name ) >= MAX_IMAGE_NAME ) { - idLib::Error( "idImageManager::AllocImage: \"%s\" is too long\n", name ); + common->Error( "idImageManager::AllocImage: \"%s\" is too long\n", name ); } int hash = idStr( name ).FileNameHash(); @@ -432,7 +433,7 @@ idImage* idImageManager::ImageFromFile( const char* _name, textureFilter_t filte } if( image->cubeFiles != cubeMap ) { - idLib::Error( "Image '%s' has been referenced with conflicting cube map states", _name ); + common->Error( "Image '%s' has been referenced with conflicting cube map states", _name ); } if( image->filter != filter || image->repeat != repeat ) @@ -453,8 +454,7 @@ idImage* idImageManager::ImageFromFile( const char* _name, textureFilter_t filte if( ( !insideLevelLoad || preloadingMapImages ) && !image->IsLoaded() ) { image->referencedOutsideLevelLoad = ( !insideLevelLoad && !preloadingMapImages ); - - image->FinalizeImage( false, nullptr ); + image->ActuallyLoadImage( false, nullptr ); // load is from front end declManager->MediaPrint( "%ix%i %s (reload for mixed referneces)\n", image->GetUploadWidth(), image->GetUploadHeight(), image->GetName() ); } @@ -478,7 +478,7 @@ idImage* idImageManager::ImageFromFile( const char* _name, textureFilter_t filte if( !insideLevelLoad || preloadingMapImages ) { image->referencedOutsideLevelLoad = ( !insideLevelLoad && !preloadingMapImages ); - image->FinalizeImage( false, nullptr ); + image->ActuallyLoadImage( false, nullptr ); // load is from front end declManager->MediaPrint( "%ix%i %s\n", image->GetUploadWidth(), image->GetUploadHeight(), image->GetName() ); } @@ -666,9 +666,9 @@ void R_CombineCubeImages_f( const idCmdArgs& args ) { if( args.Argc() != 2 ) { - idLib::Printf( "usage: combineCubeImages \n" ); - idLib::Printf( " combines basename[1-6][0001-9999].tga to basenameCM[0001-9999].tga\n" ); - idLib::Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" ); + common->Printf( "usage: combineCubeImages \n" ); + common->Printf( " combines basename[1-6][0001-9999].tga to basenameCM[0001-9999].tga\n" ); + common->Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" ); return; } @@ -686,12 +686,12 @@ void R_CombineCubeImages_f( const idCmdArgs& args ) { idStr::snPrintf( filename, sizeof( filename ), "%s%i%04i.tga", baseName.c_str(), orderRemap[side], frameNum ); - idLib::Printf( "reading %s\n", filename ); + common->Printf( "reading %s\n", filename ); R_LoadImage( filename, &pics[side], &width, &height, NULL, true, NULL ); if( !pics[side] ) { - idLib::Printf( "not found.\n" ); + common->Printf( "not found.\n" ); break; } @@ -739,7 +739,7 @@ void R_CombineCubeImages_f( const idCmdArgs& args ) } idStr::snPrintf( filename, sizeof( filename ), "%sCM%04i.tga", baseName.c_str(), frameNum ); - idLib::Printf( "writing %s\n", filename ); + common->Printf( "writing %s\n", filename ); R_WriteTGA( filename, combined, width, height * 6 ); } common->SetRefreshOnPrint( false ); @@ -848,7 +848,7 @@ void idImageManager::Preload( const idPreloadManifest& manifest, const bool& map if( preLoad_Images.GetBool() && manifest.NumResources() > 0 ) { // preload this levels images - idLib::Printf( "Preloading images...\n" ); + common->Printf( "Preloading images...\n" ); preloadingMapImages = mapPreload; int start = Sys_Milliseconds(); int numLoaded = 0; @@ -882,8 +882,8 @@ void idImageManager::Preload( const idPreloadManifest& manifest, const bool& map } //fileSystem->StopPreload(); int end = Sys_Milliseconds(); - idLib::Printf( "%05d images preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 ); - idLib::Printf( "----------------------------------------\n" ); + common->Printf( "%05d images preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 ); + common->Printf( "----------------------------------------\n" ); preloadingMapImages = false; } } @@ -937,7 +937,7 @@ int idImageManager::LoadLevelImages( bool pacifier ) if( image->levelLoadReferenced && !image->IsLoaded() ) { loadCount++; - image->FinalizeImage( false, commandList ); + image->ActuallyLoadImage( false, commandList ); } } @@ -963,13 +963,13 @@ void idImageManager::EndLevelLoad() { insideLevelLoad = false; - idLib::Printf( "----- idImageManager::EndLevelLoad -----\n" ); + common->Printf( "----- idImageManager::EndLevelLoad -----\n" ); int start = Sys_Milliseconds(); int loadCount = LoadLevelImages( true ); int end = Sys_Milliseconds(); - idLib::Printf( "%5i images loaded in %5.1f seconds\n", loadCount, ( end - start ) * 0.001 ); - idLib::Printf( "----------------------------------------\n" ); + common->Printf( "%5i images loaded in %5.1f seconds\n", loadCount, ( end - start ) * 0.001 ); + common->Printf( "----------------------------------------\n" ); //R_ListImages_f( idCmdArgs( "sorted sorted", false ) ); } #endif @@ -1060,7 +1060,7 @@ void idImageManager::LoadDeferredImages( nvrhi::ICommandList* _commandList ) } bool preloadPacifier = common->LoadPacifierRunning(); - if( !preloadPacifier ) + if( !preloadPacifier && globalImages->imagesToLoad.Num() > 0 ) { common->LoadPacifierInfo( "Loading deferred images" ); common->LoadPacifierProgressTotal( imagesToLoad.Num() ); @@ -1069,7 +1069,7 @@ void idImageManager::LoadDeferredImages( nvrhi::ICommandList* _commandList ) for( int i = 0; i < globalImages->imagesToLoad.Num(); i++ ) { // This is a "deferred" load of textures to the gpu. - globalImages->imagesToLoad[i]->FinalizeImage( false, thisCmdList ); + globalImages->imagesToLoad[i]->ActuallyLoadImage( false, thisCmdList ); if( !preloadPacifier ) { @@ -1077,10 +1077,11 @@ void idImageManager::LoadDeferredImages( nvrhi::ICommandList* _commandList ) } } #else + + // just load the binary image so we have the width and height for dmap for( int i = 0; i < globalImages->imagesToLoad.Num(); i++ ) { - // This is a "deferred" load of textures to the gpu. - globalImages->imagesToLoad[i]->FinalizeImage( false, NULL ); + globalImages->imagesToLoad[i]->ActuallyLoadImage( false, NULL ); } #endif diff --git a/neo/renderer/Image_load.cpp b/neo/renderer/Image_load.cpp index 20ac4ddd..89194255 100644 --- a/neo/renderer/Image_load.cpp +++ b/neo/renderer/Image_load.cpp @@ -308,6 +308,200 @@ void idImage::AllocImage( const idImageOpts& imgOpts, textureFilter_t tf, textur AllocImage(); } +/* +================ +GenerateImage +================ +*/ +void idImage::GenerateImage( const byte* pic, int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm, nvrhi::ICommandList* commandList, bool isRenderTarget, bool isUAV, uint sampleCount, cubeFiles_t _cubeFiles ) +{ + PurgeImage(); + + filter = filterParm; + repeat = repeatParm; + usage = usageParm; + cubeFiles = _cubeFiles; + + opts.textureType = ( sampleCount > 1 ) ? TT_2D_MULTISAMPLE : TT_2D; + opts.width = width; + opts.height = height; + opts.numLevels = 0; + opts.samples = sampleCount; + opts.isRenderTarget = isRenderTarget; + opts.isUAV = isUAV; + + // RB + if( cubeFiles == CF_2D_PACKED_MIPCHAIN ) + { + opts.width = width * ( 2.0f / 3.0f ); + } + + DeriveOpts(); + + // RB: allow pic == NULL for internal framebuffer images + if( pic == NULL || opts.textureType == TT_2D_MULTISAMPLE ) + { + AllocImage(); + isLoaded = true; + } + else + { + idBinaryImage im( GetName() ); + if( cubeFiles == CF_2D_PACKED_MIPCHAIN ) + { + im.Load2DAtlasMipchainFromMemory( width, opts.height, pic, opts.numLevels, opts.format, opts.colorFormat ); + } + else + { + im.Load2DFromMemory( width, height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips ); + } + + // don't show binarize info for generated images + common->LoadPacifierBinarizeEnd(); + + AllocImage(); + +#if defined( USE_NVRHI ) && !defined( DMAP ) + if( commandList ) + { + const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format ); + const int bytesPerBlock = info.bytesPerBlock; + + commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common ); + + for( int i = 0; i < im.NumImages(); i++ ) + { + const bimageImage_t& img = im.GetImageHeader( i ); + const byte* data = im.GetImageData( i ); + + int rowPitch = GetRowPitch( opts.format, img.width ); + commandList->writeTexture( texture, img.destZ, img.level, data, rowPitch ); + } + + commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource ); + commandList->commitBarriers(); + } +#else + /* + for( int i = 0; i < im.NumImages(); i++ ) + { + const bimageImage_t& img = im.GetImageHeader( i ); + const byte* data = im.GetImageData( i ); + SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); + } + */ +#endif + + isLoaded = true; + } + // RB end +} + +/* +==================== +GenerateCubeImage + +Non-square cube sides are not allowed +==================== +*/ +void idImage::GenerateCubeImage( const byte* pic[6], int size, textureFilter_t filterParm, textureUsage_t usageParm, nvrhi::ICommandList* commandList ) +{ + PurgeImage(); + + filter = filterParm; + repeat = TR_CLAMP; + usage = usageParm; + cubeFiles = CF_NATIVE; + + opts.textureType = TT_CUBIC; + opts.width = size; + opts.height = size; + opts.numLevels = 0; + DeriveOpts(); + + // if we don't have a rendering context, just return after we + // have filled in the parms. We must have the values set, or + // an image match from a shader before the render starts would miss + // the generated texture +#if !defined( DMAP ) + if( !tr.IsInitialized() ) + { + return; + } +#endif + + idBinaryImage im( GetName() ); + im.LoadCubeFromMemory( size, pic, opts.numLevels, opts.format, opts.gammaMips ); + + // don't show binarize info for generated images + common->LoadPacifierBinarizeEnd(); + + AllocImage(); + +#if defined( USE_NVRHI ) && !defined( DMAP ) + int numChannels = 4; + int bytesPerPixel = numChannels; + if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 ) + { + bytesPerPixel = 1; + } + + const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format ); + bytesPerPixel = info.bytesPerBlock; + + commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common ); + + for( int i = 0; i < im.NumImages(); i++ ) + { + const bimageImage_t& img = im.GetImageHeader( i ); + const byte* data = im.GetImageData( i ); + + commandList->writeTexture( texture, 0, img.level, data, GetRowPitch( opts.format, img.width ) ); + } + + commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource ); + commandList->commitBarriers(); +#else + /* + for( int i = 0; i < im.NumImages(); i++ ) + { + const bimageImage_t& img = im.GetImageHeader( i ); + const byte* data = im.GetImageData( i ); + SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); + } + */ +#endif + + isLoaded = true; +} + +// RB begin +void idImage::GenerateShadowArray( int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm, nvrhi::ICommandList* commandList ) +{ + PurgeImage(); + + filter = filterParm; + repeat = repeatParm; + usage = usageParm; + cubeFiles = CF_2D_ARRAY; + byte* pic = nullptr; + + opts.textureType = TT_2D_ARRAY; + opts.width = width; + opts.height = height; + opts.numLevels = 0; + opts.isRenderTarget = true; + + DeriveOpts(); + + // The image will be uploaded to the gpu on a deferred state. + AllocImage(); + + isLoaded = true; +} +// RB end + + /* =============== GetGeneratedName @@ -337,7 +531,7 @@ Absolutely every image goes through this path On exit, the idImage will have a valid OpenGL texture number that can be bound =============== */ -void idImage::FinalizeImage( bool fromBackEnd, nvrhi::ICommandList* commandList ) +void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandList ) { // RB: might have been called doubled by nested LoadDeferredImages if( isLoaded ) @@ -752,6 +946,142 @@ void idImage::DeferredPurgeImage() globalImages->imagesToLoad.Remove( this ); } +/* +============= +RB_UploadScratchImage + +if rows = cols * 6, assume it is a cube map animation +============= +*/ +void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::ICommandList* commandList ) +{ +#if !defined( DMAP ) + + // if rows = cols * 6, assume it is a cube map animation + if( rows == cols * 6 ) + { + rows /= 6; + const byte* pic[6]; + + for( int i = 0; i < 6; i++ ) + { + pic[i] = data + cols * rows * 4 * i; + } + + if( opts.textureType != TT_CUBIC || usage != TD_LOOKUP_TABLE_RGBA ) + { + GenerateCubeImage( pic, cols, TF_LINEAR, TD_LOOKUP_TABLE_RGBA, commandList ); + return; + } + + if( opts.width != cols || opts.height != rows ) + { + opts.width = cols; + opts.height = rows; + + 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 ) + { + bytesPerPixel = 1; + } + + const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format ); + bytesPerPixel = info.bytesPerBlock; + + SetSamplerState( TF_LINEAR, TR_CLAMP ); + + commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common ); + + int bufferW = opts.width; + if( IsCompressed() ) + { + bufferW = ( opts.width + 3 ) & ~3; + } + + for( int i = 0; i < 6; i++ ) + { + commandList->writeTexture( texture, i, 0, pic[i], GetRowPitch( opts.format, opts.width ) ); + } + + commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource ); + commandList->commitBarriers(); +#else + /* + for( int i = 0; i < 6; i++ ) + { + SubImageUpload( 0, 0, 0, i, opts.width, opts.height, pic[i] ); + } + */ +#endif + } + else + { +#if defined( USE_NVRHI ) + if( opts.width != cols || opts.height != rows ) + { + opts.width = cols; + opts.height = rows; + + AllocImage(); + } + + if( data != NULL && commandList != NULL ) + { + 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(); + } +#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 + } + + isLoaded = true; + +#endif +} + /* ================== StorageSize @@ -934,354 +1264,5 @@ void idImage::Reload( bool force, nvrhi::ICommandList* commandList ) DeferredLoadImage(); } -/* -================ -GenerateImage -================ -*/ -void idImage::GenerateImage( const byte* pic, int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm, nvrhi::ICommandList* commandList, bool isRenderTarget, bool isUAV, uint sampleCount, cubeFiles_t _cubeFiles ) -{ - PurgeImage(); - filter = filterParm; - repeat = repeatParm; - usage = usageParm; - cubeFiles = _cubeFiles; - opts.textureType = ( sampleCount > 1 ) ? TT_2D_MULTISAMPLE : TT_2D; - opts.width = width; - opts.height = height; - opts.numLevels = 0; - opts.samples = sampleCount; - opts.isRenderTarget = isRenderTarget; - opts.isUAV = isUAV; - - // RB - if( cubeFiles == CF_2D_PACKED_MIPCHAIN ) - { - opts.width = width * ( 2.0f / 3.0f ); - } - - DeriveOpts(); - - // RB: allow pic == NULL for internal framebuffer images - if( pic == NULL || opts.textureType == TT_2D_MULTISAMPLE ) - { - AllocImage(); - isLoaded = true; - } - else - { - idBinaryImage im( GetName() ); - - // foresthale 2014-05-30: give a nice progress display when binarizing - commonLocal.LoadPacifierBinarizeFilename( GetName() , "generated image" ); - if( opts.numLevels > 1 ) - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height * 4 / 3 ); - } - else - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height ); - } - - if( cubeFiles == CF_2D_PACKED_MIPCHAIN ) - { - im.Load2DAtlasMipchainFromMemory( width, opts.height, pic, opts.numLevels, opts.format, opts.colorFormat ); - } - else - { - im.Load2DFromMemory( width, height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips ); - } - - commonLocal.LoadPacifierBinarizeEnd(); - - AllocImage(); - -#if defined( USE_NVRHI ) && !defined( DMAP ) - if( commandList ) - { - const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format ); - const int bytesPerBlock = info.bytesPerBlock; - - commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common ); - - for( int i = 0; i < im.NumImages(); i++ ) - { - const bimageImage_t& img = im.GetImageHeader( i ); - const byte* data = im.GetImageData( i ); - - int rowPitch = GetRowPitch( opts.format, img.width ); - commandList->writeTexture( texture, img.destZ, img.level, data, rowPitch ); - } - - commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource ); - commandList->commitBarriers(); - } -#else - /* - for( int i = 0; i < im.NumImages(); i++ ) - { - const bimageImage_t& img = im.GetImageHeader( i ); - const byte* data = im.GetImageData( i ); - SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); - } - */ -#endif - - isLoaded = true; - } - // RB end -} - -/* -==================== -GenerateCubeImage - -Non-square cube sides are not allowed -==================== -*/ -void idImage::GenerateCubeImage( const byte* pic[6], int size, textureFilter_t filterParm, textureUsage_t usageParm, nvrhi::ICommandList* commandList ) -{ - PurgeImage(); - - filter = filterParm; - repeat = TR_CLAMP; - usage = usageParm; - cubeFiles = CF_NATIVE; - - opts.textureType = TT_CUBIC; - opts.width = size; - opts.height = size; - opts.numLevels = 0; - DeriveOpts(); - - // if we don't have a rendering context, just return after we - // have filled in the parms. We must have the values set, or - // an image match from a shader before the render starts would miss - // the generated texture -#if !defined( DMAP ) - if( !tr.IsInitialized() ) - { - return; - } -#endif - - idBinaryImage im( GetName() ); - - // foresthale 2014-05-30: give a nice progress display when binarizing - commonLocal.LoadPacifierBinarizeFilename( GetName(), "generated cube image" ); - if( opts.numLevels > 1 ) - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 * 4 / 3 ); - } - else - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 ); - } - - im.LoadCubeFromMemory( size, pic, opts.numLevels, opts.format, opts.gammaMips ); - - commonLocal.LoadPacifierBinarizeEnd(); - - AllocImage(); - -#if defined( USE_NVRHI ) && !defined( DMAP ) - int numChannels = 4; - int bytesPerPixel = numChannels; - if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 ) - { - bytesPerPixel = 1; - } - - const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format ); - bytesPerPixel = info.bytesPerBlock; - - commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common ); - - for( int i = 0; i < im.NumImages(); i++ ) - { - const bimageImage_t& img = im.GetImageHeader( i ); - const byte* data = im.GetImageData( i ); - - commandList->writeTexture( texture, 0, img.level, data, GetRowPitch( opts.format, img.width ) ); - } - - commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource ); - commandList->commitBarriers(); -#else - /* - for( int i = 0; i < im.NumImages(); i++ ) - { - const bimageImage_t& img = im.GetImageHeader( i ); - const byte* data = im.GetImageData( i ); - SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); - } - */ -#endif - - isLoaded = true; -} - -// RB begin -void idImage::GenerateShadowArray( int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm, nvrhi::ICommandList* commandList ) -{ - PurgeImage(); - - filter = filterParm; - repeat = repeatParm; - usage = usageParm; - cubeFiles = CF_2D_ARRAY; - byte* pic = nullptr; - - opts.textureType = TT_2D_ARRAY; - opts.width = width; - opts.height = height; - opts.numLevels = 0; - opts.isRenderTarget = true; - - - DeriveOpts(); - - // The image will be uploaded to the gpu on a deferred state. - AllocImage(); - - isLoaded = true; -} -// RB end - -/* -============= -RB_UploadScratchImage - -if rows = cols * 6, assume it is a cube map animation -============= -*/ -void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::ICommandList* commandList ) -{ -#if !defined( DMAP ) - - // if rows = cols * 6, assume it is a cube map animation - if( rows == cols * 6 ) - { - rows /= 6; - const byte* pic[6]; - - for( int i = 0; i < 6; i++ ) - { - pic[i] = data + cols * rows * 4 * i; - } - - if( opts.textureType != TT_CUBIC || usage != TD_LOOKUP_TABLE_RGBA ) - { - GenerateCubeImage( pic, cols, TF_LINEAR, TD_LOOKUP_TABLE_RGBA, commandList ); - return; - } - - if( opts.width != cols || opts.height != rows ) - { - opts.width = cols; - opts.height = rows; - - 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 ) - { - bytesPerPixel = 1; - } - - const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format ); - bytesPerPixel = info.bytesPerBlock; - - SetSamplerState( TF_LINEAR, TR_CLAMP ); - - commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common ); - - int bufferW = opts.width; - if( IsCompressed() ) - { - bufferW = ( opts.width + 3 ) & ~3; - } - - for( int i = 0; i < 6; i++ ) - { - commandList->writeTexture( texture, i, 0, pic[i], GetRowPitch( opts.format, opts.width ) ); - } - - commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource ); - commandList->commitBarriers(); -#else - /* - for( int i = 0; i < 6; i++ ) - { - SubImageUpload( 0, 0, 0, i, opts.width, opts.height, pic[i] ); - } - */ -#endif - } - else - { -#if defined( USE_NVRHI ) - if( opts.width != cols || opts.height != rows ) - { - opts.width = cols; - opts.height = rows; - - AllocImage(); - } - - if( data != NULL && commandList != NULL ) - { - 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(); - } -#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 - } - - isLoaded = true; - -#endif -} diff --git a/neo/renderer/NVRHI/RenderBackend_NVRHI.cpp b/neo/renderer/NVRHI/RenderBackend_NVRHI.cpp index 59a793a3..02ddef20 100644 --- a/neo/renderer/NVRHI/RenderBackend_NVRHI.cpp +++ b/neo/renderer/NVRHI/RenderBackend_NVRHI.cpp @@ -2270,7 +2270,7 @@ void idRenderBackend::SetCurrentImage( idImage* image ) if( !image->IsLoaded() && !image->IsDefaulted() ) { // TODO(Stephen): Fix me. - image->FinalizeImage( true, commandList ); + image->ActuallyLoadImage( true, commandList ); } context.imageParms[context.currentImageParm] = image; diff --git a/neo/renderer/RenderPass.cpp b/neo/renderer/RenderPass.cpp index 3711749a..276e0a8c 100644 --- a/neo/renderer/RenderPass.cpp +++ b/neo/renderer/RenderPass.cpp @@ -141,7 +141,7 @@ bool BasicTriangle::Init() commandList->open(); for( int i = 0; i < material->GetNumStages(); i++ ) { - material->GetStage( i )->texture.image->FinalizeImage( true, commandList ); + material->GetStage( i )->texture.image->ActuallyLoadImage( true, commandList ); } commandList->close(); GetDevice()->executeCommandList( commandList ); From 8389318e2647c31771adb6afe01200b6ddadf3b9 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Sat, 29 Jun 2024 12:54:29 +0200 Subject: [PATCH 6/7] Allow skipping intro videos with Escape/Gamepad Start --- neo/d3xp/menus/MenuHandler_Shell.cpp | 28 ++++++++++++++++++++++++++++ neo/framework/Common.cpp | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/neo/d3xp/menus/MenuHandler_Shell.cpp b/neo/d3xp/menus/MenuHandler_Shell.cpp index 2349458c..45f018fd 100644 --- a/neo/d3xp/menus/MenuHandler_Shell.cpp +++ b/neo/d3xp/menus/MenuHandler_Shell.cpp @@ -330,6 +330,34 @@ bool idMenuHandler_Shell::HandleGuiEvent( const sysEvent_t* sev ) if( showingIntro ) { + // RB: allow to skip intro videos + if( sev->evType == SE_KEY && sev->evValue2 == 1 && ( sev->evValue == K_ESCAPE || sev->evValue == K_JOY9 ) ) + { + if( introGui != NULL && introGui->IsActive() ) + { + gui->StopSound(); + showingIntro = false; + introGui->Activate( false ); + PlaySound( GUI_SOUND_MUSIC ); + + const char* introName = introGui->GetName(); + + if( idStr::Cmp( introName, "swf/roeintro.swf" ) == 0 ) + { + StartGame( 1 ); + } + else if( idStr::Cmp( introName, "swf/leintro.swf" ) == 0 ) + { + StartGame( 2 ); + } + else + { + StartGame( 0 ); + } + } + } + // RB end + return true; } diff --git a/neo/framework/Common.cpp b/neo/framework/Common.cpp index 855cb01b..aba644bd 100644 --- a/neo/framework/Common.cpp +++ b/neo/framework/Common.cpp @@ -1794,7 +1794,7 @@ bool idCommonLocal::ProcessEvent( const sysEvent_t* event ) { if( event->evType == SE_KEY && event->evValue2 == 1 && ( event->evValue == K_ESCAPE || event->evValue == K_JOY9 ) ) { - if( game->CheckInCinematic() == true ) + if( game->CheckInCinematic() ) { game->SkipCinematicScene(); } From 578a0517b571833e9f87f89085c422668ef0c3be Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Sat, 29 Jun 2024 13:08:51 +0200 Subject: [PATCH 7/7] Linux build fixes --- neo/tools/compilers/main_posix.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/neo/tools/compilers/main_posix.cpp b/neo/tools/compilers/main_posix.cpp index 3068f76a..070a62b2 100644 --- a/neo/tools/compilers/main_posix.cpp +++ b/neo/tools/compilers/main_posix.cpp @@ -618,6 +618,7 @@ int Sys_Milliseconds() return curtime; // DG end } + class idSysCmdline : public idSys { public: @@ -823,7 +824,7 @@ public: // Initialize everything. // if the OS allows, pass argc/argv directly (without executable name) // otherwise pass the command line in a single string (without executable name) - virtual void Init( int argc, const char* const* argv, const char* cmdline ) { }; + virtual void Init( int argc, const char* const* argv, const char* cmdline ) {} // Shuts down everything. virtual void Shutdown() {} @@ -851,6 +852,13 @@ public: virtual void UpdateScreen( bool captureToImage, bool releaseMouse = true ); virtual void UpdateLevelLoadPacifier() {} + virtual void LoadPacifierInfo( VERIFY_FORMAT_STRING const char* fmt, ... ) {} + virtual void LoadPacifierProgressTotal( int total ) {} + virtual void LoadPacifierProgressIncrement( int step ) {} + virtual bool LoadPacifierRunning() + { + return false; + } // Checks for and removes command line "+set var arg" constructs. @@ -859,7 +867,7 @@ public: virtual void StartupVariable( const char* match ) {} // Begins redirection of console output to the given buffer. - virtual void BeginRedirect( char* buffer, int buffersize, void ( *flush )( const char* ) ) { }; + virtual void BeginRedirect( char* buffer, int buffersize, void ( *flush )( const char* ) ) {} // Stops redirection of console output. virtual void EndRedirect() {}