bDebugColor

bDebugColor

#Overview

name: bDebugColor

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

It is referenced in 14 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of bDebugColor is to enable a debug feature that fills encoded textures with solid colors depending on their BCN (Block Compression) format. This is primarily used for visual identification and debugging of texture compression in Unreal Engine.

bDebugColor is used within the TextureFormatOodle plugin, which is responsible for texture compression using the Oodle technology. This setting affects the texture encoding process in Unreal Engine’s rendering system.

The value of this variable is typically set in the engine configuration files (GEngineIni) under the [TextureFormatOodleSettings] section. It can also be overridden via command line arguments using “-OodleDebugColor”.

This variable interacts with other texture compression settings, particularly those related to Rate Distortion Optimization (RDO) and BCN formats.

Developers should be aware that enabling bDebugColor will significantly alter the appearance of textures in the engine, as it replaces actual texture data with solid colors. This should only be used for debugging purposes and not in production builds.

Best practices for using this variable include:

  1. Use it temporarily for debugging texture compression issues.
  2. Disable it before creating production builds.
  3. Combine it with other Oodle texture debugging tools for comprehensive texture format analysis.
  4. Be cautious when using it in conjunction with other texture-related debug features to avoid conflicting visual feedback.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEngine.ini:3444, section: [TextureFormatOodleSettings]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:80

Scope: file

Source code excerpt:


[TextureFormatOodleSettings]
bDebugColor=False
GlobalLambdaMultiplier=1.0

The sense of the bools is set so that all-false is default behavior.

bDebugColor :

Fills the encoded texture with a solid color depending on their BCN format.
This is a handy way to see that you are in fact getting Oodle Texture in your game.
It's also an easy way to spot textures that aren't BCN compressed, since they will not
be solid color.  (for example I found that lots of the Unreal demo content uses "HDR"
which is an uncompressed format, instead of "HDRCompressed" (BC6))  The color indicates
the actual compressed format output (BC1-7).

GlobalLambdaMultiplier :

Takes all lambdas and scales them by this multiplier, so it affects the global default
and the per-texture lambdas.

It is recommended to leave this at 1.0 until you get near shipping your final game, at
which point you could tweak it to 0.9 or 1.1 to adjust your package size without having
to edit lots of per-texture lambdas.

Oodle Texture lambda
----------------------

The "lambda" parameter is the most important way of controlling Oodle Texture RDO.

"lambda" controls the tradeoff of size vs quality in the Rate Distortion Optimization.

Finding the right lambda settings will be a collaboration between artists and
programmers.  Programmers and technical artists may wish to find a global lambda
that meets your goals.  Individual texture artists may wish to tweak the lambda
per-texture when needed, but this should be rare - for the most part Oodle Texture
quality is very predictable and good on most textures.

Lambda first of all can be overridden per texture with the "LossyCompressionAmount"
setting.  This is a slider in the GUI in the editor that goes from Lowest to Highest.
The default value is "Default" and we recommend leaving that there most of the time.

If the per-texture LossyCompressionAmount is "Default", that means "inherit from LODGroup".

The LODGroup gives you a logical group of textures where you can adjust the lambda on that
whole set of textures rather than per-texture.

For example here I have changed "World" LossyCompressionAmount to TLCA_High, and 
"WorldNormalMap" to TLCA_Low :


[GlobalDefaults DeviceProfile]
@TextureLODGroups=Group
TextureLODGroups=(Group=TEXTUREGROUP_World,MinLODSize=1,MaxLODSize=8192,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage,LossyCompressionAmount=TLCA_High)
+TextureLODGroups=(Group=TEXTUREGROUP_WorldNormalMap,MinLODSize=1,MaxLODSize=8192,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage,LossyCompressionAmount=TLCA_Low)
+TextureLODGroups=(Group=TEXTUREGROUP_WorldSpecular,MinLODSize=1,MaxLODSize=8192,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)


If the LossyCompressionAmount is not set on the LODGroup (which is the default), 
then it falls through to the global default, which is set in the texture compression
project settings.

At each stage, TLCA_Default means "inherit from parent".

TLCA_None means disable RDO entirely. We do not recommend this, use TLCA_Lowest 
instead when you need very high quality.

