1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkCachedStreamingDemandDrivenPipeline.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkCachedStreamingDemandDrivenPipeline.h"
16
17 #include "vtkInformationIntegerKey.h"
18 #include "vtkInformationIntegerVectorKey.h"
19 #include "vtkObjectFactory.h"
20
21 #include "vtkAlgorithm.h"
22 #include "vtkAlgorithmOutput.h"
23 #include "vtkImageData.h"
24 #include "vtkInformation.h"
25 #include "vtkInformationVector.h"
26 #include "vtkPointData.h"
27
28 vtkStandardNewMacro(vtkCachedStreamingDemandDrivenPipeline);
29
30 //------------------------------------------------------------------------------
vtkCachedStreamingDemandDrivenPipeline()31 vtkCachedStreamingDemandDrivenPipeline ::vtkCachedStreamingDemandDrivenPipeline()
32 {
33 this->CacheSize = 0;
34 this->Data = nullptr;
35 this->Times = nullptr;
36
37 this->SetCacheSize(10);
38 }
39
40 //------------------------------------------------------------------------------
~vtkCachedStreamingDemandDrivenPipeline()41 vtkCachedStreamingDemandDrivenPipeline ::~vtkCachedStreamingDemandDrivenPipeline()
42 {
43 this->SetCacheSize(0);
44 }
45
46 //------------------------------------------------------------------------------
SetCacheSize(int size)47 void vtkCachedStreamingDemandDrivenPipeline::SetCacheSize(int size)
48 {
49 int idx;
50
51 if (size == this->CacheSize)
52 {
53 return;
54 }
55
56 this->Modified();
57
58 // free the old data
59 for (idx = 0; idx < this->CacheSize; ++idx)
60 {
61 if (this->Data[idx])
62 {
63 this->Data[idx]->Delete();
64 this->Data[idx] = nullptr;
65 }
66 }
67 delete[] this->Data;
68 this->Data = nullptr;
69 delete[] this->Times;
70 this->Times = nullptr;
71
72 this->CacheSize = size;
73 if (size == 0)
74 {
75 return;
76 }
77
78 this->Data = new vtkDataObject*[size];
79 this->Times = new vtkMTimeType[size];
80
81 for (idx = 0; idx < size; ++idx)
82 {
83 this->Data[idx] = nullptr;
84 this->Times[idx] = 0;
85 }
86 }
87
88 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)89 void vtkCachedStreamingDemandDrivenPipeline ::PrintSelf(ostream& os, vtkIndent indent)
90 {
91 this->Superclass::PrintSelf(os, indent);
92 os << indent << "CacheSize: " << this->CacheSize << "\n";
93 }
94
95 //------------------------------------------------------------------------------
NeedToExecuteData(int outputPort,vtkInformationVector ** inInfoVec,vtkInformationVector * outInfoVec)96 int vtkCachedStreamingDemandDrivenPipeline ::NeedToExecuteData(
97 int outputPort, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec)
98 {
99 // If no port is specified, check all ports. This behavior is
100 // implemented by the superclass.
101 if (outputPort < 0)
102 {
103 return this->Superclass::NeedToExecuteData(outputPort, inInfoVec, outInfoVec);
104 }
105
106 // Does the superclass want to execute? We must skip our direct superclass
107 // because it looks at update extents but does not know about the cache
108 // NOLINTNEXTLINE(bugprone-parent-virtual-call)
109 if (this->vtkDemandDrivenPipeline::NeedToExecuteData(outputPort, inInfoVec, outInfoVec))
110 {
111 return 1;
112 }
113
114 // Has the algorithm asked to be executed again?
115 if (this->ContinueExecuting)
116 {
117 return 1;
118 }
119
120 // First look through the cached data to see if it is still valid.
121 int i;
122 vtkMTimeType pmt = this->GetPipelineMTime();
123 for (i = 0; i < this->CacheSize; ++i)
124 {
125 if (this->Data[i] && this->Times[i] < pmt)
126 {
127 this->Data[i]->Delete();
128 this->Data[i] = nullptr;
129 this->Times[i] = 0;
130 }
131 }
132
133 // We need to check the requested update extent. Get the output
134 // port information and data information. We do not need to check
135 // existence of values because it has already been verified by
136 // VerifyOutputInformation.
137 vtkInformation* outInfo = outInfoVec->GetInformationObject(outputPort);
138 vtkDataObject* dataObject = outInfo->Get(vtkDataObject::DATA_OBJECT());
139 vtkInformation* dataInfo = dataObject->GetInformation();
140 if (dataInfo->Get(vtkDataObject::DATA_EXTENT_TYPE()) == VTK_PIECES_EXTENT)
141 {
142 int updatePiece = outInfo->Get(UPDATE_PIECE_NUMBER());
143 int updateNumberOfPieces = outInfo->Get(UPDATE_NUMBER_OF_PIECES());
144 int updateGhostLevel = outInfo->Get(UPDATE_NUMBER_OF_GHOST_LEVELS());
145
146 // check to see if any data in the cache fits this request
147 for (i = 0; i < this->CacheSize; ++i)
148 {
149 if (this->Data[i])
150 {
151 dataInfo = this->Data[i]->GetInformation();
152
153 // Check the unstructured extent. If we do not have the requested
154 // piece, we need to execute.
155 int dataPiece = dataInfo->Get(vtkDataObject::DATA_PIECE_NUMBER());
156 int dataNumberOfPieces = dataInfo->Get(vtkDataObject::DATA_NUMBER_OF_PIECES());
157 int dataGhostLevel = dataInfo->Get(vtkDataObject::DATA_NUMBER_OF_GHOST_LEVELS());
158 if (dataInfo->Get(vtkDataObject::DATA_EXTENT_TYPE()) == VTK_PIECES_EXTENT &&
159 dataPiece == updatePiece && dataNumberOfPieces == updateNumberOfPieces &&
160 dataGhostLevel == updateGhostLevel)
161 {
162 // we have a matching data we must copy it to our output, but for
163 // now we don't support polydata
164 return 1;
165 }
166 }
167 }
168 }
169 else if (dataInfo->Get(vtkDataObject::DATA_EXTENT_TYPE()) == VTK_3D_EXTENT)
170 {
171 // Check the structured extent. If the update extent is outside
172 // of the extent and not empty, we need to execute.
173 int dataExtent[6];
174 int updateExtent[6];
175 outInfo->Get(UPDATE_EXTENT(), updateExtent);
176
177 // check to see if any data in the cache fits this request
178 for (i = 0; i < this->CacheSize; ++i)
179 {
180 if (this->Data[i])
181 {
182 dataInfo = this->Data[i]->GetInformation();
183 dataInfo->Get(vtkDataObject::DATA_EXTENT(), dataExtent);
184 if (dataInfo->Get(vtkDataObject::DATA_EXTENT_TYPE()) == VTK_3D_EXTENT &&
185 !(updateExtent[0] < dataExtent[0] || updateExtent[1] > dataExtent[1] ||
186 updateExtent[2] < dataExtent[2] || updateExtent[3] > dataExtent[3] ||
187 updateExtent[4] < dataExtent[4] || updateExtent[5] > dataExtent[5]) &&
188 (updateExtent[0] <= updateExtent[1] && updateExtent[2] <= updateExtent[3] &&
189 updateExtent[4] <= updateExtent[5]))
190 {
191 // we have a match
192 // Pass this data to output.
193 vtkImageData* id = vtkImageData::SafeDownCast(dataObject);
194 vtkImageData* id2 = vtkImageData::SafeDownCast(this->Data[i]);
195 if (id && id2)
196 {
197 id->SetExtent(dataExtent);
198 id->GetPointData()->PassData(id2->GetPointData());
199 // not sure if we need this
200 dataObject->DataHasBeenGenerated();
201 return 0;
202 }
203 }
204 }
205 }
206 }
207
208 // We do need to execute
209 return 1;
210 }
211
212 //------------------------------------------------------------------------------
ExecuteData(vtkInformation * request,vtkInformationVector ** inInfoVec,vtkInformationVector * outInfoVec)213 int vtkCachedStreamingDemandDrivenPipeline ::ExecuteData(
214 vtkInformation* request, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec)
215 {
216 // only works for one in one out algorithms
217 if (request->Get(FROM_OUTPUT_PORT()) != 0)
218 {
219 vtkErrorMacro("vtkCachedStreamingDemandDrivenPipeline can only be used for algorithms with one "
220 "output and one input");
221 return 0;
222 }
223
224 // first do the usual thing
225 int result = this->Superclass::ExecuteData(request, inInfoVec, outInfoVec);
226
227 // then save the newly generated data
228 vtkMTimeType bestTime = VTK_INT_MAX;
229 int bestIdx = 0;
230
231 // Save the image in cache.
232 // Find a spot to put the data.
233 for (int i = 0; i < this->CacheSize; ++i)
234 {
235 if (this->Data[i] == nullptr)
236 {
237 bestIdx = i;
238 break;
239 }
240 if (this->Times[i] < bestTime)
241 {
242 bestIdx = i;
243 bestTime = this->Times[i];
244 }
245 }
246
247 vtkInformation* outInfo = outInfoVec->GetInformationObject(0);
248 vtkDataObject* dataObject = outInfo->Get(vtkDataObject::DATA_OBJECT());
249 if (this->Data[bestIdx] == nullptr)
250 {
251 this->Data[bestIdx] = dataObject->NewInstance();
252 }
253 this->Data[bestIdx]->ReleaseData();
254
255 vtkImageData* id = vtkImageData::SafeDownCast(dataObject);
256 if (id)
257 {
258 vtkInformation* inInfo = inInfoVec[0]->GetInformationObject(0);
259 vtkImageData* input = vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
260 id->SetExtent(input->GetExtent());
261 id->GetPointData()->PassData(input->GetPointData());
262 id->DataHasBeenGenerated();
263 }
264
265 vtkImageData* id2 = vtkImageData::SafeDownCast(this->Data[bestIdx]);
266 if (id && id2)
267 {
268 id2->SetExtent(id->GetExtent());
269 id2->GetPointData()->SetScalars(id->GetPointData()->GetScalars());
270 }
271
272 this->Times[bestIdx] = dataObject->GetUpdateTime();
273
274 return result;
275 }
276