Merge branch 'master' into nvrhi-rebase-040224

This commit is contained in:
Stephen Saunders 2024-02-04 15:02:13 -05:00
commit 7911f5252d
61 changed files with 3186 additions and 611 deletions

View file

@ -510,7 +510,7 @@ Recommended in this case is `cmake-vs2022-win64-no-ffmpeg.bat`
Xcode release and universal builds now automatically package the executable into a macOS app bundle, defining an Info.plist file and copying the base directory and custom icon into the application bundle's Contents/Resources folder. This is controlled by adding -DMACOSX_BUNDLE=ON to the CMake options.
Depending on which package manager you install (Homebrew or MacPorts) you may need to change the openal-soft library and include paths specified in the cmake shell scripts. For single architecture builds (debug, release, retail) the default openal-soft paths are set for Homebrew on x86, while for universal builds the default paths are set for MacPorts on x86 or Apple Silicon. If you want to build using the single architecture shell scripts (debug, release, retail) on Apple Silicon, you will need to change the openal-soft paths from `/usr/local/...` to either `/opt/homebrew/...` (Homebrew) or `/opt/local/...` (MacPorts).
For single architecture builds (debug, release, retail) the default openal-soft paths are set for Homebrew, while for universal builds the default paths are set for MacPorts. The single architecture build scripts are now portable and automatically detect Homebrew's openal-soft path prefix for x86 and Apple Silicon. The universal build script remains portable since MacPorts uses the same openal-soft installation path on x86 and Apple Silicon.
4. Compile RBDOOM-3-BFG targets:
@ -639,8 +639,10 @@ r_graphicsAPI | Default DX12, can be either DX12 or Vul
r_antiAliasing | Different Anti-Aliasing modes
r_exposure [0 .. 1] | Default 0.5, controls brightness and affects HDR -> sRGB Rec. 709 exposure key. This is what you change in the video brightness options
r_useSSAO [0 .. 1] | Use Screen Space Ambient Occlusion to darken the corners in the scene and give it more depth
r_useFilmicPostProcessing [0, 1] | Apply several post process effects to mimic a filmic look
r_forceAmbient | Default 0.5, controls additional brightness by Global Illumination
r_useFilmicPostFX [0, 1] | Apply several post process effects to mimic a filmic look
r_useCRTPostFX [0, 1] | CRT monitor/TV filter
r_renderMode [0 .. 5] | Default 0 = Doom 3, 1 = Commodore 64, 2 = Commodore 64 Highres, 3 = Sega Genesis, 4 = Sega Genesis Highres, 5 = Sony PSX
## Modding Support
Name | Description

View file

@ -19,6 +19,70 @@ TBD - RBDOOM-3-BFG 1.6.0
_______________________________
## .plan - January 20, 2024
Cudos to Stephen Saunders for this build and to reeFridge for finding the issue.
This fixes a number of multiplayer issues. Create Private Match with clients now works reliably. The missing functionality of the online game browser and leaderboards hasn't been fixed.
Changelog:
* Fixes regression Multiplayer: Accessing memory after it has been freed #846 caused by an earlier, but broken memory leak fix on my part. The fix is almost identical to PR Free idLobby memory inside destructor #847
* Fixes a critical issue with mis-reading network snapshot data on the client side, which caused no end of problems with mis-rendering, slowdowns, unstable connections, etc. The client was ignoring the entity network-synced flag which tells it whether it should read entity class-specific data. It was trying to read it all the time and sometimes coming up with null data which caused tons of problems with rendering and physics calculations (e.g. operations on NaN numbers). Simple fix was to respect the entity's network-synced flag on the client side but it makes all the difference.
* Fixes an incorrect assert on multiplayer VoiceChat shutdown
* Allows r_useScissor and r_useParallelAdd cvars to be changed in multiplayer mode for use in bake* operations on multiplayer maps
* Fixed a couple of uninitialized variables that showed up in valgrind when in multiplayer mode
* Added Amstrad CPC 6128 Retro rendering mode
## .plan - January 03, 2024
This is a preview build of the new Retro 8-bit/16-bit/PSX rendering modes.
The new rendering modes can be set in the menu options but it's controlled mainly r_renderMode.
The values are 0 = Doom, 1 = Commodore 64, 2 = Commodore 64 Highres, 3 = Sega Genesis, 4 = Sega Genesis Highres, 5 = Sony PSX
The Commodore 64 mode regulates all colors down to the original 16 color palette.
The Sega mode mimics 9 bit color HW which means 3 bit per color channel resulting in a total of 512 colors.
The PSX mode only turns off linear filtering for the textures and applies a screen space dithering effect.
All retro rendering modes try to mimic the 320x240 resolution but it is extended to 16:9 so it is 480 x 270.
Highres modes only apply a higher resolution dithering on the pixelated output.
The PSX mode has no additional artifacts yet like wiggling vertices or textures.
There are also 2 new CRT filters that are drawn on top of everything else (even the console) for more arcade vibes.
Changelog:
* Fixed scissor clipping issues of regular surfaces like light flares #651
* Duplicating lights with Ctrl+D works now
* Merged script interpreter improvements from Dhewm3, especially that fixes https://github.com/dhewm/dhewm3/issues/303
* Doubled MAX_GLOBALS for the Runners 2.6 mod
* Crash fix between level switching and loading of new textures for D3HDP and other mods
* Fixed many small memory leaks (thanks to Steve Saunders)
* Reduced console spam and got rid of the depth-stencil is read-only warnings
* Added image_pixelLook to disable texture filtering on most textures regardless of the render mode
* Changed devtools.cfg so you can easily switch between the new render modes with F7 and F8
Changelog TrenchBroomBFG:
* Added Show patches option to View Options
## .plan - October 27, 2023
This is a preview build of the new WIP ingame Light Editor with some important bugfixes in the convertMapToValve220 command.

View file

@ -3,14 +3,14 @@ bind "I" "toggle r_showSurfaceInfo"
bind "N" "noclip"
bind "M" "spawn moveable_macbethchart"
bind "F1" "toggle r_showViewEnvprobes 1 2 3 0"
bind "F2" "toggle r_showTris 1 2 3 0"
bind "F1" "toggle editLights"
bind "F2" "toggle r_showTris 1 2 0"
bind "F3" "toggle r_forceAmbient 0.5 1.0 0"
bind "F4" "toggle r_skipInteractions"
bind "F5" "savegame quick"
bind "F6" "toggle r_showLightGrid 1 3 4 0"
bind "F7" "toggle r_useSSAO"
bind "F8" "toggle r_useFilmicPostProcessing"
bind "F7" "toggle r_renderMode 0 1 2 3 4 5 6 7"
bind "F8" "toggle r_useCRTPostFX 0 1 2"
bind "F9" "loadgame quick"
bind "F10" "toggle com_fixedTic"
bind "F11" "toggle r_pbrDebug"
//bind "F10" "toggle com_fixedTic"
bind "F11" "toggle r_useFilmicPostFX"

View file

@ -429,6 +429,8 @@ if(USE_VULKAN)
if(USE_VMA)
add_definitions(-DUSE_AMD_ALLOCATOR)
include_directories("libs/vma/include")
file(GLOB VMA_INCLUDES libs/vma/include/*.h)
source_group("libs\\vma" FILES ${VMA_INCLUDES})
endif()
endif()
@ -1308,6 +1310,7 @@ set(RBDOOM3_INCLUDES
#${FREETYPE_SOURCES}
${SOUND_INCLUDES}
${OGGVORBIS_INCLUDES}
${VMA_INCLUDES}
${OPTICK_INCLUDES}
${UI_INCLUDES}
${SWF_INCLUDES}
@ -1780,7 +1783,8 @@ else()
# delete precompiled header file after executable is compiled: IDE build case (e.g. Xcode)
else()
add_custom_command(TARGET RBDoom3BFG POST_BUILD
COMMAND ${remove_command} "idlib/precompiled.h.gch"
# SRS - added wildcards to remove tmp files from cmake ZERO_CHECK regeneration
COMMAND ${remove_command} "idlib/precompiled.h*.gch*"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "remove idlib/precompiled.h.gch"
)

View file

@ -2,5 +2,16 @@ cd ..
rm -rf build
mkdir build
cd build
# asemarafa/SRS - Determine the Homebrew path prefix for openal-soft
if [ -z "$OPENAL_PREFIX" ]; then
OPENAL_PREFIX=$(brew --prefix openal-soft 2>/dev/null)
if [ -z "$OPENAL_PREFIX" ]; then
echo "Error: openal-soft is not installed via Homebrew."
echo "Either install it using 'brew install openal-soft' or define the path prefix via OPENAL_PREFIX."
exit 1
fi
fi
# change or remove -DCMAKE_OSX_DEPLOYMENT_TARGET=<version> to match supported runtime targets
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE="-DNDEBUG" -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 -DFFMPEG=OFF -DBINKDEC=ON -DUSE_MoltenVK=ON -DOPENAL_LIBRARY=/usr/local/opt/openal-soft/lib/libopenal.dylib -DOPENAL_INCLUDE_DIR=/usr/local/opt/openal-soft/include ../neo -Wno-dev
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE="-DNDEBUG" -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 -DFFMPEG=OFF -DBINKDEC=ON -DUSE_MoltenVK=ON -DOPENAL_LIBRARY=$OPENAL_PREFIX/lib/libopenal.dylib -DOPENAL_INCLUDE_DIR=$OPENAL_PREFIX/include ../neo -Wno-dev

View file

@ -2,5 +2,16 @@ cd ..
rm -rf build
mkdir build
cd build
# asemarafa/SRS - Determine the Homebrew path prefix for openal-soft
if [ -z "$OPENAL_PREFIX" ]; then
OPENAL_PREFIX=$(brew --prefix openal-soft 2>/dev/null)
if [ -z "$OPENAL_PREFIX" ]; then
echo "Error: openal-soft is not installed via Homebrew."
echo "Either install it using 'brew install openal-soft' or define the path prefix via OPENAL_PREFIX."
exit 1
fi
fi
# change or remove -DCMAKE_OSX_DEPLOYMENT_TARGET=<version> to match supported runtime targets
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE="-DNDEBUG -DID_RETAIL" -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 -DFFMPEG=OFF -DBINKDEC=ON -DUSE_MoltenVK=ON -DOPENAL_LIBRARY=/usr/local/opt/openal-soft/lib/libopenal.dylib -DOPENAL_INCLUDE_DIR=/usr/local/opt/openal-soft/include ../neo -Wno-dev
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE="-DNDEBUG -DID_RETAIL" -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 -DFFMPEG=OFF -DBINKDEC=ON -DUSE_MoltenVK=ON -DOPENAL_LIBRARY=$OPENAL_PREFIX/lib/libopenal.dylib -DOPENAL_INCLUDE_DIR=$OPENAL_PREFIX/include ../neo -Wno-dev

View file

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

View file

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

View file

@ -2,10 +2,22 @@ cd ..
rm -rf xcode-debug
mkdir xcode-debug
cd xcode-debug
# asemarafa/SRS - Determine the Homebrew path prefix for openal-soft
if [ -z "$OPENAL_PREFIX" ]; then
OPENAL_PREFIX=$(brew --prefix openal-soft 2>/dev/null)
if [ -z "$OPENAL_PREFIX" ]; then
echo "Error: openal-soft is not installed via Homebrew."
echo "Either install it using 'brew install openal-soft' or define the path prefix via OPENAL_PREFIX."
exit 1
fi
fi
# note 1: remove or set -DCMAKE_SUPPRESS_REGENERATION=OFF to reenable ZERO_CHECK target which checks for CMakeLists.txt changes and re-runs CMake before builds
# however, if ZERO_CHECK is reenabled **must** add VULKAN_SDK location to Xcode Custom Paths (under Prefs/Locations) otherwise build failures may occur
# note 2: policy CMAKE_POLICY_DEFAULT_CMP0142=NEW suppresses non-existant per-config suffixes on Xcode library search paths, works for cmake version 3.25 and later
# note 3: env variable MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE=1 enables MoltenVK's image view swizzle which may be required on older macOS versions or hardware (see vulkaninfo)
# note 4: env variable MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=0 disables synchronous queue submits which is optimal for the synchronization method used by the game
# note 5: env variable MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=2 enables MoltenVK's use of Metal argument buffers only if VK_EXT_descriptor_indexing is enabled
cmake -G Xcode -DCMAKE_BUILD_TYPE=Debug -DCMAKE_XCODE_GENERATE_SCHEME=ON -DCMAKE_XCODE_SCHEME_ENVIRONMENT="MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE=1;MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=0;MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=2" -DCMAKE_XCODE_SCHEME_ENABLE_GPU_API_VALIDATION=OFF -DCMAKE_SUPPRESS_REGENERATION=ON -DOPENAL_LIBRARY=/usr/local/opt/openal-soft/lib/libopenal.dylib -DOPENAL_INCLUDE_DIR=/usr/local/opt/openal-soft/include ../neo -DCMAKE_POLICY_DEFAULT_CMP0142=NEW -Wno-dev
# note 3: env variable MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE=1 enables MoltenVK's image view swizzle which may be required on older macOS versions or hardware (see vulkaninfo) - only used for VulkanSDK < 1.3.275
# note 4: env variable MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=0 disables synchronous queue submits which is optimal for the synchronization method used by the game - only used for VulkanSDK < 1.3.275
# note 5: env variable MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=2 enables MoltenVK's use of Metal argument buffers only if VK_EXT_descriptor_indexing is enabled - only used for VulkanSDK < 1.3.275
# note 6: env variable MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA=1.0 disables MoltenVK's timestampPeriod lowpass filter for non-Apple GPUs - only used for VulkanSDK < 1.3.275
cmake -G Xcode -DCMAKE_BUILD_TYPE=Debug -DCMAKE_XCODE_GENERATE_SCHEME=ON -DCMAKE_XCODE_SCHEME_ENVIRONMENT="MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE=1;MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=0;MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=2;MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA=1.0" -DCMAKE_XCODE_SCHEME_ENABLE_GPU_API_VALIDATION=OFF -DCMAKE_SUPPRESS_REGENERATION=ON -DOPENAL_LIBRARY=$OPENAL_PREFIX/lib/libopenal.dylib -DOPENAL_INCLUDE_DIR=$OPENAL_PREFIX/include ../neo -DCMAKE_POLICY_DEFAULT_CMP0142=NEW -Wno-dev

View file

@ -2,7 +2,18 @@ cd ..
rm -rf xcode-release
mkdir xcode-release
cd xcode-release
# asemarafa/SRS - Determine the Homebrew path prefix for openal-soft
if [ -z "$OPENAL_PREFIX" ]; then
OPENAL_PREFIX=$(brew --prefix openal-soft 2>/dev/null)
if [ -z "$OPENAL_PREFIX" ]; then
echo "Error: openal-soft is not installed via Homebrew."
echo "Either install it using 'brew install openal-soft' or define the path prefix via OPENAL_PREFIX."
exit 1
fi
fi
# note 1: remove or set -DCMAKE_SUPPRESS_REGENERATION=OFF to reenable ZERO_CHECK target which checks for CMakeLists.txt changes and re-runs CMake before builds
# however, if ZERO_CHECK is reenabled **must** add VULKAN_SDK location to Xcode Custom Paths (under Prefs/Locations) otherwise build failures may occur
# note 2: policy CMAKE_POLICY_DEFAULT_CMP0142=NEW suppresses non-existant per-config suffixes on Xcode library search paths, works for cmake version 3.25 and later
cmake -G Xcode -DCMAKE_BUILD_TYPE=Release -DCMAKE_CONFIGURATION_TYPES="Release;MinSizeRel;RelWithDebInfo" -DMACOSX_BUNDLE=ON -DFFMPEG=OFF -DBINKDEC=ON -DUSE_MoltenVK=ON -DCMAKE_XCODE_GENERATE_SCHEME=ON -DCMAKE_XCODE_SCHEME_ENABLE_GPU_API_VALIDATION=OFF -DCMAKE_SUPPRESS_REGENERATION=ON -DOPENAL_LIBRARY=/usr/local/opt/openal-soft/lib/libopenal.dylib -DOPENAL_INCLUDE_DIR=/usr/local/opt/openal-soft/include ../neo -DCMAKE_POLICY_DEFAULT_CMP0142=NEW -Wno-dev
cmake -G Xcode -DCMAKE_BUILD_TYPE=Release -DCMAKE_CONFIGURATION_TYPES="Release;MinSizeRel;RelWithDebInfo" -DMACOSX_BUNDLE=ON -DFFMPEG=OFF -DBINKDEC=ON -DUSE_MoltenVK=ON -DCMAKE_XCODE_GENERATE_SCHEME=ON -DCMAKE_XCODE_SCHEME_ENABLE_GPU_API_VALIDATION=OFF -DCMAKE_SUPPRESS_REGENERATION=ON -DOPENAL_LIBRARY=$OPENAL_PREFIX/lib/libopenal.dylib -DOPENAL_INCLUDE_DIR=$OPENAL_PREFIX/include ../neo -DCMAKE_POLICY_DEFAULT_CMP0142=NEW -Wno-dev

View file

@ -2,6 +2,15 @@ cd ..
rm -rf xcode-universal
mkdir xcode-universal
cd xcode-universal
# SRS - Determine if openal-soft universal variant is installed via MacPorts
OPENAL_VARIANTS=$(port info --variants openal-soft 2>/dev/null)
if [[ $OPENAL_VARIANTS != *universal* ]]; then
echo "Error: openal-soft universal variant is not installed via MacPorts."
echo "Please install it using 'sudo port install openal-soft +universal'"
exit 1
fi
# note 1: remove or set -DCMAKE_SUPPRESS_REGENERATION=OFF to reenable ZERO_CHECK target which checks for CMakeLists.txt changes and re-runs CMake before builds
# however, if ZERO_CHECK is reenabled **must** add VULKAN_SDK location to Xcode Custom Paths (under Prefs/Locations) otherwise build failures may occur
# note 2: policy CMAKE_POLICY_DEFAULT_CMP0142=NEW suppresses non-existant per-config suffixes on Xcode library search paths, works for cmake version 3.25 and later

View file

@ -429,7 +429,6 @@ idPlayerView::SingleView
*/
void idPlayerView::SingleView( const renderView_t* view, idMenuHandler_HUD* hudManager )
{
// normal rendering
if( !view )
{

View file

@ -1368,9 +1368,11 @@ public:
SYSTEM_FIELD_VSYNC,
SYSTEM_FIELD_ANTIALIASING,
// RB begin
SYSTEM_FIELD_POSTFX,
SYSTEM_FIELD_SSAO,
SYSTEM_FIELD_RENDERMODE,
SYSTEM_FIELD_AMBIENT_BRIGHTNESS,
SYSTEM_FIELD_SSAO,
SYSTEM_FIELD_FILMIC_POSTFX,
SYSTEM_FIELD_CRT_POSTFX,
// RB end
SYSTEM_FIELD_BRIGHTNESS,
SYSTEM_FIELD_VOLUME,

View file

@ -34,7 +34,7 @@ const static int NUM_SYSTEM_OPTIONS_OPTIONS = 8;
extern idCVar r_graphicsAPI;
extern idCVar r_antiAliasing;
extern idCVar r_useFilmicPostProcessing;
extern idCVar r_useFilmicPostFX;
extern idCVar r_swapInterval;
extern idCVar s_volume_dB;
extern idCVar r_exposure; // RB: use this to control HDR exposure or brightness in LDR mode
@ -119,10 +119,19 @@ void idMenuScreen_Shell_SystemOptions::Initialize( idMenuHandler* data )
// RB begin
control = new( TAG_SWF ) idMenuWidget_ControlButton();
control->SetOptionType( OPTION_SLIDER_TEXT );
control->SetLabel( "Filmic VFX" );
control->SetDataSource( &systemData, idMenuDataSource_SystemSettings::SYSTEM_FIELD_POSTFX );
control->SetLabel( "Render Mode" );
control->SetDataSource( &systemData, idMenuDataSource_SystemSettings::SYSTEM_FIELD_RENDERMODE );
control->SetupEvents( DEFAULT_REPEAT_TIME, options->GetChildren().Num() );
control->AddEventAction( WIDGET_EVENT_PRESS ).Set( WIDGET_ACTION_COMMAND, idMenuDataSource_SystemSettings::SYSTEM_FIELD_POSTFX );
control->AddEventAction( WIDGET_EVENT_PRESS ).Set( WIDGET_ACTION_COMMAND, idMenuDataSource_SystemSettings::SYSTEM_FIELD_RENDERMODE );
options->AddChild( control );
control = new( TAG_SWF ) idMenuWidget_ControlButton();
control->SetOptionType( OPTION_SLIDER_BAR );
control->SetLabel( "Ambient Lighting" );
control->SetDescription( "Sets the amount of indirect lighting. Needed for modern PBR reflections" );
control->SetDataSource( &systemData, idMenuDataSource_SystemSettings::SYSTEM_FIELD_AMBIENT_BRIGHTNESS );
control->SetupEvents( 2, options->GetChildren().Num() );
control->AddEventAction( WIDGET_EVENT_PRESS ).Set( WIDGET_ACTION_COMMAND, idMenuDataSource_SystemSettings::SYSTEM_FIELD_AMBIENT_BRIGHTNESS );
options->AddChild( control );
control = new( TAG_SWF ) idMenuWidget_ControlButton();
@ -142,12 +151,19 @@ void idMenuScreen_Shell_SystemOptions::Initialize( idMenuHandler* data )
options->AddChild( control );*/
control = new( TAG_SWF ) idMenuWidget_ControlButton();
control->SetOptionType( OPTION_SLIDER_BAR );
control->SetLabel( "Ambient Lighting" );
control->SetDescription( "Sets the amount of indirect lighting. Needed for modern PBR reflections" );
control->SetDataSource( &systemData, idMenuDataSource_SystemSettings::SYSTEM_FIELD_AMBIENT_BRIGHTNESS );
control->SetupEvents( 2, options->GetChildren().Num() );
control->AddEventAction( WIDGET_EVENT_PRESS ).Set( WIDGET_ACTION_COMMAND, idMenuDataSource_SystemSettings::SYSTEM_FIELD_SSAO );
control->SetOptionType( OPTION_SLIDER_TEXT );
control->SetLabel( "Filmic Post FX" );
control->SetDataSource( &systemData, idMenuDataSource_SystemSettings::SYSTEM_FIELD_FILMIC_POSTFX );
control->SetupEvents( DEFAULT_REPEAT_TIME, options->GetChildren().Num() );
control->AddEventAction( WIDGET_EVENT_PRESS ).Set( WIDGET_ACTION_COMMAND, idMenuDataSource_SystemSettings::SYSTEM_FIELD_FILMIC_POSTFX );
options->AddChild( control );
control = new( TAG_SWF ) idMenuWidget_ControlButton();
control->SetOptionType( OPTION_SLIDER_TEXT );
control->SetLabel( "CRT Filter" );
control->SetDataSource( &systemData, idMenuDataSource_SystemSettings::SYSTEM_FIELD_CRT_POSTFX );
control->SetupEvents( DEFAULT_REPEAT_TIME, options->GetChildren().Num() );
control->AddEventAction( WIDGET_EVENT_PRESS ).Set( WIDGET_ACTION_COMMAND, idMenuDataSource_SystemSettings::SYSTEM_FIELD_CRT_POSTFX );
options->AddChild( control );
// RB end
@ -421,7 +437,7 @@ void idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings::LoadData
//originalShadowMapping = r_useShadowMapping.GetInteger();
originalSSAO = r_useSSAO.GetInteger();
originalAmbientBrightness = r_forceAmbient.GetFloat();
originalPostProcessing = r_useFilmicPostProcessing.GetInteger();
originalPostProcessing = r_useFilmicPostFX.GetInteger();
// RB end
const int fullscreen = r_fullscreen.GetInteger();
@ -593,11 +609,25 @@ void idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings::AdjustFi
break;
}
// RB begin
case SYSTEM_FIELD_POSTFX:
case SYSTEM_FIELD_RENDERMODE:
{
static const int numValues = 8;
static const int values[numValues] = { 0, 1, 2, 3, 4, 5, 6, 7 };
r_renderMode.SetInteger( AdjustOption( r_renderMode.GetInteger(), values, numValues, adjustAmount ) );
break;
}
case SYSTEM_FIELD_FILMIC_POSTFX:
{
static const int numValues = 2;
static const int values[numValues] = { 0, 1 };
r_useFilmicPostProcessing.SetInteger( AdjustOption( r_useFilmicPostProcessing.GetInteger(), values, numValues, adjustAmount ) );
r_useFilmicPostFX.SetInteger( AdjustOption( r_useFilmicPostFX.GetInteger(), values, numValues, adjustAmount ) );
break;
}
case SYSTEM_FIELD_CRT_POSTFX:
{
static const int numValues = 3;
static const int values[numValues] = { 0, 1, 2 };
r_useCRTPostFX.SetInteger( AdjustOption( r_useCRTPostFX.GetInteger(), values, numValues, adjustAmount ) );
break;
}
/*
@ -759,21 +789,27 @@ idSWFScriptVar idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings
return values[ r_antiAliasing.GetInteger() ];
}
case SYSTEM_FIELD_POSTFX:
if( r_useFilmicPostProcessing.GetInteger() > 0 )
case SYSTEM_FIELD_RENDERMODE:
{
static const int numValues = 8;
static const char* values[numValues] =
{
return "#str_swf_enabled";
}
else
{
return "#str_swf_disabled";
}
//return va( "%dx", idMath::IPow( 2, r_motionBlur.GetInteger() ) );
// RB begin
"Doom 3",
"Commodore 64",
"Commodore 64 Hi",
"Amstrad CPC 6128",
"Amstrad CPC 6128 Hi",
"Sega Genesis",
"Sega Genesis Highres",
"Sony PSX",
};
/*
case SYSTEM_FIELD_SHADOWMAPPING:
if( r_useShadowMapping.GetInteger() == 1 )
compile_time_assert( numValues == ( RENDERMODE_PSX + 1 ) );
return values[ r_renderMode.GetInteger() ];
}
case SYSTEM_FIELD_FILMIC_POSTFX:
if( r_useFilmicPostFX.GetInteger() > 0 )
{
return "#str_swf_enabled";
}
@ -781,7 +817,19 @@ idSWFScriptVar idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings
{
return "#str_swf_disabled";
}
*/
case SYSTEM_FIELD_CRT_POSTFX:
{
static const int numValues = 3;
static const char* values[numValues] =
{
"#str_swf_disabled",
"Mattias CRT",
"Newpixie CRT",
};
return values[ r_useCRTPostFX.GetInteger() ];
}
//case SYSTEM_FIELD_LODBIAS:
// return LinearAdjust( r_lodBias.GetFloat(), -1.0f, 1.0f, 0.0f, 100.0f );
@ -798,7 +846,6 @@ idSWFScriptVar idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings
case SYSTEM_FIELD_AMBIENT_BRIGHTNESS:
return LinearAdjust( r_forceAmbient.GetFloat(), 0.0f, 1.0f, 0.0f, 100.0f );
// RB end
case SYSTEM_FIELD_BRIGHTNESS:
return LinearAdjust( r_exposure.GetFloat(), 0.0f, 1.0f, 0.0f, 100.0f );
@ -848,7 +895,7 @@ bool idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings::IsDataCh
return true;
}
if( originalPostProcessing != r_useFilmicPostProcessing.GetInteger() )
if( originalPostProcessing != r_useFilmicPostFX.GetInteger() )
{
return true;
}

View file

@ -315,6 +315,7 @@ void idCommonLocal::TimeRenderDemo( const char* demoName, bool twice, bool quit
while( readDemo )
{
BusyWait(); // SRS - BusyWait() calls UpdateScreen() which draws and renders out-of-sequence but still supports frame timing
commonLocal.frameTiming.finishSyncTime_EndFrame = Sys_Microseconds();
commonLocal.mainFrameTiming = commonLocal.frameTiming;
// ** End of current logical frame **

View file

@ -380,14 +380,26 @@ public:
// RB end
// SRS start
uint64 GetRendererStartFrameSyncMicroseconds() const
void SetRendererMvkEncodeMicroseconds( uint64 mvkEncodeMicroSeconds )
{
return mainFrameTiming.finishSyncTime - mainFrameTiming.startSyncTime;
metal_encode = mvkEncodeMicroSeconds;
return;
}
uint64 GetRendererEndFrameSyncMicroseconds() const
uint64 GetRendererMvkEncodeMicroseconds() const
{
return mainFrameTiming.finishSyncTime_EndFrame - mainFrameTiming.startRenderTime;
return metal_encode;
}
void SetRendererGpuMemoryMB( int gpuMemoryMB )
{
gpu_memory = gpuMemoryMB;
return;
}
int GetRendererGpuMemoryMB() const
{
return gpu_memory;
}
// SRS end
@ -604,6 +616,11 @@ private:
backEndCounters_t stats_backend;
performanceCounters_t stats_frontend;
// SRS - MoltenVK's Vulkan to Metal command buffer encoding time, set default to 0 for non-macOS platforms (Windows and Linux)
uint64 metal_encode = 0;
// SRS - Cross-platform GPU Memory usage counter, set default to 0 in case platform or graphics API does not support queries
int gpu_memory = 0;
// Used during loading screens
int lastPacifierSessionTime;
int lastPacifierGuiTime;

View file

@ -225,8 +225,10 @@ float idConsoleLocal::DrawFPS( float y )
extern idCVar r_swapInterval;
static float previousTimes[FPS_FRAMES];
static float previousCpuUsage[FPS_FRAMES] = {};
static float previousGpuUsage[FPS_FRAMES] = {};
static float previousTimesNormalized[FPS_FRAMES_HISTORY];
static int index;
static int index = 0;
static int previous;
static int valuesOffset = 0;
@ -239,6 +241,8 @@ float idConsoleLocal::DrawFPS( float y )
previous = t;
int fps = 0;
float cpuUsage = 0.0;
float gpuUsage = 0.0;
const float milliSecondsPerFrame = 1000.0f / com_engineHz_latched;
@ -253,6 +257,8 @@ float idConsoleLocal::DrawFPS( float y )
for( int i = 0 ; i < FPS_FRAMES ; i++ )
{
total += previousTimes[i];
cpuUsage += previousCpuUsage[i];
gpuUsage += previousGpuUsage[i];
}
if( !total )
{
@ -260,6 +266,8 @@ float idConsoleLocal::DrawFPS( float y )
}
fps = 1000000 * FPS_FRAMES / total;
fps = ( fps + 500 ) / 1000;
cpuUsage /= FPS_FRAMES;
gpuUsage /= FPS_FRAMES;
const char* s = va( "%ifps", fps );
int w = strlen( s ) * BIGCHAR_WIDTH;
@ -309,12 +317,26 @@ float idConsoleLocal::DrawFPS( float y )
const int64 frameIdleTime = int64( commonLocal.mainFrameTiming.startGameTime ) - int64( commonLocal.mainFrameTiming.finishSyncTime );
const int64 frameBusyTime = int64( commonLocal.frameTiming.finishSyncTime ) - int64( commonLocal.mainFrameTiming.startGameTime );
// SRS - Frame sync time represents swap buffer synchronization + game thread wait + other time spent outside of rendering
const int64 frameSyncTime = int64( commonLocal.frameTiming.finishSyncTime ) - int64( commonLocal.mainFrameTiming.startRenderTime ) - int64( rendererBackEndTime );
// SRS - Frame sync time represents swap buffer synchronization + other frame time spent outside of game thread and renderer backend
const int64 gameThreadWaitTime = int64( commonLocal.mainFrameTiming.finishSyncTime_EndFrame ) - int64( commonLocal.mainFrameTiming.finishRenderTime );
const int64 frameSyncTime = int64( commonLocal.frameTiming.finishSyncTime ) - int64( commonLocal.mainFrameTiming.startRenderTime + rendererBackEndTime ) - gameThreadWaitTime;
// SRS - GPU idle time is simply the difference between measured frame-over-frame time and GPU busy time (directly from GPU timers)
const int64 rendererGPUIdleTime = frameBusyTime + frameIdleTime - rendererGPUTime;
// SRS - Estimate CPU busy time measured from start of game thread until completion of game thread and renderer backend (including excess MoltenVK encoding time if applicable)
#if defined(__APPLE__) && defined( USE_MoltenVK )
const int64 rendererMvkEncodeTime = commonLocal.GetRendererMvkEncodeMicroseconds();
const int64 rendererQueueSubmitTime = int64( commonLocal.mainFrameTiming.finishRenderTime - commonLocal.mainFrameTiming.startRenderTime ) - int64( rendererBackEndTime );
const int64 rendererCPUBusyTime = int64( commonLocal.mainFrameTiming.finishSyncTime_EndFrame - commonLocal.mainFrameTiming.startGameTime ) + Min( Max( int64( 0 ), rendererMvkEncodeTime - rendererQueueSubmitTime - gameThreadWaitTime ), frameSyncTime - rendererQueueSubmitTime );
#else
const int64 rendererCPUBusyTime = int64( commonLocal.mainFrameTiming.finishSyncTime_EndFrame - commonLocal.mainFrameTiming.startGameTime );
#endif
// SRS - Save current CPU and GPU usage factors in ring buffer to calculate smoothed averages for future frames
previousCpuUsage[( index - 1 ) % FPS_FRAMES] = float( rendererCPUBusyTime ) / float( frameBusyTime + frameIdleTime ) * 100.0;
previousGpuUsage[( index - 1 ) % FPS_FRAMES] = float( rendererGPUTime ) / float( rendererGPUTime + rendererGPUIdleTime ) * 100.0;
#if 1
// RB: use ImGui to show more detailed stats about the scene loads
@ -427,7 +449,7 @@ float idConsoleLocal::DrawFPS( float y )
ImGui::TextColored( colorCyan, "API: %s, AA[%i, %i]: %s, %s", API, width, height, aaMode, resolutionText.c_str() );
ImGui::TextColored( colorGold, "Device: %s", deviceManager->GetRendererString() );
ImGui::TextColored( colorGold, "Device: %s, Memory: %i MB", deviceManager->GetRendererString(), commonLocal.GetRendererGpuMemoryMB() );
ImGui::TextColored( colorLtGrey, "GENERAL: views:%i draws:%i tris:%i",
commonLocal.stats_frontend.c_numViews,
@ -477,7 +499,7 @@ float idConsoleLocal::DrawFPS( float y )
if( com_showFPS.GetInteger() > 2 )
{
const char* overlay = va( "Average FPS %i", fps );
const char* overlay = va( "Average FPS %-4i", fps );
ImGui::PlotLines( "Relative\nFrametime ms", previousTimesNormalized, FPS_FRAMES_HISTORY, valuesOffset, overlay, -10.0f, 10.0f, ImVec2( 0, 50 ) );
}
@ -494,12 +516,20 @@ float idConsoleLocal::DrawFPS( float y )
ImGui::TextColored( gameThreadRenderTime > maxTime ? colorRed : colorWhite, "RF: %5llu us SSR: %5llu us", gameThreadRenderTime, rendererGPU_SSRTime );
ImGui::TextColored( rendererBackEndTime > maxTime ? colorRed : colorWhite, "RB: %5llu us Ambient Pass: %5llu us", rendererBackEndTime, rendererGPUAmbientPassTime );
ImGui::TextColored( rendererGPUShadowAtlasTime > maxTime ? colorRed : colorWhite, "Shadows: %5llu us Shadow Atlas: %5llu us", rendererShadowsTime, rendererGPUShadowAtlasTime );
#if defined(__APPLE__) && defined( USE_MoltenVK )
// SRS - For more recent versions of MoltenVK with enhanced performance statistics (v1.2.6 and later), display the Vulkan to Metal encoding thread time on macOS
ImGui::TextColored( rendererMvkEncodeTime > maxTime || rendererGPUInteractionsTime > maxTime ? colorRed : colorWhite, "Encode: %5lld us Interactions: %5llu us", rendererMvkEncodeTime, rendererGPUInteractionsTime );
ImGui::TextColored( rendererGPUShaderPassesTime > maxTime ? colorRed : colorWhite, "Sync: %5lld us Shader Pass: %5llu us", frameSyncTime, rendererGPUShaderPassesTime );
#else
ImGui::TextColored( rendererGPUInteractionsTime > maxTime ? colorRed : colorWhite, "Sync: %5lld us Interactions: %5llu us", frameSyncTime, rendererGPUInteractionsTime );
ImGui::TextColored( rendererGPUShaderPassesTime > maxTime ? colorRed : colorWhite, " Shader Pass: %5llu us", rendererGPUShaderPassesTime );
#endif
ImGui::TextColored( rendererGPU_TAATime > maxTime ? colorRed : colorWhite, " TAA: %5llu us", rendererGPU_TAATime );
ImGui::TextColored( rendererGPUPostProcessingTime > maxTime ? colorRed : colorWhite, " PostFX: %5llu us", rendererGPUPostProcessingTime );
ImGui::TextColored( frameBusyTime > maxTime || rendererGPUTime > maxTime ? colorRed : colorWhite, "Total: %5lld us Total: %5lld us", frameBusyTime, rendererGPUTime );
ImGui::TextColored( colorWhite, "Idle: %5lld us Idle: %5lld us", frameIdleTime, rendererGPUIdleTime );
// SRS - Show CPU and GPU overall usage statistics
//ImGui::TextColored( colorWhite, "Usage: %3.0f %% Usage: %3.0f %%", cpuUsage, gpuUsage );
ImGui::End();
}

View file

@ -398,6 +398,8 @@ void idCommonLocal::Draw()
// draw the half console / notify console on top of everything
console->Draw( false );
renderSystem->DrawCRTPostFX();
}
}
@ -880,13 +882,13 @@ void idCommonLocal::Frame()
}
frameTiming.finishRenderTime = Sys_Microseconds();
// SRS - Use finishSyncTime_EndFrame to record timing just before gameThread.WaitForThread() for com_smp = 1
frameTiming.finishSyncTime_EndFrame = Sys_Microseconds();
// make sure the game / draw thread has completed
// This may block if the game is taking longer than the render back end
gameThread.WaitForThread();
// SRS - Use finishSyncTime_EndFrame to record timing just after gameThread.WaitForThread()
frameTiming.finishSyncTime_EndFrame = Sys_Microseconds();
// Send local usermds to the server.
// This happens after the game frame has run so that prediction data is up to date.
SendUsercmds( Game()->GetLocalClientNum() );

