adds multiple targets to the posteffect class

These changes allows for multiple color targets from a post effect pass.

This is not 100% complete yet as the api still expects 1 target out from a posteffect and will not pass those on to other stages in a posteffect chain but will be adding that soon. This is a working state and everything renders correctly here.
This commit is contained in:
marauder2k7 2026-04-19 15:47:48 +01:00
parent 10cff00c23
commit 60e659aedc
4 changed files with 494 additions and 508 deletions

View file

@ -137,9 +137,6 @@ GFX_ImplementTextureProfile( PostFxTargetProfile,
GFXTextureProfile::Pooled, GFXTextureProfile::Pooled,
GFXTextureProfile::NONE ); GFXTextureProfile::NONE );
IMPLEMENT_CONOBJECT(PostEffect);
GFX_ImplementTextureProfile( PostFxTextureProfile, GFX_ImplementTextureProfile( PostFxTextureProfile,
GFXTextureProfile::DiffuseMap, GFXTextureProfile::DiffuseMap,
GFXTextureProfile::Static | GFXTextureProfile::PreserveSize, GFXTextureProfile::Static | GFXTextureProfile::PreserveSize,
@ -162,6 +159,12 @@ GFX_ImplementTextureProfile( VRDepthProfile,
GFXTextureProfile::ZTarget, GFXTextureProfile::ZTarget,
GFXTextureProfile::NONE ); GFXTextureProfile::NONE );
IMPLEMENT_CONOBJECT(PostEffect);
//---------------------------------------------------------------------
// EffectConst
//---------------------------------------------------------------------
void PostEffect::EffectConst::set( const String &newVal ) void PostEffect::EffectConst::set( const String &newVal )
{ {
if ( mStringVal == newVal ) if ( mStringVal == newVal )
@ -445,6 +448,9 @@ void PostEffect::EffectConst::setToBuffer( GFXShaderConstBufferRef buff )
} }
} }
//---------------------------------------------------------------------
// EffectConst END
//---------------------------------------------------------------------
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// PostEffect // PostEffect
@ -459,12 +465,10 @@ PostEffect::PostEffect()
mSkip(false), mSkip(false),
mPreProcessed(false), mPreProcessed(false),
mAllowReflectPass(false), mAllowReflectPass(false),
mTargetClear( PFXTargetClear_None ),
mTargetScale(Point2F::One), mTargetScale(Point2F::One),
mTargetViewport( PFXTargetViewport_TargetSize ),
mTargetSize(Point2I::Zero), mTargetSize(Point2I::Zero),
mTargetFormat( GFXFormatR8G8B8A8 ), mTargetViewport(PFXTargetViewport_TargetSize),
mTargetClearColor( LinearColorF::BLACK ), mMipCap(1),
mOneFrameOnly(false), mOneFrameOnly(false),
mOnThisFrame(true), mOnThisFrame(true),
mRTSizeSC(NULL), mRTSizeSC(NULL),
@ -499,9 +503,16 @@ PostEffect::PostEffect()
mInvCameraTransSC(NULL), mInvCameraTransSC(NULL),
mMatCameraToScreenSC(NULL), mMatCameraToScreenSC(NULL),
mMatScreenToCameraSC(NULL), mMatScreenToCameraSC(NULL),
mIsCapturingSC(NULL), mIsCapturingSC(NULL)
mMipCap(1)
{ {
// MRT arrays — slot 0 gets primary defaults, 1-3 are inactive.
for (U32 c = 0; c < NumMRTTargets; c++)
{
mTargetFormat[c] = GFXFormatR8G8B8A8;
mTargetClearColor[c] = LinearColorF::BLACK;
mTargetClear[c] = PFXTargetClear_None;
}
dMemset(mTexSRGB, 0, sizeof(bool) * NumTextures); dMemset(mTexSRGB, 0, sizeof(bool) * NumTextures);
dMemset(mActiveTextures, 0, sizeof(GFXTextureObject*) * NumTextures); dMemset(mActiveTextures, 0, sizeof(GFXTextureObject*) * NumTextures);
dMemset(mActiveNamedTarget, 0, sizeof(NamedTexTarget*) * NumTextures); dMemset(mActiveNamedTarget, 0, sizeof(NamedTexTarget*) * NumTextures);
@ -527,10 +538,19 @@ void PostEffect::initPersistFields()
addField( "stateBlock", TYPEID<GFXStateBlockData>(), Offset( mStateBlockData, PostEffect ), addField( "stateBlock", TYPEID<GFXStateBlockData>(), Offset( mStateBlockData, PostEffect ),
"Name of a GFXStateBlockData for this effect." ); "Name of a GFXStateBlockData for this effect." );
addField( "target", TypeRealString, Offset( mTargetName, PostEffect ), addField( "target", TypeRealString, Offset( mTargetName, PostEffect ), NumMRTTargets,
"String identifier of this effect's target texture.\n" "String identifier of this effect's target texture.\n"
"@see PFXTextureIdentifiers" ); "@see PFXTextureIdentifiers" );
addField("targetFormat", TypeGFXFormat, Offset(mTargetFormat, PostEffect), NumMRTTargets,
"Format of the target texture, not applicable if writing to the backbuffer.");
addField("targetClearColor", TypeColorF, Offset(mTargetClearColor, PostEffect), NumMRTTargets,
"Color to which the target texture is cleared before rendering.");
addField("targetClear", TYPEID< PFXTargetClear >(), Offset(mTargetClear, PostEffect), NumMRTTargets,
"Describes when the target texture should be cleared.");
addField( "targetDepthStencil", TypeRealString, Offset( mTargetDepthStencilName, PostEffect ), addField( "targetDepthStencil", TypeRealString, Offset( mTargetDepthStencilName, PostEffect ),
"Optional string identifier for this effect's target depth/stencil texture.\n" "Optional string identifier for this effect's target depth/stencil texture.\n"
"@see PFXTextureIdentifiers" ); "@see PFXTextureIdentifiers" );
@ -544,15 +564,6 @@ void PostEffect::initPersistFields()
addField( "targetSize", TypePoint2I, Offset( mTargetSize, PostEffect ), addField( "targetSize", TypePoint2I, Offset( mTargetSize, PostEffect ),
"If non-zero this is used as the absolute target size." ); "If non-zero this is used as the absolute target size." );
addField( "targetFormat", TypeGFXFormat, Offset( mTargetFormat, PostEffect ),
"Format of the target texture, not applicable if writing to the backbuffer." );
addField( "targetClearColor", TypeColorF, Offset( mTargetClearColor, PostEffect ),
"Color to which the target texture is cleared before rendering." );
addField( "targetClear", TYPEID< PFXTargetClear >(), Offset( mTargetClear, PostEffect ),
"Describes when the target texture should be cleared." );
addField( "targetViewport", TYPEID< PFXTargetViewport >(), Offset( mTargetViewport, PostEffect ), addField( "targetViewport", TYPEID< PFXTargetViewport >(), Offset( mTargetViewport, PostEffect ),
"Specifies how the viewport should be set up for a target texture." ); "Specifies how the viewport should be set up for a target texture." );
@ -624,15 +635,21 @@ bool PostEffect::onAdd()
} }
// Is the target a named target? // Is the target a named target?
if ( mTargetName.isNotEmpty() && mTargetName[0] == '#' ) bool anyNamed = false;
for (U32 c = 0; c < NumMRTTargets; c++)
{ {
mNamedTarget.registerWithName(mTargetName.substr(1)); if (mTargetName[c].isNotEmpty() && mTargetName[c][0] == '#')
mNamedTarget.getTextureDelegate().bind( this, &PostEffect::_getTargetTexture ); {
mNamedTarget[c].registerWithName(mTargetName[c].substr(1));
mNamedTarget[c].getTextureDelegate().bind(this, &PostEffect::_getTargetTexture);
anyNamed = true;
} }
}
if ( mTargetDepthStencilName.isNotEmpty() && mTargetDepthStencilName[0] == '#' ) if ( mTargetDepthStencilName.isNotEmpty() && mTargetDepthStencilName[0] == '#' )
mNamedTargetDepthStencil.registerWithName( mTargetDepthStencilName.substr( 1 ) ); mNamedTargetDepthStencil.registerWithName( mTargetDepthStencilName.substr( 1 ) );
if (mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered()) if (anyNamed || mNamedTargetDepthStencil.isRegistered())
GFXTextureManager::addEventDelegate( this, &PostEffect::_onTextureEvent ); GFXTextureManager::addEventDelegate( this, &PostEffect::_onTextureEvent );
// Call onAdd in script // Call onAdd in script
@ -661,14 +678,19 @@ void PostEffect::onRemove()
mShader = NULL; mShader = NULL;
_cleanTargets(); _cleanTargets();
if ( mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered() ) bool anyNamed = false;
GFXTextureManager::removeEventDelegate( this, &PostEffect::_onTextureEvent ); for (U32 c = 0; c < NumMRTTargets; c++)
if ( mNamedTarget.isRegistered() )
{ {
mNamedTarget.unregister(); if (mNamedTarget[c].isRegistered())
mNamedTarget.getTextureDelegate().clear(); {
mNamedTarget[c].unregister();
mNamedTarget[c].getTextureDelegate().clear();
anyNamed = true;
} }
}
if (anyNamed || mNamedTargetDepthStencil.isRegistered() )
GFXTextureManager::removeEventDelegate( this, &PostEffect::_onTextureEvent );
if ( mNamedTargetDepthStencil.isRegistered() ) if ( mNamedTargetDepthStencil.isRegistered() )
mNamedTargetDepthStencil.unregister(); mNamedTargetDepthStencil.unregister();
@ -1156,7 +1178,7 @@ void PostEffect::_setupTexture( U32 stage, GFXTexHandle &inputTex, const RectI *
RectI viewport = GFX->getViewport(); RectI viewport = GFX->getViewport();
if ( texFilename.compare( "$inTex", 0, String::NoCase ) == 0 ) if ( _inTexSlotFromName(texFilename) >= 0 )
{ {
theTex = inputTex; theTex = inputTex;
@ -1236,8 +1258,9 @@ void PostEffect::_setupTransforms()
void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarget ) void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarget )
{ {
if ( mNamedTarget.isRegistered() || for (U32 c = 0; c < NumMRTTargets; c++)
mTargetName.compare( "$outTex", 0, String::NoCase ) == 0 ) {
if (mNamedTarget[c].isRegistered() || _outTexSlotFromName(mTargetName[c]) >= 0)
{ {
// Size it relative to the texture of the first stage or // Size it relative to the texture of the first stage or
// if NULL then use the current target. // if NULL then use the current target.
@ -1268,14 +1291,14 @@ void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarg
// Make sure its at least 1x1. // Make sure its at least 1x1.
targetSize.setMax(Point2I::One); targetSize.setMax(Point2I::One);
if ( mNamedTarget.isRegistered() || if (mNamedTarget[c].isRegistered() ||
!mTargetTex || !mTargetTex[c] ||
mTargetTex.getWidthHeight() != targetSize ) mTargetTex[c].getWidthHeight() != targetSize)
{ {
mTargetTex.set( targetSize.x, targetSize.y, mTargetFormat, mTargetTex[c].set(targetSize.x, targetSize.y, mTargetFormat[c],
&PostFxTargetProfile, "PostEffect::_setupTarget", mMipCap); &PostFxTargetProfile, "PostEffect::_setupTarget", mMipCap);
if ( mTargetClear == PFXTargetClear_OnCreate ) if (mTargetClear[c] == PFXTargetClear_OnCreate)
*outClearTarget = true; *outClearTarget = true;
if (mTargetViewport == PFXTargetViewport_GFXViewport) if (mTargetViewport == PFXTargetViewport_GFXViewport)
@ -1288,7 +1311,7 @@ void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarg
const RectI& viewport = GFX->getViewport(); const RectI& viewport = GFX->getViewport();
mNamedTarget.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) ); mNamedTarget[c].setViewport(RectI(viewport.point.x * scale.x, viewport.point.y * scale.y, viewport.extent.x * scale.x, viewport.extent.y * scale.y));
} }
else if (mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture()) else if (mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture())
{ {
@ -1298,17 +1321,18 @@ void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarg
const RectI& viewport = mActiveNamedTarget[0]->getViewport(); const RectI& viewport = mActiveNamedTarget[0]->getViewport();
mNamedTarget.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) ); mNamedTarget[c].setViewport(RectI(viewport.point.x * scale.x, viewport.point.y * scale.y, viewport.extent.x * scale.x, viewport.extent.y * scale.y));
} }
else else
{ {
// PFXTargetViewport_TargetSize // PFXTargetViewport_TargetSize
mNamedTarget.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) ); mNamedTarget[c].setViewport(RectI(0, 0, targetSize.x, targetSize.y));
} }
} }
} }
else else
mTargetTex = NULL; mTargetTex[c] = NULL;
}
// Do we have a named depthStencil target? // Do we have a named depthStencil target?
if (mNamedTargetDepthStencil.isRegistered()) if (mNamedTargetDepthStencil.isRegistered())
@ -1347,7 +1371,7 @@ void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarg
mTargetDepthStencil.set(targetSize.x, targetSize.y, GFXFormatD24S8, mTargetDepthStencil.set(targetSize.x, targetSize.y, GFXFormatD24S8,
&GFXZTargetProfile, "PostEffect::_setupTarget"); &GFXZTargetProfile, "PostEffect::_setupTarget");
if ( mTargetClear == PFXTargetClear_OnCreate ) if (mTargetClear[0] == PFXTargetClear_OnCreate)
*outClearTarget = true; *outClearTarget = true;
if (mTargetViewport == PFXTargetViewport_GFXViewport) if (mTargetViewport == PFXTargetViewport_GFXViewport)
@ -1382,7 +1406,7 @@ void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarg
else else
mTargetDepthStencil = NULL; mTargetDepthStencil = NULL;
if ( mTargetClear == PFXTargetClear_OnDraw ) if (mTargetClear[0] == PFXTargetClear_OnDraw)
*outClearTarget = true; *outClearTarget = true;
if (!mTarget && (mTargetTex || mTargetDepthStencil)) if (!mTarget && (mTargetTex || mTargetDepthStencil))
@ -1391,7 +1415,9 @@ void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarg
void PostEffect::_cleanTargets( bool recurse ) void PostEffect::_cleanTargets( bool recurse )
{ {
mTargetTex = NULL; for (U32 c = 0; c < NumMRTTargets; c++)
mTargetTex[c] = NULL;
mTargetDepthStencil = NULL; mTargetDepthStencil = NULL;
mTarget = NULL; mTarget = NULL;
@ -1461,16 +1487,42 @@ void PostEffect::process( const SceneRenderState *state,
bool clearTarget = false; bool clearTarget = false;
_setupTarget( state, &clearTarget ); _setupTarget( state, &clearTarget );
if ( mTargetTex || mTargetDepthStencil ) const bool hasDepth = mTargetDepthStencil.isValid();
bool hasColorTarget = false;
for (U32 c = 0; c < NumMRTTargets; c++)
{
if (mTargetTex[c].isValid())
{
hasColorTarget = true;
break;
}
}
// Attach each color slot. NULL explicitly detaches unused slots,
// preventing stale attachments from a previous frame.
static const GFXTextureTarget::RenderSlot kSlots[NumMRTTargets] =
{
GFXTextureTarget::Color0,
GFXTextureTarget::Color1,
GFXTextureTarget::Color2,
GFXTextureTarget::Color3,
};
if (hasColorTarget || hasDepth)
{ {
const RectI &oldViewport = GFX->getViewport(); const RectI &oldViewport = GFX->getViewport();
GFXTarget *oldTarget = GFX->getActiveRenderTarget(); GFXTarget *oldTarget = GFX->getActiveRenderTarget();
GFX->pushActiveRenderTarget(); GFX->pushActiveRenderTarget();
mTarget->attachTexture( GFXTextureTarget::Color0, mTargetTex );
for (U32 c = 0; c < NumMRTTargets; c++)
{
mTarget->attachTexture(kSlots[c], mTargetTex[c].isValid() ? mTargetTex[c] : NULL);
}
// Set the right depth stencil target. // Set the right depth stencil target.
if ( !mTargetDepthStencil && mTargetTex.getWidthHeight() == GFX->getActiveRenderTarget()->getSize() ) if (!hasDepth && mTargetTex[0].isValid() && mTargetTex[0].getWidthHeight() == oldTarget->getSize())
mTarget->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil); mTarget->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
else else
mTarget->attachTexture(GFXTextureTarget::DepthStencil, mTargetDepthStencil); mTarget->attachTexture(GFXTextureTarget::DepthStencil, mTargetDepthStencil);
@ -1478,10 +1530,13 @@ void PostEffect::process( const SceneRenderState *state,
// Set the render target but not its viewport. We'll do that below. // Set the render target but not its viewport. We'll do that below.
GFX->setActiveRenderTarget( mTarget, false ); GFX->setActiveRenderTarget( mTarget, false );
if(mNamedTarget.isRegistered()) if (mNamedTarget[0].isRegistered())
{ {
// Always use the name target's viewport, if available. It was set up in _setupTarget(). GFX->setViewport(mNamedTarget[0].getViewport());
GFX->setViewport(mNamedTarget.getViewport()); }
else if (mTargetTex[0].isValid())
{
GFX->setViewport(RectI(Point2I::Zero, mTargetTex[0].getWidthHeight()));
} }
else if(mTargetViewport == PFXTargetViewport_GFXViewport) else if(mTargetViewport == PFXTargetViewport_GFXViewport)
{ {
@ -1510,7 +1565,18 @@ void PostEffect::process( const SceneRenderState *state,
} }
if (clearTarget) if (clearTarget)
GFX->clear( GFXClearTarget, mTargetClearColor, 1.f, 0 ); {
LinearColorF clearColor = LinearColorF::BLACK;
for (U32 c = 0; c < NumMRTTargets; c++)
{
if (mTargetTex[c].isValid() && mTargetClear[c] != PFXTargetClear_None)
{
clearColor = mTargetClearColor[c];
break;
}
}
GFX->clear(GFXClearTarget, clearColor, 1.f, 0);
}
// Setup the shader and constants. // Setup the shader and constants.
if ( mShader ) if ( mShader )
@ -1545,24 +1611,22 @@ void PostEffect::process( const SceneRenderState *state,
// Allow PostEffecVis to hook in. // Allow PostEffecVis to hook in.
PFXVIS->onPFXProcessed( this ); PFXVIS->onPFXProcessed( this );
if ( mTargetTex || mTargetDepthStencil ) if (hasColorTarget || hasDepth)
{ {
mTarget->resolve(); mTarget->resolve();
GFX->popActiveRenderTarget(); GFX->popActiveRenderTarget();
} }
else else
{ {
// We wrote to the active back buffer, so release
// the current texture copy held by the manager.
//
// This ensures a new copy is made.
PFXMGR->releaseBackBufferTex(); PFXMGR->releaseBackBufferTex();
} }
// Return and release our target texture. inOutTex = mTargetTex[0];
inOutTex = mTargetTex; for (U32 c = 0; c < NumMRTTargets; c++)
if ( !mNamedTarget.isRegistered() ) {
mTargetTex = NULL; if (!mNamedTarget[c].isRegistered())
mTargetTex[c] = NULL;
}
// Restore the transforms before the children // Restore the transforms before the children
// are processed as it screws up the viewport. // are processed as it screws up the viewport.
@ -1842,10 +1906,12 @@ void PostEffect::_checkRequirements()
} }
// First make sure the target format is supported. // First make sure the target format is supported.
if ( mNamedTarget.isRegistered() ) for (U32 c = 0; c < NumMRTTargets; c++)
{
if (mNamedTarget[c].isRegistered())
{ {
Vector<GFXFormat> formats; Vector<GFXFormat> formats;
formats.push_back( mTargetFormat ); formats.push_back(mTargetFormat[c]);
GFXFormat format = GFX->selectSupportedFormat(&PostFxTargetProfile, GFXFormat format = GFX->selectSupportedFormat(&PostFxTargetProfile,
formats, formats,
true, true,
@ -1853,9 +1919,10 @@ void PostEffect::_checkRequirements()
false); false);
// If we didn't get our format out then its unsupported! // If we didn't get our format out then its unsupported!
if ( format != mTargetFormat ) if (format != mTargetFormat[c])
return; return;
} }
}
// Gather macros specified on this PostEffect. // Gather macros specified on this PostEffect.
Vector<GFXShaderMacro> macros( mShaderMacros ); Vector<GFXShaderMacro> macros( mShaderMacros );
@ -1981,12 +2048,12 @@ void PostEffect::clearShaderMacros()
mUpdateShader = true; mUpdateShader = true;
} }
GFXTextureObject* PostEffect::_getTargetTexture( U32 ) GFXTextureObject* PostEffect::_getTargetTexture( U32 index)
{ {
// A TexGen PostEffect will generate its texture now if it // A TexGen PostEffect will generate its texture now if it
// has not already. // has not already.
if ( mRenderTime == PFXTexGenOnDemand && if ( mRenderTime == PFXTexGenOnDemand &&
( !mTargetTex || mUpdateShader ) ) ( !mTargetTex[index] || mUpdateShader ) )
{ {
GFXTexHandle chainTex; GFXTexHandle chainTex;
process( NULL, chainTex ); process( NULL, chainTex );
@ -1996,7 +2063,7 @@ GFXTextureObject* PostEffect::_getTargetTexture( U32 )
// amount of non-swappable RTs in use. // amount of non-swappable RTs in use.
} }
return mTargetTex.getPointer(); return mTargetTex[index].getPointer();
} }
DefineEngineMethod( PostEffect, reload, void, (),, DefineEngineMethod( PostEffect, reload, void, (),,

View file

@ -67,14 +67,6 @@ class Frustum;
class SceneRenderState; class SceneRenderState;
class ConditionerFeature; class ConditionerFeature;
///
GFX_DeclareTextureProfile( PostFxTargetProfile );
///
class PostEffect : public SimGroup class PostEffect : public SimGroup
{ {
typedef SimGroup Parent; typedef SimGroup Parent;
@ -86,59 +78,87 @@ public:
enum enum
{ {
NumTextures = 16, NumTextures = 16,
/// Maximum simultaneous color render target outputs (MRT)
NumMRTTargets = 4,
}; };
protected: protected:
//--------------------------------------------------------------------------
// Input textures
//--------------------------------------------------------------------------
DECLARE_IMAGEASSET_ARRAY(PostEffect, Texture, GFXStaticTextureSRGBProfile, NumTextures); DECLARE_IMAGEASSET_ARRAY(PostEffect, Texture, GFXStaticTextureSRGBProfile, NumTextures);
GFXTextureProfile* mTextureProfile[NumTextures]; GFXTextureProfile* mTextureProfile[NumTextures];
GFXTexHandle mTexture[NumTextures]; GFXTexHandle mTexture[NumTextures];
bool mTexSRGB[NumTextures]; bool mTexSRGB[NumTextures];
enum enum { NormalTextureType = 0, CubemapType, CubemapArrayType } mTextureType[NumTextures];
{
NormalTextureType = 0,
CubemapType,
CubemapArrayType,
} mTextureType[NumTextures];
GFXCubemapHandle mCubemapTextures[NumTextures]; GFXCubemapHandle mCubemapTextures[NumTextures];
GFXCubemapArrayHandle mCubemapArrayTextures[NumTextures]; GFXCubemapArrayHandle mCubemapArrayTextures[NumTextures];
NamedTexTarget mNamedTarget;
NamedTexTarget mNamedTargetDepthStencil;
GFXTextureObject* mActiveTextures[NumTextures]; GFXTextureObject* mActiveTextures[NumTextures];
NamedTexTarget* mActiveNamedTarget[NumTextures]; NamedTexTarget* mActiveNamedTarget[NumTextures];
RectI mActiveTextureViewport[NumTextures]; RectI mActiveTextureViewport[NumTextures];
//--------------------------------------------------------------------------
// MRT color output targets
//
// Replaces the original single: mNamedTarget, mTargetName, mTargetTex,
// mTargetFormat, mTargetClearColor, mTargetClear
//--------------------------------------------------------------------------
String mTargetName[NumMRTTargets]; ///< Per-slot output name.
GFXFormat mTargetFormat[NumMRTTargets]; ///< Per-slot texture format.
LinearColorF mTargetClearColor[NumMRTTargets]; ///< Per-slot clear colour.
PFXTargetClear mTargetClear[NumMRTTargets]; ///< Per-slot clear policy.
GFXTexHandle mTargetTex[NumMRTTargets]; ///< Runtime texture per slot.
NamedTexTarget mNamedTarget[NumMRTTargets]; ///< Named target per slot.
// These remain single values — shared across ALL active MRT slots.
Point2F mTargetScale; ///< Relative size vs current GFX render target.
Point2I mTargetSize; ///< Absolute size override; (0,0) = use mTargetScale.
PFXTargetViewport mTargetViewport; ///< How the viewport rect is derived.
/// Single GFXTextureTarget — ALL active MRT slots attach to this one object.
GFXTextureTargetRef mTarget;
S32 mMipCap;
//--------------------------------------------------------------------------
// Depth stencil
//--------------------------------------------------------------------------
String mTargetDepthStencilName;
GFXTexHandle mTargetDepthStencil;
NamedTexTarget mNamedTargetDepthStencil;
//--------------------------------------------------------------------------
// State block / shader
//--------------------------------------------------------------------------
GFXStateBlockData* mStateBlockData; GFXStateBlockData* mStateBlockData;
GFXStateBlockRef mStateBlock; GFXStateBlockRef mStateBlock;
String mShaderName; String mShaderName;
GFXShaderRef mShader; GFXShaderRef mShader;
Vector<GFXShaderMacro> mShaderMacros; Vector<GFXShaderMacro> mShaderMacros;
GFXShaderConstBufferRef mShaderConsts; GFXShaderConstBufferRef mShaderConsts;
//--------------------------------------------------------------------------
// Auto shader constant handles
//--------------------------------------------------------------------------
GFXShaderConstHandle* mRTSizeSC; GFXShaderConstHandle* mRTSizeSC;
GFXShaderConstHandle* mOneOverRTSizeSC; GFXShaderConstHandle* mOneOverRTSizeSC;
GFXShaderConstHandle* mRTRatioSC; GFXShaderConstHandle* mRTRatioSC;
GFXShaderConstHandle* mTexSizeSC[NumTextures]; GFXShaderConstHandle* mTexSizeSC[NumTextures];
GFXShaderConstHandle* mRenderTargetParamsSC[NumTextures]; GFXShaderConstHandle* mRenderTargetParamsSC[NumTextures];
GFXShaderConstHandle* mMipCountSC[NumTextures]; GFXShaderConstHandle* mMipCountSC[NumTextures];
GFXShaderConstHandle* mViewportOffsetSC; GFXShaderConstHandle* mViewportOffsetSC;
GFXShaderConstHandle* mTargetViewportSC; GFXShaderConstHandle* mTargetViewportSC;
GFXShaderConstHandle* mFogDataSC; GFXShaderConstHandle* mFogDataSC;
GFXShaderConstHandle* mFogColorSC; GFXShaderConstHandle* mFogColorSC;
GFXShaderConstHandle* mEyePosSC; GFXShaderConstHandle* mEyePosSC;
@ -165,122 +185,59 @@ protected:
GFXShaderConstHandle* mInvCameraTransSC; GFXShaderConstHandle* mInvCameraTransSC;
GFXShaderConstHandle* mMatCameraToScreenSC; GFXShaderConstHandle* mMatCameraToScreenSC;
GFXShaderConstHandle* mMatScreenToCameraSC; GFXShaderConstHandle* mMatScreenToCameraSC;
GFXShaderConstHandle* mIsCapturingSC; GFXShaderConstHandle* mIsCapturingSC;
//--------------------------------------------------------------------------
// Render scheduling
//--------------------------------------------------------------------------
bool mAllowReflectPass; bool mAllowReflectPass;
/// If true update the shader.
bool mUpdateShader; bool mUpdateShader;
GFXTextureTargetRef mTarget;
String mTargetName;
GFXTexHandle mTargetTex;
S32 mMipCap;
String mTargetDepthStencilName;
GFXTexHandle mTargetDepthStencil;
/// If mTargetSize is zero then this scale is
/// used to make a relative texture size to the
/// active render target.
Point2F mTargetScale;
/// If non-zero this is used as the absolute
/// texture target size.
/// @see mTargetScale
Point2I mTargetSize;
GFXFormat mTargetFormat;
/// The color to prefill the named target when
/// first created by the effect.
LinearColorF mTargetClearColor;
PFXRenderTime mRenderTime; PFXRenderTime mRenderTime;
PFXTargetClear mTargetClear; PFXTargetClear mTargetClear_unused; // kept for binary compat if needed — see arrays above
PFXTargetViewport mTargetViewport;
String mRenderBin; String mRenderBin;
S16 mRenderPriority; S16 mRenderPriority;
/// This is true if the effect has been succesfully
/// initialized and all requirements are met for use.
bool mIsValid; bool mIsValid;
/// True if the effect has been enabled by the manager.
bool mEnabled; bool mEnabled;
/// Skip processing of this PostEffect and its children even if its parent is enabled.
/// Parent and sibling PostEffects in the chain are still processed.
/// This is intended for debugging purposes.
bool mSkip; bool mSkip;
bool mPreProcessed; bool mPreProcessed;
bool mOneFrameOnly; bool mOneFrameOnly;
bool mOnThisFrame; bool mOnThisFrame;
U32 mShaderReloadKey; U32 mShaderReloadKey;
//--------------------------------------------------------------------------
// EffectConst
//--------------------------------------------------------------------------
class EffectConst class EffectConst
{ {
public: public:
EffectConst(const String& name, const String& val) EffectConst(const String& name, const String& val)
: mName( name ), : mName(name), mHandle(NULL), mDirty(true) {
mHandle( NULL ),
mDirty( true )
{
set(val); set(val);
} }
EffectConst(const String& name, const F32& val) EffectConst(const String& name, const F32& val)
: mName(name), : mName(name), mHandle(NULL), mDirty(true) {
mHandle(NULL),
mDirty(true)
{
set(val); set(val);
} }
EffectConst(const String& name, const int& val) EffectConst(const String& name, const int& val)
: mName(name), : mName(name), mHandle(NULL), mDirty(true) {
mHandle(NULL),
mDirty(true)
{
set(val); set(val);
} }
EffectConst(const String& name, const Point4F& val) EffectConst(const String& name, const Point4F& val)
: mName(name), : mName(name), mHandle(NULL), mDirty(true) {
mHandle(NULL),
mDirty(true)
{
set(val); set(val);
} }
EffectConst(const String& name, const MatrixF& val) EffectConst(const String& name, const MatrixF& val)
: mName(name), : mName(name), mHandle(NULL), mDirty(true) {
mHandle(NULL),
mDirty(true)
{
set(val); set(val);
} }
EffectConst(const String& name, const Vector<Point4F>& val) EffectConst(const String& name, const Vector<Point4F>& val)
: mName(name), : mName(name), mHandle(NULL), mDirty(true) {
mHandle(NULL),
mDirty(true)
{
set(val); set(val);
} }
EffectConst(const String& name, const Vector<MatrixF>& val) EffectConst(const String& name, const Vector<MatrixF>& val)
: mName(name), : mName(name), mHandle(NULL), mDirty(true) {
mHandle(NULL),
mDirty(true)
{
set(val); set(val);
} }
@ -291,165 +248,130 @@ protected:
void set(const MatrixF& newVal); void set(const MatrixF& newVal);
void set(const Vector<Point4F>& newVal); void set(const Vector<Point4F>& newVal);
void set(const Vector<MatrixF>& newVal); void set(const Vector<MatrixF>& newVal);
void setToBuffer(GFXShaderConstBufferRef buff); void setToBuffer(GFXShaderConstBufferRef buff);
String mName; String mName;
GFXShaderConstHandle* mHandle; GFXShaderConstHandle* mHandle;
String mStringVal; String mStringVal;
S32 mIntVal; S32 mIntVal;
F32 mFloatVal; F32 mFloatVal;
Point4F mPointVal; Point4F mPointVal;
MatrixF mMatrixVal; MatrixF mMatrixVal;
Vector<Point4F> mPointArrayVal; Vector<Point4F> mPointArrayVal;
Vector<MatrixF> mMatrixArrayVal; Vector<MatrixF> mMatrixArrayVal;
enum enum {
{ StringType, IntType, FloatType, PointType,
StringType, MatrixType, PointArrayType, MatrixArrayType
IntType,
FloatType,
PointType,
MatrixType,
PointArrayType,
MatrixArrayType
} mValueType; } mValueType;
bool mDirty; bool mDirty;
}; };
typedef HashTable<StringCase, EffectConst*> EffectConstTable; typedef HashTable<StringCase, EffectConst*> EffectConstTable;
EffectConstTable mEffectConsts; EffectConstTable mEffectConsts;
/// //--------------------------------------------------------------------------
virtual void _updateScreenGeometry( const Frustum &frustum, // Internal methods
GFXVertexBufferHandle<PFXVertex> *outVB ); //--------------------------------------------------------------------------
/// virtual void _updateScreenGeometry(const Frustum& frustum, GFXVertexBufferHandle<PFXVertex>* outVB);
virtual void _setupStateBlock(const SceneRenderState* state); virtual void _setupStateBlock(const SceneRenderState* state);
///
virtual void _setupConstants(const SceneRenderState* state); virtual void _setupConstants(const SceneRenderState* state);
///
virtual void _setupTransforms(); virtual void _setupTransforms();
///
virtual void _setupTarget(const SceneRenderState* state, bool* outClearTarget); virtual void _setupTarget(const SceneRenderState* state, bool* outClearTarget);
///
virtual void _setupTexture(U32 slot, GFXTexHandle& inputTex, const RectI* inTexViewport); virtual void _setupTexture(U32 slot, GFXTexHandle& inputTex, const RectI* inTexViewport);
virtual void _setupCubemapTexture(U32 stage, GFXCubemapHandle& inputTex); virtual void _setupCubemapTexture(U32 stage, GFXCubemapHandle& inputTex);
virtual void _setupCubemapArrayTexture(U32 slot, GFXCubemapArrayHandle& inputTex); virtual void _setupCubemapArrayTexture(U32 slot, GFXCubemapArrayHandle& inputTex);
/// Protected set method for toggling the enabled state.
static bool _setIsEnabled(void* object, const char* index, const char* data); static bool _setIsEnabled(void* object, const char* index, const char* data);
/// Called from the light manager activate signal.
/// @see LightManager::addActivateCallback
void _onLMActivate(const char*, bool activate) void _onLMActivate(const char*, bool activate)
{ {
if ( activate ) if (activate) mUpdateShader = true;
mUpdateShader = true;
} }
/// We handle texture events to release named rendered targets.
/// @see GFXTextureManager::addEventDelegate
void _onTextureEvent(GFXTexCallbackCode code) void _onTextureEvent(GFXTexCallbackCode code)
{ {
if ( code == GFXZombify && (mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered()) ) if (code != GFXZombify) return;
_cleanTargets(); bool anyNamed = mNamedTargetDepthStencil.isRegistered();
for (U32 c = 0; c < NumMRTTargets && !anyNamed; c++)
anyNamed = mNamedTarget[c].isRegistered();
if (anyNamed) _cleanTargets();
} }
///
void _updateConditioners(); void _updateConditioners();
///
void _cleanTargets(bool recurse = false); void _cleanTargets(bool recurse = false);
///
void _checkRequirements(); void _checkRequirements();
///
GFXTextureObject* _getTargetTexture(U32 index); GFXTextureObject* _getTargetTexture(U32 index);
/// Map "$outTex" / "$outTex0".."$outTex3" to a slot index [0..NumMRTTargets-1].
/// Returns -1 if the name is not an $outTexN pattern.
S32 _outTexSlotFromName(const String& name)
{
if (name.compare("$outTex", 0, String::NoCase) == 0) return 0; // backwards compat
if (name.compare("$outTex0", 0, String::NoCase) == 0) return 0;
if (name.compare("$outTex1", 0, String::NoCase) == 0) return 1;
if (name.compare("$outTex2", 0, String::NoCase) == 0) return 2;
if (name.compare("$outTex3", 0, String::NoCase) == 0) return 3;
return -1;
}
S32 _inTexSlotFromName(const String& name)
{
if (name.compare("$inTex", 0, String::NoCase) == 0) return 0; // backwards compat
if (name.compare("$inTex0", 0, String::NoCase) == 0) return 0;
if (name.compare("$inTex1", 0, String::NoCase) == 0) return 1;
if (name.compare("$inTex2", 0, String::NoCase) == 0) return 2;
if (name.compare("$inTex3", 0, String::NoCase) == 0) return 3;
return -1;
}
public: public:
/// Constructor.
PostEffect(); PostEffect();
/// Destructor.
virtual ~PostEffect(); virtual ~PostEffect();
DECLARE_CONOBJECT(PostEffect); DECLARE_CONOBJECT(PostEffect);
// SimObject
bool onAdd() override; bool onAdd() override;
void onRemove() override; void onRemove() override;
static void initPersistFields(); static void initPersistFields();
/// @name Callbacks
/// @{
DECLARE_CALLBACK(void, onAdd, ()); DECLARE_CALLBACK(void, onAdd, ());
DECLARE_CALLBACK(void, preProcess, ()); DECLARE_CALLBACK(void, preProcess, ());
DECLARE_CALLBACK(void, setShaderConsts, ()); DECLARE_CALLBACK(void, setShaderConsts, ());
DECLARE_CALLBACK(bool, onEnabled, ()); DECLARE_CALLBACK(bool, onEnabled, ());
DECLARE_CALLBACK(void, onDisabled, ()); DECLARE_CALLBACK(void, onDisabled, ());
/// @}
virtual void process(const SceneRenderState* state, virtual void process(const SceneRenderState* state,
GFXTexHandle& inOutTex, GFXTexHandle& inOutTex,
const RectI* inTexViewport = NULL); const RectI* inTexViewport = NULL);
///
void reload(); void reload();
///
void enable(); void enable();
///
void disable(); void disable();
/// Dump the shader disassembly to a temporary text file.
/// Returns true and sets outFilename to the file if successful.
bool dumpShaderDisassembly(String& outFilename) const; bool dumpShaderDisassembly(String& outFilename) const;
/// Returns the SimSet which contains all PostEffects.
SimSet* getSet() const; SimSet* getSet() const;
///
bool isEnabled() const { return mEnabled; } bool isEnabled() const { return mEnabled; }
/// Is set to skip rendering.
bool isSkipped() const { return mSkip; } bool isSkipped() const { return mSkip; }
void setSkip(bool s) { mSkip = s; }
/// Set the effect to skip rendering.
void setSkip( bool skip ) { mSkip = skip; }
PFXRenderTime getRenderTime() const { return mRenderTime; } PFXRenderTime getRenderTime() const { return mRenderTime; }
const String& getRenderBin() const { return mRenderBin; } const String& getRenderBin() const { return mRenderBin; }
F32 getPriority() const { return mRenderPriority; } F32 getPriority() const { return mRenderPriority; }
void setTexture(U32 index, const String& filePath); void setTexture(U32 index, const String& filePath);
void setTexture(U32 index, const GFXTexHandle& texHandle); void setTexture(U32 index, const GFXTexHandle& texHandle);
void setCubemapTexture(U32 index, const GFXCubemapHandle &cubemapHandle); void setCubemapTexture(U32 index, const GFXCubemapHandle& handle);
void setCubemapArrayTexture(U32 index, const GFXCubemapArrayHandle &cubemapArrayHandle); void setCubemapArrayTexture(U32 index, const GFXCubemapArrayHandle& handle);
void setShaderMacro(const String& name, const String& value = String::EmptyString); void setShaderMacro(const String& name, const String& value = String::EmptyString);
bool removeShaderMacro(const String& name); bool removeShaderMacro(const String& name);
void clearShaderMacros(); void clearShaderMacros();
///
void setShaderConst(const String& name, const String& val); void setShaderConst(const String& name, const String& val);
void setShaderConst(const String& name, const F32& val); void setShaderConst(const String& name, const F32& val);
void setShaderConst(const String& name, const int& val); void setShaderConst(const String& name, const int& val);
@ -458,18 +380,16 @@ public:
void setShaderConst(const String& name, const Vector<Point4F>& val); void setShaderConst(const String& name, const Vector<Point4F>& val);
void setShaderConst(const String& name, const Vector<MatrixF>& val); void setShaderConst(const String& name, const Vector<MatrixF>& val);
void setOnThisFrame( bool enabled ) { mOnThisFrame = enabled; } void setOnThisFrame(bool e) { mOnThisFrame = e; }
bool isOnThisFrame() { return mOnThisFrame; } bool isOnThisFrame() { return mOnThisFrame; }
void setOneFrameOnly( bool enabled ) { mOneFrameOnly = enabled; } void setOneFrameOnly(bool e) { mOneFrameOnly = e; }
bool isOneFrameOnly() { return mOneFrameOnly; } bool isOneFrameOnly() { return mOneFrameOnly; }
F32 getAspectRatio() const; F32 getAspectRatio() const;
GFXShaderRef getShader() { return mShader; } GFXShaderRef getShader() { return mShader; }
Vector<GFXShaderMacro>* getShaderMacros() { return &mShaderMacros; } Vector<GFXShaderMacro>* getShaderMacros() { return &mShaderMacros; }
GFXShaderConstBufferRef getShaderConstBuffer() { return mShaderConsts; } GFXShaderConstBufferRef getShaderConstBuffer() { return mShaderConsts; }
enum PostEffectRequirements enum PostEffectRequirements
{ {
RequiresDepth = BIT(0), RequiresDepth = BIT(0),

View file

@ -99,11 +99,10 @@ struct PFXFrameState
}; };
/// ///
GFX_DeclareTextureProfile( PostFxTargetProfile) ;
GFX_DeclareTextureProfile( PostFxTextureProfile ); GFX_DeclareTextureProfile( PostFxTextureProfile );
GFX_DeclareTextureProfile( PostFxTextureSRGBProfile ); GFX_DeclareTextureProfile( PostFxTextureSRGBProfile );
GFX_DeclareTextureProfile( VRTextureProfile ); GFX_DeclareTextureProfile( VRTextureProfile );
GFX_DeclareTextureProfile( VRDepthProfile ); GFX_DeclareTextureProfile( VRDepthProfile );
/// ///

View file

@ -228,8 +228,8 @@ void PostEffectVis::onPFXProcessed( PostEffect *pfx )
GFXTextureObject *tex; GFXTextureObject *tex;
if ( pfx->mTargetTex ) if ( pfx->mTargetTex[0])
tex = pfx->mTargetTex; tex = pfx->mTargetTex[0];
else else
tex = PFXMGR->getBackBufferTex(); tex = PFXMGR->getBackBufferTex();
@ -245,7 +245,7 @@ void PostEffectVis::onPFXProcessed( PostEffect *pfx )
if ( tex ) if ( tex )
dSprintf( caption, 256, "%s[%i] target - %s [ %ix%i ]", name, pfx->getId(), pfx->mTargetName.c_str(), tex->getWidth(), tex->getHeight() ); dSprintf( caption, 256, "%s[%i] target - %s [ %ix%i ]", name, pfx->getId(), pfx->mTargetName[0].c_str(), tex->getWidth(), tex->getHeight());
else else
dSprintf( caption, 256, "%s[%i] target", name, pfx->getId() ); dSprintf( caption, 256, "%s[%i] target", name, pfx->getId() );