1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2006 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
41 //---------------------------------------------------------------------------
46 #include "OSGConfig.h"
48 #include "OSGComputeShaderChunk.h"
49 #include "OSGDrawEnv.h"
51 #include "OSGShaderVariables.h"
52 #include "OSGConceptPropertyChecks.h"
54 #include <boost/bind.hpp>
58 // Documentation for this class is emitted in the
59 // OSGComputeShaderChunkBase.cpp file.
60 // To modify it, please change the .fcd file (OSGComputeShaderChunk.fcd) and
61 // regenerate the base file.
63 /***************************************************************************\
65 \***************************************************************************/
67 StateChunkClass
ComputeShaderChunk::_class("ShaderProgram", 1, 40);
69 volatile UInt16
ComputeShaderChunk::_uiChunkCounter
= 1;
71 UInt32
ComputeShaderChunk::_arbComputeShader
= Window::invalidExtensionID
;
73 /***************************************************************************\
75 \***************************************************************************/
77 void ComputeShaderChunk::initMethod(InitPhase ePhase
)
79 Inherited::initMethod(ePhase
);
81 if(ePhase
== TypeObject::SystemPost
)
84 Window::registerExtension("GL_ARB_compute_shader");
88 UInt32
ComputeShaderChunk::handleGL(DrawEnv
*pEnv
,
90 Window::GLObjectStatusE mode
,
93 UInt32 returnValue
= 0;
94 Window
*pWin
= pEnv
->getWindow();
96 if(!pWin
->hasExtOrVersion(_arbComputeShader
, 0x0403, 0xFFFF))
98 FWARNING(("OpenGL compute shader is not supported, couldn't find "
99 "extension 'GL_ARB_compute_shader'!\n"));
101 pWin
->setGLObjectId(getGLId(), 0);
106 if(mode
== Window::initialize
||
107 mode
== Window::reinitialize
||
108 mode
== Window::needrefresh
)
110 GLuint uiProgram
= GLuint(pWin
->getGLObjectId(getGLId()));;
112 if(mode
!= Window::needrefresh
)
116 OSGGETGLFUNCBYID_GL3_ES(glDeleteProgram
,
118 ShaderProgram::getFuncIdDeleteProgram(),
121 osgGlDeleteProgram(uiProgram
);
124 OSGGETGLFUNCBYID_GL3_ES(glCreateProgram
,
126 ShaderProgram::getFuncIdCreateProgram(),
129 OSGGETGLFUNCBYID_GL3_ES(glAttachShader
,
131 ShaderProgram::getFuncIdAttachShader(),
134 OSGGETGLFUNCBYID_GL3_ES(glLinkProgram
,
136 ShaderProgram::getFuncIdLinkProgram(),
139 uiProgram
= osgGlCreateProgram();
141 ComputeShaderIt vIt
= _mfComputeShader
.begin();
142 ComputeShaderIt vEnd
= _mfComputeShader
.end ();
144 for(; vIt
!= vEnd
; ++vIt
)
146 (*vIt
)->validate(pEnv
);
149 GLuint(pWin
->getGLObjectId((*vIt
)->getGLId()));
152 osgGlAttachShader(uiProgram
, uiShader
);
155 osgGlLinkProgram(uiProgram
);
158 Char8
*szInfoBuffer
= NULL
;
160 OSGGETGLFUNCBYID_GL3_ES(glGetProgramiv
,
162 ShaderProgram::getFuncIdGetProgramiv(),
165 osgGlGetProgramiv(uiProgram
,
166 GL_OBJECT_INFO_LOG_LENGTH_ARB
,
171 szInfoBuffer
= new Char8
[iInfoLength
];
172 szInfoBuffer
[0] = '\0';
174 OSGGETGLFUNCBYID_GL3_ES(
176 osgGlGetProgramInfoLog
,
177 ShaderProgram::getFuncIdGetProgramInfoLog(),
180 osgGlGetProgramInfoLog( uiProgram
,
188 osgGlGetProgramiv(uiProgram
, GL_LINK_STATUS
, &iStatus
);
192 if(szInfoBuffer
!= NULL
&& szInfoBuffer
[0] != '\0')
194 FFATAL(("Couldn't link compute program!\n%s\n",
199 FFATAL(("Couldn't link compute program!\n"
200 "No further info available\n"));
203 OSGGETGLFUNCBYID_GL3_ES(glDeleteProgram
,
205 ShaderProgram::getFuncIdDeleteProgram(),
208 osgGlDeleteProgram(uiProgram
);
214 if(szInfoBuffer
!= NULL
&& szInfoBuffer
[0] != '\0')
216 FWARNING(("ComputeShaderChunk: link status: %s\n",
221 pWin
->setGLObjectId(getGLId(), uiProgram
);
223 updateVariableLocations(pEnv
, uiProgram
);
228 OSGGETGLFUNCBYID_GL3_ES(glUseProgram
,
230 ShaderProgram::getFuncIdUseProgram(),
233 osgGlUseProgram(uiProgram
);
235 updateVariables(pEnv
, uiProgram
);
237 if(0x0000 == (uiOptions
& KeepProgActive
))
243 returnValue
|= ProgActive
;
251 void ComputeShaderChunk::handleDestroyGL(DrawEnv
*pEnv
,
253 Window::GLObjectStatusE mode
)
255 Window
*pWin
= pEnv
->getWindow();
257 if(!pWin
->hasExtOrVersion(_arbComputeShader
, 0x0403, 0xFFFF))
259 FWARNING(("OpenGL Shading Language is not supported, couldn't find "
260 "extension 'GL_ARB_shading_language_100'!\n"));
262 pWin
->setGLObjectId(id
, 0);
267 // BUG this is not called for every window!
268 if(mode
== Window::destroy
)
270 GLuint uiProgram
= GLuint(pWin
->getGLObjectId(id
));
274 OSGGETGLFUNCBYID_GL3_ES(glDeleteProgram
,
276 ShaderProgram::getFuncIdDeleteProgram(),
279 osgGlDeleteProgram(uiProgram
);
281 pWin
->setGLObjectId(id
, 0);
284 else if(mode
== Window::finaldestroy
)
286 ;//SWARNING << "Last program user destroyed" << std::endl;
290 /***************************************************************************\
292 \***************************************************************************/
294 /*-------------------------------------------------------------------------*\
296 \*-------------------------------------------------------------------------*/
298 /*----------------------- constructors & destructors ----------------------*/
300 ComputeShaderChunk::ComputeShaderChunk(void) :
306 ComputeShaderChunk::ComputeShaderChunk(const ComputeShaderChunk
&source
) :
312 ComputeShaderChunk::~ComputeShaderChunk(void)
316 void ComputeShaderChunk::onCreate(const ComputeShaderChunk
*source
)
318 Inherited::onCreate(source
);
320 // ignore prototypes.
321 if(GlobalSystemState
== Startup
)
325 Window::registerGLObject(
326 boost::bind(&ComputeShaderChunk::handleGL
,
327 ComputeShaderChunkMTUncountedPtr(this),
329 &ComputeShaderChunk::handleDestroyGL
));
331 _uiChunkId
= ComputeShaderChunk::_uiChunkCounter
++;
334 void ComputeShaderChunk::onCreateAspect(const ComputeShaderChunk
*createAspect
,
335 const ComputeShaderChunk
*source
)
337 Inherited::onCreateAspect(createAspect
, source
);
339 _uiChunkId
= createAspect
->_uiChunkId
;
342 void ComputeShaderChunk::onDestroy(UInt32 uiId
)
345 Window::destroyGLObject(getGLId(), 1);
347 Inherited::onDestroy(uiId
);
350 const StateChunkClass
*ComputeShaderChunk::getClass(void) const
355 UInt16
ComputeShaderChunk::getChunkId(void)
360 /*----------------------------- class specific ----------------------------*/
362 void ComputeShaderChunk::changed(ConstFieldMaskArg whichField
,
366 bool bMarkChanged
= false;
368 if(0x0000 != (whichField
& ComputeProgramFieldMask
) &&
369 0 != _sfComputeProgram
.getValue().size() )
371 if(_mfComputeShader
.size() == 0)
373 ShaderProgramUnrecPtr pProg
= ShaderProgram::createDependent(
374 this->getFieldFlags()->_bNamespaceMask
);
376 pProg
->setShaderType(GL_COMPUTE_SHADER
);
378 addComputeShader(pProg
);
380 pProg
->setVariables(this->getVariables());
382 else if(_mfComputeShader
.size() > 1)
384 editMFComputeShader()->resize(1);
387 _mfComputeShader
[0]->setProgram(_sfComputeProgram
.getValue());
391 Window::reinitializeGLObject(this->getGLId());
395 if(0x0000 != (whichField
& VariablesFieldMask
))
397 ShaderProgramVariables
*pVars
= _sfVariables
.getValue();
401 if(details
== 0x0001)
403 // be save reset all locations
405 if(pVars
->getMFVariables()->size() == 0)
407 editMFVariableLocations()->clear();
411 editMFVariableLocations()->resize(
412 pVars
->getMFVariables()->size(),
415 std::fill(editMFVariableLocations()->begin(),
416 editMFVariableLocations()->end (),
420 // be save reset all locations
422 if(pVars
->getMFProceduralVariables()->size() == 0 )
424 editMFProceduralVariableLocations()->clear();
428 editMFProceduralVariableLocations()->resize(
429 pVars
->getMFProceduralVariables()->size(),
432 std::fill(editMFProceduralVariableLocations()->begin(),
433 editMFProceduralVariableLocations()->end (),
439 Window::refreshGLObject(this->getGLId());
442 if(0x0000 != (whichField
& ComputeShaderFieldMask
))
446 Window::reinitializeGLObject(this->getGLId());
449 if(bMarkChanged
== true)
451 // be save reset all locations
453 std::fill(editMFVariableLocations()->begin(),
454 editMFVariableLocations()->end (),
457 std::fill(editMFProceduralVariableLocations()->begin(),
458 editMFProceduralVariableLocations()->end (),
461 if(_sfVariables
.getValue() != NULL
)
463 _sfVariables
.getValue()->markAllChanged();
467 Inherited::changed(whichField
, origin
, details
);
470 void ComputeShaderChunk::activate(DrawEnv
*pEnv
,
473 Window
*pWin
= pEnv
->getWindow();
475 UInt32 uiValRes
= pWin
->validateGLObject(getGLId(),
479 GLuint uiProgId
= GLuint(pWin
->getGLObjectId(getGLId()));
484 pEnv
->setActiveShader(uiProgId
);
486 if(0x0000 == (uiValRes
& ProgActive
))
488 OSGGETGLFUNCBYID_GL3_ES(glUseProgram
,
490 ShaderProgram::getFuncIdUseProgram(),
493 osgGlUseProgram(uiProgId
);
496 pEnv
->incNumShaderChanges();
498 updateProceduralVariables(pEnv
, ShaderProcVariable::SHDAll
);
502 void ComputeShaderChunk::changeFrom(DrawEnv
*pEnv
,
506 ComputeShaderChunk
*pOld
= dynamic_cast<ComputeShaderChunk
*>(pOther
);
508 // pOther can be a ShaderExecutableChunk, since we share the StateClass id
512 Window
*pWin
= pEnv
->getWindow();
513 GLuint uiProgId
= GLuint(pWin
->getGLObjectId(getGLId()));
515 UInt32 uiDep
= ShaderProcVariable::SHDObject
;
517 if(uiProgId
!= pEnv
->getActiveShader())
519 UInt32 uiValRes
= pWin
->validateGLObject(getGLId(),
523 uiProgId
= GLuint(pWin
->getGLObjectId(getGLId()));
528 pEnv
->setActiveShader(uiProgId
);
530 if(0x0000 == (uiValRes
& ProgActive
))
532 OSGGETGLFUNCBYID_GL3_ES(glUseProgram
,
534 ShaderProgram::getFuncIdUseProgram(),
537 osgGlUseProgram(uiProgId
);
540 uiDep
= ShaderProcVariable::SHDAll
;
542 pEnv
->incNumShaderChanges();
545 updateProceduralVariables(pEnv
, uiDep
);
549 pOther
->deactivate(pEnv
, uiIdx
);
550 activate (pEnv
, uiIdx
);
552 pEnv
->incNumShaderChanges();
556 void ComputeShaderChunk::deactivate(DrawEnv
*pEnv
,
559 if(pEnv
->getWindow()->getGLObjectId(getGLId()) == 0)
562 pEnv
->setActiveShader(0);
564 OSGGETGLFUNC_GL3_ES(glUseProgram
,
566 ShaderProgram::getFuncIdUseProgram());
571 void ComputeShaderChunk::dump( UInt32
,
572 const BitVector
) const
574 SLOG
<< "Dump ComputeShaderChunk NI" << std::endl
;
577 bool ComputeShaderChunk::readComputeProgram(const Char8
*file
)
579 return readProgram(editSFComputeProgram()->getValue(), file
);
582 bool ComputeShaderChunk::readProgram( std::string
&szTarget
,
583 const Char8
*szFilename
)
585 std::ifstream
s(szFilename
);
589 return readProgram(szTarget
, s
);
593 FWARNING(("ShaderChunk::readProgram: couldn't open '%s' "
594 "for reading!\n", szFilename
));
601 bool ComputeShaderChunk::readProgram(std::string
&szTarget
,
602 std::istream
&iStream
)
612 FWARNING(("SHLChunk::readProgram: stream is not good!\n"));
619 iStream
.read(buf
, BUFSIZE
);
621 szTarget
.append(buf
, iStream
.gcount());
623 while(!iStream
.eof());
628 bool ComputeShaderChunk::subUniformVariable(const Char8
*name
)
630 if(_sfVariables
.getValue() != NULL
)
632 return _sfVariables
.getValue()->subUniformVariable(
634 editMFVariableLocations(),
635 editMFProceduralVariableLocations());
642 void ComputeShaderChunk::clearUniformVariables(void)
644 if(_sfVariables
.getValue() != NULL
)
646 _sfVariables
.getValue()->clearUniformVariables();
649 editMFVariableLocations ()->clear();
650 editMFProceduralVariableLocations()->clear();
653 bool ComputeShaderChunk::addOSGVariable(const Char8
*name
)
655 if(_sfVariables
.getValue() == NULL
)
657 ShaderProgramVariablesUnrecPtr pVar
=
658 ShaderProgramVariables::createDependent(
659 this->getFieldFlags()->_bNamespaceMask
);
663 if(_mfComputeShader
.size() > 0)
665 _mfComputeShader
[0]->setVariables(this->getVariables());
669 return _sfVariables
.getValue()->addOSGVariable(
671 editMFProceduralVariableLocations());
674 bool ComputeShaderChunk::addProceduralVariable(
676 ProcVarFunctor pFunc
,
679 if(_sfVariables
.getValue() == NULL
)
681 ShaderProgramVariablesUnrecPtr pParam
=
682 ShaderProgramVariables::createDependent(
683 this->getFieldFlags()->_bNamespaceMask
);
685 setVariables(pParam
);
687 if(_mfComputeShader
.size() > 0)
689 _mfComputeShader
[0]->setVariables(this->getVariables());
693 return _sfVariables
.getValue()->addProceduralVariable(
697 editMFProceduralVariableLocations());
700 bool ComputeShaderChunk::updateNodeProceduralVariable(
702 ProcVarNodeFunctor pFunc
,
705 if(_sfVariables
.getValue() == NULL
)
707 ShaderProgramVariablesUnrecPtr pParam
=
708 ShaderProgramVariables::createDependent(
709 this->getFieldFlags()->_bNamespaceMask
);
711 setVariables(pParam
);
713 if(_mfComputeShader
.size() > 0)
715 _mfComputeShader
[0]->setVariables(this->getVariables());
719 return _sfVariables
.getValue()->updateNodeProceduralVariable(name
,
724 bool ComputeShaderChunk::addNodeProceduralVariable(
726 ProcVarNodeFunctor pFunc
,
729 if(_sfVariables
.getValue() == NULL
)
731 ShaderProgramVariablesUnrecPtr pParam
=
732 ShaderProgramVariables::createDependent(
733 this->getFieldFlags()->_bNamespaceMask
);
735 setVariables(pParam
);
737 if(_mfComputeShader
.size() > 0)
739 _mfComputeShader
[0]->setVariables(this->getVariables());
743 return _sfVariables
.getValue()->addNodeProceduralVariable(
747 editMFProceduralVariableLocations());
750 bool ComputeShaderChunk::updateProceduralVariable(
752 ProcVarFunctor pFunc
,
755 if(_sfVariables
.getValue() == NULL
)
757 ShaderProgramVariablesUnrecPtr pParam
=
758 ShaderProgramVariables::createDependent(
759 this->getFieldFlags()->_bNamespaceMask
);
761 setVariables(pParam
);
763 if(_mfComputeShader
.size() > 0)
765 _mfComputeShader
[0]->setVariables(this->getVariables());
769 return _sfVariables
.getValue()->updateProceduralVariable(name
,
775 void ComputeShaderChunk::updateParameters(
777 const UInt32
¶meters
,
780 bool keepProgramActive
)
784 const UInt32
*ComputeShaderChunk::getMFParameters(void) const
792 void ComputeShaderChunk::updateVariableLocations(DrawEnv
*pEnv
,
798 const ShaderProgramVariables::MFVariablesType
*pMFVars
= NULL
;
799 const ShaderProgramVariables::MFProceduralVariablesType
*pMFProcVars
= NULL
;
801 if(_sfVariables
.getValue() != NULL
)
803 pMFVars
= _sfVariables
.getValue()->getMFVariables ();
804 pMFProcVars
= _sfVariables
.getValue()->getMFProceduralVariables();
807 if(pMFVars
!= NULL
&& pMFVars
->size() != 0)
809 MFInt32
&vVarLocations
= *this->editMFVariableLocations();
811 OSG_ASSERT(pMFVars
->size() == vVarLocations
.size());
813 MFInt32::iterator mLocIt
= vVarLocations
.begin();
815 ShaderProgramVariables::MFVariablesType::const_iterator mVarIt
=
817 ShaderProgramVariables::MFVariablesType::const_iterator mVarEnd
=
820 OSGGETGLFUNC_GL3_ES(glGetUniformLocation
,
821 osgGlGetUniformLocation
,
822 ShaderProgram::getFuncIdGetUniformLocation());
824 for(; mVarIt
!= mVarEnd
; ++mVarIt
, ++mLocIt
)
826 *mLocIt
= osgGlGetUniformLocation(uiProgram
,
827 (*mVarIt
)->getName().c_str());
831 if(pMFProcVars
!= NULL
&& pMFProcVars
->size() != 0)
833 MFInt32
&vVarLocations
= *this->editMFProceduralVariableLocations();
835 OSG_ASSERT(pMFProcVars
->size() == vVarLocations
.size());
837 MFInt32::iterator mLocIt
= vVarLocations
.begin();
839 ShaderProgramVariables::MFProceduralVariablesType::const_iterator
840 mVarIt
= pMFProcVars
->begin();
841 ShaderProgramVariables::MFProceduralVariablesType::const_iterator
842 mVarEnd
= pMFProcVars
->end ();
844 OSGGETGLFUNC_GL3_ES(glGetUniformLocation
,
845 osgGlGetUniformLocation
,
846 ShaderProgram::getFuncIdGetUniformLocation());
848 for(; mVarIt
!= mVarEnd
; ++mVarIt
, ++mLocIt
)
850 *mLocIt
= osgGlGetUniformLocation(uiProgram
,
851 (*mVarIt
)->getName().c_str());
856 void ComputeShaderChunk::updateVariables(DrawEnv
*pEnv
,
862 const ShaderProgramVariables::MFVariablesType
*pMFVars
= NULL
;
863 ShaderProgramVariables::MFVariableChangedType
*pMFVarChg
= NULL
;
865 if(_sfVariables
.getValue() != NULL
)
867 pMFVars
= _sfVariables
.getValue()->getMFVariables ();
868 pMFVarChg
= _sfVariables
.getValue()->editMFVariableChanged();
871 if(pMFVars
== NULL
|| pMFVars
->size() == 0 || pMFVarChg
== NULL
)
876 OSG_ASSERT(pMFVars
->size() == pMFVarChg
->size());
878 MFInt32
&vVarLocations
= *this->editMFVariableLocations();
880 OSG_ASSERT(pMFVars
->size() == vVarLocations
.size());
882 MFInt32::iterator mLocIt
= vVarLocations
.begin();
884 ShaderProgramVariables::MFVariablesType::const_iterator mVarIt
=
886 ShaderProgramVariables::MFVariablesType::const_iterator mVarEnd
=
889 ShaderProgramVariables::MFVariableChangedType::iterator mVarChgIt
=
892 bool warnUnknown
= ShaderVariable::WarnUnknown
;
894 for(; mVarIt
!= mVarEnd
; ++mVarIt
, ++mLocIt
, ++mVarChgIt
)
896 ShaderVariable
*pVar
= *mVarIt
;
901 if(*mVarChgIt
== false)
906 osgUniformShaderVariableSwitch(pEnv
, pVar
,
907 *mLocIt
, uiProgram
, warnUnknown
);
911 void ComputeShaderChunk::updateProceduralVariables(
913 UInt32 uiUpdateDependents
)
915 UInt32 uiProgram
= pEnv
->getActiveShader();
920 const ShaderProgramVariables::MFProceduralVariablesType
*pMFVars
= NULL
;
922 if(_sfVariables
.getValue() != NULL
)
924 pMFVars
= _sfVariables
.getValue()->getMFProceduralVariables();
927 if(pMFVars
== NULL
|| pMFVars
->size() == 0)
932 MFInt32
&vVarLocations
= *this->editMFProceduralVariableLocations();
934 OSG_ASSERT(pMFVars
->size() == vVarLocations
.size());
936 MFInt32::iterator mLocIt
= vVarLocations
.begin();
938 ShaderProgramVariables::MFProceduralVariablesType::const_iterator mVarIt
=
940 ShaderProgramVariables::MFProceduralVariablesType::const_iterator mVarEnd
=
943 Window
*pWin
= pEnv
->getWindow();
945 osgSinkUnusedWarning(pWin
);
947 for(; mVarIt
!= mVarEnd
; ++mVarIt
, ++mLocIt
)
949 ShaderVariable
*pVar
= *mVarIt
;
951 switch(pVar
->getTypeId())
953 case ShaderVariable::SHVTypeOSG
:
955 ShaderVariableOSG
*p
=
956 dynamic_cast<ShaderVariableOSG
*>(pVar
);
958 if(0x0000 == (p
->getDependency() & uiUpdateDependents
))
963 OSGGETGLFUNCBYID_GL3_ES(
964 glGetUniformLocation
,
965 osgGlGetUniformLocation
,
966 ShaderProgram::getFuncIdGetUniformLocation(),
969 *mLocIt
= osgGlGetUniformLocation(uiProgram
,
970 p
->getName().c_str());
973 p
->evaluate(pEnv
, *mLocIt
);
977 case ShaderVariable::SHVTypeFunctor
:
979 ShaderVariableFunctor
*p
=
980 dynamic_cast<ShaderVariableFunctor
*>(pVar
);
982 if(0x0000 == (p
->getDependency() & uiUpdateDependents
))
987 OSGGETGLFUNCBYID_GL3_ES(
988 glGetUniformLocation
,
989 osgGlGetUniformLocation
,
990 ShaderProgram::getFuncIdGetUniformLocation(),
993 *mLocIt
= osgGlGetUniformLocation(uiProgram
,
994 p
->getName().c_str());
997 p
->evaluate(pEnv
, *mLocIt
);