View file

@ -70,5 +70,11 @@
#else
#define OPTICK_ENABLE_GPU_VULKAN (OPTICK_ENABLE_GPU /*&& 0*/)
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Vulkan Functions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if !defined(OPTICK_STATIC_VULKAN_FUNCTIONS)
#define OPTICK_STATIC_VULKAN_FUNCTIONS (0 /*1*/)
#endif
#endif

View file

@ -96,6 +96,7 @@
// Vulkan Forward Declarations
#define OPTICK_DEFINE_HANDLE(object) typedef struct object##_T *object;
OPTICK_DEFINE_HANDLE(VkInstance);
OPTICK_DEFINE_HANDLE(VkDevice);
OPTICK_DEFINE_HANDLE(VkPhysicalDevice);
OPTICK_DEFINE_HANDLE(VkQueue);
@ -125,6 +126,7 @@ struct VkCommandBufferBeginInfo;
#endif
#endif
typedef void* (VKAPI_PTR *PFN_vkGetInstanceProcAddr_)(VkInstance instance, const char* pName);
typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties_)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties);
typedef int32_t (VKAPI_PTR *PFN_vkCreateQueryPool_)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
typedef int32_t (VKAPI_PTR *PFN_vkCreateCommandPool_)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool);
@ -165,6 +167,7 @@ namespace Optick
{
struct OPTICK_API VulkanFunctions
{
PFN_vkGetInstanceProcAddr_ vkGetInstanceProcAddr;
PFN_vkGetPhysicalDeviceProperties_ vkGetPhysicalDeviceProperties;
PFN_vkCreateQueryPool_ vkCreateQueryPool;
PFN_vkCreateCommandPool_ vkCreateCommandPool;
@ -778,7 +781,7 @@ struct OPTICK_API GPUContext
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OPTICK_API void InitGpuD3D12(ID3D12Device* device, ID3D12CommandQueue** cmdQueues, uint32_t numQueues);
OPTICK_API void InitGpuVulkan(VkDevice* vkDevices, VkPhysicalDevice* vkPhysicalDevices, VkQueue* vkQueues, uint32_t* cmdQueuesFamily, uint32_t numQueues, const VulkanFunctions* functions);
OPTICK_API void InitGpuVulkan(VkInstance vkInstance, VkDevice* vkDevices, VkPhysicalDevice* vkPhysicalDevices, VkQueue* vkQueues, uint32_t* cmdQueuesFamily, uint32_t numQueues, const VulkanFunctions* functions);
OPTICK_API void GpuFlip(void* swapChain, uint32_t frameID = 0);
OPTICK_API GPUContext SetGpuContext(GPUContext context);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -1046,7 +1049,7 @@ struct OptickApp
// GPU events
#define OPTICK_GPU_INIT_D3D12(DEVICE, CMD_QUEUES, NUM_CMD_QUEUS) ::Optick::InitGpuD3D12(DEVICE, CMD_QUEUES, NUM_CMD_QUEUS);
#define OPTICK_GPU_INIT_VULKAN(DEVICES, PHYSICAL_DEVICES, CMD_QUEUES, CMD_QUEUES_FAMILY, NUM_CMD_QUEUS, FUNCTIONS) ::Optick::InitGpuVulkan(DEVICES, PHYSICAL_DEVICES, CMD_QUEUES, CMD_QUEUES_FAMILY, NUM_CMD_QUEUS, FUNCTIONS);
#define OPTICK_GPU_INIT_VULKAN(INSTANCE, DEVICES, PHYSICAL_DEVICES, CMD_QUEUES, CMD_QUEUES_FAMILY, NUM_CMD_QUEUS, FUNCTIONS) ::Optick::InitGpuVulkan(INSTANCE, DEVICES, PHYSICAL_DEVICES, CMD_QUEUES, CMD_QUEUES_FAMILY, NUM_CMD_QUEUS, FUNCTIONS);
// Setup GPU context:
// Params:
@ -1121,7 +1124,7 @@ struct OptickApp
#define OPTICK_SET_MEMORY_ALLOCATOR(ALLOCATE_FUNCTION, DEALLOCATE_FUNCTION, INIT_THREAD_CALLBACK)
#define OPTICK_SHUTDOWN()
#define OPTICK_GPU_INIT_D3D12(DEVICE, CMD_QUEUES, NUM_CMD_QUEUS)
#define OPTICK_GPU_INIT_VULKAN(DEVICES, PHYSICAL_DEVICES, CMD_QUEUES, CMD_QUEUES_FAMILY, NUM_CMD_QUEUS, FUNCTIONS)
#define OPTICK_GPU_INIT_VULKAN(INSTANCE, DEVICES, PHYSICAL_DEVICES, CMD_QUEUES, CMD_QUEUES_FAMILY, NUM_CMD_QUEUS, FUNCTIONS)
#define OPTICK_GPU_CONTEXT(...)
#define OPTICK_GPU_EVENT(NAME)
#define OPTICK_GPU_FLIP(...)

View file

@ -33,6 +33,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdexcept>
#if defined(OPTICK_MSVC)
@ -143,11 +144,12 @@ static const ProcessID INVALID_PROCESS_ID = (ProcessID)-1;
#ifdef _DEBUG
#define OPTICK_ASSERT(arg, description) if (!(arg)) { OPTICK_DEBUG_BREAK; }
#define OPTICK_FAILED(description) { OPTICK_DEBUG_BREAK; }
#define OPTICK_VERIFY(arg, description, operation) if (!(arg)) { OPTICK_DEBUG_BREAK; operation; }
#else
#define OPTICK_ASSERT(arg, description)
#define OPTICK_FAILED(description)
#define OPTICK_FAILED(description) { throw std::runtime_error(description); }
#define OPTICK_VERIFY(arg, description, operation) if (!(arg)) { OPTICK_FAILED(description); operation; }
#endif
#define OPTICK_VERIFY(arg, description, operation) if (!(arg)) { OPTICK_DEBUG_BREAK; operation; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -71,7 +71,7 @@ namespace Optick
GPUProfilerVulkan();
~GPUProfilerVulkan();
void InitDevice(VkDevice* devices, VkPhysicalDevice* physicalDevices, VkQueue* cmdQueues, uint32_t* cmdQueuesFamily, uint32_t nodeCount, const VulkanFunctions* functions);
void InitDevice(VkInstance instance, VkDevice* devices, VkPhysicalDevice* physicalDevices, VkQueue* cmdQueues, uint32_t* cmdQueuesFamily, uint32_t nodeCount, const VulkanFunctions* functions);
void QueryTimestamp(VkCommandBuffer commandBuffer, int64_t* outCpuTimestamp);
void Flip(VkSwapchainKHR swapChain);
@ -94,10 +94,10 @@ namespace Optick
}
};
void InitGpuVulkan(VkDevice* vkDevices, VkPhysicalDevice* vkPhysicalDevices, VkQueue* vkQueues, uint32_t* cmdQueuesFamily, uint32_t numQueues, const VulkanFunctions* functions)
void InitGpuVulkan(VkInstance vkInstance, VkDevice* vkDevices, VkPhysicalDevice* vkPhysicalDevices, VkQueue* vkQueues, uint32_t* cmdQueuesFamily, uint32_t numQueues, const VulkanFunctions* functions)
{
GPUProfilerVulkan* gpuProfiler = Memory::New<GPUProfilerVulkan>();
gpuProfiler->InitDevice(vkDevices, vkPhysicalDevices, vkQueues, cmdQueuesFamily, numQueues, functions);
gpuProfiler->InitDevice(vkInstance, vkDevices, vkPhysicalDevices, vkQueues, cmdQueuesFamily, numQueues, functions);
Core::Get().InitGPUProfiler(gpuProfiler);
}
@ -107,15 +107,17 @@ namespace Optick
prevPresentID = 0;
}
void GPUProfilerVulkan::InitDevice(VkDevice* devices, VkPhysicalDevice* physicalDevices, VkQueue* cmdQueues, uint32_t* cmdQueuesFamily, uint32_t nodeCount, const VulkanFunctions* functions)
void GPUProfilerVulkan::InitDevice(VkInstance instance, VkDevice* devices, VkPhysicalDevice* physicalDevices, VkQueue* cmdQueues, uint32_t* cmdQueuesFamily, uint32_t nodeCount, const VulkanFunctions* functions)
{
if (functions != nullptr)
{
vulkanFunctions = *functions;
}
else
else
{
#if OPTICK_STATIC_VULKAN_FUNCTIONS
vulkanFunctions = {
nullptr, // don't define vkGetInstanceProcAddr if vulkan functions are static
vkGetPhysicalDeviceProperties,
(PFN_vkCreateQueryPool_)vkCreateQueryPool,
(PFN_vkCreateCommandPool_)vkCreateCommandPool,
@ -142,6 +144,23 @@ namespace Optick
vkFreeCommandBuffers,
nullptr, // dynamically define vkGetPastPresentationTimingGOOGLE if VK_GOOGLE_display_timing extension available
};
#else
OPTICK_FAILED("Either set OPTICK_STATIC_VULKAN_FUNCTIONS = 1 or VulkanFunctions must be defined! Can't initialize GPU Profiler!");
#endif
}
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr_ = nullptr;
if (vulkanFunctions.vkGetInstanceProcAddr)
{
if (instance)
{
vkGetDeviceProcAddr_ = (PFN_vkGetDeviceProcAddr)(*vulkanFunctions.vkGetInstanceProcAddr)(instance, "vkGetDeviceProcAddr");
vulkanFunctions.vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties_)(*vulkanFunctions.vkGetInstanceProcAddr)(instance, "vkGetPhysicalDeviceProperties");
}
else
{
OPTICK_FAILED("VkInstance must be defined if VulkanFunctions::vkGetInstanceProcAddr is defined! Can't initialize GPU Profiler!");
}
}
VkQueryPoolCreateInfo queryPoolCreateInfo;
@ -168,6 +187,40 @@ namespace Optick
VkResult r;
for (uint32_t i = 0; i < nodeCount; ++i)
{
if (vkGetDeviceProcAddr_)
{
vulkanFunctions.vkCreateQueryPool = (PFN_vkCreateQueryPool_)vkGetDeviceProcAddr_(devices[i], "vkCreateQueryPool");
vulkanFunctions.vkCreateCommandPool = (PFN_vkCreateCommandPool_)vkGetDeviceProcAddr_(devices[i], "vkCreateCommandPool");
vulkanFunctions.vkCreateEvent = (PFN_vkCreateEvent_)vkGetDeviceProcAddr_(devices[i], "vkCreateEvent");
vulkanFunctions.vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers_)vkGetDeviceProcAddr_(devices[i], "vkAllocateCommandBuffers");
vulkanFunctions.vkCreateFence = (PFN_vkCreateFence_)vkGetDeviceProcAddr_(devices[i], "vkCreateFence");
vulkanFunctions.vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool_)vkGetDeviceProcAddr_(devices[i], "vkCmdResetQueryPool");
vulkanFunctions.vkResetQueryPool = (PFN_vkResetQueryPool_)vkGetDeviceProcAddr_(devices[i], "vkResetQueryPool");
vulkanFunctions.vkCmdWaitEvents = (PFN_vkCmdWaitEvents_)vkGetDeviceProcAddr_(devices[i], "vkCmdWaitEvents");
vulkanFunctions.vkResetEvent = (PFN_vkResetEvent_)vkGetDeviceProcAddr_(devices[i], "vkResetEvent");
vulkanFunctions.vkSetEvent = (PFN_vkSetEvent_)vkGetDeviceProcAddr_(devices[i], "vkSetEvent");
vulkanFunctions.vkQueueSubmit = (PFN_vkQueueSubmit_)vkGetDeviceProcAddr_(devices[i], "vkQueueSubmit");
vulkanFunctions.vkWaitForFences = (PFN_vkWaitForFences_)vkGetDeviceProcAddr_(devices[i], "vkWaitForFences");
vulkanFunctions.vkResetCommandBuffer = (PFN_vkResetCommandBuffer_)vkGetDeviceProcAddr_(devices[i], "vkResetCommandBuffer");
vulkanFunctions.vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp_)vkGetDeviceProcAddr_(devices[i], "vkCmdWriteTimestamp");
vulkanFunctions.vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults_)vkGetDeviceProcAddr_(devices[i], "vkGetQueryPoolResults");
vulkanFunctions.vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer_)vkGetDeviceProcAddr_(devices[i], "vkBeginCommandBuffer");
vulkanFunctions.vkEndCommandBuffer = (PFN_vkEndCommandBuffer_)vkGetDeviceProcAddr_(devices[i], "vkEndCommandBuffer");
vulkanFunctions.vkResetFences = (PFN_vkResetFences_)vkGetDeviceProcAddr_(devices[i], "vkResetFences");
vulkanFunctions.vkDestroyCommandPool = (PFN_vkDestroyCommandPool_)vkGetDeviceProcAddr_(devices[i], "vkDestroyCommandPool");
vulkanFunctions.vkDestroyQueryPool = (PFN_vkDestroyQueryPool_)vkGetDeviceProcAddr_(devices[i], "vkDestroyQueryPool");
vulkanFunctions.vkDestroyEvent = (PFN_vkDestroyEvent_)vkGetDeviceProcAddr_(devices[i], "vkDestroyEvent");
vulkanFunctions.vkDestroyFence = (PFN_vkDestroyFence_)vkGetDeviceProcAddr_(devices[i], "vkDestroyFence");
vulkanFunctions.vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers_)vkGetDeviceProcAddr_(devices[i], "vkFreeCommandBuffers");
vulkanFunctions.vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE_)vkGetDeviceProcAddr_(devices[i], "vkGetPastPresentationTimingGOOGLE");
}
#if OPTICK_STATIC_VULKAN_FUNCTIONS
else if (!vulkanFunctions.vkGetPastPresentationTimingGOOGLE)
{
vulkanFunctions.vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE_)vkGetDeviceProcAddr(devices[i], "vkGetPastPresentationTimingGOOGLE");
}
#endif
VkPhysicalDeviceProperties properties = { 0 };
(*vulkanFunctions.vkGetPhysicalDeviceProperties)(physicalDevices[i], &properties);
GPUProfiler::InitNode(properties.deviceName, i);
@ -175,7 +228,6 @@ namespace Optick
NodePayload* nodePayload = Memory::New<NodePayload>();
nodePayloads[i] = nodePayload;
nodePayload->vulkanFunctions = &vulkanFunctions;
nodePayload->vulkanFunctions->vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE_)vkGetDeviceProcAddr(devices[i], "vkGetPastPresentationTimingGOOGLE");
nodePayload->device = devices[i];
nodePayload->physicalDevice = physicalDevices[i];
nodePayload->queue = cmdQueues[i];
@ -498,7 +550,7 @@ namespace Optick
#include "optick_common.h"
namespace Optick
{
void InitGpuVulkan(VkDevice* /*vkDevices*/, VkPhysicalDevice* /*vkPhysicalDevices*/, VkQueue* /*vkQueues*/, uint32_t* /*cmdQueuesFamily*/, uint32_t /*numQueues*/, const VulkanFunctions* /*functions*/)
void InitGpuVulkan(VkInstance /*vkInstance*/, VkDevice* /*vkDevices*/, VkPhysicalDevice* /*vkPhysicalDevices*/, VkQueue* /*vkQueues*/, uint32_t* /*cmdQueuesFamily*/, uint32_t /*numQueues*/, const VulkanFunctions* /*functions*/)
{
OPTICK_FAILED("OPTICK_ENABLE_GPU_VULKAN is disabled! Can't initialize GPU Profiler!");
}

View file

@ -289,7 +289,7 @@ Server::Server(short port) : socket(Memory::New<Socket>()), saveCb(nullptr)
{
if (!socket->Bind(port, 4))
{
OPTICK_FAILED("Failed to bind a socket! Most probably the port is blocked by anti-virus! Change the port and verify that your game has enough permissions to communicate over the TCP\IP.");
OPTICK_FAILED("Failed to bind a socket! Most probably the port is blocked by anti-virus! Change the port and verify that your game has enough permissions to communicate over the TCP/IP.");
}
else
{
@ -499,4 +499,4 @@ Server & Server::Get()
}
#endif //USE_OPTICK
#endif //USE_OPTICK

View file

@ -46,7 +46,6 @@ If you have questions concerning this license or the applicable additional terms
#include "../libs/mesa/format_r11g11b10f.h"
idCVar image_highQualityCompression( "image_highQualityCompression", "0", CVAR_BOOL, "Use high quality (slow) compression" );
idCVar r_useHighQualitySky( "r_useHighQualitySky", "1", CVAR_BOOL | CVAR_ARCHIVE, "Use high quality skyboxes" );
/*
========================

View file

@ -459,15 +459,7 @@ public:
return ( void* )texture.Get();
}
void* GetSampler( SamplerCache& samplerCache )
{
if( !sampler )
{
sampler = samplerCache.GetOrCreateSampler( samplerDesc );
}
return ( void* )sampler.Get();
}
void* GetSampler( SamplerCache& samplerCache );
void* GetSampler( nvrhi::IDevice* device )
{

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2021 Robert Beckebans
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").
@ -1148,3 +1148,209 @@ void idImageManager::CreateIntrinsicImages()
release_assert( loadingIconImage->referencedOutsideLevelLoad );
release_assert( hellLoadingIconImage->referencedOutsideLevelLoad );
}
CONSOLE_COMMAND( makeImageHeader, "load an image and turn it into a .h file", NULL )
{
byte* buffer;
int width = 0, height = 0;
if( args.Argc() < 2 )
{
common->Printf( "USAGE: makeImageHeader filename [exportname]\n" );
return;
}
idStr filename = args.Argv( 1 );
R_LoadImage( filename, &buffer, &width, &height, NULL, true, NULL );
if( !buffer )
{
common->Printf( "loading %s failed.\n", filename.c_str() );
return;
}
filename.StripFileExtension();
idStr exportname;
if( args.Argc() == 3 )
{
exportname.Format( "Image_%s.h", args.Argv( 2 ) );
}
else
{
exportname.Format( "Image_%s.h", filename.c_str() );
}
for( int i = 0; i < exportname.Length(); i++ )
{
if( exportname[ i ] == '/' )
{
exportname[ i ] = '_';
}
}
idFileLocal headerFile( fileSystem->OpenFileWrite( exportname, "fs_basepath" ) );
idStr uppername = exportname;
uppername.ToUpper();
for( int i = 0; i < uppername.Length(); i++ )
{
if( uppername[ i ] == '.' )
{
uppername[ i ] = '_';
}
}
headerFile->Printf( "#ifndef %s_TEX_H\n", uppername.c_str() );
headerFile->Printf( "#define %s_TEX_H\n\n", uppername.c_str() );
headerFile->Printf( "#define %s_TEX_WIDTH %i\n", uppername.c_str(), width );
headerFile->Printf( "#define %s_TEX_HEIGHT %i\n\n", uppername.c_str(), height );
headerFile->Printf( "static const unsigned char %s_Bytes[] = {\n", uppername.c_str() );
int bufferSize = width * height * 4;
for( int i = 0; i < bufferSize; i++ )
{
byte b = buffer[i];
if( i < ( bufferSize - 1 ) )
{
headerFile->Printf( "0x%02hhx, ", b );
}
else
{
headerFile->Printf( "0x%02hhx", b );
}
if( i % 12 == 0 )
{
headerFile->Printf( "\n" );
}
}
headerFile->Printf( "\n};\n#endif\n" );
Mem_Free( buffer );
}
CONSOLE_COMMAND( makePaletteHeader, "load a .pal palette, build an image from it and turn it into a .h file", NULL )
{
if( args.Argc() < 2 )
{
common->Printf( "USAGE: makePaletteHeader filename [exportname]\n" );
return;
}
idStr filename = args.Argv( 1 );
filename.DefaultFileExtension( ".pal" );
ID_TIME_T timeStamp;
char* palBuffer;
int palBufferLen = fileSystem->ReadFile( filename, ( void** )&palBuffer, &timeStamp );
if( palBufferLen <= 0 || palBuffer == nullptr )
{
return;
}
// parse JASC-PAL file
idLexer src;
idToken token, token2;
src.LoadMemory( palBuffer, palBufferLen, filename, 0 );
src.ExpectTokenString( "JASC" );
src.ExpectTokenString( "-" );
src.ExpectTokenString( "PAL" );
int palVersion = src.ParseInt();
int numColors = src.ParseInt();
//idList<id
byte rgb[3];
for( int i = 0; i < numColors; i++ )
{
rgb[0] = src.ParseInt();
rgb[1] = src.ParseInt();
rgb[2] = src.ParseInt();
idLib::Printf( "RGB( %d, %d, %d ),\n", rgb[0], rgb[1], rgb[2] );
}
fileSystem->FreeFile( palBuffer );
filename.StripFileExtension();
// TODO build image and convert to header
//byte* buffer;
//int width = 0, height = 0;
/*
idStr exportname;
if( args.Argc() == 3 )
{
exportname.Format( "Image_%s.h", args.Argv( 2 ) );
}
else
{
exportname.Format( "Image_%s.h", filename.c_str() );
}
for( int i = 0; i < exportname.Length(); i++ )
{
if( exportname[ i ] == '/' )
{
exportname[ i ] = '_';
}
}
idFileLocal headerFile( fileSystem->OpenFileWrite( exportname, "fs_basepath" ) );
idStr uppername = exportname;
uppername.ToUpper();
for( int i = 0; i < uppername.Length(); i++ )
{
if( uppername[ i ] == '.' )
{
uppername[ i ] = '_';
}
}
headerFile->Printf( "#ifndef %s_TEX_H\n", uppername.c_str() );
headerFile->Printf( "#define %s_TEX_H\n\n", uppername.c_str() );
headerFile->Printf( "#define %s_TEX_WIDTH %i\n", uppername.c_str(), width );
headerFile->Printf( "#define %s_TEX_HEIGHT %i\n\n", uppername.c_str(), height );
headerFile->Printf( "static const unsigned char %s_Bytes[] = {\n", uppername.c_str() );
int bufferSize = width * height * 4;
for( int i = 0; i < bufferSize; i++ )
{
byte b = buffer[i];
if( i < ( bufferSize - 1 ) )
{
headerFile->Printf( "0x%02hhx, ", b );
}
else
{
headerFile->Printf( "0x%02hhx", b );
}
if( i % 12 == 0 )
{
headerFile->Printf( "\n" );
}
}
headerFile->Printf( "\n};\n#endif\n" );
Mem_Free( buffer );
*/
}

View file

@ -73,8 +73,6 @@ typedef struct mtrParsingData_s
bool forceOverlays;
} mtrParsingData_t;
extern idCVar r_useHighQualitySky;
idCVar r_forceSoundOpAmplitude( "r_forceSoundOpAmplitude", "0", CVAR_FLOAT, "Don't call into the sound system for amplitudes" );
/*
@ -1870,14 +1868,7 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
}
if( !token.Icmp( "uncompressedCubeMap" ) )
{
if( r_useHighQualitySky.GetBool() )
{
td = TD_HIGHQUALITY_CUBE; // motorsep 05-17-2015; token to mark cubemap/skybox to be uncompressed texture
}
else
{
td = TD_LOWQUALITY_CUBE;
}
td = TD_HIGHQUALITY_CUBE; // motorsep 05-17-2015; token to mark cubemap/skybox to be uncompressed texture
continue;
}
if( !token.Icmp( "nopicmip" ) )

View file

@ -44,7 +44,7 @@ static const char* MD5_SnapshotName = "_MD5_Snapshot_";
static const byte MD5B_VERSION = 106;
static const unsigned int MD5B_MAGIC = ( '5' << 24 ) | ( 'D' << 16 ) | ( 'M' << 8 ) | MD5B_VERSION;
idCVar r_useGPUSkinning( "r_useGPUSkinning", "1", CVAR_INTEGER, "animate normals and tangents instead of deriving" );
idCVar r_useGPUSkinning( "r_useGPUSkinning", "1", CVAR_INTEGER | CVAR_NOCHEAT, "animate normals and tangents instead of deriving" );
/***********************************************************************

View file

@ -729,9 +729,13 @@ bool idUniformBuffer::AllocBufferObject( const void* data, int allocSize, buffer
// This buffer is a shader resource as opposed to a constant buffer due to
// constant buffers not being able to be sub-ranged.
nvrhi::BufferDesc bufferDesc;
//bufferDesc.initialState = nvrhi::ResourceStates::ConstantBuffer; // SRS - shouldn't this be initialized to CopyDest?
bufferDesc.initialState = nvrhi::ResourceStates::CopyDest;
bufferDesc.canHaveTypedViews = true;
bufferDesc.canHaveRawViews = true;
bufferDesc.byteSize = numBytes;
bufferDesc.structStride = sizeof( idVec4 ); // SRS - this defines a structured storage buffer vs. a constant buffer
bufferDesc.initialState = nvrhi::ResourceStates::Common;
bufferDesc.structStride = sizeof( idVec4 );
bufferDesc.isConstantBuffer = true;
if( usage == BU_DYNAMIC )
{

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2022 Robert Beckebans
Copyright (C) 2013-2023 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").
@ -30,11 +30,7 @@ If you have questions concerning this license or the applicable additional terms
#include "precompiled.h"
#pragma hdrstop
/*
================================================================================================
Contains the Image implementation for OpenGL.
================================================================================================
*/
idCVar image_pixelLook( "image_pixelLook", "0", CVAR_BOOL | CVAR_ARCHIVE, "Turn off linear filtering on most textures to achieve the 90s software renderer look" );
#include "../RenderCommon.h"
@ -296,6 +292,36 @@ void idImage::SetTexParameters()
{
}
/*
========================
idImage::GetSampler
========================
*/
void* idImage::GetSampler( SamplerCache& samplerCache )
{
if( R_UsePixelatedLook() )
{
if( !sampler )
{
nvrhi::SamplerDesc sampDesc = samplerDesc;
// turn off linear filtering
sampDesc.setAllFilters( false );
sampler = samplerCache.GetOrCreateSampler( samplerDesc );
}
}
else
{
if( !sampler )
{
sampler = samplerCache.GetOrCreateSampler( samplerDesc );
}
}
return ( void* )sampler.Get();
}
/*
========================
idImage::AllocImage

View file

@ -733,18 +733,37 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
desc[2].bindings[5].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 10 )->GetTextureID();
}
if( desc[3].bindings.empty() )
if( R_UsePixelatedLook() )
{
desc[3].bindings =
if( desc[3].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearClampSampler )
};
desc[3].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearClampSampler )
};
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearClampSampler;
}
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearClampSampler;
if( desc[3].bindings.empty() )
{
desc[3].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearClampSampler )
};
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearClampSampler;
}
}
}
else if( type == BINDING_LAYOUT_AMBIENT_LIGHTING_IBL_SKINNED )
@ -804,18 +823,37 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
desc[2].bindings[5].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 10 )->GetTextureID();
}
if( desc[3].bindings.empty() )
if( R_UsePixelatedLook() )
{
desc[3].bindings =
if( desc[3].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearClampSampler )
};
desc[3].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearClampSampler )
};
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearClampSampler;
}
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearClampSampler;
if( desc[3].bindings.empty() )
{
desc[3].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearClampSampler )
};
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearClampSampler;
}
}
}
else if( type == BINDING_LAYOUT_DRAW_AO )
@ -900,18 +938,37 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
}
// samplers: 3
if( desc[3].bindings.empty() )
if( R_UsePixelatedLook() )
{
desc[3].bindings =
if( desc[3].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler )
};
desc[3].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler )
};
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
}
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
if( desc[3].bindings.empty() )
{
desc[3].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler )
};
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
}
}
}
else if( type == BINDING_LAYOUT_DRAW_INTERACTION_SKINNED )
@ -967,18 +1024,37 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
}
// samplers: 3
if( desc[3].bindings.empty() )
if( R_UsePixelatedLook() )
{
desc[3].bindings =
if( desc[3].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler )
};
desc[3].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler )
};
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
}
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
if( desc[3].bindings.empty() )
{
desc[3].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler )
};
}
else
{
desc[3].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
desc[3].bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
}
}
}
else if( type == BINDING_LAYOUT_DRAW_INTERACTION_SM )
@ -1037,24 +1113,49 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
}
// samplers: 3
if( desc[3].bindings.empty() )
if( R_UsePixelatedLook() )
{
auto& bindings = desc[3].bindings;
bindings =
if( desc[3].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler ),
nvrhi::BindingSetItem::Sampler( 2, commonPasses.m_LinearClampCompareSampler ),
nvrhi::BindingSetItem::Sampler( 3, commonPasses.m_PointWrapSampler ) // blue noise
};
auto& bindings = desc[3].bindings;
bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler ),
nvrhi::BindingSetItem::Sampler( 2, commonPasses.m_LinearClampCompareSampler ),
nvrhi::BindingSetItem::Sampler( 3, commonPasses.m_PointWrapSampler ) // blue noise
};
}
else
{
auto& bindings = desc[3].bindings;
bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
bindings[2].resourceHandle = commonPasses.m_LinearClampCompareSampler;
bindings[3].resourceHandle = commonPasses.m_PointWrapSampler;
}
}
else
{
auto& bindings = desc[3].bindings;
bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
bindings[2].resourceHandle = commonPasses.m_LinearClampCompareSampler;
bindings[3].resourceHandle = commonPasses.m_PointWrapSampler;
if( desc[3].bindings.empty() )
{
auto& bindings = desc[3].bindings;
bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler ),
nvrhi::BindingSetItem::Sampler( 2, commonPasses.m_LinearClampCompareSampler ),
nvrhi::BindingSetItem::Sampler( 3, commonPasses.m_PointWrapSampler ) // blue noise
};
}
else
{
auto& bindings = desc[3].bindings;
bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
bindings[2].resourceHandle = commonPasses.m_LinearClampCompareSampler;
bindings[3].resourceHandle = commonPasses.m_PointWrapSampler;
}
}
}
else if( type == BINDING_LAYOUT_DRAW_INTERACTION_SM_SKINNED )
@ -1117,24 +1218,49 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
}
// samplers: 3
if( desc[3].bindings.empty() )
if( R_UsePixelatedLook() )
{
auto& bindings = desc[3].bindings;
bindings =
if( desc[3].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler ),
nvrhi::BindingSetItem::Sampler( 2, commonPasses.m_LinearClampCompareSampler ),
nvrhi::BindingSetItem::Sampler( 3, commonPasses.m_PointWrapSampler ) // blue noise
};
auto& bindings = desc[3].bindings;
bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler ),
nvrhi::BindingSetItem::Sampler( 2, commonPasses.m_LinearClampCompareSampler ),
nvrhi::BindingSetItem::Sampler( 3, commonPasses.m_PointWrapSampler ) // blue noise
};
}
else
{
auto& bindings = desc[3].bindings;
bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
bindings[2].resourceHandle = commonPasses.m_LinearClampCompareSampler;
bindings[3].resourceHandle = commonPasses.m_PointWrapSampler;
}
}
else
{
auto& bindings = desc[3].bindings;
bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
bindings[2].resourceHandle = commonPasses.m_LinearClampCompareSampler;
bindings[3].resourceHandle = commonPasses.m_PointWrapSampler;
if( desc[3].bindings.empty() )
{
auto& bindings = desc[3].bindings;
bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler ),
nvrhi::BindingSetItem::Sampler( 2, commonPasses.m_LinearClampCompareSampler ),
nvrhi::BindingSetItem::Sampler( 3, commonPasses.m_PointWrapSampler ) // blue noise
};
}
else
{
auto& bindings = desc[3].bindings;
bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
bindings[2].resourceHandle = commonPasses.m_LinearClampCompareSampler;
bindings[3].resourceHandle = commonPasses.m_PointWrapSampler;
}
}
}
else if( type == BINDING_LAYOUT_FOG )
@ -1340,16 +1466,33 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
desc[0].bindings[3].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 2 )->GetTextureID();
}
if( desc[1].bindings.empty() )
if( R_UsePixelatedLook() )
{
desc[1].bindings =
if( desc[1].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearClampSampler )
};
desc[1].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointClampSampler )
};
}
else
{
desc[1].bindings[0].resourceHandle = commonPasses.m_PointClampSampler;
}
}
else
{
desc[1].bindings[0].resourceHandle = commonPasses.m_LinearClampSampler;
if( desc[1].bindings.empty() )
{
desc[1].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearClampSampler )
};
}
else
{
desc[1].bindings[0].resourceHandle = commonPasses.m_LinearClampSampler;
}
}
}
else if( type == BINDING_LAYOUT_POST_PROCESS_FINAL )
@ -1415,16 +1558,33 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
bindings[1].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID();
}
if( desc[2].bindings.empty() )
if( R_UsePixelatedLook() )
{
desc[2].bindings =
if( desc[2].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearWrapSampler )
};
desc[2].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler )
};
}
else
{
desc[2].bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
}
}
else
{
desc[2].bindings[0].resourceHandle = commonPasses.m_LinearWrapSampler;
if( desc[2].bindings.empty() )
{
desc[2].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearWrapSampler )
};
}
else
{
desc[2].bindings[0].resourceHandle = commonPasses.m_LinearWrapSampler;
}
}
}
else if( type == BINDING_LAYOUT_NORMAL_CUBE_SKINNED )
@ -1462,16 +1622,33 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
bindings[1].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID();
}
if( desc[2].bindings.empty() )
if( R_UsePixelatedLook() )
{
desc[2].bindings =
if( desc[2].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearWrapSampler )
};
desc[2].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler )
};
}
else
{
desc[2].bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
}
}
else
{
desc[2].bindings[0].resourceHandle = commonPasses.m_LinearWrapSampler;
if( desc[2].bindings.empty() )
{
desc[2].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearWrapSampler )
};
}
else
{
desc[2].bindings[0].resourceHandle = commonPasses.m_LinearWrapSampler;
}
}
}
else if( type == BINDING_LAYOUT_BINK_VIDEO )
@ -1495,16 +1672,33 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
desc[0].bindings[3].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 2 )->GetTextureID();
}
if( desc[1].bindings.empty() )
if( R_UsePixelatedLook() )
{
desc[1].bindings =
if( desc[1].bindings.empty() )
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearWrapSampler )
};
desc[1].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler )
};
}
else
{
desc[1].bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
}
}
else
{
desc[1].bindings[0].resourceHandle = commonPasses.m_LinearWrapSampler;
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 )
@ -1597,11 +1791,12 @@ void idRenderBackend::GL_EndFrame()
commandList->close();
deviceManager->GetDevice()->executeCommandList( commandList );
// required for Vulkan: transition our swap image to present
deviceManager->EndFrame();
// SRS - execute after EndFrame() to avoid need for barrier command list on Vulkan
deviceManager->GetDevice()->executeCommandList( commandList );
// update jitter for perspective matrix
taaPass->AdvanceFrame();
}
@ -1830,7 +2025,7 @@ See if some cvars that we watch have changed
*/
void idRenderBackend::CheckCVars()
{
// gamma stuff
// TODO remove, gamma stuff doesn't work and isn't used using the latest Nvidia drivers
if( r_gamma.IsModified() || r_brightness.IsModified() )
{
r_gamma.ClearModified();
@ -1845,56 +2040,14 @@ void idRenderBackend::CheckCVars()
deviceManager->SetVsyncEnabled( r_swapInterval.GetInteger() );
}
// filtering
/*if( r_maxAnisotropicFiltering.IsModified() || r_useTrilinearFiltering.IsModified() || r_lodBias.IsModified() )
// retro rendering
if( r_renderMode.IsModified() )
{
idLib::Printf( "Updating texture filter parameters.\n" );
r_maxAnisotropicFiltering.ClearModified();
r_useTrilinearFiltering.ClearModified();
r_lodBias.ClearModified();
r_renderMode.ClearModified();
for( int i = 0; i < globalImages->images.Num(); i++ )
{
if( globalImages->images[i] )
{
globalImages->images[i]->Bind();
globalImages->images[i]->SetTexParameters();
}
}
}*/
#if 0
if( r_antiAliasing.IsModified() )
{
switch( r_antiAliasing.GetInteger() )
{
case ANTI_ALIASING_MSAA_2X:
case ANTI_ALIASING_MSAA_4X:
if( r_antiAliasing.GetInteger() > 0 )
{
//glEnable( GL_MULTISAMPLE );
}
break;
default:
//glDisable( GL_MULTISAMPLE );
break;
}
if( tr.IsInitialized() )
{
Framebuffer::ResizeFramebuffers();
}
if( taaPass )
{
delete taaPass;
taaPass = NULL;
}
r_antiAliasing.ClearModified();
// clear caches because PSX rendering will use nearest texture filtering instead of linear
ClearCaches();
}
#endif
}
/*

View file

@ -362,7 +362,7 @@ bool idRenderProgManager::CommitConstantBuffer( nvrhi::ICommandList* commandList
// The vkDoom3 backend even didn't bother with this and always fired the uniforms for each draw call.
if( uniformsChanged || bindingLayoutTypeChanged )
{
commandList->writeBuffer( constantBuffer[BindingLayoutType()], uniforms.Ptr(), uniforms.Allocated() );
commandList->writeBuffer( constantBuffer /*[BindingLayoutType()]*/, uniforms.Ptr(), uniforms.Allocated() );
uniformsChanged = false;

