diff --git a/Engine/source/lighting/common/projectedShadow.cpp b/Engine/source/lighting/common/projectedShadow.cpp index 030c37fd7..867f5c1b8 100644 --- a/Engine/source/lighting/common/projectedShadow.cpp +++ b/Engine/source/lighting/common/projectedShadow.cpp @@ -551,7 +551,7 @@ void ProjectedShadow::_renderToTexture( F32 camDist, const TSRenderState &rdata } if ( smShadowFilter ) - smShadowFilter->process( NULL, mShadowTexture ); + smShadowFilter->process( NULL, &mShadowTexture ); } // Restore frustum diff --git a/Engine/source/postFx/postEffect.cpp b/Engine/source/postFx/postEffect.cpp index ab4363c37..9b2db6808 100644 --- a/Engine/source/postFx/postEffect.cpp +++ b/Engine/source/postFx/postEffect.cpp @@ -137,9 +137,6 @@ GFX_ImplementTextureProfile( PostFxTargetProfile, GFXTextureProfile::Pooled, GFXTextureProfile::NONE ); -IMPLEMENT_CONOBJECT(PostEffect); - - GFX_ImplementTextureProfile( PostFxTextureProfile, GFXTextureProfile::DiffuseMap, GFXTextureProfile::Static | GFXTextureProfile::PreserveSize, @@ -162,6 +159,12 @@ GFX_ImplementTextureProfile( VRDepthProfile, GFXTextureProfile::ZTarget, GFXTextureProfile::NONE ); +IMPLEMENT_CONOBJECT(PostEffect); + +//--------------------------------------------------------------------- +// EffectConst +//--------------------------------------------------------------------- + void PostEffect::EffectConst::set( const String &newVal ) { if ( mStringVal == newVal ) @@ -445,69 +448,77 @@ void PostEffect::EffectConst::setToBuffer( GFXShaderConstBufferRef buff ) } } +//--------------------------------------------------------------------- +// EffectConst END +//--------------------------------------------------------------------- //------------------------------------------------------------------------- // PostEffect //------------------------------------------------------------------------- PostEffect::PostEffect() - : mRenderTime( PFXAfterDiffuse ), - mRenderPriority( 1.0 ), - mEnabled( false ), - mStateBlockData( NULL ), - mUpdateShader( true ), - mSkip( false ), - mPreProcessed(false), - mAllowReflectPass( false ), - mTargetClear( PFXTargetClear_None ), - mTargetScale( Point2F::One ), - mTargetViewport( PFXTargetViewport_TargetSize ), - mTargetSize( Point2I::Zero ), - mTargetFormat( GFXFormatR8G8B8A8 ), - mTargetClearColor( LinearColorF::BLACK ), - mOneFrameOnly( false ), - mOnThisFrame( true ), - mRTSizeSC( NULL ), - mIsValid( false ), - mShaderReloadKey( 0 ), - mOneOverRTSizeSC( NULL ), - mViewportOffsetSC( NULL ), - mTargetViewportSC( NULL ), - mFogDataSC( NULL ), - mFogColorSC( NULL ), - mEyePosSC( NULL ), - mMatWorldToScreenSC( NULL ), - mMatScreenToWorldSC( NULL ), - mMatPrevScreenToWorldSC( NULL ), - mNearFarSC( NULL ), - mInvNearFarSC( NULL ), - mWorldToScreenScaleSC( NULL ), - mProjectionOffsetSC( NULL ), - mWaterColorSC( NULL ), - mWaterFogDataSC( NULL ), - mAmbientColorSC( NULL ), - mWaterFogPlaneSC( NULL ), - mWaterDepthGradMaxSC( NULL ), - mScreenSunPosSC( NULL ), - mLightDirectionSC( NULL ), - mCameraForwardSC( NULL ), - mAccumTimeSC( NULL ), - mDampnessSC(NULL), - mDeltaTimeSC( NULL ), - mInvCameraMatSC( NULL ), - mMatCameraToWorldSC( NULL), - mInvCameraTransSC(NULL), - mMatCameraToScreenSC(NULL), - mMatScreenToCameraSC(NULL), - mIsCapturingSC(NULL), - mMipCap(1) + : mRenderTime(PFXAfterDiffuse), + mRenderPriority(1.0), + mEnabled(false), + mStateBlockData(NULL), + mUpdateShader(true), + mSkip(false), + mPreProcessed(false), + mAllowReflectPass(false), + mTargetScale(Point2F::One), + mTargetSize(Point2I::Zero), + mTargetViewport(PFXTargetViewport_TargetSize), + mMipCap(1), + mOneFrameOnly(false), + mOnThisFrame(true), + mRTSizeSC(NULL), + mIsValid(false), + mShaderReloadKey(0), + mOneOverRTSizeSC(NULL), + mViewportOffsetSC(NULL), + mTargetViewportSC(NULL), + mFogDataSC(NULL), + mFogColorSC(NULL), + mEyePosSC(NULL), + mMatWorldToScreenSC(NULL), + mMatScreenToWorldSC(NULL), + mMatPrevScreenToWorldSC(NULL), + mNearFarSC(NULL), + mInvNearFarSC(NULL), + mWorldToScreenScaleSC(NULL), + mProjectionOffsetSC(NULL), + mWaterColorSC(NULL), + mWaterFogDataSC(NULL), + mAmbientColorSC(NULL), + mWaterFogPlaneSC(NULL), + mWaterDepthGradMaxSC(NULL), + mScreenSunPosSC(NULL), + mLightDirectionSC(NULL), + mCameraForwardSC(NULL), + mAccumTimeSC(NULL), + mDampnessSC(NULL), + mDeltaTimeSC(NULL), + mInvCameraMatSC(NULL), + mMatCameraToWorldSC(NULL), + mInvCameraTransSC(NULL), + mMatCameraToScreenSC(NULL), + mMatScreenToCameraSC(NULL), + mIsCapturingSC(NULL) { - dMemset( mTexSRGB, 0, sizeof(bool) * NumTextures); - dMemset( mActiveTextures, 0, sizeof( GFXTextureObject* ) * NumTextures ); - dMemset( mActiveNamedTarget, 0, sizeof( NamedTexTarget* ) * NumTextures ); - dMemset( mActiveTextureViewport, 0, sizeof( RectI ) * NumTextures ); - dMemset( mTexSizeSC, 0, sizeof( GFXShaderConstHandle* ) * NumTextures ); - dMemset( mRenderTargetParamsSC, 0, sizeof( GFXShaderConstHandle* ) * NumTextures ); + // 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(mActiveTextures, 0, sizeof(GFXTextureObject*) * NumTextures); + dMemset(mActiveNamedTarget, 0, sizeof(NamedTexTarget*) * NumTextures); + dMemset(mActiveTextureViewport, 0, sizeof(RectI) * NumTextures); + dMemset(mTexSizeSC, 0, sizeof(GFXShaderConstHandle*) * NumTextures); + dMemset(mRenderTargetParamsSC, 0, sizeof(GFXShaderConstHandle*) * NumTextures); dMemset(mMipCountSC, 0, sizeof(GFXShaderConstHandle*) * NumTextures); } @@ -527,9 +538,18 @@ void PostEffect::initPersistFields() addField( "stateBlock", TYPEID(), Offset( mStateBlockData, PostEffect ), "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" "@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 ), "Optional string identifier for this effect's target depth/stencil texture.\n" @@ -543,15 +563,6 @@ void PostEffect::initPersistFields() addField( "targetSize", TypePoint2I, Offset( mTargetSize, PostEffect ), "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 ), "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? - if ( mTargetName.isNotEmpty() && mTargetName[0] == '#' ) + bool anyNamed = false; + for (U32 c = 0; c < NumMRTTargets; c++) { - mNamedTarget.registerWithName(mTargetName.substr(1)); - mNamedTarget.getTextureDelegate().bind( this, &PostEffect::_getTargetTexture ); + if (mTargetName[c].isNotEmpty() && mTargetName[c][0] == '#') + { + mNamedTarget[c].registerWithName(mTargetName[c].substr(1)); + mNamedTarget[c].getTextureDelegate().bind(this, &PostEffect::_getTargetTexture); + anyNamed = true; + } } + if ( mTargetDepthStencilName.isNotEmpty() && mTargetDepthStencilName[0] == '#' ) mNamedTargetDepthStencil.registerWithName( mTargetDepthStencilName.substr( 1 ) ); - if (mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered()) + if (anyNamed || mNamedTargetDepthStencil.isRegistered()) GFXTextureManager::addEventDelegate( this, &PostEffect::_onTextureEvent ); // Call onAdd in script @@ -661,15 +678,20 @@ void PostEffect::onRemove() mShader = NULL; _cleanTargets(); - if ( mNamedTarget.isRegistered() || mNamedTargetDepthStencil.isRegistered() ) - GFXTextureManager::removeEventDelegate( this, &PostEffect::_onTextureEvent ); - - if ( mNamedTarget.isRegistered() ) + bool anyNamed = false; + for (U32 c = 0; c < NumMRTTargets; c++) { - mNamedTarget.unregister(); - mNamedTarget.getTextureDelegate().clear(); + if (mNamedTarget[c].isRegistered()) + { + mNamedTarget[c].unregister(); + mNamedTarget[c].getTextureDelegate().clear(); + anyNamed = true; + } } + if (anyNamed || mNamedTargetDepthStencil.isRegistered() ) + GFXTextureManager::removeEventDelegate( this, &PostEffect::_onTextureEvent ); + if ( mNamedTargetDepthStencil.isRegistered() ) mNamedTargetDepthStencil.unregister(); } @@ -1147,7 +1169,10 @@ void PostEffect::_setupConstants( const SceneRenderState *state ) } } -void PostEffect::_setupTexture( U32 stage, GFXTexHandle &inputTex, const RectI *inTexViewport ) +void PostEffect::_setupTexture(U32 stage, + GFXTexHandle* inputTex, + U32 inputTexCount, + const RectI* inTexViewport) { const String &texFilename = mTextureAsset[stage].notNull() ? mTextureAsset[stage]->getImageFile() : ""; @@ -1156,17 +1181,17 @@ void PostEffect::_setupTexture( U32 stage, GFXTexHandle &inputTex, const RectI * RectI viewport = GFX->getViewport(); - if ( texFilename.compare( "$inTex", 0, String::NoCase ) == 0 ) + S32 inSlot = _inTexSlotFromName(texFilename); + if (inSlot >= 0) { - theTex = inputTex; + if ((U32)inSlot < inputTexCount) + { + theTex = inputTex[inSlot]; - if ( inTexViewport ) - { - viewport = *inTexViewport; - } - else if ( theTex ) - { - viewport.set( 0, 0, theTex->getWidth(), theTex->getHeight() ); + if (inSlot == 0 && inTexViewport) + viewport = *inTexViewport; + else if (theTex) + viewport.set(0, 0, theTex->getWidth(), theTex->getHeight()); } } else if ( texFilename.compare( "$backBuffer", 0, String::NoCase ) == 0 ) @@ -1236,162 +1261,144 @@ void PostEffect::_setupTransforms() void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarget ) { - if ( mNamedTarget.isRegistered() || - mTargetName.compare( "$outTex", 0, String::NoCase ) == 0 ) + Point2I targetSize; + if (!mTargetSize.isZero()) + targetSize = mTargetSize; + else if (mActiveTextures[0]) { - // Size it relative to the texture of the first stage or - // if NULL then use the current target. - - Point2I targetSize; - - // If we have an absolute target size then use that. - if ( !mTargetSize.isZero() ) - targetSize = mTargetSize; - - // Else generate a relative size using the target scale. - else if ( mActiveTextures[ 0 ] ) - { - const Point3I &texSize = mActiveTextures[ 0 ]->getSize(); - - targetSize.set( texSize.x * mTargetScale.x, - texSize.y * mTargetScale.y ); - } - else - { - GFXTarget *oldTarget = GFX->getActiveRenderTarget(); - const Point2I &oldTargetSize = oldTarget->getSize(); - - targetSize.set( oldTargetSize.x * mTargetScale.x, - oldTargetSize.y * mTargetScale.y ); - } - - // Make sure its at least 1x1. - targetSize.setMax( Point2I::One ); - - if ( mNamedTarget.isRegistered() || - !mTargetTex || - mTargetTex.getWidthHeight() != targetSize ) - { - mTargetTex.set( targetSize.x, targetSize.y, mTargetFormat, - &PostFxTargetProfile, "PostEffect::_setupTarget", mMipCap); - - if ( mTargetClear == PFXTargetClear_OnCreate ) - *outClearTarget = true; - - if(mTargetViewport == PFXTargetViewport_GFXViewport) - { - // We may need to scale the GFX viewport to fit within - // our target texture size - GFXTarget *oldTarget = GFX->getActiveRenderTarget(); - const Point2I &oldTargetSize = oldTarget->getSize(); - Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y)); - - 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 ) ); - } - else if(mTargetViewport == PFXTargetViewport_NamedInTexture0 && mActiveNamedTarget[0] && mActiveNamedTarget[0]->getTexture()) - { - // Scale the named input texture's viewport to match our target - const Point3I &namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize(); - Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y)); - - 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 ) ); - } - else - { - // PFXTargetViewport_TargetSize - mNamedTarget.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) ); - } - } + const Point3I& texSize = mActiveTextures[0]->getSize(); + targetSize.set(texSize.x * mTargetScale.x, texSize.y * mTargetScale.y); } else - mTargetTex = NULL; - - // Do we have a named depthStencil target? - if ( mNamedTargetDepthStencil.isRegistered() ) { - // Size it relative to the texture of the first stage or - // if NULL then use the current target. - Point2I targetSize; + GFXTarget* oldTarget = GFX->getActiveRenderTarget(); + const Point2I& oldTargetSize = oldTarget->getSize(); + targetSize.set(oldTargetSize.x * mTargetScale.x, oldTargetSize.y * mTargetScale.y); + } + targetSize.setMax(Point2I::One); - // If we have an absolute target size then use that. - if ( !mTargetSize.isZero() ) - targetSize = mTargetSize; - - // Else generate a relative size using the target scale. - else if ( mActiveTextures[ 0 ] ) + for (U32 c = 0; c < NumMRTTargets; c++) + { + if (mNamedTarget[c].isRegistered() || _outTexSlotFromName(mTargetName[c]) >= 0) { - const Point3I &texSize = mActiveTextures[ 0 ]->getSize(); + if (mNamedTarget[c].isRegistered() || + !mTargetTex[c] || + mTargetTex[c].getWidthHeight() != targetSize) + { + mTargetTex[c].set(targetSize.x, targetSize.y, mTargetFormat[c], + &PostFxTargetProfile, "PostEffect::_setupTarget", mMipCap); - targetSize.set( texSize.x * mTargetScale.x, - texSize.y * mTargetScale.y ); + if (mTargetClear[c] == PFXTargetClear_OnCreate) + *outClearTarget = true; + + if (mTargetViewport == PFXTargetViewport_GFXViewport) + { + // We may need to scale the GFX viewport to fit within + // our target texture size + GFXTarget* oldTarget = GFX->getActiveRenderTarget(); + const Point2I& oldTargetSize = oldTarget->getSize(); + Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y)); + const RectI& viewport = GFX->getViewport(); + 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()) + { + // Scale the named input texture's viewport to match our target + const Point3I& namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize(); + Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y)); + const RectI& viewport = mActiveNamedTarget[0]->getViewport(); + 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 + { + mNamedTarget[c].setViewport(RectI(0, 0, targetSize.x, targetSize.y)); + } + } } else + mTargetTex[c] = NULL; + } + + bool auxActive = false; + for (U32 c = 1; c < NumMRTTargets; c++) + { + if (mTargetTex[c].isValid()) { - GFXTarget *oldTarget = GFX->getActiveRenderTarget(); - const Point2I &oldTargetSize = oldTarget->getSize(); - - targetSize.set( oldTargetSize.x * mTargetScale.x, - oldTargetSize.y * mTargetScale.y ); + auxActive = true; + break; } + } - // Make sure its at least 1x1. - targetSize.setMax( Point2I::One ); - - if ( mNamedTargetDepthStencil.isRegistered() && - mTargetDepthStencil.getWidthHeight() != targetSize ) - { - mTargetDepthStencil.set( targetSize.x, targetSize.y, GFXFormatD24S8, - &GFXZTargetProfile, "PostEffect::_setupTarget" ); + if (auxActive && !mTargetTex[0].isValid()) + { + /* If we have issues later on, uncomment this! + Con::warnf("PostEffect '%s': auxiliary MRT slots are active but target[0] " + "has no texture. Auto-promoting slot 0 to a temporary. " + "Use a named target (#name) on slot 0 for MRT setups.", getName());*/ - if ( mTargetClear == PFXTargetClear_OnCreate ) + mTargetTex[0].set(targetSize.x, targetSize.y, mTargetFormat[0], + &PostFxTargetProfile, "PostEffect::MRTSlot[0]_auto", mMipCap); + } + + if (mNamedTargetDepthStencil.isRegistered()) + { + if (mNamedTargetDepthStencil.isRegistered() && mTargetDepthStencil.getWidthHeight() != targetSize) + { + mTargetDepthStencil.set(targetSize.x, targetSize.y, GFXFormatD24S8, + &GFXZTargetProfile, "PostEffect::_setupTarget"); + + if (mTargetClear[0] == PFXTargetClear_OnCreate) *outClearTarget = true; - if(mTargetViewport == PFXTargetViewport_GFXViewport) + if (mTargetViewport == PFXTargetViewport_GFXViewport) { // We may need to scale the GFX viewport to fit within // our target texture size - GFXTarget *oldTarget = GFX->getActiveRenderTarget(); - const Point2I &oldTargetSize = oldTarget->getSize(); + GFXTarget* oldTarget = GFX->getActiveRenderTarget(); + const Point2I& oldTargetSize = oldTarget->getSize(); Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y)); + const RectI& viewport = GFX->getViewport(); - const RectI &viewport = GFX->getViewport(); - - mNamedTargetDepthStencil.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) ); + mNamedTargetDepthStencil.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()) { // Scale the named input texture's viewport to match our target - const Point3I &namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize(); + const Point3I& namedTargetSize = mActiveNamedTarget[0]->getTexture()->getSize(); Point2F scale(targetSize.x / F32(namedTargetSize.x), targetSize.y / F32(namedTargetSize.y)); + const RectI& viewport = mActiveNamedTarget[0]->getViewport(); - const RectI &viewport = mActiveNamedTarget[0]->getViewport(); - - mNamedTargetDepthStencil.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) ); + mNamedTargetDepthStencil.setViewport(RectI(viewport.point.x * scale.x, viewport.point.y * scale.y, viewport.extent.x * scale.x, viewport.extent.y * scale.y)); } else { // PFXTargetViewport_TargetSize - mNamedTargetDepthStencil.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) ); + mNamedTargetDepthStencil.setViewport(RectI(0, 0, targetSize.x, targetSize.y)); } } } else mTargetDepthStencil = NULL; - if ( mTargetClear == PFXTargetClear_OnDraw ) + if (mTargetClear[0] == PFXTargetClear_OnDraw) *outClearTarget = true; - if ( !mTarget && (mTargetTex || mTargetDepthStencil) ) + bool hasAny = mTargetDepthStencil.isValid(); + for (U32 c = 0; c < NumMRTTargets && !hasAny; c++) + hasAny = mTargetTex[c].isValid(); + + if (!mTarget && hasAny) mTarget = GFX->allocRenderToTextureTarget(); } void PostEffect::_cleanTargets( bool recurse ) { - mTargetTex = NULL; + for (U32 c = 0; c < NumMRTTargets; c++) + mTargetTex[c] = NULL; + mTargetDepthStencil = NULL; mTarget = NULL; @@ -1406,9 +1413,10 @@ void PostEffect::_cleanTargets( bool recurse ) } } -void PostEffect::process( const SceneRenderState *state, - GFXTexHandle &inOutTex, - const RectI *inTexViewport ) +void PostEffect::process( const SceneRenderState* state, + GFXTexHandle* inOutTex, + U32 inOutTexCount, + const RectI* inTexViewport) { // If the shader is forced to be skipped... then skip. if ( mSkip ) @@ -1444,11 +1452,16 @@ void PostEffect::process( const SceneRenderState *state, } GFXTransformSaver saver; + GFXTexHandle chain[NumMRTTargets]; + U32 texCount = getMin(inOutTexCount, (U32)NumMRTTargets); + for (U32 c = 0; c < texCount; c++) + chain[c] = inOutTex[c]; + // Set the textures. for (U32 i = 0; i < NumTextures; i++) { if (mTextureType[i] == NormalTextureType) - _setupTexture(i, inOutTex, inTexViewport); + _setupTexture(i, chain, texCount, inTexViewport); else if (mTextureType[i] == CubemapType) _setupCubemapTexture(i, mCubemapTextures[i]); else if (mTextureType[i] == CubemapArrayType) @@ -1461,27 +1474,57 @@ void PostEffect::process( const SceneRenderState *state, bool clearTarget = false; _setupTarget( state, &clearTarget ); - if ( mTargetTex || mTargetDepthStencil ) + const bool hasDepth = mTargetDepthStencil.isValid(); + bool hasColorTarget = false; + + U32 curTargetCount = 0; + for (U32 c = 0; c < NumMRTTargets; c++) + { + if (mTargetTex[c].isValid()) + { + hasColorTarget = true; + curTargetCount++; + } + } + + // 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(); GFXTarget *oldTarget = GFX->getActiveRenderTarget(); 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. - if ( !mTargetDepthStencil && mTargetTex.getWidthHeight() == GFX->getActiveRenderTarget()->getSize() ) - mTarget->attachTexture( GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil ); + if (!hasDepth && mTargetTex[0].isValid() && mTargetTex[0].getWidthHeight() == oldTarget->getSize()) + mTarget->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil); else - mTarget->attachTexture( GFXTextureTarget::DepthStencil, mTargetDepthStencil ); + mTarget->attachTexture(GFXTextureTarget::DepthStencil, mTargetDepthStencil); // Set the render target but not its viewport. We'll do that below. 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.getViewport()); + GFX->setViewport(mNamedTarget[0].getViewport()); + } + else if (mTargetTex[0].isValid()) + { + GFX->setViewport(RectI(Point2I::Zero, mTargetTex[0].getWidthHeight())); } else if(mTargetViewport == PFXTargetViewport_GFXViewport) { @@ -1509,8 +1552,19 @@ void PostEffect::process( const SceneRenderState *state, } } - if ( clearTarget ) - GFX->clear( GFXClearTarget, mTargetClearColor, 1.f, 0 ); + if (clearTarget) + { + 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. if ( mShader ) @@ -1545,35 +1599,36 @@ void PostEffect::process( const SceneRenderState *state, // Allow PostEffecVis to hook in. PFXVIS->onPFXProcessed( this ); - if ( mTargetTex || mTargetDepthStencil ) + if (hasColorTarget || hasDepth) { mTarget->resolve(); GFX->popActiveRenderTarget(); } 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(); } - // Return and release our target texture. - inOutTex = mTargetTex; - if ( !mNamedTarget.isRegistered() ) - mTargetTex = NULL; + for (U32 c = 0; c < NumMRTTargets; c++) + { + if (c < texCount) + chain[c] = mTargetTex[c]; + + if (!mNamedTarget[c].isRegistered()) + mTargetTex[c] = NULL; + } // Restore the transforms before the children // are processed as it screws up the viewport. saver.restore(); + const U32 nextTexCount = getMax(getMax(texCount, curTargetCount), 1u); // Now process my children. iterator i = begin(); for ( ; i != end(); i++ ) { PostEffect *effect = static_cast(*i); - effect->process( state, inOutTex ); + effect->process( state, chain, nextTexCount); } if ( mOneFrameOnly ) @@ -1842,19 +1897,22 @@ void PostEffect::_checkRequirements() } // First make sure the target format is supported. - if ( mNamedTarget.isRegistered() ) + for (U32 c = 0; c < NumMRTTargets; c++) { - Vector formats; - formats.push_back( mTargetFormat ); - GFXFormat format = GFX->selectSupportedFormat( &PostFxTargetProfile, - formats, - true, - false, - false ); - - // If we didn't get our format out then its unsupported! - if ( format != mTargetFormat ) - return; + if (mNamedTarget[c].isRegistered()) + { + Vector formats; + formats.push_back(mTargetFormat[c]); + GFXFormat format = GFX->selectSupportedFormat(&PostFxTargetProfile, + formats, + true, + false, + false); + + // If we didn't get our format out then its unsupported! + if (format != mTargetFormat[c]) + return; + } } // Gather macros specified on this PostEffect. @@ -1981,22 +2039,16 @@ void PostEffect::clearShaderMacros() mUpdateShader = true; } -GFXTextureObject* PostEffect::_getTargetTexture( U32 ) +GFXTextureObject* PostEffect::_getTargetTexture(U32 index) { - // A TexGen PostEffect will generate its texture now if it - // has not already. - if ( mRenderTime == PFXTexGenOnDemand && - ( !mTargetTex || mUpdateShader ) ) + if (mRenderTime == PFXTexGenOnDemand + && (!mTargetTex[index] || mUpdateShader)) { - GFXTexHandle chainTex; - process( NULL, chainTex ); - - // TODO: We should add a conditional copy - // to a non-RT texture here to reduce the - // amount of non-swappable RTs in use. + GFXTexHandle chainTex[NumMRTTargets]; // zero-initialised by GFXTexHandle ctor + process(NULL, chainTex, NumMRTTargets); } - return mTargetTex.getPointer(); + return mTargetTex[index].getPointer(); } DefineEngineMethod( PostEffect, reload, void, (),, diff --git a/Engine/source/postFx/postEffect.h b/Engine/source/postFx/postEffect.h index 101f171dc..7d7914f22 100644 --- a/Engine/source/postFx/postEffect.h +++ b/Engine/source/postFx/postEffect.h @@ -67,14 +67,6 @@ class Frustum; class SceneRenderState; class ConditionerFeature; - -/// -GFX_DeclareTextureProfile( PostFxTargetProfile ); - - - - -/// class PostEffect : public SimGroup { typedef SimGroup Parent; @@ -86,389 +78,318 @@ public: enum { NumTextures = 16, + + /// Maximum simultaneous color render target outputs (MRT) + NumMRTTargets = 4, }; protected: + //-------------------------------------------------------------------------- + // Input textures + //-------------------------------------------------------------------------- + DECLARE_IMAGEASSET_ARRAY(PostEffect, Texture, GFXStaticTextureSRGBProfile, NumTextures); - GFXTextureProfile* mTextureProfile[NumTextures]; - GFXTexHandle mTexture[NumTextures]; + GFXTextureProfile* mTextureProfile[NumTextures]; + GFXTexHandle mTexture[NumTextures]; + bool mTexSRGB[NumTextures]; - bool mTexSRGB[NumTextures]; + enum { NormalTextureType = 0, CubemapType, CubemapArrayType } mTextureType[NumTextures]; - enum - { - NormalTextureType = 0, - CubemapType, - CubemapArrayType, - } mTextureType[NumTextures]; - - GFXCubemapHandle mCubemapTextures[NumTextures]; + GFXCubemapHandle mCubemapTextures[NumTextures]; GFXCubemapArrayHandle mCubemapArrayTextures[NumTextures]; - NamedTexTarget mNamedTarget; - NamedTexTarget mNamedTargetDepthStencil; + GFXTextureObject* mActiveTextures[NumTextures]; + NamedTexTarget* mActiveNamedTarget[NumTextures]; + RectI mActiveTextureViewport[NumTextures]; - GFXTextureObject *mActiveTextures[NumTextures]; + //-------------------------------------------------------------------------- + // MRT color output targets + // + // Replaces the original single: mNamedTarget, mTargetName, mTargetTex, + // mTargetFormat, mTargetClearColor, mTargetClear + //-------------------------------------------------------------------------- - NamedTexTarget *mActiveNamedTarget[NumTextures]; + 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. - RectI mActiveTextureViewport[NumTextures]; + GFXTexHandle mTargetTex[NumMRTTargets]; ///< Runtime texture per slot. + NamedTexTarget mNamedTarget[NumMRTTargets]; ///< Named target per slot. - GFXStateBlockData *mStateBlockData; - - GFXStateBlockRef mStateBlock; - - String mShaderName; - - GFXShaderRef mShader; - - Vector mShaderMacros; - - GFXShaderConstBufferRef mShaderConsts; - - GFXShaderConstHandle *mRTSizeSC; - GFXShaderConstHandle *mOneOverRTSizeSC; - GFXShaderConstHandle* mRTRatioSC; - - GFXShaderConstHandle *mTexSizeSC[NumTextures]; - GFXShaderConstHandle *mRenderTargetParamsSC[NumTextures]; - GFXShaderConstHandle* mMipCountSC[NumTextures]; - - GFXShaderConstHandle *mViewportOffsetSC; - - GFXShaderConstHandle *mTargetViewportSC; - - GFXShaderConstHandle *mFogDataSC; - GFXShaderConstHandle *mFogColorSC; - GFXShaderConstHandle *mEyePosSC; - GFXShaderConstHandle *mMatWorldToScreenSC; - GFXShaderConstHandle *mMatScreenToWorldSC; - GFXShaderConstHandle *mMatPrevScreenToWorldSC; - GFXShaderConstHandle *mNearFarSC; - GFXShaderConstHandle *mInvNearFarSC; - GFXShaderConstHandle *mWorldToScreenScaleSC; - GFXShaderConstHandle *mProjectionOffsetSC; - GFXShaderConstHandle *mWaterColorSC; - GFXShaderConstHandle *mWaterFogDataSC; - GFXShaderConstHandle *mAmbientColorSC; - GFXShaderConstHandle *mWaterFogPlaneSC; - GFXShaderConstHandle *mWaterDepthGradMaxSC; - GFXShaderConstHandle *mScreenSunPosSC; - GFXShaderConstHandle *mLightDirectionSC; - GFXShaderConstHandle *mCameraForwardSC; - GFXShaderConstHandle *mAccumTimeSC; - GFXShaderConstHandle* mDampnessSC; - GFXShaderConstHandle *mDeltaTimeSC; - GFXShaderConstHandle *mInvCameraMatSC; - GFXShaderConstHandle *mMatCameraToWorldSC; - GFXShaderConstHandle *mInvCameraTransSC; - GFXShaderConstHandle *mMatCameraToScreenSC; - GFXShaderConstHandle *mMatScreenToCameraSC; - - GFXShaderConstHandle* mIsCapturingSC; - - bool mAllowReflectPass; - - /// If true update the shader. - bool mUpdateShader; + // 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; - String mTargetName; - GFXTexHandle mTargetTex; S32 mMipCap; - String mTargetDepthStencilName; - GFXTexHandle mTargetDepthStencil; + //-------------------------------------------------------------------------- + // Depth stencil + //-------------------------------------------------------------------------- - /// If mTargetSize is zero then this scale is - /// used to make a relative texture size to the - /// active render target. - Point2F mTargetScale; + String mTargetDepthStencilName; + GFXTexHandle mTargetDepthStencil; + NamedTexTarget mNamedTargetDepthStencil; - /// If non-zero this is used as the absolute - /// texture target size. - /// @see mTargetScale - Point2I mTargetSize; + //-------------------------------------------------------------------------- + // State block / shader + //-------------------------------------------------------------------------- - GFXFormat mTargetFormat; + GFXStateBlockData* mStateBlockData; + GFXStateBlockRef mStateBlock; + String mShaderName; + GFXShaderRef mShader; + Vector mShaderMacros; + GFXShaderConstBufferRef mShaderConsts; - /// The color to prefill the named target when - /// first created by the effect. - LinearColorF mTargetClearColor; + //-------------------------------------------------------------------------- + // Auto shader constant handles + //-------------------------------------------------------------------------- + GFXShaderConstHandle* mRTSizeSC; + GFXShaderConstHandle* mOneOverRTSizeSC; + GFXShaderConstHandle* mRTRatioSC; + GFXShaderConstHandle* mTexSizeSC[NumTextures]; + GFXShaderConstHandle* mRenderTargetParamsSC[NumTextures]; + GFXShaderConstHandle* mMipCountSC[NumTextures]; + GFXShaderConstHandle* mViewportOffsetSC; + GFXShaderConstHandle* mTargetViewportSC; + GFXShaderConstHandle* mFogDataSC; + GFXShaderConstHandle* mFogColorSC; + GFXShaderConstHandle* mEyePosSC; + GFXShaderConstHandle* mMatWorldToScreenSC; + GFXShaderConstHandle* mMatScreenToWorldSC; + GFXShaderConstHandle* mMatPrevScreenToWorldSC; + GFXShaderConstHandle* mNearFarSC; + GFXShaderConstHandle* mInvNearFarSC; + GFXShaderConstHandle* mWorldToScreenScaleSC; + GFXShaderConstHandle* mProjectionOffsetSC; + GFXShaderConstHandle* mWaterColorSC; + GFXShaderConstHandle* mWaterFogDataSC; + GFXShaderConstHandle* mAmbientColorSC; + GFXShaderConstHandle* mWaterFogPlaneSC; + GFXShaderConstHandle* mWaterDepthGradMaxSC; + GFXShaderConstHandle* mScreenSunPosSC; + GFXShaderConstHandle* mLightDirectionSC; + GFXShaderConstHandle* mCameraForwardSC; + GFXShaderConstHandle* mAccumTimeSC; + GFXShaderConstHandle* mDampnessSC; + GFXShaderConstHandle* mDeltaTimeSC; + GFXShaderConstHandle* mInvCameraMatSC; + GFXShaderConstHandle* mMatCameraToWorldSC; + GFXShaderConstHandle* mInvCameraTransSC; + GFXShaderConstHandle* mMatCameraToScreenSC; + GFXShaderConstHandle* mMatScreenToCameraSC; + GFXShaderConstHandle* mIsCapturingSC; + + //-------------------------------------------------------------------------- + // Render scheduling + //-------------------------------------------------------------------------- + + bool mAllowReflectPass; + bool mUpdateShader; PFXRenderTime mRenderTime; - PFXTargetClear mTargetClear; - PFXTargetViewport mTargetViewport; + PFXTargetClear mTargetClear_unused; // kept for binary compat if needed — see arrays above + String mRenderBin; + S16 mRenderPriority; + bool mIsValid; + bool mEnabled; + bool mSkip; + bool mPreProcessed; + bool mOneFrameOnly; + bool mOnThisFrame; + U32 mShaderReloadKey; - String mRenderBin; - - S16 mRenderPriority; - - /// This is true if the effect has been succesfully - /// initialized and all requirements are met for use. - bool mIsValid; - - /// True if the effect has been enabled by the manager. - 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 mPreProcessed; - - bool mOneFrameOnly; - bool mOnThisFrame; - - U32 mShaderReloadKey; + //-------------------------------------------------------------------------- + // EffectConst + //-------------------------------------------------------------------------- class EffectConst { public: - - EffectConst( const String &name, const String &val ) - : mName( name ), - mHandle( NULL ), - mDirty( true ) - { - set( val ); - } - - EffectConst(const String &name, const F32 &val) - : mName(name), - mHandle(NULL), - mDirty(true) - { + EffectConst(const String& name, const String& val) + : mName(name), mHandle(NULL), mDirty(true) { + set(val); + } + EffectConst(const String& name, const F32& val) + : mName(name), mHandle(NULL), mDirty(true) { set(val); } - EffectConst(const String& name, const int& val) - : mName(name), - mHandle(NULL), - mDirty(true) - { + : mName(name), mHandle(NULL), mDirty(true) { + set(val); + } + EffectConst(const String& name, const Point4F& val) + : mName(name), mHandle(NULL), mDirty(true) { + set(val); + } + EffectConst(const String& name, const MatrixF& val) + : mName(name), mHandle(NULL), mDirty(true) { + set(val); + } + EffectConst(const String& name, const Vector& val) + : mName(name), mHandle(NULL), mDirty(true) { + set(val); + } + EffectConst(const String& name, const Vector& val) + : mName(name), mHandle(NULL), mDirty(true) { set(val); } - EffectConst(const String &name, const Point4F &val) - : mName(name), - mHandle(NULL), - mDirty(true) - { - set(val); - } - - EffectConst(const String &name, const MatrixF &val) - : mName(name), - mHandle(NULL), - mDirty(true) - { - set(val); - } - - EffectConst(const String &name, const Vector &val) - : mName(name), - mHandle(NULL), - mDirty(true) - { - set(val); - } - - EffectConst(const String &name, const Vector &val) - : mName(name), - mHandle(NULL), - mDirty(true) - { - set(val); - } - - void set( const String &newVal ); - void set(const F32 &newVal); + void set(const String& newVal); + void set(const F32& newVal); void set(const int& newVal); - void set(const Point4F &newVal); - void set(const MatrixF &newVal); - void set(const Vector &newVal); - void set(const Vector &newVal); - - void setToBuffer( GFXShaderConstBufferRef buff ); - - String mName; - - GFXShaderConstHandle *mHandle; - - String mStringVal; - - S32 mIntVal; - F32 mFloatVal; - Point4F mPointVal; - MatrixF mMatrixVal; + void set(const Point4F& newVal); + void set(const MatrixF& newVal); + void set(const Vector& newVal); + void set(const Vector& newVal); + void setToBuffer(GFXShaderConstBufferRef buff); + String mName; + GFXShaderConstHandle* mHandle; + String mStringVal; + S32 mIntVal; + F32 mFloatVal; + Point4F mPointVal; + MatrixF mMatrixVal; Vector mPointArrayVal; Vector mMatrixArrayVal; - enum - { - StringType, - IntType, - FloatType, - PointType, - MatrixType, - PointArrayType, - MatrixArrayType + enum { + StringType, IntType, FloatType, PointType, + MatrixType, PointArrayType, MatrixArrayType } mValueType; bool mDirty; }; - typedef HashTable EffectConstTable; - + typedef HashTable EffectConstTable; EffectConstTable mEffectConsts; - /// - virtual void _updateScreenGeometry( const Frustum &frustum, - GFXVertexBufferHandle *outVB ); + //-------------------------------------------------------------------------- + // Internal methods + //-------------------------------------------------------------------------- - /// - virtual void _setupStateBlock( const SceneRenderState *state ); - - /// - virtual void _setupConstants( const SceneRenderState *state ); - - /// + virtual void _updateScreenGeometry(const Frustum& frustum, GFXVertexBufferHandle* outVB); + virtual void _setupStateBlock(const SceneRenderState* state); + virtual void _setupConstants(const SceneRenderState* state); virtual void _setupTransforms(); + virtual void _setupTarget(const SceneRenderState* state, bool* outClearTarget); + virtual void _setupTexture(U32 stage, GFXTexHandle* inputTex, U32 inputTexCount, const RectI* inTexViewport); + virtual void _setupCubemapTexture(U32 stage, GFXCubemapHandle& inputTex); + virtual void _setupCubemapArrayTexture(U32 slot, GFXCubemapArrayHandle& inputTex); - /// - virtual void _setupTarget( const SceneRenderState *state, bool *outClearTarget ); + static bool _setIsEnabled(void* object, const char* index, const char* data); - /// - virtual void _setupTexture( U32 slot, GFXTexHandle &inputTex, const RectI *inTexViewport ); - virtual void _setupCubemapTexture(U32 stage, GFXCubemapHandle &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 ); - - /// Called from the light manager activate signal. - /// @see LightManager::addActivateCallback - void _onLMActivate( const char*, bool activate ) + void _onLMActivate(const char*, bool activate) { - if ( activate ) - mUpdateShader = true; + if (activate) 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()) ) - _cleanTargets(); + if (code != GFXZombify) return; + bool anyNamed = mNamedTargetDepthStencil.isRegistered(); + for (U32 c = 0; c < NumMRTTargets && !anyNamed; c++) + anyNamed = mNamedTarget[c].isRegistered(); + if (anyNamed) _cleanTargets(); } - /// void _updateConditioners(); - - /// - void _cleanTargets( bool recurse = false ); - - /// + void _cleanTargets(bool recurse = false); 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: - /// Constructor. PostEffect(); - - /// Destructor. virtual ~PostEffect(); DECLARE_CONOBJECT(PostEffect); - // SimObject bool onAdd() override; void onRemove() override; static void initPersistFields(); - /// @name Callbacks - /// @{ + DECLARE_CALLBACK(void, onAdd, ()); + DECLARE_CALLBACK(void, preProcess, ()); + DECLARE_CALLBACK(void, setShaderConsts, ()); + DECLARE_CALLBACK(bool, onEnabled, ()); + DECLARE_CALLBACK(void, onDisabled, ()); - DECLARE_CALLBACK( void, onAdd, () ); - DECLARE_CALLBACK( void, preProcess, () ); - DECLARE_CALLBACK( void, setShaderConsts, () ); - DECLARE_CALLBACK( bool, onEnabled, () ); - DECLARE_CALLBACK( void, onDisabled, () ); + virtual void process(const SceneRenderState* state, + GFXTexHandle* inOutTex, + U32 inOutTexCount = 1, + const RectI* inTexViewport = NULL); - /// @} - - virtual void process( const SceneRenderState *state, - GFXTexHandle &inOutTex, - const RectI *inTexViewport = NULL ); - - /// void reload(); - - /// void enable(); - - /// 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; - - /// Returns the SimSet which contains all PostEffects. + bool dumpShaderDisassembly(String& outFilename) const; SimSet* getSet() const; - /// bool isEnabled() const { return mEnabled; } - - /// Is set to skip rendering. bool isSkipped() const { return mSkip; } - - /// Set the effect to skip rendering. - void setSkip( bool skip ) { mSkip = skip; } + void setSkip(bool s) { mSkip = s; } PFXRenderTime getRenderTime() const { return mRenderTime; } + const String& getRenderBin() const { return mRenderBin; } + F32 getPriority() const { return mRenderPriority; } - const String& getRenderBin() const { return mRenderBin; } - - 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 setCubemapTexture(U32 index, const GFXCubemapHandle &cubemapHandle); - void setCubemapArrayTexture(U32 index, const GFXCubemapArrayHandle &cubemapArrayHandle); + void setCubemapTexture(U32 index, const GFXCubemapHandle& handle); + void setCubemapArrayTexture(U32 index, const GFXCubemapArrayHandle& handle); - void setShaderMacro( const String &name, const String &value = String::EmptyString ); - bool removeShaderMacro( const String &name ); + void setShaderMacro(const String& name, const String& value = String::EmptyString); + bool removeShaderMacro(const String& name); void clearShaderMacros(); - /// - void setShaderConst( const String &name, const String &val ); - void setShaderConst(const String &name, const F32 &val); + void setShaderConst(const String& name, const String& val); + void setShaderConst(const String& name, const F32& val); void setShaderConst(const String& name, const int& val); - void setShaderConst(const String &name, const Point4F &val); - void setShaderConst(const String &name, const MatrixF &val); - void setShaderConst(const String &name, const Vector &val); - void setShaderConst(const String &name, const Vector &val); + void setShaderConst(const String& name, const Point4F& val); + void setShaderConst(const String& name, const MatrixF& val); + void setShaderConst(const String& name, const Vector& val); + void setShaderConst(const String& name, const Vector& val); - void setOnThisFrame( bool enabled ) { mOnThisFrame = enabled; } + void setOnThisFrame(bool e) { mOnThisFrame = e; } bool isOnThisFrame() { return mOnThisFrame; } - void setOneFrameOnly( bool enabled ) { mOneFrameOnly = enabled; } - bool isOneFrameOnly() { return mOneFrameOnly; } + void setOneFrameOnly(bool e) { mOneFrameOnly = e; } + bool isOneFrameOnly() { return mOneFrameOnly; } - F32 getAspectRatio() const; - - GFXShaderRef getShader() { return mShader; } + F32 getAspectRatio() const; + GFXShaderRef getShader() { return mShader; } Vector* getShaderMacros() { return &mShaderMacros; } GFXShaderConstBufferRef getShaderConstBuffer() { return mShaderConsts; } - enum PostEffectRequirements { diff --git a/Engine/source/postFx/postEffectCommon.h b/Engine/source/postFx/postEffectCommon.h index d99800295..d3a031337 100644 --- a/Engine/source/postFx/postEffectCommon.h +++ b/Engine/source/postFx/postEffectCommon.h @@ -99,11 +99,10 @@ struct PFXFrameState }; /// +GFX_DeclareTextureProfile( PostFxTargetProfile) ; GFX_DeclareTextureProfile( PostFxTextureProfile ); GFX_DeclareTextureProfile( PostFxTextureSRGBProfile ); - GFX_DeclareTextureProfile( VRTextureProfile ); - GFX_DeclareTextureProfile( VRDepthProfile ); /// @@ -119,4 +118,4 @@ GFXDeclareVertexFormat( PFXVertex ) Point3F wsEyeRay; }; -#endif // _POSTEFFECTCOMMON_H_ \ No newline at end of file +#endif // _POSTEFFECTCOMMON_H_ diff --git a/Engine/source/postFx/postEffectManager.cpp b/Engine/source/postFx/postEffectManager.cpp index d65e25e25..ec30732de 100644 --- a/Engine/source/postFx/postEffectManager.cpp +++ b/Engine/source/postFx/postEffectManager.cpp @@ -284,14 +284,14 @@ void PostEffectManager::renderEffects( const SceneRenderState *state, // This is used to pass the output texture // of one effect into the next effect. - GFXTexHandle chainTex; + GFXTexHandle chainTex[PostEffect::NumMRTTargets]; // Process the effects. for ( U32 i = 0; i < effects->size(); i++ ) { PostEffect *effect = (*effects)[i]; AssertFatal( effect != NULL, "Somehow this happened" ); - effect->process( state, chainTex ); + effect->process(state, chainTex, PostEffect::NumMRTTargets); } } diff --git a/Engine/source/postFx/postEffectVis.cpp b/Engine/source/postFx/postEffectVis.cpp index 4a7442b72..69bca92ca 100644 --- a/Engine/source/postFx/postEffectVis.cpp +++ b/Engine/source/postFx/postEffectVis.cpp @@ -103,7 +103,7 @@ void PostEffectVis::open( PostEffect *pfx ) // Only allocate window/bitmaps for input textures that are actually used. if ( i > Target ) { - if ( pfx->mTextureAsset[i-1].notNull() && pfx->mTextureAsset[i - 1]->getImageFile() == StringTable->EmptyString()) + if ( pfx->mTextureAsset[i-1].isNull()) { window.window[i] = NULL; window.bmp[i] = NULL; @@ -197,7 +197,7 @@ void PostEffectVis::onStartOfFrame() if ( !itr->bmp[i] || itr->pfx->getRenderTime() == PFXTexGenOnDemand ) continue; - itr->bmp[i]->setBitmap( NULL ); + itr->bmp[i]->setBitmap( ""); _setDefaultCaption( *itr, i ); } } @@ -225,32 +225,32 @@ void PostEffectVis::onPFXProcessed( PostEffect *pfx ) { pBmpCtrl = itr->bmp[Target]; pWinCtrl = itr->window[Target]; + String caption; - GFXTextureObject *tex; + for (U32 c = 0; c < PostEffect::NumMRTTargets; c++) + { + GFXTextureObject* tex; - if ( pfx->mTargetTex ) - tex = pfx->mTargetTex; - else - tex = PFXMGR->getBackBufferTex(); + if (pfx->mTargetTex[c]) + tex = pfx->mTargetTex[c]; + else + tex = PFXMGR->getBackBufferTex(); - pBmpCtrl->setBitmapHandle( tex ); + pBmpCtrl->setBitmapHandle(tex); - char caption[256]; - char name[256]; - - if ( pfx->getName() == NULL || dStrlen( pfx->getName() ) == 0 ) - dSprintf( name, 256, "(none)" ); - else - dSprintf( name, 256, "%s", pfx->getName() ); + if (pfx->getName() == NULL || dStrlen(pfx->getName()) == 0) + caption += "(none)"; + else + caption += String::ToString(pfx->getName()); - if ( tex ) - dSprintf( caption, 256, "%s[%i] target - %s [ %ix%i ]", name, pfx->getId(), pfx->mTargetName.c_str(), tex->getWidth(), tex->getHeight() ); - else - dSprintf( caption, 256, "%s[%i] target", name, pfx->getId() ); - - - pWinCtrl->setDataField( StringTable->insert("text"), NULL, caption ); + if (tex) + caption += String::ToString("[%i] target - %s [ %ix%i ]", pfx->getId(), pfx->mTargetName[c].c_str(), tex->getWidth(), tex->getHeight()); + else + caption += String::ToString("[%i] target", pfx->getId()); + } + + pWinCtrl->setDataField( StringTable->insert("text"), NULL, caption.c_str() ); } for ( U32 i = Input1; i < TexCount; i++ ) diff --git a/Engine/source/renderInstance/renderFormatChanger.cpp b/Engine/source/renderInstance/renderFormatChanger.cpp index 893ef2cf6..374de6de4 100644 --- a/Engine/source/renderInstance/renderFormatChanger.cpp +++ b/Engine/source/renderInstance/renderFormatChanger.cpp @@ -144,7 +144,7 @@ void RenderFormatToken::process(SceneRenderState *state, RenderPassStateBin *cal // Run the PostEffect which copies data into the new target. if ( mCopyPostEffect.isValid() ) - mCopyPostEffect->process( state, curBackBuffer, &mTarget.getViewport() ); + mCopyPostEffect->process( state, &curBackBuffer,1, &mTarget.getViewport() ); } break; @@ -174,7 +174,7 @@ void RenderFormatToken::process(SceneRenderState *state, RenderPassStateBin *cal { // Need to create a texhandle here, since inOutTex gets assigned during process() GFXTexHandle inOutTex = mTargetColorTexture[mTargetChainIdx]; - mResolvePostEffect->process( state, inOutTex, &mTarget.getViewport() ); + mResolvePostEffect->process( state, &inOutTex, 1, &mTarget.getViewport() ); } } break;