From 8f55d32cb15ece3b825fc3c36c6763a3db50e9e3 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 22 Mar 2021 15:37:43 +0100 Subject: [PATCH] glgsg: Workaround for Cg shader issue with multiple GSGs Fixes #1117 --- panda/src/glstuff/glCgShaderContext_src.cxx | 15 ++---- .../glstuff/glGraphicsStateGuardian_src.cxx | 48 +++++++++++++++++-- .../src/glstuff/glGraphicsStateGuardian_src.h | 8 +++- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 1691d10ca7..c0a3b7d284 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -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 diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index bd6112107a..2e997a8587 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -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 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. diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index b3974522ea..02e22961ce 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -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 _destroyed_cg_contexts; #endif #ifdef SUPPORT_IMMEDIATE_MODE