getavalon / core

The safe post-production pipeline - https://getavalon.github.io/2.0
MIT License
218 stars 48 forks source link

Gaffer Integration #404

Open BigRoy opened 5 years ago

BigRoy commented 5 years ago

Issue

I'm looking to integrate Gaffer for the Avalon pipeline. For this integration I've started a draft Gaffer branch however I thought it would be best to open a Gaffer issue to discuss how to best perform the integration because Gaffer has some small differences as to how we integrated most other hosts avalon supports.

gaffer_avalon_menu

A screenshot from the running prototype

Problem 1: Getting the root, script or application variable from Gaffer into Avalon tools

To run scripts again a currently open script (work scene) in Gaffer you need to have a handle to what "parent" script/application/root you want to operate against. Without that it's non-trivial to find which is the Gaffer scene you want to run against.

Initially I thought to store this handle in avalon.gaffer so that whatever runs the script could store it:

# Pseudocode (we don't likely need to actually store *all* of these)
avalon.gaffer.root = root
avalon.gaffer.script= script
avalon.gaffer.application = application

Then any Loader or Pyblish plug-in could just do:

root = avalon.gaffer.root
# continue Python scripts as per Gaffer documentation
# ...

However, this would only store one root whereas Gaffer can have multiple open scripts within a single process. (Definitely follow the links John shared in that linked comment, as it describes it in more detail and replies to people asking about similar issues as this. - See quotes below)

John Haddon (core Gaffer developer) states:

I can't recommend setting up a global variable for the script, because there's no guarantee it's the one the user is thinking of. The correct approach is pass the script to your function as an argument, having determined which script to act on from the UI context. - John Haddon

AND

There's a fundamental difference between Gaffer and Nuke, in that a single Gaffer process can have multiple scripts open, whereas (correct me if I'm wrong) a single Nuke process can only have a single script open. This is why there can be no equivalent to nuke.root(). Allowing multiple scripts in a single process has a few benefits, perhaps the most notable being that they can all share the same in-memory caches.

If you're in the mindset of developing for others apps, this can take some getting used to. Typically its a case of taking into account the UI context in which the user is performing an action - John Haddon

So the interface/tool/plug-ins should get to know which one to address, and it should be just passed along to that interface to know "use this handle".

Problem 2: Set up installation for Pyblish-QML so it communicates without crashing

It is possible to launch Pyblish-QML from Gaffer without a conflict in Python processes by specificying the PYBLISH_QML_PYTHON_EXECUTABLE explicitly. With that Pyblish QML is able to start up, however still unable to communicate with Gaffer without crashing. As such, it directly locks up QML and crashes:

QObject::killTimer: Timers cannot be stopped from another thread
QObject::~QObject: Timers cannot be stopped from another thread

For that we'll need to build an install method for Pyblish QML as it also has for other hosts. However, that will likely afterwards run into Problem 1 too since the Pyblish plug-ins should be able to identify which Gaffer script/application to run against. As such, Problem 1 is the more pressing issue.


How to play around with the draft Gaffer <-> Avalon integration?

If you want to get started playing around with the current draft branch you could do so, but note that it doesn't do a lot functionality wise. See setup/gaffer/README.md for some details on how to use the current draft.


Reference:

BigRoy commented 5 years ago

Just wanted to add this link to the discussion as it shows another potential trick from an old thread. Not sure if that still works. Also it's probably not the recommended way, but it might lead to other ideas.

Also as a reminder to myself. ;)