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.
314 lines
9.6 KiB
314 lines
9.6 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkImageMultipleInputFilter.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 "vtkImageMultipleInputFilter.h"
|
|
|
|
#include "vtkImageData.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkMultiThreader.h"
|
|
#include "vtkObjectFactory.h"
|
|
|
|
vtkCxxRevisionMacro(vtkImageMultipleInputFilter, "$Revision: 1.66 $");
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkImageMultipleInputFilter::vtkImageMultipleInputFilter()
|
|
{
|
|
this->NumberOfInputs = 0;
|
|
this->NumberOfRequiredInputs = 1;
|
|
this->SetNumberOfInputPorts(1);
|
|
this->Bypass = 0;
|
|
|
|
this->Threader = vtkMultiThreader::New();
|
|
this->NumberOfThreads = this->Threader->GetNumberOfThreads();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkImageMultipleInputFilter::~vtkImageMultipleInputFilter()
|
|
{
|
|
this->Threader->Delete();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMultipleInputFilter::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "NumberOfThreads: " << this->NumberOfThreads << "\n";
|
|
if ( this->Bypass )
|
|
{
|
|
os << indent << "Bypass: On\n";
|
|
}
|
|
else
|
|
{
|
|
os << indent << "Bypass: Off\n";
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Adds an input to the first null position in the input list.
|
|
// Expands the list memory if necessary
|
|
void vtkImageMultipleInputFilter::AddInput(vtkImageData *input)
|
|
{
|
|
this->vtkProcessObject::AddInput(input);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMultipleInputFilter::RemoveInput(vtkImageData *input)
|
|
{
|
|
this->vtkProcessObject::RemoveInput(input);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set an Input of this filter.
|
|
void vtkImageMultipleInputFilter::SetInput(int idx, vtkImageData *input)
|
|
{
|
|
this->vtkProcessObject::SetNthInput(idx, input);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkImageData *vtkImageMultipleInputFilter::GetInput()
|
|
{
|
|
return this->GetInput(0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkImageData *vtkImageMultipleInputFilter::GetInput(int idx)
|
|
{
|
|
if (this->NumberOfInputs <= idx)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return (vtkImageData*)(this->Inputs[idx]);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMultipleInputFilter::ExecuteInformation()
|
|
{
|
|
vtkImageData *output = this->GetOutput();
|
|
vtkImageData *input = this->GetInput(0);
|
|
|
|
if ( input == NULL || output == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Set the defaults from input1
|
|
output->CopyTypeSpecificInformation(input);
|
|
|
|
// Let the subclass modify the default.
|
|
this->ExecuteInformation((vtkImageData**)(this->Inputs), output);
|
|
}
|
|
|
|
// Call the alternate version of this method, and use the returned input
|
|
// update extent for all inputs
|
|
void vtkImageMultipleInputFilter::ComputeInputUpdateExtents( vtkDataObject
|
|
*output )
|
|
{
|
|
int outExt[6], inExt[6];
|
|
|
|
output->GetUpdateExtent( outExt );
|
|
|
|
for (int idx = 0; idx < this->NumberOfInputs; idx++)
|
|
{
|
|
if (this->Inputs[idx] != NULL)
|
|
{
|
|
this->ComputeInputUpdateExtent( inExt, outExt, idx );
|
|
this->Inputs[idx]->SetUpdateExtent( inExt );
|
|
}
|
|
}
|
|
}
|
|
|
|
// By default, simply set the input update extent to match the given output
|
|
// extent
|
|
void vtkImageMultipleInputFilter::ComputeInputUpdateExtent(
|
|
int inExt[6],
|
|
int outExt[6],
|
|
int vtkNotUsed(whichInput) )
|
|
{
|
|
memcpy(inExt,outExt,sizeof(int)*6);
|
|
}
|
|
|
|
|
|
struct vtkImageMultiThreadStruct
|
|
{
|
|
vtkImageMultipleInputFilter *Filter;
|
|
vtkImageData **Inputs;
|
|
vtkImageData *Output;
|
|
};
|
|
|
|
// 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 vtkImageMultiThreadedExecute( void *arg )
|
|
{
|
|
vtkImageMultiThreadStruct *str;
|
|
int ext[6], splitExt[6], total;
|
|
int threadId, threadCount;
|
|
|
|
threadId = ((vtkMultiThreader::ThreadInfo *)(arg))->ThreadID;
|
|
threadCount = ((vtkMultiThreader::ThreadInfo *)(arg))->NumberOfThreads;
|
|
|
|
str = (vtkImageMultiThreadStruct *)(((vtkMultiThreader::ThreadInfo *)(arg))->UserData);
|
|
|
|
memcpy(ext,str->Filter->GetOutput()->GetUpdateExtent(),
|
|
sizeof(int)*6);
|
|
|
|
// 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)
|
|
{
|
|
str->Filter->ThreadedExecute(str->Inputs, str->Output, 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;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// The execute method created by the subclass.
|
|
void vtkImageMultipleInputFilter::ExecuteData(vtkDataObject *out)
|
|
{
|
|
// Make sure the Input has been set.
|
|
if ( this->GetInput() == NULL )
|
|
{
|
|
vtkErrorMacro(<< "ExecuteData: Input is not set.");
|
|
return;
|
|
}
|
|
|
|
// Too many filters have floating point exceptions to execute
|
|
// with empty input/ no request.
|
|
if (this->UpdateExtentIsEmpty(out))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
vtkImageData *outdata = this->AllocateOutputData(out);
|
|
this->MultiThread((vtkImageData**)this->GetInputs(), outdata);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageMultipleInputFilter::MultiThread(vtkImageData **inputs, vtkImageData *output)
|
|
{
|
|
vtkImageMultiThreadStruct str;
|
|
|
|
str.Filter = this;
|
|
str.Inputs = inputs;
|
|
str.Output = output;
|
|
|
|
this->Threader->SetNumberOfThreads(this->NumberOfThreads);
|
|
|
|
// setup threading and the invoke threadedExecute
|
|
this->Threader->SetSingleMethod(vtkImageMultiThreadedExecute, &str);
|
|
this->Threader->SingleMethodExecute();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// The execute method created by the subclass.
|
|
void vtkImageMultipleInputFilter::ThreadedExecute(vtkImageData
|
|
**vtkNotUsed(inData),
|
|
vtkImageData *vtkNotUsed(outData),
|
|
int extent[6], int threadId)
|
|
{
|
|
extent = extent;
|
|
if (threadId == 0)
|
|
{
|
|
vtkErrorMacro("subclass must override ThreadedExecute!!!");
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// 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 vtkImageMultipleInputFilter::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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkImageMultipleInputFilter::FillInputPortInformation(int port,
|
|
vtkInformation* info)
|
|
{
|
|
if(!this->Superclass::FillInputPortInformation(port, info))
|
|
{
|
|
return 0;
|
|
}
|
|
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
|
|
return 1;
|
|
}
|
|
|