View file

@ -254,8 +254,8 @@ void SsaoPass::Render(
quarterResExtent.maxY = ( quarterResExtent.maxY + 3 ) / 4;
// TODO required and remove this by fixing the shaders
// because they include #include <global_inc.hlsl>
renderProgManager.BindShader_TextureVertexColor();
renderProgManager.CommitConstantBuffer( commandList, true );
SsaoConstants ssaoConstants = {};

View file

@ -2172,11 +2172,11 @@ void idRenderBackend::AmbientPass( const drawSurf_t* const* drawSurfs, int numDr
specularColor = lightColor;// * 0.5f;
float ambientBoost = 1.0f;
if( !r_usePBR.GetBool() )
{
ambientBoost += r_useSSAO.GetBool() ? 0.2f : 0.0f;
ambientBoost *= 1.1f;
}
//if( !r_usePBR.GetBool() )
//{
// ambientBoost += r_useSSAO.GetBool() ? 0.2f : 0.0f;
// ambientBoost *= 1.1f;
//}
ambientColor.x = r_forceAmbient.GetFloat() * ambientBoost;
ambientColor.y = r_forceAmbient.GetFloat() * ambientBoost;
@ -2186,7 +2186,7 @@ void idRenderBackend::AmbientPass( const drawSurf_t* const* drawSurfs, int numDr
renderProgManager.SetRenderParm( RENDERPARM_AMBIENT_COLOR, ambientColor.ToFloatPtr() );
bool useIBL = r_usePBR.GetBool() && !fillGbuffer;
bool useIBL = !fillGbuffer;
// setup renderparms assuming we will be drawing trivial surfaces first
RB_SetupForFastPathInteractions( diffuseColor, specularColor );
@ -5374,6 +5374,10 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
break;
}
case RC_CRT_POST_PROCESS:
CRTPostProcess();
break;
default:
common->Error( "RB_ExecuteBackEndCommands: bad commandId" );
break;
@ -5382,12 +5386,13 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
DrawFlickerBox();
GL_EndFrame();
// stop rendering on this thread
uint64 backEndFinishTime = Sys_Microseconds();
pc.cpuTotalMicroSec = backEndFinishTime - backEndStartTime;
// SRS - capture backend timing before GL_EndFrame() since it can block when r_mvkSynchronousQueueSubmits is enabled on macOS/MoltenVK
GL_EndFrame();
if( r_debugRenderToTexture.GetInteger() == 1 )
{
common->Printf( "3d: %i, 2d: %i, SetBuf: %i, CpyRenders: %i, CpyFrameBuf: %i\n", c_draw3d, c_draw2d, c_setBuffers, c_copyRenders, pc.c_copyFrameBuffer );
@ -5976,15 +5981,6 @@ idRenderBackend::PostProcess
extern idCVar rs_enable;
void idRenderBackend::PostProcess( const void* data )
{
// only do the post process step if resolution scaling is enabled. Prevents the unnecessary copying of the framebuffer and
// corresponding full screen quad pass.
/*
if( rs_enable.GetInteger() == 0 && !r_useFilmicPostProcessing.GetBool() && r_antiAliasing.GetInteger() == 0 )
{
return;
}
*/
if( viewDef->renderView.rdflags & RDF_IRRADIANCE )
{
#if defined( USE_NVRHI )
@ -6102,7 +6098,7 @@ void idRenderBackend::PostProcess( const void* data )
}
#endif
if( r_useFilmicPostProcessing.GetBool() )
if( r_useFilmicPostFX.GetBool() || r_renderMode.GetInteger() > 0 )
{
BlitParameters blitParms;
blitParms.sourceTexture = ( nvrhi::ITexture* )globalImages->ldrImage->GetTextureID();
@ -6119,7 +6115,37 @@ void idRenderBackend::PostProcess( const void* data )
GL_SelectTexture( 1 );
globalImages->blueNoiseImage256->Bind();
renderProgManager.BindShader_PostProcess();
float jitterTexScale[4] = {};
if( r_renderMode.GetInteger() == RENDERMODE_C64 || r_renderMode.GetInteger() == RENDERMODE_C64_HIGHRES )
{
jitterTexScale[0] = r_renderMode.GetInteger() == RENDERMODE_C64_HIGHRES ? 2.0 : 1.0;
renderProgManager.BindShader_PostProcess_RetroC64();
}
else if( r_renderMode.GetInteger() == RENDERMODE_CPC || r_renderMode.GetInteger() == RENDERMODE_CPC_HIGHRES )
{
jitterTexScale[0] = r_renderMode.GetInteger() == RENDERMODE_CPC_HIGHRES ? 2.0 : 1.0;
renderProgManager.BindShader_PostProcess_RetroCPC();
}
else if( r_renderMode.GetInteger() == RENDERMODE_GENESIS || r_renderMode.GetInteger() == RENDERMODE_GENESIS_HIGHRES )
{
jitterTexScale[0] = r_renderMode.GetInteger() == RENDERMODE_GENESIS_HIGHRES ? 2.0 : 1.0;
renderProgManager.BindShader_PostProcess_RetroGenesis();
}
else if( r_renderMode.GetInteger() == RENDERMODE_PSX )
{
renderProgManager.BindShader_PostProcess_RetroPSX();
}
else
{
renderProgManager.BindShader_PostProcess();
}
jitterTexScale[1] = r_retroDitherScale.GetFloat();
SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale
float jitterTexOffset[4];
jitterTexOffset[0] = 1.0f / globalImages->blueNoiseImage256->GetUploadWidth();
@ -6164,3 +6190,90 @@ void idRenderBackend::PostProcess( const void* data )
renderLog.CloseBlock();
renderLog.CloseMainBlock();
}
void idRenderBackend::CRTPostProcess()
{
#if 1
//renderLog.OpenMainBlock( MRB_POSTPROCESS );
renderLog.OpenBlock( "Render_CRTPostFX", colorBlue );
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS | GLS_CULL_TWOSIDED );
int screenWidth = renderSystem->GetWidth();
int screenHeight = renderSystem->GetHeight();
// set the window clipping
GL_Viewport( 0, 0, screenWidth, screenHeight );
GL_Scissor( 0, 0, screenWidth, screenHeight );
if( r_useCRTPostFX.GetInteger() > 0 )
{
BlitParameters blitParms;
blitParms.sourceTexture = ( nvrhi::ITexture* )globalImages->ldrImage->GetTextureID();
blitParms.targetFramebuffer = globalFramebuffers.smaaBlendFBO->GetApiObject();
blitParms.targetViewport = nvrhi::Viewport( renderSystem->GetWidth(), renderSystem->GetHeight() );
commonPasses.BlitTexture( commandList, blitParms, &bindingCache );
GL_SelectTexture( 0 );
globalImages->smaaBlendImage->Bind();
globalFramebuffers.ldrFBO->Bind();
GL_SelectTexture( 1 );
globalImages->blueNoiseImage256->Bind();
if( r_useCRTPostFX.GetInteger() == 1 )
{
renderProgManager.BindShader_CrtMattias();
}
else
{
renderProgManager.BindShader_CrtNewPixie();
}
float windowCoordParm[4];
windowCoordParm[0] = r_crtCurvature.GetFloat();
windowCoordParm[1] = r_crtVignette.GetFloat();
windowCoordParm[2] = screenWidth;
windowCoordParm[3] = screenHeight;
SetFragmentParm( RENDERPARM_WINDOWCOORD, windowCoordParm ); // rpWindowCoord
float jitterTexOffset[4];
jitterTexOffset[0] = 1.0f / globalImages->blueNoiseImage256->GetUploadWidth();
jitterTexOffset[1] = 1.0f / globalImages->blueNoiseImage256->GetUploadHeight();
if( r_shadowMapRandomizeJitter.GetBool() )
{
jitterTexOffset[2] = Sys_Milliseconds() / 1000.0f;
jitterTexOffset[3] = tr.frameCount % 64;
}
else
{
jitterTexOffset[2] = 0.0f;
jitterTexOffset[3] = 0.0f;
}
SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset
// Draw
DrawElementsWithCounters( &unitSquareSurface );
}
//GL_SelectTexture( 0 );
//renderProgManager.Unbind();
// copy LDR result to DX12 / Vulkan swapchain image
BlitParameters blitParms;
blitParms.sourceTexture = ( nvrhi::ITexture* )globalImages->ldrImage->GetTextureID();
blitParms.targetFramebuffer = deviceManager->GetCurrentFramebuffer();
blitParms.targetViewport = nvrhi::Viewport( renderSystem->GetWidth(), renderSystem->GetHeight() );
commonPasses.BlitTexture( commandList, blitParms, &bindingCache );
GL_SelectTexture( 0 );
globalImages->currentRenderImage->Bind();
renderLog.CloseBlock();
//renderLog.CloseMainBlock();
#endif
}

View file

@ -208,7 +208,9 @@ private:
// Experimental feature
void MotionBlur();
void PostProcess( const void* data );
void CRTPostProcess();
private:
void GL_StartFrame();

View file

@ -699,11 +699,12 @@ TR_CMDS
enum renderCommand_t
{
RC_NOP,
RC_DRAW_VIEW_3D, // may be at a reduced resolution, will be upsampled before 2D GUIs
RC_DRAW_VIEW_GUI, // not resolution scaled
RC_DRAW_VIEW_3D, // may be at a reduced resolution, will be upsampled before 2D GUIs
RC_DRAW_VIEW_GUI, // not resolution scaled
RC_SET_BUFFER,
RC_COPY_RENDER,
RC_POST_PROCESS,
RC_POST_PROCESS, // postfx after scene rendering is done but before GUI rendering
RC_CRT_POST_PROCESS, // CRT simulation after everything has been rendered on the final swapchain image
};
struct emptyCommand_t
@ -746,6 +747,13 @@ struct postProcessCommand_t
viewDef_t* viewDef;
};
struct crtPostProcessCommand_t
{
renderCommand_t commandId;
renderCommand_t* next;
int padding;
};
//=======================================================================
// this is the inital allocation for max number of drawsurfs
@ -932,6 +940,8 @@ public:
virtual void DrawBigChar( int x, int y, int ch );
virtual void DrawBigStringExt( int x, int y, const char* string, const idVec4& setColor, bool forceColor );
virtual void DrawCRTPostFX(); // RB
virtual void WriteDemoPics();
virtual void WriteEndFrame();
virtual void DrawDemoPics();
@ -950,7 +960,6 @@ public:
virtual void CropRenderSize( int width, int height );
virtual void CropRenderSize( int x, int y, int width, int height, bool topLeftAncor );
virtual void CaptureRenderToImage( const char* imageName, bool clearColorAfterCopy = false );
virtual void CaptureRenderToFile( const char* fileName, bool fixAlpha );
virtual void UnCrop();
virtual bool UploadImage( const char* imageName, const byte* data, int width, int height );
@ -1259,7 +1268,6 @@ extern idCVar r_hdrDebug;
extern idCVar r_ldrContrastThreshold;
extern idCVar r_ldrContrastOffset;
extern idCVar r_useFilmicPostProcessing;
extern idCVar r_forceAmbient;
extern idCVar r_useSSAO;
@ -1267,7 +1275,6 @@ extern idCVar r_ssaoDebug;
extern idCVar r_ssaoFiltering;
extern idCVar r_useHierarchicalDepthBuffer;
extern idCVar r_usePBR;
extern idCVar r_pbrDebug;
extern idCVar r_showViewEnvprobes;
extern idCVar r_showLightGrid; // show Quake 3 style light grid points
@ -1283,6 +1290,28 @@ extern idCVar r_taaClampingFactor;
extern idCVar r_taaNewFrameWeight;
extern idCVar r_taaMaxRadiance;
extern idCVar r_taaMotionVectors;
extern idCVar r_useFilmicPostFX;
extern idCVar r_useCRTPostFX;
extern idCVar r_crtCurvature;
extern idCVar r_crtVignette;
enum RenderMode
{
RENDERMODE_DOOM,
RENDERMODE_C64,
RENDERMODE_C64_HIGHRES,
RENDERMODE_CPC,
RENDERMODE_CPC_HIGHRES,
RENDERMODE_GENESIS,
RENDERMODE_GENESIS_HIGHRES,
RENDERMODE_PSX,
};
extern idCVar r_retroDitherScale;
extern idCVar r_renderMode;
extern idCVar image_pixelLook;
// RB end
/*
@ -1293,6 +1322,8 @@ INITIALIZATION
====================================================================
*/
bool R_UsePixelatedLook();
bool R_UseTemporalAA();
uint R_GetMSAASamples();

View file

@ -88,10 +88,10 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
uniforms.SetNum( RENDERPARM_TOTAL, vec4_zero );
uniformsChanged = false;
for( int i = 0; i < NUM_BINDING_LAYOUTS; i++ )
//for( int i = 0; i < NUM_BINDING_LAYOUTS; i++ )
{
auto constantBufferDesc = nvrhi::utils::CreateVolatileConstantBufferDesc( uniforms.Allocated(), va( "RenderParams_%d", i ), 16384 );
constantBuffer[i] = device->createBuffer( constantBufferDesc );
auto constantBufferDesc = nvrhi::utils::CreateVolatileConstantBufferDesc( uniforms.Allocated(), va( "RenderParams_%d", 1 ), 16384 );
constantBuffer = device->createBuffer( constantBufferDesc );
}
// === Main draw vertex layout ===
@ -521,6 +521,12 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
{ BUILTIN_SKYBOX, "builtin/legacy/skybox", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_WOBBLESKY, "builtin/legacy/wobblesky", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_POSTPROCESS, "builtin/post/postprocess", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_POSTPROCESS_RETRO_C64, "builtin/post/retro_c64", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_POSTPROCESS_RETRO_CPC, "builtin/post/retro_cpc", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_POSTPROCESS_RETRO_GENESIS, "builtin/post/retro_genesis", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_POSTPROCESS_RETRO_PSX, "builtin/post/retro_ps1", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_CRT_MATTIAS, "builtin/post/crt_mattias", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_CRT_NUPIXIE, "builtin/post/crt_newpixie", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_SCREEN, "builtin/post/screen", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_TONEMAP, "builtin/post/tonemap", "", { { "BRIGHTPASS", "0" }, { "HDR_DEBUG", "0"} }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
@ -618,7 +624,6 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
}
}
r_usePBR.ClearModified();
r_pbrDebug.ClearModified();
uniforms.SetNum( RENDERPARM_TOTAL, vec4_zero );
@ -720,9 +725,9 @@ void idRenderProgManager::Shutdown()
}
// SRS - Unmap buffer memory using overloaded = operator
for( int i = 0; i < constantBuffer.Num(); i++ )
//for( int i = 0; i < constantBuffer.Num(); i++ )
{
constantBuffer[i] = nullptr;
constantBuffer = nullptr;
}
}

