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);
 | |
| }
 | |
| 
 |