glgsg: Workaround for Cg shader issue with multiple GSGs

Fixes #1117
This commit is contained in:
rdb 2021-03-22 15:37:43 +01:00
parent 40b94c1f97
commit 8f55d32cb1
3 changed files with 54 additions and 17 deletions

View File

@ -49,18 +49,9 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
nassertv(s->get_language() == Shader::SL_Cg);
// Get a Cg context for this GSG.
CGcontext context = glgsg->_cg_context;
if (context == 0) {
// The GSG doesn't have a Cg context yet. Create one.
glgsg->_cg_context = context = cgCreateContext();
#if CG_VERSION_NUM >= 3100
// This just sounds like a good thing to do.
cgGLSetContextGLSLVersion(context, cgGLDetectGLSLVersion());
if (glgsg->_shader_caps._active_vprofile == CG_PROFILE_GLSLV) {
cgGLSetContextOptimalOptions(context, CG_PROFILE_GLSLC);
}
#endif
CGcontext context = glgsg->get_cg_context();
if (context == nullptr) {
return;
}
// Ask the shader to compile itself for us and to give us the resulting Cg

View File

@ -93,6 +93,11 @@ PStatCollector CLP(GraphicsStateGuardian)::_fbo_bind_pcollector("Draw:Bind FBO")
PStatCollector CLP(GraphicsStateGuardian)::_check_error_pcollector("Draw:Check errors");
PStatCollector CLP(GraphicsStateGuardian)::_check_residency_pcollector("*:PStats:Check residency");
#if defined(HAVE_CG) && !defined(OPENGLES)
AtomicAdjust::Integer CLP(GraphicsStateGuardian)::_num_gsgs_with_cg_contexts = 0;
pvector<CGcontext> CLP(GraphicsStateGuardian)::_destroyed_cg_contexts;
#endif
// The following noop functions are assigned to the corresponding glext
// function pointers in the class, in case the functions are not defined by
// the GL, just so it will always be safe to call the extension functions.
@ -527,7 +532,7 @@ CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) :
_shader_point_size = false;
#endif
#ifdef HAVE_CG
#if defined(HAVE_CG) && !defined(OPENGLES)
_cg_context = 0;
#endif
@ -11556,13 +11561,48 @@ set_state_and_transform(const RenderState *target,
void CLP(GraphicsStateGuardian)::
free_pointers() {
#if defined(HAVE_CG) && !defined(OPENGLES)
if (_cg_context != 0) {
cgDestroyContext(_cg_context);
_cg_context = 0;
if (_cg_context) {
_destroyed_cg_contexts.push_back(_cg_context);
_cg_context = nullptr;
// Don't destroy the Cg context until the last GSG that uses Cg has been
// destroyed. This works around a Cg bug, see #1117.
if (!AtomicAdjust::dec(_num_gsgs_with_cg_contexts)) {
for (CGcontext context : _destroyed_cg_contexts) {
cgDestroyContext(context);
}
_destroyed_cg_contexts.clear();
}
}
#endif
}
/**
* Returns a Cg context for this GSG.
*/
#if defined(HAVE_CG) && !defined(OPENGLES)
CGcontext CLP(GraphicsStateGuardian)::
get_cg_context() {
CGcontext context = _cg_context;
if (context == nullptr) {
context = cgCreateContext();
#if CG_VERSION_NUM >= 3100
// This just sounds like a good thing to do.
cgGLSetContextGLSLVersion(context, cgGLDetectGLSLVersion());
if (_shader_caps._active_vprofile == CG_PROFILE_GLSLV) {
cgGLSetContextOptimalOptions(context, CG_PROFILE_GLSLC);
}
#endif
AtomicAdjust::inc(_num_gsgs_with_cg_contexts);
_cg_context = context;
}
return context;
}
#endif
/**
* This is called by set_state_and_transform() when the texture state has
* changed.

View File

@ -506,6 +506,10 @@ protected:
virtual void free_pointers();
#if defined(HAVE_CG) && !defined(OPENGLES)
CGcontext get_cg_context();
#endif
#ifndef OPENGLES_1
INLINE void enable_vertex_attrib_array(GLuint index);
INLINE void disable_vertex_attrib_array(GLuint index);
@ -689,8 +693,10 @@ protected:
GLfloat _max_line_width;
#ifdef HAVE_CG
#if defined(HAVE_CG) && !defined(OPENGLES)
CGcontext _cg_context;
static AtomicAdjust::Integer _num_gsgs_with_cg_contexts;
static pvector<CGcontext> _destroyed_cg_contexts;
#endif
#ifdef SUPPORT_IMMEDIATE_MODE