View file

@ -366,6 +366,12 @@ enum
BUILTIN_WOBBLESKY,
BUILTIN_POSTPROCESS,
// RB begin
BUILTIN_POSTPROCESS_RETRO_C64, // Commodore 64
BUILTIN_POSTPROCESS_RETRO_CPC, // Amstrad 6128
BUILTIN_POSTPROCESS_RETRO_GENESIS, // Sega Genesis / Megadrive
BUILTIN_POSTPROCESS_RETRO_PSX, // Sony Playstation 1
BUILTIN_CRT_MATTIAS,
BUILTIN_CRT_NUPIXIE,
BUILTIN_SCREEN,
BUILTIN_TONEMAP,
BUILTIN_BRIGHTPASS,
@ -817,6 +823,36 @@ public:
BindShader_Builtin( BUILTIN_POSTPROCESS );
}
void BindShader_PostProcess_RetroC64()
{
BindShader_Builtin( BUILTIN_POSTPROCESS_RETRO_C64 );
}
void BindShader_PostProcess_RetroCPC()
{
BindShader_Builtin( BUILTIN_POSTPROCESS_RETRO_CPC );
}
void BindShader_PostProcess_RetroGenesis()
{
BindShader_Builtin( BUILTIN_POSTPROCESS_RETRO_GENESIS );
}
void BindShader_PostProcess_RetroPSX()
{
BindShader_Builtin( BUILTIN_POSTPROCESS_RETRO_PSX );
}
void BindShader_CrtMattias()
{
BindShader_Builtin( BUILTIN_CRT_MATTIAS );
}
void BindShader_CrtNewPixie()
{
BindShader_Builtin( BUILTIN_CRT_NUPIXIE );
}
void BindShader_Screen()
{
BindShader_Builtin( BUILTIN_SCREEN );
@ -964,7 +1000,7 @@ public:
ID_INLINE nvrhi::IBuffer* ConstantBuffer()
{
return constantBuffer[BindingLayoutType()];
return constantBuffer;//[BindingLayoutType()];
}
ID_INLINE idUniformBuffer& BindingParamUbo()
{
@ -1070,7 +1106,8 @@ private:
idStaticList< idStaticList<nvrhi::BindingLayoutHandle, nvrhi::c_MaxBindingLayouts>, NUM_BINDING_LAYOUTS > bindingLayouts;
idArray<nvrhi::BufferHandle, NUM_BINDING_LAYOUTS> constantBuffer;
//idArray<nvrhi::BufferHandle, NUM_BINDING_LAYOUTS> constantBuffer;
nvrhi::BufferHandle constantBuffer;
};
extern idRenderProgManager renderProgManager;

View file

@ -782,7 +782,6 @@ const emptyCommand_t* idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffe
// set the time for shader effects in 2D rendering
frameShaderTime = Sys_Milliseconds() * 0.001;
// RB: TODO RC_SET_BUFFER is not handled in OpenGL
setBufferCommand_t* cmd2 = ( setBufferCommand_t* )R_GetCommandBuffer( sizeof( *cmd2 ) );
cmd2->commandId = RC_SET_BUFFER;
cmd2->buffer = 0;
@ -1038,53 +1037,6 @@ void idRenderSystemLocal::CaptureRenderToImage( const char* imageName, bool clea
guiModel->Clear();
}
/*
==============
idRenderSystemLocal::CaptureRenderToFile
==============
*/
void idRenderSystemLocal::CaptureRenderToFile( const char* fileName, bool fixAlpha )
{
if( !IsInitialized() )
{
return;
}
idScreenRect& rc = renderCrops[currentRenderCrop];
guiModel->EmitFullScreen();
guiModel->Clear();
RenderCommandBuffers( frameData->cmdHead );
// TODO implement for NVRHI
#if !defined( USE_VULKAN ) && !defined( USE_NVRHI )
glReadBuffer( GL_BACK );
// include extra space for OpenGL padding to word boundaries
int c = ( rc.GetWidth() + 3 ) * rc.GetHeight();
byte* data = ( byte* )R_StaticAlloc( c * 3 );
glReadPixels( rc.x1, rc.y1, rc.GetWidth(), rc.GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, data );
byte* data2 = ( byte* )R_StaticAlloc( c * 4 );
for( int i = 0 ; i < c ; i++ )
{
data2[ i * 4 ] = data[ i * 3 ];
data2[ i * 4 + 1 ] = data[ i * 3 + 1 ];
data2[ i * 4 + 2 ] = data[ i * 3 + 2 ];
data2[ i * 4 + 3 ] = 0xff;
}
R_WriteTGA( fileName, data2, rc.GetWidth(), rc.GetHeight(), true );
R_StaticFree( data );
R_StaticFree( data2 );
#endif
}
/*
==============
@ -1153,3 +1105,19 @@ bool idRenderSystemLocal::UploadImage( const char* imageName, const byte* data,
return true;
}
// RB
void idRenderSystemLocal::DrawCRTPostFX()
{
if( !IsInitialized() )
{
return;
}
guiModel->EmitFullScreen();
guiModel->Clear();
crtPostProcessCommand_t* cmd = ( crtPostProcessCommand_t* )R_GetCommandBuffer( sizeof( *cmd ) );
cmd->commandId = RC_CRT_POST_PROCESS;
}

View file

@ -306,6 +306,8 @@ public:
virtual void DrawBigChar( int x, int y, int ch ) = 0;
virtual void DrawBigStringExt( int x, int y, const char* string, const idVec4& setColor, bool forceColor ) = 0;
virtual void DrawCRTPostFX() = 0; // RB
// dump all 2D drawing so far this frame to the demo file
virtual void WriteDemoPics() = 0;
virtual void WriteEndFrame() = 0;
@ -359,9 +361,6 @@ public:
virtual void CropRenderSize( int width, int height ) = 0;
virtual void CropRenderSize( int x, int y, int width, int height, bool topLeftAncor ) = 0;
virtual void CaptureRenderToImage( const char* imageName, bool clearColorAfterCopy = false ) = 0;
// fixAlpha will set all the alpha channel values to 0xff, which allows screen captures
// to use the default tga loading code without having dimmed down areas in many places
virtual void CaptureRenderToFile( const char* fileName, bool fixAlpha = false ) = 0;
virtual void UnCrop() = 0;
// the image has to be already loaded ( most straightforward way would be through a FindMaterial )

View file

@ -171,9 +171,6 @@ idCVar r_flareSize( "r_flareSize", "1", CVAR_RENDERER | CVAR_FLOAT, "scale the f
idCVar r_useScissor( "r_useScissor", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_NOCHEAT, "scissor clip as portals and lights are processed" );
idCVar r_useLightDepthBounds( "r_useLightDepthBounds", "1", CVAR_RENDERER | CVAR_BOOL, "use depth bounds test on lights to reduce both shadow and interaction fill" );
idCVar r_useShadowDepthBounds( "r_useShadowDepthBounds", "1", CVAR_RENDERER | CVAR_BOOL, "use depth bounds test on individual shadow volumes to reduce shadow fill" );
// RB begin
idCVar r_useHalfLambertLighting( "r_useHalfLambertLighting", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "use Half-Lambert lighting instead of classic Lambert, requires reloadShaders" );
// RB end
idCVar r_screenFraction( "r_screenFraction", "100", CVAR_RENDERER | CVAR_INTEGER, "for testing fill rate, the resolution of the entire screen can be changed" );
idCVar r_usePortals( "r_usePortals", "1", CVAR_RENDERER | CVAR_BOOL, " 1 = use portals to perform area culling, otherwise draw everything" );
@ -276,7 +273,7 @@ idCVar r_hdrDebug( "r_hdrDebug", "0", CVAR_RENDERER | CVAR_FLOAT, "show scene lu
idCVar r_ldrContrastThreshold( "r_ldrContrastThreshold", "1.1", CVAR_RENDERER | CVAR_FLOAT, "" );
idCVar r_ldrContrastOffset( "r_ldrContrastOffset", "3", CVAR_RENDERER | CVAR_FLOAT, "" );
idCVar r_useFilmicPostProcessing( "r_useFilmicPostProcessing", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "apply several post process effects to mimic a filmic look" );
idCVar r_useFilmicPostFX( "r_useFilmicPostFX", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "filmic look with chromatic abberation and film grain" );
idCVar r_forceAmbient( "r_forceAmbient", "0.5", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "render additional ambient pass to make the game less dark", 0.0f, 1.0f );
@ -285,8 +282,6 @@ idCVar r_ssaoDebug( "r_ssaoDebug", "0", CVAR_RENDERER | CVAR_INTEGER, "" );
idCVar r_ssaoFiltering( "r_ssaoFiltering", "0", CVAR_RENDERER | CVAR_BOOL, "" );
idCVar r_useHierarchicalDepthBuffer( "r_useHierarchicalDepthBuffer", "1", CVAR_RENDERER | CVAR_BOOL, "" );
// RB: only change r_usePBR if you are a developer
idCVar r_usePBR( "r_usePBR", "1", CVAR_RENDERER | CVAR_ROM | CVAR_STATIC | CVAR_BOOL, "use PBR and Image Based Lighting instead of old Quake 4 style ambient lighting" );
idCVar r_pbrDebug( "r_pbrDebug", "0", CVAR_RENDERER | CVAR_INTEGER, "show which materials have PBR support (green = PBR, red = oldschool D3)" );
idCVar r_showViewEnvprobes( "r_showViewEnvprobes", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = displays the bounding boxes of all view environment probes, 2 = show irradiance" );
idCVar r_showLightGrid( "r_showLightGrid", "0", CVAR_RENDERER | CVAR_INTEGER, "show Quake 3 style light grid points" );
@ -302,6 +297,14 @@ idCVar r_taaClampingFactor( "r_taaClampingFactor", "1.0", CVAR_RENDERER | CVAR_F
idCVar r_taaNewFrameWeight( "r_taaNewFrameWeight", "0.1", CVAR_RENDERER | CVAR_FLOAT, "" );
idCVar r_taaMaxRadiance( "r_taaMaxRadiance", "10000", CVAR_RENDERER | CVAR_FLOAT, "" );
idCVar r_taaMotionVectors( "r_taaMotionVectors", "1", CVAR_RENDERER | CVAR_BOOL, "" );
idCVar r_useCRTPostFX( "r_useCRTPostFX", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "RetroArch CRT shader: 1 = Matthias CRT, 1 = New Pixie", 0, 2 );
idCVar r_crtCurvature( "r_crtCurvature", "2", CVAR_RENDERER | CVAR_FLOAT, "rounded borders" );
idCVar r_crtVignette( "r_crtVignette", "0.8", CVAR_RENDERER | CVAR_FLOAT, "fading into the borders" );
idCVar r_retroDitherScale( "r_retroDitherScale", "0.3", CVAR_RENDERER | CVAR_FLOAT, "" );
idCVar r_renderMode( "r_renderMode", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "0 = Doom, 1 = Commodore 64, 2 = Commodore 64 Highres, 3 = Amstrad CPC 6128, 4 = Amstrad CPC 6128 Highres, 5 = Sega Genesis, 6 = Sega Genesis Highres, 7 = Sony PSX", 0, 7 );
// RB end
const char* fileExten[4] = { "tga", "png", "jpg", "exr" };
@ -311,6 +314,11 @@ const char* skyDirection[6] = { "_forward", "_back", "_left", "_right", "_up", "
DeviceManager* deviceManager = NULL;
bool R_UsePixelatedLook()
{
return ( r_renderMode.GetInteger() == RENDERMODE_PSX ) || image_pixelLook.GetBool();
}
bool R_UseTemporalAA()
{
if( !r_useTemporalAA.GetBool() )
@ -2203,10 +2211,12 @@ void idRenderSystemLocal::Shutdown()
// SRS - wait for fence to hit before freeing any resources the GPU may be using, otherwise get Vulkan validation layer errors on shutdown
// SRS - skip this step if we are in a Doom Classic game
#if defined(USE_DOOMCLASSIC)
if( common->GetCurrentGame() == DOOM3_BFG )
{
backend.GL_BlockingSwapBuffers();
}
#endif
// free the vertex cache, which should have nothing allocated now
vertexCache.Shutdown();

View file

@ -1264,89 +1264,4 @@ static const unsigned char brfLutTexBytes[] =
Mem_Free( hdrBuffer );
}
CONSOLE_COMMAND( makeImageHeader, "load an image and turn it into a .h file", NULL )
{
byte* buffer;
int width = 0, height = 0;
if( args.Argc() < 2 )
{
common->Printf( "USAGE: makeImageHeader filename [exportname]\n" );
return;
}
idStr filename = args.Argv( 1 );
R_LoadImage( filename, &buffer, &width, &height, NULL, true, NULL );
if( !buffer )
{
common->Printf( "loading %s failed.\n", filename.c_str() );
return;
}
filename.StripFileExtension();
idStr exportname;
if( args.Argc() == 3 )
{
exportname.Format( "Image_%s.h", args.Argv( 2 ) );
}
else
{
exportname.Format( "Image_%s.h", filename.c_str() );
}
for( int i = 0; i < exportname.Length(); i++ )
{
if( exportname[ i ] == '/' )
{
exportname[ i ] = '_';
}
}
idFileLocal headerFile( fileSystem->OpenFileWrite( exportname, "fs_basepath" ) );
idStr uppername = exportname;
uppername.ToUpper();
for( int i = 0; i < uppername.Length(); i++ )
{
if( uppername[ i ] == '.' )
{
uppername[ i ] = '_';
}
}
headerFile->Printf( "#ifndef %s_TEX_H\n", uppername.c_str() );
headerFile->Printf( "#define %s_TEX_H\n\n", uppername.c_str() );
headerFile->Printf( "#define %s_TEX_WIDTH %i\n", uppername.c_str(), width );
headerFile->Printf( "#define %s_TEX_HEIGHT %i\n\n", uppername.c_str(), height );
headerFile->Printf( "static const unsigned char %s_Bytes[] = {\n", uppername.c_str() );
int bufferSize = width * height * 4;
for( int i = 0; i < bufferSize; i++ )
{
byte b = buffer[i];
if( i < ( bufferSize - 1 ) )
{
headerFile->Printf( "0x%02hhx, ", b );
}
else
{
headerFile->Printf( "0x%02hhx", b );
}
if( i % 12 == 0 )
{
headerFile->Printf( "\n" );
}
}
headerFile->Printf( "\n};\n#endif\n" );
Mem_Free( buffer );
}

View file

@ -31,10 +31,20 @@ source_group("global" FILES ${globalshaders})
source_group("user" FILES ${usershaders})
compile_shaders_all_platforms(
TARGET Shaders
CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/shaders.cfg
OUTPUT_BASE ${CMAKE_CURRENT_SOURCE_DIR}/../../base/renderprogs2 # This path scheme is a bit odd.
SHADER_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
SOURCES ${shaders}
)
if(STANDALONE)
compile_shaders_all_platforms(
TARGET Shaders
CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/shaders.cfg
OUTPUT_BASE ${CMAKE_CURRENT_SOURCE_DIR}/../../content/renderprogs2
SHADER_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
SOURCES ${shaders}
)
else()
compile_shaders_all_platforms(
TARGET Shaders
CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/shaders.cfg
OUTPUT_BASE ${CMAKE_CURRENT_SOURCE_DIR}/../../base/renderprogs2 # This path scheme is a bit odd.
SHADER_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
SOURCES ${shaders}
)
endif()

View file

@ -0,0 +1,127 @@
/*
===========================================================================
newpixie CRT
Copyright (c) 2016 Mattias Gustavsson
Copyright (c) 2023 Robert Beckebans
MIT License
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.
===========================================================================
*/
#include <global_inc.hlsl>
// *INDENT-OFF*
Texture2D t_CurrentRender : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState LinearSampler : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState samp1 : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
float2 curve( float2 uv, float curvature )
{
uv = ( uv - 0.5 ) * 2.0;
uv *= 1.1;
uv.x *= 1.0 + pow( ( abs( uv.y ) / 5.0 ), 2.0 );
uv.y *= 1.0 + pow( ( abs( uv.x ) / 4.0 ), 2.0 );
uv = ( uv / curvature ) + 0.5;
uv = uv * 0.92 + 0.04;
return uv;
}
void main( PS_IN fragment, out PS_OUT result )
{
float2 iResolution = rpWindowCoord.zw;
float iTime = rpJitterTexOffset.x;
float2 q = fragment.texcoord0.xy;
q = saturate( q );
float2 uv = q;
if( rpWindowCoord.x > 0.0 )
{
uv = curve( uv, 2.0 );
}
// wiggle
float x = 0.0; //sin( 0.3 * iTime + uv.y * 21.0 ) * sin( 0.7 * iTime + uv.y * 29.0 ) * sin( 0.3 + 0.33 * iTime + uv.y * 31.0 ) * 0.0017;
float3 col;
col.r = t_CurrentRender.Sample( LinearSampler, float2( x + uv.x + 0.001, uv.y + 0.001 ) ).x + 0.05;
col.g = t_CurrentRender.Sample( LinearSampler, float2( x + uv.x + 0.000, uv.y - 0.002 ) ).y + 0.05;
col.b = t_CurrentRender.Sample( LinearSampler, float2( x + uv.x - 0.002, uv.y + 0.000 ) ).z + 0.05;
/* Ghosting */
#if 1
col.r += 0.08 * t_CurrentRender.Sample( LinearSampler, 0.75 * float2( x + 0.025, -0.027 ) + float2( uv.x + 0.001, uv.y + 0.001 ) ).x;
col.g += 0.05 * t_CurrentRender.Sample( LinearSampler, 0.75 * float2( x + -0.022, -0.02 ) + float2( uv.x + 0.000, uv.y - 0.002 ) ).y;
col.b += 0.08 * t_CurrentRender.Sample( LinearSampler, 0.75 * float2( x + -0.02, -0.018 ) + float2( uv.x - 0.002, uv.y + 0.000 ) ).z;
#endif
/* Level adjustment (curves) */
col = clamp( col * 0.6 + 0.4 * col * col * 1.0, 0.0, 1.0 );
/* Vignette */
float vig = ( 0.0 + 1.0 * 16.0 * uv.x * uv.y * ( 1.0 - uv.x ) * ( 1.0 - uv.y ) );
col *= _float3( pow( vig, 0.3 ) );
col *= float3( 0.95, 1.05, 0.95 );
col *= 2.8;
/* Scanlines */
float scans = clamp( 0.35 + 0.35 * sin( 3.5 * iTime + uv.y * iResolution.y * 1.5 ), 0.0, 1.0 );
float s = pow( scans, 1.7 );
col = col * _float3( 0.4 + 0.7 * s ) ;
col *= 1.0 + 0.01 * sin( 110.0 * iTime );
if( uv.x < 0.0 || uv.x > 1.0 )
{
col *= 0.0;
}
if( uv.y < 0.0 || uv.y > 1.0 )
{
col *= 0.0;
}
col *= 1.0 - 0.65 * _float3( clamp( ( fmod( fragment.texcoord0.x, 2.0 ) - 1.0 ) * 2.0, 0.0, 1.0 ) );
float comp = smoothstep( 0.1, 0.9, sin( iTime ) );
// Remove the next line to stop cross-fade between original and postprocess
//col = mix( col, oricol, comp );
result.color = float4( col.x, col.y, col.z, 1.0 );
}

View file

@ -0,0 +1,55 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -0,0 +1,254 @@
/*
===========================================================================
newpixie CRT
Copyright (c) 2016 Mattias Gustavsson
Copyright (c) 2023 Robert Beckebans
MIT License
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.
===========================================================================
*/
#include <global_inc.hlsl>
// *INDENT-OFF*
Texture2D t_CurrentRender : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState LinearSampler : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState samp1 : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
float3 tsample( Texture2D tex, vec2 tc, float offs, vec2 resolution )
{
#if 1
//tc = tc * vec2( 1.025, 0.92 ) + vec2( -0.0125, 0.04 );
float3 s = pow( abs( tex.Sample( LinearSampler, vec2( tc.x, 1.0 - tc.y ) ).rgb ), _float3( 2.2 ) );
return s * _float3( 1.25 );
#else
float3 s = tex.Sample( LinearSampler, vec2( tc.x, 1.0 - tc.y ) ).rgb;
return s;
#endif
}
float3 filmic( float3 LinearColor )
{
float3 x = max( _float3( 0.0 ), LinearColor - _float3( 0.004 ) );
return ( x * ( 6.2 * x + 0.5 ) ) / ( x * ( 6.2 * x + 1.7 ) + 0.06 );
}
float2 curve( float2 uv, float curvature )
{
uv = ( uv - 0.5 ) * 2.0;
uv *= 1.1;
uv.x *= 1.0 + pow( ( abs( uv.y ) / 5.0 ), 2.0 );
uv.y *= 1.0 + pow( ( abs( uv.x ) / 4.0 ), 2.0 );
uv = ( uv / curvature ) + 0.5;
uv = uv * 0.92 + 0.04;
return uv;
}
float2 curve2( float2 uv, float curvature )
{
uv = ( uv - 0.5 ) * 2.0;
uv *= 1.1;
uv.x *= 1.0 + pow( ( abs( uv.y ) / 4.0 ), 2.0 );
uv.y *= 1.0 + pow( ( abs( uv.x ) / 3.0 ), 2.0 );
uv = ( uv / curvature ) + 0.5;
uv = uv * 0.92 + 0.04;
return uv;
}
void main( PS_IN fragment, out PS_OUT result )
{
// revised version from RetroArch
struct Params
{
float curvature;
float ghosting;
float scanroll;
float vignette;
float wiggle_toggle;
int FrameCount;
};
Params params;
params.curvature = rpWindowCoord.x;
params.ghosting = 0.0;
params.scanroll = 1.0;
params.wiggle_toggle = 0.0;
params.vignette = rpWindowCoord.y;
params.FrameCount = int( rpJitterTexOffset.w );
// stop time variable so the screen doesn't wiggle
float time = params.FrameCount % 849 * 36.0;
float2 uv = fragment.texcoord0.xy;
uv.y = 1.0 - uv.y;
uv = saturate( uv );
/* Curve */
//float2 curved_uv = lerp( curve2( uv, params.curvature ), uv, 0.4 );
//float scale = -0.101;
//float2 scuv = curved_uv * ( 1.0 - scale ) + scale / 2.0 + float2( 0.003, -0.001 );
//uv = scuv;
float2 curved_uv = uv;
if( params.curvature > 0.0 )
{
curved_uv = curve( uv, 2.0 );
}
float2 scuv = curved_uv;
float2 resolution = rpWindowCoord.zw;
/* Main color, Bleed */
float3 col;
float x = params.wiggle_toggle * sin( 0.1 * time + curved_uv.y * 13.0 ) * sin( 0.23 * time + curved_uv.y * 19.0 ) * sin( 0.3 + 0.11 * time + curved_uv.y * 23.0 ) * 0.0012;
// make time do something again
time = float( params.FrameCount % 640 * 1 );
Texture2D backbuffer = t_CurrentRender;
#if 1
col.r = tsample( backbuffer, vec2( x + scuv.x + 0.0009, scuv.y + 0.0009 ), resolution.y / 800.0, resolution ).x + 0.02;
col.g = tsample( backbuffer, vec2( x + scuv.x + 0.0000, scuv.y - 0.0011 ), resolution.y / 800.0, resolution ).y + 0.02;
col.b = tsample( backbuffer, vec2( x + scuv.x - 0.0015, scuv.y + 0.0000 ), resolution.y / 800.0, resolution ).z + 0.02;
#else
col.r = t_CurrentRender.Sample( LinearSampler, float2( x + uv.x + 0.001, uv.y + 0.001 ) ).x + 0.05;
col.g = t_CurrentRender.Sample( LinearSampler, float2( x + uv.x + 0.000, uv.y - 0.002 ) ).y + 0.05;
col.b = t_CurrentRender.Sample( LinearSampler, float2( x + uv.x - 0.002, uv.y + 0.000 ) ).z + 0.05;
#endif
/* Ghosting */
#if 1
{
float o = sin( -fragment.position.y * 1.5 ) / resolution.x;
x += o * 0.25;
float ghs = 0.15 * params.ghosting;
Texture2D blurbuffer = t_CurrentRender; // FIXME
float3 r = tsample( blurbuffer, float2( x - 0.014 * 1.0, -0.027 ) * 0.85 + 0.007 * float2( 0.35 * sin( 1.0 / 7.0 + 15.0 * curved_uv.y + 0.9 * time ),
0.35 * sin( 2.0 / 7.0 + 10.0 * curved_uv.y + 1.37 * time ) ) + float2( scuv.x + 0.001, scuv.y + 0.001 ),
5.5 + 1.3 * sin( 3.0 / 9.0 + 31.0 * curved_uv.x + 1.70 * time ), resolution ).xyz * float3( 0.5, 0.25, 0.25 );
float3 g = tsample( blurbuffer, float2( x - 0.019 * 1.0, -0.020 ) * 0.85 + 0.007 * float2( 0.35 * cos( 1.0 / 9.0 + 15.0 * curved_uv.y + 0.5 * time ),
0.35 * sin( 2.0 / 9.0 + 10.0 * curved_uv.y + 1.50 * time ) ) + float2( scuv.x + 0.000, scuv.y - 0.002 ),
5.4 + 1.3 * sin( 3.0 / 3.0 + 71.0 * curved_uv.x + 1.90 * time ), resolution ).xyz * float3( 0.25, 0.5, 0.25 );
float3 b = tsample( blurbuffer, float2( x - 0.017 * 1.0, -0.003 ) * 0.85 + 0.007 * float2( 0.35 * sin( 2.0 / 3.0 + 15.0 * curved_uv.y + 0.7 * time ),
0.35 * cos( 2.0 / 3.0 + 10.0 * curved_uv.y + 1.63 * time ) ) + float2( scuv.x - 0.002, scuv.y + 0.000 ),
5.3 + 1.3 * sin( 3.0 / 7.0 + 91.0 * curved_uv.x + 1.65 * time ), resolution ).xyz * float3( 0.25, 0.25, 0.5 );
float i = clamp( col.r * 0.299 + col.g * 0.587 + col.b * 0.114, 0.0, 1.0 );
i = pow( 1.0 - pow( i, 2.0 ), 1.0 );
i = ( 1.0 - i ) * 0.85 + 0.15;
col += _float3( ghs * ( 1.0 - 0.299 ) ) * pow( clamp( _float3( 3.0 ) * r, _float3( 0.0 ), _float3( 1.0 ) ), _float3( 2.0 ) ) * _float3( i );
col += _float3( ghs * ( 1.0 - 0.587 ) ) * pow( clamp( _float3( 3.0 ) * g, _float3( 0.0 ), _float3( 1.0 ) ), _float3( 2.0 ) ) * _float3( i );
col += _float3( ghs * ( 1.0 - 0.114 ) ) * pow( clamp( _float3( 3.0 ) * b, _float3( 0.0 ), _float3( 1.0 ) ), _float3( 2.0 ) ) * _float3( i );
}
#endif
/* Level adjustment (curves) */
#if 1
col *= float3( 0.95, 1.05, 0.95 );
col = clamp( col * 1.3 + 0.75 * col * col + 1.25 * col * col * col * col * col, _float3( 0.0 ), _float3( 10.0 ) );
#endif
/* Vignette */
#if 1
float vig = ( ( 1.0 - 0.99 * params.vignette ) + 1.0 * 16.0 * curved_uv.x * curved_uv.y * ( 1.0 - curved_uv.x ) * ( 1.0 - curved_uv.y ) );
vig = 1.3 * pow( vig, 0.5 );
col *= vig;
#endif
time *= params.scanroll;
/* Scanlines */
float scans = clamp( 0.35 + 0.18 * sin( 6.0 * time - curved_uv.y * resolution.y * 1.5 ), 0.0, 1.0 );
float s = pow( scans, 0.9 );
col = col * _float3( s );
/* Vertical lines (shadow mask) */
col *= 1.0 - 0.23 * ( clamp( ( fragment.position.xy.x % 3.0 ) / 2.0, 0.0, 1.0 ) );
/* Tone map */
col = filmic( col );
/* Noise */
#if 1
/*float2 seed = floor(curved_uv*resolution.xy*float2(0.5))/resolution.xy;*/
float2 seed = curved_uv * resolution.xy;
/* seed = curved_uv; */
col -= 0.015 * pow( float3( rand( seed + time ), rand( seed + time * 2.0 ), rand( seed + time * 3.0 ) ), _float3( 1.5 ) );
#endif
/* Flicker */
col *= ( 1.0 - 0.004 * ( sin( 50.0 * time + curved_uv.y * 2.0 ) * 0.5 + 0.5 ) );
/* Clamp */
#if 1
if( curved_uv.x < 0.0 || curved_uv.x > 1.0 )
{
col *= 0.0;
}
if( curved_uv.y < 0.0 || curved_uv.y > 1.0 )
{
col *= 0.0;
}
#endif
uv = curved_uv;
#if 1
/* Frame */
float2 fscale = float2( 0.026, -0.018 ); //float2( -0.018, -0.013 );
//uv = float2( uv.x, 1.0 - uv.y );
//float4 f = texture( frametexture, vTexCoord.xy ); //*((1.0)+2.0*fscale)-fscale-float2(-0.0, 0.005));
//f.xyz = mix( f.xyz, float3( 0.5, 0.5, 0.5 ), 0.5 );
float4 f = _float4( 0.5 );
float fvig = clamp( -0.00 + 512.0 * uv.x * uv.y * ( 1.0 - uv.x ) * ( 1.0 - uv.y ), 0.2, 0.8 );
//col = lerp( col, lerp( max( col, 0.0 ), pow( abs( f.xyz ), _float3( 1.4 ) ) * fvig, f.w * f.w ), _float3( use_frame ) );
//col = lerp( col, lerp( max( col, 0.0 ), pow( abs( f.xyz ), _float3( 1.4 ) ) * fvig, f.w * f.w ), _float3( 1.0 ) );
// Gamma correction since we are not rendering to an sRGB render target.
col = pow( col, _float3( 1.0 / 1.1 ) );
#endif
result.color = float4( col, 1.0 );
}

View file

@ -0,0 +1,55 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -72,8 +72,6 @@ struct PS_OUT
#define Dithering_QuantizationSteps 16.0 // 8.0 = 2 ^ 3 quantization bits
#define Dithering_NoiseBoost 1.0
#define Dithering_Wide 1.0
#define DITHER_IN_LINEAR_SPACE 0
#define DITHER_GENERATE_NOISE 0
float3 overlay( float3 a, float3 b )
{
@ -284,70 +282,9 @@ float3 BlueNoise3( float2 n, float x )
}
float Noise( float2 n, float x )
{
n += x;
#if 1
return frac( sin( dot( n.xy, float2( 12.9898, 78.233 ) ) ) * 43758.5453 ) * 2.0 - 1.0;
#else
//return BlueNoise( n, 55.0 );
return BlueNoise( n, 1.0 );
//return InterleavedGradientNoise( n ) * 2.0 - 1.0;
#endif
}
// Step 1 in generation of the dither source texture.
float Step1( float2 uv, float n )
{
float a = 1.0, b = 2.0, c = -12.0, t = 1.0;
return ( 1.0 / ( a * 4.0 + b * 4.0 - c ) ) * (
Noise( uv + float2( -1.0, -1.0 ) * t, n ) * a +
Noise( uv + float2( 0.0, -1.0 ) * t, n ) * b +
Noise( uv + float2( 1.0, -1.0 ) * t, n ) * a +
Noise( uv + float2( -1.0, 0.0 ) * t, n ) * b +
Noise( uv + float2( 0.0, 0.0 ) * t, n ) * c +
Noise( uv + float2( 1.0, 0.0 ) * t, n ) * b +
Noise( uv + float2( -1.0, 1.0 ) * t, n ) * a +
Noise( uv + float2( 0.0, 1.0 ) * t, n ) * b +
Noise( uv + float2( 1.0, 1.0 ) * t, n ) * a +
0.0 );
}
// Step 2 in generation of the dither source texture.
float Step2( float2 uv, float n )
{
float a = 1.0, b = 2.0, c = -2.0, t = 1.0;
#if DITHER_IN_LINEAR_SPACE
return ( 1.0 / ( a * 4.0 + b * 4.0 - c ) ) * (
#else
return ( 4.0 / ( a * 4.0 + b * 4.0 - c ) ) * (
#endif
Step1( uv + float2( -1.0, -1.0 ) * t, n ) * a +
Step1( uv + float2( 0.0, -1.0 ) * t, n ) * b +
Step1( uv + float2( 1.0, -1.0 ) * t, n ) * a +
Step1( uv + float2( -1.0, 0.0 ) * t, n ) * b +
Step1( uv + float2( 0.0, 0.0 ) * t, n ) * c +
Step1( uv + float2( 1.0, 0.0 ) * t, n ) * b +
Step1( uv + float2( -1.0, 1.0 ) * t, n ) * a +
Step1( uv + float2( 0.0, 1.0 ) * t, n ) * b +
Step1( uv + float2( 1.0, 1.0 ) * t, n ) * a +
0.0 );
}
// Used for stills.
float3 Step3( float2 uv )
{
#if DITHER_GENERATE_NOISE
float a = Step2( uv, 0.07 );
float b = Step2( uv, 0.11 );
float c = Step2( uv, 0.13 );
return float3( a, b, c );
#else
float3 noise = BlueNoise3( uv, 0.0 );
#if 1
@ -359,19 +296,11 @@ float3 Step3( float2 uv )
#endif
return noise;
#endif
}
// Used for temporal dither.
float3 Step3T( float2 uv )
{
#if DITHER_GENERATE_NOISE
float a = Step2( uv, 0.07 * fract( rpJitterTexOffset.z ) );
float b = Step2( uv, 0.11 * fract( rpJitterTexOffset.z ) );
float c = Step2( uv, 0.13 * fract( rpJitterTexOffset.z ) );
return float3( a, b, c );
#else
float3 noise = BlueNoise3( uv, 1.0 );
#if 1
@ -383,7 +312,6 @@ float3 Step3T( float2 uv )
#endif
return noise;
#endif
}
@ -395,86 +323,32 @@ void DitheringPass( inout float4 fragColor, PS_IN fragment )
float3 color = fragColor.rgb;
#if 0
// BOTTOM: Show bands.
if( uv2.y >= 0.975 )
{
// quantized signal
color = float3( uv2.x );
// BOTTOM: Show bands.
color = _float3( uv2.x );
// dithered still
//color = floor( color * Dithering_QuantizationSteps + Step3( uv ) * Dithering_NoiseBoost ) * ( 1.0 / ( Dithering_QuantizationSteps - 1.0 ) );
}
else if( uv2.y >= 0.95 )
{
// quantized signal
color = float3( uv2.x );
color = _float3( uv2.x );
color = floor( color * Dithering_QuantizationSteps ) * ( 1.0 / ( Dithering_QuantizationSteps - 1.0 ) );
}
else if( uv2.y >= 0.925 )
{
// quantized signal dithered temporally
color = float3( uv2.x );
color = _float3( uv2.x );
color = floor( color * Dithering_QuantizationSteps + Step3( uv ) * Dithering_NoiseBoost ) * ( 1.0 / ( Dithering_QuantizationSteps - 1.0 ) );
}
// TOP: Show dither texture.
else if( uv2.y >= 0.9 )
{
// TOP: Show dither texture.
color = Step3( uv ) * ( 0.25 * Dithering_NoiseBoost ) + 0.5;
}
else
#endif
{
#if DITHER_IN_LINEAR_SPACE
color = Linear3( color );
// Add grain in linear space.
#if 0
// Slow more correct solutions.
#if 1
// Too expensive.
// Helps understand the fast solutions.
float3 amount = Linear3( Srgb3( color ) + ( Dithering_NoiseBoost / Dithering_QuantizationSteps ) ) - color;
#else
// Less too expensive.
float luma = PhotoLuma( color );
// Implement this as a texture lookup table.
float amount = Linear1( Srgb1( luma ) + ( Dithering_NoiseBoost / Dithering_QuantizationSteps ) ) - luma;
#endif
#else
// Fast solutions.
#if 1
// Hack 1 (fastest).
// For HDR need saturate() around luma.
float luma = PhotoLuma( color );
float amount = mix(
Linear1( Dithering_NoiseBoost / Dithering_QuantizationSteps ),
Linear1( ( Dithering_NoiseBoost / Dithering_QuantizationSteps ) + 1.0 ) - 1.0,
luma );
#else
// Hack 2 (slower?).
// For HDR need saturate() around color in mix().
float3 amount = mix(
float3( Linear1( Dithering_NoiseBoost / Dithering_QuantizationSteps ) ),
float3( Linear1( ( Dithering_NoiseBoost / Dithering_QuantizationSteps ) + 1.0 ) - 1.0 ),
color );
#endif
#endif
color += Step3T( uv ) * amount;// * Dithering_NoiseBoost;
// The following represents hardware linear->sRGB xform
// which happens on sRGB formatted render targets,
// except using a lot less bits/pixel.
color = max( float3( 0.0 ), color );
color = Srgb3( color );
color = floor( color * Dithering_QuantizationSteps ) * ( 1.0 / ( Dithering_QuantizationSteps - 1.0 ) );
#else
#if 0
if( uv2.x <= 0.5 )
{
@ -486,8 +360,6 @@ void DitheringPass( inout float4 fragColor, PS_IN fragment )
{
color = floor( 0.5 + color * ( Dithering_QuantizationSteps + Dithering_Wide - 1.0 ) + ( -Dithering_Wide * 0.5 ) + Step3T( uv ) * ( Dithering_Wide ) ) * ( 1.0 / ( Dithering_QuantizationSteps - 1.0 ) );
}
#endif
}
fragColor.rgb = color;

View file

@ -0,0 +1,283 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2024 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
Texture2D t_BaseColor : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState samp0 : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState samp1 : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
#define RESOLUTION_DIVISOR 4.0
#define NUM_COLORS 16
float3 Average( float3 pal[NUM_COLORS] )
{
float3 sum = _float3( 0 );
for( int i = 0; i < NUM_COLORS; i++ )
{
sum += pal[i];
}
return sum / float( NUM_COLORS );
}
float3 Deviation( float3 pal[NUM_COLORS] )
{
float3 sum = _float3( 0 );
float3 avg = Average( pal );
for( int i = 0; i < NUM_COLORS; i++ )
{
sum += abs( pal[i] - avg );
}
return sum / float( NUM_COLORS );
}
// squared distance to avoid the sqrt of distance function
float ColorCompare( float3 a, float3 b )
{
float3 diff = b - a;
return dot( diff, diff );
}
// find nearest palette color using Euclidean distance
float3 LinearSearch( float3 c, float3 pal[NUM_COLORS] )
{
int index = 0;
float minDist = ColorCompare( c, pal[0] );
for( int i = 1; i < NUM_COLORS; i++ )
{
float dist = ColorCompare( c, pal[i] );
if( dist < minDist )
{
minDist = dist;
index = i;
}
}
return pal[index];
}
/*
float3 GetClosest( float3 val1, float3 val2, float3 target )
{
if( distance( target, val1 ) >= distance( val2, target ) )
{
return val2;
}
else
{
return val1;
}
}
// find nearest palette color using Euclidean disntance and binary search
// this requires an already sorted palette as input
float3 BinarySearch( float3 target, float3 pal[NUM_COLORS] )
{
float targetY = PhotoLuma( target );
// left-side case
if( targetY <= PhotoLuma( pal[0] ) )
{
return pal[0];
}
// right-side case
if( targetY >= PhotoLuma( pal[NUM_COLORS - 1] ) )
{
return pal[NUM_COLORS - 1];
}
int i = 0, j = NUM_COLORS, mid = 0;
while( i < j )
{
mid = ( i + j ) / 2;
if( distance( pal[mid], target ) < 0.01 )
{
return pal[mid];
}
// if target is less than array element, then search in left
if( targetY < PhotoLuma( pal[mid] ) )
{
// if target is greater than previous
// to mid, return closest of two
if( mid > 0 && targetY > PhotoLuma( pal[mid - 1] ) )
{
return GetClosest( pal[mid - 1], pal[mid], target );
}
j = mid;
}
else
{
if( mid < ( NUM_COLORS - 1 ) && targetY < PhotoLuma( pal[mid + 1] ) )
{
return GetClosest( pal[mid], pal[mid + 1], target );
}
i = mid + 1;
}
}
// only single element left after search
return pal[mid];
}
*/
#define RGB(r, g, b) float3(float(r)/255.0, float(g)/255.0, float(b)/255.0)
void main( PS_IN fragment, out PS_OUT result )
{
// C64 colors http://unusedino.de/ec64/technical/misc/vic656x/colors/
#if 0
const float3 palette[NUM_COLORS] =
{
RGB( 0, 0, 0 ),
RGB( 255, 255, 255 ),
RGB( 116, 67, 53 ),
RGB( 124, 172, 186 ),
RGB( 123, 72, 144 ),
RGB( 100, 151, 79 ),
RGB( 64, 50, 133 ),
RGB( 191, 205, 122 ),
RGB( 123, 91, 47 ),
RGB( 79, 69, 0 ),
RGB( 163, 114, 101 ),
RGB( 80, 80, 80 ),
RGB( 120, 120, 120 ),
RGB( 164, 215, 142 ),
RGB( 120, 106, 189 ),
RGB( 159, 159, 150 ),
};
#else
// gamma corrected version
const float3 palette[NUM_COLORS] =
{
RGB( 0, 0, 0 ), // black
RGB( 255, 255, 255 ), // white
RGB( 104, 55, 43 ), // red
RGB( 112, 164, 178 ), // cyan
RGB( 111, 61, 134 ), // purple
RGB( 88, 141, 67 ), // green
RGB( 53, 40, 121 ), // blue
RGB( 184, 199, 111 ), // yellow
RGB( 111, 79, 37 ), // orange
RGB( 67, 57, 0 ), // brown
RGB( 154, 103, 89 ), // light red
RGB( 68, 68, 68 ), // dark grey
RGB( 108, 108, 108 ), // grey
RGB( 154, 210, 132 ), // light green
RGB( 108, 94, 181 ), // light blue
RGB( 149, 149, 149 ), // light grey
};
#endif
float2 uv = ( fragment.texcoord0 );
float2 uvPixelated = floor( fragment.position.xy / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR;
float3 quantizationPeriod = _float3( 1.0 / NUM_COLORS );
// get pixellated base color
float3 color = t_BaseColor.Sample( samp0, uvPixelated * rpWindowCoord.xy ).rgb;
float2 uvDither = uvPixelated;
//if( rpJitterTexScale.x > 1.0 )
{
uvDither = fragment.position.xy / ( RESOLUTION_DIVISOR / rpJitterTexScale.x );
}
float dither = DitherArray8x8( uvDither ) - 0.5;
#if 0
if( uv.y < 0.0625 )
{
color = HSVToRGB( float3( uv.x, 1.0, uv.y * 16.0 ) );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.125 )
{
// quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.0625 ) * 16.0 ) );
color = LinearSearch( color, palette );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.1875 )
{
// dithered quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) );
color.rgb += float3( dither, dither, dither ) * quantizationPeriod;
color = LinearSearch( color, palette );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.25 )
{
color = _float3( uv.x );
color = floor( color * NUM_COLORS ) * ( 1.0 / ( NUM_COLORS - 1.0 ) );
}
#endif
//color.rgb += float3( dither, dither, dither ) * quantizationPeriod;
color.rgb += float3( dither, dither, dither ) * Deviation( palette ) * rpJitterTexScale.y;
// find closest color match from C64 color palette
color = LinearSearch( color.rgb, palette );
//color = float4( BinarySearch( color.rgb, palette ), 1.0 );
result.color = float4( color, 1.0 );
}

View file

@ -0,0 +1,55 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -0,0 +1,393 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2024 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
Texture2D t_BaseColor : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState samp0 : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState samp1 : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
#define RESOLUTION_DIVISOR 4.0
#define NUM_COLORS 32 // original 27
/*
float LinearTweak1( float c )
{
return ( c <= 0.04045 ) ? c / 12.92 : pow( ( c + 0.055 ) / 1.055, 1.4 );
}
float3 LinearTweak3( float3 c )
{
return float3( Linear1( c.r ), Linear1( c.g ), Linear1( c.b ) );
}
*/
float3 Average( float3 pal[NUM_COLORS] )
{
float3 sum = _float3( 0 );
for( int i = 0; i < NUM_COLORS; i++ )
{
sum += pal[i];
}
return sum / float( NUM_COLORS );
}
float3 Deviation( float3 pal[NUM_COLORS] )
{
float3 sum = _float3( 0 );
float3 avg = Average( pal );
for( int i = 0; i < NUM_COLORS; i++ )
{
sum += abs( pal[i] - avg );
}
return sum / float( NUM_COLORS );
}
// squared distance to avoid the sqrt of distance function
float ColorCompare( float3 a, float3 b )
{
float3 diff = b - a;
return dot( diff, diff );
}
// find nearest palette color using Euclidean distance
float3 LinearSearch( float3 c, float3 pal[NUM_COLORS] )
{
int index = 0;
float minDist = ColorCompare( c, pal[0] );
for( int i = 1; i < NUM_COLORS; i++ )
{
float dist = ColorCompare( c, pal[i] );
if( dist < minDist )
{
minDist = dist;
index = i;
}
}
return pal[index];
}
#define RGB(r, g, b) float3(float(r)/255.0, float(g)/255.0, float(b)/255.0)
void main( PS_IN fragment, out PS_OUT result )
{
#if 0
// Amstrad CPC colors https://www.cpcwiki.eu/index.php/CPC_Palette
const float3 palette[NUM_COLORS] =
{
RGB( 0, 0, 0 ), // black
RGB( 0, 0, 128 ), // blue
RGB( 0, 0, 255 ), // bright blue
RGB( 128, 0, 0 ), // red
RGB( 128, 0, 128 ), // magenta
RGB( 128, 0, 255 ), // mauve
RGB( 255, 0, 0 ), // bright red
RGB( 255, 0, 128 ), // purple
RGB( 255, 0, 255 ), // bright magenta
RGB( 0, 128, 0 ), // green
RGB( 0, 128, 128 ), // cyan
RGB( 0, 128, 255 ), // sky blue
RGB( 128, 128, 0 ), // yellow
RGB( 128, 128, 128 ), // white
RGB( 128, 128, 255 ), // pastel blue
RGB( 255, 128, 0 ), // orange
RGB( 255, 128, 128 ), // pink
RGB( 255, 128, 255 ), // pastel magenta
RGB( 0, 255, 0 ), // bright green
RGB( 0, 255, 128 ), // sea green
RGB( 0, 255, 255 ), // bright cyan
RGB( 128, 255, 0 ), // lime
RGB( 128, 255, 128 ), // pastel green
RGB( 128, 255, 255 ), // pastel cyan
RGB( 255, 255, 0 ), // bright yellow
RGB( 255, 255, 128 ), // pastel yellow
RGB( 255, 255, 255 ), // bright white
#if 1
RGB( 16, 16, 16 ), // black
RGB( 0, 28, 28 ), // dark cyan
RGB( 112, 164, 178 ) * 1.3, // cyan
#endif
};
#elif 1
// Tweaked LOSPEC CPC BOY PALETTE which is less saturated by Arne Niklas Jansson
// https://lospec.com/palette-list/cpc-boy
const float3 palette[NUM_COLORS] = // 32
{
RGB( 0, 0, 0 ),
RGB( 27, 27, 101 ),
RGB( 53, 53, 201 ),
RGB( 102, 30, 37 ),
RGB( 85, 51, 97 ),
RGB( 127, 53, 201 ),
RGB( 188, 53, 53 ),
RGB( 192, 70, 110 ),
RGB( 223, 109, 155 ),
RGB( 27, 101, 27 ),
RGB( 27, 110, 131 ),
RGB( 30, 121, 229 ),
RGB( 121, 95, 27 ),
RGB( 128, 128, 128 ),
RGB( 145, 148, 223 ),
RGB( 201, 127, 53 ),
RGB( 227, 155, 141 ),
RGB( 248, 120, 248 ),
RGB( 53, 175, 53 ),
RGB( 53, 183, 143 ),
RGB( 53, 193, 215 ),
RGB( 127, 201, 53 ),
RGB( 173, 200, 170 ),
RGB( 141, 225, 199 ),
RGB( 225, 198, 67 ),
RGB( 228, 221, 154 ),
RGB( 255, 255, 255 ),
RGB( 238, 234, 224 ),
RGB( 172, 181, 107 ),
RGB( 118, 132, 72 ),
RGB( 63, 80, 63 ),
RGB( 36, 49, 55 ),
};
#elif 0
// NES 1
// https://lospec.com/palette-list/nintendo-entertainment-system
const float3 palette[NUM_COLORS] = // 55
{
RGB( 0, 0, 0 ),
RGB( 252, 252, 252 ),
RGB( 248, 248, 248 ),
RGB( 188, 188, 188 ),
RGB( 124, 124, 124 ),
RGB( 164, 228, 252 ),
RGB( 60, 188, 252 ),
RGB( 0, 120, 248 ),
RGB( 0, 0, 252 ),
RGB( 184, 184, 248 ),
RGB( 104, 136, 252 ),
RGB( 0, 88, 248 ),
RGB( 0, 0, 188 ),
RGB( 216, 184, 248 ),
RGB( 152, 120, 248 ),
RGB( 104, 68, 252 ),
RGB( 68, 40, 188 ),
RGB( 248, 184, 248 ),
RGB( 248, 120, 248 ),
RGB( 216, 0, 204 ),
RGB( 148, 0, 132 ),
RGB( 248, 164, 192 ),
RGB( 248, 88, 152 ),
RGB( 228, 0, 88 ),
RGB( 168, 0, 32 ),
RGB( 240, 208, 176 ),
RGB( 248, 120, 88 ),
RGB( 248, 56, 0 ),
RGB( 168, 16, 0 ),
RGB( 252, 224, 168 ),
RGB( 252, 160, 68 ),
RGB( 228, 92, 16 ),
RGB( 136, 20, 0 ),
RGB( 248, 216, 120 ),
RGB( 248, 184, 0 ),
RGB( 172, 124, 0 ),
RGB( 80, 48, 0 ),
RGB( 216, 248, 120 ),
RGB( 184, 248, 24 ),
RGB( 0, 184, 0 ),
RGB( 0, 120, 0 ),
RGB( 184, 248, 184 ),
RGB( 88, 216, 84 ),
RGB( 0, 168, 0 ),
RGB( 0, 104, 0 ),
RGB( 184, 248, 216 ),
RGB( 88, 248, 152 ),
RGB( 0, 168, 68 ),
RGB( 0, 88, 0 ),
RGB( 0, 252, 252 ),
RGB( 0, 232, 216 ),
RGB( 0, 136, 136 ),
RGB( 0, 64, 88 ),
RGB( 248, 216, 248 ),
RGB( 120, 120, 120 ),
};
#elif 0
const float3 palette[NUM_COLORS] = // 32
{
RGB( 0, 0, 0 ),
RGB( 192, 64, 80 ),
RGB( 240, 240, 240 ),
RGB( 192, 192, 176 ),
RGB( 128, 144, 144 ),
RGB( 96, 96, 112 ),
RGB( 96, 64, 64 ),
RGB( 64, 48, 32 ),
RGB( 112, 80, 48 ),
RGB( 176, 112, 64 ),
RGB( 224, 160, 80 ),
RGB( 224, 192, 128 ),
RGB( 240, 224, 96 ),
RGB( 224, 128, 48 ),
RGB( 208, 80, 32 ),
RGB( 144, 48, 32 ),
RGB( 96, 48, 112 ),
RGB( 176, 96, 160 ),
RGB( 224, 128, 192 ),
RGB( 192, 160, 208 ),
RGB( 112, 112, 192 ),
RGB( 48, 64, 144 ),
RGB( 32, 32, 64 ),
RGB( 32, 96, 208 ),
RGB( 64, 160, 224 ),
RGB( 128, 208, 224 ),
RGB( 160, 240, 144 ),
RGB( 48, 160, 96 ),
RGB( 48, 64, 48 ),
RGB( 48, 112, 32 ),
RGB( 112, 160, 48 ),
RGB( 160, 208, 80 ),
};
#elif 0
// Gameboy
const float3 palette[NUM_COLORS] = // 4
{
RGB( 27, 42, 9 ),
RGB( 14, 69, 11 ),
RGB( 73, 107, 34 ),
RGB( 154, 158, 63 ),
};
#else
// https://lospec.com/palette-list/existential-demo
const float3 palette[NUM_COLORS] = // 8
{
RGB( 248, 243, 253 ),
RGB( 250, 198, 180 ),
RGB( 154, 218, 231 ),
RGB( 151, 203, 29 ),
RGB( 93, 162, 202 ),
RGB( 218, 41, 142 ),
RGB( 11, 134, 51 ),
RGB( 46, 43, 18 ),
};
#endif
float2 uv = ( fragment.texcoord0 );
float2 uvPixelated = floor( fragment.position.xy / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR;
float3 quantizationPeriod = _float3( 1.0 / NUM_COLORS );
float3 quantDeviation = Deviation( palette );
// get pixellated base color
float3 color = t_BaseColor.Sample( samp0, uvPixelated * rpWindowCoord.xy ).rgb;
float2 uvDither = uvPixelated;
//if( rpJitterTexScale.x > 1.0 )
{
uvDither = fragment.position.xy / ( RESOLUTION_DIVISOR / rpJitterTexScale.x );
}
float dither = DitherArray8x8( uvDither ) - 0.5;
#if 0
if( uv.y < 0.0625 )
{
color = HSVToRGB( float3( uv.x, 1.0, uv.y * 16.0 ) );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.125 )
{
// quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.0625 ) * 16.0 ) );
color = LinearSearch( color, palette );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.1875 )
{
// dithered quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) );
color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y;
color = LinearSearch( color, palette );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.25 )
{
color = _float3( uv.x );
color = floor( color * NUM_COLORS ) * ( 1.0 / ( NUM_COLORS - 1.0 ) );
}
#endif
//color.rgb += float3( dither, dither, dither ) * quantizationPeriod;
color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y;
// find closest color match from CPC color palette
color = LinearSearch( color.rgb, palette );
result.color = float4( color, 1.0 );
}

View file

@ -0,0 +1,55 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -0,0 +1,148 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2023 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
Texture2D t_BaseColor : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState samp0 : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState samp1 : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
#define RESOLUTION_DIVISOR 4.0
#define Dithering_QuantizationSteps 8.0 // 8.0 = 2 ^ 3 quantization bits
float3 Quantize( float3 color, float3 period )
{
return floor( color * Dithering_QuantizationSteps ) * ( 1.0 / ( Dithering_QuantizationSteps - 1.0 ) );
//return floor( ( color + period / 2.0 ) / period ) * period;
}
float3 BlueNoise3( float2 n, float x )
{
float2 uv = n.xy * rpJitterTexOffset.xy;
float3 noise = t_BlueNoise.Sample( samp1, uv ).rgb;
noise = frac( noise + c_goldenRatioConjugate * rpJitterTexOffset.w * x );
noise.x = RemapNoiseTriErp( noise.x );
noise.y = RemapNoiseTriErp( noise.y );
noise.z = RemapNoiseTriErp( noise.z );
noise = noise * 2.0 - 1.0;
return noise;
}
#define RGB(r, g, b) float3(float(r)/255.0, float(g)/255.0, float(b)/255.0)
void main( PS_IN fragment, out PS_OUT result )
{
float2 uv = ( fragment.texcoord0 );
float2 uvPixelated = floor( fragment.position.xy / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR;
// the Sega Mega Drive has a 9 bit HW palette making a total of 512 available colors
// that is 3 bit per RGB channel
// 2^3 = 8
// 8 * 8 * 8 = 512 colors
// although only 61 colors were available on the screen at the same time but we ignore this for now
const int quantizationSteps = Dithering_QuantizationSteps;
float3 quantizationPeriod = _float3( 1.0 / ( quantizationSteps - 1 ) );
// get pixellated base color
float3 color = t_BaseColor.Sample( samp0, uvPixelated * rpWindowCoord.xy ).rgb;
float2 uvDither = uvPixelated;
//if( rpJitterTexScale.x > 1.0 )
{
uvDither = fragment.position.xy / ( RESOLUTION_DIVISOR / rpJitterTexScale.x );
}
float dither = DitherArray8x8( uvDither ) - 0.5;
#if 0
if( uv.y < 0.0625 )
{
color = HSVToRGB( float3( uv.x, 1.0, uv.y * 16.0 ) );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.125 )
{
// quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.0625 ) * 16.0 ) );
color = Quantize( color, quantizationPeriod );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.1875 )
{
// dithered quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) );
color.rgb += float3( dither, dither, dither ) * quantizationPeriod;
color = Quantize( color, quantizationPeriod );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.25 )
{
color = _float3( uv.x );
color = Quantize( color, quantizationPeriod );
}
#endif
color.rgb += float3( dither, dither, dither ) * quantizationPeriod;// * rpJitterTexScale.y;
// find closest color match from Sega Mega Drive color palette
color = Quantize( color, quantizationPeriod );
result.color = float4( color, 1.0 );
}

View file

@ -0,0 +1,55 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -0,0 +1,129 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2023 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
Texture2D t_BaseColor : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState samp0 : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState samp1 : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
#define RESOLUTION_DIVISOR 4.0
#define Dithering_QuantizationSteps 32.0 // 8.0 = 2 ^ 3 quantization bits
float3 Quantize( float3 color, float3 period )
{
return floor( color * Dithering_QuantizationSteps ) * ( 1.0 / ( Dithering_QuantizationSteps - 1.0 ) );
//return floor( ( color + period / 2.0 ) / period ) * period;
}
void main( PS_IN fragment, out PS_OUT result )
{
float2 uv = ( fragment.texcoord0 );
float2 uvPixelated = floor( fragment.position.xy / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR;
// most Sony Playstation 1 titles used 5 bit per RGB channel
// 2^5 = 32
// 32 * 32 * 32 = 32768 colors
const int quantizationSteps = Dithering_QuantizationSteps;
float3 quantizationPeriod = _float3( 1.0 / ( quantizationSteps - 1 ) );
// get pixellated base color
float3 color = t_BaseColor.Sample( samp0, uvPixelated * rpWindowCoord.xy ).rgb;
// add Bayer 8x8 dithering
float2 uvDither = fragment.position.xy / RESOLUTION_DIVISOR;
float dither = DitherArray8x8( uvDither ) - 0.5;
#if 0
if( uv.y < 0.0625 )
{
color = HSVToRGB( float3( uv.x, 1.0, uv.y * 16.0 ) );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.125 )
{
// quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.0625 ) * 16.0 ) );
color = Quantize( color, quantizationPeriod );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.1875 )
{
// dithered quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) );
color.rgb += float3( dither, dither, dither ) * quantizationPeriod;
color = Quantize( color, quantizationPeriod );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.25 )
{
color = _float3( uv.x );
color = Quantize( color, quantizationPeriod );
}
#endif
color.rgb += float3( dither, dither, dither ) * quantizationPeriod;
// PSX color quantization with 15-bit
color = Quantize( color, quantizationPeriod );
//color = t_BaseColor.Sample( samp0, uv ).rgb;
result.color = float4( color, 1.0 );
}

View file

@ -0,0 +1,55 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -244,6 +244,43 @@ float4 LinearRGBToSRGB( float4 c )
#endif
}
float3 HSVToRGB( float3 HSV )
{
float3 RGB = HSV.z;
float var_h = HSV.x * 6;
float var_i = floor( var_h ); // Or ... var_i = floor( var_h )
float var_1 = HSV.z * ( 1.0 - HSV.y );
float var_2 = HSV.z * ( 1.0 - HSV.y * ( var_h - var_i ) );
float var_3 = HSV.z * ( 1.0 - HSV.y * ( 1 - ( var_h - var_i ) ) );
if( var_i == 0 )
{
RGB = float3( HSV.z, var_3, var_1 );
}
else if( var_i == 1 )
{
RGB = float3( var_2, HSV.z, var_1 );
}
else if( var_i == 2 )
{
RGB = float3( var_1, HSV.z, var_3 );
}
else if( var_i == 3 )
{
RGB = float3( var_1, var_2, HSV.z );
}
else if( var_i == 4 )
{
RGB = float3( var_3, var_1, HSV.z );
}
else
{
RGB = float3( HSV.z, var_1, var_2 );
}
return ( RGB );
}
/** Efficient GPU implementation of the octahedral unit vector encoding from
Cigolle, Donow, Evangelakos, Mara, McGuire, Meyer,
@ -366,6 +403,7 @@ float rand( float2 co )
#define _float3( x ) float3( x, x, x )
#define _float4( x ) float4( x, x, x, x )
#define _int2( x ) int2( x, x )
#define _int3( x ) int3( x, x, x )
#define vec2 float2
#define vec3 float3
#define vec4 float4
@ -488,14 +526,44 @@ float InterleavedGradientNoiseAnim( float2 uv, float frameIndex )
return rnd;
}
// RB: very efficient white noise without sine https://www.shadertoy.com/view/4djSRW
#define HASHSCALE3 float3(443.897, 441.423, 437.195)
float3 Hash33( float3 p3 )
float R2Noise( float2 uv )
{
p3 = frac( p3 * HASHSCALE3 );
p3 += dot( p3, p3.yxz + 19.19 );
return frac( ( p3.xxy + p3.yxx ) * p3.zyx );
const float a1 = 0.75487766624669276;
const float a2 = 0.569840290998;
return frac( a1 * float( uv.x ) + a2 * float( uv.y ) );
}
// array/table version from http://www.anisopteragames.com/how-to-fix-color-banding-with-dithering/
static const uint ArrayDitherArray8x8[] =
{
0, 32, 8, 40, 2, 34, 10, 42, /* 8x8 Bayer ordered dithering */
48, 16, 56, 24, 50, 18, 58, 26, /* pattern. Each input pixel */
12, 44, 4, 36, 14, 46, 6, 38, /* is scaled to the 0..63 range */
60, 28, 52, 20, 62, 30, 54, 22, /* before looking in this table */
3, 35, 11, 43, 1, 33, 9, 41, /* to determine the action. */
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21
};
float DitherArray8x8( float2 pos )
{
uint stippleOffset = ( ( uint )pos.y % 8 ) * 8 + ( ( uint )pos.x % 8 );
uint byte = ArrayDitherArray8x8[stippleOffset];
float stippleThreshold = byte / 64.0f;
return stippleThreshold;
}
float DitherArray8x8Anim( float2 pos, int frameIndexMod4 )
{
pos += int2( frameIndexMod4 % 2, frameIndexMod4 / 2 ) * uint2( 5, 5 );
uint stippleOffset = ( ( uint )pos.y % 8 ) * 8 + ( ( uint )pos.x % 8 );
uint byte = ArrayDitherArray8x8[stippleOffset];
float stippleThreshold = byte / 64.0f;
return stippleThreshold;
}
#define SMAA_RT_METRICS float4(1.0 / 1280.0, 1.0 / 720.0, 1280.0, 720.0)

View file

@ -52,6 +52,18 @@ builtin/lighting/interactionSM.ps.hlsl -T ps -D USE_GPU_SKINNING={0,1} -D LIGHT_
builtin/post/postprocess.vs.hlsl -T vs
builtin/post/postprocess.ps.hlsl -T ps
builtin/post/retro_c64.vs.hlsl -T vs
builtin/post/retro_c64.ps.hlsl -T ps
builtin/post/retro_cpc.vs.hlsl -T vs
builtin/post/retro_cpc.ps.hlsl -T ps
builtin/post/retro_genesis.vs.hlsl -T vs
builtin/post/retro_genesis.ps.hlsl -T ps
builtin/post/retro_ps1.vs.hlsl -T vs
builtin/post/retro_ps1.ps.hlsl -T ps
builtin/post/crt_mattias.vs.hlsl -T vs
builtin/post/crt_mattias.ps.hlsl -T ps
builtin/post/crt_newpixie.vs.hlsl -T vs
builtin/post/crt_newpixie.ps.hlsl -T ps
builtin/post/screen.vs.hlsl -T vs
builtin/post/screen.ps.hlsl -T ps
builtin/post/tonemap.vs.hlsl -T vs -D BRIGHTPASS={0,1} -D HDR_DEBUG={0,1}

View file

@ -27,6 +27,7 @@
#include "renderer/RenderCommon.h"
#include "renderer/RenderSystem.h"
#include "framework/Common_local.h"
#include <sys/DeviceManager.h>
#include <Windows.h>
@ -57,7 +58,7 @@ class DeviceManager_DX12 : public DeviceManager
RefCountPtr<IDXGISwapChain3> m_SwapChain;
DXGI_SWAP_CHAIN_DESC1 m_SwapChainDesc{};
DXGI_SWAP_CHAIN_FULLSCREEN_DESC m_FullScreenDesc{};
RefCountPtr<IDXGIAdapter> m_DxgiAdapter;
RefCountPtr<IDXGIAdapter3> m_DxgiAdapter;
bool m_TearingSupported = false;
std::vector<RefCountPtr<ID3D12Resource>> m_SwapChainBuffers;
@ -388,7 +389,7 @@ bool DeviceManager_DX12::CreateDeviceAndSwapChain()
}
}
m_DxgiAdapter = targetAdapter;
targetAdapter->QueryInterface( IID_PPV_ARGS( &m_DxgiAdapter ) );
D3D12_COMMAND_QUEUE_DESC queueDesc;
ZeroMemory( &queueDesc, sizeof( queueDesc ) );
@ -566,6 +567,12 @@ void DeviceManager_DX12::ResizeSwapChain()
void DeviceManager_DX12::BeginFrame()
{
OPTICK_CATEGORY( "DX12_BeginFrame", Optick::Category::Wait );
// SRS - get DXGI GPU memory usage for display in statistics overlay HUD
DXGI_QUERY_VIDEO_MEMORY_INFO memoryInfoLocal = {}, memoryInfoNonLocal = {};
m_DxgiAdapter->QueryVideoMemoryInfo( 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memoryInfoLocal );
m_DxgiAdapter->QueryVideoMemoryInfo( 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &memoryInfoNonLocal );
commonLocal.SetRendererGpuMemoryMB( int( ( memoryInfoLocal.CurrentUsage + memoryInfoNonLocal.CurrentUsage ) / 1024 / 1024 ) );
}
nvrhi::ITexture* DeviceManager_DX12::GetCurrentBackBuffer()

View file

@ -32,6 +32,7 @@
#include <unordered_set>
#include "renderer/RenderCommon.h"
#include "framework/Common_local.h"
#include <sys/DeviceManager.h>
#include <nvrhi/vulkan.h>
@ -39,12 +40,22 @@
#include <vulkan/vulkan.hpp>
// SRS - optionally needed for MoltenVK runtime config visibility
#if defined(__APPLE__) && defined( USE_MoltenVK )
#include <MoltenVK/vk_mvk_moltenvk.h>
idCVar r_mvkSynchronousQueueSubmits( "r_mvkSynchronousQueueSubmits", "0", CVAR_BOOL | CVAR_INIT, "Use MoltenVK's synchronous queue submit option." );
#if defined(__APPLE__)
#if defined( USE_MoltenVK )
#if 0
#include <MoltenVK/mvk_vulkan.h>
#include <MoltenVK/mvk_config.h> // SRS - will eventually move to these mvk include files for MoltenVK >= 1.2.7 / SDK >= 1.3.275.0
#else
#include <MoltenVK/vk_mvk_moltenvk.h> // SRS - now deprecated, but provides backwards compatibility for MoltenVK < 1.2.7 / SDK < 1.3.275.0
#endif
#endif
#if defined( VK_EXT_layer_settings ) || defined( USE_MoltenVK )
idCVar r_mvkSynchronousQueueSubmits( "r_mvkSynchronousQueueSubmits", "0", CVAR_BOOL | CVAR_INIT, "Use MoltenVK's synchronous queue submit option." );
idCVar r_mvkUseMetalArgumentBuffers( "r_mvkUseMetalArgumentBuffers", "2", CVAR_INTEGER | CVAR_INIT, "Use MoltenVK's Metal argument buffers option (0=Off, 1=Always On, 2=On when VK_EXT_descriptor_indexing enabled)", 0, 2 );
#endif
#endif
#include <nvrhi/validation.h>
#include <libs/optick/optick.h>
#if defined( USE_AMD_ALLOCATOR )
#define VMA_IMPLEMENTATION
@ -204,20 +215,21 @@ private:
{
// instance
{
#if defined(__APPLE__) && defined( VK_KHR_portability_enumeration )
#if defined(__APPLE__)
#if defined( VK_KHR_portability_enumeration )
// SRS - This is optional since it only became manadatory with Vulkan SDK 1.3.216.0 or later
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
#endif
#if defined( VK_EXT_layer_settings )
// SRS - This is optional since implemented only for MoltenVK 1.2.7 / SDK 1.3.275.0 or later
VK_EXT_LAYER_SETTINGS_EXTENSION_NAME,
#endif
#endif
VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME,
VK_EXT_DEBUG_UTILS_EXTENSION_NAME
},
// layers
{
#if defined(__APPLE__)
// SRS - synchronization2 not supported natively on MoltenVK, use layer implementation instead
"VK_LAYER_KHRONOS_synchronization2"
#endif
},
{ },
// device
{
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
@ -228,7 +240,11 @@ private:
#if USE_OPTICK
VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
#endif
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME
#if defined( VK_KHR_format_feature_flags2 )
VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME,
#endif
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
VK_EXT_MEMORY_BUDGET_EXTENSION_NAME
},
};
@ -275,7 +291,7 @@ private:
nvrhi::vulkan::DeviceHandle m_NvrhiDevice;
nvrhi::DeviceHandle m_ValidationLayer;
nvrhi::CommandListHandle m_BarrierCommandList;
//nvrhi::CommandListHandle m_BarrierCommandList; // SRS - no longer needed
std::queue<vk::Semaphore> m_PresentSemaphoreQueue;
vk::Semaphore m_PresentSemaphore;
@ -289,6 +305,19 @@ private:
// SRS - flag indicating support for presentation timing via VK_GOOGLE_display_timing extension
bool displayTimingEnabled = false;
// SRS - slot for Vulkan device API version at runtime (initialize to Vulkan build version)
uint32_t m_DeviceApiVersion = VK_HEADER_VERSION_COMPLETE;
// SRS - function pointer for initing Vulkan DynamicLoader, VMA, Optick, and MoltenVK functions
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;
#if defined(__APPLE__) && defined( USE_MoltenVK )
#if MVK_VERSION >= MVK_MAKE_VERSION( 1, 2, 6 )
// SRS - function pointer for retrieving MoltenVK advanced performance statistics
PFN_vkGetPerformanceStatisticsMVK vkGetPerformanceStatisticsMVK = nullptr;
#endif
#endif
private:
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkanDebugCallback(
VkDebugReportFlagsEXT flags,
@ -429,6 +458,7 @@ bool DeviceManager_VK::createInstance()
std::unordered_set<std::string> requiredLayers = enabledExtensions.layers;
auto instanceVersion = vk::enumerateInstanceVersion();
for( const auto& layer : vk::enumerateInstanceLayerProperties() )
{
const std::string name = layer.layerName;
@ -436,6 +466,13 @@ bool DeviceManager_VK::createInstance()
{
enabledExtensions.layers.insert( name );
}
#if defined(__APPLE__) && !defined( USE_MoltenVK )
// SRS - Vulkan SDK < 1.3.268.1 does not have native VK_KHR_synchronization2 support on macOS, add Khronos layer to emulate
else if( name == "VK_LAYER_KHRONOS_synchronization2" && instanceVersion < VK_MAKE_API_VERSION( 0, 1, 3, 268 ) )
{
enabledExtensions.layers.insert( name );
}
#endif
requiredLayers.erase( name );
}
@ -473,11 +510,68 @@ bool DeviceManager_VK::createInstance()
.setPpEnabledExtensionNames( instanceExtVec.data() )
.setPApplicationInfo( &applicationInfo );
#if defined(__APPLE__) && defined( VK_KHR_portability_enumeration )
#if defined(__APPLE__)
#if defined( VK_KHR_portability_enumeration )
if( enabledExtensions.instance.find( VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME ) != enabledExtensions.instance.end() )
{
info.setFlags( vk::InstanceCreateFlagBits( VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR ) );
}
#endif
#if defined( VK_EXT_layer_settings )
// SRS - set MoltenVK runtime configuration parameters on macOS via standardized VK_EXT_layer_settings extension
std::vector<vk::LayerSettingEXT> layerSettings;
vk::LayerSettingsCreateInfoEXT layerSettingsCreateInfo;
const vk::Bool32 valueTrue = vk::True, valueFalse = vk::False;
const int32_t useMetalArgumentBuffers = r_mvkUseMetalArgumentBuffers.GetInteger();
const float timestampPeriodLowPassAlpha = 1.0;
if( enabledExtensions.instance.find( VK_EXT_LAYER_SETTINGS_EXTENSION_NAME ) != enabledExtensions.instance.end() )
{
// SRS - use MoltenVK layer for configuration via VK_EXT_layer_settings extension
vk::LayerSettingEXT layerSetting = { "MoltenVK", "", vk::LayerSettingTypeEXT( 0 ), 1, nullptr };
// SRS - Set MoltenVK's synchronous queue submit option for vkQueueSubmit() & vkQueuePresentKHR()
layerSetting.pSettingName = "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS";
layerSetting.type = vk::LayerSettingTypeEXT::eBool32;
layerSetting.pValues = r_mvkSynchronousQueueSubmits.GetBool() ? &valueTrue : &valueFalse;
layerSettings.push_back( layerSetting );
// SRS - Enable MoltenVK's image view swizzle feature in case we don't have native image view swizzle
layerSetting.pSettingName = "MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE";
layerSetting.type = vk::LayerSettingTypeEXT::eBool32;
layerSetting.pValues = &valueTrue;
layerSettings.push_back( layerSetting );
// SRS - Turn MoltenVK's Metal argument buffer feature on for descriptor indexing only
layerSetting.pSettingName = "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS";
layerSetting.type = vk::LayerSettingTypeEXT::eInt32;
layerSetting.pValues = &useMetalArgumentBuffers;
layerSettings.push_back( layerSetting );
// SRS - Disable MoltenVK's timestampPeriod filter for HUD / Optick profiler timing calibration
layerSetting.pSettingName = "MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA";
layerSetting.type = vk::LayerSettingTypeEXT::eFloat32;
layerSetting.pValues = &timestampPeriodLowPassAlpha;
layerSettings.push_back( layerSetting );
// SRS - Only enable MoltenVK performance tracking if using API and available based on version
#if defined( USE_MoltenVK )
#if MVK_VERSION >= MVK_MAKE_VERSION( 1, 2, 6 )
// SRS - Enable MoltenVK's performance tracking for display of Metal encoding timer on macOS
layerSetting.pSettingName = "MVK_CONFIG_PERFORMANCE_TRACKING";
layerSetting.type = vk::LayerSettingTypeEXT::eBool32;
layerSetting.pValues = &valueTrue;
layerSettings.push_back( layerSetting );
#endif
#endif
layerSettingsCreateInfo.settingCount = uint32_t( layerSettings.size() );
layerSettingsCreateInfo.pSettings = layerSettings.data();
info.setPNext( &layerSettingsCreateInfo );
}
#endif
#endif
const vk::Result res = vk::createInstance( &info, nullptr, &m_VulkanInstance );
@ -823,10 +917,17 @@ bool DeviceManager_VK::createDevice()
auto meshletFeatures = vk::PhysicalDeviceMeshShaderFeaturesNV()
.setTaskShader( true )
.setMeshShader( true );
// SRS - get/set shading rate features which are detected individually by nvrhi (not just at extension level)
vk::PhysicalDeviceFeatures2 actualDeviceFeatures2;
vk::PhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures;
actualDeviceFeatures2.pNext = &fragmentShadingRateFeatures;
m_VulkanPhysicalDevice.getFeatures2( &actualDeviceFeatures2 );
auto vrsFeatures = vk::PhysicalDeviceFragmentShadingRateFeaturesKHR()
.setPipelineFragmentShadingRate( true )
.setPrimitiveFragmentShadingRate( true )
.setAttachmentFragmentShadingRate( true );
.setPipelineFragmentShadingRate( fragmentShadingRateFeatures.pipelineFragmentShadingRate )
.setPrimitiveFragmentShadingRate( fragmentShadingRateFeatures.primitiveFragmentShadingRate )
.setAttachmentFragmentShadingRate( fragmentShadingRateFeatures.attachmentFragmentShadingRate );
auto sync2Features = vk::PhysicalDeviceSynchronization2FeaturesKHR()
.setSynchronization2( true );
@ -854,7 +955,7 @@ bool DeviceManager_VK::createDevice()
auto deviceFeatures = vk::PhysicalDeviceFeatures()
.setShaderImageGatherExtended( true )
.setShaderStorageImageReadWithoutFormat( true )
.setShaderStorageImageReadWithoutFormat( actualDeviceFeatures2.features.shaderStorageImageReadWithoutFormat )
.setSamplerAnisotropy( true )
.setTessellationShader( true )
.setTextureCompressionBC( true )
@ -927,15 +1028,16 @@ bool DeviceManager_VK::createDevice()
enablePModeImmediate = find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eImmediate ) != surfacePModes.end();
enablePModeFifoRelaxed = find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eFifoRelaxed ) != surfacePModes.end();
// stash the renderer string
// stash the device renderer string and api version
auto prop = m_VulkanPhysicalDevice.getProperties();
m_RendererString = std::string( prop.deviceName.data() );
m_DeviceApiVersion = prop.apiVersion;
#if defined( USE_AMD_ALLOCATOR )
// SRS - initialize the vma allocator
VmaVulkanFunctions vulkanFunctions = {};
vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr;
vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
vulkanFunctions.vkGetDeviceProcAddr = ( PFN_vkGetDeviceProcAddr )vkGetInstanceProcAddr( m_VulkanInstance, "vkGetDeviceProcAddr" );
VmaAllocatorCreateInfo allocatorCreateInfo = {};
allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2;
@ -1105,7 +1207,6 @@ bool DeviceManager_VK::CreateDeviceAndSwapChain()
{
enabledExtensions.instance.insert( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
#if defined(__APPLE__) && defined( USE_MoltenVK )
enabledExtensions.layers.insert( "MoltenVK" );
}
// SRS - when USE_MoltenVK defined, load libMoltenVK vs. the default libvulkan
@ -1117,8 +1218,7 @@ bool DeviceManager_VK::CreateDeviceAndSwapChain()
// SRS - make static so ~DynamicLoader() does not prematurely unload vulkan dynamic lib
static const vk::DynamicLoader dl;
#endif
const PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = // NOLINT(misc-misplaced-const)
dl.getProcAddress<PFN_vkGetInstanceProcAddr>( "vkGetInstanceProcAddr" );
vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>( "vkGetInstanceProcAddr" );
VULKAN_HPP_DEFAULT_DISPATCHER.init( vkGetInstanceProcAddr );
#define CHECK(a) if (!(a)) { return false; }
@ -1153,37 +1253,70 @@ bool DeviceManager_VK::CreateDeviceAndSwapChain()
CHECK( pickPhysicalDevice() );
CHECK( findQueueFamilies( m_VulkanPhysicalDevice, m_WindowSurface ) );
// SRS - when USE_MoltenVK defined, set MoltenVK runtime configuration parameters on macOS
// SRS - when USE_MoltenVK defined, set MoltenVK runtime configuration parameters on macOS (deprecated version)
#if defined(__APPLE__) && defined( USE_MoltenVK )
vk::PhysicalDeviceFeatures2 deviceFeatures2;
vk::PhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures;
deviceFeatures2.setPNext( &portabilityFeatures );
m_VulkanPhysicalDevice.getFeatures2( &deviceFeatures2 );
MVKConfiguration pConfig;
size_t pConfigSize = sizeof( pConfig );
vkGetMoltenVKConfigurationMVK( m_VulkanInstance, &pConfig, &pConfigSize );
// SRS - Set MoltenVK's synchronous queue submit option for vkQueueSubmit() & vkQueuePresentKHR()
pConfig.synchronousQueueSubmits = r_mvkSynchronousQueueSubmits.GetBool() ? VK_TRUE : VK_FALSE;
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &pConfig, &pConfigSize );
// SRS - If we don't have native image view swizzle, enable MoltenVK's image view swizzle feature
if( portabilityFeatures.imageViewFormatSwizzle == VK_FALSE )
#if defined( VK_EXT_layer_settings )
// SRS - for backwards compatibility at runtime: execute only if we can't find the VK_EXT_layer_settings extension
if( enabledExtensions.instance.find( VK_EXT_LAYER_SETTINGS_EXTENSION_NAME ) == enabledExtensions.instance.end() )
#endif
{
idLib::Printf( "Enabling MoltenVK's image view swizzle...\n" );
pConfig.fullImageViewSwizzle = VK_TRUE;
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &pConfig, &pConfigSize );
// SRS - vkSetMoltenVKConfigurationMVK() now deprecated, but retained for MoltenVK < 1.2.7 / SDK < 1.3.275.0
const PFN_vkGetMoltenVKConfigurationMVK vkGetMoltenVKConfigurationMVK = // NOLINT(misc-misplaced-const)
( PFN_vkGetMoltenVKConfigurationMVK )vkGetInstanceProcAddr( m_VulkanInstance, "vkGetMoltenVKConfigurationMVK" );
const PFN_vkSetMoltenVKConfigurationMVK vkSetMoltenVKConfigurationMVK = // NOLINT(misc-misplaced-const)
( PFN_vkSetMoltenVKConfigurationMVK )vkGetInstanceProcAddr( m_VulkanInstance, "vkSetMoltenVKConfigurationMVK" );
vk::PhysicalDeviceFeatures2 deviceFeatures2;
vk::PhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures;
deviceFeatures2.setPNext( &portabilityFeatures );
m_VulkanPhysicalDevice.getFeatures2( &deviceFeatures2 );
MVKConfiguration mvkConfig;
size_t mvkConfigSize = sizeof( mvkConfig );
vkGetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
// SRS - Set MoltenVK's synchronous queue submit option for vkQueueSubmit() & vkQueuePresentKHR()
if( mvkConfig.synchronousQueueSubmits == VK_TRUE && !r_mvkSynchronousQueueSubmits.GetBool() )
{
idLib::Printf( "Disabled MoltenVK's synchronous queue submits...\n" );
mvkConfig.synchronousQueueSubmits = VK_FALSE;
}
// SRS - If we don't have native image view swizzle, enable MoltenVK's image view swizzle feature
if( portabilityFeatures.imageViewFormatSwizzle == VK_FALSE )
{
idLib::Printf( "Enabled MoltenVK's image view swizzle...\n" );
mvkConfig.fullImageViewSwizzle = VK_TRUE;
}
// SRS - Set MoltenVK's Metal argument buffer option for descriptor resource scaling
// - Also needed for Vulkan SDK 1.3.268.1 to work around SPIRV-Cross issue for Metal conversion.
// - See https://github.com/KhronosGroup/MoltenVK/issues/2016 and https://github.com/goki/vgpu/issues/9
// - Issue solved in Vulkan SDK >= 1.3.275.0, but config uses VK_EXT_layer_settings instead of this code.
if( mvkConfig.useMetalArgumentBuffers == MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER && r_mvkUseMetalArgumentBuffers.GetInteger() )
{
idLib::Printf( "Enabled MoltenVK's Metal argument buffers...\n" );
mvkConfig.useMetalArgumentBuffers = MVKUseMetalArgumentBuffers( r_mvkUseMetalArgumentBuffers.GetInteger() );
}
#if MVK_VERSION >= MVK_MAKE_VERSION( 1, 2, 6 )
if( mvkConfig.apiVersionToAdvertise >= VK_MAKE_API_VERSION( 0, 1, 2, 268 ) )
{
// SRS - Disable MoltenVK's timestampPeriod filter for HUD / Optick profiler timing calibration
mvkConfig.timestampPeriodLowPassAlpha = 1.0;
// SRS - Enable MoltenVK's performance tracking for display of Metal encoding timer on macOS
mvkConfig.performanceTracking = VK_TRUE;
}
#endif
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
}
// SRS - Turn MoltenVK's Metal argument buffer feature on for descriptor indexing only
if( pConfig.useMetalArgumentBuffers == MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER )
{
idLib::Printf( "Enabling MoltenVK's Metal argument buffers for descriptor indexing...\n" );
pConfig.useMetalArgumentBuffers = MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING;
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &pConfig, &pConfigSize );
}
#if MVK_VERSION >= MVK_MAKE_VERSION( 1, 2, 6 )
// SRS - Get function pointer for retrieving MoltenVK advanced performance statistics in DeviceManager_VK::BeginFrame()
vkGetPerformanceStatisticsMVK = ( PFN_vkGetPerformanceStatisticsMVK )vkGetInstanceProcAddr( m_VulkanInstance, "vkGetPerformanceStatisticsMVK" );
#endif
#endif
CHECK( createDevice() );
@ -1223,7 +1356,7 @@ bool DeviceManager_VK::CreateDeviceAndSwapChain()
CHECK( createSwapChain() );
m_BarrierCommandList = m_NvrhiDevice->createCommandList();
//m_BarrierCommandList = m_NvrhiDevice->createCommandList(); // SRS - no longer needed
// SRS - Give each swapchain image its own semaphore in case of overlap (e.g. MoltenVK async queue submit)
for( int i = 0; i < m_SwapChainImages.size(); i++ )
@ -1237,7 +1370,11 @@ bool DeviceManager_VK::CreateDeviceAndSwapChain()
#undef CHECK
OPTICK_GPU_INIT_VULKAN( ( VkDevice* )&m_VulkanDevice, ( VkPhysicalDevice* )&m_VulkanPhysicalDevice, ( VkQueue* )&m_GraphicsQueue, ( uint32_t* )&m_GraphicsQueueFamily, 1, nullptr );
#if USE_OPTICK
const Optick::VulkanFunctions optickVulkanFunctions = { ( PFN_vkGetInstanceProcAddr_ )vkGetInstanceProcAddr };
#endif
OPTICK_GPU_INIT_VULKAN( ( VkInstance )m_VulkanInstance, ( VkDevice* )&m_VulkanDevice, ( VkPhysicalDevice* )&m_VulkanPhysicalDevice, ( VkQueue* )&m_GraphicsQueue, ( uint32_t* )&m_GraphicsQueueFamily, 1, &optickVulkanFunctions );
return true;
}
@ -1260,7 +1397,7 @@ void DeviceManager_VK::DestroyDeviceAndSwapChain()
}
m_PresentSemaphore = vk::Semaphore();
m_BarrierCommandList = nullptr;
//m_BarrierCommandList = nullptr; // SRS - no longer needed
destroySwapChain();
@ -1308,6 +1445,45 @@ void DeviceManager_VK::DestroyDeviceAndSwapChain()
void DeviceManager_VK::BeginFrame()
{
OPTICK_CATEGORY( "Vulkan_BeginFrame", Optick::Category::Wait );
#if defined(__APPLE__) && defined( USE_MoltenVK )
#if MVK_VERSION >= MVK_MAKE_VERSION( 1, 2, 6 )
if( vkGetPerformanceStatisticsMVK && m_DeviceApiVersion >= VK_MAKE_API_VERSION( 0, 1, 2, 268 ) )
{
// SRS - get MoltenVK's Metal encoding time and GPU memory usage for display in statistics overlay HUD
MVKPerformanceStatistics mvkPerfStats;
size_t mvkPerfStatsSize = sizeof( mvkPerfStats );
vkGetPerformanceStatisticsMVK( m_VulkanDevice, &mvkPerfStats, &mvkPerfStatsSize );
commonLocal.SetRendererMvkEncodeMicroseconds( uint64( Max( 0.0, mvkPerfStats.queue.submitCommandBuffers.latest - mvkPerfStats.queue.retrieveCAMetalDrawable.latest ) * 1000.0 ) );
commonLocal.SetRendererGpuMemoryMB( int( mvkPerfStats.device.gpuMemoryAllocated.latest / 1024.0 ) );
}
else
#endif
#endif
{
// SRS - get Vulkan GPU memory usage for display in statistics overlay HUD
vk::PhysicalDeviceMemoryProperties2 memoryProperties2;
vk::PhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget;
memoryProperties2.pNext = &memoryBudget;
m_VulkanPhysicalDevice.getMemoryProperties2( &memoryProperties2 );
VkDeviceSize gpuMemoryAllocated = 0;
for( uint32_t i = 0; i < memoryProperties2.memoryProperties.memoryHeapCount; i++ )
{
gpuMemoryAllocated += memoryBudget.heapUsage[i];
#if defined(__APPLE__)
// SRS - macOS Vulkan API <= 1.2.268 has heap reporting defect, use heapUsage[0] only
if( m_DeviceApiVersion <= VK_MAKE_API_VERSION( 0, 1, 2, 268 ) )
{
break;
}
#endif
}
commonLocal.SetRendererGpuMemoryMB( int( gpuMemoryAllocated / 1024 / 1024 ) );
}
const vk::Result res = m_VulkanDevice.acquireNextImageKHR( m_SwapChain,
std::numeric_limits<uint64_t>::max(), // timeout
m_PresentSemaphore,
@ -1323,9 +1499,10 @@ void DeviceManager_VK::EndFrame()
{
m_NvrhiDevice->queueSignalSemaphore( nvrhi::CommandQueue::Graphics, m_PresentSemaphore, 0 );
m_BarrierCommandList->open(); // umm...
m_BarrierCommandList->close();
m_NvrhiDevice->executeCommandList( m_BarrierCommandList );
// SRS - Don't need barrier commandlist if EndFrame() is called before executeCommandList() in idRenderBackend::GL_EndFrame()
//m_BarrierCommandList->open(); // umm...
//m_BarrierCommandList->close();
//m_NvrhiDevice->executeCommandList( m_BarrierCommandList );
}
void DeviceManager_VK::Present()

View file

@ -452,6 +452,8 @@ main
*/
int main( int argc, const char** argv )
{
extern idCVar r_useGPUSkinning;
// DG: needed for Sys_ReLaunch()
cmdargc = argc;
cmdargv = argv;
@ -481,6 +483,21 @@ int main( int argc, const char** argv )
common->Init( 0, NULL, NULL );
}
// SRS - Determine the machine name, e.g. "x86_64" or "arm64"
// Might be cleaner in posix Sys_Init(), but only needed on
// macOS and all the required sys includes are located here.
size_t size;
sysctlbyname( "hw.machine", NULL, &size, NULL, 0 );
char* machineName = ( char* )Mem_Alloc( size, TAG_SYSTEM );
sysctlbyname( "hw.machine", machineName, &size, NULL, 0 );
// FIXME: On Apple Silicon disable GPU skinning to eliminate rendering artifacts
if( strcmp( machineName, "arm64" ) == 0 )
{
r_useGPUSkinning.SetInteger( 0 );
}
Mem_Free( machineName );
Posix_LateInit();
while( 1 )