1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/OpenGl/OpenGl_ShaderObject.cxx
mnv 2a33274558 0029076: Visualization - implement element shrinking Shader
Aspect_IS_HOLLOW now an alias to Aspect_IS_EMPTY and Aspect_IS_HIDDENLINE does not implicitly enables mesh edges,
so that Graphic3d_AspectFillArea3d::SetDrawEdges() should be set independently.

OpenGl_ShaderManager now provides built-in GLSL programs for drawing mesh edges
in single pass (and on OpenGL ES which does not provide glPolygonMode()).

Graphic3d_RenderingParams::ToEnableAlphaToCoverage is now enabled by default
and properly handled at TKOpenGl level - enables coverage for Graphic3d_AlphaMode_Mask primitives.

OpenGl_PrimitiveArray now uses GLSL programs instead of glPolygonMode() by default,
which can be managed by OpenGl_Caps::usePolygonMode flag (desktop OpenGL only).
glPolygonMode() is also used as fallback regardless OpenGl_Caps::usePolygonMode flag
when GLSL programs are not supported (Geometry Shaders are required)
or stipple line style is required (not implemented within Face GLSL).

vaspects command has been extended by -setInterior -setDrawEdges -setEdgeColor -setEdgeType -setEdgeWidth
arguments replacing vsetinteriorstyle/vsetedgetype/vunsetedgetype commands.
vaspects now accepts arguments without "set" prefix.
ViewerTest::ParseColor() now parses RGBA color.

Redundant command BUC60738 has been removed.
AIS_ColorScale - fixed usage of uninitialized FillArea aspects.
2019-02-22 16:23:35 +03:00

362 lines
12 KiB
C++
Executable File

