You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
386 lines
12 KiB
386 lines
12 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkPipelineSize.cxx,v $
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm 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 "vtkPipelineSize.h"
|
|
|
|
#include "vtkAlgorithmOutput.h"
|
|
#include "vtkConeSource.h"
|
|
#include "vtkDataObject.h"
|
|
#include "vtkDataReader.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkLargeInteger.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPSphereSource.h"
|
|
#include "vtkPlaneSource.h"
|
|
#include "vtkPolyData.h"
|
|
#include "vtkPolyDataMapper.h"
|
|
#include "vtkDataSetAttributes.h"
|
|
#include "vtkStreamingDemandDrivenPipeline.h"
|
|
|
|
vtkCxxRevisionMacro(vtkPipelineSize, "$Revision: 1.15 $");
|
|
vtkStandardNewMacro(vtkPipelineSize);
|
|
|
|
unsigned long
|
|
vtkPipelineSize::GetEstimatedSize(vtkAlgorithm *input, int inputPort,
|
|
int connection)
|
|
{
|
|
unsigned long sizes[3];
|
|
unsigned long memorySize = 0;
|
|
|
|
|
|
if(vtkAlgorithmOutput* inInfo =
|
|
input->GetInputConnection(inputPort, connection))
|
|
{
|
|
if (vtkAlgorithm* srcAlg =
|
|
vtkAlgorithm::SafeDownCast(
|
|
inInfo->GetProducer()))
|
|
{
|
|
this->ComputeSourcePipelineSize(srcAlg, inInfo->GetIndex(), sizes );
|
|
memorySize = sizes[2];
|
|
}
|
|
}
|
|
|
|
return memorySize;
|
|
}
|
|
|
|
// The first size is the memory going downstream from here - which is all
|
|
// the memory coming in minus any data realeased. The second size is the
|
|
// size of the specified output (which can be used by the downstream
|
|
// filter when determining how much data it might release). The final size
|
|
// is the maximum pipeline size encountered here and upstream from here.
|
|
void vtkPipelineSize::ComputeSourcePipelineSize(vtkAlgorithm *src,
|
|
int outputPort,
|
|
unsigned long size[3])
|
|
{
|
|
// watch for special sources
|
|
// handle vtkDataReader subclasses
|
|
if (src->IsA("vtkDataReader"))
|
|
{
|
|
ifstream *ifs;
|
|
vtkDataReader *rdr = vtkDataReader::SafeDownCast(src);
|
|
#ifdef _WIN32
|
|
ifs = new ifstream(rdr->GetFileName(), ios::in | ios::binary);
|
|
#else
|
|
ifs = new ifstream(rdr->GetFileName(), ios::in);
|
|
#endif
|
|
if (!ifs->fail())
|
|
{
|
|
ifs->seekg(0,ios::end);
|
|
int sz = ifs->tellg()/1024;
|
|
size[0] = sz;
|
|
size[1] = sz;
|
|
size[2] = sz;
|
|
return;
|
|
}
|
|
delete ifs;
|
|
}
|
|
|
|
// handle some simple sources
|
|
vtkLargeInteger sz;
|
|
if (src->IsA("vtkConeSource"))
|
|
{
|
|
vtkConeSource *s = vtkConeSource::SafeDownCast(src);
|
|
sz = s->GetResolution();
|
|
sz = sz * 32/1024;
|
|
size[0] = sz.CastToUnsignedLong();
|
|
size[1] = size[0];
|
|
size[2] = size[0];
|
|
return;
|
|
}
|
|
if (src->IsA("vtkPlaneSource"))
|
|
{
|
|
vtkPlaneSource *s = vtkPlaneSource::SafeDownCast(src);
|
|
sz = s->GetXResolution();
|
|
sz = sz * s->GetYResolution()*32/1024;
|
|
size[0] = sz.CastToUnsignedLong();
|
|
size[1] = size[0];
|
|
size[2] = size[0];
|
|
return;
|
|
}
|
|
if (src->IsA("vtkPSphereSource"))
|
|
{
|
|
vtkPSphereSource *s = vtkPSphereSource::SafeDownCast(src);
|
|
size[0] = s->GetEstimatedMemorySize();
|
|
size[1] = size[0];
|
|
size[2] = size[0];
|
|
return;
|
|
}
|
|
|
|
// otherwise use generic approach
|
|
this->GenericComputeSourcePipelineSize(src,outputPort,size);
|
|
}
|
|
|
|
void vtkPipelineSize::GenericComputeSourcePipelineSize(vtkAlgorithm *src,
|
|
int outputPort,
|
|
unsigned long size[3])
|
|
{
|
|
unsigned long outputSize[2];
|
|
unsigned long inputPipelineSize[3];
|
|
vtkLargeInteger mySize = 0;
|
|
unsigned long maxSize = 0;
|
|
vtkLargeInteger goingDownstreamSize = 0;
|
|
unsigned long *inputSize = NULL;
|
|
int idx;
|
|
|
|
// We need some space to store the input sizes if there are any inputs
|
|
int numberOfInputs = src->GetTotalNumberOfInputConnections();
|
|
if ( numberOfInputs > 0 )
|
|
{
|
|
inputSize = new unsigned long[numberOfInputs];
|
|
}
|
|
|
|
// Get the pipeline size propagated down each input. Keep track of max
|
|
// pipeline size, how much memory will be required downstream from here,
|
|
// the size of each input, and the memory required by this filter when
|
|
// it executes.
|
|
int port = 0;
|
|
int conn = 0;
|
|
for (idx = 0; idx < numberOfInputs; ++idx)
|
|
{
|
|
src->ConvertTotalInputToPortConnection(idx,port,conn);
|
|
inputSize[idx] = 0;
|
|
if(vtkAlgorithmOutput* inInfo = src->GetInputConnection(port, conn))
|
|
{
|
|
if (vtkAlgorithm* srcAlg =
|
|
vtkAlgorithm::SafeDownCast(inInfo->GetProducer()))
|
|
{
|
|
// Get the upstream size of the pipeline, the estimated size of this
|
|
// input, and the maximum size seen upstream from here.
|
|
this->ComputeSourcePipelineSize(srcAlg, inInfo->GetIndex(),
|
|
inputPipelineSize);
|
|
|
|
// Save this input size to possibly be used when estimating output size
|
|
inputSize[idx] = inputPipelineSize[1];
|
|
|
|
// Is the max returned bigger than the max we've seen so far?
|
|
if ( inputPipelineSize[2] > maxSize )
|
|
{
|
|
maxSize = inputPipelineSize[2];
|
|
}
|
|
|
|
// If we are going to release this input, then its size won't matter
|
|
// downstream from here.
|
|
vtkDemandDrivenPipeline *ddp =
|
|
vtkDemandDrivenPipeline::SafeDownCast(srcAlg->GetExecutive());
|
|
if (ddp &&
|
|
ddp->GetOutputInformation(inInfo->GetIndex())
|
|
->Get(vtkDemandDrivenPipeline::RELEASE_DATA()))
|
|
{
|
|
goingDownstreamSize = goingDownstreamSize + inputPipelineSize[0] -
|
|
inputPipelineSize[1];
|
|
}
|
|
else
|
|
{
|
|
goingDownstreamSize = goingDownstreamSize + inputPipelineSize[0];
|
|
}
|
|
|
|
// During execution this filter will need all the input data
|
|
mySize += inputPipelineSize[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now the we know the size of all input, compute the output size
|
|
this->ComputeOutputMemorySize(src, outputPort, inputSize, outputSize );
|
|
|
|
// This filter will produce all output so it needs all that memory.
|
|
// Also, all this data will flow downstream to the next source (if it is
|
|
// the requested output) or will still exist with no chance of being
|
|
// released (if it is the non-requested output)
|
|
mySize += outputSize[1];
|
|
goingDownstreamSize += outputSize[1];
|
|
|
|
// Is the state of the pipeline during this filter's execution the
|
|
// largest that it has been so far?
|
|
if ( mySize.CastToUnsignedLong() > maxSize )
|
|
{
|
|
maxSize = mySize.CastToUnsignedLong();
|
|
}
|
|
|
|
// The first size is the memory going downstream from here - which is all
|
|
// the memory coming in minus any data realeased. The second size is the
|
|
// size of the specified output (which can be used by the downstream
|
|
// filter when determining how much data it might release). The final size
|
|
// is the maximum pipeline size encountered here and upstream from here.
|
|
size[0] = goingDownstreamSize.CastToUnsignedLong();
|
|
size[1] = outputSize[0];
|
|
size[2] = maxSize;
|
|
|
|
// Delete the space we may have created
|
|
if ( inputSize )
|
|
{
|
|
delete [] inputSize;
|
|
}
|
|
}
|
|
|
|
void vtkPipelineSize::
|
|
ComputeOutputMemorySize( vtkAlgorithm *src, int outputPort,
|
|
unsigned long *inputSize, unsigned long size[2] )
|
|
{
|
|
vtkLargeInteger sz;
|
|
|
|
// watch for special filters such as Glyph3D
|
|
if (src->IsA("vtkGlyph3D"))
|
|
{
|
|
// the output size is the same as the source size * the number of points
|
|
// we guess the number of points to be 1/16 of the input size in bytes
|
|
if (src->GetTotalNumberOfInputConnections() >= 2)
|
|
{
|
|
sz = inputSize[1];
|
|
sz = sz * inputSize[0]*1024/16;
|
|
size[0] = sz.CastToUnsignedLong();
|
|
size[1] = size[0];
|
|
return;
|
|
}
|
|
}
|
|
|
|
this->GenericComputeOutputMemorySize(src, outputPort, inputSize, size);
|
|
}
|
|
|
|
|
|
|
|
void vtkPipelineSize::
|
|
GenericComputeOutputMemorySize( vtkAlgorithm *src, int outputPort,
|
|
unsigned long * vtkNotUsed( inputSize ),
|
|
unsigned long size[2] )
|
|
{
|
|
int idx;
|
|
vtkLargeInteger tmp = 0;
|
|
vtkLargeInteger sz = 0;
|
|
|
|
vtkDemandDrivenPipeline *ddp =
|
|
vtkDemandDrivenPipeline::SafeDownCast(src->GetExecutive());
|
|
|
|
size[0] = 0;
|
|
size[1] = 0;
|
|
|
|
// loop through all the outputs asking them how big they are given the
|
|
// information that they have on their update extent. Keep track of
|
|
// the size of the specified output in size[0], and the sum of all
|
|
// output size in size[1]. Ignore input sizes in this default implementation.
|
|
for (idx = 0; idx < src->GetNumberOfOutputPorts(); ++idx)
|
|
{
|
|
vtkInformation *outInfo = ddp->GetOutputInformation(idx);
|
|
if (outInfo)
|
|
{
|
|
tmp = 0;
|
|
vtkInformation *dataInfo =
|
|
outInfo->Get(vtkDataObject::DATA_OBJECT())->GetInformation();
|
|
if (dataInfo->Get(vtkDataObject::DATA_EXTENT_TYPE()) ==
|
|
VTK_PIECES_EXTENT)
|
|
{
|
|
// TODO: need something here
|
|
tmp = 1;
|
|
}
|
|
if (dataInfo->Get(vtkDataObject::DATA_EXTENT_TYPE()) == VTK_3D_EXTENT)
|
|
{
|
|
int uExt[6];
|
|
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),uExt);
|
|
tmp = 4;
|
|
|
|
vtkInformation *scalarInfo = vtkDataObject::GetActiveFieldInformation(outInfo,
|
|
vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS);
|
|
int numComp = 1;
|
|
if (scalarInfo)
|
|
{
|
|
tmp = vtkDataArray::GetDataTypeSize(
|
|
scalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()));
|
|
if (scalarInfo->Has(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()))
|
|
{
|
|
numComp = scalarInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS());
|
|
}
|
|
}
|
|
tmp *= numComp;
|
|
for (idx = 0; idx < 3; ++idx)
|
|
{
|
|
tmp = tmp*(uExt[idx*2+1] - uExt[idx*2] + 1);
|
|
}
|
|
tmp /= 1024;
|
|
}
|
|
if (idx == outputPort )
|
|
{
|
|
size[0] = tmp.CastToUnsignedLong();
|
|
}
|
|
}
|
|
sz += tmp;
|
|
}
|
|
|
|
size[1] = sz.CastToUnsignedLong();
|
|
}
|
|
|
|
|
|
unsigned long vtkPipelineSize::GetNumberOfSubPieces(unsigned long memoryLimit,
|
|
vtkPolyDataMapper *mapper)
|
|
{
|
|
// find the right number of pieces
|
|
if (!mapper->GetInput())
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
vtkPolyData *input = mapper->GetInput();
|
|
unsigned long subDivisions = 1;
|
|
unsigned long numPieces = mapper->GetNumberOfPieces();
|
|
unsigned long piece = mapper->GetPiece();
|
|
unsigned long oldSize, size = 0;
|
|
float ratio;
|
|
|
|
// watch for the limiting case where the size is the maximum size
|
|
// represented by an unsigned long. In that case we do not want to do the
|
|
// ratio test. We actual test for size < 0.5 of the max unsigned long which
|
|
// would indicate that oldSize is about at max unsigned long.
|
|
unsigned long maxSize;
|
|
maxSize = (((unsigned long)0x1) << (8*sizeof(unsigned long) - 1));
|
|
|
|
// we also have to watch how many pieces we are creating. Since
|
|
// NumberOfStreamDivisions is an int, it cannot be more that say 2^31
|
|
// (which is a bit much anyhow) so we also stop if the number of pieces is
|
|
// too large. Here we start off with the current number of pieces.
|
|
int count = (int) (log(static_cast<float>(numPieces))/log(static_cast<float>(2)));
|
|
|
|
// double the number of pieces until the size fits in memory
|
|
// or the reduction in size falls to 20%
|
|
do
|
|
{
|
|
oldSize = size;
|
|
input->SetUpdateExtent(piece*subDivisions, numPieces*subDivisions);
|
|
input->PropagateUpdateExtent();
|
|
size = this->GetEstimatedSize(mapper,0,0);
|
|
// watch for the first time through
|
|
if (!oldSize)
|
|
{
|
|
ratio = 0.5;
|
|
}
|
|
// otherwise the normal ratio calculation
|
|
else
|
|
{
|
|
ratio = size/(float)oldSize;
|
|
}
|
|
subDivisions = subDivisions*2;
|
|
count++;
|
|
}
|
|
while (size > memoryLimit &&
|
|
(size > maxSize || ratio < 0.8) && count < 29);
|
|
|
|
// undo the last *2
|
|
subDivisions = subDivisions/2;
|
|
|
|
return subDivisions;
|
|
}
|
|
|
|
void vtkPipelineSize::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
}
|
|
|