Note that the Unreal Editor texture dialog shows live compression results.
When you're in the editor and you adjust the LossyCompressionAmount or import a 
new texture, it shows the Oodle Texture encoded result in the texture preview.



*********/


DEFINE_LOG_CATEGORY_STATIC(LogTextureFormatOodle, Log, All);
LLM_DEFINE_TAG(OodleTexture);

/*****************
* 
* Function pointer types for the Oodle Texture functions we need to import :
* 
********************/

OODEFFUNC typedef OodleTex_Err (OOEXPLINK t_fp_OodleTex_EncodeBCN_RDO_Ex)(
    OodleTex_BC to_bcn,void * to_bcn_blocks,OO_SINTa num_blocks,
    const OodleTex_Surface * from_surfaces,OO_SINTa num_from_surfaces,OodleTex_PixelFormat from_format,
    const OodleTex_Layout * layout,
    int rdo_lagrange_lambda,
    const OodleTex_RDO_Options * options,
    int num_job_threads,void * jobify_user_ptr);
	
OODEFFUNC typedef void (OOEXPLINK t_fp_OodleTex_Plugins_SetAllocators)(
    t_fp_OodleTex_Plugin_MallocAligned * fp_OodleMallocAligned,
    t_fp_OodleTex_Plugin_Free * fp_OodleFree);
	
OODEFFUNC typedef void (OOEXPLINK t_fp_OodleTex_Plugins_SetJobSystemAndCount)(
    t_fp_OodleTex_Plugin_RunJob * fp_RunJob,
    t_fp_OodleTex_Plugin_WaitJob * fp_WaitJob,
    int target_parallelism);
	
OODEFFUNC typedef t_fp_OodleTex_Plugin_Printf * (OOEXPLINK t_fp_OodleTex_Plugins_SetPrintf)(t_fp_OodleTex_Plugin_Printf * fp_rrRawPrintf);

OODEFFUNC typedef t_fp_OodleTex_Plugin_DisplayAssertion * (OOEXPLINK t_fp_OodleTex_Plugins_SetAssertion)(t_fp_OodleTex_Plugin_DisplayAssertion * fp_rrDisplayAssertion);

OODEFFUNC typedef const char * (OOEXPLINK t_fp_OodleTex_Err_GetName)(OodleTex_Err error);

OODEFFUNC typedef const char * (OOEXPLINK t_fp_OodleTex_PixelFormat_GetName)(OodleTex_PixelFormat pf);

OODEFFUNC typedef const char * (OOEXPLINK t_fp_OodleTex_BC_GetName)(OodleTex_BC bcn);

OODEFFUNC typedef const char * (OOEXPLINK t_fp_OodleTex_RDO_UniversalTiling_GetName)(OodleTex_RDO_UniversalTiling tiling);

OODEFFUNC typedef OO_S32 (OOEXPLINK t_fp_OodleTex_BC_BytesPerBlock)(OodleTex_BC bcn);

OODEFFUNC typedef OO_S32 (OOEXPLINK t_fp_OodleTex_PixelFormat_BytesPerPixel)(OodleTex_PixelFormat pf);

OODEFFUNC typedef OodleTex_Err (OOEXPLINK t_fp_OodleTex_LogVersion)(void);

/**
 * DebugInfo passed to the Jobify callbacks for tracing 
 */
struct FOodleJobDebugInfo
{
	FStringView DebugTexturePathName;
	int32 SizeX;
	int32 SizeY;
	OodleTex_BC OodleBCN;
	int RDOLambda;
};

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:567

Scope (from outer to inner):

file
class        class FTextureFormatOodleConfig
function     FTextureFormatOodleConfig

