From a6e81d7057162ea1211a00d086daf1a2817406d0 Mon Sep 17 00:00:00 2001 From: John Haddon Date: Sat, 4 Nov 2023 11:11:42 +0000 Subject: [PATCH 1/3] TaskList : Reimplement in C++ So we don't pay the ridiculous overhead of going into Python to basically do nothing when we get there. --- Changes.md | 1 + include/GafferDispatch/TaskList.h | 71 +++++++++++++++++ include/GafferDispatch/TypeIds.h | 1 + python/GafferDispatch/TaskList.py | 62 --------------- python/GafferDispatch/__init__.py | 1 - python/GafferDispatchTest/TaskListTest.py | 18 +++-- src/GafferDispatch/TaskList.cpp | 80 ++++++++++++++++++++ src/GafferDispatchModule/TaskNodeBinding.cpp | 61 ++++++++------- 8 files changed, 198 insertions(+), 97 deletions(-) create mode 100644 include/GafferDispatch/TaskList.h delete mode 100644 python/GafferDispatch/TaskList.py create mode 100644 src/GafferDispatch/TaskList.cpp diff --git a/Changes.md b/Changes.md index 76164812705..1628344e208 100644 --- a/Changes.md +++ b/Changes.md @@ -6,6 +6,7 @@ Improvements - Toolbars : Changed hotkey behavior to toogle any tool on and off. Exclusive tools such as the Translate and Crop Window tools activate the first tool (currently Selection Tool) when they are toggled off. - CropWindowTool : Added `Alt` + `C` for toggling both the crop window tool and the relevant crop window `enabled` plug. +- TaskList : Reimplemented in C++ for improved performance. Breaking Changes ---------------- diff --git a/include/GafferDispatch/TaskList.h b/include/GafferDispatch/TaskList.h new file mode 100644 index 00000000000..65957d2ba66 --- /dev/null +++ b/include/GafferDispatch/TaskList.h @@ -0,0 +1,71 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2023, John Haddon. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above +// copyright notice, this list of conditions and the following +// disclaimer. +// +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided with +// the distribution. +// +// * Neither the name of John Haddon nor the names of +// any other contributors to this software may be used to endorse or +// promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "GafferDispatch/TaskNode.h" + +namespace GafferDispatch +{ + +class GAFFERDISPATCH_API TaskList : public TaskNode +{ + + public : + + GAFFER_NODE_DECLARE_TYPE( GafferDispatch::TaskList, TaskListTypeId, TaskNode ); + + explicit TaskList( const std::string &name=defaultName() ); + ~TaskList() override; + + Gaffer::BoolPlug *sequencePlug(); + const Gaffer::BoolPlug *sequencePlug() const; + + protected : + + IECore::MurmurHash hash( const Gaffer::Context *context ) const override; + void execute() const override; + bool requiresSequenceExecution() const override; + + private : + + static size_t g_firstPlugIndex; + + // Friendship for the bindings + friend struct GafferDispatchBindings::Detail::TaskNodeAccessor; +}; + +} // namespace GafferDispatch diff --git a/include/GafferDispatch/TypeIds.h b/include/GafferDispatch/TypeIds.h index d804276e8d2..d2f3816a03a 100644 --- a/include/GafferDispatch/TypeIds.h +++ b/include/GafferDispatch/TypeIds.h @@ -45,6 +45,7 @@ enum TypeId TaskNodeTypeId = 110160, TaskNodeTaskPlugTypeId = 110161, DispatcherTypeId = 110162, + TaskListTypeId = 110163, LastTypeId = 110180, diff --git a/python/GafferDispatch/TaskList.py b/python/GafferDispatch/TaskList.py deleted file mode 100644 index 744acb1cebc..00000000000 --- a/python/GafferDispatch/TaskList.py +++ /dev/null @@ -1,62 +0,0 @@ -########################################################################## -# -# Copyright (c) 2014, Image Engine Design Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above -# copyright notice, this list of conditions and the following -# disclaimer. -# -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided with -# the distribution. -# -# * Neither the name of John Haddon nor the names of -# any other contributors to this software may be used to endorse or -# promote products derived from this software without specific prior -# written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -########################################################################## - -import IECore - -import Gaffer -import GafferDispatch - -# Used to collect tasks for dispatching all at once -class TaskList( GafferDispatch.TaskNode ) : - - def __init__( self, name = "TaskList" ) : - - GafferDispatch.TaskNode.__init__( self, name ) - self["sequence"] = Gaffer.BoolPlug() - - def requiresSequenceExecution( self ) : - - return self["sequence"].getValue() - - def hash( self, context ) : - - return IECore.MurmurHash() - - def execute( self ) : - - pass - -IECore.registerRunTimeTyped( TaskList, typeName = "GafferDispatch::TaskList" ) diff --git a/python/GafferDispatch/__init__.py b/python/GafferDispatch/__init__.py index 7d71de00696..0f9e4cf1379 100644 --- a/python/GafferDispatch/__init__.py +++ b/python/GafferDispatch/__init__.py @@ -39,7 +39,6 @@ from ._GafferDispatch import * from .LocalDispatcher import LocalDispatcher from .SystemCommand import SystemCommand -from .TaskList import TaskList from .TaskContextProcessor import TaskContextProcessor from .Wedge import Wedge from .TaskContextVariables import TaskContextVariables diff --git a/python/GafferDispatchTest/TaskListTest.py b/python/GafferDispatchTest/TaskListTest.py index 9b859013f48..ef302190e1c 100644 --- a/python/GafferDispatchTest/TaskListTest.py +++ b/python/GafferDispatchTest/TaskListTest.py @@ -49,18 +49,24 @@ def test( self ) : n = GafferDispatch.TaskList() with Gaffer.Context() as c : - h1 = n["task"].hash() + self.assertEqual( n["task"].hash(), IECore.MurmurHash() ) c["frame"] = 10.0 - h2 = n["task"].hash() - - self.assertEqual( h1, h2 ) + self.assertEqual( n["task"].hash(), IECore.MurmurHash() ) n2 = GafferDispatch.TaskList( "TaskList2" ) with Gaffer.Context() as c : - self.assertEqual( n2["task"].hash(), h1 ) + self.assertEqual( n2["task"].hash(), IECore.MurmurHash() ) c["frame"] = 10.0 - self.assertEqual( n2["task"].hash(), h2 ) + self.assertEqual( n2["task"].hash(), IECore.MurmurHash() ) + + def testSequenceExecution( self ) : + + n = GafferDispatch.TaskList() + self.assertFalse( n["task"].requiresSequenceExecution() ) + + n["sequence"].setValue( True ) + self.assertTrue( n["task"].requiresSequenceExecution() ) if __name__ == "__main__": unittest.main() diff --git a/src/GafferDispatch/TaskList.cpp b/src/GafferDispatch/TaskList.cpp new file mode 100644 index 00000000000..f66be2d2c05 --- /dev/null +++ b/src/GafferDispatch/TaskList.cpp @@ -0,0 +1,80 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2023 John Haddon. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above +// copyright notice, this list of conditions and the following +// disclaimer. +// +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided with +// the distribution. +// +// * Neither the name of John Haddon nor the names of +// any other contributors to this software may be used to endorse or +// promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////// + +#include "GafferDispatch/TaskList.h" + +using namespace IECore; +using namespace Gaffer; +using namespace GafferDispatch; + +GAFFER_NODE_DEFINE_TYPE( TaskList ) + +size_t TaskList::g_firstPlugIndex; + +TaskList::TaskList( const std::string &name ) + : TaskNode( name ) +{ + storeIndexOfNextChild( g_firstPlugIndex ); + addChild( new BoolPlug( "sequence" ) ); +} + +TaskList::~TaskList() +{ +} + +Gaffer::BoolPlug *TaskList::sequencePlug() +{ + return getChild( g_firstPlugIndex ); +} + +const Gaffer::BoolPlug *TaskList::sequencePlug() const +{ + return getChild( g_firstPlugIndex ); +} + +IECore::MurmurHash TaskList::hash( const Context *context ) const +{ + return MurmurHash(); +} + +void TaskList::execute() const +{ +} + +bool TaskList::requiresSequenceExecution() const +{ + return sequencePlug()->getValue(); +} diff --git a/src/GafferDispatchModule/TaskNodeBinding.cpp b/src/GafferDispatchModule/TaskNodeBinding.cpp index e519194950a..17c48a50840 100644 --- a/src/GafferDispatchModule/TaskNodeBinding.cpp +++ b/src/GafferDispatchModule/TaskNodeBinding.cpp @@ -41,6 +41,7 @@ #include "GafferDispatchBindings/TaskNodeBinding.h" +#include "GafferDispatch/TaskList.h" #include "GafferDispatch/TaskNode.h" #include "GafferBindings/PlugBinding.h" @@ -135,35 +136,39 @@ void GafferDispatchModule::bindTaskNode() { using Wrapper = TaskNodeWrapper; - scope s = TaskNodeClass(); - - class_( "Task", no_init ) - .def( init() ) - .def( init() ) - .def( init() ) - .def( "plug", &taskPlug ) - .def( "context", &taskContext, ( boost::python::arg_( "_copy" ) = true ) ) - .def("__eq__", &TaskNode::Task::operator== ) - ; - - PlugClass() - .def( init( - ( - boost::python::arg_( "name" )=GraphComponent::defaultName(), - boost::python::arg_( "direction" )=Plug::In, - boost::python::arg_( "flags" )=Plug::Default + { + scope s = TaskNodeClass(); + + class_( "Task", no_init ) + .def( init() ) + .def( init() ) + .def( init() ) + .def( "plug", &taskPlug ) + .def( "context", &taskContext, ( boost::python::arg_( "_copy" ) = true ) ) + .def("__eq__", &TaskNode::Task::operator== ) + ; + + PlugClass() + .def( init( + ( + boost::python::arg_( "name" )=GraphComponent::defaultName(), + boost::python::arg_( "direction" )=Plug::In, + boost::python::arg_( "flags" )=Plug::Default + ) ) ) - ) - .def( "hash", &taskPlugHash ) - .def( "execute", &taskPlugExecute ) - .def( "executeSequence", &taskPlugExecuteSequence ) - .def( "requiresSequenceExecution", &TaskNode::TaskPlug::requiresSequenceExecution ) - .def( "preTasks", &taskPlugPreTasks ) - .def( "postTasks", &taskPlugPostTasks ) - // Adjusting the name so that it correctly reflects - // the nesting, and can be used by the PlugSerialiser. - .attr( "__qualname__" ) = "TaskNode.TaskPlug" - ; + .def( "hash", &taskPlugHash ) + .def( "execute", &taskPlugExecute ) + .def( "executeSequence", &taskPlugExecuteSequence ) + .def( "requiresSequenceExecution", &TaskNode::TaskPlug::requiresSequenceExecution ) + .def( "preTasks", &taskPlugPreTasks ) + .def( "postTasks", &taskPlugPostTasks ) + // Adjusting the name so that it correctly reflects + // the nesting, and can be used by the PlugSerialiser. + .attr( "__qualname__" ) = "TaskNode.TaskPlug" + ; + } + + TaskNodeClass(); } From e07218dfedce6a1c0ff70ed5fdcc452fd311ea69 Mon Sep 17 00:00:00 2001 From: John Haddon Date: Sat, 4 Nov 2023 12:08:00 +0000 Subject: [PATCH 2/3] FrameMask : Reimplement in C++ --- Changes.md | 2 +- include/GafferDispatch/FrameMask.h | 73 ++++++++++++ include/GafferDispatch/TypeIds.h | 1 + python/GafferDispatch/FrameMask.py | 77 ------------ python/GafferDispatch/__init__.py | 1 - src/GafferDispatch/FrameMask.cpp | 118 +++++++++++++++++++ src/GafferDispatchModule/TaskNodeBinding.cpp | 2 + 7 files changed, 195 insertions(+), 79 deletions(-) create mode 100644 include/GafferDispatch/FrameMask.h delete mode 100644 python/GafferDispatch/FrameMask.py create mode 100644 src/GafferDispatch/FrameMask.cpp diff --git a/Changes.md b/Changes.md index 1628344e208..6e979493d86 100644 --- a/Changes.md +++ b/Changes.md @@ -6,7 +6,7 @@ Improvements - Toolbars : Changed hotkey behavior to toogle any tool on and off. Exclusive tools such as the Translate and Crop Window tools activate the first tool (currently Selection Tool) when they are toggled off. - CropWindowTool : Added `Alt` + `C` for toggling both the crop window tool and the relevant crop window `enabled` plug. -- TaskList : Reimplemented in C++ for improved performance. +- TaskList, FrameMask : Reimplemented in C++ for improved performance. Breaking Changes ---------------- diff --git a/include/GafferDispatch/FrameMask.h b/include/GafferDispatch/FrameMask.h new file mode 100644 index 00000000000..87bc1a7d7ce --- /dev/null +++ b/include/GafferDispatch/FrameMask.h @@ -0,0 +1,73 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2023, John Haddon. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above +// copyright notice, this list of conditions and the following +// disclaimer. +// +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided with +// the distribution. +// +// * Neither the name of John Haddon nor the names of +// any other contributors to this software may be used to endorse or +// promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "GafferDispatch/TaskNode.h" + +#include "Gaffer/StringPlug.h" + +namespace GafferDispatch +{ + +class GAFFERDISPATCH_API FrameMask : public TaskNode +{ + + public : + + GAFFER_NODE_DECLARE_TYPE( GafferDispatch::FrameMask, FrameMaskTypeId, TaskNode ); + + explicit FrameMask( const std::string &name=defaultName() ); + ~FrameMask() override; + + Gaffer::StringPlug *maskPlug(); + const Gaffer::StringPlug *maskPlug() const; + + protected : + + void preTasks( const Gaffer::Context *context, Tasks &tasks ) const override; + IECore::MurmurHash hash( const Gaffer::Context *context ) const override; + void execute() const override; + + private : + + static size_t g_firstPlugIndex; + + // Friendship for the bindings + friend struct GafferDispatchBindings::Detail::TaskNodeAccessor; +}; + +} // namespace GafferDispatch diff --git a/include/GafferDispatch/TypeIds.h b/include/GafferDispatch/TypeIds.h index d2f3816a03a..3f45b2ebce1 100644 --- a/include/GafferDispatch/TypeIds.h +++ b/include/GafferDispatch/TypeIds.h @@ -46,6 +46,7 @@ enum TypeId TaskNodeTaskPlugTypeId = 110161, DispatcherTypeId = 110162, TaskListTypeId = 110163, + FrameMaskTypeId = 110164, LastTypeId = 110180, diff --git a/python/GafferDispatch/FrameMask.py b/python/GafferDispatch/FrameMask.py deleted file mode 100644 index 9e25dd8aad5..00000000000 --- a/python/GafferDispatch/FrameMask.py +++ /dev/null @@ -1,77 +0,0 @@ -########################################################################## -# -# Copyright (c) 2018, Image Engine Design Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above -# copyright notice, this list of conditions and the following -# disclaimer. -# -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided with -# the distribution. -# -# * Neither the name of John Haddon nor the names of -# any other contributors to this software may be used to endorse or -# promote products derived from this software without specific prior -# written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -########################################################################## - -import IECore - -import Gaffer -import GafferDispatch - -class FrameMask( GafferDispatch.TaskNode ) : - - def __init__( self, name = "FrameMask" ) : - - GafferDispatch.TaskNode.__init__( self, name ) - self["mask"] = Gaffer.StringPlug() - - def preTasks( self, context ) : - - frames = _frameListCache.get( self["mask"].getValue() ) - if ( not frames ) or ( context.getFrame() in frames ) : - return GafferDispatch.TaskNode.preTasks( self, context ) - else : - return [] - - def hash( self, context ) : - - return IECore.MurmurHash() - - def execute( self ) : - - pass - -IECore.registerRunTimeTyped( FrameMask, typeName = "GafferDispatch::FrameMask" ) - -# We cache the results of `FrameList.asList()` as a set, to avoid regenerating -# it on every frame, and to avoid linear search in `FrameMask.preTasks()`. This -# gives substantial performance improvements when dispatching large frame -# ranges. -def __frameListCacheGetter( frameExpression ) : - - frames = IECore.FrameList.parse( frameExpression ).asList() - return set( frames ), len( frames ) - -# Enough for approximately an hour's worth of frames, at a cost of < 10Mb. -_frameListCache = IECore.LRUCache( __frameListCacheGetter, 100000 ) diff --git a/python/GafferDispatch/__init__.py b/python/GafferDispatch/__init__.py index 0f9e4cf1379..d12af6c5a03 100644 --- a/python/GafferDispatch/__init__.py +++ b/python/GafferDispatch/__init__.py @@ -44,6 +44,5 @@ from .TaskContextVariables import TaskContextVariables from .TaskSwitch import TaskSwitch from .PythonCommand import PythonCommand -from .FrameMask import FrameMask __import__( "IECore" ).loadConfig( "GAFFER_STARTUP_PATHS", subdirectory = "GafferDispatch" ) diff --git a/src/GafferDispatch/FrameMask.cpp b/src/GafferDispatch/FrameMask.cpp new file mode 100644 index 00000000000..c5bf24c3c8b --- /dev/null +++ b/src/GafferDispatch/FrameMask.cpp @@ -0,0 +1,118 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2023 John Haddon. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above +// copyright notice, this list of conditions and the following +// disclaimer. +// +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided with +// the distribution. +// +// * Neither the name of John Haddon nor the names of +// any other contributors to this software may be used to endorse or +// promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////// + +#include "GafferDispatch/FrameMask.h" + +#include "Gaffer/Private/IECorePreview/LRUCache.h" + +#include "IECore/FrameList.h" + +#include + +using namespace IECore; +using namespace Gaffer; +using namespace GafferDispatch; + +namespace +{ + +// We cache the results of `FrameList.asList()` as a set, to avoid regenerating +// it on every frame, and to avoid linear search in `FrameMask::preTasks()`. This +// gives substantial performance improvements when dispatching large frame +// ranges. + +using FrameSet = std::unordered_set; +using ConstFrameSetPtr = std::shared_ptr; + +IECorePreview::LRUCache g_frameListCache( + + [] ( const std::string &frameExpression, size_t &cost, const IECore::Canceller *canceller ) + { + std::vector frames; + FrameList::parse( frameExpression )->asList( frames ); + cost = frames.size(); + return std::make_shared( frames.begin(), frames.end() ); + }, + + // Enough for approximately an hour's worth of frames, at a cost of < 10Mb. + 100000 + +); + +} // namespace + +GAFFER_NODE_DEFINE_TYPE( FrameMask ) + +size_t FrameMask::g_firstPlugIndex; + +FrameMask::FrameMask( const std::string &name ) + : TaskNode( name ) +{ + storeIndexOfNextChild( g_firstPlugIndex ); + addChild( new StringPlug( "mask" ) ); +} + +FrameMask::~FrameMask() +{ +} + +Gaffer::StringPlug *FrameMask::maskPlug() +{ + return getChild( g_firstPlugIndex ); +} + +const Gaffer::StringPlug *FrameMask::maskPlug() const +{ + return getChild( g_firstPlugIndex ); +} + +void FrameMask::preTasks( const Gaffer::Context *context, Tasks &tasks ) const +{ + ConstFrameSetPtr frames = g_frameListCache.get( maskPlug()->getValue() ); + if( frames->empty() || frames->find( context->getFrame() ) != frames->end() ) + { + TaskNode::preTasks( context, tasks ); + } +} + +IECore::MurmurHash FrameMask::hash( const Context *context ) const +{ + return MurmurHash(); +} + +void FrameMask::execute() const +{ +} diff --git a/src/GafferDispatchModule/TaskNodeBinding.cpp b/src/GafferDispatchModule/TaskNodeBinding.cpp index 17c48a50840..5a6a5af9db6 100644 --- a/src/GafferDispatchModule/TaskNodeBinding.cpp +++ b/src/GafferDispatchModule/TaskNodeBinding.cpp @@ -41,6 +41,7 @@ #include "GafferDispatchBindings/TaskNodeBinding.h" +#include "GafferDispatch/FrameMask.h" #include "GafferDispatch/TaskList.h" #include "GafferDispatch/TaskNode.h" @@ -170,5 +171,6 @@ void GafferDispatchModule::bindTaskNode() } TaskNodeClass(); + TaskNodeClass(); } From d6d0c04f72938601c95f74b34145bc4ee1d9eef5 Mon Sep 17 00:00:00 2001 From: John Haddon Date: Sat, 4 Nov 2023 13:48:30 +0000 Subject: [PATCH 3/3] TaskList : Try to fix Windows build error --- src/GafferDispatch/TaskList.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GafferDispatch/TaskList.cpp b/src/GafferDispatch/TaskList.cpp index f66be2d2c05..ac4ee507158 100644 --- a/src/GafferDispatch/TaskList.cpp +++ b/src/GafferDispatch/TaskList.cpp @@ -36,6 +36,8 @@ #include "GafferDispatch/TaskList.h" +#include "Gaffer/Context.h" + using namespace IECore; using namespace Gaffer; using namespace GafferDispatch;