// Created on: 2013-09-19
// Created by: Denis BOGOLEPOV
// Copyright (c) 2013-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Graphic3d_ShaderObject.hxx>
#include <OpenGl_Context.hxx>
#include <OpenGl_ShaderObject.hxx>
#include <OSD_Path.hxx>
#include <Standard_Assert.hxx>
#include <TCollection_AsciiString.hxx>
#include <TCollection_ExtendedString.hxx>
#ifdef _WIN32
#include <malloc.h> // for alloca()
#endif
IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderObject,OpenGl_Resource)
//! Puts line numbers to the output of GLSL program source code.
static TCollection_AsciiString putLineNumbers (const TCollection_AsciiString& theSource)
{
std::stringstream aStream;
theSource.Print (aStream);
std::string aLine;
Standard_Integer aLineNumber = 1;
TCollection_AsciiString aResultSource;
while (std::getline (aStream, aLine))
{
TCollection_AsciiString anAsciiString = TCollection_AsciiString (aLine.c_str());
anAsciiString.Prepend (TCollection_AsciiString ("\n") + TCollection_AsciiString (aLineNumber) + ": ");
aResultSource += anAsciiString;
aLineNumber++;
}
return aResultSource;
}
// =======================================================================
// function : CreateFromSource
// purpose :
// =======================================================================
Handle(Graphic3d_ShaderObject) OpenGl_ShaderObject::CreateFromSource (TCollection_AsciiString& theSource,
Graphic3d_TypeOfShaderObject theType,
const ShaderVariableList& theUniforms,
const ShaderVariableList& theStageInOuts,
const TCollection_AsciiString& theInName,
const TCollection_AsciiString& theOutName,
Standard_Integer theNbGeomInputVerts)
{
if (theSource.IsEmpty())
{
return Handle(Graphic3d_ShaderObject)();
}
TCollection_AsciiString aSrcUniforms, aSrcInOuts, aSrcInStructs, aSrcOutStructs;
for (ShaderVariableList::Iterator anUniformIter (theUniforms); anUniformIter.More(); anUniformIter.Next())
{
const ShaderVariable& aVar = anUniformIter.Value();
if ((aVar.Stages & theType) != 0)
{
aSrcUniforms += TCollection_AsciiString("\nuniform ") + aVar.Name + ";";
}
}
for (ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next())
{
const ShaderVariable& aVar = aVarListIter.Value();
Standard_Integer aStageLower = IntegerLast(), aStageUpper = IntegerFirst();
Standard_Integer aNbStages = 0;
for (Standard_Integer aStageIter = Graphic3d_TOS_VERTEX; aStageIter <= (Standard_Integer )Graphic3d_TOS_COMPUTE; aStageIter = aStageIter << 1)
{
if ((aVar.Stages & aStageIter) != 0)
{
++aNbStages;
aStageLower = Min (aStageLower, aStageIter);
aStageUpper = Max (aStageUpper, aStageIter);
}
}
if ((Standard_Integer )theType < aStageLower
|| (Standard_Integer )theType > aStageUpper)
{
continue;
}
const Standard_Boolean hasGeomStage = theNbGeomInputVerts > 0
&& aStageLower < Graphic3d_TOS_GEOMETRY
&& aStageUpper >= Graphic3d_TOS_GEOMETRY;
const Standard_Boolean isAllStagesVar = aStageLower == Graphic3d_TOS_VERTEX
&& aStageUpper == Graphic3d_TOS_FRAGMENT;
if (hasGeomStage
|| !theInName.IsEmpty()
|| !theOutName.IsEmpty())
{
if (aSrcInStructs.IsEmpty()
&& aSrcOutStructs.IsEmpty()
&& isAllStagesVar)
{
if (theType == aStageLower)
{
aSrcOutStructs = "\nout VertexData\n{";
}
else if (theType == aStageUpper)
{
aSrcInStructs = "\nin VertexData\n{";
}
else // requires theInName/theOutName
{
aSrcInStructs = "\nin VertexData\n{";
aSrcOutStructs = "\nout VertexData\n{";
}
}
}
if (isAllStagesVar
&& (!aSrcInStructs.IsEmpty()
|| !aSrcOutStructs.IsEmpty()))
{
if (!aSrcInStructs.IsEmpty())
{
aSrcInStructs += TCollection_AsciiString("\n ") + aVar.Name + ";";
}
if (!aSrcOutStructs.IsEmpty())
{
aSrcOutStructs += TCollection_AsciiString("\n ") + aVar.Name + ";";
}
}
else
{
if (theType == aStageLower)
{
aSrcInOuts += TCollection_AsciiString("\nTHE_SHADER_OUT ") + aVar.Name + ";";
}
else if (theType == aStageUpper)
{
aSrcInOuts += TCollection_AsciiString("\nTHE_SHADER_IN ") + aVar.Name + ";";
}
}
}
if (theType == Graphic3d_TOS_GEOMETRY)
{
aSrcUniforms.Prepend (TCollection_AsciiString()
+ "\nlayout (triangles) in;"
"\nlayout (triangle_strip, max_vertices = " + theNbGeomInputVerts + ") out;");
}
if (!aSrcInStructs.IsEmpty()
&& theType == Graphic3d_TOS_GEOMETRY)
{
aSrcInStructs += TCollection_AsciiString ("\n} ") + theInName + "[" + theNbGeomInputVerts + "];";
}
else if (!aSrcInStructs.IsEmpty())
{
aSrcInStructs += "\n}";
if (!theInName.IsEmpty())
{
aSrcInStructs += " ";
aSrcInStructs += theInName;
}
aSrcInStructs += ";";
}
if (!aSrcOutStructs.IsEmpty())
{
aSrcOutStructs += "\n}";
if (!theOutName.IsEmpty())
{
aSrcOutStructs += " ";
aSrcOutStructs += theOutName;
}
aSrcOutStructs += ";";
}
theSource.Prepend (aSrcUniforms + aSrcInStructs + aSrcOutStructs + aSrcInOuts);
return Graphic3d_ShaderObject::CreateFromSource (theType, theSource);
}
// =======================================================================
// function : OpenGl_ShaderObject
// purpose : Creates uninitialized shader object
// =======================================================================
OpenGl_ShaderObject::OpenGl_ShaderObject (GLenum theType)
: myType (theType),
myShaderID (NO_SHADER)
{
//
}
// =======================================================================
// function : ~OpenGl_ShaderObject
// purpose : Releases resources of shader object
// =======================================================================
OpenGl_ShaderObject::~OpenGl_ShaderObject()
{
Release (NULL);
}
// =======================================================================
// function : LoadAndCompile
// purpose :
// =======================================================================
Standard_Boolean OpenGl_ShaderObject::LoadAndCompile (const Handle(OpenGl_Context)& theCtx,
const TCollection_AsciiString& theSource,
bool theIsVerbose,
bool theToPrintSource)
{
if (!theIsVerbose)
{
return LoadSource (theCtx, theSource)
&& Compile (theCtx);
}
if (!LoadSource (theCtx, theSource))
{
if (theToPrintSource)
{
theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, theSource);
}
theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Error! Failed to set shader source");
Release (theCtx.operator->());
return false;
}
if (!Compile (theCtx))
{
if (theToPrintSource)
{
theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, putLineNumbers (theSource));
}
TCollection_AsciiString aLog;
FetchInfoLog (theCtx, aLog);
if (aLog.IsEmpty())
{
aLog = "Compilation log is empty.";
}
theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
TCollection_AsciiString ("Failed to compile shader object. Compilation log:\n") + aLog);
Release (theCtx.operator->());
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 ("Shader compilation log:\n") + aLog);
}
}
return true;
}
// =======================================================================
// function : LoadSource
// purpose : Loads shader source code
// =======================================================================
Standard_Boolean OpenGl_ShaderObject::LoadSource (const Handle(OpenGl_Context)& theCtx,
const TCollection_AsciiString& theSource)
{
if (myShaderID == NO_SHADER)
{
return Standard_False;
}
const GLchar* aLines = theSource.ToCString();
theCtx->core20fwd->glShaderSource (myShaderID, 1, &aLines, NULL);
return Standard_True;
}
// =======================================================================
// function : Compile
// purpose : Compiles the shader object
// =======================================================================
Standard_Boolean OpenGl_ShaderObject::Compile (const Handle(OpenGl_Context)& theCtx)
{
if (myShaderID == NO_SHADER)
{
return Standard_False;
}
// Try to compile shader
theCtx->core20fwd->glCompileShader (myShaderID);
// Check compile status
GLint aStatus = GL_FALSE;
theCtx->core20fwd->glGetShaderiv (myShaderID, GL_COMPILE_STATUS, &aStatus);
return aStatus != GL_FALSE;
}
// =======================================================================
// function : FetchInfoLog
// purpose : Fetches information log of the last compile operation
// =======================================================================
Standard_Boolean OpenGl_ShaderObject::FetchInfoLog (const Handle(OpenGl_Context)& theCtx,
TCollection_AsciiString& theLog)
{
if (myShaderID == NO_SHADER)
{
return Standard_False;
}
// Load information log of the compiler
GLint aLength = 0;
theCtx->core20fwd->glGetShaderiv (myShaderID, GL_INFO_LOG_LENGTH, &aLength);
if (aLength > 0)
{
GLchar* aLog = (GLchar*) alloca (aLength);
memset (aLog, 0, aLength);
theCtx->core20fwd->glGetShaderInfoLog (myShaderID, aLength, NULL, aLog);
theLog = aLog;
}
return Standard_True;
}
// =======================================================================
// function : Create
// purpose : Creates new empty shader object of specified type
// =======================================================================
Standard_Boolean OpenGl_ShaderObject::Create (const Handle(OpenGl_Context)& theCtx)
{
if (myShaderID == NO_SHADER
&& theCtx->core20fwd != NULL)
{
myShaderID = theCtx->core20fwd->glCreateShader (myType);
}
return myShaderID != NO_SHADER;
}
// =======================================================================
// function : Release
// purpose : Destroys shader object
// =======================================================================
void OpenGl_ShaderObject::Release (OpenGl_Context* theCtx)
{
if (myShaderID == NO_SHADER)
{
return;
}
Standard_ASSERT_RETURN (theCtx != NULL,
"OpenGl_ShaderObject destroyed without GL context! Possible GPU memory leakage...",);
if (theCtx->core20fwd != NULL
&& theCtx->IsValid())
{
theCtx->core20fwd->glDeleteShader (myShaderID);
}
myShaderID = NO_SHADER;
}