Cloned library of VTK-5.0.0 with extra build files for internal package management.
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.
 
 
 
 
 
 

341 lines
11 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkThreadedImageAlgorithm.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 "vtkThreadedImageAlgorithm.h"
#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkDataArray.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMultiThreader.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkTrivialProducer.h"
vtkCxxRevisionMacro(vtkThreadedImageAlgorithm, "$Revision: 1.11 $");
//----------------------------------------------------------------------------
vtkThreadedImageAlgorithm::vtkThreadedImageAlgorithm()
{
this->Threader = vtkMultiThreader::New();
this->NumberOfThreads = this->Threader->GetNumberOfThreads();
}
//----------------------------------------------------------------------------
vtkThreadedImageAlgorithm::~vtkThreadedImageAlgorithm()
{
this->Threader->Delete();
}
//----------------------------------------------------------------------------
void vtkThreadedImageAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "NumberOfThreads: " << this->NumberOfThreads << "\n";
}
struct vtkImageThreadStruct
{
vtkThreadedImageAlgorithm *Filter;
vtkInformation *Request;
vtkInformationVector **InputsInfo;
vtkInformationVector *OutputsInfo;
vtkImageData ***Inputs;
vtkImageData **Outputs;
};
//----------------------------------------------------------------------------
// For streaming and threads. Splits output update extent into num pieces.
// This method needs to be called num times. Results must not overlap for
// consistent starting extent. Subclass can override this method.
// This method returns the number of peices resulting from a successful split.
// This can be from 1 to "total".
// If 1 is returned, the extent cannot be split.
int vtkThreadedImageAlgorithm::SplitExtent(int splitExt[6],
int startExt[6],
int num, int total)
{
int splitAxis;
int min, max;
vtkDebugMacro("SplitExtent: ( " << startExt[0] << ", " << startExt[1] << ", "
<< startExt[2] << ", " << startExt[3] << ", "
<< startExt[4] << ", " << startExt[5] << "), "
<< num << " of " << total);
// start with same extent
memcpy(splitExt, startExt, 6 * sizeof(int));
splitAxis = 2;
min = startExt[4];
max = startExt[5];
while (min >= max)
{
// empty extent so cannot split
if (min > max)
{
return 1;
}
--splitAxis;
if (splitAxis < 0)
{ // cannot split
vtkDebugMacro(" Cannot Split");
return 1;
}
min = startExt[splitAxis*2];
max = startExt[splitAxis*2+1];
}
// determine the actual number of pieces that will be generated
int range = max - min + 1;
int valuesPerThread = (int)ceil(range/(double)total);
int maxThreadIdUsed = (int)ceil(range/(double)valuesPerThread) - 1;
if (num < maxThreadIdUsed)
{
splitExt[splitAxis*2] = splitExt[splitAxis*2] + num*valuesPerThread;
splitExt[splitAxis*2+1] = splitExt[splitAxis*2] + valuesPerThread - 1;
}
if (num == maxThreadIdUsed)
{
splitExt[splitAxis*2] = splitExt[splitAxis*2] + num*valuesPerThread;
}
vtkDebugMacro(" Split Piece: ( " <<splitExt[0]<< ", " <<splitExt[1]<< ", "
<< splitExt[2] << ", " << splitExt[3] << ", "
<< splitExt[4] << ", " << splitExt[5] << ")");
return maxThreadIdUsed + 1;
}
// this mess is really a simple function. All it does is call
// the ThreadedExecute method after setting the correct
// extent for this thread. Its just a pain to calculate
// the correct extent.
VTK_THREAD_RETURN_TYPE vtkThreadedImageAlgorithmThreadedExecute( void *arg )
{
vtkImageThreadStruct *str;
int ext[6], splitExt[6], total;
int threadId, threadCount;
threadId = ((vtkMultiThreader::ThreadInfo *)(arg))->ThreadID;
threadCount = ((vtkMultiThreader::ThreadInfo *)(arg))->NumberOfThreads;
str = (vtkImageThreadStruct *)
(((vtkMultiThreader::ThreadInfo *)(arg))->UserData);
// if we have an output
if (str->Filter->GetNumberOfOutputPorts())
{
// which output port did the request come from
int outputPort =
str->Request->Get(vtkDemandDrivenPipeline::FROM_OUTPUT_PORT());
// if output port is negative then that means this filter is calling the
// update directly, for now an error
if (outputPort == -1)
{
return VTK_THREAD_RETURN_VALUE;
}
// get the update extent from the output port
vtkInformation *outInfo =
str->OutputsInfo->GetInformationObject(outputPort);
int updateExtent[6];
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
updateExtent);
memcpy(ext,updateExtent, sizeof(int)*6);
}
else
{
// if there is no output, then use UE from input, use the first input
int inPort;
for (inPort = 0; inPort < str->Filter->GetNumberOfInputPorts(); ++inPort)
{
if (str->Filter->GetNumberOfInputConnections(inPort))
{
int updateExtent[6];
str->InputsInfo[inPort]
->GetInformationObject(0)
->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
updateExtent);
memcpy(ext,updateExtent, sizeof(int)*6);
break;
}
}
if (inPort >= str->Filter->GetNumberOfInputPorts())
{
return VTK_THREAD_RETURN_VALUE;
}
}
// execute the actual method with appropriate extent
// first find out how many pieces extent can be split into.
total = str->Filter->SplitExtent(splitExt, ext, threadId, threadCount);
if (threadId < total)
{
// return if nothing to do
if (splitExt[1] < splitExt[0] ||
splitExt[3] < splitExt[2] ||
splitExt[5] < splitExt[4])
{
return VTK_THREAD_RETURN_VALUE;
}
str->Filter->ThreadedRequestData(str->Request,
str->InputsInfo, str->OutputsInfo,
str->Inputs, str->Outputs,
splitExt, threadId);
}
// else
// {
// otherwise don't use this thread. Sometimes the threads dont
// break up very well and it is just as efficient to leave a
// few threads idle.
// }
return VTK_THREAD_RETURN_VALUE;
}
//----------------------------------------------------------------------------
// This is the superclasses style of Execute method. Convert it into
// an imaging style Execute method.
int vtkThreadedImageAlgorithm::RequestData(
vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
{
int i;
// setup the threasd structure
vtkImageThreadStruct str;
str.Filter = this;
str.Request = request;
str.InputsInfo = inputVector;
str.OutputsInfo = outputVector;
// now we must create the output array
str.Outputs = 0;
if (this->GetNumberOfOutputPorts())
{
str.Outputs = new vtkImageData * [this->GetNumberOfOutputPorts()];
for (i = 0; i < this->GetNumberOfOutputPorts(); ++i)
{
vtkInformation* info = outputVector->GetInformationObject(i);
vtkImageData *outData = static_cast<vtkImageData *>(
info->Get(vtkDataObject::DATA_OBJECT()));
str.Outputs[i] = outData;
int updateExtent[6];
info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
updateExtent);
// for image filters as a convenience we usually allocate the output data
// in the superclass
this->AllocateOutputData(outData, updateExtent);
}
}
// now create the inputs array
str.Inputs = 0;
if (this->GetNumberOfInputPorts())
{
str.Inputs = new vtkImageData ** [this->GetNumberOfInputPorts()];
for (i = 0; i < this->GetNumberOfInputPorts(); ++i)
{
str.Inputs[i] = 0;
vtkInformationVector* portInfo = inputVector[i];
if (portInfo->GetNumberOfInformationObjects())
{
int j;
str.Inputs[i] =
new vtkImageData *[portInfo->GetNumberOfInformationObjects()];
for (j = 0; j < portInfo->GetNumberOfInformationObjects(); ++j)
{
vtkInformation* info = portInfo->GetInformationObject(j);
str.Inputs[i][j] =
static_cast<vtkImageData*>(info->Get(vtkDataObject::DATA_OBJECT()));
}
}
}
}
// copy other arrays
if (str.Inputs && str.Inputs[0] && str.Outputs)
{
this->CopyAttributeData(str.Inputs[0][0],str.Outputs[0],inputVector);
}
this->Threader->SetNumberOfThreads(this->NumberOfThreads);
this->Threader->SetSingleMethod(vtkThreadedImageAlgorithmThreadedExecute, &str);
// always shut off debugging to avoid threading problems with GetMacros
int debug = this->Debug;
this->Debug = 0;
this->Threader->SingleMethodExecute();
this->Debug = debug;
// free up the arrays
for (i = 0; i < this->GetNumberOfInputPorts(); ++i)
{
if (str.Inputs[i])
{
delete [] str.Inputs[i];
}
}
// note the check isn't required by C++ standard but due to bad compilers
if (str.Inputs)
{
delete [] str.Inputs;
}
if (str.Outputs)
{
delete [] str.Outputs;
}
return 1;
}
//----------------------------------------------------------------------------
// The execute method created by the subclass.
void vtkThreadedImageAlgorithm::ThreadedRequestData(
vtkInformation* vtkNotUsed( request ),
vtkInformationVector** vtkNotUsed( inputVector ),
vtkInformationVector* vtkNotUsed( outputVector ),
vtkImageData ***inData,
vtkImageData **outData,
int extent[6],
int threadId)
{
this->ThreadedExecute(inData[0][0], outData[0], extent, threadId);
}
//----------------------------------------------------------------------------
// The execute method created by the subclass.
void vtkThreadedImageAlgorithm::ThreadedExecute(
vtkImageData *vtkNotUsed(inData),
vtkImageData *vtkNotUsed(outData),
int extent[6],
int vtkNotUsed(threadId))
{
extent = extent;
vtkErrorMacro("Subclass should override this method!!!");
}