1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-24 13:50:49 +03:00

0028180: Visualization, TKOpenGl - Performance of Shaded presentation dropped due to FFP disabled by default

FFP state management (light sources, matrices, clipping planes) has been
moved to OpenGl_ShaderManager for consistency with Programmable Pipeline.

OpenGl_Context::BindProgram() does not re-bind already active Program.
OpenGl_PrimitiveArray::Render() does not reset active Program at the end.

OpenGl_Context::ApplyModelViewMatrix() now checks if matrix differs
from already set one before modifying state in Shader Manager.
This allows avoing redundant state changes, matrix uploads onto GPU
and re-computation of inversed matrices.

NCollection_Mat4 has been extended with equality check operators for proper comparison.

OpenGl_ShaderManager - the tracking Material state has been added.
Removed unreachable states OPENGL_NS_RESMAT, OPENGL_NS_TEXTURE and OPENGL_NS_WHITEBACK.

Fixed resetting FFP material state after displaying GL_COLOR_ARRAY vertices;
the Material state within Shader Manager is now
invalidated within OpenGl_VertexBuffer::unbindFixedColor().

OpenGl_Workspace::ApplyAspectFace() - fixed invalidating Material State
when only Highlighting style is changing.
This commit is contained in:
kgv
2016-12-22 12:48:16 +03:00
parent decdee7d3f
commit 8613985b2a
28 changed files with 861 additions and 816 deletions

View File

