2022-09-26 15:12:13 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
2022-10-02 10:56:02 -04:00
|
|
|
#include "MuT/AST.h"
|
2022-10-01 02:04:57 -04:00
|
|
|
#include "MuT/ASTOpAddLOD.h"
|
|
|
|
|
#include "MuT/ASTOpConditional.h"
|
2022-10-02 10:56:02 -04:00
|
|
|
#include "MuT/ASTOpImageCompose.h"
|
|
|
|
|
#include "MuT/ASTOpImageMipmap.h"
|
|
|
|
|
#include "MuT/ASTOpImagePixelFormat.h"
|
2022-12-05 05:01:41 -05:00
|
|
|
#include "MuT/ASTOpImageLayer.h"
|
|
|
|
|
#include "MuT/ASTOpImageLayerColor.h"
|
2022-10-21 22:27:28 -04:00
|
|
|
#include "MuT/ASTOpMeshMorph.h"
|
2022-10-01 02:04:57 -04:00
|
|
|
#include "MuT/ASTOpInstanceAdd.h"
|
2022-11-08 12:29:21 -05:00
|
|
|
#include "MuT/ASTOpLayoutFromMesh.h"
|
2022-10-02 10:56:02 -04:00
|
|
|
#include "MuT/ASTOpParameter.h"
|
|
|
|
|
#include "MuT/CodeOptimiser.h"
|
|
|
|
|
#include "MuT/Compiler.h"
|
|
|
|
|
#include "MuT/CompilerPrivate.h"
|
|
|
|
|
#include "MuT/DataPacker.h"
|
2022-10-11 05:14:05 -04:00
|
|
|
#include "MuT/Platform.h"
|
2024-02-06 04:01:37 -05:00
|
|
|
#include "MuR/Image.h"
|
|
|
|
|
#include "MuR/ImagePrivate.h"
|
|
|
|
|
#include "MuR/MutableTrace.h"
|
|
|
|
|
#include "MuR/Operations.h"
|
|
|
|
|
#include "MuR/ParametersPrivate.h"
|
|
|
|
|
#include "MuR/Platform.h"
|
|
|
|
|
#include "MuR/Ptr.h"
|
|
|
|
|
#include "MuR/RefCounted.h"
|
|
|
|
|
#include "MuR/MutableRuntimeModule.h"
|
|
|
|
|
|
|
|
|
|
#include "HAL/PlatformCrt.h"
|
|
|
|
|
#include "HAL/PlatformMath.h"
|
|
|
|
|
#include "Logging/LogCategory.h"
|
|
|
|
|
#include "Logging/LogMacros.h"
|
|
|
|
|
#include "Misc/AssertionMacros.h"
|
2022-10-02 10:56:02 -04:00
|
|
|
#include "Trace/Detail/Channel.h"
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
#include <array>
|
2023-12-07 05:13:50 -05:00
|
|
|
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
namespace mu
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
2023-12-19 05:19:14 -05:00
|
|
|
RuntimeParameterVisitorAST::RuntimeParameterVisitorAST(const FStateCompilationData* pState)
|
2022-09-26 15:12:13 -04:00
|
|
|
: m_pState(pState)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool RuntimeParameterVisitorAST::HasAny( const Ptr<ASTOp>& root )
|
|
|
|
|
{
|
2024-06-10 04:10:54 -04:00
|
|
|
if (!m_pState->nodeState.RuntimeParams.Num())
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Shortcut flag: if true we already found a runtime parameter, don't process new ops,
|
|
|
|
|
// but still store the results of processed ops.
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
|
|
m_pending.clear();
|
|
|
|
|
|
|
|
|
|
PENDING_ITEM start;
|
|
|
|
|
start.at = root;
|
|
|
|
|
start.itemType = 0;
|
|
|
|
|
start.onlyLayoutsRelevant = 0;
|
|
|
|
|
m_pending.push_back( start );
|
|
|
|
|
|
|
|
|
|
// Don't early out to be able to complete parent op cached flags
|
|
|
|
|
while ( m_pending.size() )
|
|
|
|
|
{
|
|
|
|
|
PENDING_ITEM item = m_pending.back();
|
|
|
|
|
m_pending.pop_back();
|
|
|
|
|
Ptr<ASTOp> at = item.at;
|
|
|
|
|
|
|
|
|
|
if (!at)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Not cached?
|
|
|
|
|
if ( m_visited[at]!=OP_STATE::VISITED_HASRUNTIME
|
|
|
|
|
&&
|
|
|
|
|
m_visited[at]!=OP_STATE::VISITED_FULL_DOESNTHAVERUNTIME )
|
|
|
|
|
{
|
|
|
|
|
if (item.itemType)
|
|
|
|
|
{
|
|
|
|
|
// Item indicating we finished with all the children of a parent
|
|
|
|
|
check( m_visited[at]==OP_STATE::CHILDREN_PENDING_FULL
|
|
|
|
|
||
|
|
|
|
|
m_visited[at]==OP_STATE::CHILDREN_PENDING_PARTIAL
|
|
|
|
|
||
|
|
|
|
|
m_visited[at]==OP_STATE::VISITED_PARTIAL_DOESNTHAVERUNTIME );
|
|
|
|
|
|
|
|
|
|
bool subtreeFound = false;
|
|
|
|
|
at->ForEachChild( [&](ASTChild& ref)
|
|
|
|
|
{
|
|
|
|
|
subtreeFound = subtreeFound || m_visited[ref.child()]==OP_STATE::VISITED_HASRUNTIME;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (subtreeFound)
|
|
|
|
|
{
|
|
|
|
|
m_visited[at] = OP_STATE::VISITED_HASRUNTIME;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_visited[at] = item.onlyLayoutsRelevant
|
|
|
|
|
? OP_STATE::VISITED_PARTIAL_DOESNTHAVERUNTIME
|
|
|
|
|
: OP_STATE::VISITED_FULL_DOESNTHAVERUNTIME;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (!found)
|
|
|
|
|
{
|
|
|
|
|
// We need to process the subtree
|
|
|
|
|
check( m_visited[at]==OP_STATE::NOT_VISITED
|
|
|
|
|
||
|
|
|
|
|
( m_visited[at]==OP_STATE::VISITED_PARTIAL_DOESNTHAVERUNTIME
|
|
|
|
|
&&
|
|
|
|
|
item.onlyLayoutsRelevant==0 )
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Request the processing of the end of this instruction
|
|
|
|
|
PENDING_ITEM endItem = item;
|
|
|
|
|
endItem.itemType = 1;
|
|
|
|
|
m_pending.push_back( endItem );
|
|
|
|
|
m_visited[at] = item.onlyLayoutsRelevant
|
|
|
|
|
? OP_STATE::CHILDREN_PENDING_PARTIAL
|
|
|
|
|
: OP_STATE::CHILDREN_PENDING_FULL;
|
|
|
|
|
|
|
|
|
|
// Is it a special op type?
|
|
|
|
|
switch ( at->GetOpType() )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
case OP_TYPE::BO_PARAMETER:
|
|
|
|
|
case OP_TYPE::NU_PARAMETER:
|
|
|
|
|
case OP_TYPE::SC_PARAMETER:
|
|
|
|
|
case OP_TYPE::CO_PARAMETER:
|
|
|
|
|
case OP_TYPE::PR_PARAMETER:
|
|
|
|
|
case OP_TYPE::IM_PARAMETER:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpParameter* typed = static_cast<const ASTOpParameter*>(at.get());
|
2024-06-10 04:10:54 -04:00
|
|
|
const TArray<FString>& params = m_pState->nodeState.RuntimeParams;
|
2022-10-11 05:14:05 -04:00
|
|
|
if ( params.Find( typed->parameter.m_name)
|
2022-09-26 15:12:13 -04:00
|
|
|
!=
|
2022-10-11 05:14:05 -04:00
|
|
|
INDEX_NONE )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
found = true;
|
|
|
|
|
m_visited[at] = OP_STATE::VISITED_HASRUNTIME;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OP_TYPE::ME_INTERPOLATE:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpFixed* typed = static_cast<const ASTOpFixed*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
PENDING_ITEM childItem;
|
|
|
|
|
childItem.itemType = 0;
|
|
|
|
|
childItem.onlyLayoutsRelevant = item.onlyLayoutsRelevant;
|
|
|
|
|
|
|
|
|
|
if ( item.onlyLayoutsRelevant==0 )
|
|
|
|
|
{
|
|
|
|
|
childItem.at = typed->children[typed->op.args.MeshInterpolate.factor].child();
|
|
|
|
|
AddIfNeeded(childItem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
childItem.at = typed->children[typed->op.args.MeshInterpolate.base].child();
|
|
|
|
|
AddIfNeeded(childItem);
|
|
|
|
|
|
2024-07-23 07:00:39 -04:00
|
|
|
for (int32 t=0;t<MUTABLE_OP_MAX_INTERPOLATE_COUNT-1;++t)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
childItem.at = typed->children[typed->op.args.MeshInterpolate.targets[t]].child();
|
|
|
|
|
AddIfNeeded(childItem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
at->ForEachChild([&](ASTChild& ref)
|
|
|
|
|
{
|
|
|
|
|
PENDING_ITEM childItem;
|
|
|
|
|
childItem.itemType = 0;
|
|
|
|
|
childItem.at = ref.child();
|
|
|
|
|
childItem.onlyLayoutsRelevant = item.onlyLayoutsRelevant;
|
|
|
|
|
AddIfNeeded(childItem);
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// We won't process it.
|
|
|
|
|
m_visited[at] = OP_STATE::NOT_VISITED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m_visited[root]==OP_STATE::VISITED_HASRUNTIME;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void RuntimeParameterVisitorAST::AddIfNeeded( const PENDING_ITEM& item )
|
|
|
|
|
{
|
|
|
|
|
if (item.at)
|
|
|
|
|
{
|
|
|
|
|
if (m_visited[item.at]==OP_STATE::NOT_VISITED)
|
|
|
|
|
{
|
|
|
|
|
m_pending.push_back( item );
|
|
|
|
|
}
|
|
|
|
|
else if (m_visited[item.at]==OP_STATE::VISITED_PARTIAL_DOESNTHAVERUNTIME
|
|
|
|
|
&&
|
|
|
|
|
item.onlyLayoutsRelevant==0)
|
|
|
|
|
{
|
|
|
|
|
m_pending.push_back( item );
|
|
|
|
|
}
|
|
|
|
|
else if (m_visited[item.at]==OP_STATE::CHILDREN_PENDING_PARTIAL
|
|
|
|
|
&&
|
|
|
|
|
item.onlyLayoutsRelevant==0)
|
|
|
|
|
{
|
|
|
|
|
m_pending.push_back( item );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
Ptr<ASTOp> EnsureValidMask( Ptr<ASTOp> mask, Ptr<ASTOp> base )
|
|
|
|
|
{
|
|
|
|
|
if ( !mask )
|
|
|
|
|
{
|
|
|
|
|
Ptr<ASTOpFixed> whiteOp = new ASTOpFixed;
|
|
|
|
|
whiteOp->op.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
whiteOp->op.args.ColourConstant.value[0] = 1;
|
|
|
|
|
whiteOp->op.args.ColourConstant.value[1] = 1;
|
2022-12-09 12:21:28 -05:00
|
|
|
whiteOp->op.args.ColourConstant.value[2] = 1;
|
|
|
|
|
whiteOp->op.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> wplainOp = new ASTOpFixed;
|
|
|
|
|
wplainOp->op.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
wplainOp->SetChild( wplainOp->op.args.ImagePlainColour.colour, whiteOp );
|
|
|
|
|
wplainOp->op.args.ImagePlainColour.format = EImageFormat::IF_L_UBYTE;
|
|
|
|
|
wplainOp->op.args.ImagePlainColour.size[0] = 4;
|
2023-03-17 09:40:20 -04:00
|
|
|
wplainOp->op.args.ImagePlainColour.size[1] = 4;
|
|
|
|
|
wplainOp->op.args.ImagePlainColour.LODs = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> wresizeOp = new ASTOpFixed;
|
|
|
|
|
wresizeOp->op.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
wresizeOp->SetChild( wresizeOp->op.args.ImageResizeLike.source, wplainOp );
|
|
|
|
|
wresizeOp->SetChild( wresizeOp->op.args.ImageResizeLike.sizeSource, base );
|
|
|
|
|
|
|
|
|
|
mask = wresizeOp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
ParameterOptimiserAST::ParameterOptimiserAST(
|
2023-12-19 05:19:14 -05:00
|
|
|
FStateCompilationData& s,
|
2022-11-08 12:29:21 -05:00
|
|
|
const FModelOptimizationOptions& optimisationOptions
|
2022-09-26 15:12:13 -04:00
|
|
|
)
|
|
|
|
|
: m_stateProps(s)
|
|
|
|
|
, m_modified(false)
|
2023-06-15 06:49:52 -04:00
|
|
|
, OptimisationOptions(optimisationOptions)
|
2022-09-26 15:12:13 -04:00
|
|
|
, m_hasRuntimeParamVisitor(&s)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool ParameterOptimiserAST::Apply()
|
|
|
|
|
{
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(ParameterOptimiserAST);
|
|
|
|
|
|
|
|
|
|
m_modified = false;
|
|
|
|
|
|
|
|
|
|
// Optimise the cloned tree
|
|
|
|
|
Traverse( m_stateProps.root );
|
|
|
|
|
|
|
|
|
|
return m_modified;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ptr<ASTOp> ParameterOptimiserAST::Visit( Ptr<ASTOp> at, bool& processChildren )
|
|
|
|
|
{
|
|
|
|
|
// Only process children if there are runtime parameters in the subtree
|
|
|
|
|
processChildren = m_hasRuntimeParamVisitor.HasAny(at);
|
|
|
|
|
|
|
|
|
|
OP_TYPE type = at->GetOpType();
|
|
|
|
|
switch ( type )
|
|
|
|
|
{
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
|
// Be careful with changing merge options and "mergesurfaces" flags
|
|
|
|
|
// case OP_TYPE::ME_MERGE:
|
|
|
|
|
// {
|
|
|
|
|
// OP::MeshMergeArgs mergeArgs = program.m_code[at].args.MeshMerge;
|
|
|
|
|
|
|
|
|
|
// RuntimeParameterVisitor paramVis;
|
|
|
|
|
|
|
|
|
|
// switch ( program.m_code[ mergeArgs.base ].type )
|
|
|
|
|
// {
|
|
|
|
|
// case OP_TYPE::ME_CONDITIONAL:
|
|
|
|
|
// {
|
|
|
|
|
// OP::ADDRESS conditionAt =
|
|
|
|
|
// program.m_code[ mergeArgs.base ].args.Conditional.condition;
|
|
|
|
|
// bool conditionConst = !paramVis.HasAny( m_pModel.get(),
|
|
|
|
|
// m_state,
|
|
|
|
|
// conditionAt );
|
|
|
|
|
// if ( conditionConst )
|
|
|
|
|
// {
|
|
|
|
|
// // TODO: this may unfold mesh combinations of some models increasing the size of
|
|
|
|
|
// // the model data. Make this optimisation optional.
|
|
|
|
|
// m_modified = true;
|
|
|
|
|
|
|
|
|
|
// OP yesOp = program.m_code[at];
|
|
|
|
|
// yesOp.args.MeshMerge.base = program.m_code[ mergeArgs.base ].args.Conditional.yes;
|
|
|
|
|
|
|
|
|
|
// OP noOp = program.m_code[at];
|
|
|
|
|
// noOp.args.MeshMerge.base = program.m_code[ mergeArgs.base ].args.Conditional.no;
|
|
|
|
|
|
|
|
|
|
// OP op = program.m_code[ mergeArgs.base ];
|
|
|
|
|
// op.args.Conditional.yes = program.AddOp( yesOp );
|
|
|
|
|
// op.args.Conditional.no = program.AddOp( noOp );
|
|
|
|
|
// at = program.AddOp( op );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// case OP_TYPE::ME_MERGE:
|
|
|
|
|
// {
|
|
|
|
|
// OP::ADDRESS childBaseAt = program.m_code[ mergeArgs.base ].args.MeshMerge.base;
|
|
|
|
|
// bool childBaseConst = !paramVis.HasAny( m_pModel.get(),
|
|
|
|
|
// m_state,
|
|
|
|
|
// childBaseAt );
|
|
|
|
|
|
|
|
|
|
// OP::ADDRESS childAddAt = program.m_code[ mergeArgs.base ].args.MeshMerge.added;
|
|
|
|
|
// bool childAddConst = !paramVis.HasAny( m_pModel.get(),
|
|
|
|
|
// m_state,
|
|
|
|
|
// childAddAt );
|
|
|
|
|
|
|
|
|
|
// bool addConst = !paramVis.HasAny( m_pModel.get(),
|
|
|
|
|
// m_state,
|
|
|
|
|
// mergeArgs.added );
|
|
|
|
|
|
|
|
|
|
// if ( !childBaseConst && childAddConst && addConst )
|
|
|
|
|
// {
|
|
|
|
|
// m_modified = true;
|
|
|
|
|
|
|
|
|
|
// OP bottom = program.m_code[at];
|
|
|
|
|
// bottom.args.MeshMerge.base = childAddAt;
|
|
|
|
|
|
|
|
|
|
// OP top = program.m_code[ mergeArgs.base ];
|
|
|
|
|
// top.args.MeshMerge.added = program.AddOp( bottom );
|
|
|
|
|
// at = program.AddOp( top );
|
|
|
|
|
// }
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// default:
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
|
case OP_TYPE::IM_CONDITIONAL:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpConditional* typedAt = static_cast<const ASTOpConditional*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// If the condition is not runtime, but the branches are, try to move the
|
|
|
|
|
// conditional down
|
|
|
|
|
bool optimised = false;
|
|
|
|
|
|
|
|
|
|
if ( !m_hasRuntimeParamVisitor.HasAny( typedAt->condition.child() ) )
|
|
|
|
|
{
|
|
|
|
|
OP_TYPE yesType = typedAt->yes->GetOpType();
|
|
|
|
|
OP_TYPE noType = typedAt->no->GetOpType();
|
|
|
|
|
|
|
|
|
|
bool yesHasAny = m_hasRuntimeParamVisitor.HasAny( typedAt->yes.child() );
|
|
|
|
|
bool noHasAny = m_hasRuntimeParamVisitor.HasAny( typedAt->no.child() );
|
|
|
|
|
|
|
|
|
|
if ( !optimised && yesHasAny && noHasAny && yesType==noType)
|
|
|
|
|
{
|
|
|
|
|
switch (yesType)
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IM_COMPOSE:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageCompose* typedYes = static_cast<const ASTOpImageCompose*>(typedAt->yes.child().get());
|
|
|
|
|
const ASTOpImageCompose* typedNo = static_cast<const ASTOpImageCompose*>(typedAt->no.child().get());
|
2024-05-13 03:20:24 -04:00
|
|
|
if ( typedYes->BlockId == typedNo->BlockId
|
2022-09-26 15:12:13 -04:00
|
|
|
&&
|
|
|
|
|
(
|
|
|
|
|
(typedYes->Mask.child().get() != nullptr)
|
|
|
|
|
==
|
|
|
|
|
(typedNo->Mask.child().get() != nullptr)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
// Move the conditional down
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> compOp = mu::Clone<ASTOpImageCompose>(typedYes);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpConditional> baseCond = mu::Clone<ASTOpConditional>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
baseCond->yes = typedYes->Base.child();
|
|
|
|
|
baseCond->no = typedNo->Base.child();
|
|
|
|
|
compOp->Base = baseCond;
|
|
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpConditional> blockCond = mu::Clone<ASTOpConditional>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
blockCond->yes = typedYes->BlockImage.child();
|
|
|
|
|
blockCond->no = typedNo->BlockImage.child();
|
|
|
|
|
compOp->BlockImage = blockCond;
|
|
|
|
|
|
|
|
|
|
if (typedYes->Mask)
|
|
|
|
|
{
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpConditional> maskCond = mu::Clone<ASTOpConditional>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
maskCond->yes = typedYes->Mask.child();
|
|
|
|
|
maskCond->no = typedNo->Mask.child();
|
|
|
|
|
compOp->Mask = maskCond;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpConditional> layCond = mu::Clone<ASTOpConditional>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
layCond->type = OP_TYPE::LA_CONDITIONAL;
|
|
|
|
|
layCond->yes = typedYes->Layout.child();
|
|
|
|
|
layCond->no = typedNo->Layout.child();
|
|
|
|
|
compOp->Layout = layCond;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
at = compOp;
|
|
|
|
|
optimised = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !optimised && yesHasAny )
|
|
|
|
|
{
|
|
|
|
|
switch (yesType)
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IM_LAYERCOLOUR:
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayerColor* typedYes = static_cast<const ASTOpImageLayerColor*>(typedAt->yes.child().get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> blackOp = new ASTOpFixed;
|
|
|
|
|
blackOp->op.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[0] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[1] = 0;
|
2022-12-09 12:21:28 -05:00
|
|
|
blackOp->op.args.ColourConstant.value[2] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> plainOp = new ASTOpFixed;
|
|
|
|
|
plainOp->op.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
plainOp->SetChild( plainOp->op.args.ImagePlainColour.colour, blackOp );
|
|
|
|
|
plainOp->op.args.ImagePlainColour.format = EImageFormat::IF_L_UBYTE;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.size[0] = 4;
|
2023-03-17 09:40:20 -04:00
|
|
|
plainOp->op.args.ImagePlainColour.size[1] = 4;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.LODs = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> resizeOp = new ASTOpFixed;
|
|
|
|
|
resizeOp->op.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
resizeOp->SetChild( resizeOp->op.args.ImageResizeLike.source, plainOp );
|
2022-12-05 05:01:41 -05:00
|
|
|
resizeOp->SetChild( resizeOp->op.args.ImageResizeLike.sizeSource, typedYes->base );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpConditional> maskOp = mu::Clone<ASTOpConditional>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
maskOp->no = resizeOp;
|
|
|
|
|
|
|
|
|
|
// If there is no mask (because it is optional), we need to make a
|
|
|
|
|
// white plain image
|
2022-12-05 05:01:41 -05:00
|
|
|
maskOp->yes = EnsureValidMask( typedYes->mask.child(), typedYes->base.child() );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpConditional> baseOp = mu::Clone<ASTOpConditional>(typedAt);
|
|
|
|
|
baseOp->yes = typedYes->base.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageLayerColor> softOp = mu::Clone<ASTOpImageLayerColor>(typedYes);
|
|
|
|
|
softOp->base = baseOp;
|
|
|
|
|
softOp->mask = maskOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
at = softOp;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// It seems this is not worth since it replaces a conditional by a compose
|
|
|
|
|
// (but only at build time, not update?) and it introduces the use of masks
|
|
|
|
|
// and resize likes... plus masks can't always be used if BC formats.
|
|
|
|
|
// case OP_TYPE::IM_COMPOSE:
|
|
|
|
|
// {
|
|
|
|
|
// optimised = true;
|
|
|
|
|
|
|
|
|
|
// OP blackOp;
|
|
|
|
|
// blackOp.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
// blackOp.args.ColourConstant.value[0] = 0;
|
|
|
|
|
// blackOp.args.ColourConstant.value[1] = 0;
|
|
|
|
|
// blackOp.args.ColourConstant.value[2] = 0;
|
2022-12-09 12:21:28 -05:00
|
|
|
// blackOp.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// OP plainOp;
|
|
|
|
|
// plainOp.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
// plainOp.args.ImagePlainColour.colour = program.AddOp( blackOp );
|
|
|
|
|
// plainOp.args.ImagePlainColour.format = IF_L_UBYTE;
|
2023-03-17 09:40:20 -04:00
|
|
|
// plainOp.args.ImagePlainColour.size = ;
|
|
|
|
|
// plainOp.args.ImagePlainColour.LODs = ;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// OP resizeOp;
|
|
|
|
|
// resizeOp.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
// resizeOp.args.ImageResizeLike.source = program.AddOp( plainOp );
|
|
|
|
|
// resizeOp.args.ImageResizeLike.sizeSource =
|
|
|
|
|
// program.m_code[args.yes].args.ImageCompose.blockImage;
|
|
|
|
|
|
|
|
|
|
// OP maskOp = program.m_code[at];
|
|
|
|
|
// maskOp.args.Conditional.no = program.AddOp( resizeOp );
|
|
|
|
|
|
|
|
|
|
// // If there is no mask (because it is optional), we need to make a
|
|
|
|
|
// // white plain image
|
|
|
|
|
// maskOp.args.Conditional.yes = EnsureValidMask
|
|
|
|
|
// ( program.m_code[args.yes].args.ImageCompose.mask,
|
|
|
|
|
// program.m_code[args.yes].args.ImageCompose.base,
|
|
|
|
|
// program );
|
|
|
|
|
|
|
|
|
|
// OP baseOp = program.m_code[at];
|
|
|
|
|
// baseOp.args.Conditional.yes =
|
|
|
|
|
// program.m_code[args.yes].args.ImageCompose.base;
|
|
|
|
|
|
|
|
|
|
// OP composeOp = program.m_code[args.yes];
|
|
|
|
|
// composeOp.args.ImageCompose.base = program.AddOp( baseOp );
|
|
|
|
|
// composeOp.args.ImageCompose.mask = program.AddOp( maskOp );
|
|
|
|
|
|
|
|
|
|
// at = program.AddOp( composeOp );
|
|
|
|
|
|
|
|
|
|
// // Process the new children
|
|
|
|
|
// at = Recurse( at, program );
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if ( !optimised && noHasAny )
|
|
|
|
|
{
|
|
|
|
|
switch (noType)
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IM_LAYERCOLOUR:
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayerColor* typedNo = static_cast<const ASTOpImageLayerColor*>(typedAt->no.child().get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> blackOp = new ASTOpFixed;
|
|
|
|
|
blackOp->op.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[0] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[1] = 0;
|
2022-12-09 12:21:28 -05:00
|
|
|
blackOp->op.args.ColourConstant.value[2] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> plainOp = new ASTOpFixed;
|
|
|
|
|
plainOp->op.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
plainOp->SetChild( plainOp->op.args.ImagePlainColour.colour, blackOp );
|
|
|
|
|
plainOp->op.args.ImagePlainColour.format = EImageFormat::IF_L_UBYTE;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.size[0] = 4;
|
2023-03-17 09:40:20 -04:00
|
|
|
plainOp->op.args.ImagePlainColour.size[1] = 4;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.LODs = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> resizeOp = new ASTOpFixed;
|
|
|
|
|
resizeOp->op.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
resizeOp->SetChild( resizeOp->op.args.ImageResizeLike.source, plainOp );
|
2022-12-05 05:01:41 -05:00
|
|
|
resizeOp->SetChild( resizeOp->op.args.ImageResizeLike.sizeSource, typedNo->base );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpConditional> maskOp = mu::Clone<ASTOpConditional>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
maskOp->no = resizeOp;
|
|
|
|
|
|
|
|
|
|
// If there is no mask (because it is optional), we need to make a
|
|
|
|
|
// white plain image
|
2022-12-05 05:01:41 -05:00
|
|
|
maskOp->no = EnsureValidMask( typedNo->mask.child(), typedNo->base.child() );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpConditional> baseOp = mu::Clone<ASTOpConditional>(typedAt);
|
|
|
|
|
baseOp->no = typedNo->base.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageLayerColor> softOp = mu::Clone<ASTOpImageLayerColor>(typedNo);
|
|
|
|
|
softOp->base = baseOp;
|
|
|
|
|
softOp->mask = maskOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
at = softOp;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_modified |= optimised;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
|
case OP_TYPE::IM_SWITCH:
|
|
|
|
|
{
|
|
|
|
|
// If the switch is not runtime, but the branches are, try to move the
|
|
|
|
|
// switch down
|
|
|
|
|
// bool optimised = false;
|
|
|
|
|
|
|
|
|
|
// OP::ADDRESS variable = program.m_code[at].args.Switch.variable;
|
|
|
|
|
|
|
|
|
|
// if ( !m_hasRuntimeParamVisitor.HasAny( variable, program ) )
|
|
|
|
|
// {
|
|
|
|
|
// SWITCH_CHAIN chain = GetSwitchChain( program, at );
|
|
|
|
|
|
|
|
|
|
// bool branchHasAny = false;
|
|
|
|
|
// OP_TYPE branchType = (OP_TYPE)program.m_code[program.m_code[at].args.Switch.values[0]].type;
|
2022-10-11 05:14:05 -04:00
|
|
|
// for ( map<uint16,OP::ADDRESS>::const_iterator it=chain.cases.begin();
|
2022-09-26 15:12:13 -04:00
|
|
|
// it != chain.cases.end();
|
|
|
|
|
// ++it )
|
|
|
|
|
// {
|
|
|
|
|
// if ( program.m_code[it->second].type != branchType )
|
|
|
|
|
// {
|
|
|
|
|
// branchType = OP_TYPE::NONE;
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// if (!branchHasAny)
|
|
|
|
|
// {
|
|
|
|
|
// branchHasAny = m_hasRuntimeParamVisitor.HasAny( it->second, program );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if ( chain.def && program.m_code[chain.def].type != branchType )
|
|
|
|
|
// {
|
|
|
|
|
// branchType = OP_TYPE::NONE;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Some branch in runtime
|
|
|
|
|
// if ( branchHasAny )
|
|
|
|
|
// {
|
|
|
|
|
// switch ( branchType )
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
|
|
// // TODO: Other operations
|
|
|
|
|
// case OP_TYPE::IM_BLEND:
|
|
|
|
|
// case OP_TYPE::IM_MULTIPLY:
|
|
|
|
|
// {
|
|
|
|
|
// // Move the switch down the base
|
|
|
|
|
// OP::ADDRESS baseAt = 0;
|
2022-10-11 05:14:05 -04:00
|
|
|
// for ( map<uint16,OP::ADDRESS>::const_iterator it=chain.cases.begin();
|
2022-09-26 15:12:13 -04:00
|
|
|
// it != chain.cases.end();
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// OP bsw;
|
|
|
|
|
// bsw.type = OP_TYPE::IM_SWITCH;
|
|
|
|
|
// bsw.args.Switch.variable = variable;
|
|
|
|
|
|
|
|
|
|
// for ( int b=0;
|
|
|
|
|
// it != chain.cases.end() && b<MUTABLE_OP_MAX_SWITCH_OPTIONS;
|
|
|
|
|
// ++b )
|
|
|
|
|
// {
|
|
|
|
|
// bsw.args.Switch.conditions[b] = it->first;
|
|
|
|
|
// bsw.args.Switch.values[b] =
|
|
|
|
|
// program.m_code[it->second].args.ImageLayer.base;
|
|
|
|
|
// ++it;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// bsw.args.Switch.def = baseAt;
|
|
|
|
|
// baseAt = program.AddOp( bsw );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Move the switch down the mask
|
|
|
|
|
// OP::ADDRESS maskAt = 0;
|
2022-10-11 05:14:05 -04:00
|
|
|
// for ( map<uint16,OP::ADDRESS>::const_iterator it=chain.cases.begin();
|
2022-09-26 15:12:13 -04:00
|
|
|
// it != chain.cases.end();
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// OP bsw;
|
|
|
|
|
// bsw.type = OP_TYPE::IM_SWITCH;
|
|
|
|
|
// bsw.args.Switch.variable = variable;
|
|
|
|
|
|
|
|
|
|
// for ( int b=0;
|
|
|
|
|
// it != chain.cases.end() && b<MUTABLE_OP_MAX_SWITCH_OPTIONS;
|
|
|
|
|
// ++b )
|
|
|
|
|
// {
|
|
|
|
|
// bsw.args.Switch.conditions[b] = it->first;
|
|
|
|
|
// bsw.args.Switch.values[b] =
|
|
|
|
|
// program.m_code[it->second].args.ImageLayer.mask;
|
|
|
|
|
// ++it;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// bsw.args.Switch.def = maskAt;
|
|
|
|
|
// maskAt = program.AddOp( bsw );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Move the switch down the blended
|
|
|
|
|
// OP::ADDRESS blendedAt = 0;
|
2022-10-11 05:14:05 -04:00
|
|
|
// for ( map<uint16,OP::ADDRESS>::const_iterator it=chain.cases.begin();
|
2022-09-26 15:12:13 -04:00
|
|
|
// it != chain.cases.end();
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// OP bsw;
|
|
|
|
|
// bsw.type = OP_TYPE::IM_SWITCH;
|
|
|
|
|
// bsw.args.Switch.variable = variable;
|
|
|
|
|
|
|
|
|
|
// for ( int b=0;
|
|
|
|
|
// it != chain.cases.end() && b<MUTABLE_OP_MAX_SWITCH_OPTIONS;
|
|
|
|
|
// ++b )
|
|
|
|
|
// {
|
|
|
|
|
// bsw.args.Switch.conditions[b] = it->first;
|
|
|
|
|
// bsw.args.Switch.values[b] =
|
|
|
|
|
// program.m_code[it->second].args.ImageLayer.blended;
|
|
|
|
|
// ++it;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// bsw.args.Switch.def = blendedAt;
|
|
|
|
|
// blendedAt = program.AddOp( bsw );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// OP top;
|
|
|
|
|
// top.type = branchType;
|
|
|
|
|
// top.args.ImageLayer.base = baseAt;
|
|
|
|
|
// top.args.ImageLayer.mask = maskAt;
|
|
|
|
|
// top.args.ImageLayer.blended = blendedAt;
|
|
|
|
|
// at = program.AddOp( top );
|
|
|
|
|
// optimised = true;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // TODO: Other operations
|
|
|
|
|
// case OP_TYPE::IM_SOFTLIGHTCOLOUR:
|
|
|
|
|
// {
|
|
|
|
|
// // Move the switch down the base
|
|
|
|
|
// OP::ADDRESS baseAt = 0;
|
2022-10-11 05:14:05 -04:00
|
|
|
// for ( map<uint16,OP::ADDRESS>::const_iterator it=chain.cases.begin();
|
2022-09-26 15:12:13 -04:00
|
|
|
// it != chain.cases.end();
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// OP bsw;
|
|
|
|
|
// bsw.type = OP_TYPE::IM_SWITCH;
|
|
|
|
|
// bsw.args.Switch.variable = variable;
|
|
|
|
|
|
|
|
|
|
// for ( int b=0;
|
|
|
|
|
// it != chain.cases.end() && b<MUTABLE_OP_MAX_SWITCH_OPTIONS;
|
|
|
|
|
// ++b )
|
|
|
|
|
// {
|
|
|
|
|
// bsw.args.Switch.conditions[b] = it->first;
|
|
|
|
|
// bsw.args.Switch.values[b] =
|
|
|
|
|
// program.m_code[it->second].args.ImageLayerColour.base;
|
|
|
|
|
// ++it;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// bsw.args.Switch.def = baseAt;
|
|
|
|
|
// baseAt = program.AddOp( bsw );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Move the switch down the mask
|
|
|
|
|
// OP::ADDRESS maskAt = 0;
|
2022-10-11 05:14:05 -04:00
|
|
|
// for ( map<uint16,OP::ADDRESS>::const_iterator it=chain.cases.begin();
|
2022-09-26 15:12:13 -04:00
|
|
|
// it != chain.cases.end();
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// OP bsw;
|
|
|
|
|
// bsw.type = OP_TYPE::IM_SWITCH;
|
|
|
|
|
// bsw.args.Switch.variable = variable;
|
|
|
|
|
|
|
|
|
|
// for ( int b=0;
|
|
|
|
|
// it != chain.cases.end() && b<MUTABLE_OP_MAX_SWITCH_OPTIONS;
|
|
|
|
|
// ++b )
|
|
|
|
|
// {
|
|
|
|
|
// bsw.args.Switch.conditions[b] = it->first;
|
|
|
|
|
// bsw.args.Switch.values[b] =
|
|
|
|
|
// program.m_code[it->second].args.ImageLayerColour.mask;
|
|
|
|
|
// ++it;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// bsw.args.Switch.def = maskAt;
|
|
|
|
|
// maskAt = program.AddOp( bsw );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Move the switch down the colour
|
|
|
|
|
// OP::ADDRESS colourAt = 0;
|
2022-10-11 05:14:05 -04:00
|
|
|
// for ( map<uint16,OP::ADDRESS>::const_iterator it=chain.cases.begin();
|
2022-09-26 15:12:13 -04:00
|
|
|
// it != chain.cases.end();
|
|
|
|
|
// )
|
|
|
|
|
// {
|
|
|
|
|
// OP bsw;
|
|
|
|
|
// bsw.type = OP_TYPE::CO_SWITCH;
|
|
|
|
|
// bsw.args.Switch.variable = variable;
|
|
|
|
|
|
|
|
|
|
// for ( int b=0;
|
|
|
|
|
// it != chain.cases.end() && b<MUTABLE_OP_MAX_SWITCH_OPTIONS;
|
|
|
|
|
// ++b )
|
|
|
|
|
// {
|
|
|
|
|
// bsw.args.Switch.conditions[b] = it->first;
|
|
|
|
|
// bsw.args.Switch.values[b] =
|
|
|
|
|
// program.m_code[it->second].args.ImageLayerColour.colour;
|
|
|
|
|
// ++it;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// bsw.args.Switch.def = colourAt;
|
|
|
|
|
// colourAt = program.AddOp( bsw );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// OP top;
|
|
|
|
|
// top.type = branchType;
|
|
|
|
|
// top.args.ImageLayerColour.base = baseAt;
|
|
|
|
|
// top.args.ImageLayerColour.mask = maskAt;
|
|
|
|
|
// top.args.ImageLayerColour.colour = colourAt;
|
|
|
|
|
// at = program.AddOp( top );
|
|
|
|
|
// optimised = true;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// default:
|
|
|
|
|
// break;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// m_modified |= optimised;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
|
|
|
case OP_TYPE::IM_COMPOSE:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageCompose* typedAt = static_cast<const ASTOpImageCompose*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> blockAt = typedAt->BlockImage.child();
|
|
|
|
|
Ptr<ASTOp> baseAt = typedAt->Base.child();
|
|
|
|
|
Ptr<ASTOp> layoutAt = typedAt->Layout.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
if (!blockAt)
|
|
|
|
|
{
|
|
|
|
|
at = baseAt;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OP_TYPE blockType = blockAt->GetOpType();
|
|
|
|
|
OP_TYPE baseType = baseAt->GetOpType();
|
|
|
|
|
|
|
|
|
|
bool baseHasRuntime = m_hasRuntimeParamVisitor.HasAny( baseAt );
|
|
|
|
|
bool blockHasRuntime = m_hasRuntimeParamVisitor.HasAny( blockAt );
|
|
|
|
|
bool layoutHasRuntime = m_hasRuntimeParamVisitor.HasAny( layoutAt );
|
|
|
|
|
|
|
|
|
|
bool optimised = false;
|
|
|
|
|
|
|
|
|
|
// Try to optimise base and block together, if possible
|
|
|
|
|
if ( blockHasRuntime && baseHasRuntime && !layoutHasRuntime )
|
|
|
|
|
{
|
|
|
|
|
if ( baseType == blockType )
|
|
|
|
|
{
|
|
|
|
|
switch ( blockType )
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IM_LAYERCOLOUR:
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayerColor* typedBaseAt = static_cast<const ASTOpImageLayerColor*>(baseAt.get());
|
|
|
|
|
const ASTOpImageLayerColor* typedBlockAt = static_cast<const ASTOpImageLayerColor*>(blockAt.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// The mask is a compose of the block mask on the base mask, but if none has
|
|
|
|
|
// a mask we don't need to make one.
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> baseImage = typedBaseAt->base.child();
|
|
|
|
|
Ptr<ASTOp> baseMask = typedBaseAt->mask.child();
|
|
|
|
|
Ptr<ASTOp> blockImage = typedBlockAt->base.child();
|
|
|
|
|
Ptr<ASTOp> blockMask = typedBlockAt->mask.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpImageCompose> maskOp;
|
|
|
|
|
if (baseMask || blockMask)
|
|
|
|
|
{
|
|
|
|
|
// \TODO: BLEH! This may create a discrepancy of number of mips between
|
|
|
|
|
// the base image and the mask This is for now solved with emergy fix
|
|
|
|
|
// c36adf47-e40d-490f-b709-41142bafad78
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> newBaseMask = EnsureValidMask(baseMask, baseImage);
|
|
|
|
|
Ptr<ASTOp> newBlockMask = EnsureValidMask(blockMask, blockImage);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
maskOp = mu::Clone<ASTOpImageCompose>(typedAt);
|
|
|
|
|
maskOp->Base = newBaseMask;
|
|
|
|
|
maskOp->BlockImage = newBlockMask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The base is composition of the bases of both layer effect
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> baseOp = mu::Clone<ASTOpImageCompose>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
baseOp->Base = baseImage;
|
|
|
|
|
baseOp->BlockImage = blockImage;
|
|
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageLayerColor> nop = mu::Clone<ASTOpImageLayerColor>(blockAt);
|
|
|
|
|
nop->mask = maskOp;
|
|
|
|
|
nop->base = baseOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Done
|
|
|
|
|
at = nop;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OP_TYPE::IM_LAYER:
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayer* typedBaseAt = static_cast<const ASTOpImageLayer*>(baseAt.get());
|
|
|
|
|
const ASTOpImageLayer* typedBlockAt = static_cast<const ASTOpImageLayer*>(blockAt.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// The mask is a compose of the block mask on the base mask, but if none has
|
|
|
|
|
// a mask we don't need to make one.
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> baseImage = typedBaseAt->base.child();
|
|
|
|
|
Ptr<ASTOp> baseBlended = typedBaseAt->blend.child();
|
|
|
|
|
Ptr<ASTOp> baseMask = typedBaseAt->mask.child();
|
|
|
|
|
Ptr<ASTOp> blockImage = typedBlockAt->base.child();
|
|
|
|
|
Ptr<ASTOp> blockBlended = typedBlockAt->blend.child();
|
|
|
|
|
Ptr<ASTOp> blockMask = typedBlockAt->mask.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpImageCompose> maskOp;
|
|
|
|
|
if (baseMask || blockMask)
|
|
|
|
|
{
|
|
|
|
|
// \TODO: BLEH! This may create a discrepancy of number of mips between
|
|
|
|
|
// the base image and the mask This is for now solved with emergy fix
|
|
|
|
|
// c36adf47-e40d-490f-b709-41142bafad78
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> newBaseMask = EnsureValidMask(baseMask, baseImage);
|
|
|
|
|
Ptr<ASTOp> newBlockMask = EnsureValidMask(blockMask, blockImage);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
maskOp = mu::Clone<ASTOpImageCompose>(typedAt);
|
|
|
|
|
maskOp->Base = newBaseMask;
|
|
|
|
|
maskOp->BlockImage = newBlockMask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The base is composition of the bases of both layer effect
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> baseOp = mu::Clone<ASTOpImageCompose>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
baseOp->Base = baseImage;
|
|
|
|
|
baseOp->BlockImage = blockImage;
|
|
|
|
|
|
|
|
|
|
// The base is composition of the bases of both layer effect
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> blendedOp = mu::Clone<ASTOpImageCompose>(typedAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
blendedOp->Base = baseBlended;
|
|
|
|
|
blendedOp->BlockImage = blockBlended;
|
|
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageLayer> nop = mu::Clone<ASTOpImageLayer>(blockAt);
|
|
|
|
|
nop->mask = maskOp;
|
|
|
|
|
nop->base = baseOp;
|
|
|
|
|
nop->blend = blendedOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Done
|
|
|
|
|
at = nop;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Swap two composes
|
|
|
|
|
if ( !optimised && baseHasRuntime && !blockHasRuntime
|
|
|
|
|
&&
|
|
|
|
|
baseType == OP_TYPE::IM_COMPOSE )
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageCompose* typedBaseAt = static_cast<const ASTOpImageCompose*>(baseAt.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> baseBlockAt = typedBaseAt->BlockImage.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
bool baseBlockHasAny = m_hasRuntimeParamVisitor.HasAny( baseBlockAt );
|
|
|
|
|
if ( baseBlockHasAny )
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
|
|
|
|
// Swap
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> childCompose = mu::Clone<ASTOpImageCompose>(at);
|
2022-09-26 15:12:13 -04:00
|
|
|
childCompose->Base = typedBaseAt->Base.child();
|
|
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> parentCompose = mu::Clone<ASTOpImageCompose>(baseAt);
|
2022-09-26 15:12:13 -04:00
|
|
|
parentCompose->Base = childCompose;
|
|
|
|
|
|
|
|
|
|
at = parentCompose;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try to optimise the block
|
|
|
|
|
// This optimisation requires a lot of memory for every target. Use only if
|
|
|
|
|
// we are optimising for GPU processing.
|
|
|
|
|
if ( !optimised && blockHasRuntime && !baseHasRuntime
|
|
|
|
|
//&& m_stateProps.m_gpu.m_external
|
|
|
|
|
// TODO BLEH
|
|
|
|
|
// Only worth in case of more than one block using the same operation. Move this
|
|
|
|
|
// optimisation to that test.
|
|
|
|
|
//&& false
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
switch ( blockType )
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IM_LAYERCOLOUR:
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayerColor* typedBlockAt = static_cast<const ASTOpImageLayerColor*>(blockAt.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> blockImage = typedBlockAt->base.child();
|
|
|
|
|
Ptr<ASTOp> blockMask = typedBlockAt->mask.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// The mask is a compose of the layer mask on a black image, however if there is
|
|
|
|
|
// no mask and the base of the layer opertation is a blanklayout, we can skip
|
|
|
|
|
// generating a mask.
|
|
|
|
|
Ptr<ASTOpImageCompose> maskOp;
|
|
|
|
|
if (blockMask || baseType!=OP_TYPE::IM_BLANKLAYOUT)
|
|
|
|
|
{
|
|
|
|
|
maskOp = mu::Clone<ASTOpImageCompose>(at);
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> newMaskBlock = EnsureValidMask(blockMask, blockImage);
|
2022-09-26 15:12:13 -04:00
|
|
|
maskOp->BlockImage = newMaskBlock;
|
|
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> blackOp = new ASTOpFixed;
|
|
|
|
|
blackOp->op.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[0] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[1] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[2] = 0;
|
2022-12-09 12:21:28 -05:00
|
|
|
blackOp->op.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> plainOp = new ASTOpFixed;
|
|
|
|
|
plainOp->op.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
plainOp->SetChild( plainOp->op.args.ImagePlainColour.colour, blackOp );
|
|
|
|
|
plainOp->op.args.ImagePlainColour.format = EImageFormat::IF_L_UBYTE;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.size[0] = 4;
|
2023-03-17 09:40:20 -04:00
|
|
|
plainOp->op.args.ImagePlainColour.size[1] = 4;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.LODs = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> baseResizeOp = new ASTOpFixed;
|
|
|
|
|
baseResizeOp->op.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
baseResizeOp->SetChild( baseResizeOp->op.args.ImageResizeLike.sizeSource, baseAt );
|
|
|
|
|
baseResizeOp->SetChild( baseResizeOp->op.args.ImageResizeLike.source, plainOp );
|
|
|
|
|
|
|
|
|
|
maskOp->Base = baseResizeOp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The base is composition of the layer base on the compose base
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageCompose> baseOp = mu::Clone<ASTOpImageCompose>(at);
|
|
|
|
|
baseOp->BlockImage = typedBlockAt->base.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageLayerColor> nop = mu::Clone<ASTOpImageLayerColor>(blockAt);
|
|
|
|
|
nop->mask = maskOp;
|
|
|
|
|
nop->base = baseOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Done
|
|
|
|
|
at = nop;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OP_TYPE::IM_LAYER:
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayer* typedBlockAt = static_cast<const ASTOpImageLayer*>(blockAt.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> blockImage = typedBlockAt->base.child();
|
|
|
|
|
Ptr<ASTOp> blockBlended = typedBlockAt->blend.child();
|
|
|
|
|
Ptr<ASTOp> blockMask = typedBlockAt->mask.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// The mask is a compose of the layer mask on a black image, however if there is
|
|
|
|
|
// no mask and the base of the layer opertation is a blanklayout, we can skip
|
|
|
|
|
// generating a mask.
|
|
|
|
|
Ptr<ASTOpImageCompose> maskOp;
|
|
|
|
|
if (blockMask || baseType != OP_TYPE::IM_BLANKLAYOUT)
|
|
|
|
|
{
|
|
|
|
|
maskOp = mu::Clone<ASTOpImageCompose>(at);
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> newMaskBlock = EnsureValidMask(blockMask, blockImage);
|
2022-09-26 15:12:13 -04:00
|
|
|
maskOp->BlockImage = newMaskBlock;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> blackOp = new ASTOpFixed;
|
|
|
|
|
blackOp->op.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[0] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[1] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[2] = 0;
|
2022-12-09 12:21:28 -05:00
|
|
|
blackOp->op.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> plainOp = new ASTOpFixed;
|
|
|
|
|
plainOp->op.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
plainOp->SetChild( plainOp->op.args.ImagePlainColour.colour, blackOp );
|
|
|
|
|
plainOp->op.args.ImagePlainColour.format = EImageFormat::IF_L_UBYTE;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.size[0] = 4;
|
2023-03-17 09:40:20 -04:00
|
|
|
plainOp->op.args.ImagePlainColour.size[1] = 4;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.LODs = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> baseResizeOp = new ASTOpFixed;
|
|
|
|
|
baseResizeOp->op.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
baseResizeOp->SetChild( baseResizeOp->op.args.ImageResizeLike.sizeSource, baseAt );
|
|
|
|
|
baseResizeOp->SetChild( baseResizeOp->op.args.ImageResizeLike.source, plainOp );
|
|
|
|
|
|
|
|
|
|
maskOp->Base = baseResizeOp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The blended is a compose of the blended image on a blank image
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> blendedOp = mu::Clone<ASTOpImageCompose>(at);
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
blendedOp->BlockImage = blockBlended;
|
|
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> blackOp = new ASTOpFixed;
|
|
|
|
|
blackOp->op.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[0] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[1] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[2] = 0;
|
2022-12-09 12:21:28 -05:00
|
|
|
blackOp->op.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> plainOp = new ASTOpFixed;
|
|
|
|
|
plainOp->op.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
plainOp->SetChild( plainOp->op.args.ImagePlainColour.colour, blackOp );
|
|
|
|
|
FImageDesc blendedDesc = baseAt->GetImageDesc();
|
|
|
|
|
plainOp->op.args.ImagePlainColour.format = blendedDesc.m_format;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.size[0] = 4;
|
2023-03-17 09:40:20 -04:00
|
|
|
plainOp->op.args.ImagePlainColour.size[1] = 4;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.LODs = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> resizeOp = new ASTOpFixed;
|
|
|
|
|
resizeOp->op.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
resizeOp->SetChild( resizeOp->op.args.ImageResizeLike.sizeSource, baseAt );
|
|
|
|
|
resizeOp->SetChild( resizeOp->op.args.ImageResizeLike.source, plainOp );
|
|
|
|
|
|
|
|
|
|
blendedOp->Base = resizeOp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The base is composition of the softlight base on the compose base
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageCompose> baseOp = mu::Clone<ASTOpImageCompose>(at);
|
|
|
|
|
baseOp->BlockImage = typedBlockAt->base.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageLayer> nop = mu::Clone<ASTOpImageLayer>(blockAt);
|
|
|
|
|
nop->base = baseOp;
|
|
|
|
|
nop->mask = maskOp;
|
|
|
|
|
nop->blend = blendedOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Done
|
|
|
|
|
at = nop;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// case OP_TYPE::IM_INTERPOLATE:
|
|
|
|
|
// {
|
|
|
|
|
// optimised = true;
|
|
|
|
|
// OP op = program.m_code[blockAt];
|
|
|
|
|
|
|
|
|
|
// // The targets are composition of the block targets on the compose base
|
|
|
|
|
// for ( int t=0; t<MUTABLE_OP_MAX_INTERPOLATE_COUNT; ++t )
|
|
|
|
|
// {
|
|
|
|
|
// if ( op.args.ImageInterpolate.targets[t] )
|
|
|
|
|
// {
|
|
|
|
|
// OP targetOp = program.m_code[at];
|
|
|
|
|
// targetOp.args.ImageCompose.blockImage =
|
|
|
|
|
// op.args.ImageInterpolate.targets[t];
|
|
|
|
|
// op.args.ImageInterpolate.targets[t] = program.AddOp( targetOp );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Done
|
|
|
|
|
// at = program.AddOp( op );
|
|
|
|
|
|
|
|
|
|
// // Reprocess the new children
|
|
|
|
|
// at = Recurse( at, program );
|
|
|
|
|
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try to optimise the base
|
|
|
|
|
if ( !optimised && baseHasRuntime /*&& m_stateProps.nodeState.m_optimisation.m_gpu.m_external*/ )
|
|
|
|
|
{
|
|
|
|
|
switch ( baseType )
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IM_LAYERCOLOUR:
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayerColor* typedBaseAt = static_cast<const ASTOpImageLayerColor*>(baseAt.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> maskOp = mu::Clone<ASTOpImageCompose>(at);
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
Ptr<ASTOpFixed> blackOp = new ASTOpFixed;
|
|
|
|
|
blackOp->op.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[0] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[1] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[2] = 0;
|
2022-12-09 12:21:28 -05:00
|
|
|
blackOp->op.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> plainOp = new ASTOpFixed;
|
|
|
|
|
plainOp->op.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
plainOp->SetChild( plainOp->op.args.ImagePlainColour.colour, blackOp );
|
|
|
|
|
plainOp->op.args.ImagePlainColour.format = EImageFormat::IF_L_UBYTE; //TODO: FORMAT_LIKE
|
|
|
|
|
plainOp->op.args.ImagePlainColour.size[0] = 4;
|
2023-03-17 09:40:20 -04:00
|
|
|
plainOp->op.args.ImagePlainColour.size[1] = 4;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.LODs = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> blockResizeOp = new ASTOpFixed;
|
|
|
|
|
blockResizeOp->op.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
blockResizeOp->SetChild( blockResizeOp->op.args.ImageResizeLike.sizeSource, blockAt );
|
|
|
|
|
blockResizeOp->SetChild( blockResizeOp->op.args.ImageResizeLike.source, plainOp );
|
|
|
|
|
|
|
|
|
|
// Blank out the block from the mask
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> newMaskBase = EnsureValidMask( typedBaseAt->mask.child(), baseAt );
|
2022-09-26 15:12:13 -04:00
|
|
|
maskOp->Base = newMaskBase;
|
|
|
|
|
maskOp->BlockImage = blockResizeOp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The base is composition of the softlight base on the compose base
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> baseOp = mu::Clone<ASTOpImageCompose>(at);
|
2022-12-05 05:01:41 -05:00
|
|
|
baseOp->Base = typedBaseAt->base.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageLayerColor> nop = mu::Clone<ASTOpImageLayerColor>(baseAt);
|
|
|
|
|
nop->base = baseOp;
|
|
|
|
|
nop->mask = maskOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Done
|
|
|
|
|
at = nop;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OP_TYPE::IM_LAYER:
|
|
|
|
|
{
|
|
|
|
|
optimised = true;
|
|
|
|
|
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayer* typedBaseAt = static_cast<const ASTOpImageLayer*>(baseAt.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageCompose> maskOp = mu::Clone<ASTOpImageCompose>(at);
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
Ptr<ASTOpFixed> blackOp = new ASTOpFixed;
|
|
|
|
|
blackOp->op.type = OP_TYPE::CO_CONSTANT;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[0] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[1] = 0;
|
|
|
|
|
blackOp->op.args.ColourConstant.value[2] = 0;
|
2022-12-09 12:21:28 -05:00
|
|
|
blackOp->op.args.ColourConstant.value[3] = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> plainOp = new ASTOpFixed;
|
|
|
|
|
plainOp->op.type = OP_TYPE::IM_PLAINCOLOUR;
|
|
|
|
|
plainOp->SetChild( plainOp->op.args.ImagePlainColour.colour, blackOp );
|
|
|
|
|
plainOp->op.args.ImagePlainColour.format = EImageFormat::IF_L_UBYTE; //TODO: FORMAT_LIKE
|
|
|
|
|
plainOp->op.args.ImagePlainColour.size[0] = 4;
|
2023-03-17 09:40:20 -04:00
|
|
|
plainOp->op.args.ImagePlainColour.size[1] = 4;
|
|
|
|
|
plainOp->op.args.ImagePlainColour.LODs = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
Ptr<ASTOpFixed> blockResizeOp = new ASTOpFixed;
|
|
|
|
|
blockResizeOp->op.type = OP_TYPE::IM_RESIZELIKE;
|
|
|
|
|
blockResizeOp->SetChild( blockResizeOp->op.args.ImageResizeLike.sizeSource, blockAt );
|
|
|
|
|
blockResizeOp->SetChild( blockResizeOp->op.args.ImageResizeLike.source, plainOp );
|
|
|
|
|
|
|
|
|
|
// Blank out the block from the mask
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOp> newMaskBase = EnsureValidMask( typedBaseAt->mask.child(), baseAt );
|
2022-09-26 15:12:13 -04:00
|
|
|
maskOp->Base = newMaskBase;
|
|
|
|
|
maskOp->BlockImage = blockResizeOp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The base is composition of the effect base on the compose base
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageCompose> baseOp = mu::Clone<ASTOpImageCompose>(at);
|
|
|
|
|
baseOp->Base = typedBaseAt->base.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
Ptr<ASTOpImageLayer> nop = mu::Clone<ASTOpImageLayer>(baseAt);
|
|
|
|
|
nop->base = baseOp;
|
|
|
|
|
nop->mask = maskOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Done
|
|
|
|
|
at = nop;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// case OP_TYPE::IM_INTERPOLATE:
|
|
|
|
|
// {
|
|
|
|
|
// optimised = true;
|
|
|
|
|
// OP op = program.m_code[baseAt];
|
|
|
|
|
|
|
|
|
|
// // The targets are composition of the blocks on the compose base targets
|
|
|
|
|
// for ( int t=0; t<MUTABLE_OP_MAX_INTERPOLATE_COUNT; ++t )
|
|
|
|
|
// {
|
|
|
|
|
// if ( op.args.ImageInterpolate.targets[t] )
|
|
|
|
|
// {
|
|
|
|
|
// OP targetOp = program.m_code[at];
|
|
|
|
|
// targetOp.args.ImageCompose.base =
|
|
|
|
|
// op.args.ImageInterpolate.targets[t];
|
|
|
|
|
// op.args.ImageInterpolate.targets[t] = program.AddOp( targetOp );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Done
|
|
|
|
|
// at = program.AddOp( op );
|
|
|
|
|
|
|
|
|
|
// // Reprocess the new children
|
|
|
|
|
// at = Recurse( at, program );
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_modified = m_modified || optimised;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
|
|
|
// TODO: Other ops?
|
|
|
|
|
case OP_TYPE::IM_BLEND:
|
|
|
|
|
{
|
|
|
|
|
OP op = program.m_code[at];
|
|
|
|
|
|
|
|
|
|
if ( !m_hasRuntimeParamVisitor.HasAny( op.args.ImageLayer.mask, program ) )
|
|
|
|
|
{
|
|
|
|
|
// If both the base and the blended have the same image layer operation with
|
|
|
|
|
// similar parameters, we can move that operation up.
|
|
|
|
|
OP_TYPE baseType = program.m_code[ op.args.ImageLayer.base ].type;
|
|
|
|
|
OP_TYPE blendedType = program.m_code[ op.args.ImageLayer.blended ].type;
|
|
|
|
|
if ( baseType == blendedType )
|
|
|
|
|
{
|
|
|
|
|
switch ( baseType )
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IM_BLENDCOLOUR:
|
|
|
|
|
case OP_TYPE::IM_SOFTLIGHTCOLOUR:
|
|
|
|
|
case OP_TYPE::IM_HARDLIGHTCOLOUR:
|
|
|
|
|
case OP_TYPE::IM_BURNCOLOUR:
|
|
|
|
|
case OP_TYPE::IM_SCREENCOLOUR:
|
|
|
|
|
case OP_TYPE::IM_OVERLAYCOLOUR:
|
|
|
|
|
case OP_TYPE::IM_DODGECOLOUR:
|
|
|
|
|
case OP_TYPE::IM_MULTIPLYCOLOUR:
|
|
|
|
|
{
|
2023-06-15 06:49:52 -04:00
|
|
|
if ( OptimisationOptions.m_optimiseOverlappedMasks )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
OP::ADDRESS maskAt = op.args.ImageLayer.mask;
|
|
|
|
|
OP::ADDRESS baseMaskAt =
|
|
|
|
|
program.m_code[ op.args.ImageLayer.base ].args.ImageLayerColour.mask;
|
|
|
|
|
OP::ADDRESS blendedMaskAt =
|
|
|
|
|
program.m_code[ op.args.ImageLayer.blended ].args.ImageLayerColour.mask;
|
|
|
|
|
OP::ADDRESS baseColourAt =
|
|
|
|
|
program.m_code[ op.args.ImageLayer.base ].args.ImageLayerColour.colour;
|
|
|
|
|
OP::ADDRESS blendedColourAt =
|
|
|
|
|
program.m_code[ op.args.ImageLayer.blended ].args.ImageLayerColour.colour;
|
|
|
|
|
|
|
|
|
|
// Check extra conditions on the masks
|
|
|
|
|
if ( maskAt && baseMaskAt && blendedMaskAt
|
|
|
|
|
&& (baseColourAt==blendedColourAt)
|
|
|
|
|
&& !AreMasksOverlapping( program, baseMaskAt, blendedMaskAt )
|
|
|
|
|
&& !AreMasksOverlapping( program, baseMaskAt, maskAt ) )
|
|
|
|
|
{
|
|
|
|
|
// We can apply the transform
|
|
|
|
|
m_modified = true;
|
|
|
|
|
|
|
|
|
|
OP baseOp;
|
|
|
|
|
baseOp.type = OP_TYPE::IM_BLEND;
|
|
|
|
|
baseOp.args.ImageLayer.base =
|
|
|
|
|
program.m_code[ op.args.ImageLayer.base ].args.ImageLayerColour.base;
|
|
|
|
|
baseOp.args.ImageLayer.blended =
|
|
|
|
|
program.m_code[ op.args.ImageLayer.blended ].args.ImageLayerColour.base;
|
|
|
|
|
baseOp.args.ImageLayer.mask = maskAt;
|
|
|
|
|
|
|
|
|
|
// TODO: Find out why these are not equivalent
|
|
|
|
|
// OP maskOp;
|
|
|
|
|
// maskOp.type = OP_TYPE::IM_SCREEN;
|
|
|
|
|
// maskOp.args.ImageLayer.base = baseMaskAt;
|
|
|
|
|
// maskOp.args.ImageLayer.blended = blendedMaskAt;
|
|
|
|
|
OP maskOp;
|
|
|
|
|
maskOp.type = OP_TYPE::IM_BLEND;
|
|
|
|
|
maskOp.args.ImageLayer.base = baseMaskAt;
|
|
|
|
|
maskOp.args.ImageLayer.blended = blendedMaskAt;
|
|
|
|
|
maskOp.args.ImageLayer.mask = blendedMaskAt;
|
|
|
|
|
maskOp.args.ImageLayer.flags = OP::ImageLayerArgs::F_BINARY_MASK;
|
|
|
|
|
|
|
|
|
|
OP top;
|
|
|
|
|
top.type = baseType;
|
|
|
|
|
top.args.ImageLayerColour.base = program.AddOp( baseOp );
|
|
|
|
|
top.args.ImageLayerColour.mask = program.AddOp( maskOp );
|
|
|
|
|
top.args.ImageLayerColour.colour = baseColourAt;
|
|
|
|
|
at = program.AddOp( top );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
|
|
|
// Sink the mipmap if worth it.
|
|
|
|
|
case OP_TYPE::IM_MIPMAP:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageMipmap* typedAt = static_cast<const ASTOpImageMipmap*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> sourceOp = typedAt->Source.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
switch ( sourceOp->GetOpType() )
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IM_LAYERCOLOUR:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayerColor* typedSource = static_cast<const ASTOpImageLayerColor*>(sourceOp.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
bool colourHasRuntime = m_hasRuntimeParamVisitor.HasAny( typedSource->color.child() );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
if (colourHasRuntime)
|
|
|
|
|
{
|
|
|
|
|
m_modified = true;
|
|
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageLayerColor> top = mu::Clone<ASTOpImageLayerColor>(sourceOp);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageMipmap> baseOp = mu::Clone<ASTOpImageMipmap>(at);
|
2022-12-05 05:01:41 -05:00
|
|
|
baseOp->Source = typedSource->base.child();
|
|
|
|
|
top->base = baseOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> sourceMaskOp = typedSource->mask.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
if (sourceMaskOp)
|
|
|
|
|
{
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOpImageMipmap> maskOp = mu::Clone<ASTOpImageMipmap>(at);
|
2022-09-26 15:12:13 -04:00
|
|
|
maskOp->Source = sourceMaskOp;
|
2022-12-05 05:01:41 -05:00
|
|
|
top->mask = maskOp;
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
at = top;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return at;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AccumulateAllImageFormatsOpAST
|
|
|
|
|
: public Visitor_TopDown_Unique_Const< std::array<uint8_t, size_t(EImageFormat::IF_COUNT)> >
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
void Run( const ASTOpList& roots )
|
|
|
|
|
{
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(AccumulateAllImageFormatsOpAST);
|
|
|
|
|
|
|
|
|
|
// Initially, all formats are supported
|
|
|
|
|
m_allSupported.fill(1);
|
|
|
|
|
|
|
|
|
|
// The initial traversal state is no format supported
|
|
|
|
|
m_initialState.fill(0);
|
|
|
|
|
Traverse( roots, m_initialState );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Visit( const Ptr<ASTOp>& at ) override
|
|
|
|
|
{
|
|
|
|
|
bool recurse = false;
|
|
|
|
|
|
|
|
|
|
const std::array<uint8_t, (size_t)EImageFormat::IF_COUNT>& currentFormats = GetCurrentState();
|
|
|
|
|
|
|
|
|
|
// Remove unsupported formats
|
|
|
|
|
if (GetOpDataType( at->GetOpType() )==DT_IMAGE)
|
|
|
|
|
{
|
2023-01-12 09:46:04 -05:00
|
|
|
std::array<uint8_t, (size_t)EImageFormat::IF_COUNT>* it = m_supportedFormats.Find(at);
|
2022-10-11 05:14:05 -04:00
|
|
|
if (!it)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
// Default to all supported
|
2022-10-11 05:14:05 -04:00
|
|
|
m_supportedFormats.Add(at, m_allSupported);
|
|
|
|
|
it = m_supportedFormats.Find(at);
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( unsigned f=0; f< (unsigned)EImageFormat::IF_COUNT; ++f )
|
|
|
|
|
{
|
|
|
|
|
if ( !currentFormats[f] )
|
|
|
|
|
{
|
2022-10-11 05:14:05 -04:00
|
|
|
(*it)[f] = 0;
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ( at->GetOpType() )
|
|
|
|
|
{
|
|
|
|
|
// TODO: Code shared with the constant data format optimisation visitor
|
|
|
|
|
case OP_TYPE::IM_LAYERCOLOUR:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayerColor* typedAt = static_cast<const ASTOpImageLayerColor*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
RecurseWithCurrentState( typedAt->base.child() );
|
|
|
|
|
RecurseWithCurrentState( typedAt->color.child() );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
if ( typedAt->mask )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
std::array<uint8_t, (size_t)EImageFormat::IF_COUNT> newState;
|
|
|
|
|
newState.fill(0);
|
|
|
|
|
newState[(size_t)EImageFormat::IF_L_UBYTE ] = 1;
|
|
|
|
|
newState[(size_t)EImageFormat::IF_L_UBYTE_RLE ] = 1;
|
|
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
RecurseWithState( typedAt->mask.child(), newState );
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OP_TYPE::IM_LAYER:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpImageLayer* typedAt = static_cast<const ASTOpImageLayer*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
RecurseWithCurrentState( typedAt->base.child() );
|
|
|
|
|
RecurseWithCurrentState( typedAt->blend.child() );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
std::array<uint8_t, (size_t)EImageFormat::IF_COUNT> newState;
|
|
|
|
|
newState.fill(0);
|
|
|
|
|
// TODO
|
|
|
|
|
//newState[ IF_L_UBYTE ] = 1;
|
|
|
|
|
//newState[ IF_L_UBYTE_RLE ] = 1;
|
|
|
|
|
|
2022-12-05 05:01:41 -05:00
|
|
|
if ( typedAt->mask )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2022-12-05 05:01:41 -05:00
|
|
|
RecurseWithState( typedAt->mask.child(), newState );
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case OP_TYPE::IM_DISPLACE:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpFixed* typedAt = static_cast<const ASTOpFixed*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
RecurseWithCurrentState( typedAt->children[typedAt->op.args.ImageDisplace.source].child() );
|
|
|
|
|
|
|
|
|
|
std::array<uint8_t, (size_t)EImageFormat::IF_COUNT> newState;
|
|
|
|
|
newState.fill(0);
|
|
|
|
|
newState[(size_t)EImageFormat::IF_L_UBYTE ] = 1;
|
|
|
|
|
newState[(size_t)EImageFormat::IF_L_UBYTE_RLE ] = 1;
|
|
|
|
|
RecurseWithState( typedAt->children[typedAt->op.args.ImageDisplace.displacementMap].child(), newState );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
SetCurrentState( m_initialState );
|
|
|
|
|
recurse = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return recurse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool IsSupportedFormat( Ptr<ASTOp> at, EImageFormat format ) const
|
|
|
|
|
{
|
2023-01-12 09:46:04 -05:00
|
|
|
const std::array<uint8_t, (size_t)EImageFormat::IF_COUNT>* it = m_supportedFormats.Find(at);
|
2022-10-11 05:14:05 -04:00
|
|
|
if (!it)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
return (*it)[(size_t)format]!=0;
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
//! Formats known to be supported for every instruction.
|
|
|
|
|
//! IF_COUNT*code.size() entries
|
2022-10-11 05:14:05 -04:00
|
|
|
TMap< Ptr<ASTOp>, std::array<uint8_t, (size_t)EImageFormat::IF_COUNT> > m_supportedFormats;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
//! Constant convenience initial value
|
|
|
|
|
std::array<uint8_t, (size_t)EImageFormat::IF_COUNT> m_initialState;
|
|
|
|
|
|
|
|
|
|
//! Constant convenience initial value
|
|
|
|
|
std::array<uint8_t, (size_t)EImageFormat::IF_COUNT> m_allSupported;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
void SubtreeRelevantParametersVisitorAST::Run( Ptr<ASTOp> root )
|
|
|
|
|
{
|
|
|
|
|
// Cached?
|
2023-12-19 05:19:14 -05:00
|
|
|
TSet<FString>* it = m_resultCache.Find( FState(root,false) );
|
|
|
|
|
if (it)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2023-12-19 05:19:14 -05:00
|
|
|
m_params = *it;
|
2022-09-26 15:12:13 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Not cached
|
|
|
|
|
{
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(SubtreeRelevantParametersVisitorAST);
|
|
|
|
|
|
2023-09-26 04:43:37 -04:00
|
|
|
m_params.Empty();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// The state is the onlyLayoutRelevant flag
|
|
|
|
|
ASTOp::Traverse_TopDown_Unique_Imprecise_WithState<bool>( root, false,
|
2022-10-11 05:14:05 -04:00
|
|
|
[&]( Ptr<ASTOp>& at, bool& state, TArray<TPair<Ptr<ASTOp>,bool>>& pending )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
(void)state;
|
|
|
|
|
|
|
|
|
|
switch ( at->GetOpType() )
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::NU_PARAMETER:
|
|
|
|
|
case OP_TYPE::SC_PARAMETER:
|
|
|
|
|
case OP_TYPE::BO_PARAMETER:
|
|
|
|
|
case OP_TYPE::CO_PARAMETER:
|
|
|
|
|
case OP_TYPE::PR_PARAMETER:
|
|
|
|
|
case OP_TYPE::IM_PARAMETER:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpParameter* typedAt = static_cast<const ASTOpParameter*>(at.get());
|
2023-09-26 04:43:37 -04:00
|
|
|
m_params.Add(typedAt->parameter.m_name);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Not interested in the parameters from the parameters decorators.
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-08 12:29:21 -05:00
|
|
|
case OP_TYPE::LA_FROMMESH:
|
|
|
|
|
{
|
|
|
|
|
// Manually choose how to recurse this op
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpLayoutFromMesh* pTyped = static_cast<const ASTOpLayoutFromMesh*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-11-08 12:29:21 -05:00
|
|
|
// For that mesh we only want to know about the layouts
|
|
|
|
|
if (const ASTChild& Mesh = pTyped->Mesh)
|
|
|
|
|
{
|
|
|
|
|
pending.Add({ Mesh.m_child, true });
|
|
|
|
|
}
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-11-08 12:29:21 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-06-08 05:48:32 -04:00
|
|
|
case OP_TYPE::ME_MORPH:
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
// Manually choose how to recurse this op
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpMeshMorph* pTyped = static_cast<const ASTOpMeshMorph*>( at.get() );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
if ( pTyped->Base )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2023-01-12 09:46:04 -05:00
|
|
|
pending.Add({ pTyped->Base.m_child, state });
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mesh morphs don't modify the layouts, so we can ignore the factor and morphs
|
|
|
|
|
if (!state)
|
|
|
|
|
{
|
2023-01-12 09:46:04 -05:00
|
|
|
if ( pTyped->Factor )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2023-01-12 09:46:04 -05:00
|
|
|
pending.Add({ pTyped->Factor.m_child, state });
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
|
2023-06-08 05:48:32 -04:00
|
|
|
if ( pTyped->Target )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2023-06-08 05:48:32 -04:00
|
|
|
pending.Add({ pTyped->Target.m_child, state });
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
2023-12-19 05:19:14 -05:00
|
|
|
m_resultCache.Add( FState(root,false), m_params );
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//! Mark all the instructions that don't depend on runtime parameters but are below
|
|
|
|
|
//! instructions that do.
|
|
|
|
|
//! Also detect which instructions are the root of a resource that is dynamic in this state.
|
|
|
|
|
//! Visitor state is:
|
|
|
|
|
//! .first IsResourceRoot
|
|
|
|
|
//! .second ParentIsRuntime
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
2022-10-11 05:14:05 -04:00
|
|
|
class StateCacheDetectorAST : public Visitor_TopDown_Unique_Const< TPair<bool,bool> >
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
|
2023-12-19 05:19:14 -05:00
|
|
|
StateCacheDetectorAST(FStateCompilationData* pState )
|
2022-09-26 15:12:13 -04:00
|
|
|
: m_hasRuntimeParamVisitor( pState )
|
|
|
|
|
{
|
|
|
|
|
ASTOpList roots;
|
2022-10-11 05:14:05 -04:00
|
|
|
roots.Add(pState->root);
|
|
|
|
|
Traverse(roots, { false,false });
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
pState->m_updateCache.Empty();
|
|
|
|
|
pState->m_dynamicResources.Empty();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
for( const TPair<Ptr<ASTOp>, bool>& i : m_cache )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2022-10-11 05:14:05 -04:00
|
|
|
if ( i.Value )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2022-10-11 05:14:05 -04:00
|
|
|
pState->m_updateCache.Add( i.Key );
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-12 09:46:04 -05:00
|
|
|
for(const TPair<Ptr<ASTOp>, bool>& i : m_dynamicResourceRoot )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2022-10-11 05:14:05 -04:00
|
|
|
if ( i.Value )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
// Generate the list of relevant parameters
|
|
|
|
|
SubtreeRelevantParametersVisitorAST subtreeParams;
|
2022-10-11 05:14:05 -04:00
|
|
|
subtreeParams.Run( i.Key );
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
// Temp copy
|
2023-09-26 04:43:37 -04:00
|
|
|
TArray<FString> ParamCopy;
|
|
|
|
|
for ( const FString& e: subtreeParams.m_params )
|
2022-10-11 05:14:05 -04:00
|
|
|
{
|
|
|
|
|
ParamCopy.Add(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pState->m_dynamicResources.Emplace( i.Key, MoveTemp(ParamCopy) );
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Visit( const Ptr<ASTOp>& at ) override
|
|
|
|
|
{
|
|
|
|
|
bool thisIsRuntime = m_hasRuntimeParamVisitor.HasAny( at );
|
|
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
bool resourceRoot = GetCurrentState().Key;
|
|
|
|
|
bool parentIsRuntime = GetCurrentState().Value;
|
|
|
|
|
|
|
|
|
|
m_cache.FindOrAdd(at, false);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
OP_TYPE type = at->GetOpType();
|
|
|
|
|
if ( GetOpDesc( type ).cached )
|
|
|
|
|
{
|
|
|
|
|
// If parent is runtime, but we are not
|
|
|
|
|
if ( (!thisIsRuntime) && parentIsRuntime
|
|
|
|
|
&&
|
|
|
|
|
// Resource roots are special, and they don't need to be marked as updateCache
|
|
|
|
|
// since the dynamicResource flag takes care of everything.
|
|
|
|
|
!resourceRoot )
|
|
|
|
|
{
|
|
|
|
|
// We want to cache this result to update the instances.
|
|
|
|
|
// Mark this as update cache
|
2022-10-11 05:14:05 -04:00
|
|
|
m_cache.Add(at, true);
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !m_cache[at] && resourceRoot && thisIsRuntime )
|
|
|
|
|
{
|
2022-10-11 05:14:05 -04:00
|
|
|
m_dynamicResourceRoot.Add(at, true);
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !m_cache[at] && thisIsRuntime )
|
|
|
|
|
{
|
|
|
|
|
switch( type )
|
|
|
|
|
{
|
|
|
|
|
case OP_TYPE::IN_ADDIMAGE:
|
|
|
|
|
case OP_TYPE::IN_ADDMESH:
|
|
|
|
|
case OP_TYPE::IN_ADDVECTOR:
|
|
|
|
|
case OP_TYPE::IN_ADDSCALAR:
|
|
|
|
|
case OP_TYPE::IN_ADDSTRING:
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
const ASTOpInstanceAdd* typedAt = static_cast<const ASTOpInstanceAdd*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
TPair<bool,bool> newState;
|
|
|
|
|
newState.Key = false; //resource root
|
|
|
|
|
newState.Value = thisIsRuntime;
|
2022-09-26 15:12:13 -04:00
|
|
|
RecurseWithState( typedAt->instance.child(), newState );
|
|
|
|
|
|
|
|
|
|
if ( typedAt->value )
|
|
|
|
|
{
|
2022-10-11 05:14:05 -04:00
|
|
|
newState.Key = true; //resource root
|
|
|
|
|
newState.Value = thisIsRuntime;
|
2022-09-26 15:12:13 -04:00
|
|
|
RecurseWithState( typedAt->value.child(), newState );
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
2022-10-11 05:14:05 -04:00
|
|
|
TPair<bool,bool> newState;
|
|
|
|
|
newState.Key = false; //resource root
|
|
|
|
|
newState.Value = thisIsRuntime;
|
2022-09-26 15:12:13 -04:00
|
|
|
SetCurrentState(newState);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
//!
|
2022-10-11 05:14:05 -04:00
|
|
|
TMap<Ptr<ASTOp>,bool> m_cache;
|
|
|
|
|
TMap<Ptr<ASTOp>,bool> m_dynamicResourceRoot;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
RuntimeParameterVisitorAST m_hasRuntimeParamVisitor;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//! Find out what images can be compressed during build phase of an instance so that the update
|
|
|
|
|
//! cache can be smaller (and some update operations faster)
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
class StateCacheFormatOptimiserAST : public Visitor_TopDown_Unique_Cloning
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
|
2023-12-19 05:19:14 -05:00
|
|
|
StateCacheFormatOptimiserAST(FStateCompilationData& state,
|
2022-09-26 15:12:13 -04:00
|
|
|
const AccumulateAllImageFormatsOpAST& opFormats )
|
|
|
|
|
: m_state(state)
|
|
|
|
|
, m_opFormats(opFormats)
|
|
|
|
|
{
|
|
|
|
|
Traverse( state.root );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
|
|
Ptr<ASTOp> Visit( Ptr<ASTOp> at, bool& processChildren ) override
|
|
|
|
|
{
|
|
|
|
|
processChildren = true;
|
|
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
bool isUpdateCache = m_state.m_updateCache.Contains(at);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
if ( isUpdateCache )
|
|
|
|
|
{
|
|
|
|
|
// Its children cannot be update-cache, so no need to process them.
|
|
|
|
|
processChildren = false;
|
|
|
|
|
|
|
|
|
|
// See if we can convert it to a more efficient format
|
|
|
|
|
if ( GetOpDataType( at->GetOpType() )==DT_IMAGE )
|
|
|
|
|
{
|
|
|
|
|
FImageDesc desc = at->GetImageDesc();
|
|
|
|
|
|
|
|
|
|
if ( desc.m_format!=EImageFormat::IF_L_UBYTE_RLE
|
|
|
|
|
&&
|
|
|
|
|
m_opFormats.IsSupportedFormat(at, EImageFormat::IF_L_UBYTE_RLE) )
|
|
|
|
|
{
|
|
|
|
|
Ptr<ASTOpImagePixelFormat> op = new ASTOpImagePixelFormat;
|
|
|
|
|
op->Format = EImageFormat::IF_L_UBYTE_RLE;
|
|
|
|
|
// Note: we have to clone here, to avoid a loop with the visitor system
|
|
|
|
|
// that updates visited children before processing a node.
|
|
|
|
|
ASTOp::MapChildFunc Identity = [](const Ptr<ASTOp>& o) {return o;};
|
|
|
|
|
op->Source = at->Clone(Identity);
|
|
|
|
|
|
|
|
|
|
at = op;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return at;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
2023-12-19 05:19:14 -05:00
|
|
|
FStateCompilationData& m_state;
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
const AccumulateAllImageFormatsOpAST& m_opFormats;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
RuntimeTextureCompressionRemoverAST::RuntimeTextureCompressionRemoverAST(
|
2023-12-19 05:19:14 -05:00
|
|
|
FStateCompilationData* pState,
|
2023-03-08 04:37:54 -05:00
|
|
|
bool bInAlwaysUncompress
|
|
|
|
|
)
|
2022-09-26 15:12:13 -04:00
|
|
|
: m_hasRuntimeParamVisitor(pState)
|
2023-03-08 04:37:54 -05:00
|
|
|
, bAlwaysUncompress(bInAlwaysUncompress)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
Traverse( pState->root );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ptr<ASTOp> RuntimeTextureCompressionRemoverAST::Visit( Ptr<ASTOp> at, bool& processChildren )
|
|
|
|
|
{
|
|
|
|
|
OP_TYPE type = at->GetOpType();
|
|
|
|
|
processChildren = GetOpDataType(type)==DT_INSTANCE;
|
|
|
|
|
|
2023-03-08 04:37:54 -05:00
|
|
|
// TODO: Finer grained: what if the runtime parameter just selects between compressed
|
2022-09-26 15:12:13 -04:00
|
|
|
// textures? We don't want them uncompressed.
|
|
|
|
|
if( type==OP_TYPE::IN_ADDIMAGE )
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
ASTOpInstanceAdd* typedAt = static_cast<ASTOpInstanceAdd*>(at.get());
|
2023-01-12 09:46:04 -05:00
|
|
|
Ptr<ASTOp> imageAt = typedAt->value.child();
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Does it have a runtime parameter in its subtree?
|
|
|
|
|
bool hasRuntimeParameter = m_hasRuntimeParamVisitor.HasAny( imageAt );
|
|
|
|
|
|
2023-03-08 04:37:54 -05:00
|
|
|
if (bAlwaysUncompress || hasRuntimeParameter)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
FImageDesc imageDesc = imageAt->GetImageDesc( true );
|
|
|
|
|
|
|
|
|
|
// Is it a compressed format?
|
|
|
|
|
EImageFormat format = imageDesc.m_format;
|
|
|
|
|
EImageFormat uncompressedFormat = GetUncompressedFormat( format );
|
|
|
|
|
bool isCompressedFormat = (uncompressedFormat != format);
|
|
|
|
|
|
|
|
|
|
if (isCompressedFormat)
|
|
|
|
|
{
|
|
|
|
|
Ptr<ASTOpInstanceAdd> newAt = mu::Clone<ASTOpInstanceAdd>(at);
|
|
|
|
|
|
|
|
|
|
// Add a new format operation to uncompress the image
|
|
|
|
|
Ptr<ASTOpImagePixelFormat> fop = new ASTOpImagePixelFormat;
|
|
|
|
|
fop->Format = uncompressedFormat;
|
|
|
|
|
fop->FormatIfAlpha = uncompressedFormat;
|
|
|
|
|
fop->Source = imageAt;
|
|
|
|
|
|
|
|
|
|
newAt->value = fop;
|
|
|
|
|
at = newAt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return at;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
2024-07-23 07:00:39 -04:00
|
|
|
LODCountReducerAST::LODCountReducerAST( Ptr<ASTOp>& root, int32 lodCount )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
m_lodCount = lodCount;
|
|
|
|
|
Traverse( root );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ptr<ASTOp> LODCountReducerAST::Visit( Ptr<ASTOp> at, bool& processChildren )
|
|
|
|
|
{
|
|
|
|
|
processChildren = true;
|
|
|
|
|
|
|
|
|
|
if( at->GetOpType()==OP_TYPE::IN_ADDLOD )
|
|
|
|
|
{
|
2024-01-18 03:27:38 -05:00
|
|
|
ASTOpAddLOD* typedAt = static_cast<ASTOpAddLOD*>(at.get());
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
if (typedAt->lods.Num()>(size_t)m_lodCount)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
Ptr<ASTOpAddLOD> newAt = mu::Clone<ASTOpAddLOD>(at);
|
2022-10-11 05:14:05 -04:00
|
|
|
while( newAt->lods.Num()>(size_t)m_lodCount )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2022-10-11 05:14:05 -04:00
|
|
|
newAt->lods.Pop();
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
at = newAt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
processChildren = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return at;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
|
|
|
//---------------------------------------------------------------------------------------------
|
2022-12-05 05:01:41 -05:00
|
|
|
void CodeOptimiser::OptimiseStatesAST()
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
2024-06-10 04:10:54 -04:00
|
|
|
MUTABLE_CPUPROFILER_SCOPE(OptimiseStatesAST);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2024-06-10 04:10:54 -04:00
|
|
|
for ( int32 s=0; s<m_states.Num(); ++s )
|
|
|
|
|
{
|
|
|
|
|
// Remove the unnecessary lods
|
|
|
|
|
FStateOptimizationOptions StateOptimization = m_states[s].nodeState.Optimisation;
|
|
|
|
|
if (StateOptimization.bOnlyFirstLOD)
|
|
|
|
|
{
|
|
|
|
|
LODCountReducerAST(m_states[s].root, StateOptimization.FirstLOD + 1 + StateOptimization.NumExtraLODsToBuildAfterFirstLOD);
|
|
|
|
|
}
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2023-03-08 04:37:54 -05:00
|
|
|
// Apply texture compression strategy
|
2024-01-10 09:28:37 -05:00
|
|
|
bool bModified = false;
|
2024-06-10 04:10:54 -04:00
|
|
|
switch (StateOptimization.TextureCompressionStrategy)
|
2023-03-08 04:37:54 -05:00
|
|
|
{
|
|
|
|
|
case ETextureCompressionStrategy::DontCompressRuntime:
|
|
|
|
|
{
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(RuntimeTextureCompressionRemover);
|
|
|
|
|
RuntimeTextureCompressionRemoverAST r(&m_states[s], false);
|
2024-01-10 09:28:37 -05:00
|
|
|
bModified = true;
|
2023-03-08 04:37:54 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case ETextureCompressionStrategy::NeverCompress:
|
|
|
|
|
{
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(RuntimeTextureCompressionRemover);
|
|
|
|
|
RuntimeTextureCompressionRemoverAST r(&m_states[s], true);
|
2024-01-10 09:28:37 -05:00
|
|
|
bModified = true;
|
2023-03-08 04:37:54 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-26 15:12:13 -04:00
|
|
|
// If a state has no runtime parameters, skip its optimisation alltogether
|
2024-06-10 04:10:54 -04:00
|
|
|
if (bModified || m_states[s].nodeState.RuntimeParams.Num())
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
// Promote the intructions that depend on runtime parameters, and sink new
|
|
|
|
|
// format instructions.
|
|
|
|
|
bool modified = true;
|
2024-07-23 07:00:39 -04:00
|
|
|
int32 numIterations = 0;
|
2022-09-26 15:12:13 -04:00
|
|
|
while (modified && (!m_optimizeIterationsMax || m_optimizeIterationsLeft>0 || !numIterations ))
|
|
|
|
|
{
|
|
|
|
|
modified = false;
|
|
|
|
|
|
|
|
|
|
++numIterations;
|
|
|
|
|
--m_optimizeIterationsLeft;
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT("State optimise iteration %d, max %d, left %d"),
|
|
|
|
|
numIterations, m_optimizeIterationsMax, m_optimizeIterationsLeft);
|
|
|
|
|
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - before parameter optimiser"));
|
|
|
|
|
|
2023-06-15 06:49:52 -04:00
|
|
|
ParameterOptimiserAST param( m_states[s], m_options->GetPrivate()->OptimisationOptions );
|
2022-09-26 15:12:13 -04:00
|
|
|
modified = param.Apply();
|
|
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
TArray<Ptr<ASTOp>> roots;
|
|
|
|
|
roots.Add(m_states[s].root);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - after parameter optimiser"));
|
2024-07-23 07:00:39 -04:00
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// All kind of optimisations that depend on the meaning of each operation
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - semantic optimiser"));
|
2023-06-15 06:49:52 -04:00
|
|
|
modified |= SemanticOptimiserAST( roots, m_options->GetPrivate()->OptimisationOptions, 1 );
|
2024-07-23 07:00:39 -04:00
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
2022-09-26 15:12:13 -04:00
|
|
|
//ASTOp::LogHistogram(roots);
|
|
|
|
|
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - sink optimiser"));
|
2023-06-15 06:49:52 -04:00
|
|
|
modified |= SinkOptimiserAST( roots, m_options->GetPrivate()->OptimisationOptions );
|
2024-07-23 07:00:39 -04:00
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
2022-09-26 15:12:13 -04:00
|
|
|
//ASTOp::LogHistogram(roots);
|
|
|
|
|
|
|
|
|
|
// Image size operations are treated separately
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - size optimiser"));
|
|
|
|
|
modified |= SizeOptimiserAST( roots );
|
|
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
|
|
|
|
|
|
|
|
|
//LogicOptimiser log;
|
|
|
|
|
//modified |= log.Apply( program, s );
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
TArray<Ptr<ASTOp>> roots;
|
|
|
|
|
roots.Add(m_states[s].root);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - duplicated data remover"));
|
|
|
|
|
DuplicatedDataRemoverAST( roots );
|
|
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
|
|
|
|
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - duplicated code remover"));
|
|
|
|
|
DuplicatedCodeRemoverAST( roots );
|
|
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
|
|
|
|
|
2022-10-11 05:14:05 -04:00
|
|
|
m_states[s].root = roots[0];
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 07:00:39 -04:00
|
|
|
|
|
|
|
|
TArray<Ptr<ASTOp>> roots;
|
|
|
|
|
for (const FStateCompilationData& s : m_states)
|
|
|
|
|
{
|
|
|
|
|
roots.Add(s.root);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-26 15:12:13 -04:00
|
|
|
// Mark the instructions that don't depend on runtime parameters to be cached. This is
|
|
|
|
|
// necessary at this stage before GPU optimisation.
|
|
|
|
|
{
|
|
|
|
|
AccumulateAllImageFormatsOpAST opFormats;
|
|
|
|
|
opFormats.Run(roots);
|
|
|
|
|
|
2024-07-23 07:00:39 -04:00
|
|
|
// Reset the state root operations in case they have changed due to optimization
|
|
|
|
|
for (int32 RootIndex = 0; RootIndex < m_states.Num(); ++RootIndex)
|
|
|
|
|
{
|
|
|
|
|
m_states[RootIndex].root = roots[RootIndex];
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 05:19:14 -05:00
|
|
|
for (FStateCompilationData& s: m_states )
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - state cache"));
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(StateCache);
|
|
|
|
|
StateCacheDetectorAST c( &s );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - state cache format"));
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(StateCacheFormat);
|
|
|
|
|
StateCacheFormatOptimiserAST f( s, opFormats );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reoptimise because of state cache reformats and gpuization
|
|
|
|
|
{
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(Reoptimise);
|
|
|
|
|
bool modified = true;
|
2024-02-12 05:31:15 -05:00
|
|
|
int32 numIterations = 0;
|
|
|
|
|
int32 Pass = 1;
|
2022-09-26 15:12:13 -04:00
|
|
|
while (modified && (!m_optimizeIterationsMax || m_optimizeIterationsLeft>0 || !numIterations ))
|
|
|
|
|
{
|
|
|
|
|
++numIterations;
|
|
|
|
|
--m_optimizeIterationsLeft;
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT("State reoptimise iteration %d, max %d, left %d"),
|
|
|
|
|
numIterations, m_optimizeIterationsMax, m_optimizeIterationsLeft);
|
|
|
|
|
|
|
|
|
|
modified = false;
|
|
|
|
|
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - semantic optimiser"));
|
2024-07-23 07:00:39 -04:00
|
|
|
modified |= SemanticOptimiserAST( roots, m_options->GetPrivate()->OptimisationOptions, Pass );
|
|
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Image size operations are treated separately
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - size optimiser"));
|
|
|
|
|
modified |= SizeOptimiserAST( roots );
|
2024-07-23 07:00:39 -04:00
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
2022-09-26 15:12:13 -04:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 07:00:39 -04:00
|
|
|
for(Ptr<ASTOp>& Root : roots)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - constant optimiser"));
|
2024-07-23 07:00:39 -04:00
|
|
|
modified = ConstantGeneratorAST( m_options->GetPrivate(), Root, Pass );
|
2024-02-12 05:31:15 -05:00
|
|
|
}
|
2022-09-26 15:12:13 -04:00
|
|
|
|
2024-07-23 07:00:39 -04:00
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - duplicated data remover"));
|
|
|
|
|
DuplicatedDataRemoverAST( roots );
|
|
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
|
|
|
|
|
|
|
|
|
UE_LOG(LogMutableCore, Verbose, TEXT(" - duplicated code remover"));
|
|
|
|
|
DuplicatedCodeRemoverAST( roots );
|
|
|
|
|
//UE_LOG(LogMutableCore, Verbose, TEXT("(int) %s : %ld"), TEXT("ast size"), int64(ASTOp::CountNodes(roots)));
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 07:00:39 -04:00
|
|
|
// Reset the state root operations in case they have changed due to optimization
|
|
|
|
|
for (int32 RootIndex = 0; RootIndex < m_states.Num(); ++RootIndex)
|
|
|
|
|
{
|
|
|
|
|
m_states[RootIndex].root = roots[RootIndex];
|
|
|
|
|
}
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// Optimise the data formats
|
|
|
|
|
{
|
|
|
|
|
MUTABLE_CPUPROFILER_SCOPE(DataFormats);
|
|
|
|
|
|
2023-09-13 06:59:56 -04:00
|
|
|
DataOptimise( m_options.get(), roots);
|
2022-09-26 15:12:13 -04:00
|
|
|
|
|
|
|
|
// After optimising the data formats, we may remove more constants
|
|
|
|
|
DuplicatedDataRemoverAST( roots );
|
|
|
|
|
DuplicatedCodeRemoverAST( roots );
|
|
|
|
|
|
|
|
|
|
// Update the marks for the instructions that don't depend on runtime parameters to be
|
|
|
|
|
// cached.
|
2023-12-19 05:19:14 -05:00
|
|
|
for (FStateCompilationData& s:m_states)
|
2022-09-26 15:12:13 -04:00
|
|
|
{
|
|
|
|
|
StateCacheDetectorAST c( &s );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|