/*========================================================================= Program: Visualization Toolkit Module: vtkThreadedImageAlgorithm.cxx 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" //---------------------------------------------------------------------------- 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 = static_cast(ceil(range/static_cast(total))); int maxThreadIdUsed = static_cast(ceil(range/static_cast(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: ( " <(arg)->ThreadID; threadCount = static_cast(arg)->NumberOfThreads; str = static_cast (static_cast(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; bool found = false; 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); found = true; break; } } if (!found) { 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 = vtkImageData::SafeDownCast( info->Get(vtkDataObject::DATA_OBJECT())); str.Outputs[i] = outData; if (outData) { int updateExtent[6]; info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), updateExtent); // unlike geometry filters, for image filters data is pre-allocated // in the superclass (which means, in this class) this->AllocateOutputData(outData, info, 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] = vtkImageData::SafeDownCast( 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 bool debug = this->Debug; this->Debug = false; this->Threader->SingleMethodExecute(); this->Debug = debug; // free up the arrays for (i = 0; i < this->GetNumberOfInputPorts(); ++i) { delete [] str.Inputs[i]; } delete [] str.Inputs; 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 * inData, vtkImageData * outData, int extent[6], int threadId) { (void)inData; (void)outData; (void)extent; (void)threadId; vtkErrorMacro("Subclass should override this method!!!"); }