// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-FileCopyrightText: Copyright 2003 Sandia Corporation // SPDX-License-Identifier: LicenseRef-BSD-3-Clause-Sandia-USGov /** * @class vtkParallelRenderManager * @brief An object to control parallel rendering. * * * vtkParallelRenderManager operates in multiple processes. It provides * proper renderers and render windows for performing the parallel * rendering correctly. It can also attach itself to render windows and * propagate rendering events and camera views. * * @attention * Many parallel rendering schemes do not correctly handle transparency. * Unless otherwise documented, assume a sub class does not. * * @todo * Synchronization/barrier primitives. * * @todo * Query ranges of scalar values of objects in addition to the boundary in * three-space * */ #ifndef vtkParallelRenderManager_h #define vtkParallelRenderManager_h #include "vtkObject.h" #include "vtkRenderingParallelModule.h" // For export macro VTK_ABI_NAMESPACE_BEGIN class vtkDoubleArray; class vtkMultiProcessController; class vtkMultiProcessStream; class vtkRenderer; class vtkRendererCollection; class vtkRenderWindow; class vtkTimerLog; class vtkUnsignedCharArray; class VTKRENDERINGPARALLEL_EXPORT vtkParallelRenderManager : public vtkObject { public: vtkTypeMacro(vtkParallelRenderManager, vtkObject); void PrintSelf(ostream& os, vtkIndent indent) override; /** * Builds a vtkRenderWindow compatible with this render manager. The * user program is responsible for registering the render window with the * SetRenderWindow method and calling Delete. It is not advisable to use * a parallel render manager with a render window that was not built with * this method. */ virtual vtkRenderWindow* MakeRenderWindow(); /** * Builds a vtkRenderer compatible with this render manager. (Should we * also register it?) The user program is responsible for calling * Delete. It is not advisable to use a parallel render manager with a * renderer that was not built with this method. */ virtual vtkRenderer* MakeRenderer(); ///@{ /** * Set/Get the RenderWindow to use for compositing. * We add a start and end observer to the window. */ vtkGetObjectMacro(RenderWindow, vtkRenderWindow); virtual void SetRenderWindow(vtkRenderWindow* renWin); ///@} ///@{ /** * Set/Get the vtkMultiProcessController which will handle communications * for the parallel rendering. */ vtkGetObjectMacro(Controller, vtkMultiProcessController); virtual void SetController(vtkMultiProcessController* controller); ///@} /** * This method sets the piece and number of pieces for each * actor with a polydata mapper. */ virtual void InitializePieces(); /** * Make all rendering windows not viewable set as off screen rendering. * To make all renderwindows on screen rendering again, call * OffScreenRenderingOff on all the render windows. This class assumes * the window on root node is the only one viewable. Subclasses should * change this as necessary. */ virtual void InitializeOffScreen(); /** * Initializes the RMIs and then, if on root node, starts the interactor * on the attached render window. Otherwise, starts processing RMIs. * When the interactor returns, it breaks the RMI listening on all other * processors. */ virtual void StartInteractor(); /** * If on node other than root, starts serving RMI requests for parallel * renders. */ virtual void StartServices(); /** * If on root node, stops the RMI processing on all service nodes. */ virtual void StopServices(); ///@{ /** * Callbacks that initialize and finish rendering and other tasks. */ virtual void StartRender(); virtual void EndRender(); virtual void SatelliteStartRender(); virtual void SatelliteEndRender(); virtual void RenderRMI(); virtual void ResetCamera(vtkRenderer* ren); virtual void ResetCameraClippingRange(vtkRenderer* ren); virtual void ComputeVisiblePropBoundsRMI(int renderId); ///@} virtual void InitializeRMIs(); /** * Resets the camera of each renderer contained in the RenderWindow. * Should only be called in the "root" process, and all remote processes * must be processing RMIs for this method to complete. */ virtual void ResetAllCameras(); /** * Calculates the bounds by gathering information from all processes. */ virtual void ComputeVisiblePropBounds(vtkRenderer* ren, double bounds[6]); ///@{ /** * Turns on/off parallel rendering. When on (the default) the object * responds to render events of the attached window, propagates the * render event to other processors, and otherwise enables the parallel * rendering process. */ vtkSetMacro(ParallelRendering, int); vtkGetMacro(ParallelRendering, int); vtkBooleanMacro(ParallelRendering, int); ///@} ///@{ /** * Turns on/off render event propagation. When on (the default) and * ParallelRendering is on, process 0 will send an RMI call to all remote * processes to perform a synchronized render. When off, render must be * manually called on each process. */ vtkSetMacro(RenderEventPropagation, int); vtkGetMacro(RenderEventPropagation, int); vtkBooleanMacro(RenderEventPropagation, int); ///@} /** * Get/Set the default value used for RenderEventPropagation when a new * instance of vtkParallelRenderManager is created. * Set to true by default. */ static void SetDefaultRenderEventPropagation(bool val) { vtkParallelRenderManager::DefaultRenderEventPropagation = val; } static bool GetDefaultRenderEventPropagation() { return vtkParallelRenderManager::DefaultRenderEventPropagation; } ///@{ /** * This is used for tiled display rendering. When data has been * duplicated on all processes, then we do not need to compositing. * Cameras and renders are still propagated though. */ vtkSetMacro(UseCompositing, int); vtkGetMacro(UseCompositing, int); vtkBooleanMacro(UseCompositing, int); ///@} ///@{ /** * Set/Get the reduction factor (for sort-last based parallel renderers). * The size of rendered image is divided by the reduction factor and then * is blown up to the size of the current vtkRenderWindow. Setting * higher reduction factors enables shorter image transfer times (which * is often the bottleneck) but will greatly reduce image quality. A * reduction factor of 2 or greater should only be used for intermediate * images in interactive applications. A reduction factor of 1 (or less) * will result in no change in image quality. A parallel render manager * may ignore the image reduction factor if it will result in little or * no performance enhancements (eg. it does not do image space * manipulations). */ virtual void SetImageReductionFactor(double factor); vtkGetMacro(ImageReductionFactor, double); ///@} vtkSetMacro(MaxImageReductionFactor, double); vtkGetMacro(MaxImageReductionFactor, double); /** * Sets the ReductionFactor based on the given desired update rate and * the rendering metrics taken from the last time UpdateServerInfo was * called. Note that if AutoReductionFactor is on, this function is called * with the desired update rate of the render window automatically. */ virtual void SetImageReductionFactorForUpdateRate(double DesiredUpdateRate); ///@{ /** * If on, the ReductionFactor is automatically adjusted to best meet the * the DesiredUpdateRate in the current RenderWindow based on metrics * from the last render. */ vtkSetMacro(AutoImageReductionFactor, int); vtkGetMacro(AutoImageReductionFactor, int); vtkBooleanMacro(AutoImageReductionFactor, int); ///@} ///@{ /** * Get rendering metrics. */ vtkGetMacro(RenderTime, double); vtkGetMacro(ImageProcessingTime, double); ///@} ///@{ /** * By default, the state of all renderers in the root's render window is * propagated to the rest of the processes. In order for this to work, all * render windows must have the same renderers in the same order. If this is * not the case, you can turn off the SyncRenderWindowRenderers. When this * flag is off, the list of renderers held by this parallel render manager * (initially empty) is synced. You can modify the list of renderers with the * AddRenderer, RemoveRenderer, and RemoveAllRenderers methods. */ vtkGetMacro(SyncRenderWindowRenderers, int); vtkSetMacro(SyncRenderWindowRenderers, int); vtkBooleanMacro(SyncRenderWindowRenderers, int); virtual void AddRenderer(vtkRenderer*); virtual void RemoveRenderer(vtkRenderer*); virtual void RemoveAllRenderers(); ///@} ///@{ /** * If on (the default), the result of any image space manipulations are * written back to the render window frame buffer. If off, the image * stored in the frame buffer may not be correct. Either way, the * correct frame buffer images may be read with * vtkParallelRenderManager::GetPixelData. Turning WriteBackImages off * may result in a speedup if the render window is not visible to the user * and images are read back for further processing or transit. */ vtkSetMacro(WriteBackImages, int); vtkGetMacro(WriteBackImages, int); vtkBooleanMacro(WriteBackImages, int); ///@} ///@{ /** * If on (the default), when the ImageReductionFactor is greater than 1 * and WriteBackImages is on, the image will be magnified to fill the * entire render window. */ vtkSetMacro(MagnifyImages, int); vtkGetMacro(MagnifyImages, int); vtkBooleanMacro(MagnifyImages, int); ///@} enum { NEAREST, LINEAR }; ///@{ /** * Sets the method used to magnify images. Nearest simply replicates * each pixel enough times to fill the image. Linear performs linear * interpolation between the pixels. */ virtual void SetMagnifyImageMethod(int method); vtkGetMacro(MagnifyImageMethod, int); void SetMagnifyImageMethodToNearest() { this->SetMagnifyImageMethod(NEAREST); } void SetMagnifyImageMethodToLinear() { this->SetMagnifyImageMethod(LINEAR); } ///@} ///@{ /** * Convenience functions for magnifying images. */ virtual void MagnifyImage(vtkUnsignedCharArray* fullImage, const int fullImageSize[2], vtkUnsignedCharArray* reducedImage, const int reducedImageSize[2], const int fullImageViewport[4] = nullptr, const int reducedImageViewport[4] = nullptr); static void MagnifyImageNearest(vtkUnsignedCharArray* fullImage, const int fullImageSize[2], vtkUnsignedCharArray* reducedImage, const int reducedImageSize[2], const int fullImageViewport[4] = nullptr, const int reducedImageViewport[4] = nullptr); static void MagnifyImageLinear(vtkUnsignedCharArray* fullImage, const int fullImageSize[2], vtkUnsignedCharArray* reducedImage, const int reducedImageSize[2], const int fullImageViewport[4] = nullptr, const int reducedImageViewport[4] = nullptr); ///@} ///@{ /** * The most appropriate way to retrieve full size image data after a * render. Will work regardless of whether WriteBackImages or * MagnifyImage is on or off. The data returned may be a shallow copy of * an internal array. Therefore, the data may be invalid after the next * render or if the ParallelRenderManager is destroyed. */ virtual void GetPixelData(vtkUnsignedCharArray* data); virtual void GetPixelData(int x1, int y1, int x2, int y2, vtkUnsignedCharArray* data); ///@} ///@{ /** * The most appropriate way to retrieve reduced size image data after a * render. Will work regardless of whether WriteBackImages or * MagnifyImage is on or off. The data returned may be a shallow copy of * an internal array. Therefore, the data may be invalid after the next * render or if the ParallelRenderManager is destroyed. */ virtual void GetReducedPixelData(vtkUnsignedCharArray* data); virtual void GetReducedPixelData(int x1, int y1, int x2, int y2, vtkUnsignedCharArray* data); ///@} ///@{ /** * Returns the full image size calculated at the last render. */ vtkGetVector2Macro(FullImageSize, int); ///@} ///@{ /** * Returns the reduced image size calculated at the last render. */ vtkGetVector2Macro(ReducedImageSize, int); ///@} /** * Given the x and y size of the render windows, reposition them * in a tile of n columns. */ void TileWindows(int xsize, int ysize, int nColumns); ///@{ /** * Get/Set if all Images must use RGBA instead of RGB. By default, * this flag is on. */ vtkSetMacro(UseRGBA, int); vtkGetMacro(UseRGBA, int); ///@} ///@{ /** * If ForceRenderWindowSize is set to true, the render manager will use * the RenderWindowSize ivar instead of getting the size from the render window. */ vtkSetMacro(ForceRenderWindowSize, int); vtkGetMacro(ForceRenderWindowSize, int); ///@} ///@{ /** * If ForceRenderWindowSize is set to true, the render manager will use * the Size ivar instead of getting the size from the render window. */ vtkSetVector2Macro(ForcedRenderWindowSize, int); vtkGetVector2Macro(ForcedRenderWindowSize, int); ///@} enum Tags { RENDER_RMI_TAG = 34532, COMPUTE_VISIBLE_PROP_BOUNDS_RMI_TAG = 54636, WIN_INFO_TAG = 87834, REN_INFO_TAG = 87836, LIGHT_INFO_TAG = 87838, REN_ID_TAG = 58794, BOUNDS_TAG = 23543 }; virtual void CheckForAbortRender() {} virtual int CheckForAbortComposite() { return 0; } ///@{ /** * The default is to allow the use of the back buffer for compositing. * If set to false, this will prevent to manager from swapping buffers. * This allows something else (for instance VisibleCellSelection) to * control front/back buffer swapping. */ vtkSetMacro(UseBackBuffer, int); vtkGetMacro(UseBackBuffer, int); vtkBooleanMacro(UseBackBuffer, int); ///@} ///@{ /** * When set the render manager will synchronize the TileViewport and TileScale * properties. This may not be desirable in cases where there's some other * mechanism to set the tile dimensions eg. Tile displays. */ vtkSetMacro(SynchronizeTileProperties, int); vtkGetMacro(SynchronizeTileProperties, int); vtkBooleanMacro(SynchronizeTileProperties, int); ///@} ///@{ /** * INTERNAL METHODS (DON NOT USE). * There are internal methods made public so that they can be called from * callback functions. */ virtual void GenericStartRenderCallback(); virtual void GenericEndRenderCallback(); ///@} protected: vtkParallelRenderManager(); ~vtkParallelRenderManager() override; ///@{ /** * Add/Remove event handlers for the render window. */ void AddRenderWindowEventHandlers(); void RemoveRenderWindowEventHandlers(); ///@} vtkRenderWindow* RenderWindow; vtkMultiProcessController* Controller; vtkRendererCollection* Renderers; virtual vtkRendererCollection* GetRenderers(); int ForceRenderWindowSize; int ForcedRenderWindowSize[2]; /** * The "root" node's process id. This is the node which is listening for * and propagating new render events from the RenderWindow. All * processes on the controller must have the same value. This value must * be set before SetRenderWindow method is called. In the constructor or * the SetController methods are good places. By default this is set to * 0. */ int RootProcessId; int ObservingRenderWindow; int ObservingAbort; unsigned long StartRenderTag; unsigned long EndRenderTag; unsigned long ResetCameraTag; unsigned long ResetCameraClippingRangeTag; unsigned long AbortRenderCheckTag; double ImageReductionFactor; double MaxImageReductionFactor; int AutoImageReductionFactor; int WriteBackImages; int MagnifyImages; int MagnifyImageMethod; int UseRGBA; int SynchronizeTileProperties; int FullImageSize[2]; int ReducedImageSize[2]; vtkUnsignedCharArray* FullImage; vtkUnsignedCharArray* ReducedImage; int FullImageUpToDate; int ReducedImageUpToDate; int RenderWindowImageUpToDate; vtkDoubleArray* Viewports; int Lock; int ParallelRendering; int RenderEventPropagation; int UseCompositing; int SyncRenderWindowRenderers; vtkTimerLog* Timer; double RenderTime; double ImageProcessingTime; /** * Used by SetImageReductionFactorForUpdateRate to smooth transitions * transitions between image reduction factors. */ double AverageTimePerPixel; /** * Used to synchronize rendering information per frame. * These are old methods provided for backward compatibility. One should look * at using CollectWindowInformation(), ProcessWindowInformation() etc. for * buffered sending of information over. */ virtual void SendWindowInformation() {} virtual void ReceiveWindowInformation() {} virtual void SendRendererInformation(vtkRenderer*) {} virtual void ReceiveRendererInformation(vtkRenderer*) {} /** * Subclass should override these methods (instead of * SendWindowInformation/ReceiveWindowInformation or * SendRendererInformation/ReceiveRendererInformation) to collect or process * meta-data to synchronize rendering information per frame. * Subclass should not use the Controller directly to send receive messages * in any of these methods otherwise deadlocks may ensue. */ virtual void CollectWindowInformation(vtkMultiProcessStream&) {} virtual bool ProcessWindowInformation(vtkMultiProcessStream&) { return true; } virtual void CollectRendererInformation(vtkRenderer*, vtkMultiProcessStream&) {} virtual bool ProcessRendererInformation(vtkRenderer*, vtkMultiProcessStream&) { return true; } ///@{ /** * Here is a good place to handle processing of data before and after * render. */ virtual void PreRenderProcessing() = 0; virtual void PostRenderProcessing() = 0; ///@} /** * Called in satellites to set the render window size to the current * FullImageSize and ReducedImageSize (or vice versa). */ virtual void SetRenderWindowSize(); /** * Called by ComputeVisiblePropBoundsRMI to get the bounds of a local * renderer. Override this method if the true bounds are different than * those reported by the renderer. */ virtual void LocalComputeVisiblePropBounds(vtkRenderer* ren, double bounds[6]); /** * When called, fills FullImage. */ virtual void MagnifyReducedImage(); /** * Write the full image back to the RenderWindow. */ virtual void WriteFullImage(); /** * Reads in the reduced image from the RenderWindow. */ virtual void ReadReducedImage(); /** * Returns 1 if the RenderWindow's last image is in the front buffer, 0 * if it is in the back. */ virtual int LastRenderInFrontBuffer(); /** * Select buffer to read from / render into. */ virtual int ChooseBuffer(); /** * Sets the current render window's pixel data. */ virtual void SetRenderWindowPixelData(vtkUnsignedCharArray* pixels, const int pixelDimensions[2]); /** * Returns true if the image for the given renderer should be rendered at a * reduced size to be magnified later. This method always returns true, but * subclasses may render some renderers at a reduced size, magnify them, and * then render the other renderers at full resolution. */ virtual int ImageReduceRenderer(vtkRenderer*) { return 1; } struct RenderWindowInfo { int FullSize[2]; int ReducedSize[2]; int NumberOfRenderers; int UseCompositing; int TileScale[2]; double ImageReductionFactor; double DesiredUpdateRate; double TileViewport[4]; // Initialize members RenderWindowInfo() = default; // Save/restore the struct to/from a stream. void Save(vtkMultiProcessStream& stream); bool Restore(vtkMultiProcessStream& stream); }; struct RendererInfo { int Draw = 0; int NumberOfLights = 0; double Viewport[4] = { 0., 0., 0., 0. }; double CameraPosition[3] = { 0., 0., 0. }; double CameraFocalPoint[3] = { 0., 0., 0. }; double CameraViewUp[3] = { 0., 0., 0. }; double WindowCenter[2] = { 0., 0. }; double CameraClippingRange[2] = { 0., 0. }; double CameraViewAngle = 0.; double Background[3] = { 0., 0., 0. }; double Background2[3] = { 0., 0., 0. }; bool GradientBackground = false; double ParallelScale = 0.; // Initialize members RendererInfo() = default; // Save/restore the struct to/from a stream. void Save(vtkMultiProcessStream& stream); bool Restore(vtkMultiProcessStream& stream); }; struct LightInfo { double Position[3]; double FocalPoint[3]; double Type; // Initialize members LightInfo() = default; // Save/restore the struct to/from a stream. void Save(vtkMultiProcessStream& stream); bool Restore(vtkMultiProcessStream& stream); }; int AddedRMIs; unsigned long RenderRMIId; unsigned long BoundsRMIId; int UseBackBuffer; static bool DefaultRenderEventPropagation; private: vtkParallelRenderManager(const vtkParallelRenderManager&) = delete; void operator=(const vtkParallelRenderManager&) = delete; }; VTK_ABI_NAMESPACE_END #endif // vtkParalleRenderManager_h