1 // Created on: 2013-08-27
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013 OPEN CASCADE SAS
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
26 #include <OpenGl_Cl.hxx>
33 #pragma comment (lib, "DelayImp.lib")
34 #pragma comment (lib, "OpenCL.lib")
36 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
37 #include <OpenGL/CGLCurrent.h>
42 #include <OpenGl_Context.hxx>
43 #include <OpenGl_Texture.hxx>
44 #include <OpenGl_View.hxx>
45 #include <OpenGl_Workspace.hxx>
47 using namespace OpenGl_Raytrace;
49 //! Use this macro to output ray-tracing debug info
50 // #define RAY_TRACE_PRINT_INFO
52 #ifdef RAY_TRACE_PRINT_INFO
53 #include <OSD_Timer.hxx>
56 //! OpenCL source of ray-tracing kernels.
57 extern const char THE_RAY_TRACE_OPENCL_SOURCE[];
59 // =======================================================================
60 // function : MatVecMult
61 // purpose : Multiples 4x4 matrix by 4D vector
62 // =======================================================================
63 template< typename T >
64 OpenGl_RTVec4f MatVecMult (const T m[16], const OpenGl_RTVec4f& v)
66 return OpenGl_RTVec4f (
67 static_cast<float> (m[ 0] * v.x() + m[ 4] * v.y() +
68 m[ 8] * v.z() + m[12] * v.w()),
69 static_cast<float> (m[ 1] * v.x() + m[ 5] * v.y() +
70 m[ 9] * v.z() + m[13] * v.w()),
71 static_cast<float> (m[ 2] * v.x() + m[ 6] * v.y() +
72 m[10] * v.z() + m[14] * v.w()),
73 static_cast<float> (m[ 3] * v.x() + m[ 7] * v.y() +
74 m[11] * v.z() + m[15] * v.w()));
77 // =======================================================================
78 // function : UpdateRaytraceEnvironmentMap
79 // purpose : Updates environment map for ray-tracing
80 // =======================================================================
81 Standard_Boolean OpenGl_Workspace::UpdateRaytraceEnvironmentMap()
84 return Standard_False;
86 if (myViewModificationStatus == myView->ModificationState())
89 cl_int anError = CL_SUCCESS;
91 if (myRaytraceEnvironment != NULL)
92 clReleaseMemObject (myRaytraceEnvironment);
97 if (!myView->TextureEnv().IsNull() && myView->SurfaceDetail() != Visual3d_TOD_NONE)
99 aSizeX = (myView->TextureEnv()->SizeX() <= 0) ? 1 : myView->TextureEnv()->SizeX();
100 aSizeY = (myView->TextureEnv()->SizeY() <= 0) ? 1 : myView->TextureEnv()->SizeY();
103 cl_image_format aImageFormat;
105 aImageFormat.image_channel_order = CL_RGBA;
106 aImageFormat.image_channel_data_type = CL_FLOAT;
108 myRaytraceEnvironment = clCreateImage2D (myComputeContext, CL_MEM_READ_ONLY,
109 &aImageFormat, aSizeX, aSizeY, 0,
112 cl_float* aPixelData = new cl_float[aSizeX * aSizeY * 4];
114 // Note: texture format is not compatible with OpenCL image
115 // (it's not possible to create image directly from texture)
117 if (!myView->TextureEnv().IsNull() && myView->SurfaceDetail() != Visual3d_TOD_NONE)
119 myView->TextureEnv()->Bind (GetGlContext());
121 glGetTexImage (GL_TEXTURE_2D,
127 myView->TextureEnv()->Unbind (GetGlContext());
131 for (int aPixel = 0; aPixel < aSizeX * aSizeY * 4; ++aPixel)
132 aPixelData[aPixel] = 0.f;
135 size_t anImageOffset[] = { 0,
139 size_t anImageRegion[] = { aSizeX,
143 anError |= clEnqueueWriteImage (myRaytraceQueue, myRaytraceEnvironment, CL_TRUE,
144 anImageOffset, anImageRegion, 0, 0, aPixelData,
146 #ifdef RAY_TRACE_PRINT_INFO
147 if (anError != CL_SUCCESS)
148 std::cout << "Error! Failed to write environment map image!" << std::endl;
153 myViewModificationStatus = myView->ModificationState();
155 return (anError == CL_SUCCESS);
158 // =======================================================================
159 // function : UpdateRaytraceGeometry
160 // purpose : Updates 3D scene geometry for ray tracing
161 // =======================================================================
162 Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (Standard_Boolean theCheck)
165 return Standard_False;
167 // Note: In 'check' mode the scene geometry is analyzed for modifications
168 // This is light-weight procedure performed for each frame
172 myRaytraceSceneData.Clear();
174 myIsRaytraceDataValid = Standard_False;
178 if (myLayersModificationStatus != myView->LayerList().ModificationState())
180 return UpdateRaytraceGeometry (Standard_False);
184 float* aTransform (NULL);
186 // The set of processed structures (reflected to ray-tracing)
187 // This set is used to remove out-of-date records from the
188 // hash map of structures
189 std::set<const OpenGl_Structure*> anElements;
191 const OpenGl_LayerList& aList = myView->LayerList();
193 for (OpenGl_SequenceOfLayers::Iterator anLayerIt (aList.Layers()); anLayerIt.More(); anLayerIt.Next())
195 const OpenGl_PriorityList& aPriorityList = anLayerIt.Value();
197 if (aPriorityList.NbStructures() == 0)
200 const OpenGl_ArrayOfStructure& aStructArray = aPriorityList.ArrayOfStructures();
202 for (int anIndex = 0; anIndex < aStructArray.Length(); ++anIndex)
204 OpenGl_SequenceOfStructure::Iterator aStructIt;
206 for (aStructIt.Init (aStructArray (anIndex)); aStructIt.More(); aStructIt.Next())
208 const OpenGl_Structure* aStructure = aStructIt.Value();
212 if (CheckRaytraceStructure (aStructure))
214 return UpdateRaytraceGeometry (Standard_False);
219 if (!aStructure->IsRaytracable())
222 if (aStructure->Transformation()->mat != NULL)
224 if (aTransform == NULL)
225 aTransform = new float[16];
227 for (int i = 0; i < 4; ++i)
228 for (int j = 0; j < 4; ++j)
230 aTransform[j * 4 + i] = aStructure->Transformation()->mat[i][j];
234 AddRaytraceStructure (aStructure, aTransform, anElements);
242 // Actualize the hash map of structures -- remove out-of-date records
243 std::map<const OpenGl_Structure*, Standard_Size>::iterator anIter = myStructureStates.begin();
245 while (anIter != myStructureStates.end())
247 if (anElements.find (anIter->first) == anElements.end())
249 myStructureStates.erase (anIter++);
257 // Actualize OpenGL layer list state
258 myLayersModificationStatus = myView->LayerList().ModificationState();
261 #ifdef RAY_TRACE_PRINT_INFO
266 myBVHBuilder.Build (myRaytraceSceneData);
268 #ifdef RAY_TRACE_PRINT_INFO
269 std::cout << " Build time: " << aTimer.ElapsedTime() << " for "
270 << myRaytraceSceneData.Triangles.size() / 1000 << "K triangles" << std::endl;
273 const float aScaleFactor = 1.5f;
275 myRaytraceSceneRadius = aScaleFactor *
276 Max ( Max (fabsf (myRaytraceSceneData.AABB.CornerMin().x()),
277 Max (fabsf (myRaytraceSceneData.AABB.CornerMin().y()),
278 fabsf (myRaytraceSceneData.AABB.CornerMin().z()))),
279 Max (fabsf (myRaytraceSceneData.AABB.CornerMax().x()),
280 Max (fabsf (myRaytraceSceneData.AABB.CornerMax().y()),
281 fabsf (myRaytraceSceneData.AABB.CornerMax().z()))) );
283 myRaytraceSceneEpsilon = Max (1e-4f, myRaytraceSceneRadius * 1e-4f);
285 return WriteRaytraceSceneToDevice();
288 delete [] aTransform;
290 return Standard_True;
293 // =======================================================================
294 // function : CheckRaytraceStructure
295 // purpose : Adds OpenGL structure to ray-traced scene geometry
296 // =======================================================================
297 Standard_Boolean OpenGl_Workspace::CheckRaytraceStructure (const OpenGl_Structure* theStructure)
299 if (!theStructure->IsRaytracable())
301 // Checks to see if all ray-tracable elements were
302 // removed from the structure
303 if (theStructure->ModificationState() > 0)
305 theStructure->ResetModificationState();
306 return Standard_True;
309 return Standard_False;
312 std::map<const OpenGl_Structure*, Standard_Size>::iterator aStructState = myStructureStates.find (theStructure);
314 if (aStructState != myStructureStates.end())
315 return aStructState->second != theStructure->ModificationState();
317 return Standard_True;
320 // =======================================================================
321 // function : CreateMaterial
322 // purpose : Creates ray-tracing material properties
323 // =======================================================================
324 void CreateMaterial (const OPENGL_SURF_PROP& theProp,
325 OpenGl_RaytraceMaterial& theMaterial)
327 const float* aSrcAmb = theProp.isphysic ? theProp.ambcol.rgb : theProp.matcol.rgb;
328 theMaterial.Ambient = OpenGl_RTVec4f (aSrcAmb[0] * theProp.amb,
329 aSrcAmb[1] * theProp.amb,
330 aSrcAmb[2] * theProp.amb,
333 const float* aSrcDif = theProp.isphysic ? theProp.difcol.rgb : theProp.matcol.rgb;
334 theMaterial.Diffuse = OpenGl_RTVec4f (aSrcDif[0] * theProp.diff,
335 aSrcDif[1] * theProp.diff,
336 aSrcDif[2] * theProp.diff,
339 const float aDefSpecCol[4] = {1.0f, 1.0f, 1.0f, 1.0f};
340 const float* aSrcSpe = theProp.isphysic ? theProp.speccol.rgb : aDefSpecCol;
341 theMaterial.Specular = OpenGl_RTVec4f (aSrcSpe[0] * theProp.spec,
342 aSrcSpe[1] * theProp.spec,
343 aSrcSpe[2] * theProp.spec,
346 const float* aSrcEms = theProp.isphysic ? theProp.emscol.rgb : theProp.matcol.rgb;
347 theMaterial.Emission = OpenGl_RTVec4f (aSrcEms[0] * theProp.emsv,
348 aSrcEms[1] * theProp.emsv,
349 aSrcEms[2] * theProp.emsv,
352 // Note: Here we use sub-linear transparency function
353 // to produce realistic-looking transparency effect
354 theMaterial.Transparency = OpenGl_RTVec4f (powf (theProp.trans, 0.75f),
359 const float aMaxRefl = Max (theMaterial.Diffuse.x() + theMaterial.Specular.x(),
360 Max (theMaterial.Diffuse.y() + theMaterial.Specular.y(),
361 theMaterial.Diffuse.z() + theMaterial.Specular.z()));
363 const float aReflectionScale = 0.75f / aMaxRefl;
365 theMaterial.Reflection = OpenGl_RTVec4f (theProp.speccol.rgb[0] * theProp.spec,
366 theProp.speccol.rgb[1] * theProp.spec,
367 theProp.speccol.rgb[2] * theProp.spec,
368 0.f) * aReflectionScale;
371 // =======================================================================
372 // function : AddRaytraceStructure
373 // purpose : Adds OpenGL structure to ray-traced scene geometry
374 // =======================================================================
375 Standard_Boolean OpenGl_Workspace::AddRaytraceStructure (const OpenGl_Structure* theStructure,
376 const float* theTransform,
377 std::set<const OpenGl_Structure*>& theElements)
379 #ifdef RAY_TRACE_PRINT_INFO
380 std::cout << "Add Structure" << std::endl;
383 theElements.insert (theStructure);
385 if (!theStructure->IsVisible())
387 myStructureStates[theStructure] = theStructure->ModificationState();
388 return Standard_True;
391 // Get structure material
392 int aStructMatID = -1;
394 if (theStructure->AspectFace() != NULL)
396 aStructMatID = static_cast<int> (myRaytraceSceneData.Materials.size());
398 OpenGl_RaytraceMaterial aStructMaterial;
399 CreateMaterial (theStructure->AspectFace()->IntFront(), aStructMaterial);
401 myRaytraceSceneData.Materials.push_back (aStructMaterial);
404 OpenGl_ListOfGroup::Iterator anItg (theStructure->Groups());
408 // Get group material
409 int aGroupMatID = -1;
411 if (anItg.Value()->AspectFace() != NULL)
413 aGroupMatID = static_cast<int> (myRaytraceSceneData.Materials.size());
415 OpenGl_RaytraceMaterial aGroupMaterial;
416 CreateMaterial (anItg.Value()->AspectFace()->IntFront(), aGroupMaterial);
418 myRaytraceSceneData.Materials.push_back (aGroupMaterial);
421 int aMatID = aGroupMatID < 0 ? aStructMatID : aGroupMatID;
423 if (aStructMatID < 0 && aGroupMatID < 0)
425 aMatID = static_cast<int> (myRaytraceSceneData.Materials.size());
427 myRaytraceSceneData.Materials.push_back (OpenGl_RaytraceMaterial());
430 // Add OpenGL elements from group (only arrays of primitives)
431 for (const OpenGl_ElementNode* aNode = anItg.Value()->FirstNode(); aNode != NULL; aNode = aNode->next)
433 if (TelNil == aNode->type)
435 OpenGl_AspectFace* anAspect = dynamic_cast<OpenGl_AspectFace*> (aNode->elem);
437 if (anAspect != NULL)
439 aMatID = static_cast<int> (myRaytraceSceneData.Materials.size());
441 OpenGl_RaytraceMaterial aMaterial;
442 CreateMaterial (anAspect->IntFront(), aMaterial);
444 myRaytraceSceneData.Materials.push_back (aMaterial);
447 else if (TelParray == aNode->type)
449 OpenGl_PrimitiveArray* aPrimArray = dynamic_cast<OpenGl_PrimitiveArray*> (aNode->elem);
451 if (aPrimArray != NULL)
453 AddRaytracePrimitiveArray (aPrimArray->PArray(), aMatID, theTransform);
461 float* aTransform (NULL);
463 // Process all connected OpenGL structures
464 OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures());
468 if (anIts.Value()->Transformation()->mat != NULL)
470 float* aTransform = new float[16];
472 for (int i = 0; i < 4; ++i)
473 for (int j = 0; j < 4; ++j)
475 aTransform[j * 4 + i] =
476 anIts.Value()->Transformation()->mat[i][j];
480 if (anIts.Value()->IsRaytracable())
481 AddRaytraceStructure (anIts.Value(), aTransform != NULL ? aTransform : theTransform, theElements);
488 myStructureStates[theStructure] = theStructure->ModificationState();
490 return Standard_True;
493 // =======================================================================
494 // function : AddRaytracePrimitiveArray
495 // purpose : Adds OpenGL primitive array to ray-traced scene geometry
496 // =======================================================================
497 Standard_Boolean OpenGl_Workspace::AddRaytracePrimitiveArray (const CALL_DEF_PARRAY* theArray,
499 const float* theTransform)
501 if (theArray->type != TelPolygonsArrayType &&
502 theArray->type != TelTrianglesArrayType &&
503 theArray->type != TelQuadranglesArrayType &&
504 theArray->type != TelTriangleFansArrayType &&
505 theArray->type != TelTriangleStripsArrayType &&
506 theArray->type != TelQuadrangleStripsArrayType)
508 return Standard_True;
511 if (theArray->vertices == NULL)
512 return Standard_False;
514 #ifdef RAY_TRACE_PRINT_INFO
515 switch (theArray->type)
517 case TelPolygonsArrayType:
518 std::cout << "\tTelPolygonsArrayType" << std::endl; break;
519 case TelTrianglesArrayType:
520 std::cout << "\tTelTrianglesArrayType" << std::endl; break;
521 case TelQuadranglesArrayType:
522 std::cout << "\tTelQuadranglesArrayType" << std::endl; break;
523 case TelTriangleFansArrayType:
524 std::cout << "\tTelTriangleFansArrayType" << std::endl; break;
525 case TelTriangleStripsArrayType:
526 std::cout << "\tTelTriangleStripsArrayType" << std::endl; break;
527 case TelQuadrangleStripsArrayType:
528 std::cout << "\tTelQuadrangleStripsArrayType" << std::endl; break;
532 // Simple optimization to eliminate possible memory allocations
533 // during processing of the primitive array vertices
534 myRaytraceSceneData.Vertices.reserve (
535 myRaytraceSceneData.Vertices.size() + theArray->num_vertexs);
537 const int aFirstVert = static_cast<int> (myRaytraceSceneData.Vertices.size());
539 for (int aVert = 0; aVert < theArray->num_vertexs; ++aVert)
541 OpenGl_RTVec4f aVertex (theArray->vertices[aVert].xyz[0],
542 theArray->vertices[aVert].xyz[1],
543 theArray->vertices[aVert].xyz[2],
547 aVertex = MatVecMult (theTransform, aVertex);
549 myRaytraceSceneData.Vertices.push_back (aVertex);
551 myRaytraceSceneData.AABB.Add (aVertex);
554 myRaytraceSceneData.Normals.reserve (
555 myRaytraceSceneData.Normals.size() + theArray->num_vertexs);
557 for (int aNorm = 0; aNorm < theArray->num_vertexs; ++aNorm)
559 OpenGl_RTVec4f aNormal;
561 // Note: In case of absence of normals, the visualizer
562 // will use generated geometric normals
564 if (theArray->vnormals != NULL)
566 aNormal = OpenGl_RTVec4f (theArray->vnormals[aNorm].xyz[0],
567 theArray->vnormals[aNorm].xyz[1],
568 theArray->vnormals[aNorm].xyz[2],
572 aNormal = MatVecMult (theTransform, aNormal);
575 myRaytraceSceneData.Normals.push_back (aNormal);
578 if (theArray->num_bounds > 0)
580 #ifdef RAY_TRACE_PRINT_INFO
581 std::cout << "\tNumber of bounds = " << theArray->num_bounds << std::endl;
586 for (int aBound = 0; aBound < theArray->num_bounds; ++aBound)
588 const int aVertNum = theArray->bounds[aBound];
590 #ifdef RAY_TRACE_PRINT_INFO
591 std::cout << "\tAdd indices from bound " << aBound << ": " <<
592 aVertOffset << ", " << aVertNum << std::endl;
595 if (!AddRaytraceVertexIndices (theArray, aFirstVert, aVertOffset, aVertNum, theMatID))
597 return Standard_False;
600 aVertOffset += aVertNum;
605 const int aVertNum = theArray->num_edges > 0 ? theArray->num_edges : theArray->num_vertexs;
607 #ifdef RAY_TRACE_PRINT_INFO
608 std::cout << "\tAdd indices: " << aVertNum << std::endl;
611 return AddRaytraceVertexIndices (theArray, aFirstVert, 0, aVertNum, theMatID);
614 return Standard_True;
617 // =======================================================================
618 // function : AddRaytraceVertexIndices
619 // purpose : Adds vertex indices to ray-traced scene geometry
620 // =======================================================================
621 Standard_Boolean OpenGl_Workspace::AddRaytraceVertexIndices (const CALL_DEF_PARRAY* theArray,
627 myRaytraceSceneData.Triangles.reserve (myRaytraceSceneData.Triangles.size() + theVertNum);
628 switch (theArray->type)
630 case TelTrianglesArrayType: return AddRaytraceTriangleArray (theArray, theFirstVert, theVertOffset, theVertNum, theMatID);
631 case TelQuadranglesArrayType: return AddRaytraceQuadrangleArray (theArray, theFirstVert, theVertOffset, theVertNum, theMatID);
632 case TelTriangleFansArrayType: return AddRaytraceTriangleFanArray (theArray, theFirstVert, theVertOffset, theVertNum, theMatID);
633 case TelTriangleStripsArrayType: return AddRaytraceTriangleStripArray (theArray, theFirstVert, theVertOffset, theVertNum, theMatID);
634 case TelQuadrangleStripsArrayType: return AddRaytraceQuadrangleStripArray (theArray, theFirstVert, theVertOffset, theVertNum, theMatID);
635 case TelPolygonsArrayType: return AddRaytracePolygonArray (theArray, theFirstVert, theVertOffset, theVertNum, theMatID);
636 default: return Standard_False;
640 // =======================================================================
641 // function : AddRaytraceTriangleArray
642 // purpose : Adds OpenGL triangle array to ray-traced scene geometry
643 // =======================================================================
644 Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleArray (const CALL_DEF_PARRAY* theArray,
651 return Standard_True;
653 if (theArray->num_edges > 0)
655 for (int aVert = theVertOffset; aVert < theVertOffset + theVertNum - 2; aVert += 3)
657 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + theArray->edges[aVert + 0],
658 theFirstVert + theArray->edges[aVert + 1],
659 theFirstVert + theArray->edges[aVert + 2],
665 for (int aVert = theVertOffset; aVert < theVertOffset + theVertNum - 2; aVert += 3)
667 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + aVert + 0,
668 theFirstVert + aVert + 1,
669 theFirstVert + aVert + 2,
674 return Standard_True;
677 // =======================================================================
678 // function : AddRaytraceTriangleFanArray
679 // purpose : Adds OpenGL triangle fan array to ray-traced scene geometry
680 // =======================================================================
681 Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleFanArray (const CALL_DEF_PARRAY* theArray,
688 return Standard_True;
690 if (theArray->num_edges > 0)
692 for (int aVert = theVertOffset; aVert < theVertOffset + theVertNum - 2; ++aVert)
694 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + theArray->edges[theVertOffset],
695 theFirstVert + theArray->edges[aVert + 1],
696 theFirstVert + theArray->edges[aVert + 2],
702 for (int aVert = theVertOffset; aVert < theVertOffset + theVertNum - 2; ++aVert)
704 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + theVertOffset,
705 theFirstVert + aVert + 1,
706 theFirstVert + aVert + 2,
711 return Standard_True;
714 // =======================================================================
715 // function : AddRaytraceTriangleStripArray
716 // purpose : Adds OpenGL triangle strip array to ray-traced scene geometry
717 // =======================================================================
718 Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleStripArray (const CALL_DEF_PARRAY* theArray,
725 return Standard_True;
727 if (theArray->num_edges > 0)
729 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (
730 theFirstVert + theArray->edges[theVertOffset + 0],
731 theFirstVert + theArray->edges[theVertOffset + 1],
732 theFirstVert + theArray->edges[theVertOffset + 2],
735 for (int aVert = theVertOffset + 1, aTriNum = 1; aVert < theVertOffset + theVertNum - 2; ++aVert, ++aTriNum)
737 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (
738 theFirstVert + theArray->edges[aVert + (aTriNum % 2) ? 1 : 0],
739 theFirstVert + theArray->edges[aVert + (aTriNum % 2) ? 0 : 1],
740 theFirstVert + theArray->edges[aVert + 2],
746 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + theVertOffset + 0,
747 theFirstVert + theVertOffset + 1,
748 theFirstVert + theVertOffset + 2,
751 for (int aVert = theVertOffset + 1, aTriNum = 1; aVert < theVertOffset + theVertNum - 2; ++aVert, ++aTriNum)
753 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + aVert + ( aTriNum % 2 ) ? 1 : 0,
754 theFirstVert + aVert + ( aTriNum % 2 ) ? 0 : 1,
755 theFirstVert + aVert + 2,
760 return Standard_True;
763 // =======================================================================
764 // function : AddRaytraceQuadrangleArray
765 // purpose : Adds OpenGL quad array to ray-traced scene geometry
766 // =======================================================================
767 Standard_Boolean OpenGl_Workspace::AddRaytraceQuadrangleArray (const CALL_DEF_PARRAY* theArray,
774 return Standard_True;
776 if (theArray->num_edges > 0)
778 for (int aVert = theVertOffset; aVert < theVertOffset + theVertNum - 3; aVert += 4)
780 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + theArray->edges[aVert + 0],
781 theFirstVert + theArray->edges[aVert + 1],
782 theFirstVert + theArray->edges[aVert + 2],
785 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + theArray->edges[aVert + 0],
786 theFirstVert + theArray->edges[aVert + 2],
787 theFirstVert + theArray->edges[aVert + 3],
793 for (int aVert = theVertOffset; aVert < theVertOffset + theVertNum - 3; aVert += 4)
795 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + aVert + 0,
796 theFirstVert + aVert + 1,
797 theFirstVert + aVert + 2,
800 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + aVert + 0,
801 theFirstVert + aVert + 2,
802 theFirstVert + aVert + 3,
807 return Standard_True;
810 // =======================================================================
811 // function : AddRaytraceQuadrangleStripArray
812 // purpose : Adds OpenGL quad strip array to ray-traced scene geometry
813 // =======================================================================
814 Standard_Boolean OpenGl_Workspace::AddRaytraceQuadrangleStripArray (const CALL_DEF_PARRAY* theArray,
821 return Standard_True;
823 if (theArray->num_edges > 0)
825 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (
826 theFirstVert + theArray->edges[theVertOffset + 0],
827 theFirstVert + theArray->edges[theVertOffset + 1],
828 theFirstVert + theArray->edges[theVertOffset + 2],
831 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (
832 theFirstVert + theArray->edges[theVertOffset + 1],
833 theFirstVert + theArray->edges[theVertOffset + 3],
834 theFirstVert + theArray->edges[theVertOffset + 2],
837 for (int aVert = theVertOffset + 2; aVert < theVertOffset + theVertNum - 3; aVert += 2)
839 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (
840 theFirstVert + theArray->edges[aVert + 0],
841 theFirstVert + theArray->edges[aVert + 1],
842 theFirstVert + theArray->edges[aVert + 2],
845 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (
846 theFirstVert + theArray->edges[aVert + 1],
847 theFirstVert + theArray->edges[aVert + 3],
848 theFirstVert + theArray->edges[aVert + 2],
854 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + 0,
859 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + 1,
864 for (int aVert = theVertOffset + 2; aVert < theVertOffset + theVertNum - 3; aVert += 2)
866 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + aVert + 0,
867 theFirstVert + aVert + 1,
868 theFirstVert + aVert + 2,
871 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + aVert + 1,
872 theFirstVert + aVert + 3,
873 theFirstVert + aVert + 2,
878 return Standard_True;
881 // =======================================================================
882 // function : AddRaytracePolygonArray
883 // purpose : Adds OpenGL polygon array to ray-traced scene geometry
884 // =======================================================================
885 Standard_Boolean OpenGl_Workspace::AddRaytracePolygonArray (const CALL_DEF_PARRAY* theArray,
891 if (theArray->num_vertexs < 3)
892 return Standard_True;
894 if (theArray->edges != NULL)
896 for (int aVert = theVertOffset; aVert < theVertOffset + theVertNum - 2; ++aVert)
898 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + theArray->edges[theVertOffset],
899 theFirstVert + theArray->edges[aVert + 1],
900 theFirstVert + theArray->edges[aVert + 2],
906 for (int aVert = theVertOffset; aVert < theVertOffset + theVertNum - 2; ++aVert)
908 myRaytraceSceneData.Triangles.push_back (OpenGl_RTVec4i (theFirstVert + theVertOffset,
909 theFirstVert + aVert + 1,
910 theFirstVert + aVert + 2,
915 return Standard_True;
918 // =======================================================================
919 // function : UpdateRaytraceLightSources
920 // purpose : Updates 3D scene light sources for ray-tracing
921 // =======================================================================
922 Standard_Boolean OpenGl_Workspace::UpdateRaytraceLightSources (const GLdouble theInvModelView[16])
924 myRaytraceSceneData.LightSources.clear();
926 OpenGl_RTVec4f anAmbient (0.0f, 0.0f, 0.0f, 0.0f);
927 for (OpenGl_ListOfLight::Iterator anItl (myView->LightList());
928 anItl.More(); anItl.Next())
930 const OpenGl_Light& aLight = anItl.Value();
931 if (aLight.Type == Visual3d_TOLS_AMBIENT)
933 anAmbient += OpenGl_RTVec4f (aLight.Color.r(), aLight.Color.g(), aLight.Color.b(), 0.0f);
937 OpenGl_RTVec4f aDiffuse (aLight.Color.r(), aLight.Color.g(), aLight.Color.b(), 1.0f);
938 OpenGl_RTVec4f aPosition (-aLight.Direction.x(), -aLight.Direction.y(), -aLight.Direction.z(), 0.0f);
939 if (aLight.Type != Visual3d_TOLS_DIRECTIONAL)
941 aPosition = OpenGl_RTVec4f (aLight.Position.x(), aLight.Position.y(), aLight.Position.z(), 1.0f);
943 if (aLight.IsHeadlight)
945 aPosition = MatVecMult (theInvModelView, aPosition);
948 myRaytraceSceneData.LightSources.push_back (OpenGl_RaytraceLight (aDiffuse, aPosition));
951 if (myRaytraceSceneData.LightSources.size() > 0)
953 myRaytraceSceneData.LightSources.front().Ambient += anAmbient;
957 myRaytraceSceneData.LightSources.push_back (OpenGl_RaytraceLight (OpenGl_RTVec4f (anAmbient.rgb(), -1.0f)));
960 cl_int anError = CL_SUCCESS;
962 if (myRaytraceLightSourceBuffer != NULL)
963 clReleaseMemObject (myRaytraceLightSourceBuffer);
965 const size_t myLightBufferSize = myRaytraceSceneData.LightSources.size() > 0
966 ? myRaytraceSceneData.LightSources.size()
969 myRaytraceLightSourceBuffer = clCreateBuffer (myComputeContext, CL_MEM_READ_ONLY,
970 myLightBufferSize * sizeof(OpenGl_RaytraceLight),
973 if (myRaytraceSceneData.LightSources.size() > 0)
975 const void* aDataPtr = myRaytraceSceneData.LightSources.front().Packed();
976 anError |= clEnqueueWriteBuffer (myRaytraceQueue, myRaytraceLightSourceBuffer, CL_TRUE, 0,
977 myLightBufferSize * sizeof(OpenGl_RaytraceLight), aDataPtr,
981 #ifdef RAY_TRACE_PRINT_INFO
982 if (anError != CL_SUCCESS)
984 std::cout << "Error! Failed to set light sources!";
986 return Standard_False;
990 return Standard_True;
993 // =======================================================================
994 // function : CheckOpenCL
995 // purpose : Checks OpenCL dynamic library availability
996 // =======================================================================
997 Standard_Boolean CheckOpenCL()
999 #if defined ( _WIN32 )
1003 cl_uint aNbPlatforms;
1004 clGetPlatformIDs (0, NULL, &aNbPlatforms);
1006 __except (EXCEPTION_EXECUTE_HANDLER)
1008 return Standard_False;
1013 return Standard_True;
1016 // =======================================================================
1017 // function : InitOpenCL
1018 // purpose : Initializes OpenCL objects
1019 // =======================================================================
1020 Standard_Boolean OpenGl_Workspace::InitOpenCL()
1022 if (myComputeInitStatus != OpenGl_CLIS_NONE)
1024 return myComputeInitStatus == OpenGl_CLIS_INIT;
1029 myComputeInitStatus = OpenGl_CLIS_FAIL; // fail to load OpenCL library
1030 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1031 GL_DEBUG_TYPE_ERROR_ARB,
1033 GL_DEBUG_SEVERITY_HIGH_ARB,
1034 "Failed to load OpenCL dynamic library!");
1035 return Standard_False;
1038 // Obtain the list of platforms available
1039 cl_uint aNbPlatforms = 0;
1040 cl_int anError = clGetPlatformIDs (0, NULL, &aNbPlatforms);
1041 cl_platform_id* aPlatforms = (cl_platform_id* )alloca (aNbPlatforms * sizeof(cl_platform_id));
1042 anError |= clGetPlatformIDs (aNbPlatforms, aPlatforms, NULL);
1043 if (anError != CL_SUCCESS
1044 || aNbPlatforms == 0)
1046 myComputeInitStatus = OpenGl_CLIS_FAIL;
1047 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1048 GL_DEBUG_TYPE_ERROR_ARB,
1050 GL_DEBUG_SEVERITY_HIGH_ARB,
1051 "No any OpenCL platform installed!");
1052 return Standard_False;
1055 // Note: We try to find NVIDIA or AMD platforms with GPU devices!
1056 cl_platform_id aPrefPlatform = NULL;
1057 for (cl_uint aPlatIter = 0; aPlatIter < aNbPlatforms; ++aPlatIter)
1060 anError = clGetPlatformInfo (aPlatforms[aPlatIter], CL_PLATFORM_NAME,
1061 sizeof(aName), aName, NULL);
1062 if (anError != CL_SUCCESS)
1067 if (strncmp (aName, "NVIDIA", strlen ("NVIDIA")) == 0)
1069 aPrefPlatform = aPlatforms[aPlatIter];
1071 // Use optimizations for NVIDIA GPUs
1072 myIsAmdComputePlatform = Standard_False;
1074 else if (strncmp (aName, "AMD", strlen ("AMD")) == 0)
1076 aPrefPlatform = (aPrefPlatform == NULL)
1077 ? aPlatforms[aPlatIter]
1080 // Use optimizations for ATI/AMD platform
1081 myIsAmdComputePlatform = Standard_True;
1085 if (aPrefPlatform == NULL)
1087 aPrefPlatform = aPlatforms[0];
1090 // Obtain the list of devices available in the selected platform
1091 cl_uint aNbDevices = 0;
1092 anError = clGetDeviceIDs (aPrefPlatform, CL_DEVICE_TYPE_GPU,
1093 0, NULL, &aNbDevices);
1095 cl_device_id* aDevices = (cl_device_id* )alloca (aNbDevices * sizeof(cl_device_id));
1096 anError |= clGetDeviceIDs (aPrefPlatform, CL_DEVICE_TYPE_GPU,
1097 aNbDevices, aDevices, NULL);
1098 if (anError != CL_SUCCESS)
1100 myComputeInitStatus = OpenGl_CLIS_FAIL;
1101 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1102 GL_DEBUG_TYPE_ERROR_ARB,
1104 GL_DEBUG_SEVERITY_HIGH_ARB,
1105 "Failed to get OpenCL GPU device!");
1106 return Standard_False;
1109 // Note: Simply get first available GPU
1110 cl_device_id aDevice = aDevices[0];
1112 // detect old contexts
1113 char aVerClStr[256];
1114 clGetDeviceInfo (aDevice, CL_DEVICE_VERSION,
1115 sizeof(aVerClStr), aVerClStr, NULL);
1116 aVerClStr[strlen ("OpenCL 1.0")] = '\0';
1117 const bool isVer10 = strncmp (aVerClStr, "OpenCL 1.0", strlen ("OpenCL 1.0")) == 0;
1119 // Create OpenCL context
1120 cl_context_properties aCtxProp[] =
1122 #if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1123 CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE,
1124 (cl_context_properties )CGLGetShareGroup (CGLGetCurrentContext()),
1125 #elif defined(_WIN32)
1126 CL_CONTEXT_PLATFORM, (cl_context_properties )aPrefPlatform,
1127 CL_GL_CONTEXT_KHR, (cl_context_properties )wglGetCurrentContext(),
1128 CL_WGL_HDC_KHR, (cl_context_properties )wglGetCurrentDC(),
1130 CL_GL_CONTEXT_KHR, (cl_context_properties )glXGetCurrentContext(),
1131 CL_GLX_DISPLAY_KHR, (cl_context_properties )glXGetCurrentDisplay(),
1132 CL_CONTEXT_PLATFORM, (cl_context_properties )aPrefPlatform,
1137 myComputeContext = clCreateContext (aCtxProp,
1138 #if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1139 0, NULL, // device will be taken from GL context
1143 NULL, NULL, &anError);
1144 if (anError != CL_SUCCESS)
1146 myComputeInitStatus = OpenGl_CLIS_FAIL;
1147 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1148 GL_DEBUG_TYPE_ERROR_ARB,
1150 GL_DEBUG_SEVERITY_HIGH_ARB,
1151 "Failed to initialize OpenCL context!");
1152 return Standard_False;
1155 // Create OpenCL program
1156 const char* aSources[] =
1158 isVer10 ? "#define M_PI_F ( float )( 3.14159265359f )\n" : "",
1159 THE_RAY_TRACE_OPENCL_SOURCE
1161 myRaytraceProgram = clCreateProgramWithSource (myComputeContext, 2,
1162 aSources, NULL, &anError);
1163 if (anError != CL_SUCCESS)
1165 myComputeInitStatus = OpenGl_CLIS_FAIL;
1166 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1167 GL_DEBUG_TYPE_ERROR_ARB,
1169 GL_DEBUG_SEVERITY_HIGH_ARB,
1170 "Failed to create OpenCL ray-tracing program!");
1171 return Standard_False;
1174 anError = clBuildProgram (myRaytraceProgram, 0,
1175 NULL, NULL, NULL, NULL);
1179 cl_int aResult = clGetProgramBuildInfo (myRaytraceProgram, aDevice,
1180 CL_PROGRAM_BUILD_LOG, 0, NULL, &aLogLen);
1182 char* aBuildLog = (char* )alloca (aLogLen);
1183 aResult |= clGetProgramBuildInfo (myRaytraceProgram, aDevice,
1184 CL_PROGRAM_BUILD_LOG, aLogLen, aBuildLog, NULL);
1185 if (aResult == CL_SUCCESS)
1187 if (anError != CL_SUCCESS)
1189 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1190 GL_DEBUG_TYPE_ERROR_ARB,
1192 GL_DEBUG_SEVERITY_HIGH_ARB,
1197 #ifdef RAY_TRACE_PRINT_INFO
1198 std::cout << aBuildLog << std::endl;
1204 if (anError != CL_SUCCESS)
1206 return Standard_False;
1209 // Create OpenCL ray tracing kernels
1210 myRaytraceRenderKernel = clCreateKernel (myRaytraceProgram, "Main", &anError);
1211 if (anError != CL_SUCCESS)
1213 myComputeInitStatus = OpenGl_CLIS_FAIL;
1214 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1215 GL_DEBUG_TYPE_ERROR_ARB,
1217 GL_DEBUG_SEVERITY_HIGH_ARB,
1218 "Failed to create OpenCL ray-tracing kernel!");
1219 return Standard_False;
1222 myRaytraceSmoothKernel = clCreateKernel (myRaytraceProgram, "MainAntialiased", &anError);
1223 if (anError != CL_SUCCESS)
1225 myComputeInitStatus = OpenGl_CLIS_FAIL;
1226 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1227 GL_DEBUG_TYPE_ERROR_ARB,
1229 GL_DEBUG_SEVERITY_HIGH_ARB,
1230 "Failed to create OpenCL ray-tracing kernel!");
1231 return Standard_False;
1234 // Create OpenCL command queue
1235 // Note: For profiling set CL_QUEUE_PROFILING_ENABLE
1236 cl_command_queue_properties aProps = CL_QUEUE_PROFILING_ENABLE;
1238 myRaytraceQueue = clCreateCommandQueue (myComputeContext, aDevice, aProps, &anError);
1239 if (anError != CL_SUCCESS)
1241 myComputeInitStatus = OpenGl_CLIS_FAIL;
1242 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1243 GL_DEBUG_TYPE_ERROR_ARB,
1245 GL_DEBUG_SEVERITY_HIGH_ARB,
1246 "Failed to create OpenCL command queue!");
1248 return Standard_False;
1251 myComputeInitStatus = OpenGl_CLIS_INIT; // initialized in normal way
1252 return Standard_True;
1255 // =======================================================================
1256 // function : GetOpenClDeviceInfo
1257 // purpose : Returns information about device used for computations
1258 // =======================================================================
1259 Standard_Boolean OpenGl_Workspace::GetOpenClDeviceInfo (NCollection_DataMap<TCollection_AsciiString,
1260 TCollection_AsciiString>& theInfo) const
1263 if (myComputeContext == NULL)
1265 return Standard_False;
1268 size_t aDevicesSize = 0;
1269 cl_int anError = clGetContextInfo (myComputeContext, CL_CONTEXT_DEVICES, 0, NULL, &aDevicesSize);
1270 cl_device_id* aDevices = (cl_device_id* )alloca (aDevicesSize);
1271 anError |= clGetContextInfo (myComputeContext, CL_CONTEXT_DEVICES, aDevicesSize, aDevices, NULL);
1272 if (anError != CL_SUCCESS)
1274 return Standard_False;
1277 char aDeviceName[256];
1278 anError |= clGetDeviceInfo (aDevices[0], CL_DEVICE_NAME, sizeof(aDeviceName), aDeviceName, NULL);
1279 theInfo.Bind ("Name", aDeviceName);
1281 char aDeviceVendor[256];
1282 anError |= clGetDeviceInfo (aDevices[0], CL_DEVICE_VENDOR, sizeof(aDeviceVendor), aDeviceVendor, NULL);
1283 theInfo.Bind ("Vendor", aDeviceVendor);
1285 cl_device_type aDeviceType;
1286 anError |= clGetDeviceInfo (aDevices[0], CL_DEVICE_TYPE, sizeof(aDeviceType), &aDeviceType, NULL);
1287 theInfo.Bind ("Type", aDeviceType == CL_DEVICE_TYPE_GPU ? "GPU" : "CPU");
1288 return Standard_True;
1291 // =======================================================================
1292 // function : ReleaseOpenCL
1293 // purpose : Releases resources of OpenCL objects
1294 // =======================================================================
1295 void OpenGl_Workspace::ReleaseOpenCL()
1297 clReleaseKernel (myRaytraceRenderKernel);
1298 clReleaseKernel (myRaytraceSmoothKernel);
1300 clReleaseProgram (myRaytraceProgram);
1301 clReleaseCommandQueue (myRaytraceQueue);
1303 clReleaseMemObject (myRaytraceOutputImage);
1304 clReleaseMemObject (myRaytraceEnvironment);
1305 clReleaseMemObject (myRaytraceOutputImageSmooth);
1307 clReleaseMemObject (myRaytraceVertexBuffer);
1308 clReleaseMemObject (myRaytraceNormalBuffer);
1309 clReleaseMemObject (myRaytraceTriangleBuffer);
1311 clReleaseMemObject (myRaytraceMaterialBuffer);
1312 clReleaseMemObject (myRaytraceLightSourceBuffer);
1314 clReleaseMemObject (myRaytraceNodeMinPointBuffer);
1315 clReleaseMemObject (myRaytraceNodeMaxPointBuffer);
1316 clReleaseMemObject (myRaytraceNodeDataRcrdBuffer);
1318 clReleaseContext (myComputeContext);
1320 if (glIsTexture (*myRaytraceOutputTexture))
1321 glDeleteTextures (2, myRaytraceOutputTexture);
1324 // =======================================================================
1325 // function : ResizeRaytraceOutputBuffer
1326 // purpose : Resizes OpenCL output image
1327 // =======================================================================
1328 Standard_Boolean OpenGl_Workspace::ResizeRaytraceOutputBuffer (const cl_int theSizeX,
1329 const cl_int theSizeY)
1331 if (myComputeContext == NULL)
1333 return Standard_False;
1336 bool toResize = true;
1339 if (*myRaytraceOutputTexture != 0)
1341 if (!myGlContext->IsGlGreaterEqual (2, 1))
1343 return Standard_False;
1346 glBindTexture (GL_TEXTURE_RECTANGLE, *myRaytraceOutputTexture);
1348 glGetTexLevelParameteriv (GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aSizeX);
1349 glGetTexLevelParameteriv (GL_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aSizeY);
1351 toResize = (aSizeX != theSizeX) || (aSizeY != theSizeY);
1354 glDeleteTextures (2, myRaytraceOutputTexture);
1359 return Standard_True;
1362 glGenTextures (2, myRaytraceOutputTexture);
1363 for (int aTexIter = 0; aTexIter < 2; ++aTexIter)
1365 glBindTexture (GL_TEXTURE_RECTANGLE, myRaytraceOutputTexture[aTexIter]);
1367 glTexParameteri (GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP);
1368 glTexParameteri (GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP);
1369 glTexParameteri (GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_R, GL_CLAMP);
1371 glTexParameteri (GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1372 glTexParameteri (GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1374 glTexImage2D (GL_TEXTURE_RECTANGLE, 0, GL_RGBA32F,
1375 theSizeX, theSizeY, 0,
1376 GL_RGBA, GL_FLOAT, NULL);
1379 cl_int anError = CL_SUCCESS;
1381 if (myRaytraceOutputImage != NULL)
1383 clReleaseMemObject (myRaytraceOutputImage);
1385 if (myRaytraceOutputImageSmooth != NULL)
1387 clReleaseMemObject (myRaytraceOutputImageSmooth);
1390 myRaytraceOutputImage = clCreateFromGLTexture2D (myComputeContext, CL_MEM_READ_WRITE,
1391 GL_TEXTURE_RECTANGLE, 0,
1392 myRaytraceOutputTexture[0], &anError);
1393 if (anError != CL_SUCCESS)
1395 #ifdef RAY_TRACE_PRINT_INFO
1396 std::cout << "Error! Failed to create output image!" << std::endl;
1398 return Standard_False;
1401 myRaytraceOutputImageSmooth = clCreateFromGLTexture2D (myComputeContext, CL_MEM_READ_WRITE,
1402 GL_TEXTURE_RECTANGLE, 0,
1403 myRaytraceOutputTexture[1], &anError);
1404 if (anError != CL_SUCCESS)
1406 #ifdef RAY_TRACE_PRINT_INFO
1407 std::cout << "Error! Failed to create anti-aliased output image!" << std::endl;
1409 return Standard_False;
1412 return Standard_True;
1415 // =======================================================================
1416 // function : WriteRaytraceSceneToDevice
1417 // purpose : Writes scene geometry to OpenCl device
1418 // =======================================================================
1419 Standard_Boolean OpenGl_Workspace::WriteRaytraceSceneToDevice()
1421 if (myComputeContext == NULL)
1422 return Standard_False;
1424 cl_int anError = CL_SUCCESS;
1426 if (myRaytraceNormalBuffer != NULL)
1427 anError |= clReleaseMemObject (myRaytraceNormalBuffer);
1429 if (myRaytraceVertexBuffer != NULL)
1430 anError |= clReleaseMemObject (myRaytraceVertexBuffer);
1432 if (myRaytraceTriangleBuffer != NULL)
1433 anError |= clReleaseMemObject (myRaytraceTriangleBuffer);
1435 if (myRaytraceNodeMinPointBuffer != NULL)
1436 anError |= clReleaseMemObject (myRaytraceNodeMinPointBuffer);
1438 if (myRaytraceNodeMaxPointBuffer != NULL)
1439 anError |= clReleaseMemObject (myRaytraceNodeMaxPointBuffer);
1441 if (myRaytraceNodeDataRcrdBuffer != NULL)
1442 anError |= clReleaseMemObject (myRaytraceNodeDataRcrdBuffer);
1444 if (myRaytraceMaterialBuffer != NULL)
1445 anError |= clReleaseMemObject (myRaytraceMaterialBuffer);
1447 if (anError != CL_SUCCESS)
1449 #ifdef RAY_TRACE_PRINT_INFO
1450 std::cout << "Error! Failed to release OpenCL scene buffers!" << std::endl;
1452 return Standard_False;
1455 // Create geometry buffers
1456 cl_int anErrorTemp = CL_SUCCESS;
1457 const size_t myVertexBufferSize = myRaytraceSceneData.Vertices.size() > 0
1458 ? myRaytraceSceneData.Vertices.size() : 1;
1460 myRaytraceVertexBuffer = clCreateBuffer (myComputeContext, CL_MEM_READ_ONLY,
1461 myVertexBufferSize * sizeof(cl_float4), NULL, &anErrorTemp);
1462 anError |= anErrorTemp;
1464 const size_t myNormalBufferSize = myRaytraceSceneData.Normals.size() > 0
1465 ? myRaytraceSceneData.Normals.size() : 1;
1466 myRaytraceNormalBuffer = clCreateBuffer (myComputeContext, CL_MEM_READ_ONLY,
1467 myNormalBufferSize * sizeof(cl_float4), NULL, &anErrorTemp);
1468 anError |= anErrorTemp;
1470 const size_t myTriangleBufferSize = myRaytraceSceneData.Triangles.size() > 0
1471 ? myRaytraceSceneData.Triangles.size() : 1;
1472 myRaytraceTriangleBuffer = clCreateBuffer (myComputeContext, CL_MEM_READ_ONLY,
1473 myTriangleBufferSize * sizeof(cl_int4), NULL, &anErrorTemp);
1474 anError |= anErrorTemp;
1475 if (anError != CL_SUCCESS)
1477 #ifdef RAY_TRACE_PRINT_INFO
1478 std::cout << "Error! Failed to create OpenCL geometry buffers!" << std::endl;
1480 return Standard_False;
1483 // Create material buffer
1484 const size_t myMaterialBufferSize = myRaytraceSceneData.Materials.size() > 0
1485 ? myRaytraceSceneData.Materials.size() : 1;
1486 myRaytraceMaterialBuffer = clCreateBuffer (myComputeContext, CL_MEM_READ_ONLY,
1487 myMaterialBufferSize * sizeof(OpenGl_RaytraceMaterial), NULL,
1489 if (anErrorTemp != CL_SUCCESS)
1491 #ifdef RAY_TRACE_PRINT_INFO
1492 std::cout << "Error! Failed to create OpenCL material buffer!" << std::endl;
1494 return Standard_False;
1497 // Create BVH buffers
1498 OpenGl_BVH aTree = myBVHBuilder.Tree();
1499 const size_t myNodeMinPointBufferSize = aTree.MinPointBuffer().size() > 0
1500 ? aTree.MinPointBuffer().size() : 1;
1501 myRaytraceNodeMinPointBuffer = clCreateBuffer (myComputeContext, CL_MEM_READ_ONLY,
1502 myNodeMinPointBufferSize * sizeof(cl_float4), NULL,
1504 anError |= anErrorTemp;
1506 const size_t myNodeMaxPointBufferSize = aTree.MaxPointBuffer().size() > 0
1507 ? aTree.MaxPointBuffer().size() : 1;
1508 myRaytraceNodeMaxPointBuffer = clCreateBuffer (myComputeContext, CL_MEM_READ_ONLY,
1509 myNodeMaxPointBufferSize * sizeof(cl_float4), NULL,
1511 anError |= anErrorTemp;
1513 const size_t myNodeDataRecordBufferSize = aTree.DataRcrdBuffer().size() > 0
1514 ? aTree.DataRcrdBuffer().size() : 1;
1515 myRaytraceNodeDataRcrdBuffer = clCreateBuffer (myComputeContext, CL_MEM_READ_ONLY,
1516 myNodeDataRecordBufferSize * sizeof(cl_int4), NULL,
1518 anError |= anErrorTemp;
1519 if (anError != CL_SUCCESS)
1521 #ifdef RAY_TRACE_PRINT_INFO
1522 std::cout << "Error! Failed to create OpenCL BVH buffers!" << std::endl;
1524 return Standard_False;
1527 // Write scene geometry buffers
1528 if (myRaytraceSceneData.Triangles.size() > 0)
1530 anError |= clEnqueueWriteBuffer (myRaytraceQueue, myRaytraceVertexBuffer, CL_FALSE,
1531 0, myRaytraceSceneData.Vertices.size() * sizeof(cl_float4),
1532 &myRaytraceSceneData.Vertices.front(),
1534 anError |= clEnqueueWriteBuffer (myRaytraceQueue, myRaytraceNormalBuffer, CL_FALSE,
1535 0, myRaytraceSceneData.Normals.size() * sizeof(cl_float4),
1536 &myRaytraceSceneData.Normals.front(),
1538 anError |= clEnqueueWriteBuffer (myRaytraceQueue, myRaytraceTriangleBuffer, CL_FALSE,
1539 0, myRaytraceSceneData.Triangles.size() * sizeof(cl_int4),
1540 &myRaytraceSceneData.Triangles.front(),
1542 if (anError != CL_SUCCESS)
1544 #ifdef RAY_TRACE_PRINT_INFO
1545 std::cout << "Error! Failed to write OpenCL geometry buffers!" << std::endl;
1547 return Standard_False;
1551 // Write BVH buffers
1552 if (aTree.DataRcrdBuffer().size() > 0)
1554 anError |= clEnqueueWriteBuffer (myRaytraceQueue, myRaytraceNodeMinPointBuffer, CL_FALSE,
1555 0, aTree.MinPointBuffer().size() * sizeof(cl_float4),
1556 &aTree.MinPointBuffer().front(),
1558 anError |= clEnqueueWriteBuffer (myRaytraceQueue, myRaytraceNodeMaxPointBuffer, CL_FALSE,
1559 0, aTree.MaxPointBuffer().size() * sizeof(cl_float4),
1560 &aTree.MaxPointBuffer().front(),
1562 anError |= clEnqueueWriteBuffer (myRaytraceQueue, myRaytraceNodeDataRcrdBuffer, CL_FALSE,
1563 0, aTree.DataRcrdBuffer().size() * sizeof(cl_int4),
1564 &aTree.DataRcrdBuffer().front(),
1566 if (anError != CL_SUCCESS)
1568 #ifdef RAY_TRACE_PRINT_INFO
1569 std::cout << "Error! Failed to write OpenCL BVH buffers!" << std::endl;
1571 return Standard_False;
1575 // Write material buffers
1576 if (myRaytraceSceneData.Materials.size() > 0)
1578 const size_t aSize = myRaytraceSceneData.Materials.size();
1579 const void* aDataPtr = myRaytraceSceneData.Materials.front().Packed();
1581 anError |= clEnqueueWriteBuffer (myRaytraceQueue, myRaytraceMaterialBuffer, CL_FALSE,
1582 0, aSize * sizeof(OpenGl_RaytraceMaterial), aDataPtr,
1584 if (anError != CL_SUCCESS)
1586 #ifdef RAY_TRACE_PRINT_INFO
1587 std::cout << "Error! Failed to write OpenCL material buffer!" << std::endl;
1589 return Standard_False;
1593 anError |= clFinish (myRaytraceQueue);
1594 #ifdef RAY_TRACE_PRINT_INFO
1595 if (anError != CL_SUCCESS)
1596 std::cout << "Error! Failed to set scene data buffers!" << std::endl;
1599 if (anError == CL_SUCCESS)
1600 myIsRaytraceDataValid = myRaytraceSceneData.Triangles.size() > 0;
1602 #ifdef RAY_TRACE_PRINT_INFO
1604 float aMemUsed = static_cast<float> (
1605 myRaytraceSceneData.Materials.size()) * sizeof (OpenGl_RaytraceMaterial);
1607 aMemUsed += static_cast<float> (
1608 myRaytraceSceneData.Triangles.size() * sizeof (OpenGl_RTVec4i) +
1609 myRaytraceSceneData.Vertices.size() * sizeof (OpenGl_RTVec4f) +
1610 myRaytraceSceneData.Normals.size() * sizeof (OpenGl_RTVec4f));
1612 aMemUsed += static_cast<float> (
1613 aTree.MinPointBuffer().size() * sizeof (OpenGl_RTVec4f) +
1614 aTree.MaxPointBuffer().size() * sizeof (OpenGl_RTVec4f) +
1615 aTree.DataRcrdBuffer().size() * sizeof (OpenGl_RTVec4i));
1617 std::cout << "GPU memory used (Mb): " << aMemUsed / 1e6f << std::endl;
1621 myRaytraceSceneData.Clear();
1623 myBVHBuilder.CleanUp();
1625 return (CL_SUCCESS == anError);
1628 #define OPENCL_GROUP_SIZE_TEST_
1630 // =======================================================================
1631 // function : RunRaytraceOpenCLKernels
1632 // purpose : Runs OpenCL ray-tracing kernels
1633 // =======================================================================
1634 Standard_Boolean OpenGl_Workspace::RunRaytraceOpenCLKernels (const Graphic3d_CView& theCView,
1635 const GLfloat theOrigins[16],
1636 const GLfloat theDirects[16],
1640 if (myRaytraceRenderKernel == NULL || myRaytraceQueue == NULL)
1641 return Standard_False;
1643 ////////////////////////////////////////////////////////////
1644 // Set kernel arguments
1646 cl_uint anIndex = 0;
1649 anError = clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1650 sizeof(cl_mem), &myRaytraceOutputImage);
1651 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1652 sizeof(cl_mem), &myRaytraceEnvironment);
1653 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1654 sizeof(cl_mem), &myRaytraceNodeMinPointBuffer);
1655 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1656 sizeof(cl_mem), &myRaytraceNodeMaxPointBuffer);
1657 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1658 sizeof(cl_mem), &myRaytraceNodeDataRcrdBuffer);
1659 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1660 sizeof(cl_mem), &myRaytraceLightSourceBuffer);
1661 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1662 sizeof(cl_mem), &myRaytraceMaterialBuffer);
1663 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1664 sizeof(cl_mem), &myRaytraceVertexBuffer);
1665 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1666 sizeof(cl_mem), &myRaytraceNormalBuffer);
1667 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1668 sizeof(cl_mem), &myRaytraceTriangleBuffer);
1670 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1671 sizeof(cl_float16), theOrigins);
1672 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1673 sizeof(cl_float16), theDirects);
1675 cl_int aLightCount = static_cast<cl_int> (myRaytraceSceneData.LightSources.size());
1677 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1678 sizeof(cl_int), &aLightCount);
1679 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1680 sizeof(cl_float), &myRaytraceSceneEpsilon);
1681 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1682 sizeof(cl_float), &myRaytraceSceneRadius);
1683 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1684 sizeof(cl_int), &theCView.IsShadowsEnabled);
1685 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1686 sizeof(cl_int), &theCView.IsReflectionsEnabled);
1687 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1688 sizeof(cl_int), &theSizeX);
1689 anError |= clSetKernelArg (myRaytraceRenderKernel, anIndex++,
1690 sizeof(cl_int), &theSizeY);
1691 if (anError != CL_SUCCESS)
1693 const TCollection_ExtendedString aMsg = "Error! Failed to set arguments of ray-tracing kernel!";
1694 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1695 GL_DEBUG_TYPE_ERROR_ARB,
1697 GL_DEBUG_SEVERITY_HIGH_ARB,
1699 return Standard_False;
1702 // Note: second-pass 'smoothing' kernel runs only if anti-aliasing is enabled
1703 if (theCView.IsAntialiasingEnabled)
1706 anError = clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1707 sizeof(cl_mem), &myRaytraceOutputImage);
1708 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1709 sizeof(cl_mem), &myRaytraceOutputImageSmooth);
1710 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1711 sizeof(cl_mem), &myRaytraceEnvironment);
1712 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1713 sizeof(cl_mem), &myRaytraceNodeMinPointBuffer);
1714 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1715 sizeof(cl_mem), &myRaytraceNodeMaxPointBuffer);
1716 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1717 sizeof(cl_mem), &myRaytraceNodeDataRcrdBuffer);
1718 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1719 sizeof(cl_mem), &myRaytraceLightSourceBuffer);
1720 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1721 sizeof(cl_mem), &myRaytraceMaterialBuffer);
1722 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1723 sizeof(cl_mem), &myRaytraceVertexBuffer);
1724 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1725 sizeof(cl_mem), &myRaytraceNormalBuffer);
1726 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1727 sizeof(cl_mem), &myRaytraceTriangleBuffer);
1729 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1730 sizeof(cl_float16), theOrigins);
1731 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1732 sizeof(cl_float16), theDirects);
1734 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1735 sizeof(cl_int), &aLightCount);
1736 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1737 sizeof(cl_float), &myRaytraceSceneEpsilon);
1738 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1739 sizeof(cl_float), &myRaytraceSceneRadius);
1740 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1741 sizeof(cl_int), &theCView.IsShadowsEnabled);
1742 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1743 sizeof(cl_int), &theCView.IsReflectionsEnabled);
1744 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1745 sizeof(cl_int), &theSizeX);
1746 anError |= clSetKernelArg (myRaytraceSmoothKernel, anIndex++,
1747 sizeof(cl_int), &theSizeY);
1748 if (anError != CL_SUCCESS)
1750 const TCollection_ExtendedString aMsg = "Error! Failed to set arguments of 'smoothing' kernel!";
1751 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1752 GL_DEBUG_TYPE_ERROR_ARB,
1754 GL_DEBUG_SEVERITY_HIGH_ARB,
1756 return Standard_False;
1761 size_t aLocSizeRender[] = { myIsAmdComputePlatform ? 2 : 4, 32 };
1763 #ifdef OPENCL_GROUP_SIZE_TEST
1764 for (size_t aLocX = 2; aLocX <= 32; aLocX <<= 1 )
1765 for (size_t aLocY = 2; aLocY <= 32; aLocY <<= 1 )
1768 #ifdef OPENCL_GROUP_SIZE_TEST
1769 aLocSizeRender[0] = aLocX;
1770 aLocSizeRender[1] = aLocY;
1773 size_t aWorkSizeX = theSizeX;
1774 if (aWorkSizeX % aLocSizeRender[0] != 0)
1775 aWorkSizeX += aLocSizeRender[0] - aWorkSizeX % aLocSizeRender[0];
1777 size_t aWokrSizeY = theSizeY;
1778 if (aWokrSizeY % aLocSizeRender[1] != 0 )
1779 aWokrSizeY += aLocSizeRender[1] - aWokrSizeY % aLocSizeRender[1];
1781 size_t aGlbSizeRender[] = { aWorkSizeX, aWokrSizeY };
1784 cl_event anEvent (NULL), anEventSmooth (NULL);
1785 anError = clEnqueueNDRangeKernel (myRaytraceQueue, myRaytraceRenderKernel,
1786 2, NULL, aGlbSizeRender, aLocSizeRender,
1788 if (anError != CL_SUCCESS)
1790 const TCollection_ExtendedString aMsg = "Error! Failed to execute the ray-tracing kernel!";
1791 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1792 GL_DEBUG_TYPE_ERROR_ARB,
1794 GL_DEBUG_SEVERITY_HIGH_ARB,
1796 return Standard_False;
1798 clWaitForEvents (1, &anEvent);
1800 if (theCView.IsAntialiasingEnabled)
1802 size_t aLocSizeSmooth[] = { myIsAmdComputePlatform ? 8 : 4,
1803 myIsAmdComputePlatform ? 8 : 32 };
1805 #ifdef OPENCL_GROUP_SIZE_TEST
1806 aLocSizeSmooth[0] = aLocX;
1807 aLocSizeSmooth[1] = aLocY;
1810 aWorkSizeX = theSizeX;
1811 if (aWorkSizeX % aLocSizeSmooth[0] != 0)
1812 aWorkSizeX += aLocSizeSmooth[0] - aWorkSizeX % aLocSizeSmooth[0];
1814 size_t aWokrSizeY = theSizeY;
1815 if (aWokrSizeY % aLocSizeSmooth[1] != 0 )
1816 aWokrSizeY += aLocSizeSmooth[1] - aWokrSizeY % aLocSizeSmooth[1];
1818 size_t aGlbSizeSmooth [] = { aWorkSizeX, aWokrSizeY };
1819 anError = clEnqueueNDRangeKernel (myRaytraceQueue, myRaytraceSmoothKernel,
1820 2, NULL, aGlbSizeSmooth, aLocSizeSmooth,
1821 0, NULL, &anEventSmooth);
1822 clWaitForEvents (1, &anEventSmooth);
1824 if (anError != CL_SUCCESS)
1826 const TCollection_ExtendedString aMsg = "Error! Failed to execute the 'smoothing' kernel!";
1827 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
1828 GL_DEBUG_TYPE_ERROR_ARB,
1830 GL_DEBUG_SEVERITY_HIGH_ARB,
1832 return Standard_False;
1836 // Get the profiling data
1837 #if defined (RAY_TRACE_PRINT_INFO) || defined(OPENCL_GROUP_SIZE_TEST)
1839 cl_ulong aTimeStart,
1842 clGetEventProfilingInfo (anEvent, CL_PROFILING_COMMAND_START,
1843 sizeof(aTimeStart), &aTimeStart, NULL);
1844 clGetEventProfilingInfo (anEvent, CL_PROFILING_COMMAND_END,
1845 sizeof(aTimeFinal), &aTimeFinal, NULL);
1846 std::cout << "\tRender time (ms): " << ( aTimeFinal - aTimeStart ) / 1e6f << std::endl;
1848 if (theCView.IsAntialiasingEnabled)
1850 clGetEventProfilingInfo (anEventSmooth, CL_PROFILING_COMMAND_START,
1851 sizeof(aTimeStart), &aTimeStart, NULL);
1852 clGetEventProfilingInfo (anEventSmooth, CL_PROFILING_COMMAND_END,
1853 sizeof(aTimeFinal), &aTimeFinal, NULL);
1854 std::cout << "\tSmoothing time (ms): " << ( aTimeFinal - aTimeStart ) / 1e6f << std::endl;
1858 if (anEvent != NULL)
1859 clReleaseEvent (anEvent);
1861 if (anEventSmooth != NULL)
1862 clReleaseEvent (anEventSmooth);
1865 return Standard_True;
1868 // =======================================================================
1869 // function : ComputeInverseMatrix
1870 // purpose : Computes inversion of 4x4 floating-point matrix
1871 // =======================================================================
1872 template <typename T>
1873 void ComputeInverseMatrix (const T m[16], T inv[16])
1875 inv[ 0] = m[ 5] * (m[10] * m[15] - m[11] * m[14]) -
1876 m[ 9] * (m[ 6] * m[15] - m[ 7] * m[14]) -
1877 m[13] * (m[ 7] * m[10] - m[ 6] * m[11]);
1879 inv[ 1] = m[ 1] * (m[11] * m[14] - m[10] * m[15]) -
1880 m[ 9] * (m[ 3] * m[14] - m[ 2] * m[15]) -
1881 m[13] * (m[ 2] * m[11] - m[ 3] * m[10]);
1883 inv[ 2] = m[ 1] * (m[ 6] * m[15] - m[ 7] * m[14]) -
1884 m[ 5] * (m[ 2] * m[15] - m[ 3] * m[14]) -
1885 m[13] * (m[ 3] * m[ 6] - m[ 2] * m[ 7]);
1887 inv[ 3] = m[ 1] * (m[ 7] * m[10] - m[ 6] * m[11]) -
1888 m[ 5] * (m[ 3] * m[10] - m[ 2] * m[11]) -
1889 m[ 9] * (m[ 2] * m[ 7] - m[ 3] * m[ 6]);
1891 inv[ 4] = m[ 4] * (m[11] * m[14] - m[10] * m[15]) -
1892 m[ 8] * (m[ 7] * m[14] - m[ 6] * m[15]) -
1893 m[12] * (m[ 6] * m[11] - m[ 7] * m[10]);
1895 inv[ 5] = m[ 0] * (m[10] * m[15] - m[11] * m[14]) -
1896 m[ 8] * (m[ 2] * m[15] - m[ 3] * m[14]) -
1897 m[12] * (m[ 3] * m[10] - m[ 2] * m[11]);
1899 inv[ 6] = m[ 0] * (m[ 7] * m[14] - m[ 6] * m[15]) -
1900 m[ 4] * (m[ 3] * m[14] - m[ 2] * m[15]) -
1901 m[12] * (m[ 2] * m[ 7] - m[ 3] * m[ 6]);
1903 inv[ 7] = m[ 0] * (m[ 6] * m[11] - m[ 7] * m[10]) -
1904 m[ 4] * (m[ 2] * m[11] - m[ 3] * m[10]) -
1905 m[ 8] * (m[ 3] * m[ 6] - m[ 2] * m[ 7]);
1907 inv[ 8] = m[ 4] * (m[ 9] * m[15] - m[11] * m[13]) -
1908 m[ 8] * (m[ 5] * m[15] - m[ 7] * m[13]) -
1909 m[12] * (m[ 7] * m[ 9] - m[ 5] * m[11]);
1911 inv[ 9] = m[ 0] * (m[11] * m[13] - m[ 9] * m[15]) -
1912 m[ 8] * (m[ 3] * m[13] - m[ 1] * m[15]) -
1913 m[12] * (m[ 1] * m[11] - m[ 3] * m[ 9]);
1915 inv[10] = m[ 0] * (m[ 5] * m[15] - m[ 7] * m[13]) -
1916 m[ 4] * (m[ 1] * m[15] - m[ 3] * m[13]) -
1917 m[12] * (m[ 3] * m[ 5] - m[ 1] * m[ 7]);
1919 inv[11] = m[ 0] * (m[ 7] * m[ 9] - m[ 5] * m[11]) -
1920 m[ 4] * (m[ 3] * m[ 9] - m[ 1] * m[11]) -
1921 m[ 8] * (m[ 1] * m[ 7] - m[ 3] * m[ 5]);
1923 inv[12] = m[ 4] * (m[10] * m[13] - m[ 9] * m[14]) -
1924 m[ 8] * (m[ 6] * m[13] - m[ 5] * m[14]) -
1925 m[12] * (m[ 5] * m[10] - m[ 6] * m[ 9]);
1927 inv[13] = m[ 0] * (m[ 9] * m[14] - m[10] * m[13]) -
1928 m[ 8] * (m[ 1] * m[14] - m[ 2] * m[13]) -
1929 m[12] * (m[ 2] * m[ 9] - m[ 1] * m[10]);
1931 inv[14] = m[ 0] * (m[ 6] * m[13] - m[ 5] * m[14]) -
1932 m[ 4] * (m[ 2] * m[13] - m[ 1] * m[14]) -
1933 m[12] * (m[ 1] * m[ 6] - m[ 2] * m[ 5]);
1935 inv[15] = m[ 0] * (m[ 5] * m[10] - m[ 6] * m[ 9]) -
1936 m[ 4] * (m[ 1] * m[10] - m[ 2] * m[ 9]) -
1937 m[ 8] * (m[ 2] * m[ 5] - m[ 1] * m[ 6]);
1939 T det = m[0] * inv[ 0] +
1944 if (det == T (0.0)) return;
1946 det = T (1.0) / det;
1948 for (int i = 0; i < 16; ++i)
1952 // =======================================================================
1953 // function : GenerateCornerRays
1954 // purpose : Generates primary rays for corners of screen quad
1955 // =======================================================================
1956 void GenerateCornerRays (const GLdouble theInvModelProj[16],
1957 float theOrigins[16],
1958 float theDirects[16])
1960 int aOriginIndex = 0;
1961 int aDirectIndex = 0;
1963 for (int y = -1; y <= 1; y += 2)
1965 for (int x = -1; x <= 1; x += 2)
1967 OpenGl_RTVec4f aOrigin (float(x),
1972 aOrigin = MatVecMult (theInvModelProj, aOrigin);
1974 OpenGl_RTVec4f aDirect (float(x),
1979 aDirect = MatVecMult (theInvModelProj, aDirect) - aOrigin;
1981 GLdouble aInvLen = 1.f / sqrt (aDirect.x() * aDirect.x() +
1982 aDirect.y() * aDirect.y() +
1983 aDirect.z() * aDirect.z());
1985 theOrigins [aOriginIndex++] = static_cast<GLfloat> (aOrigin.x());
1986 theOrigins [aOriginIndex++] = static_cast<GLfloat> (aOrigin.y());
1987 theOrigins [aOriginIndex++] = static_cast<GLfloat> (aOrigin.z());
1988 theOrigins [aOriginIndex++] = 1.f;
1990 theDirects [aDirectIndex++] = static_cast<GLfloat> (aDirect.x() * aInvLen);
1991 theDirects [aDirectIndex++] = static_cast<GLfloat> (aDirect.y() * aInvLen);
1992 theDirects [aDirectIndex++] = static_cast<GLfloat> (aDirect.z() * aInvLen);
1993 theDirects [aDirectIndex++] = 0.f;
1998 // =======================================================================
1999 // function : Raytrace
2000 // purpose : Redraws the window using OpenCL ray tracing
2001 // =======================================================================
2002 Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView,
2005 const Tint theToSwap)
2008 return Standard_False;
2010 if (!ResizeRaytraceOutputBuffer (theSizeX, theSizeY))
2011 return Standard_False;
2013 if (!UpdateRaytraceEnvironmentMap())
2014 return Standard_False;
2016 if (!UpdateRaytraceGeometry (Standard_True))
2017 return Standard_False;
2019 // Get model-view and projection matrices
2020 TColStd_Array2OfReal theOrientation (0, 3, 0, 3);
2021 TColStd_Array2OfReal theViewMapping (0, 3, 0, 3);
2023 myView->GetMatrices (theOrientation, theViewMapping, Standard_True);
2025 GLdouble aOrientationMatrix[16];
2026 GLdouble aViewMappingMatrix[16];
2027 GLdouble aOrientationInvers[16];
2029 for (int j = 0; j < 4; ++j)
2030 for (int i = 0; i < 4; ++i)
2032 aOrientationMatrix [4 * j + i] = theOrientation (i, j);
2033 aViewMappingMatrix [4 * j + i] = theViewMapping (i, j);
2036 ComputeInverseMatrix (aOrientationMatrix, aOrientationInvers);
2038 if (!UpdateRaytraceLightSources (aOrientationInvers))
2039 return Standard_False;
2041 // Generate primary rays for corners of the screen quad
2042 glMatrixMode (GL_MODELVIEW);
2044 glLoadMatrixd (aViewMappingMatrix);
2045 glMultMatrixd (aOrientationMatrix);
2047 GLdouble aModelProject[16];
2048 GLdouble aInvModelProj[16];
2050 glGetDoublev (GL_MODELVIEW_MATRIX, aModelProject);
2052 ComputeInverseMatrix (aModelProject, aInvModelProj);
2054 GLfloat aOrigins[16];
2055 GLfloat aDirects[16];
2057 GenerateCornerRays (aInvModelProj,
2061 // Compute ray-traced image using OpenCL kernel
2062 cl_mem anImages[] = { myRaytraceOutputImage, myRaytraceOutputImageSmooth };
2063 cl_int anError = clEnqueueAcquireGLObjects (myRaytraceQueue,
2066 clFinish (myRaytraceQueue);
2068 if (myIsRaytraceDataValid)
2070 RunRaytraceOpenCLKernels (theCView,
2077 anError |= clEnqueueReleaseGLObjects (myRaytraceQueue,
2080 clFinish (myRaytraceQueue);
2083 glPushAttrib (GL_ENABLE_BIT |
2085 GL_COLOR_BUFFER_BIT |
2086 GL_DEPTH_BUFFER_BIT);
2088 glDisable (GL_DEPTH_TEST);
2090 if (NamedStatus & OPENGL_NS_WHITEBACK)
2092 glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
2096 glClearColor (myBgColor.rgb[0],
2102 glClear (GL_COLOR_BUFFER_BIT);
2104 Handle(OpenGl_Workspace) aWorkspace (this);
2105 myView->DrawBackground (aWorkspace);
2107 // Draw dummy quad to show result image
2108 glEnable (GL_COLOR_MATERIAL);
2109 glEnable (GL_BLEND);
2111 glDisable (GL_DEPTH_TEST);
2113 glBlendFunc (GL_ONE, GL_SRC_ALPHA);
2115 glEnable (GL_TEXTURE_RECTANGLE);
2117 glMatrixMode (GL_PROJECTION);
2120 glMatrixMode (GL_MODELVIEW);
2123 glColor3f (1.0f, 1.0f, 1.0f);
2125 glBindTexture (GL_TEXTURE_RECTANGLE, myRaytraceOutputTexture[theCView.IsAntialiasingEnabled ? 1 : 0]);
2127 if (myIsRaytraceDataValid)
2131 glTexCoord2i ( 0, 0); glVertex2f (-1.f, -1.f);
2132 glTexCoord2i ( 0, theSizeY); glVertex2f (-1.f, 1.f);
2133 glTexCoord2i (theSizeX, theSizeY); glVertex2f ( 1.f, 1.f);
2134 glTexCoord2i (theSizeX, 0); glVertex2f ( 1.f, -1.f);
2144 GetGlContext()->SwapBuffers();
2145 myBackBufferRestored = Standard_False;
2150 return Standard_True;