// 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 #include "vtkParallelRenderManager.h" #include "vtkActor.h" #include "vtkActorCollection.h" #include "vtkCallbackCommand.h" #include "vtkCamera.h" #include "vtkDoubleArray.h" #include "vtkLight.h" #include "vtkLightCollection.h" #include "vtkMath.h" #include "vtkMultiProcessController.h" #include "vtkMultiProcessStream.h" // needed for vtkMultiProcessStream. #include "vtkPolyDataMapper.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkRendererCollection.h" #include "vtkTimerLog.h" #include "vtkUnsignedCharArray.h" VTK_ABI_NAMESPACE_BEGIN static void AbortRenderCheck( vtkObject* caller, unsigned long vtkNotUsed(event), void* clientData, void*); static void GenericStartRender( vtkObject* caller, unsigned long vtkNotUsed(event), void* clientData, void*); static void GenericEndRender( vtkObject* caller, unsigned long vtkNotUsed(event), void* clientData, void*); /* static void ResetCamera(vtkObject *caller, unsigned long vtkNotUsed(event), void *clientData, void *); static void ResetCameraClippingRange(vtkObject *caller, unsigned long vtkNotUsed(event), void *clientData, void *); */ static void RenderRMI(void* arg, void*, int, int); static void ComputeVisiblePropBoundsRMI(void* arg, void*, int, int); bool vtkParallelRenderManager::DefaultRenderEventPropagation = true; //------------------------------------------------------------------------------ vtkParallelRenderManager::vtkParallelRenderManager() { this->RenderWindow = nullptr; this->ObservingRenderWindow = 0; this->ObservingAbort = 0; this->Controller = nullptr; this->SetController(vtkMultiProcessController::GetGlobalController()); this->RootProcessId = 0; this->Renderers = vtkRendererCollection::New(); this->SyncRenderWindowRenderers = 1; this->Lock = 0; this->ImageReductionFactor = 1; this->MaxImageReductionFactor = 16; this->AutoImageReductionFactor = 0; this->AverageTimePerPixel = 0.0; this->RenderTime = 0.0; this->ImageProcessingTime = 0.0; this->ParallelRendering = 1; this->WriteBackImages = 1; this->MagnifyImages = 1; this->MagnifyImageMethod = vtkParallelRenderManager::NEAREST; this->RenderEventPropagation = vtkParallelRenderManager::DefaultRenderEventPropagation ? 1 : 0; this->UseCompositing = 1; this->FullImage = vtkUnsignedCharArray::New(); this->ReducedImage = vtkUnsignedCharArray::New(); this->FullImageUpToDate = 0; this->ReducedImageUpToDate = 0; this->RenderWindowImageUpToDate = 0; this->FullImageSize[0] = 0; this->FullImageSize[1] = 0; this->ReducedImageSize[0] = 0; this->ReducedImageSize[1] = 0; this->ForceRenderWindowSize = 0; this->ForcedRenderWindowSize[0] = 0; this->ForcedRenderWindowSize[1] = 0; this->Viewports = vtkDoubleArray::New(); this->Viewports->SetNumberOfComponents(4); this->UseRGBA = 1; this->AddedRMIs = 0; this->RenderRMIId = 0; this->BoundsRMIId = 0; this->Timer = vtkTimerLog::New(); this->UseBackBuffer = 1; this->SynchronizeTileProperties = 1; } //------------------------------------------------------------------------------ vtkParallelRenderManager::~vtkParallelRenderManager() { this->SetRenderWindow(nullptr); if (this->Controller && this->AddedRMIs) { this->Controller->RemoveRMI(this->RenderRMIId); this->Controller->RemoveRMI(this->BoundsRMIId); this->AddedRMIs = 0; } this->SetController(nullptr); if (this->FullImage) this->FullImage->Delete(); if (this->ReducedImage) this->ReducedImage->Delete(); if (this->Viewports) this->Viewports->Delete(); if (this->Timer) this->Timer->Delete(); if (this->Renderers) this->Renderers->Delete(); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "ParallelRendering: " << (this->ParallelRendering ? "on" : "off") << endl; os << indent << "RenderEventPropagation: " << (this->RenderEventPropagation ? "on" : "off") << endl; os << indent << "UseCompositing: " << (this->UseCompositing ? "on" : "off") << endl; os << indent << "SyncRenderWindowRenderers: " << (this->SyncRenderWindowRenderers ? "on" : "off") << endl; os << indent << "ObservingRenderWindow: " << (this->ObservingRenderWindow ? "yes" : "no") << endl; os << indent << "Locked: " << (this->Lock ? "yes" : "no") << endl; os << indent << "ImageReductionFactor: " << this->ImageReductionFactor << endl; os << indent << "MaxImageReductionFactor: " << this->MaxImageReductionFactor << endl; os << indent << "AutoImageReductionFactor: " << (this->AutoImageReductionFactor ? "on" : "off") << endl; if (this->MagnifyImageMethod == vtkParallelRenderManager::LINEAR) { os << indent << "MagnifyImageMethod: LINEAR\n"; } else if (this->MagnifyImageMethod == vtkParallelRenderManager::NEAREST) { os << indent << "MagnifyImageMethod: NEAREST\n"; } os << indent << "WriteBackImages: " << (this->WriteBackImages ? "on" : "off") << endl; os << indent << "MagnifyImages: " << (this->MagnifyImages ? "on" : "off") << endl; os << indent << "FullImageSize: (" << this->FullImageSize[0] << ", " << this->FullImageSize[1] << ")" << endl; os << indent << "ReducedImageSize: (" << this->ReducedImageSize[0] << ", " << this->ReducedImageSize[1] << ")" << endl; os << indent << "RenderWindow: " << this->RenderWindow << endl; os << indent << "Controller: " << this->Controller << endl; os << indent << "Renderers: " << this->Renderers << endl; os << indent << "RootProcessId: " << this->RootProcessId << endl; os << indent << "Last render time: " << this->RenderTime << endl; os << indent << "Last image processing time: " << this->ImageProcessingTime << endl; os << indent << "UseRGBA: " << this->UseRGBA << endl; os << indent << "SynchronizeTileProperties: " << this->SynchronizeTileProperties << endl; os << indent << "FullImage: "; if (this->FullImage) { this->FullImage->PrintSelf(os, indent.GetNextIndent()); } else { os << "(none)" << endl; } os << indent << "ForcedRenderWindowSize: " << this->ForcedRenderWindowSize[0] << " " << this->ForcedRenderWindowSize[1] << endl; os << indent << "ForceRenderWindowSize: " << this->ForceRenderWindowSize << endl; os << indent << "UseBackBuffer: " << (this->UseBackBuffer ? "on" : "off") << endl; } //------------------------------------------------------------------------------ vtkRenderWindow* vtkParallelRenderManager::MakeRenderWindow() { vtkDebugMacro("MakeRenderWindow"); return vtkRenderWindow::New(); } //------------------------------------------------------------------------------ vtkRenderer* vtkParallelRenderManager::MakeRenderer() { vtkDebugMacro("MakeRenderer"); return vtkRenderer::New(); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::AddRenderWindowEventHandlers() { if (this->RenderWindow && !this->ObservingRenderWindow) { vtkCallbackCommand* cbc = vtkCallbackCommand::New(); cbc->SetCallback(::GenericStartRender); cbc->SetClientData((void*)this); // renWin will delete the cbc when the observer is removed. this->StartRenderTag = this->RenderWindow->AddObserver(vtkCommand::StartEvent, cbc); cbc->Delete(); cbc = vtkCallbackCommand::New(); cbc->SetCallback(::GenericEndRender); cbc->SetClientData((void*)this); // renWin will delete the cbc when the observer is removed. this->EndRenderTag = this->RenderWindow->AddObserver(vtkCommand::EndEvent, cbc); cbc->Delete(); this->ObservingRenderWindow = 1; } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::RemoveRenderWindowEventHandlers() { if (this->RenderWindow && this->ObservingRenderWindow) { this->RenderWindow->RemoveObserver(this->StartRenderTag); this->RenderWindow->RemoveObserver(this->EndRenderTag); this->StartRenderTag = 0; this->EndRenderTag = 0; this->ObservingRenderWindow = 0; } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::SetRenderWindow(vtkRenderWindow* renWin) { vtkDebugMacro("SetRenderWindow"); if (this->RenderWindow == renWin) { return; } if (this->RenderWindow) { // Remove all of the observers. if (this->ObservingAbort) { this->RenderWindow->RemoveObserver(this->AbortRenderCheckTag); this->AbortRenderCheckTag = 0; this->ObservingAbort = 0; } this->RemoveRenderWindowEventHandlers(); } vtkSetObjectBodyMacro(RenderWindow, vtkRenderWindow, renWin); if (this->RenderWindow) { vtkCallbackCommand* cbc; // In case a subclass wants to raise aborts. cbc = vtkCallbackCommand::New(); cbc->SetCallback(::AbortRenderCheck); cbc->SetClientData((void*)this); // renWin will delete the cbc when the observer is removed. this->AbortRenderCheckTag = renWin->AddObserver(vtkCommand::AbortCheckEvent, cbc); cbc->Delete(); this->ObservingAbort = 1; this->AddRenderWindowEventHandlers(); } } //------------------------------------------------------------------------------ vtkCxxSetObjectMacro(vtkParallelRenderManager, Controller, vtkMultiProcessController); //------------------------------------------------------------------------------ void vtkParallelRenderManager::InitializePieces() { vtkDebugMacro("InitializePieces"); vtkRendererCollection* rens; vtkRenderer* ren; vtkActorCollection* actors; vtkActor* actor; vtkMapper* mapper; vtkPolyDataMapper* pdMapper; int piece, numPieces; if ((this->RenderWindow == nullptr) || (this->Controller == nullptr)) { vtkWarningMacro("Called InitializePieces before setting RenderWindow or Controller"); return; } piece = this->Controller->GetLocalProcessId(); numPieces = this->Controller->GetNumberOfProcesses(); rens = this->GetRenderers(); vtkCollectionSimpleIterator rsit; rens->InitTraversal(rsit); while ((ren = rens->GetNextRenderer(rsit))) { actors = ren->GetActors(); vtkCollectionSimpleIterator ait; actors->InitTraversal(ait); while ((actor = actors->GetNextActor(ait))) { mapper = actor->GetMapper(); pdMapper = vtkPolyDataMapper::SafeDownCast(mapper); if (pdMapper) { pdMapper->SetPiece(piece); pdMapper->SetNumberOfPieces(numPieces); } } } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::InitializeOffScreen() { vtkDebugMacro("InitializeOffScreen"); if ((this->RenderWindow == nullptr) || (this->Controller == nullptr)) { vtkWarningMacro("Called InitializeOffScreen before setting RenderWindow or Controller"); return; } if ((this->Controller->GetLocalProcessId() != this->RootProcessId) || !this->WriteBackImages) { this->RenderWindow->OffScreenRenderingOn(); } else { this->RenderWindow->OffScreenRenderingOff(); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::StartInteractor() { vtkDebugMacro("StartInteractor"); if ((this->Controller == nullptr) || (this->RenderWindow == nullptr)) { vtkErrorMacro("Must set Controller and RenderWindow before starting interactor."); return; } if (this->Controller->GetLocalProcessId() == this->RootProcessId) { vtkRenderWindowInteractor* inter = this->RenderWindow->GetInteractor(); if (!inter) { vtkErrorMacro("Render window does not have an interactor."); } else { inter->Initialize(); inter->Start(); } // By the time we reach here, the interaction is finished. this->StopServices(); } else { this->StartServices(); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::StartServices() { vtkDebugMacro("StartServices"); if (!this->Controller) { vtkErrorMacro("Must set Controller before starting service"); return; } if (this->Controller->GetLocalProcessId() == this->RootProcessId) { vtkWarningMacro("Starting service on root process (probably not what you wanted to do)"); } this->InitializeRMIs(); this->Controller->ProcessRMIs(); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::StopServices() { vtkDebugMacro("StopServices"); if (!this->Controller) { vtkErrorMacro("Must set Controller before stopping service"); return; } if (this->Controller->GetLocalProcessId() != this->RootProcessId) { vtkErrorMacro("Can only stop services on root node"); return; } this->Controller->TriggerRMIOnAllChildren(vtkMultiProcessController::BREAK_RMI_TAG); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::GenericStartRenderCallback() { if (!this->Controller) { return; } if (this->Controller->GetLocalProcessId() == this->RootProcessId) { this->StartRender(); } else // LocalProcessId != RootProcessId { this->SatelliteStartRender(); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::GenericEndRenderCallback() { if (!this->Controller) { return; } if (this->Controller->GetLocalProcessId() == this->RootProcessId) { this->EndRender(); } else // LocalProcessId != RootProcessId { this->SatelliteEndRender(); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::StartRender() { vtkParallelRenderManager::RenderWindowInfo winInfo; vtkParallelRenderManager::RendererInfo renInfo; vtkParallelRenderManager::LightInfo lightInfo; vtkDebugMacro("StartRender"); if ((this->Controller == nullptr) || (this->Lock)) { return; } this->Lock = 1; this->FullImageUpToDate = 0; this->ReducedImageUpToDate = 0; this->RenderWindowImageUpToDate = 0; if (this->FullImage->GetPointer(0) == this->ReducedImage->GetPointer(0)) { // "Un-share" pointer for full/reduced images in case we need separate // arrays this run. this->ReducedImage->Initialize(); } if (!this->ParallelRendering) { this->Lock = 0; return; } this->InvokeEvent(vtkCommand::StartEvent, nullptr); this->ImageProcessingTime = 0; // Used to time the total render (without compositing). this->Timer->StartTimer(); if (this->AutoImageReductionFactor) { this->SetImageReductionFactorForUpdateRate(this->RenderWindow->GetDesiredUpdateRate()); } // Make adjustments for window size. int* tilesize; if (this->ForceRenderWindowSize) { tilesize = this->ForcedRenderWindowSize; } else { tilesize = this->RenderWindow->GetActualSize(); } int size[2]; size[0] = tilesize[0]; size[1] = tilesize[1]; if ((size[0] == 0) || (size[1] == 0)) { // It helps to have a real window size. vtkDebugMacro("Resetting window size to 300x300"); size[0] = size[1] = 300; this->RenderWindow->SetSize(size[0], size[1]); } this->FullImageSize[0] = size[0]; this->FullImageSize[1] = size[1]; // Round up. this->ReducedImageSize[0] = (int)((size[0] + this->ImageReductionFactor - 1) / this->ImageReductionFactor); this->ReducedImageSize[1] = (int)((size[1] + this->ImageReductionFactor - 1) / this->ImageReductionFactor); // Collect and distribute information about current state of RenderWindow vtkRendererCollection* rens = this->GetRenderers(); winInfo.FullSize[0] = this->FullImageSize[0]; winInfo.FullSize[1] = this->FullImageSize[1]; winInfo.ReducedSize[0] = this->ReducedImageSize[0]; winInfo.ReducedSize[1] = this->ReducedImageSize[1]; winInfo.NumberOfRenderers = rens->GetNumberOfItems(); winInfo.ImageReductionFactor = this->ImageReductionFactor; winInfo.UseCompositing = this->UseCompositing; winInfo.DesiredUpdateRate = this->RenderWindow->GetDesiredUpdateRate(); this->RenderWindow->GetTileScale(winInfo.TileScale); this->RenderWindow->GetTileViewport(winInfo.TileViewport); if (this->RenderEventPropagation) { this->Controller->TriggerRMIOnAllChildren(vtkParallelRenderManager::RENDER_RMI_TAG); } // Gather information about the window to send. vtkMultiProcessStream stream; winInfo.Save(stream); this->CollectWindowInformation(stream); if (this->ImageReductionFactor > 1) { this->Viewports->SetNumberOfTuples(rens->GetNumberOfItems()); } vtkCollectionSimpleIterator cookie; vtkRenderer* ren; int i; for (rens->InitTraversal(cookie), i = 0; (ren = rens->GetNextRenderer(cookie)) != nullptr; i++) { ren->GetViewport(renInfo.Viewport); // Adjust Renderer viewports to get reduced size image. if (this->ImageReductionFactor > 1) { this->Viewports->SetTuple(i, renInfo.Viewport); if (this->ImageReduceRenderer(ren)) { renInfo.Viewport[0] /= this->ImageReductionFactor; renInfo.Viewport[1] /= this->ImageReductionFactor; renInfo.Viewport[2] /= this->ImageReductionFactor; renInfo.Viewport[3] /= this->ImageReductionFactor; ren->SetViewport(renInfo.Viewport); } } vtkTypeBool hasActiveCamera = ren->IsActiveCameraCreated(); vtkCamera* cam = ren->GetActiveCamera(); if (!hasActiveCamera) { this->ResetCamera(ren); } cam->GetPosition(renInfo.CameraPosition); cam->GetFocalPoint(renInfo.CameraFocalPoint); cam->GetViewUp(renInfo.CameraViewUp); cam->GetClippingRange(renInfo.CameraClippingRange); renInfo.CameraViewAngle = cam->GetViewAngle(); cam->GetWindowCenter(renInfo.WindowCenter); ren->GetBackground(renInfo.Background); ren->GetBackground2(renInfo.Background2); renInfo.GradientBackground = ren->GetGradientBackground(); if (cam->GetParallelProjection()) { renInfo.ParallelScale = cam->GetParallelScale(); } else { renInfo.ParallelScale = 0.0; } renInfo.Draw = ren->GetDraw(); vtkLightCollection* lc = ren->GetLights(); renInfo.NumberOfLights = lc->GetNumberOfItems(); renInfo.Save(stream); vtkLight* light; vtkCollectionSimpleIterator lsit; for (lc->InitTraversal(lsit); (light = lc->GetNextLight(lsit));) { lightInfo.Type = (double)(light->GetLightType()); light->GetPosition(lightInfo.Position); light->GetFocalPoint(lightInfo.FocalPoint); lightInfo.Save(stream); } this->CollectRendererInformation(ren, stream); } if (!this->Controller->Broadcast(stream, this->Controller->GetLocalProcessId())) { return; } // Backwards compatibility stuff. this->SendWindowInformation(); rens->InitTraversal(cookie); while ((ren = rens->GetNextRenderer(cookie)) != nullptr) { this->SendRendererInformation(ren); } this->PreRenderProcessing(); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::EndRender() { if (!this->ParallelRendering) { return; } this->Timer->StopTimer(); this->RenderTime = this->Timer->GetElapsedTime() - this->ImageProcessingTime; // Just because we are not doing compositing does not mean a subclass // does not need to do post render processing. // if (!this->UseCompositing) // { // this->Lock = 0; // return; // } if (this->CheckForAbortComposite()) { this->Lock = 0; return; } this->PostRenderProcessing(); // Restore renderer viewports, if necessary. if (this->ImageReductionFactor > 1) { vtkRendererCollection* rens = this->GetRenderers(); vtkCollectionSimpleIterator cookie; vtkRenderer* ren; int i; for (rens->InitTraversal(cookie), i = 0; (ren = rens->GetNextRenderer(cookie)) != nullptr; i++) { ren->SetViewport(this->Viewports->GetPointer(4 * i)); } } this->WriteFullImage(); this->InvokeEvent(vtkCommand::EndEvent, nullptr); this->Lock = 0; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::SatelliteEndRender() { if (this->CheckForAbortComposite()) { return; } // It's a mistake to check ParallelRendering on the Satellites. // The Root node decides if the render calls are to be propagated to the // satellites...the satellites always reply to the Root nodes requests. // if (!this->ParallelRendering) // { // return; // } // Just because we are not doing compositing does not mean a subclass // does not need to do post render processing. // if (!this->UseCompositing) // { // return; // } this->PostRenderProcessing(); this->WriteFullImage(); this->InvokeEvent(vtkCommand::EndEvent, nullptr); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::RenderRMI() { this->RenderWindow->Render(); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::ResetCamera(vtkRenderer* ren) { vtkDebugMacro("ResetCamera"); double bounds[6]; if (this->Lock) { // Can't query other processes in the middle of a render. // Just grab local value instead. this->LocalComputeVisiblePropBounds(ren, bounds); ren->ResetCamera(bounds); return; } this->Lock = 1; this->ComputeVisiblePropBounds(ren, bounds); // Keep from setting camera from some outrageous value. if (!vtkMath::AreBoundsInitialized(bounds)) { // See if the not pickable values are better. ren->ComputeVisiblePropBounds(bounds); if (!vtkMath::AreBoundsInitialized(bounds)) { this->Lock = 0; return; } } ren->ResetCamera(bounds); this->Lock = 0; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::ResetCameraClippingRange(vtkRenderer* ren) { vtkDebugMacro("ResetCameraClippingRange"); double bounds[6]; if (this->Lock) { // Can't query other processes in the middle of a render. // Just grab local value instead. this->LocalComputeVisiblePropBounds(ren, bounds); ren->ResetCameraClippingRange(bounds); return; } this->Lock = 1; this->ComputeVisiblePropBounds(ren, bounds); ren->ResetCameraClippingRange(bounds); this->Lock = 0; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::ComputeVisiblePropBoundsRMI(int renderId) { vtkDebugMacro("ComputeVisiblePropBoundsRMI"); int i; vtkRendererCollection* rens = this->GetRenderers(); vtkRenderer* ren = nullptr; vtkCollectionSimpleIterator rsit; rens->InitTraversal(rsit); for (i = 0; i <= renderId; i++) { ren = rens->GetNextRenderer(rsit); } if (ren == nullptr) { vtkWarningMacro("Client requested invalid renderer in " "ComputeVisiblePropBoundsRMI\n" "Defaulting to first renderer"); ren = rens->GetFirstRenderer(); } double bounds[6]; this->LocalComputeVisiblePropBounds(ren, bounds); this->Controller->Send(bounds, 6, this->RootProcessId, vtkParallelRenderManager::BOUNDS_TAG); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::LocalComputeVisiblePropBounds(vtkRenderer* ren, double bounds[6]) { ren->ComputeVisiblePropBounds(bounds); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::ComputeVisiblePropBounds(vtkRenderer* ren, double bounds[6]) { vtkDebugMacro(<< "ComputeVisiblePropBounds"); if (!this->ParallelRendering) { ren->ComputeVisiblePropBounds(bounds); return; } if (this->Controller) { if (this->Controller->GetLocalProcessId() != this->RootProcessId) { vtkErrorMacro("ComputeVisiblePropBounds/ResetCamera can only be called on root process"); return; } vtkRendererCollection* rens = this->GetRenderers(); vtkCollectionSimpleIterator rsit; rens->InitTraversal(rsit); int renderId = 0; while (true) { vtkRenderer* myren = rens->GetNextRenderer(rsit); if (myren == nullptr) { vtkWarningMacro("ComputeVisiblePropBounds called with unregistered renderer " << ren << "\nDefaulting to first renderer."); renderId = 0; break; } if (myren == ren) { // Found correct renderer. break; } renderId++; } // Invoke RMI's on servers to perform their own ComputeVisiblePropBounds. int numProcs = this->Controller->GetNumberOfProcesses(); int id; this->Controller->TriggerRMIOnAllChildren( &renderId, sizeof(int), vtkParallelRenderManager::COMPUTE_VISIBLE_PROP_BOUNDS_RMI_TAG); // Now that all the RMI's have been invoked, we can safely query our // local bounds even if an Update requires a parallel operation. this->LocalComputeVisiblePropBounds(ren, bounds); // Collect all the bounds. for (id = 0; id < numProcs; id++) { double tmp[6]; if (id == this->RootProcessId) { continue; } this->Controller->Receive(tmp, 6, id, vtkParallelRenderManager::BOUNDS_TAG); bounds[0] = std::min(tmp[0], bounds[0]); bounds[1] = std::max(tmp[1], bounds[1]); bounds[2] = std::min(tmp[2], bounds[2]); bounds[3] = std::max(tmp[3], bounds[3]); bounds[4] = std::min(tmp[4], bounds[4]); bounds[5] = std::max(tmp[5], bounds[5]); } } else { vtkWarningMacro("ComputeVisiblePropBounds/ResetCamera called before Controller set"); ren->ComputeVisiblePropBounds(bounds); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::InitializeRMIs() { vtkDebugMacro("InitializeRMIs"); if (this->Controller == nullptr) { vtkErrorMacro("InitializeRMIs requires a controller."); return; } if (!this->AddedRMIs) { this->AddedRMIs = 1; this->RenderRMIId = this->Controller->AddRMI(::RenderRMI, this, vtkParallelRenderManager::RENDER_RMI_TAG); this->BoundsRMIId = this->Controller->AddRMI(::ComputeVisiblePropBoundsRMI, this, vtkParallelRenderManager::COMPUTE_VISIBLE_PROP_BOUNDS_RMI_TAG); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::ResetAllCameras() { vtkDebugMacro("ResetAllCameras"); if (!this->RenderWindow) { vtkErrorMacro("Called ResetAllCameras before RenderWindow set"); return; } vtkRendererCollection* rens; vtkRenderer* ren; rens = this->GetRenderers(); vtkCollectionSimpleIterator rsit; for (rens->InitTraversal(rsit); (ren = rens->GetNextRenderer(rsit));) { this->ResetCamera(ren); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::SetImageReductionFactor(double factor) { // Clamp factor. factor = (factor < 1) ? 1 : factor; factor = (factor > this->MaxImageReductionFactor) ? this->MaxImageReductionFactor : factor; if (this->MagnifyImageMethod == LINEAR) { // Make factor be a power of 2. int pow_of_2 = 1; while (pow_of_2 <= factor) { pow_of_2 <<= 1; } factor = pow_of_2 >> 1; } if (factor == this->ImageReductionFactor) { return; } this->ImageReductionFactor = factor; this->Modified(); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::SetMagnifyImageMethod(int method) { if (this->MagnifyImageMethod == method) { return; } this->MagnifyImageMethod = method; // May need to modify image reduction factor. this->SetImageReductionFactor(this->ImageReductionFactor); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::SetImageReductionFactorForUpdateRate(double desiredUpdateRate) { vtkDebugMacro("Setting reduction factor for update rate of " << desiredUpdateRate); if (desiredUpdateRate == 0.0) { this->SetImageReductionFactor(1); return; } int* size; if (this->ForceRenderWindowSize) { size = this->ForcedRenderWindowSize; } else { size = this->RenderWindow->GetActualSize(); } int numPixels = size[0] * size[1]; int numReducedPixels = (int)(numPixels / (this->ImageReductionFactor * this->ImageReductionFactor)); double renderTime = this->GetRenderTime(); double pixelTime = this->GetImageProcessingTime(); double timePerPixel; if (numReducedPixels > 0) { timePerPixel = pixelTime / numReducedPixels; } else { // Must be before first render. this->SetImageReductionFactor(1); return; } this->AverageTimePerPixel = (3 * this->AverageTimePerPixel + timePerPixel) / 4; if (this->AverageTimePerPixel <= 0) { this->AverageTimePerPixel = 0; this->SetImageReductionFactor(1); return; } double allottedPixelTime = 1.0 / desiredUpdateRate - renderTime; // Give ourselves at least 15% of render time. allottedPixelTime = std::max(allottedPixelTime, 0.15 * renderTime); vtkDebugMacro("TimePerPixel: " << timePerPixel << ", AverageTimePerPixel: " << this->AverageTimePerPixel << ", AllottedPixelTime: " << allottedPixelTime); double pixelsToUse = allottedPixelTime / this->AverageTimePerPixel; if ((pixelsToUse < 1) || (numPixels / pixelsToUse > this->MaxImageReductionFactor)) { this->SetImageReductionFactor(this->MaxImageReductionFactor); } else if (pixelsToUse >= numPixels) { this->SetImageReductionFactor(1); } else { this->SetImageReductionFactor((int)(numPixels / pixelsToUse)); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::SetRenderWindowSize() { if (!this->RenderWindow->GetOffScreenRendering()) { // Make sure we can support the requested image size. const int* screensize = this->RenderWindow->GetScreenSize(); if (this->FullImageSize[0] > screensize[0]) { // Reduce both dimensions to preserve aspect ratio. this->FullImageSize[1] = (this->FullImageSize[1] * screensize[0]) / this->FullImageSize[0]; this->FullImageSize[0] = screensize[0]; } if (this->FullImageSize[1] > screensize[1]) { // Reduce both dimensions to preserve aspect ratio. this->FullImageSize[0] = (this->FullImageSize[0] * screensize[1]) / this->FullImageSize[1]; this->FullImageSize[1] = screensize[1]; } // Make sure the reduced image is no bigger than the full image. this->ReducedImageSize[0] = std::min(this->ReducedImageSize[0], this->FullImageSize[0]); this->ReducedImageSize[1] = std::min(this->ReducedImageSize[1], this->FullImageSize[1]); } // Correct image reduction factor. this->ImageReductionFactor = (double)this->FullImageSize[0] / this->ReducedImageSize[0]; this->RenderWindow->SetSize(this->FullImageSize[0], this->FullImageSize[1]); } //------------------------------------------------------------------------------ vtkRendererCollection* vtkParallelRenderManager::GetRenderers() { if (this->SyncRenderWindowRenderers) { return this->RenderWindow->GetRenderers(); } else { return this->Renderers; } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::AddRenderer(vtkRenderer* ren) { this->Renderers->AddItem(ren); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::RemoveRenderer(vtkRenderer* ren) { this->Renderers->RemoveItem(ren); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::RemoveAllRenderers() { this->Renderers->RemoveAllItems(); } //------------------------------------------------------------------------------ int vtkParallelRenderManager::LastRenderInFrontBuffer() { return this->RenderWindow->GetSwapBuffers(); } //------------------------------------------------------------------------------ int vtkParallelRenderManager::ChooseBuffer() { // always render buffer return 0; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::MagnifyImageNearest(vtkUnsignedCharArray* fullImage, const int fullImageSize[2], vtkUnsignedCharArray* reducedImage, const int reducedImageSize[2], const int fullImageViewport[4], const int reducedImageViewport[4]) { int numComp = reducedImage->GetNumberOfComponents(); fullImage->SetNumberOfComponents(4); fullImage->SetNumberOfTuples(fullImageSize[0] * fullImageSize[1]); int destLeft, destBottom, destWidth, destHeight; if (fullImageViewport) { destLeft = fullImageViewport[0]; destBottom = fullImageViewport[1]; destWidth = fullImageViewport[2] - fullImageViewport[0]; destHeight = fullImageViewport[3] - fullImageViewport[1]; } else { destLeft = destBottom = 0; destWidth = fullImageSize[0]; destHeight = fullImageSize[1]; } int srcLeft, srcBottom, srcWidth, srcHeight; if (reducedImageViewport) { srcLeft = reducedImageViewport[0]; srcBottom = reducedImageViewport[1]; srcWidth = reducedImageViewport[2] - reducedImageViewport[0]; srcHeight = reducedImageViewport[3] - reducedImageViewport[1]; } else { srcLeft = srcBottom = 0; srcWidth = reducedImageSize[0]; srcHeight = reducedImageSize[1]; } if (numComp == 4) { // If there are 4 components per pixel, we can speed up the inflation // by copying integers instead of characters. // Making a bunch of tmp variables for speed within the loops // Look I know the compiler should optimize this stuff // but I don't trust compilers... besides testing shows // this code is faster than the old code float xstep = (float)srcWidth / destWidth; float ystep = (float)srcHeight / destHeight; float xaccum = 0, yaccum = 0; int destlinesize = fullImageSize[0]; int srclinesize = reducedImageSize[0]; int xmemsize = 4 * destWidth; unsigned int* lastsrcline = nullptr; unsigned int* destline = (unsigned int*)fullImage->GetPointer(4 * (destBottom * destlinesize + destLeft)); unsigned int* srcline = (unsigned int*)reducedImage->GetPointer(4 * (srcBottom * srclinesize + srcLeft)); unsigned int* srczero = srcline; // Inflate image. for (int y = 0; y < destHeight; ++y, yaccum += ystep) { // If this line same as last one. if (srcline == lastsrcline) { memcpy(destline, destline - destlinesize, xmemsize); } else { for (int x = 0; x < destWidth; ++x, xaccum += xstep) { destline[x] = srcline[(int)(xaccum)]; } xaccum = 0; lastsrcline = srcline; } destline += destlinesize; srcline = srczero + srclinesize * int(yaccum); // Performance fixme } } else { // Inflate image. double xstep = (double)srcWidth / destWidth; double ystep = (double)srcHeight / destHeight; unsigned char* lastsrcline = nullptr; for (int y = 0; y < destHeight; y++) { unsigned char* destline = fullImage->GetPointer(4 * (fullImageSize[0] * (y + destBottom) + destLeft)); unsigned char* srcline = reducedImage->GetPointer( numComp * (reducedImageSize[0] * ((int)(ystep * y) + srcBottom) + srcLeft)); if (srcline == lastsrcline) { // This line same as last one. memcpy(destline, (const unsigned char*)(destline - 4 * fullImageSize[0]), 4 * destWidth); } else { for (int x = 0; x < destWidth; x++) { int srcloc = numComp * (int)(x * xstep); int destloc = 4 * x; int i; for (i = 0; i < numComp; i++) { destline[destloc + i] = srcline[srcloc + i]; } for (; i < 4; i++) { destline[destloc + i] = 0xFF; } } lastsrcline = srcline; } } } } //------------------------------------------------------------------------------ // A neat trick to quickly divide all 4 of the bytes in an integer by 2. #define VTK_VEC_DIV_2(intvector) (((intvector) >> 1) & 0x7F7F7F7F) void vtkParallelRenderManager::MagnifyImageLinear(vtkUnsignedCharArray* fullImage, const int fullImageSize[2], vtkUnsignedCharArray* reducedImage, const int reducedImageSize[2], const int fullImageViewport[4], const int reducedImageViewport[4]) { int xmag, ymag; int x, y; int srcComp = reducedImage->GetNumberOfComponents(); // Allocate full image so all pixels are on 4-byte integer boundaries. fullImage->SetNumberOfComponents(4); fullImage->SetNumberOfTuples(fullImageSize[0] * fullImageSize[1]); int destLeft, destBottom, destWidth, destHeight; if (fullImageViewport) { destLeft = fullImageViewport[0]; destBottom = fullImageViewport[1]; destWidth = fullImageViewport[2] - fullImageViewport[0]; destHeight = fullImageViewport[3] - fullImageViewport[1]; } else { destLeft = destBottom = 0; destWidth = fullImageSize[0]; destHeight = fullImageSize[1]; } int srcLeft, srcBottom, srcWidth, srcHeight; if (reducedImageViewport) { srcLeft = reducedImageViewport[0]; srcBottom = reducedImageViewport[1]; srcWidth = reducedImageViewport[2] - reducedImageViewport[0]; srcHeight = reducedImageViewport[3] - reducedImageViewport[1]; } else { srcLeft = srcBottom = 0; srcWidth = reducedImageSize[0]; srcHeight = reducedImageSize[1]; } // Guess x and y magnification. Round up to ensure we do not try to // read data from the image data that does not exist. xmag = (destWidth + srcWidth - 1) / srcWidth; ymag = (destHeight + srcHeight - 1) / srcHeight; // For speed, we only magnify by powers of 2. Round up to the nearest // power of 2 to ensure that the reduced image is large enough. int powOf2; for (powOf2 = 1; powOf2 < xmag; powOf2 <<= 1) { } xmag = powOf2; for (powOf2 = 1; powOf2 < ymag; powOf2 <<= 1) { } ymag = powOf2; unsigned char* srcline = reducedImage->GetPointer(srcComp * srcBottom * reducedImageSize[0]); unsigned char* destline = fullImage->GetPointer(4 * destBottom * fullImageSize[0]); for (y = 0; y < destHeight; y += ymag) { unsigned char* srcval = srcline + srcComp * srcLeft; unsigned char* destval = destline + 4 * destLeft; for (x = 0; x < destWidth; x += xmag) { destval[0] = srcval[0]; destval[1] = srcval[1]; destval[2] = srcval[2]; destval[3] = 0xFF; // Hope we don't need the alpha value. srcval += srcComp; destval += 4 * xmag; } srcline += srcComp * reducedImageSize[0]; destline += 4 * fullImageSize[0] * ymag; } // Now that we have everything on 4-byte boundaries, we will treat // everything as integers for much faster computation. unsigned int* image = (unsigned int*)fullImage->GetPointer(0) + destBottom * fullImageSize[0] + destLeft; // Fill in scanlines. for (; xmag > 1; xmag >>= 1) { int halfXMag = xmag / 2; for (y = 0; y < destHeight; y += ymag) { unsigned int* scanline = image + y * fullImageSize[0]; int maxX = destWidth - halfXMag; // Don't access bad memory. for (x = halfXMag; x < maxX; x += xmag) { scanline[x] = VTK_VEC_DIV_2(scanline[x - halfXMag]) + VTK_VEC_DIV_2(scanline[x + halfXMag]); } if (x < destWidth) { scanline[x] = scanline[x - halfXMag]; } } } // Add blank scanlines. for (; ymag > 1; ymag >>= 1) { int halfYMag = ymag / 2; int maxY = destHeight - halfYMag; // Don't access bad memory. for (y = halfYMag; y < maxY; y += ymag) { unsigned int* destline2 = image + y * fullImageSize[0]; unsigned int* srcline1 = image + (y - halfYMag) * fullImageSize[0]; unsigned int* srcline2 = image + (y + halfYMag) * fullImageSize[0]; for (x = 0; x < destWidth; x++) { destline2[x] = VTK_VEC_DIV_2(srcline1[x]) + VTK_VEC_DIV_2(srcline2[x]); } } if (y < destHeight) { unsigned int* destline2 = image + y * fullImageSize[0]; unsigned int* srcline1 = image + (y - halfYMag) * fullImageSize[0]; for (x = 0; x < destWidth; x++) { destline2[x] = srcline1[x]; } } } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::MagnifyImage(vtkUnsignedCharArray* fullImage, const int fullImageSize[2], vtkUnsignedCharArray* reducedImage, const int reducedImageSize[2], const int fullImageViewport[4], const int reducedImageViewport[4]) { switch (this->MagnifyImageMethod) { case vtkParallelRenderManager::NEAREST: this->MagnifyImageNearest(fullImage, fullImageSize, reducedImage, reducedImageSize, fullImageViewport, reducedImageViewport); break; case LINEAR: this->MagnifyImageLinear(fullImage, fullImageSize, reducedImage, reducedImageSize, fullImageViewport, reducedImageViewport); break; } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::MagnifyReducedImage() { if ((this->FullImageUpToDate)) { return; } this->ReadReducedImage(); if (this->FullImage->GetPointer(0) != this->ReducedImage->GetPointer(0)) { this->Timer->StartTimer(); this->MagnifyImage( this->FullImage, this->FullImageSize, this->ReducedImage, this->ReducedImageSize); this->Timer->StopTimer(); // We log the image inflation under render time because it is inversely // proportional to the image size. This makes the auto image reduction // calculation work better. this->RenderTime += this->Timer->GetElapsedTime(); } this->FullImageUpToDate = 1; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::WriteFullImage() { if (this->RenderWindowImageUpToDate || !this->WriteBackImages) { return; } if (this->MagnifyImages && ((this->FullImageSize[0] != this->ReducedImageSize[0]) || (this->FullImageSize[1] != this->ReducedImageSize[1]))) { this->MagnifyReducedImage(); this->SetRenderWindowPixelData(this->FullImage, this->FullImageSize); } else { // Only write back image if it has already been read and potentially // changed. if (this->ReducedImageUpToDate) { this->SetRenderWindowPixelData(this->ReducedImage, this->ReducedImageSize); } } this->RenderWindowImageUpToDate = 1; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::SetRenderWindowPixelData( vtkUnsignedCharArray* pixels, const int pixelDimensions[2]) { if (pixels->GetNumberOfComponents() == 4) { this->RenderWindow->SetRGBACharPixelData( 0, 0, pixelDimensions[0] - 1, pixelDimensions[1] - 1, pixels, this->ChooseBuffer()); } else { this->RenderWindow->SetPixelData( 0, 0, pixelDimensions[0] - 1, pixelDimensions[1] - 1, pixels, this->ChooseBuffer()); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::ReadReducedImage() { if (this->ReducedImageUpToDate) { return; } this->Timer->StartTimer(); if (this->ImageReductionFactor > 1) { if (this->UseRGBA) { this->RenderWindow->GetRGBACharPixelData(0, 0, this->ReducedImageSize[0] - 1, this->ReducedImageSize[1] - 1, this->ChooseBuffer(), this->ReducedImage); } else { this->RenderWindow->GetPixelData(0, 0, this->ReducedImageSize[0] - 1, this->ReducedImageSize[1] - 1, this->ChooseBuffer(), this->ReducedImage); } } else { if (this->UseRGBA) { this->RenderWindow->GetRGBACharPixelData(0, 0, this->FullImageSize[0] - 1, this->FullImageSize[1] - 1, this->ChooseBuffer(), this->FullImage); } else { this->RenderWindow->GetPixelData(0, 0, this->FullImageSize[0] - 1, this->FullImageSize[1] - 1, this->ChooseBuffer(), this->FullImage); } this->FullImageUpToDate = 1; this->ReducedImage->SetNumberOfComponents(this->FullImage->GetNumberOfComponents()); this->ReducedImage->SetArray(this->FullImage->GetPointer(0), this->FullImage->GetDataSize(), 1); this->ReducedImage->SetNumberOfTuples(this->FullImage->GetNumberOfTuples()); } this->Timer->StopTimer(); this->ImageProcessingTime += this->Timer->GetElapsedTime(); this->ReducedImageUpToDate = 1; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::GetPixelData(vtkUnsignedCharArray* data) { if (!this->RenderWindow) { vtkErrorMacro("Tried to read pixel data from non-existent RenderWindow"); return; } // Read image from RenderWindow and magnify if necessary. this->MagnifyReducedImage(); data->SetNumberOfComponents(this->FullImage->GetNumberOfComponents()); data->SetArray(this->FullImage->GetPointer(0), this->FullImage->GetDataSize(), 1); data->SetNumberOfTuples(this->FullImage->GetNumberOfTuples()); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::GetPixelData( int x1, int y1, int x2, int y2, vtkUnsignedCharArray* data) { if (!this->RenderWindow) { vtkErrorMacro("Tried to read pixel data from non-existent RenderWindow"); return; } this->MagnifyReducedImage(); if (x1 > x2) { int tmp = x1; x1 = x2; x2 = tmp; } if (y1 > y2) { int tmp = y1; y1 = y2; y2 = tmp; } if ((x1 < 0) || (x2 >= this->FullImageSize[0]) || (y1 < 0) || (y2 >= this->FullImageSize[1])) { vtkErrorMacro("Requested pixel data out of RenderWindow bounds"); return; } vtkIdType width = x2 - x1 + 1; vtkIdType height = y2 - y1 + 1; int numComp = this->FullImage->GetNumberOfComponents(); data->SetNumberOfComponents(numComp); data->SetNumberOfTuples(width * height); const unsigned char* src = this->FullImage->GetPointer(0); unsigned char* dest = data->WritePointer(0, width * height * numComp); for (int row = 0; row < height; row++) { memcpy(dest + row * width * numComp, src + (row + y1) * this->FullImageSize[0] * numComp + x1 * numComp, width * numComp); } } //------------------------------------------------------------------------------ void vtkParallelRenderManager::GetReducedPixelData(vtkUnsignedCharArray* data) { if (!this->RenderWindow) { vtkErrorMacro("Tried to read pixel data from non-existent RenderWindow"); return; } // Read image from RenderWindow and magnify if necessary. this->ReadReducedImage(); data->SetNumberOfComponents(this->ReducedImage->GetNumberOfComponents()); data->SetArray(this->ReducedImage->GetPointer(0), this->ReducedImage->GetDataSize(), 1); data->SetNumberOfTuples(this->ReducedImage->GetNumberOfTuples()); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::GetReducedPixelData( int x1, int y1, int x2, int y2, vtkUnsignedCharArray* data) { if (!this->RenderWindow) { vtkErrorMacro("Tried to read pixel data from non-existent RenderWindow"); return; } this->ReadReducedImage(); if (x1 > x2) { int tmp = x1; x1 = x2; x2 = tmp; } if (y1 > y2) { int tmp = y1; y1 = y2; y2 = tmp; } if ((x1 < 0) || (x2 >= this->ReducedImageSize[0]) || (y1 < 0) || (y2 >= this->ReducedImageSize[1])) { vtkErrorMacro("Requested pixel data out of RenderWindow bounds"); return; } vtkIdType width = x2 - x1 + 1; vtkIdType height = y2 - y1 + 1; int numComp = this->ReducedImage->GetNumberOfComponents(); data->SetNumberOfComponents(numComp); data->SetNumberOfTuples(width * height); const unsigned char* src = this->ReducedImage->GetPointer(0); unsigned char* dest = data->WritePointer(0, width * height * numComp); for (int row = 0; row < height; row++) { memcpy(dest + row * width * numComp, src + (row + y1) * this->ReducedImageSize[0] * numComp + x1 * numComp, width * numComp); } } // Static function prototypes -------------------------------------------- static void AbortRenderCheck( vtkObject* vtkNotUsed(caller), unsigned long vtkNotUsed(event), void* clientData, void*) { vtkParallelRenderManager* self = (vtkParallelRenderManager*)clientData; self->CheckForAbortRender(); } static void GenericStartRender( vtkObject* vtkNotUsed(caller), unsigned long vtkNotUsed(event), void* clientData, void*) { vtkParallelRenderManager* self = (vtkParallelRenderManager*)clientData; self->GenericStartRenderCallback(); } static void GenericEndRender( vtkObject* vtkNotUsed(caller), unsigned long vtkNotUsed(event), void* clientData, void*) { vtkParallelRenderManager* self = (vtkParallelRenderManager*)clientData; self->GenericEndRenderCallback(); } /* static void ResetCamera(vtkObject *caller, unsigned long vtkNotUsed(event), void *clientData, void *) { vtkParallelRenderManager *self = (vtkParallelRenderManager *)clientData; vtkRenderer *ren = (vtkRenderer *)caller; self->ResetCamera(ren); } static void ResetCameraClippingRange(vtkObject *caller, unsigned long vtkNotUsed(event), void *clientData, void *) { vtkParallelRenderManager *self = (vtkParallelRenderManager *)clientData; vtkRenderer *ren = (vtkRenderer *)caller; self->ResetCameraClippingRange(ren); } */ static void RenderRMI(void* arg, void*, int, int) { vtkParallelRenderManager* self = (vtkParallelRenderManager*)arg; self->RenderRMI(); } static void ComputeVisiblePropBoundsRMI(void* arg, void* remoteArg, int remoteArgLength, int) { assert(remoteArgLength == sizeof(int)); (void)remoteArgLength; int* iarg = reinterpret_cast(remoteArg); vtkParallelRenderManager* self = (vtkParallelRenderManager*)arg; self->ComputeVisiblePropBoundsRMI(*iarg); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::SatelliteStartRender() { vtkParallelRenderManager::RenderWindowInfo winInfo; vtkParallelRenderManager::RendererInfo renInfo; vtkParallelRenderManager::LightInfo lightInfo; int i, j; vtkDebugMacro("SatelliteStartRender"); this->FullImageUpToDate = 0; this->ReducedImageUpToDate = 0; this->RenderWindowImageUpToDate = 0; if (this->FullImage->GetPointer(0) == this->ReducedImage->GetPointer(0)) { // "Un-share" pointer for full/reduced images in case we need separate // arrays this run. this->ReducedImage->Initialize(); } // if (!this->ParallelRendering) // { // return; // } this->InvokeEvent(vtkCommand::StartEvent, nullptr); vtkMultiProcessStream stream; if (!this->Controller->Broadcast(stream, this->RootProcessId)) { return; } if (!winInfo.Restore(stream)) { vtkErrorMacro("Failed to read window information"); return; } this->RenderWindow->SetDesiredUpdateRate(winInfo.DesiredUpdateRate); if (this->SynchronizeTileProperties) { this->RenderWindow->SetTileViewport(winInfo.TileViewport); this->RenderWindow->SetTileScale(winInfo.TileScale); } this->SetUseCompositing(winInfo.UseCompositing); if (this->MaxImageReductionFactor < winInfo.ImageReductionFactor) { this->SetMaxImageReductionFactor(winInfo.ImageReductionFactor); } this->SetImageReductionFactor(winInfo.ImageReductionFactor); this->FullImageSize[0] = winInfo.FullSize[0]; this->FullImageSize[1] = winInfo.FullSize[1]; this->ReducedImageSize[0] = winInfo.ReducedSize[0]; this->ReducedImageSize[1] = winInfo.ReducedSize[1]; // Backwards compatibility. this->ReceiveWindowInformation(); if (!this->ProcessWindowInformation(stream)) { vtkErrorMacro("Failed to process window information correctly."); return; } this->SetRenderWindowSize(); vtkCollectionSimpleIterator rsit; vtkRendererCollection* rens = this->GetRenderers(); this->Viewports->SetNumberOfTuples(rens->GetNumberOfItems()); rens->InitTraversal(rsit); for (i = 0; i < winInfo.NumberOfRenderers; i++) { vtkLightCollection* lc = nullptr; vtkCollectionSimpleIterator lsit; vtkRenderer* ren = rens->GetNextRenderer(rsit); if (ren == nullptr) { vtkErrorMacro("Not enough renderers"); } else { // Backwards compatibility this->ReceiveRendererInformation(ren); if (!renInfo.Restore(stream)) { vtkErrorMacro("Failed to read renderer information for " << i); continue; } this->Viewports->SetTuple(i, ren->GetViewport()); ren->SetViewport(renInfo.Viewport); ren->SetBackground(renInfo.Background[0], renInfo.Background[1], renInfo.Background[2]); ren->SetBackground2(renInfo.Background2[0], renInfo.Background2[1], renInfo.Background2[2]); ren->SetGradientBackground(renInfo.GradientBackground); vtkCamera* cam = ren->GetActiveCamera(); cam->SetPosition(renInfo.CameraPosition); cam->SetFocalPoint(renInfo.CameraFocalPoint); cam->SetViewUp(renInfo.CameraViewUp); cam->SetClippingRange(renInfo.CameraClippingRange); cam->SetViewAngle(renInfo.CameraViewAngle); cam->SetWindowCenter(renInfo.WindowCenter[0], renInfo.WindowCenter[1]); if (renInfo.ParallelScale != 0.0) { cam->ParallelProjectionOn(); cam->SetParallelScale(renInfo.ParallelScale); } else { cam->ParallelProjectionOff(); } ren->SetDraw(renInfo.Draw); lc = ren->GetLights(); lc->InitTraversal(lsit); } for (j = 0; j < renInfo.NumberOfLights; j++) { if (ren != nullptr && lc != nullptr) { vtkLight* light = lc->GetNextLight(lsit); if (light == nullptr) { // Not enough lights? Just create them. vtkDebugMacro("Adding light"); light = vtkLight::New(); ren->AddLight(light); light->Delete(); } if (!lightInfo.Restore(stream)) { vtkErrorMacro("Failed to read light information"); continue; } light->SetLightType((int)(lightInfo.Type)); light->SetPosition(lightInfo.Position); light->SetFocalPoint(lightInfo.FocalPoint); } } if (ren != nullptr) { vtkLight* light; while ((light = lc->GetNextLight(lsit))) { // To many lights? Just remove the extras. ren->RemoveLight(light); } } if (!this->ProcessRendererInformation(ren, stream)) { vtkErrorMacro("Failed to process renderer information correctly."); } } if (rens->GetNextRenderer(rsit)) { vtkErrorMacro("Too many renderers."); } this->PreRenderProcessing(); } //------------------------------------------------------------------------------ void vtkParallelRenderManager::TileWindows(int xsize, int ysize, int ncolumn) { if (!this->RenderWindow || !this->Controller) { return; } int procId = this->Controller->GetLocalProcessId(); int row = procId / ncolumn; int column = procId % ncolumn; this->RenderWindow->SetPosition(xsize * column, ysize * row); } //------------------------------------------------------------------------------ // ********* INFO OBJECT METHODS *************************** //------------------------------------------------------------------------------ void vtkParallelRenderManager::RenderWindowInfo::Save(vtkMultiProcessStream& stream) { stream << vtkParallelRenderManager::WIN_INFO_TAG << this->FullSize[0] << this->FullSize[1] << this->ReducedSize[0] << this->ReducedSize[1] << this->NumberOfRenderers << this->UseCompositing << this->TileScale[0] << this->TileScale[1] << this->ImageReductionFactor << this->DesiredUpdateRate << this->TileViewport[0] << this->TileViewport[1] << this->TileViewport[2] << this->TileViewport[3]; } //------------------------------------------------------------------------------ bool vtkParallelRenderManager::RenderWindowInfo::Restore(vtkMultiProcessStream& stream) { int tag; stream >> tag; if (tag != vtkParallelRenderManager::WIN_INFO_TAG) { return false; } stream >> this->FullSize[0] >> this->FullSize[1] >> this->ReducedSize[0] >> this->ReducedSize[1] >> this->NumberOfRenderers >> this->UseCompositing >> this->TileScale[0] >> this->TileScale[1] >> this->ImageReductionFactor >> this->DesiredUpdateRate >> this->TileViewport[0] >> this->TileViewport[1] >> this->TileViewport[2] >> this->TileViewport[3]; return true; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::RendererInfo::Save(vtkMultiProcessStream& stream) { int value = this->GradientBackground; stream << vtkParallelRenderManager::REN_INFO_TAG << this->Draw << this->NumberOfLights << this->Viewport[0] << this->Viewport[1] << this->Viewport[2] << this->Viewport[3] << this->CameraPosition[0] << this->CameraPosition[1] << this->CameraPosition[2] << this->CameraFocalPoint[0] << this->CameraFocalPoint[1] << this->CameraFocalPoint[2] << this->CameraViewUp[0] << this->CameraViewUp[1] << this->CameraViewUp[2] << this->WindowCenter[0] << this->WindowCenter[1] << this->CameraClippingRange[0] << this->CameraClippingRange[1] << this->CameraViewAngle << this->Background[0] << this->Background[1] << this->Background[2] << this->Background2[0] << this->Background2[1] << this->Background2[2] << value << this->ParallelScale; } //------------------------------------------------------------------------------ bool vtkParallelRenderManager::RendererInfo::Restore(vtkMultiProcessStream& stream) { int tag; stream >> tag; if (tag != vtkParallelRenderManager::REN_INFO_TAG) { return false; } int value; stream >> this->Draw >> this->NumberOfLights >> this->Viewport[0] >> this->Viewport[1] >> this->Viewport[2] >> this->Viewport[3] >> this->CameraPosition[0] >> this->CameraPosition[1] >> this->CameraPosition[2] >> this->CameraFocalPoint[0] >> this->CameraFocalPoint[1] >> this->CameraFocalPoint[2] >> this->CameraViewUp[0] >> this->CameraViewUp[1] >> this->CameraViewUp[2] >> this->WindowCenter[0] >> this->WindowCenter[1] >> this->CameraClippingRange[0] >> this->CameraClippingRange[1] >> this->CameraViewAngle >> this->Background[0] >> this->Background[1] >> this->Background[2] >> this->Background2[0] >> this->Background2[1] >> this->Background2[2] >> value >> this->ParallelScale; this->GradientBackground = value == 1; return true; } //------------------------------------------------------------------------------ bool vtkParallelRenderManager::LightInfo::Restore(vtkMultiProcessStream& stream) { int tag; stream >> tag; if (tag != vtkParallelRenderManager::LIGHT_INFO_TAG) { return false; } stream >> this->Position[0] >> this->Position[1] >> this->Position[2] >> this->FocalPoint[0] >> this->FocalPoint[1] >> this->FocalPoint[2] >> this->Type; return true; } //------------------------------------------------------------------------------ void vtkParallelRenderManager::LightInfo::Save(vtkMultiProcessStream& stream) { stream << vtkParallelRenderManager::LIGHT_INFO_TAG << this->Position[0] << this->Position[1] << this->Position[2] << this->FocalPoint[0] << this->FocalPoint[1] << this->FocalPoint[2] << this->Type; } VTK_ABI_NAMESPACE_END