// commercial license or contractual agreement.
#include <OSD_File.hxx>
+#include <OSD_Environment.hxx>
#include <OSD_Protection.hxx>
#include <Graphic3d_Buffer.hxx>
#include <OpenGl_GlCore32.hxx>
-IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderProgram,OpenGl_Resource)
+#include "../Shaders/Shaders_DeclarationsImpl_glsl.pxx"
+#include "../Shaders/Shaders_Declarations_glsl.pxx"
+
+#ifdef _WIN32
+ #include <malloc.h> // for alloca()
+#endif
+
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderProgram, OpenGl_NamedResource)
OpenGl_VariableSetterSelector OpenGl_ShaderProgram::mySetterSelector = OpenGl_VariableSetterSelector();
"occProjectionMatrixInverseTranspose", // OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE
"occClipPlaneEquations", // OpenGl_OCC_CLIP_PLANE_EQUATIONS
- "occClipPlaneSpaces", // OpenGl_OCC_CLIP_PLANE_SPACES
+ "occClipPlaneChains", // OpenGl_OCC_CLIP_PLANE_CHAINS
"occClipPlaneCount", // OpenGl_OCC_CLIP_PLANE_COUNT
"occLightSourcesCount", // OpenGl_OCC_LIGHT_SOURCE_COUNT
"occLightSources", // OpenGl_OCC_LIGHT_SOURCE_PARAMS
"occLightAmbient", // OpenGl_OCC_LIGHT_AMBIENT
- "occActiveSampler", // OpenGl_OCCT_ACTIVE_SAMPLER
"occTextureEnable", // OpenGl_OCCT_TEXTURE_ENABLE
"occDistinguishingMode", // OpenGl_OCCT_DISTINGUISH_MODE
"occFrontMaterial", // OpenGl_OCCT_FRONT_MATERIAL
"occBackMaterial", // OpenGl_OCCT_BACK_MATERIAL
+ "occAlphaCutoff", // OpenGl_OCCT_ALPHA_CUTOFF
"occColor", // OpenGl_OCCT_COLOR
+ "occOitOutput", // OpenGl_OCCT_OIT_OUTPUT
+ "occOitDepthFactor", // OpenGl_OCCT_OIT_DEPTH_FACTOR
+
"occTexTrsf2d", // OpenGl_OCCT_TEXTURE_TRSF2D
- "occPointSize" // OpenGl_OCCT_POINT_SIZE
+ "occPointSize", // OpenGl_OCCT_POINT_SIZE
+ "occViewport", // OpenGl_OCCT_VIEWPORT
+ "occLineWidth", // OpenGl_OCCT_LINE_WIDTH
+ "occLineFeather", // OpenGl_OCCT_LINE_FEATHER
+ "occWireframeColor", // OpenGl_OCCT_WIREFRAME_COLOR
+ "occIsQuadMode", // OpenGl_OCCT_QUAD_MODE_STATE
+
+ "occOrthoScale", // OpenGl_OCCT_ORTHO_SCALE
+ "occSilhouetteThickness" // OpenGl_OCCT_SILHOUETTE_THICKNESS
};
+namespace
+{
+ //! Convert Graphic3d_TypeOfShaderObject enumeration into OpenGL enumeration.
+ static GLenum shaderTypeToGl (Graphic3d_TypeOfShaderObject theType)
+ {
+ switch (theType)
+ {
+ case Graphic3d_TOS_VERTEX: return GL_VERTEX_SHADER;
+ case Graphic3d_TOS_FRAGMENT: return GL_FRAGMENT_SHADER;
+ case Graphic3d_TOS_GEOMETRY: return GL_GEOMETRY_SHADER;
+ case Graphic3d_TOS_TESS_CONTROL: return GL_TESS_CONTROL_SHADER;
+ case Graphic3d_TOS_TESS_EVALUATION: return GL_TESS_EVALUATION_SHADER;
+ case Graphic3d_TOS_COMPUTE: return GL_COMPUTE_SHADER;
+ }
+ return 0;
+ }
+}
+
// =======================================================================
// function : OpenGl_VariableSetterSelector
// purpose : Creates new variable setter selector
// function : OpenGl_ShaderProgram
// purpose : Creates uninitialized shader program
// =======================================================================
-OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram)& theProxy)
-: myProgramID (NO_PROGRAM),
+OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram)& theProxy,
+ const TCollection_AsciiString& theId)
+: OpenGl_NamedResource (!theProxy.IsNull() ? theProxy->GetId() : theId),
+ myProgramID (NO_PROGRAM),
myProxy (theProxy),
- myShareCount(1)
+ myShareCount(1),
+ myNbLightsMax (0),
+ myNbClipPlanesMax (0),
+ myNbFragOutputs (1),
+ myHasAlphaTest (false),
+ myHasWeightOitOutput (false),
+ myHasTessShader (false)
{
memset (myCurrentState, 0, sizeof (myCurrentState));
- for (GLint aVar = 0; aVar < OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES; ++aVar)
- {
- myStateLocations[aVar] = INVALID_LOCATION;
- }
}
// =======================================================================
Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)& theCtx,
const Graphic3d_ShaderObjectList& theShaders)
{
+ myHasTessShader = false;
if (theCtx.IsNull() || !Create (theCtx))
{
return Standard_False;
}
- OSD_File aDeclFile (Graphic3d_ShaderProgram::ShadersFolder() + "/Declarations.glsl");
- OSD_File aDeclImplFile (Graphic3d_ShaderProgram::ShadersFolder() + "/DeclarationsImpl.glsl");
- if (!aDeclFile.Exists()
- || !aDeclImplFile.Exists())
+ TCollection_AsciiString aHeaderVer = !myProxy.IsNull() ? myProxy->Header() : TCollection_AsciiString();
+ int aShaderMask = 0;
+ for (Graphic3d_ShaderObjectList::Iterator anIter (theShaders); anIter.More(); anIter.Next())
{
- const TCollection_ExtendedString aMsg = "Error! Failed to load OCCT shader declarations file";
- theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_ERROR,
- 0,
- GL_DEBUG_SEVERITY_HIGH,
- aMsg);
- return Standard_False;
+ aShaderMask |= anIter.Value()->Type();
}
-
- TCollection_AsciiString aHeader = !myProxy.IsNull() && !myProxy->Header().IsEmpty()
- ? (myProxy->Header() + "\n")
- : TCollection_AsciiString();
-
- TCollection_AsciiString aDeclarations;
- aDeclFile.Open (OSD_ReadOnly, OSD_Protection());
- aDeclFile.Read (aDeclarations, (int)aDeclFile.Size());
- aDeclFile.Close();
-
- TCollection_AsciiString aDeclImpl;
- aDeclImplFile.Open (OSD_ReadOnly, OSD_Protection());
- aDeclImplFile.Read (aDeclImpl, (int)aDeclImplFile.Size());
- aDeclImplFile.Close();
- aDeclarations += aDeclImpl;
-
- for (Graphic3d_ShaderObjectList::Iterator anIter (theShaders);
- anIter.More(); anIter.Next())
+ myHasTessShader = (aShaderMask & (Graphic3d_TOS_TESS_CONTROL | Graphic3d_TOS_TESS_EVALUATION)) != 0;
+ myNbFragOutputs = !myProxy.IsNull() ? myProxy->NbFragmentOutputs() : 1;
+ myHasAlphaTest = !myProxy.IsNull() && myProxy->HasAlphaTest();
+ myHasWeightOitOutput = !myProxy.IsNull() ? myProxy->HasWeightOitOutput() && myNbFragOutputs >= 2 : 1;
+
+ // detect the minimum GLSL version required for defined Shader Objects
+#if defined(GL_ES_VERSION_2_0)
+ if (myHasTessShader)
{
- if (!anIter.Value()->IsDone())
+ if (!theCtx->IsGlGreaterEqual (3, 2))
{
- const TCollection_ExtendedString aMsg = "Error! Failed to get shader source";
- theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_ERROR,
- 0,
- GL_DEBUG_SEVERITY_HIGH,
- aMsg);
- return Standard_False;
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error! Tessellation shader requires OpenGL ES 3.2+");
+ return false;
}
-
- Handle(OpenGl_ShaderObject) aShader;
-
- // Note: Add support of other shader types here
- switch (anIter.Value()->Type())
+ else if (aHeaderVer.IsEmpty())
{
- case Graphic3d_TOS_VERTEX:
- aShader = new OpenGl_ShaderObject (GL_VERTEX_SHADER);
+ aHeaderVer = "#version 320 es";
+ }
+ }
+ else if ((aShaderMask & Graphic3d_TOS_GEOMETRY) != 0)
+ {
+ switch (theCtx->hasGeometryStage)
+ {
+ case OpenGl_FeatureNotAvailable:
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error! Geometry shader requires OpenGL ES 3.2+ or GL_EXT_geometry_shader");
+ return false;
+ }
+ case OpenGl_FeatureInExtensions:
+ {
+ if (aHeaderVer.IsEmpty())
+ {
+ aHeaderVer = "#version 310 es";
+ }
break;
- case Graphic3d_TOS_FRAGMENT:
- aShader = new OpenGl_ShaderObject (GL_FRAGMENT_SHADER);
+ }
+ case OpenGl_FeatureInCore:
+ {
+ if (aHeaderVer.IsEmpty())
+ {
+ aHeaderVer = "#version 320 es";
+ }
break;
+ }
}
+ }
+ else if ((aShaderMask & Graphic3d_TOS_COMPUTE) != 0)
+ {
+ if (!theCtx->IsGlGreaterEqual (3, 1))
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error! Compute shaders require OpenGL ES 3.1+");
+ return false;
+ }
+ else if (aHeaderVer.IsEmpty())
+ {
+ aHeaderVer = "#version 310 es";
+ }
+ }
+#else
+ if ((aShaderMask & Graphic3d_TOS_COMPUTE) != 0)
+ {
+ if (!theCtx->IsGlGreaterEqual (4, 3))
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error! Compute shaders require OpenGL 4.3+");
+ return 0;
+ }
+ else if (aHeaderVer.IsEmpty())
+ {
+ aHeaderVer = "#version 430";
+ }
+ }
+ else if (myHasTessShader)
+ {
+ if (!theCtx->IsGlGreaterEqual (4, 0))
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error! Tessellation shaders require OpenGL 4.0+");
+ return 0;
+ }
+ else if (aHeaderVer.IsEmpty())
+ {
+ aHeaderVer = "#version 400";
+ }
+ }
+ else if ((aShaderMask & Graphic3d_TOS_GEOMETRY) != 0)
+ {
+ if (!theCtx->IsGlGreaterEqual (3, 2))
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error! Geometry shaders require OpenGL 3.2+");
+ return 0;
+ }
+ else if (aHeaderVer.IsEmpty())
+ {
+ aHeaderVer = "#version 150";
+ }
+ }
+#endif
- // Is unsupported shader type?
- if (aShader.IsNull())
+ for (Graphic3d_ShaderObjectList::Iterator anIter (theShaders); anIter.More(); anIter.Next())
+ {
+ if (!anIter.Value()->IsDone())
+ {
+ const TCollection_ExtendedString aMsg = "Error! Failed to get shader source";
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
+ return Standard_False;
+ }
+
+ const GLenum aShaderType = shaderTypeToGl (anIter.Value()->Type());
+ if (aShaderType == 0)
{
- TCollection_ExtendedString aMsg = "Error! Unsupported shader type";
- theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_ERROR,
- 0,
- GL_DEBUG_SEVERITY_HIGH,
- aMsg);
return Standard_False;
}
+ Handle(OpenGl_ShaderObject) aShader = new OpenGl_ShaderObject (aShaderType);
if (!aShader->Create (theCtx))
{
aShader->Release (theCtx.operator->());
return Standard_False;
}
- TCollection_AsciiString aSource = aDeclarations + anIter.Value()->Source();
- switch (anIter.Value()->Type())
+ TCollection_AsciiString anExtensions = "// Enable extensions used in OCCT GLSL programs\n";
+ if (myNbFragOutputs > 1)
{
- case Graphic3d_TOS_VERTEX:
+ if (theCtx->hasDrawBuffers)
{
- aSource = aHeader + TCollection_AsciiString ("#define VERTEX_SHADER\n") + aSource;
- break;
+ anExtensions += "#define OCC_ENABLE_draw_buffers\n";
+ if (myHasWeightOitOutput)
+ {
+ anExtensions += "#define OCC_WRITE_WEIGHT_OIT_COVERAGE\n";
+ }
}
- case Graphic3d_TOS_FRAGMENT:
+ else
{
- #if defined(GL_ES_VERSION_2_0)
- TCollection_AsciiString aPrefix (theCtx->hasHighp
- ? "precision highp float;\n"
- "precision highp int;\n"
- : "precision mediump float;\n"
- "precision mediump int;\n");
- aSource = aHeader + aPrefix + aSource;
- #else
- aSource = aHeader + aSource;
- #endif
- break;
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error! Multiple draw buffers required by the program, but aren't supported by OpenGL");
+ return Standard_False;
}
- }
- if (!aShader->LoadSource (theCtx, aSource))
+ if (theCtx->hasDrawBuffers == OpenGl_FeatureInExtensions)
+ {
+ if (theCtx->arbDrawBuffers)
+ {
+ anExtensions += "#extension GL_ARB_draw_buffers : enable\n";
+ }
+ else if (theCtx->extDrawBuffers)
+ {
+ anExtensions += "#extension GL_EXT_draw_buffers : enable\n";
+ }
+ }
+ }
+ if (myHasAlphaTest)
{
- const TCollection_ExtendedString aMsg = "Error! Failed to set shader source";
- theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_ERROR,
- 0,
- GL_DEBUG_SEVERITY_HIGH,
- aMsg);
- aShader->Release (theCtx.operator->());
- return Standard_False;
+ anExtensions += "#define OCC_ALPHA_TEST\n";
}
- if (!aShader->Compile (theCtx))
+ if (theCtx->hasSampleVariables == OpenGl_FeatureInExtensions)
{
- TCollection_AsciiString aLog;
- aShader->FetchInfoLog (theCtx, aLog);
- if (aLog.IsEmpty())
+#if defined(GL_ES_VERSION_2_0)
+ if (theCtx->oesSampleVariables)
+ {
+ anExtensions += "#extension GL_OES_sample_variables : enable\n";
+ }
+#else
+ if (theCtx->arbSampleShading)
{
- aLog = "Compilation log is empty.";
+ anExtensions += "#extension GL_ARB_sample_shading : enable\n";
}
- theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_ERROR,
- 0,
- GL_DEBUG_SEVERITY_HIGH,
- TCollection_ExtendedString ("Failed to compile shader object. Compilation log:\n") + aLog);
+#endif
+ }
+#if defined(GL_ES_VERSION_2_0)
+ if (theCtx->hasGeometryStage == OpenGl_FeatureInExtensions)
+ {
+ anExtensions += "#extension GL_EXT_geometry_shader : enable\n"
+ "#extension GL_EXT_shader_io_blocks : enable\n";
+ }
+#endif
+
+ TCollection_AsciiString aPrecisionHeader;
+ if (anIter.Value()->Type() == Graphic3d_TOS_FRAGMENT)
+ {
+ #if defined(GL_ES_VERSION_2_0)
+ aPrecisionHeader = theCtx->hasHighp
+ ? "precision highp float;\n"
+ "precision highp int;\n"
+ : "precision mediump float;\n"
+ "precision mediump int;\n";
+ #endif
+ }
+
+ TCollection_AsciiString aHeaderType;
+ switch (anIter.Value()->Type())
+ {
+ case Graphic3d_TOS_COMPUTE: { aHeaderType = "#define COMPUTE_SHADER\n"; break; }
+ case Graphic3d_TOS_VERTEX: { aHeaderType = "#define VERTEX_SHADER\n"; break; }
+ case Graphic3d_TOS_TESS_CONTROL: { aHeaderType = "#define TESS_CONTROL_SHADER\n"; break; }
+ case Graphic3d_TOS_TESS_EVALUATION: { aHeaderType = "#define TESS_EVALUATION_SHADER\n"; break; }
+ case Graphic3d_TOS_GEOMETRY: { aHeaderType = "#define GEOMETRY_SHADER\n"; break; }
+ case Graphic3d_TOS_FRAGMENT: { aHeaderType = "#define FRAGMENT_SHADER\n"; break; }
+ }
+
+ TCollection_AsciiString aHeaderConstants;
+ myNbLightsMax = !myProxy.IsNull() ? myProxy->NbLightsMax() : 0;
+ myNbClipPlanesMax = !myProxy.IsNull() ? myProxy->NbClipPlanesMax() : 0;
+ aHeaderConstants += TCollection_AsciiString("#define THE_MAX_LIGHTS ") + myNbLightsMax + "\n";
+ aHeaderConstants += TCollection_AsciiString("#define THE_MAX_CLIP_PLANES ") + myNbClipPlanesMax + "\n";
+ aHeaderConstants += TCollection_AsciiString("#define THE_NB_FRAG_OUTPUTS ") + myNbFragOutputs + "\n";
+ if (!myProxy.IsNull()
+ && myProxy->HasDefaultSampler())
+ {
+ aHeaderConstants += "#define THE_HAS_DEFAULT_SAMPLER\n";
+ }
+
+ const TCollection_AsciiString aSource = aHeaderVer // #version - header defining GLSL version, should be first
+ + (!aHeaderVer.IsEmpty() ? "\n" : "")
+ + anExtensions // #extension - list of enabled extensions, should be second
+ + aPrecisionHeader // precision - default precision qualifiers, should be before any code
+ + aHeaderType // auxiliary macros defining a shader stage (type)
+ + aHeaderConstants
+ + Shaders_Declarations_glsl // common declarations (global constants and Vertex Shader inputs)
+ + Shaders_DeclarationsImpl_glsl
+ + anIter.Value()->Source(); // the source code itself (defining main() function)
+ if (!aShader->LoadAndCompile (theCtx, myResourceId, aSource))
+ {
aShader->Release (theCtx.operator->());
return Standard_False;
}
- else if (theCtx->caps->glslWarnings)
+
+ if (theCtx->caps->glslDumpLevel)
{
- TCollection_AsciiString aLog;
- aShader->FetchInfoLog (theCtx, aLog);
- if (!aLog.IsEmpty()
- && !aLog.IsEqual ("No errors.\n"))
+ TCollection_AsciiString anOutputSource = aSource;
+ if (theCtx->caps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Short)
{
- theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_PORTABILITY,
- 0,
- GL_DEBUG_SEVERITY_LOW,
- TCollection_ExtendedString ("Shader compilation log:\n") + aLog);
+ anOutputSource = aHeaderVer
+ + (!aHeaderVer.IsEmpty() ? "\n" : "")
+ + anExtensions
+ + aPrecisionHeader
+ + aHeaderType
+ + aHeaderConstants
+ + anIter.Value()->Source();
}
+ aShader->DumpSourceCode (theCtx, myResourceId, anOutputSource);
}
if (!AttachShader (theCtx, aShader))
if (!Link (theCtx))
{
- TCollection_AsciiString aLog;
- FetchInfoLog (theCtx, aLog);
- if (aLog.IsEmpty())
- {
- aLog = "Linker log is empty.";
- }
- theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_ERROR,
- 0,
- GL_DEBUG_SEVERITY_HIGH,
- TCollection_ExtendedString ("Failed to link program object! Linker log:\n") + aLog);
return Standard_False;
}
- else if (theCtx->caps->glslWarnings)
+
+ // set uniform defaults
+ const Handle(OpenGl_ShaderProgram)& anOldProgram = theCtx->ActiveProgram();
+ theCtx->core20fwd->glUseProgram (myProgramID);
+ if (const OpenGl_ShaderUniformLocation aLocTexEnable = GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE))
{
- TCollection_AsciiString aLog;
- FetchInfoLog (theCtx, aLog);
- if (!aLog.IsEmpty()
- && !aLog.IsEqual ("No errors.\n"))
+ SetUniform (theCtx, aLocTexEnable, 0); // Off
+ }
+ if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occActiveSampler"))
+ {
+ SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_0));
+ }
+ if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerBaseColor"))
+ {
+ SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_BaseColor));
+ }
+ if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerPointSprite"))
+ {
+ SetUniform (theCtx, aLocSampler, GLint(theCtx->SpriteTextureUnit()));
+ }
+
+ const TCollection_AsciiString aSamplerNamePrefix ("occSampler");
+ const Standard_Integer aNbUnitsMax = Max (theCtx->MaxCombinedTextureUnits(), Graphic3d_TextureUnit_NB);
+ for (GLint aUnitIter = 0; aUnitIter < aNbUnitsMax; ++aUnitIter)
+ {
+ const TCollection_AsciiString aName = aSamplerNamePrefix + aUnitIter;
+ if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, aName.ToCString()))
{
- theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_PORTABILITY,
- 0,
- GL_DEBUG_SEVERITY_LOW,
- TCollection_ExtendedString ("GLSL linker log:\n") + aLog);
+ SetUniform (theCtx, aLocSampler, aUnitIter);
}
}
+ theCtx->core20fwd->glUseProgram (!anOldProgram.IsNull() ? anOldProgram->ProgramId() : OpenGl_ShaderProgram::NO_PROGRAM);
return Standard_True;
}
// function : Link
// purpose : Links the program object
// =======================================================================
-Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCtx)
+Standard_Boolean OpenGl_ShaderProgram::link (const Handle(OpenGl_Context)& theCtx)
{
if (myProgramID == NO_PROGRAM)
{
return Standard_False;
}
+ memset (myCurrentState, 0, sizeof (myCurrentState));
for (GLint aVar = 0; aVar < OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES; ++aVar)
{
myStateLocations[aVar] = GetUniformLocation (theCtx, PredefinedKeywords[aVar]);
return Standard_True;
}
+// =======================================================================
+// function : Link
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCtx,
+ bool theIsVerbose)
+{
+ if (!theIsVerbose)
+ {
+ return link (theCtx);
+ }
+
+ if (!link (theCtx))
+ {
+ TCollection_AsciiString aLog;
+ FetchInfoLog (theCtx, aLog);
+ if (aLog.IsEmpty())
+ {
+ aLog = "Linker log is empty.";
+ }
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Failed to link program object [") + myResourceId + "]! Linker log:\n" + aLog);
+ return false;
+ }
+ else if (theCtx->caps->glslWarnings)
+ {
+ TCollection_AsciiString aLog;
+ FetchInfoLog (theCtx, aLog);
+ if (!aLog.IsEmpty()
+ && !aLog.IsEqual ("No errors.\n"))
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
+ TCollection_AsciiString ("GLSL linker log [") + myResourceId +"]:\n" + aLog);
+ }
+ }
+ return true;
+}
+
// =======================================================================
// function : FetchInfoLog
// purpose : Fetches information log of the last link operation
return Standard_True;
}
-// =======================================================================
-// function : ActiveState
-// purpose : Returns index of last modification for specified state type
-// =======================================================================
-Standard_Size OpenGl_ShaderProgram::ActiveState (const OpenGl_UniformStateType theType) const
-{
- if (theType < MaxStateTypes)
- {
- return myCurrentState[theType];
- }
- return 0;
-}
-
-// =======================================================================
-// function : UpdateState
-// purpose : Updates index of last modification for specified state type
-// =======================================================================
-void OpenGl_ShaderProgram::UpdateState (const OpenGl_UniformStateType theType,
- const Standard_Size theIndex)
-{
- if (theType < MaxStateTypes)
- {
- myCurrentState[theType] = theIndex;
- }
-}
-
// =======================================================================
// function : GetUniformLocation
// purpose : Returns location (index) of the specific uniform variable
// =======================================================================
-GLint OpenGl_ShaderProgram::GetUniformLocation (const Handle(OpenGl_Context)& theCtx,
- const GLchar* theName) const
+OpenGl_ShaderUniformLocation OpenGl_ShaderProgram::GetUniformLocation (const Handle(OpenGl_Context)& theCtx,
+ const GLchar* theName) const
{
- return myProgramID != NO_PROGRAM
- ? theCtx->core20fwd->glGetUniformLocation (myProgramID, theName)
- : INVALID_LOCATION;
+ return OpenGl_ShaderUniformLocation (myProgramID != NO_PROGRAM
+ ? theCtx->core20fwd->glGetUniformLocation (myProgramID, theName)
+ : INVALID_LOCATION);
}
// =======================================================================
: INVALID_LOCATION;
}
-// =======================================================================
-// function : GetStateLocation
-// purpose : Returns location of the OCCT state uniform variable
-// =======================================================================
-GLint OpenGl_ShaderProgram::GetStateLocation (const GLuint theVariable) const
-{
- if (theVariable < OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES)
- {
- return myStateLocations[theVariable];
- }
- return INVALID_LOCATION;
-}
-
// =======================================================================
// function : GetUniform
// purpose : Returns the value of the integer uniform variable
// =======================================================================
Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)& theCtx,
const GLchar* theName,
- const GLenum theTextureUnit)
+ const Graphic3d_TextureUnit theTextureUnit)
{
return SetSampler (theCtx, GetUniformLocation (theCtx, theName), theTextureUnit);
}
// =======================================================================
Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)& theCtx,
GLint theLocation,
- const GLenum theTextureUnit)
+ const Graphic3d_TextureUnit theTextureUnit)
{
if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
{
myProgramID = NO_PROGRAM;
}
+
+// =======================================================================
+// function : UpdateDebugDump
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::UpdateDebugDump (const Handle(OpenGl_Context)& theCtx,
+ const TCollection_AsciiString& theFolder,
+ Standard_Boolean theToBeautify,
+ Standard_Boolean theToReset)
+{
+ if (myProgramID == NO_PROGRAM)
+ {
+ return Standard_False;
+ }
+
+ TCollection_AsciiString aFolder = theFolder;
+ if (aFolder.IsEmpty())
+ {
+ OSD_Environment aShaderVar ("CSF_ShadersDirectoryDump");
+ aFolder = aShaderVar.Value();
+ if (aFolder.IsEmpty())
+ {
+ aFolder = ".";
+ }
+ }
+
+ bool hasUpdates = false;
+ for (OpenGl_ShaderList::Iterator anIter (myShaderObjects); anIter.More(); anIter.Next())
+ {
+ if (!anIter.Value().IsNull())
+ {
+ // desktop OpenGL (but not OpenGL ES) allows multiple shaders of the same stage to be attached,
+ // but here we expect only single source per stage
+ hasUpdates = anIter.ChangeValue()->updateDebugDump (theCtx, myResourceId, aFolder, theToBeautify, theToReset) || hasUpdates;
+ }
+ }
+ if (hasUpdates)
+ {
+ return Link (theCtx);
+ }
+ return Standard_False;
+}