Source code excerpt:


	FTextureFormatOodleConfig() :
		bDebugColor(false),
		GlobalLambdaMultiplier(1.f)
	{
	}

	const FLocalDebugConfig& GetLocalDebugConfig() const
	{

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:588

Scope (from outer to inner):

file
class        class FTextureFormatOodleConfig
function     void ImportFromConfigCache

Source code excerpt:

		
		// Class config variables
		GConfig->GetBool(IniSection, TEXT("bDebugColor"), bDebugColor, GEngineIni);
		GConfig->GetString(IniSection, TEXT("DebugDumpFilter"), LocalDebugConfig.DebugDumpFilter, GEngineIni);
		GConfig->GetInt(IniSection, TEXT("LogVerbosity"), LocalDebugConfig.LogVerbosity, GEngineIni);
		GConfig->GetFloat(IniSection, TEXT("GlobalLambdaMultiplier"), GlobalLambdaMultiplier, GEngineIni);
		
		FString CmdLineString;
		if (FParse::Value(FCommandLine::Get(), TEXT("-OodleDebugDumpFilter="), CmdLineString) )

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:603

Scope (from outer to inner):

file
class        class FTextureFormatOodleConfig
function     void ImportFromConfigCache

Source code excerpt:

		{
			UE_LOG(LogTextureFormatOodle, Display, TEXT("Enabling debug color encoding from command line (-OodleDebugColor)"));
			bDebugColor = true;
		}

		// sanitize config values :
		if ( GlobalLambdaMultiplier <= 0.f )
		{
			GlobalLambdaMultiplier = 1.f;

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:632

Scope (from outer to inner):

file
class        class FTextureFormatOodleConfig
function     FCbObject ExportToCb

Source code excerpt:

		Writer.BeginObject("TextureFormatOodleSettings");

		if (bDebugColor)
		{
			Writer.AddBool("bDebugColor", bDebugColor);
		}
		if (GlobalLambdaMultiplier != 1.f)
		{
			Writer.AddFloat("GlobalLambdaMultipler", GlobalLambdaMultiplier);
		}

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:709

Scope (from outer to inner):

file
class        class FTextureFormatOodleConfig
function     void GetOodleCompressParameters

Source code excerpt:


		// Use the DDC2 provided value if it exists.
		bool bUseDebugColor = InBuildSettings.FormatConfigOverride.FindView("bDebugColor").AsBool(bDebugColor);

		float UseGlobalLambdaMultiplier = InBuildSettings.FormatConfigOverride.FindView("GlobalLambdaMultipler").AsFloat(GlobalLambdaMultiplier);

		//
		// Convert general build settings in to oodle relevant values.
		//

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:789

Scope (from outer to inner):

file
class        class FTextureFormatOodleConfig

Source code excerpt:

private:
	// the sense of these bools is set so that default behavior = all false
	bool bDebugColor; // color textures by their BCN, for data discovery
	// after lambda is set, multiply by this scale factor :
	//	(multiplies the default and per-Texture overrides)
	//	is intended to let you do last minute whole-game adjustment
	float GlobalLambdaMultiplier;
	FLocalDebugConfig LocalDebugConfig;
};

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:944

Scope (from outer to inner):

file
class        class FTextureFormatOodle : public ITextureFormat
function     virtual FString GetDerivedDataKeyString

Source code excerpt:

		OodleTex_BCNFlags BCNFlags;
		EPixelFormat CompressedPixelFormat;
		bool bDebugColor;

		// @todo Oodle this is not quite the same "bHasAlpha" that Compress will see
		//	bHasAlpha is used for AutoDXT -> DXT1/5
		//	we do have Texture.bForceNoAlphaChannel/CompressionNoAlpha but that's not quite what we want
		// do go ahead and read bForceNoAlphaChannel/CompressionNoAlpha so that we invalidate DDC when that changes
		bool bHasAlpha = !InBuildSettings.bForceNoAlphaChannel; 
		
		GlobalFormatConfig.GetOodleCompressParameters(&CompressedPixelFormat, &RDOLambda, &EffortLevel, &bDebugColor, &RDOUniversalTiling, &BCNFlags, InBuildSettings, bHasAlpha);

		int icpf = (int)CompressedPixelFormat;

		check(RDOLambda<256);
		if (bDebugColor)
		{
			// Debug Color is solid or check for RDO/ no RDO
			//	so make different DDC keys :
			if ( RDOLambda == 0 )
				RDOLambda = 256;
			else

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:1036

Scope (from outer to inner):

file
class        class FTextureFormatOodle : public ITextureFormat
function     virtual EPixelFormat GetEncodedPixelFormat

Source code excerpt:

		OodleTex_BCNFlags BCNFlags;
		EPixelFormat CompressedPixelFormat;
		bool bDebugColor;

		GlobalFormatConfig.GetOodleCompressParameters(&CompressedPixelFormat, &RDOLambda, &EffortLevel, &bDebugColor, &RDOUniversalTiling, &BCNFlags, InBuildSettings, bImageHasAlphaChannel);
		return CompressedPixelFormat;
	}

	static void DebugDumpDDS(const FStringView & DebugTexturePathName,
			int32 SizeX,int32 SizeY,int32 Slice, UE::DDS::EDXGIFormat DebugFormat, const TCHAR * InOrOut,
			const void * PixelData, size_t PixelDataSize)

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:1155

Scope (from outer to inner):

file
class        class FTextureFormatOodle : public ITextureFormat
function     virtual bool CompressImage

Source code excerpt:

		OodleTex_BCNFlags BCNFlags;
		EPixelFormat CompressedPixelFormat;
		bool bDebugColor;
		GlobalFormatConfig.GetOodleCompressParameters(&CompressedPixelFormat, &RDOLambda, &EffortLevel, &bDebugColor, &RDOUniversalTiling, &BCNFlags, InBuildSettings, bHasAlpha);

		OodleTex_BC OodleBCN = OodleTex_BC_Invalid;
		if ( CompressedPixelFormat == PF_DXT1 ) { OodleBCN = OodleTex_BC1_WithTransparency; bHasAlpha = false; }
		else if ( CompressedPixelFormat == PF_DXT3 ) { OodleBCN = OodleTex_BC2; }
		else if ( CompressedPixelFormat == PF_DXT5 ) { OodleBCN = OodleTex_BC3; }
		else if ( CompressedPixelFormat == PF_BC4 ) { OodleBCN = OodleTex_BC4U; }

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:1226

Scope (from outer to inner):

file
class        class FTextureFormatOodle : public ITextureFormat
function     virtual bool CompressImage

Source code excerpt:

		else if ((OodleBCN == OodleTex_BC4U || OodleBCN == OodleTex_BC5U) &&
			Gamma == EGammaSpace::Linear &&			
			!bDebugColor)
		{
			// for BC4/5 use 16-bit integer U16 pixels :
			//	BC4/5 should always have linear gamma

			// input image format now can be BGRA8 (used to always be RGBA32F)
			// but to maintain matching output with previous RGBA32F format, still do convert to RGBA16

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:1269

Scope (from outer to inner):

file
class        class FTextureFormatOodle : public ITextureFormat
function     virtual bool CompressImage

Source code excerpt:

			Gamma != InImage.GammaSpace ||
			(CompressedPixelFormat == PF_DXT5 && TextureFormatName == GTextureFormatNameDXT5n) ||
			bDebugColor || bIsSpecial2U16;
		FImage ImageCopy;
		if (bNeedsImageCopy)
		{
			TRACE_CPUPROFILER_EVENT_SCOPE(Texture.Oodle_FormatChange);

                        //not sure if we should bill this alloc to OodleTexture or the calling context (TextureCompressor)

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:1342

Scope (from outer to inner):

file
class        class FTextureFormatOodle : public ITextureFormat
function     virtual bool CompressImage

Source code excerpt:

		}

		if ( bDebugColor )
		{
			// fill Texture with solid color based on which BCN we would have output
			//   checker board if RDO
			// lets you visually identify BCN textures in the Editor or game
			const bool IsRDO = RDOLambda != 0;
			constexpr SSIZE_T CheckerSizeBits = 4;

#Loc: <Workspace>/Engine/Plugins/Developer/TextureFormatOodle/Source/Private/TextureFormatOodle.cpp:1507

Scope (from outer to inner):

file
class        class FTextureFormatOodle : public ITextureFormat
function     virtual bool CompressImage

Source code excerpt:

		bool bImageDump = false;
		if (GlobalFormatConfig.GetLocalDebugConfig().DebugDumpFilter.Len() && 
			!bDebugColor && // don't bother if they are solid color
			(Image.SizeX >= 4 || Image.SizeY >= 4)) // don't bother if they are too small.
		{
			if (FWildcardString::IsMatchSubstring(*GlobalFormatConfig.GetLocalDebugConfig().DebugDumpFilter, DebugTexturePathName.GetData(), DebugTexturePathName.GetData() + DebugTexturePathName.Len(), ESearchCase::IgnoreCase))
			{
				bImageDump = true;
			}