@@ -249,6 +249,88 @@ const char THE_FRAG_CLIP_PLANES_2[] =
EOL" discard;"
EOL" }";
#if !defined(GL_ES_VERSION_2_0)
static const GLfloat THE_DEFAULT_AMBIENT[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
static const GLfloat THE_DEFAULT_SPOT_DIR[3] = { 0.0f, 0.0f, -1.0f };
static const GLfloat THE_DEFAULT_SPOT_EXPONENT = 0.0f;
static const GLfloat THE_DEFAULT_SPOT_CUTOFF = 180.0f;
//! Bind FFP light source.
static void bindLight (const OpenGl_Light& theLight,
const GLenum theLightGlId,
const OpenGl_Mat4& theModelView,
OpenGl_Context* theCtx)
{
// the light is a headlight?
if (theLight.IsHeadlight)
{
theCtx->core11->glMatrixMode (GL_MODELVIEW);
theCtx->core11->glLoadIdentity();
}
// setup light type
switch (theLight.Type)
{
case Graphic3d_TOLS_AMBIENT : break; // handled by separate if-clause at beginning of method
case Graphic3d_TOLS_DIRECTIONAL:
{
// if the last parameter of GL_POSITION, is zero, the corresponding light source is a Directional one
const OpenGl_Vec4 anInfDir = -theLight.Direction;
// to create a realistic effect, set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE.
theCtx->core11->glLightfv (theLightGlId, GL_AMBIENT, THE_DEFAULT_AMBIENT);
theCtx->core11->glLightfv (theLightGlId, GL_DIFFUSE, theLight.Color.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_SPECULAR, theLight.Color.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_POSITION, anInfDir.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_SPOT_DIRECTION, THE_DEFAULT_SPOT_DIR);
theCtx->core11->glLightf (theLightGlId, GL_SPOT_EXPONENT, THE_DEFAULT_SPOT_EXPONENT);
theCtx->core11->glLightf (theLightGlId, GL_SPOT_CUTOFF, THE_DEFAULT_SPOT_CUTOFF);
break;
}
case Graphic3d_TOLS_POSITIONAL:
{
// to create a realistic effect, set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE
const OpenGl_Vec4 aPosition (static_cast<float>(theLight.Position.x()), static_cast<float>(theLight.Position.y()), static_cast<float>(theLight.Position.z()), 1.0f);
theCtx->core11->glLightfv (theLightGlId, GL_AMBIENT, THE_DEFAULT_AMBIENT);
theCtx->core11->glLightfv (theLightGlId, GL_DIFFUSE, theLight.Color.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_SPECULAR, theLight.Color.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_POSITION, aPosition.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_SPOT_DIRECTION, THE_DEFAULT_SPOT_DIR);
theCtx->core11->glLightf (theLightGlId, GL_SPOT_EXPONENT, THE_DEFAULT_SPOT_EXPONENT);
theCtx->core11->glLightf (theLightGlId, GL_SPOT_CUTOFF, THE_DEFAULT_SPOT_CUTOFF);
theCtx->core11->glLightf (theLightGlId, GL_CONSTANT_ATTENUATION, theLight.ConstAttenuation());
theCtx->core11->glLightf (theLightGlId, GL_LINEAR_ATTENUATION, theLight.LinearAttenuation());
theCtx->core11->glLightf (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0);
break;
}
case Graphic3d_TOLS_SPOT:
{
const OpenGl_Vec4 aPosition (static_cast<float>(theLight.Position.x()), static_cast<float>(theLight.Position.y()), static_cast<float>(theLight.Position.z()), 1.0f);
theCtx->core11->glLightfv (theLightGlId, GL_AMBIENT, THE_DEFAULT_AMBIENT);
theCtx->core11->glLightfv (theLightGlId, GL_DIFFUSE, theLight.Color.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_SPECULAR, theLight.Color.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_POSITION, aPosition.GetData());
theCtx->core11->glLightfv (theLightGlId, GL_SPOT_DIRECTION, theLight.Direction.GetData());
theCtx->core11->glLightf (theLightGlId, GL_SPOT_EXPONENT, theLight.Concentration() * 128.0f);
theCtx->core11->glLightf (theLightGlId, GL_SPOT_CUTOFF, (theLight.Angle() * 180.0f) / GLfloat(M_PI));
theCtx->core11->glLightf (theLightGlId, GL_CONSTANT_ATTENUATION, theLight.ConstAttenuation());
theCtx->core11->glLightf (theLightGlId, GL_LINEAR_ATTENUATION, theLight.LinearAttenuation());
theCtx->core11->glLightf (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0f);
break;
}
}
// restore matrix in case of headlight
if (theLight.IsHeadlight)
{
theCtx->core11->glLoadMatrixf (theModelView.GetData());
}
glEnable (theLightGlId);
}
#endif
}
// =======================================================================
@@ -256,7 +338,8 @@ const char THE_FRAG_CLIP_PLANES_2[] =
// purpose : Creates new empty shader manager
// =======================================================================
OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
: myShadingModel (Graphic3d_TOSM_VERTEX),
: myFfpProgram (new OpenGl_ShaderProgramFFP()),
myShadingModel (Graphic3d_TOSM_VERTEX),
myContext (theContext),
myHasLocalOrigin (Standard_False),
myLastView (NULL)
@@ -480,54 +563,72 @@ void OpenGl_ShaderManager::UpdateWorldViewStateTo (const OpenGl_Mat4& theWorldVi
myWorldViewState.Update();
}
// =======================================================================
// function : LightSourceState
// purpose : Returns current state of OCCT light sources
// =======================================================================
const OpenGl_LightSourceState& OpenGl_ShaderManager::LightSourceState() const
{
return myLightSourceState;
}
// =======================================================================
// function : ProjectionState
// purpose : Returns current state of OCCT projection transform
// =======================================================================
const OpenGl_ProjectionState& OpenGl_ShaderManager::ProjectionState() const
{
return myProjectionState;
}
// =======================================================================
// function : ModelWorldState
// purpose : Returns current state of OCCT model-world transform
// =======================================================================
const OpenGl_ModelWorldState& OpenGl_ShaderManager::ModelWorldState() const
{
return myModelWorldState;
}
// =======================================================================
// function : WorldViewState
// purpose : Returns current state of OCCT world-view transform
// =======================================================================
const OpenGl_WorldViewState& OpenGl_ShaderManager::WorldViewState() const
{
return myWorldViewState;
}
// =======================================================================
// function : PushLightSourceState
// purpose : Pushes state of OCCT light sources to the program
// =======================================================================
void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgram)& theProgram) const
{
if (myLightSourceState.Index() == theProgram->ActiveState (OpenGl_LIGHT_SOURCES_STATE)
|| !theProgram->IsValid())
if (myLightSourceState.Index() == theProgram->ActiveState (OpenGl_LIGHT_SOURCES_STATE))
{
return;
}
theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
if (theProgram == myFfpProgram)
{
#if !defined(GL_ES_VERSION_2_0)
if (myContext->core11 == NULL)
{
return;
}
if (myContext->core11 != NULL)
{
GLenum aLightGlId = GL_LIGHT0;
OpenGl_Vec4 anAmbient (0.0f, 0.0f, 0.0f, 0.0f);
const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
for (OpenGl_ListOfLight::Iterator aLightIt (*myLightSourceState.LightSources()); aLightIt.More(); aLightIt.Next())
{
const OpenGl_Light& aLight = aLightIt.Value();
if (aLight.Type == Graphic3d_TOLS_AMBIENT)
{
anAmbient += aLight.Color;
continue;
}
else if (aLightGlId > GL_LIGHT7) // OpenGLMaxLights - only 8 lights in OpenGL...
{
continue;
}
bindLight (aLightIt.Value(), aLightGlId, aModelView, myContext);
++aLightGlId;
}
// apply accumulated ambient color
anAmbient.a() = 1.0f;
myContext->core11->glLightModelfv (GL_LIGHT_MODEL_AMBIENT, anAmbient.GetData());
// GL_LIGHTING is managed by drawers to switch between shaded / no lighting output,
// therefore managing the state here does not have any effect - do it just for consistency.
if (aLightGlId != GL_LIGHT0)
{
::glEnable (GL_LIGHTING);
}
else
{
::glDisable (GL_LIGHTING);
}
// switch off unused lights
for (; aLightGlId <= GL_LIGHT7; ++aLightGlId)
{
::glDisable (aLightGlId);
}
}
#endif
return;
}
for (Standard_Integer aLightIt = 0; aLightIt < OpenGLMaxLights; ++aLightIt)
{
myLightTypeArray[aLightIt].Type = -1;
@@ -546,7 +647,6 @@ void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgr
theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
myLightTypeArray[0].Packed());
theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
return;
}
@@ -615,8 +715,6 @@ void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgr
aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
myLightParamsArray[0].Packed());
}
theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
}
// =======================================================================
@@ -630,6 +728,19 @@ void OpenGl_ShaderManager::PushProjectionState (const Handle(OpenGl_ShaderProgra
return;
}
theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
if (theProgram == myFfpProgram)
{
#if !defined(GL_ES_VERSION_2_0)
if (myContext->core11 != NULL)
{
myContext->core11->glMatrixMode (GL_PROJECTION);
myContext->core11->glLoadMatrixf (myProjectionState.ProjectionMatrix());
}
#endif
return;
}
theProgram->SetUniform (myContext,
theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX),
myProjectionState.ProjectionMatrix());
@@ -649,8 +760,6 @@ void OpenGl_ShaderManager::PushProjectionState (const Handle(OpenGl_ShaderProgra
{
theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse(), true);
}
theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
}
// =======================================================================
@@ -664,6 +773,21 @@ void OpenGl_ShaderManager::PushModelWorldState (const Handle(OpenGl_ShaderProgra
return;
}
theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
if (theProgram == myFfpProgram)
{
#if !defined(GL_ES_VERSION_2_0)
if (myContext->core11 != NULL)
{
const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
myContext->core11->glMatrixMode (GL_MODELVIEW);
myContext->core11->glLoadMatrixf (aModelView.GetData());
theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
}
#endif
return;
}
theProgram->SetUniform (myContext,
theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX),
myModelWorldState.ModelWorldMatrix());
@@ -683,8 +807,6 @@ void OpenGl_ShaderManager::PushModelWorldState (const Handle(OpenGl_ShaderProgra
{
theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse(), true);
}
theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
}
// =======================================================================
@@ -698,6 +820,21 @@ void OpenGl_ShaderManager::PushWorldViewState (const Handle(OpenGl_ShaderProgram
return;
}
theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
if (theProgram == myFfpProgram)
{
#if !defined(GL_ES_VERSION_2_0)
if (myContext->core11 != NULL)
{
const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
myContext->core11->glMatrixMode (GL_MODELVIEW);
myContext->core11->glLoadMatrixf (aModelView.GetData());
theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
}
#endif
return;
}
theProgram->SetUniform (myContext,
theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX),
myWorldViewState.WorldViewMatrix());
@@ -717,8 +854,6 @@ void OpenGl_ShaderManager::PushWorldViewState (const Handle(OpenGl_ShaderProgram
{
theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse(), true);
}
theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
}
// =======================================================================
@@ -751,6 +886,77 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)
}
theProgram->UpdateState (OpenGl_CLIP_PLANES_STATE, myClippingState.Index());
if (theProgram == myFfpProgram)
{
#if !defined(GL_ES_VERSION_2_0)
if (myContext->core11 == NULL)
{
return;
}
const Standard_Integer aNbMaxPlanes = Min (myContext->MaxClipPlanes(), THE_MAX_CLIP_PLANES);
OpenGl_Vec4d anEquations[THE_MAX_CLIP_PLANES];
Standard_Integer aPlaneId = 0;
Standard_Boolean toRestoreModelView = Standard_False;
for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
{
const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
if (aPlaneIter.IsDisabled())
{
continue;
}
else if (aPlaneId >= aNbMaxPlanes)
{
myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
TCollection_ExtendedString("Warning: clipping planes limit (") + aNbMaxPlanes + ") has been exceeded.");
break;
}
const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
OpenGl_Vec4d& aPlaneEq = anEquations[aPlaneId];
aPlaneEq.x() = anEquation.x();
aPlaneEq.y() = anEquation.y();
aPlaneEq.z() = anEquation.z();
aPlaneEq.w() = anEquation.w();
if (myHasLocalOrigin)
{
const gp_XYZ aPos = aPlane->ToPlane().Position().Location().XYZ() - myLocalOrigin;
const Standard_Real aD = -(anEquation.x() * aPos.X() + anEquation.y() * aPos.Y() + anEquation.z() * aPos.Z());
aPlaneEq.w() = aD;
}
const GLenum anFfpPlaneID = GL_CLIP_PLANE0 + aPlaneId;
if (anFfpPlaneID == GL_CLIP_PLANE0)
{
// set either identity or pure view matrix
toRestoreModelView = Standard_True;
myContext->core11->glMatrixMode (GL_MODELVIEW);
myContext->core11->glLoadMatrixf (myWorldViewState.WorldViewMatrix().GetData());
}
::glEnable (anFfpPlaneID);
myContext->core11->glClipPlane (anFfpPlaneID, aPlaneEq);
++aPlaneId;
}
// switch off unused lights
for (; aPlaneId < aNbMaxPlanes; ++aPlaneId)
{
::glDisable (GL_CLIP_PLANE0 + aPlaneId);
}
// restore combined model-view matrix
if (toRestoreModelView)
{
const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
myContext->core11->glLoadMatrixf (aModelView.GetData());
}
#endif
return;
}
const GLint aLocEquations = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_EQUATIONS);
if (aLocEquations == OpenGl_ShaderProgram::INVALID_LOCATION)
{
@@ -801,17 +1007,81 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)
theProgram->SetUniform (myContext, aLocEquations, THE_MAX_CLIP_PLANES, anEquations);
}
// =======================================================================
// function : PushMaterialState
// purpose :
// =======================================================================
void OpenGl_ShaderManager::PushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
{
if (myMaterialState.Index() == theProgram->ActiveState (OpenGl_MATERIAL_STATE))
{
return;
}
const OpenGl_Material& aFrontMat = myMaterialState.FrontMaterial();
const OpenGl_Material& aBackMat = myMaterialState.BackMaterial();
theProgram->UpdateState (OpenGl_MATERIAL_STATE, myMaterialState.Index());
if (theProgram == myFfpProgram)
{
#if !defined(GL_ES_VERSION_2_0)
if (myContext->core11 == NULL)
{
return;
}
const GLenum aFrontFace = myMaterialState.ToDistinguish() ? GL_FRONT : GL_FRONT_AND_BACK;
myContext->core11->glMaterialfv(aFrontFace, GL_AMBIENT, aFrontMat.Ambient.GetData());
myContext->core11->glMaterialfv(aFrontFace, GL_DIFFUSE, aFrontMat.Diffuse.GetData());
myContext->core11->glMaterialfv(aFrontFace, GL_SPECULAR, aFrontMat.Specular.GetData());
myContext->core11->glMaterialfv(aFrontFace, GL_EMISSION, aFrontMat.Emission.GetData());
myContext->core11->glMaterialf (aFrontFace, GL_SHININESS, aFrontMat.Shine());
if (myMaterialState.ToDistinguish())
{
myContext->core11->glMaterialfv(GL_BACK, GL_AMBIENT, aBackMat.Ambient.GetData());
myContext->core11->glMaterialfv(GL_BACK, GL_DIFFUSE, aBackMat.Diffuse.GetData());
myContext->core11->glMaterialfv(GL_BACK, GL_SPECULAR, aBackMat.Specular.GetData());
myContext->core11->glMaterialfv(GL_BACK, GL_EMISSION, aBackMat.Emission.GetData());
myContext->core11->glMaterialf (GL_BACK, GL_SHININESS, aBackMat.Shine());
}
#endif
return;
}
theProgram->SetUniform (myContext,
theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),
myMaterialState.ToMapTexture() ? 1 : 0);
theProgram->SetUniform (myContext,
theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE),
myMaterialState.ToDistinguish() ? 1 : 0);
const GLint aLocFront = theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL);
if (aLocFront != OpenGl_ShaderProgram::INVALID_LOCATION)
{
theProgram->SetUniform (myContext, aLocFront, OpenGl_Material::NbOfVec4(),
aFrontMat.Packed());
}
const GLint aLocBack = theProgram->GetStateLocation (OpenGl_OCCT_BACK_MATERIAL);
if (aLocBack != OpenGl_ShaderProgram::INVALID_LOCATION)
{
theProgram->SetUniform (myContext, aLocBack, OpenGl_Material::NbOfVec4(),
aBackMat.Packed());
}
}
// =======================================================================
// function : PushState
// purpose : Pushes state of OCCT graphics parameters to the program
// =======================================================================
void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const
{
PushClippingState (theProgram);
PushWorldViewState (theProgram);
PushModelWorldState (theProgram);
PushProjectionState (theProgram);
PushLightSourceState (theProgram);
const Handle(OpenGl_ShaderProgram)& aProgram = !theProgram.IsNull() ? theProgram : myFfpProgram;
PushClippingState (aProgram);
PushWorldViewState (aProgram);
PushModelWorldState (aProgram);
PushProjectionState (aProgram);
PushLightSourceState (aProgram);
PushMaterialState (aProgram);
}
// =======================================================================
@@ -1776,12 +2046,12 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_Sh
// =======================================================================
Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram)
{
if (!myContext->BindProgram (theProgram))
const Standard_Boolean isBound = myContext->BindProgram (theProgram);
if (isBound
&& !theProgram.IsNull())
{
return Standard_False;
theProgram->ApplyVariables (myContext);
}
theProgram->ApplyVariables (myContext);
PushState (theProgram);
return Standard_True;
return isBound;
}