Files
ThirdParty-6/ParaView-5.0.1/ParaViewCore/ClientServerCore/Rendering/vtkIceTSynchronizedRenderers.cxx

431 lines
14 KiB
C++

/*=========================================================================
Program: ParaView
Module: vtkIceTSynchronizedRenderers.cxx
Copyright (c) Kitware, Inc.
All rights reserved.
See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkIceTSynchronizedRenderers.h"
#include "vtkCamera.h"
#include "vtkCameraPass.h"
#include "vtkCullerCollection.h"
#include "vtkImageProcessingPass.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "vtkPVDefaultPass.h"
#include "vtkRenderer.h"
#include "vtkOpenGLRenderer.h"
#include "vtkRenderState.h"
#include "vtkRenderWindow.h"
#include "vtkSmartPointer.h"
#include "vtkTileDisplayHelper.h"
#include "vtkTilesHelper.h"
#include "vtkTimerLog.h"
#include "vtkOpenGLError.h"
#include <assert.h>
#include <IceT.h>
#include <IceTGL.h>
#include <map>
// This pass is used to simply render an image onto the frame buffer. Used when
// an ImageProcessingPass is set to paste the IceT composited image into the
// frame buffer for the ImageProcessingPass.
class vtkMyImagePasterPass : public vtkRenderPass
{
public:
static vtkMyImagePasterPass* New();
vtkTypeMacro(vtkMyImagePasterPass, vtkRenderPass);
vtkIceTCompositePass* IceTCompositePass;
vtkRenderPass* DelegatePass;
bool UseDepthBuffer;
virtual void Render(const vtkRenderState* render_state)
{
vtkOpenGLClearErrorMacro();
if (this->DelegatePass)
{
this->DelegatePass->Render(render_state);
vtkOpenGLCheckErrorMacro("failed after delegate pass render");
}
if (this->IceTCompositePass)
{
this->IceTCompositePass->GetLastRenderedTile(this->Image);
}
if (this->Image.IsValid())
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
this->Image.PushToFrameBuffer(render_state->GetRenderer());
if (this->UseDepthBuffer)
{
this->IceTCompositePass->PushIceTDepthBufferToScreen(render_state);
}
}
glFinish();
vtkOpenGLCheckErrorMacro("failed after push depth buffer");
}
void SetImage(const vtkSynchronizedRenderers::vtkRawImage& image)
{
this->Image = image;
}
void SetUseDepthBuffer(bool useDB)
{
this->UseDepthBuffer = useDB;
}
virtual void ReleaseGraphicsResources(vtkWindow *window)
{
if (this->DelegatePass)
{
this->DelegatePass->ReleaseGraphicsResources(window);
}
if (this->IceTCompositePass)
{
this->IceTCompositePass->ReleaseGraphicsResources(window);
}
this->Superclass::ReleaseGraphicsResources(window);
}
protected:
vtkMyImagePasterPass()
{
this->DelegatePass = NULL;
this->IceTCompositePass = NULL;
this->UseDepthBuffer = false;
}
~vtkMyImagePasterPass()
{
}
vtkSynchronizedRenderers::vtkRawImage Image;
};
vtkStandardNewMacro(vtkMyImagePasterPass);
namespace
{
class vtkMyCameraPass : public vtkCameraPass
{
vtkIceTCompositePass* IceTCompositePass;
public:
vtkTypeMacro(vtkMyCameraPass, vtkCameraPass);
static vtkMyCameraPass* New();
// Description:
// Set the icet composite pass.
vtkSetObjectMacro(IceTCompositePass, vtkIceTCompositePass);
virtual void GetTiledSizeAndOrigin(
const vtkRenderState* render_state,
int* width, int* height, int *originX,
int* originY)
{
assert (this->IceTCompositePass != NULL);
int tile_dims[2];
this->IceTCompositePass->GetTileDimensions(tile_dims);
if (tile_dims[0] > 1 || tile_dims[1] > 1)
{
// we have a complicated relationship with tile-scale when we are in
// tile-display mode :).
// vtkPVSynchronizedRenderWindows sets up the tile-scale and origin on the
// window so that 2D annotations work just fine. However that messes up
// when we are using IceT since IceT will do the camera translations. So
// for IceT's sake, we reset the tile_scale/tile_viewport when doing the
// camera transformations. Of course, this is only an issue when rendering
// for tile-displays.
int tile_scale[2];
double tile_viewport[4];
render_state->GetRenderer()->GetRenderWindow()->GetTileScale(tile_scale);
render_state->GetRenderer()->GetRenderWindow()->GetTileViewport(tile_viewport);
render_state->GetRenderer()->GetRenderWindow()->SetTileScale(1, 1);
render_state->GetRenderer()->GetRenderWindow()->SetTileViewport(0,0,1,1);
this->Superclass::GetTiledSizeAndOrigin(render_state, width, height, originX, originY);
render_state->GetRenderer()->GetRenderWindow()->SetTileScale(tile_scale);
render_state->GetRenderer()->GetRenderWindow()->SetTileViewport(tile_viewport);
*originX *= this->IceTCompositePass->GetTileDimensions()[0];
*originY *= this->IceTCompositePass->GetTileDimensions()[1];
*width *= this->IceTCompositePass->GetTileDimensions()[0];
*height *= this->IceTCompositePass->GetTileDimensions()[1];
}
else
{
this->Superclass::GetTiledSizeAndOrigin(render_state, width, height, originX, originY);
}
}
virtual void ReleaseGraphicsResources(vtkWindow *window)
{
if (this->IceTCompositePass)
{
this->IceTCompositePass->ReleaseGraphicsResources(window);
}
this->Superclass::ReleaseGraphicsResources(window);
}
protected:
vtkMyCameraPass() {this->IceTCompositePass = NULL; }
~vtkMyCameraPass() { this->SetIceTCompositePass(0); }
};
vtkStandardNewMacro(vtkMyCameraPass);
// vtkPVIceTCompositePass extends vtkIceTCompositePass to add some ParaView
// specific rendering tweaks eg.
// * render to full viewport
// * don't let IceT paste back rendered images to the active frame buffer.
class vtkPVIceTCompositePass : public vtkIceTCompositePass
{
public:
vtkTypeMacro(vtkPVIceTCompositePass, vtkIceTCompositePass);
static vtkPVIceTCompositePass* New();
// Description:
// Updates some IceT context parameters to suit ParaView's need esp. in
// multi-view configuration.
virtual void SetupContext(const vtkRenderState* render_state)
{
vtkOpenGLClearErrorMacro();
this->Superclass::SetupContext(render_state);
// Don't make icet render the composited image to the screen. We'll paste it
// explicitly if needed. This is required since IceT/Viewport interactions
// lead to weird results in multi-view configurations. Much easier to simply
// paste back the image to the correct region after icet has rendered.
icetDisable(ICET_GL_DISPLAY);
icetDisable(ICET_GL_DISPLAY_INFLATE);
if (render_state->GetFrameBuffer() == NULL)
{
vtkRenderWindow* window = render_state->GetRenderer()->GetRenderWindow();
int *size = window->GetActualSize();
glViewport(0, 0, size[0], size[1]);
}
glDisable(GL_SCISSOR_TEST);
double background[3];
render_state->GetRenderer()->GetBackground(background);
// gradient background is not going to work correctly when using volume
// rendering or translucent geometry, but otherwise if should work fine. We
// set the background color so that solid background works correctly for
// these two cases.
glClearColor((GLclampf)background[0], (GLclampf)background[1],
(GLclampf)background[2], 0.0f);
icetEnable(ICET_CORRECT_COLORED_BACKGROUND);
vtkOpenGLCheckErrorMacro("failed after setup context");
}
protected:
vtkPVIceTCompositePass()
{
vtkPVDefaultPass* defaultPass = vtkPVDefaultPass::New();
this->SetRenderPass(defaultPass);
defaultPass->Delete();
}
~vtkPVIceTCompositePass()
{
}
};
vtkStandardNewMacro(vtkPVIceTCompositePass);
};
vtkStandardNewMacro(vtkIceTSynchronizedRenderers);
//vtkCxxSetObjectMacro(vtkIceTSynchronizedRenderers, ImageProcessingPass, vtkImageProcessingPass);
//----------------------------------------------------------------------------
vtkIceTSynchronizedRenderers::vtkIceTSynchronizedRenderers()
{
// First thing we do is create the ice-t render pass. This is essential since
// most methods calls on this class simply forward it to the ice-t render
// pass.
this->IceTCompositePass = vtkPVIceTCompositePass::New();
vtkMyCameraPass* cameraPass = vtkMyCameraPass::New();
cameraPass->SetDelegatePass(this->IceTCompositePass);
cameraPass->SetIceTCompositePass(this->IceTCompositePass);
this->CameraRenderPass = cameraPass;
this->SetParallelController(vtkMultiProcessController::GetGlobalController());
this->ImagePastingPass = vtkMyImagePasterPass::New();
this->ImageProcessingPass = NULL;
this->RenderPass = NULL;
this->Identifier = 0;
}
//----------------------------------------------------------------------------
vtkIceTSynchronizedRenderers::~vtkIceTSynchronizedRenderers()
{
vtkTileDisplayHelper::GetInstance()->EraseTile(this->Identifier);
this->ImagePastingPass->Delete();
this->IceTCompositePass->Delete();
this->IceTCompositePass = 0;
this->CameraRenderPass->Delete();
this->CameraRenderPass = 0;
this->SetImageProcessingPass(0);
this->SetRenderPass(0);
}
//----------------------------------------------------------------------------
void vtkIceTSynchronizedRenderers::SetImageProcessingPass(
vtkImageProcessingPass* pass)
{
vtkSetObjectBodyMacro(ImageProcessingPass, vtkImageProcessingPass, pass);
if (pass && this->Renderer)
{
int tile_dims[2];
this->IceTCompositePass->GetTileDimensions(tile_dims);
if (tile_dims[0] >= 1 && tile_dims[1] >= 1)
{
this->CameraRenderPass->SetAspectRatioOverride(tile_dims[0]*1.0/tile_dims[1]);
}
this->ImagePastingPass->DelegatePass = this->CameraRenderPass;
this->ImagePastingPass->IceTCompositePass = this->IceTCompositePass;
pass->SetDelegatePass(this->ImagePastingPass);
this->Renderer->SetPass(pass);
}
else if (this->Renderer && this->CameraRenderPass)
{
this->CameraRenderPass->SetAspectRatioOverride(1.0);
this->Renderer->SetPass(this->CameraRenderPass);
}
}
//----------------------------------------------------------------------------
void vtkIceTSynchronizedRenderers::SetUseDepthBuffer(bool useDB)
{
this->ImagePastingPass->SetUseDepthBuffer(useDB);
}
//----------------------------------------------------------------------------
void vtkIceTSynchronizedRenderers::SetRenderPass(vtkRenderPass *pass)
{
vtkSetObjectBodyMacro(RenderPass, vtkRenderPass, pass);
if (this->IceTCompositePass)
{
if (pass)
{
this->IceTCompositePass->SetRenderPass(pass);
}
else
{
vtkPVDefaultPass* defaultPass = vtkPVDefaultPass::New();
this->IceTCompositePass->SetRenderPass(defaultPass);
defaultPass->Delete();
}
}
}
//----------------------------------------------------------------------------
void vtkIceTSynchronizedRenderers::HandleEndRender()
{
if (this->WriteBackImages)
{
this->WriteBackImages = false;
this->Superclass::HandleEndRender();
this->WriteBackImages = true;
}
else
{
this->Superclass::HandleEndRender();
}
if (this->WriteBackImages)
{
vtkSynchronizedRenderers::vtkRawImage lastRenderedImage =
this->CaptureRenderedImage();
if (lastRenderedImage.IsValid())
{
double viewport[4];
this->IceTCompositePass->GetPhysicalViewport(viewport);
vtkTileDisplayHelper::GetInstance()->SetTile(this->Identifier,
viewport, this->Renderer,
lastRenderedImage);
}
else
{
vtkTileDisplayHelper::GetInstance()->EraseTile(this->Identifier);
}
// Write-back either the freshly rendered tile or what was most recently
// rendered.
vtkTileDisplayHelper::GetInstance()->FlushTiles(this->Identifier,
this->Renderer->GetActiveCamera()->GetLeftEye());
}
}
//----------------------------------------------------------------------------
void vtkIceTSynchronizedRenderers::SetRenderer(vtkRenderer* ren)
{
if (this->Renderer && this->Renderer->GetPass() == this->CameraRenderPass)
{
this->Renderer->SetPass(NULL);
}
this->Superclass::SetRenderer(ren);
if (ren)
{
this->Renderer->SetPass(this->CameraRenderPass);
// icet cannot work correctly in tile-display mode is software culling is
// applied in vtkRenderer inself. vtkPVIceTCompositePass will cull out-of-frustum
// props using icet-model-view matrix later.
ren->GetCullers()->RemoveAllItems();
}
}
//----------------------------------------------------------------------------
void vtkIceTSynchronizedRenderers::SetRenderEmptyImages(bool useREI)
{
this->IceTCompositePass->SetRenderEmptyImages(useREI);
}
//----------------------------------------------------------------------------
void vtkIceTSynchronizedRenderers::SetImageReductionFactor(int val)
{
// Don't call superclass. Since ice-t has better mechanisms for dealing with
// image reduction factor rather than simply reducing the viewport. This
// ensures that it works nicely in tile-display mode as well.
// this->Superclass::SetImageReductionFactor(val);
this->IceTCompositePass->SetImageReductionFactor(val);
}
//----------------------------------------------------------------------------
vtkSynchronizedRenderers::vtkRawImage&
vtkIceTSynchronizedRenderers::CaptureRenderedImage()
{
// We capture the image from IceTCompositePass. This avoids the capture of
// buffer from screen when not necessary.
vtkRawImage& rawImage =
(this->GetImageReductionFactor() == 1)?
this->FullImage : this->ReducedImage;
if (!rawImage.IsValid())
{
this->IceTCompositePass->GetLastRenderedTile(rawImage);
if (rawImage.IsValid() && this->ImageProcessingPass)
{
// When using an image processing pass, we simply capture the result from
// the active buffer. However, we do that, only when IceT produced some
// valid result on this process.
rawImage.Capture(this->Renderer);
}
}
return rawImage;
}
//----------------------------------------------------------------------------
void vtkIceTSynchronizedRenderers::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}