30f0ad28 |
1 | // Created on: 2013-09-19 |
2 | // Created by: Denis BOGOLEPOV |
d5f74e42 |
3 | // Copyright (c) 2013-2014 OPEN CASCADE SAS |
30f0ad28 |
4 | // |
973c2be1 |
5 | // This file is part of Open CASCADE Technology software library. |
30f0ad28 |
6 | // |
d5f74e42 |
7 | // This library is free software; you can redistribute it and/or modify it under |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
973c2be1 |
9 | // by the Free Software Foundation, with special exception defined in the file |
10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
11 | // distribution for complete text of the license and disclaimer of any warranty. |
30f0ad28 |
12 | // |
973c2be1 |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
30f0ad28 |
15 | |
16 | #include <Graphic3d_ShaderObject.hxx> |
d95f5ce1 |
17 | #include <Message_Messenger.hxx> |
30f0ad28 |
18 | #include <OpenGl_Context.hxx> |
19 | #include <OpenGl_ShaderObject.hxx> |
d95f5ce1 |
20 | #include <OSD_File.hxx> |
30f0ad28 |
21 | #include <OSD_Path.hxx> |
d95f5ce1 |
22 | #include <OSD_Process.hxx> |
23 | #include <OSD_Protection.hxx> |
30f0ad28 |
24 | #include <Standard_Assert.hxx> |
25 | #include <TCollection_AsciiString.hxx> |
2bda8346 |
26 | #include <TCollection_ExtendedString.hxx> |
30f0ad28 |
27 | |
7c65581d |
28 | #ifdef _WIN32 |
29 | #include <malloc.h> // for alloca() |
30 | #endif |
30f0ad28 |
31 | |
92efcf78 |
32 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderObject,OpenGl_Resource) |
33 | |
2bda8346 |
34 | //! Puts line numbers to the output of GLSL program source code. |
35 | static TCollection_AsciiString putLineNumbers (const TCollection_AsciiString& theSource) |
36 | { |
37 | std::stringstream aStream; |
38 | theSource.Print (aStream); |
39 | std::string aLine; |
40 | Standard_Integer aLineNumber = 1; |
41 | TCollection_AsciiString aResultSource; |
42 | while (std::getline (aStream, aLine)) |
43 | { |
44 | TCollection_AsciiString anAsciiString = TCollection_AsciiString (aLine.c_str()); |
45 | anAsciiString.Prepend (TCollection_AsciiString ("\n") + TCollection_AsciiString (aLineNumber) + ": "); |
46 | aResultSource += anAsciiString; |
47 | aLineNumber++; |
48 | } |
49 | return aResultSource; |
50 | } |
51 | |
737e9a8d |
52 | //! Return GLSL shader stage title. |
53 | static TCollection_AsciiString getShaderTypeString (GLenum theType) |
54 | { |
55 | switch (theType) |
56 | { |
57 | case GL_VERTEX_SHADER: return "Vertex Shader"; |
58 | case GL_FRAGMENT_SHADER: return "Fragment Shader"; |
59 | case GL_GEOMETRY_SHADER: return "Geometry Shader"; |
60 | case GL_TESS_CONTROL_SHADER: return "Tessellation Control Shader"; |
61 | case GL_TESS_EVALUATION_SHADER: return "Tessellation Evaluation Shader"; |
62 | case GL_COMPUTE_SHADER: return "Compute Shader"; |
63 | } |
64 | return "Shader"; |
65 | } |
66 | |
3b4c6945 |
67 | // ======================================================================= |
68 | // function : CreateFromSource |
69 | // purpose : |
70 | // ======================================================================= |
71 | Handle(Graphic3d_ShaderObject) OpenGl_ShaderObject::CreateFromSource (TCollection_AsciiString& theSource, |
72 | Graphic3d_TypeOfShaderObject theType, |
73 | const ShaderVariableList& theUniforms, |
74 | const ShaderVariableList& theStageInOuts, |
75 | const TCollection_AsciiString& theInName, |
76 | const TCollection_AsciiString& theOutName, |
77 | Standard_Integer theNbGeomInputVerts) |
78 | { |
2a332745 |
79 | if (theSource.IsEmpty()) |
80 | { |
81 | return Handle(Graphic3d_ShaderObject)(); |
82 | } |
83 | |
3b4c6945 |
84 | TCollection_AsciiString aSrcUniforms, aSrcInOuts, aSrcInStructs, aSrcOutStructs; |
85 | for (ShaderVariableList::Iterator anUniformIter (theUniforms); anUniformIter.More(); anUniformIter.Next()) |
86 | { |
87 | const ShaderVariable& aVar = anUniformIter.Value(); |
88 | if ((aVar.Stages & theType) != 0) |
89 | { |
90 | aSrcUniforms += TCollection_AsciiString("\nuniform ") + aVar.Name + ";"; |
91 | } |
92 | } |
93 | for (ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next()) |
94 | { |
95 | const ShaderVariable& aVar = aVarListIter.Value(); |
96 | Standard_Integer aStageLower = IntegerLast(), aStageUpper = IntegerFirst(); |
97 | Standard_Integer aNbStages = 0; |
98 | for (Standard_Integer aStageIter = Graphic3d_TOS_VERTEX; aStageIter <= (Standard_Integer )Graphic3d_TOS_COMPUTE; aStageIter = aStageIter << 1) |
99 | { |
100 | if ((aVar.Stages & aStageIter) != 0) |
101 | { |
102 | ++aNbStages; |
103 | aStageLower = Min (aStageLower, aStageIter); |
104 | aStageUpper = Max (aStageUpper, aStageIter); |
105 | } |
106 | } |
107 | if ((Standard_Integer )theType < aStageLower |
108 | || (Standard_Integer )theType > aStageUpper) |
109 | { |
110 | continue; |
111 | } |
112 | |
113 | const Standard_Boolean hasGeomStage = theNbGeomInputVerts > 0 |
114 | && aStageLower < Graphic3d_TOS_GEOMETRY |
115 | && aStageUpper >= Graphic3d_TOS_GEOMETRY; |
2a332745 |
116 | const Standard_Boolean isAllStagesVar = aStageLower == Graphic3d_TOS_VERTEX |
117 | && aStageUpper == Graphic3d_TOS_FRAGMENT; |
3b4c6945 |
118 | if (hasGeomStage |
119 | || !theInName.IsEmpty() |
120 | || !theOutName.IsEmpty()) |
121 | { |
122 | if (aSrcInStructs.IsEmpty() |
2a332745 |
123 | && aSrcOutStructs.IsEmpty() |
124 | && isAllStagesVar) |
3b4c6945 |
125 | { |
126 | if (theType == aStageLower) |
127 | { |
128 | aSrcOutStructs = "\nout VertexData\n{"; |
129 | } |
130 | else if (theType == aStageUpper) |
131 | { |
132 | aSrcInStructs = "\nin VertexData\n{"; |
133 | } |
134 | else // requires theInName/theOutName |
135 | { |
136 | aSrcInStructs = "\nin VertexData\n{"; |
137 | aSrcOutStructs = "\nout VertexData\n{"; |
138 | } |
139 | } |
140 | } |
141 | |
2a332745 |
142 | if (isAllStagesVar |
143 | && (!aSrcInStructs.IsEmpty() |
144 | || !aSrcOutStructs.IsEmpty())) |
3b4c6945 |
145 | { |
146 | if (!aSrcInStructs.IsEmpty()) |
147 | { |
148 | aSrcInStructs += TCollection_AsciiString("\n ") + aVar.Name + ";"; |
149 | } |
150 | if (!aSrcOutStructs.IsEmpty()) |
151 | { |
152 | aSrcOutStructs += TCollection_AsciiString("\n ") + aVar.Name + ";"; |
153 | } |
154 | } |
155 | else |
156 | { |
157 | if (theType == aStageLower) |
158 | { |
159 | aSrcInOuts += TCollection_AsciiString("\nTHE_SHADER_OUT ") + aVar.Name + ";"; |
160 | } |
161 | else if (theType == aStageUpper) |
162 | { |
163 | aSrcInOuts += TCollection_AsciiString("\nTHE_SHADER_IN ") + aVar.Name + ";"; |
164 | } |
165 | } |
166 | } |
167 | |
2a332745 |
168 | if (theType == Graphic3d_TOS_GEOMETRY) |
169 | { |
170 | aSrcUniforms.Prepend (TCollection_AsciiString() |
171 | + "\nlayout (triangles) in;" |
172 | "\nlayout (triangle_strip, max_vertices = " + theNbGeomInputVerts + ") out;"); |
173 | } |
3b4c6945 |
174 | if (!aSrcInStructs.IsEmpty() |
175 | && theType == Graphic3d_TOS_GEOMETRY) |
176 | { |
177 | aSrcInStructs += TCollection_AsciiString ("\n} ") + theInName + "[" + theNbGeomInputVerts + "];"; |
178 | } |
179 | else if (!aSrcInStructs.IsEmpty()) |
180 | { |
181 | aSrcInStructs += "\n}"; |
182 | if (!theInName.IsEmpty()) |
183 | { |
184 | aSrcInStructs += " "; |
185 | aSrcInStructs += theInName; |
186 | } |
187 | aSrcInStructs += ";"; |
188 | } |
2a332745 |
189 | if (!aSrcOutStructs.IsEmpty()) |
3b4c6945 |
190 | { |
191 | aSrcOutStructs += "\n}"; |
2a332745 |
192 | if (!theOutName.IsEmpty()) |
3b4c6945 |
193 | { |
194 | aSrcOutStructs += " "; |
195 | aSrcOutStructs += theOutName; |
196 | } |
197 | aSrcOutStructs += ";"; |
198 | } |
199 | |
200 | theSource.Prepend (aSrcUniforms + aSrcInStructs + aSrcOutStructs + aSrcInOuts); |
201 | return Graphic3d_ShaderObject::CreateFromSource (theType, theSource); |
202 | } |
203 | |
30f0ad28 |
204 | // ======================================================================= |
205 | // function : OpenGl_ShaderObject |
206 | // purpose : Creates uninitialized shader object |
207 | // ======================================================================= |
208 | OpenGl_ShaderObject::OpenGl_ShaderObject (GLenum theType) |
209 | : myType (theType), |
210 | myShaderID (NO_SHADER) |
211 | { |
212 | // |
213 | } |
214 | |
215 | // ======================================================================= |
216 | // function : ~OpenGl_ShaderObject |
217 | // purpose : Releases resources of shader object |
218 | // ======================================================================= |
219 | OpenGl_ShaderObject::~OpenGl_ShaderObject() |
220 | { |
221 | Release (NULL); |
222 | } |
223 | |
2bda8346 |
224 | // ======================================================================= |
225 | // function : LoadAndCompile |
226 | // purpose : |
227 | // ======================================================================= |
228 | Standard_Boolean OpenGl_ShaderObject::LoadAndCompile (const Handle(OpenGl_Context)& theCtx, |
737e9a8d |
229 | const TCollection_AsciiString& theId, |
2bda8346 |
230 | const TCollection_AsciiString& theSource, |
231 | bool theIsVerbose, |
232 | bool theToPrintSource) |
233 | { |
234 | if (!theIsVerbose) |
235 | { |
236 | return LoadSource (theCtx, theSource) |
237 | && Compile (theCtx); |
238 | } |
239 | |
240 | if (!LoadSource (theCtx, theSource)) |
241 | { |
242 | if (theToPrintSource) |
243 | { |
244 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, theSource); |
245 | } |
737e9a8d |
246 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
247 | TCollection_AsciiString ("Error! Failed to set ") + getShaderTypeString (myType) + " [" + theId + "] source"); |
2bda8346 |
248 | return false; |
249 | } |
250 | |
251 | if (!Compile (theCtx)) |
252 | { |
253 | if (theToPrintSource) |
254 | { |
255 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, putLineNumbers (theSource)); |
256 | } |
257 | TCollection_AsciiString aLog; |
258 | FetchInfoLog (theCtx, aLog); |
259 | if (aLog.IsEmpty()) |
260 | { |
261 | aLog = "Compilation log is empty."; |
262 | } |
263 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
737e9a8d |
264 | TCollection_AsciiString ("Failed to compile ") + getShaderTypeString (myType) + " [" + theId + "]. Compilation log:\n" + aLog); |
2bda8346 |
265 | return false; |
266 | } |
267 | else if (theCtx->caps->glslWarnings) |
268 | { |
269 | TCollection_AsciiString aLog; |
270 | FetchInfoLog (theCtx, aLog); |
271 | if (!aLog.IsEmpty() |
272 | && !aLog.IsEqual ("No errors.\n")) |
273 | { |
274 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW, |
737e9a8d |
275 | getShaderTypeString (myType) + " [" + theId + "] compilation log:\n" + aLog); |
2bda8346 |
276 | } |
277 | } |
278 | return true; |
279 | } |
280 | |
737e9a8d |
281 | // ======================================================================= |
282 | // function : DumpSourceCode |
283 | // purpose : |
284 | // ======================================================================= |
285 | void OpenGl_ShaderObject::DumpSourceCode (const Handle(OpenGl_Context)& theCtx, |
286 | const TCollection_AsciiString& theId, |
287 | const TCollection_AsciiString& theSource) const |
288 | { |
289 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 0, GL_DEBUG_SEVERITY_MEDIUM, |
290 | getShaderTypeString (myType) + " [" + theId + "] source code:\n" + theSource); |
291 | } |
292 | |
30f0ad28 |
293 | // ======================================================================= |
294 | // function : LoadSource |
295 | // purpose : Loads shader source code |
296 | // ======================================================================= |
297 | Standard_Boolean OpenGl_ShaderObject::LoadSource (const Handle(OpenGl_Context)& theCtx, |
298 | const TCollection_AsciiString& theSource) |
299 | { |
300 | if (myShaderID == NO_SHADER) |
301 | { |
302 | return Standard_False; |
303 | } |
304 | |
305 | const GLchar* aLines = theSource.ToCString(); |
4e1523ef |
306 | theCtx->core20fwd->glShaderSource (myShaderID, 1, &aLines, NULL); |
30f0ad28 |
307 | return Standard_True; |
308 | } |
309 | |
310 | // ======================================================================= |
311 | // function : Compile |
312 | // purpose : Compiles the shader object |
313 | // ======================================================================= |
314 | Standard_Boolean OpenGl_ShaderObject::Compile (const Handle(OpenGl_Context)& theCtx) |
315 | { |
316 | if (myShaderID == NO_SHADER) |
317 | { |
318 | return Standard_False; |
319 | } |
320 | |
321 | // Try to compile shader |
4e1523ef |
322 | theCtx->core20fwd->glCompileShader (myShaderID); |
30f0ad28 |
323 | |
324 | // Check compile status |
325 | GLint aStatus = GL_FALSE; |
4e1523ef |
326 | theCtx->core20fwd->glGetShaderiv (myShaderID, GL_COMPILE_STATUS, &aStatus); |
30f0ad28 |
327 | return aStatus != GL_FALSE; |
328 | } |
329 | |
330 | // ======================================================================= |
331 | // function : FetchInfoLog |
332 | // purpose : Fetches information log of the last compile operation |
333 | // ======================================================================= |
334 | Standard_Boolean OpenGl_ShaderObject::FetchInfoLog (const Handle(OpenGl_Context)& theCtx, |
335 | TCollection_AsciiString& theLog) |
336 | { |
337 | if (myShaderID == NO_SHADER) |
338 | { |
339 | return Standard_False; |
340 | } |
341 | |
342 | // Load information log of the compiler |
343 | GLint aLength = 0; |
4e1523ef |
344 | theCtx->core20fwd->glGetShaderiv (myShaderID, GL_INFO_LOG_LENGTH, &aLength); |
30f0ad28 |
345 | if (aLength > 0) |
346 | { |
347 | GLchar* aLog = (GLchar*) alloca (aLength); |
348 | memset (aLog, 0, aLength); |
4e1523ef |
349 | theCtx->core20fwd->glGetShaderInfoLog (myShaderID, aLength, NULL, aLog); |
30f0ad28 |
350 | theLog = aLog; |
351 | } |
352 | |
353 | return Standard_True; |
354 | } |
355 | |
356 | // ======================================================================= |
357 | // function : Create |
358 | // purpose : Creates new empty shader object of specified type |
359 | // ======================================================================= |
360 | Standard_Boolean OpenGl_ShaderObject::Create (const Handle(OpenGl_Context)& theCtx) |
361 | { |
362 | if (myShaderID == NO_SHADER |
4e1523ef |
363 | && theCtx->core20fwd != NULL) |
30f0ad28 |
364 | { |
4e1523ef |
365 | myShaderID = theCtx->core20fwd->glCreateShader (myType); |
30f0ad28 |
366 | } |
367 | |
368 | return myShaderID != NO_SHADER; |
369 | } |
370 | |
371 | // ======================================================================= |
372 | // function : Release |
373 | // purpose : Destroys shader object |
374 | // ======================================================================= |
10b9c7df |
375 | void OpenGl_ShaderObject::Release (OpenGl_Context* theCtx) |
30f0ad28 |
376 | { |
377 | if (myShaderID == NO_SHADER) |
378 | { |
379 | return; |
380 | } |
381 | |
382 | Standard_ASSERT_RETURN (theCtx != NULL, |
383 | "OpenGl_ShaderObject destroyed without GL context! Possible GPU memory leakage...",); |
384 | |
4e1523ef |
385 | if (theCtx->core20fwd != NULL |
ec2eeb2d |
386 | && theCtx->IsValid()) |
30f0ad28 |
387 | { |
4e1523ef |
388 | theCtx->core20fwd->glDeleteShader (myShaderID); |
30f0ad28 |
389 | } |
390 | myShaderID = NO_SHADER; |
391 | } |
d95f5ce1 |
392 | |
393 | //! Return GLSL shader stage file extension. |
394 | static const char* getShaderExtension (GLenum theType) |
395 | { |
396 | switch (theType) |
397 | { |
398 | case GL_VERTEX_SHADER: return ".vs"; |
399 | case GL_FRAGMENT_SHADER: return ".fs"; |
400 | case GL_GEOMETRY_SHADER: return ".gs"; |
401 | case GL_TESS_CONTROL_SHADER: return ".tcs"; |
402 | case GL_TESS_EVALUATION_SHADER: return ".tes"; |
403 | case GL_COMPUTE_SHADER: return ".cs"; |
404 | } |
405 | return ".glsl"; |
406 | } |
407 | |
408 | //! Expand substring with additional tail. |
409 | static void insertSubString (TCollection_AsciiString& theString, |
410 | const char& thePattern, |
411 | const TCollection_AsciiString& theSubstitution) |
412 | { |
413 | const int aSubLen = theSubstitution.Length(); |
414 | for (int aCharIter = 1, aNbChars = theString.Length(); aCharIter <= aNbChars; ++aCharIter) |
415 | { |
416 | if (theString.Value (aCharIter) == thePattern) |
417 | { |
418 | theString.Insert (aCharIter + 1, theSubstitution); |
419 | aCharIter += aSubLen; |
420 | aNbChars += aSubLen; |
421 | } |
422 | } |
423 | } |
424 | |
425 | //! Dump GLSL shader source code into file. |
426 | static bool dumpShaderSource (const TCollection_AsciiString& theFileName, |
427 | const TCollection_AsciiString& theSource, |
428 | bool theToBeautify) |
429 | { |
430 | OSD_File aFile (theFileName); |
431 | aFile.Build (OSD_WriteOnly, OSD_Protection()); |
432 | TCollection_AsciiString aSource = theSource; |
433 | if (theToBeautify) |
434 | { |
435 | insertSubString (aSource, ';', "\n"); |
436 | insertSubString (aSource, '{', "\n"); |
437 | insertSubString (aSource, '}', "\n"); |
438 | } |
439 | if (!aFile.IsOpen()) |
440 | { |
441 | Message::DefaultMessenger()->Send (TCollection_AsciiString("Error: File '") + theFileName + "' cannot be opened to save shader", Message_Fail); |
442 | return false; |
443 | } |
444 | |
445 | if (aSource.Length() > 0) |
446 | { |
447 | aFile.Write (aSource.ToCString(), aSource.Length()); |
448 | } |
449 | aFile.Close(); |
450 | Message::DefaultMessenger()->Send (TCollection_AsciiString ("Shader source dumped into '") + theFileName + "'", Message_Warning); |
451 | return true; |
452 | } |
453 | |
454 | //! Read GLSL shader source code from file dump. |
455 | static bool restoreShaderSource (TCollection_AsciiString& theSource, |
456 | const TCollection_AsciiString& theFileName) |
457 | { |
458 | OSD_File aFile (theFileName); |
459 | aFile.Open (OSD_ReadOnly, OSD_Protection()); |
460 | if (!aFile.IsOpen()) |
461 | { |
462 | Message::DefaultMessenger()->Send (TCollection_AsciiString ("File '") + theFileName + "' cannot be opened to load shader", Message_Fail); |
463 | return false; |
464 | } |
465 | |
466 | const Standard_Integer aSize = (Standard_Integer )aFile.Size(); |
467 | if (aSize > 0) |
468 | { |
469 | theSource = TCollection_AsciiString (aSize, '\0'); |
470 | aFile.Read (theSource, aSize); |
471 | } |
472 | aFile.Close(); |
473 | Message::DefaultMessenger()->Send (TCollection_AsciiString ("Restored shader dump from '") + theFileName + "'", Message_Warning); |
474 | return true; |
475 | } |
476 | |
477 | // ======================================================================= |
478 | // function : updateDebugDump |
479 | // purpose : |
480 | // ======================================================================= |
481 | Standard_Boolean OpenGl_ShaderObject::updateDebugDump (const Handle(OpenGl_Context)& theCtx, |
482 | const TCollection_AsciiString& theProgramId, |
483 | const TCollection_AsciiString& theFolder, |
484 | Standard_Boolean theToBeautify, |
485 | Standard_Boolean theToReset) |
486 | { |
487 | const TCollection_AsciiString aFileName = theFolder + "/" + theProgramId + getShaderExtension (myType); |
488 | if (!theToReset) |
489 | { |
490 | OSD_File aFile (aFileName); |
491 | if (aFile.Exists()) |
492 | { |
493 | const Quantity_Date aDate = aFile.AccessMoment(); |
494 | if (aDate > myDumpDate) |
495 | { |
496 | TCollection_AsciiString aNewSource; |
497 | if (restoreShaderSource (aNewSource, aFileName)) |
498 | { |
737e9a8d |
499 | LoadAndCompile (theCtx, theProgramId, aNewSource); |
d95f5ce1 |
500 | return Standard_True; |
501 | } |
502 | } |
503 | return Standard_False; |
504 | } |
505 | } |
506 | |
507 | bool isDumped = false; |
508 | if (myShaderID != NO_SHADER) |
509 | { |
510 | GLint aLength = 0; |
511 | theCtx->core20fwd->glGetShaderiv (myShaderID, GL_SHADER_SOURCE_LENGTH, &aLength); |
512 | if (aLength > 0) |
513 | { |
514 | TCollection_AsciiString aSource (aLength - 1, '\0'); |
515 | theCtx->core20fwd->glGetShaderSource (myShaderID, aLength, NULL, (GLchar* )aSource.ToCString()); |
516 | dumpShaderSource (aFileName, aSource, theToBeautify); |
517 | isDumped = true; |
518 | } |
519 | } |
520 | if (!isDumped) |
521 | { |
522 | dumpShaderSource (aFileName, "", false); |
523 | } |
524 | myDumpDate = OSD_Process().SystemDate(); |
525 | return Standard_False; |
526 | } |