Using Fabric for Maya with Maya 2016

Maya 2016のサポートはFabric Engine バージョン 2.0.0 で最初に追加されました。Maya 2016の新しい重要な機能のひとつに、Mayaノードグラフの並列評価のサポートがあります。Fabric for Mayaでは、Maya 2016の並列評価機能が有効になっているときは、(ユーザーが設定すれば)特定のノードを並列に実行することができるようになりました。

デフォルトでは、CanvasとSpliceノードはたとえ、Mayaの並列評価が有効になっていたとしても、互いに並列に動作することはありません。なぜかというと、Fabric for Mayaはあらゆる互いのノードが同時に実行されることが安全であるか、確証を持てないためです。例えば、ある2つのノードはスレッドセーフでないKLエクステンションを使っているかもしれません。

Fabric for Mayaでは、ノードごとの並列評価動作を設定できます。2つの異なる動作があります。

  • 共有実行(または評価):Fabricノードは、共有実行が有効になっている他のあらゆる全てのFabricノードと、潜在的に並列に実行されます。

    注釈

    共有実行が有効になっているCanvasノードとSpliceノードは、潜在的に互いに並列実行されます。
  • 排他実行(または評価)(これがデフォルトです):Fabricノードは他のFabricノードとは並列に実行されません。しかしながら、Fabricノードでない、他のノードとは並列に実行される可能性があります(この並列動作はMaya 2016によってコントロールされます)。

注釈

CanvasノードとSpliceノードの共有実行は、Canvasノード、Spliceノードの内部の並列評価とは異なります。たとえFabricノードが共有実行を有効にされていなくても、PEXコールのような内部的な並列操作は実行できるのです。

現在のところ、共有実行はスクリプティングを通してのみ、有効にすることができます。共有実行を有効にするためのスクリプトコマンドが、各Fabric CanvasとFabric Spliceにあります。

Follow these steps to see an example showing the difference between shared and unshared execution of Canvas nodes:

  1. The samples folder “Maya/Canvas/ParallelEvaluation” contains a scene called “four_outlines_with_parallel_evaluation”. It comes in two versions, with the suffix “_OFF” (no shared execution) and with “_ON” (shared execution).
  2. Load the “four_outlines_with_parallel_evaluation_OFF” sample and press playback. After one hundred frames stop playback and take a look at the script log. You will see the time, in milliseconds, it took to evaluate all the Canvas nodes. Keep that number in mind.
  3. Now load the “four_outlines_with_parallel_evaluation_ON” sample and press playback. Depending on your CPU you will probably already notice that it plays back faster. Stop playback and take a look at the script log again. This time the evaluation time should be noticeable smaller.

Canvasノードの並列評価の有効化

Canvasノードの並列評価を有効にするMELコマンドは:

FabricCanvasSetExecuteShared -mayaNode canvasMayaNodeName -enable true;

このコマンドは即座に効果をもたらします。

The MEL command to get the current parallel evaluation mode of a Canvas node is:

FabricCanvasGetExecuteShared -mayaNode canvasMayaNodeName;

It returns 1 (true) if parallel evaluation is enabled for the node and 0 (false) if it is disabled.

Canvasノードの並列計算を行うサンプルのMELスクリプトです:

$count = 16;
loadPlugin "FabricMaya";
file -f -new;
spaceLocator -n "inputLocator1" -p 0 0 0;
spaceLocator -n "inputLocator2" -p 0 0 0;
createNode -n "combiningCanvasNode" "canvasNode";
for ($i = 0; $i < $count; ++$i)
{
    $nodeName = `format -s $i "slowCanvasNode^1s"`;
    print `format -s $nodeName "** Building node ^1s\n"`;
    createNode -n $nodeName "canvasNode";

    FabricCanvasSetExecuteShared -m $nodeName -e false;

    FabricCanvasAddFunc -m $nodeName -e "" -t "func" -c "dfgEntry {}\n";
    FabricCanvasAddPort -m $nodeName -e "func" -d "i1" -p "In" -t "Vec3";
    FabricCanvasAddPort -m $nodeName -e "func" -d "i2" -p "In" -t "Vec3";
    FabricCanvasAddPort -m $nodeName -e "func" -d "o" -p "Out" -t "Vec3";
    FabricCanvasSetCode -m $nodeName -e "func" -c `format -s $i "dfgEntry {\n  UInt64 ticks = getCurrentTicks();\n  o = Vec3();\n  for ( Index n = 0; n < (1<<20); ++n )\n    o += +2e-8 * (i1 + i2);\n  //report(\"op:slow^1s:tid=\" + getHardwareThreadID() + \":\" + getSecondsBetweenTicks(ticks, getCurrentTicks()) + \"ms\");\n}\n"`;

    FabricCanvasAddPort -m $nodeName -e "" -d "i1" -p "In" -t "Vec3";
    FabricCanvasConnect -m $nodeName -e "" -s "i1" -d "func.i1";
    connectAttr -f "inputLocator1.translate" `format -s $nodeName "^1s.i1"`;

    FabricCanvasAddPort -m $nodeName -e "" -d "i2" -p "In" -t "Vec3";
    FabricCanvasConnect -m $nodeName -e "" -s "i2" -d "func.i2";
    connectAttr -f "inputLocator2.translate" `format -s $nodeName "^1s.i2"`;

    FabricCanvasAddPort -m $nodeName -e "" -d "o" -p "Out" -t "Vec3";
    FabricCanvasConnect -m $nodeName -e "" -s "func.o" -d "o";
    $iName = `format -s $i "i^1s"`;
    FabricCanvasAddPort -m "combiningCanvasNode" -e "" -d $iName -p "In" -t "Vec3";
    connectAttr -f `format -s $nodeName "^1s.o"` `format -s $iName "combiningCanvasNode.^1s"`;
}

print "** Building node combiningCanvasNode\n";
FabricCanvasAddPort -m "combiningCanvasNode" -e "" -d "o" -p "Out" -t "Vec3";
spaceLocator -n "outputLocator" -p 0 0 0;
connectAttr -f "combiningCanvasNode.o" "outputLocator.translate";
$combinedKL = "dfgEntry {\n  UInt64 ticks = getCurrentTicks();\n  o = Vec3();";
for ($i = 0; $i < $count; ++$i)
{
  $combinedKL = `format -s $combinedKL -s $i "^1s\n  o += i^2s;"`;
}
$combinedKL = `format -s $combinedKL "^1s\n  //report(\"op:combined:tid=\" + getHardwareThreadID() + \":\" + getSecondsBetweenTicks(ticks, getCurrentTicks()) + \"ms\");\n}"`;
FabricCanvasAddFunc -m "combiningCanvasNode" -e "" -t "func" -c "dfgEntry {}";
FabricCanvasSetCode -m "combiningCanvasNode" -e "func" -c $combinedKL;
for ($i = 0; $i < $count; ++$i)
{
    $iName = `format -s $i "i^1s"`;
    FabricCanvasAddPort -m "combiningCanvasNode" -e "func" -d $iName -p "In" -t "Vec3";
    FabricCanvasConnect -m "combiningCanvasNode" -e "" -s $iName -d `format -s $iName "func.^1s"`;
}
FabricCanvasAddPort -m "combiningCanvasNode" -e "func" -d "o" -p "Out" -t "Vec3";
FabricCanvasConnect -m "combiningCanvasNode" -e "" -s "func.o" -d "o";

currentTime 1;
select -r "inputLocator1";
move -r -10 0 -10;
setKeyframe "inputLocator1.translate";
select -r "inputLocator2";
move -r 3 0 -3;
setKeyframe "inputLocator2.translate";
currentTime 120;
select -r "inputLocator1";
move -r -10 0 10;
setKeyframe "inputLocator1.translate";
select -r "inputLocator2";
move -r -7 0 7;
setKeyframe "inputLocator2.translate";
currentTime 1;
select -r "inputLocator1";

Spliceノードの並列評価の有効化

Spliceノードの並列評価を有効にするMELコマンドは:

fabricSplice "setEvaluateShared" spliceMayaNodeName "{\"enabled\": true}";

このコマンドは即座に効果をもたらします。

Spliceノードの並列計算を行うサンプルのMELスクリプトです:

$count = 16;
loadPlugin "FabricMaya";
file -f -new;
spaceLocator -n "inputLocator1" -p 0 0 0;
spaceLocator -n "inputLocator2" -p 0 0 0;
createNode -n "combiningSpliceNode" "spliceMayaNode";
for ($i = 0; $i < $count; ++$i)
{
    $nodeName = `format -stringArg $i "slowSpliceNode^1s"`;
    print `format -stringArg $nodeName "Building node ^1s"`;
    createNode -n $nodeName "spliceMayaNode";
    fabricSplice "setEvaluateShared" $nodeName "{\"enabled\": true}";
    fabricSplice "addInputPort" $nodeName "{\"portName\": \"i1\", \"dataType\" : \"Vec3\", \"arrayType\": \"Single Value\", \"addMayaAttr\": true}";
    connectAttr -f "inputLocator1.translate" `format -stringArg $nodeName "^1s.i1"`;
    fabricSplice "addInputPort" $nodeName "{\"portName\": \"i2\", \"dataType\" : \"Vec3\", \"arrayType\": \"Single Value\", \"addMayaAttr\": true}";
    connectAttr -f "inputLocator2.translate" `format -stringArg $nodeName "^1s.i2"`;
    fabricSplice "addOutputPort" $nodeName "{\"portName\": \"o\", \"dataType\" : \"Vec3\", \"arrayType\": \"Single Value\", \"addMayaAttr\": true}";
    $iName = `format -stringArg $i "i^1s"`;
    fabricSplice "addInputPort" "combiningSpliceNode" `format -stringArg $iName "{\"portName\": \"^1s\", \"dataType\" : \"Vec3\", \"arrayType\": \"Single Value\", \"addMayaAttr\": true}"`;
    connectAttr -f `format -stringArg $nodeName "^1s.o"` `format -stringArg $iName "combiningSpliceNode.^1s"`;
    fabricSplice "addKLOperator" $nodeName `format -stringArg $i "{\"opName\": \"slow^1s\"}"` `format -stringArg $i "require Math;\noperator slow^1s(\n  in Vec3 i1,\n  in Vec3 i2,\n  io Vec3 o\n  )\n{\n  UInt64 ticks = getCurrentTicks();\n  o = Vec3();\n  for ( Index n = 0; n < (1<<20); ++n )\n    o += +2e-8 * (i1 + i2);\n  report(\"op:slow^1s:tid=\" + getHardwareThreadID() + \":\" + getSecondsBetweenTicks(ticks, getCurrentTicks()) + \"ms\");\n}"`;
}
print `format -stringArg "combiningSpliceNode" "Building node ^1s"`;
fabricSplice "addOutputPort" "combiningSpliceNode" "{\"portName\": \"o\", \"dataType\" : \"Vec3\", \"arrayType\": \"Single Value\", \"addMayaAttr\": true}";
spaceLocator -n "outputLocator" -p 0 0 0;
connectAttr -f "combiningSpliceNode.o" "outputLocator.translate";
$combinedKL = "require Math;\noperator combined(";
for ($i = 0; $i < $count; ++$i)
{
  $combinedKL = `format -stringArg $combinedKL -stringArg $i "^1s\n  in Vec3 i^2s,"`;
}
$combinedKL = `format -stringArg $combinedKL "^1s\n  io Vec3 o\n  )\n{\n  UInt64 ticks = getCurrentTicks();\n  o = Vec3();"`;
for ($i = 0; $i < $count; ++$i)
{
  $combinedKL = `format -stringArg $combinedKL -stringArg $i "^1s\n  o += i^2s;"`;
}
$combinedKL = `format -stringArg $combinedKL "^1s\n  report(\"op:combined:tid=\" + getHardwareThreadID() + \":\" + getSecondsBetweenTicks(ticks, getCurrentTicks()) + \"ms\");\n}"`;
fabricSplice "addKLOperator" "combiningSpliceNode" "{\"opName\": \"combined\"}" $combinedKL;
currentTime 1;
select -r "inputLocator1";
move -r -10 0 -10;
setKeyframe "inputLocator1.translate";
select -r "inputLocator2";
move -r 3 0 -3;
setKeyframe "inputLocator2.translate";
currentTime 120;
select -r "inputLocator1";
move -r -10 0 10;
setKeyframe "inputLocator1.translate";
select -r "inputLocator2";
move -r -7 0 7;
setKeyframe "inputLocator2.translate";
currentTime 1;
select -r "inputLocator1";

共有実行を標準で有効にする

Maya 2016では、2つの環境変数 FABRIC_CANVAS_PARALLEL_DEFAULTFABRIC_SPLICE_PARALLEL_DEFAULT によって、標準でFabricノードの共有実行を有効にできます。

警告

これらの変数は、非常によくコントロールされた状況下でのみ使用されるべきです。そうであるなら、全てのユーザーが作成したFabricノードが互いに並列に実行されるでしょう。もしこれらのノードが、(たとえ直接的でなくても)共通の共有リソースに書き込みをおこなったら、おそらくクラッシュを引き起こすでしょう。