Browse Source

Memory barriers, immutable texture storage, bindless textures, fixes for multisample FBOs, code cleanup, etc.

rdb 11 years ago
parent
commit
efa258ebf3

+ 1 - 1
panda/src/glstuff/glCgShaderContext_src.I

@@ -40,7 +40,7 @@ valid() {
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(CgShaderContext)::
 uses_standard_vertex_arrays() {
-  return _uses_standard_vertex_arrays;
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 19 - 9
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -40,8 +40,10 @@ TypeHandle CLP(CgShaderContext)::_type_handle;
 CLP(CgShaderContext)::
 CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
   _glgsg = glgsg;
-  _uses_standard_vertex_arrays = false;
   _cg_context = 0;
+  _cg_vprogram = 0;
+  _cg_fprogram = 0;
+  _cg_gprogram = 0;
   _cg_vprofile = CG_PROFILE_UNKNOWN;
   _cg_fprofile = CG_PROFILE_UNKNOWN;
   _cg_gprofile = CG_PROFILE_UNKNOWN;
@@ -409,10 +411,14 @@ disable_shader_vertex_arrays() {
 ////////////////////////////////////////////////////////////////////
 bool CLP(CgShaderContext)::
 update_shader_vertex_arrays(ShaderContext *prev, bool force) {
-  if (prev) prev->disable_shader_vertex_arrays();
+  if (prev) {
+    prev->disable_shader_vertex_arrays();
+  }
+
   if (!valid()) {
     return true;
   }
+
   cg_report_errors();
 
 #ifdef SUPPORT_IMMEDIATE_MODE
@@ -451,11 +457,17 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         }
 
         CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
-        cgGLSetParameterPointer(p,
-                                num_values, _glgsg->get_numeric_type(numeric_type),
-                                stride, client_pointer + start);
+
         cgGLEnableClientState(p);
-      } else  {
+        if (numeric_type == GeomEnums::NT_packed_dabc) {
+          cgGLSetParameterPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
+                                  stride, client_pointer + start);
+        } else {
+          cgGLSetParameterPointer(p,
+                                  num_values, _glgsg->get_numeric_type(numeric_type),
+                                  stride, client_pointer + start);
+        }
+      } else {
         CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
         cgGLDisableClientState(p);
       }
@@ -464,7 +476,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
 
   cg_report_errors();
   _glgsg->report_my_gl_errors();
-  
+
   return true;
 }
 
@@ -507,7 +519,6 @@ disable_shader_texture_bindings() {
     // cgGLDisableTextureParameter(p);
   }
 #endif  // OPENGLES_2
-  _stage_offset = 0;
 
   cg_report_errors();
   _glgsg->report_my_gl_errors();
@@ -538,7 +549,6 @@ update_shader_texture_bindings(ShaderContext *prev) {
   // filtered TextureAttrib in _target_texture.
   const TextureAttrib *texattrib = DCAST(TextureAttrib, _glgsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
   nassertv(texattrib != (TextureAttrib *)NULL);
-  _stage_offset = texattrib->get_num_on_stages();
 
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
     InternalName *id = _shader->_tex_spec[i]._name;

+ 0 - 3
panda/src/glstuff/glCgShaderContext_src.h

@@ -61,11 +61,8 @@ private:
 
   pvector <CGparameter> _cg_parameter_map;
 
-  int _stage_offset;
   CLP(GraphicsStateGuardian) *_glgsg;
 
-  bool _uses_standard_vertex_arrays;
-
   void release_resources();
 
 public:

+ 29 - 21
panda/src/glstuff/glGeomMunger_src.cxx

@@ -46,7 +46,7 @@ CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) :
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GeomMunger)::Destructor
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 CLP(GeomMunger)::
 ~CLP(GeomMunger)() {
@@ -84,9 +84,13 @@ munge_format_impl(const GeomVertexFormat *orig,
   PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig);
   new_format->set_animation(animation);
 
+  CLP(GraphicsStateGuardian) *glgsg;
+  DCAST_INTO_R(glgsg, get_gsg(), NULL);
+
   const GeomVertexColumn *color_type = orig->get_color_column();
   if (color_type != (GeomVertexColumn *)NULL &&
-      color_type->get_numeric_type() == NT_packed_dabc) {
+      color_type->get_numeric_type() == NT_packed_dabc &&
+      !glgsg->_supports_packed_dabc) {
     // We need to convert the color format; OpenGL doesn't support the
     // byte order of DirectX's packed ARGB format.
     int color_array = orig->get_array_with(InternalName::get_color());
@@ -102,7 +106,7 @@ munge_format_impl(const GeomVertexFormat *orig,
   if (animation.get_animation_type() == AT_hardware) {
     // If we want hardware animation, we need to reserve space for the
     // blend weights.
-      
+
     // Make sure the old weights and indices are removed, just in
     // case.
     new_format->remove_column(InternalName::get_transform_weight());
@@ -116,11 +120,11 @@ munge_format_impl(const GeomVertexFormat *orig,
       new_array_format->add_column
         (InternalName::get_transform_weight(), animation.get_num_transforms() - 1,
          NT_stdfloat, C_other);
-      
+
       if (animation.get_indexed_transforms()) {
         // Also, if we'll be indexing into the transform table, reserve
         // space for the index.
-        
+
         // TODO: We should examine the maximum palette index so we can
         // decide whether we need 16-bit indices.  That implies saving
         // the maximum palette index, presumably in the AnimationSpec.
@@ -129,7 +133,7 @@ munge_format_impl(const GeomVertexFormat *orig,
         new_array_format->add_column
           (InternalName::get_transform_index(), animation.get_num_transforms(),
            NT_uint8, C_index);
-      }                                    
+      }
 
       new_format->add_array(new_array_format);
     }
@@ -149,16 +153,16 @@ munge_format_impl(const GeomVertexFormat *orig,
       new_format->add_array(new_array_format);
     }
     format = GeomVertexFormat::register_format(new_format);
-  
+
   } else if ((_flags & F_interleaved_arrays) != 0) {
     // Combine the primary data columns into a single array.
     new_format = new GeomVertexFormat(*format);
     PT(GeomVertexArrayFormat) new_array_format = new GeomVertexArrayFormat;
-  
+
     const GeomVertexColumn *column = format->get_vertex_column();
     if (column != (const GeomVertexColumn *)NULL) {
       new_array_format->add_column
-        (column->get_name(), column->get_num_components(), 
+        (column->get_name(), column->get_num_components(),
          column->get_numeric_type(), column->get_contents(),
          -1, column->get_column_alignment());
       new_format->remove_column(column->get_name());
@@ -167,7 +171,7 @@ munge_format_impl(const GeomVertexFormat *orig,
     column = format->get_normal_column();
     if (column != (const GeomVertexColumn *)NULL) {
       new_array_format->add_column
-        (column->get_name(), column->get_num_components(), 
+        (column->get_name(), column->get_num_components(),
          column->get_numeric_type(), column->get_contents(),
          -1, column->get_column_alignment());
       new_format->remove_column(column->get_name());
@@ -176,7 +180,7 @@ munge_format_impl(const GeomVertexFormat *orig,
     column = format->get_color_column();
     if (column != (const GeomVertexColumn *)NULL) {
       new_array_format->add_column
-        (column->get_name(), column->get_num_components(), 
+        (column->get_name(), column->get_num_components(),
          column->get_numeric_type(), column->get_contents(),
          -1, column->get_column_alignment());
       new_format->remove_column(column->get_name());
@@ -187,7 +191,7 @@ munge_format_impl(const GeomVertexFormat *orig,
     if (_texture != (TextureAttrib *)NULL) {
       typedef pset<const InternalName *> UsedStages;
       UsedStages used_stages;
-      
+
       int num_stages = _texture->get_num_on_stages();
       for (int i = 0; i < num_stages; ++i) {
         TextureStage *stage = _texture->get_on_stage(i);
@@ -197,7 +201,7 @@ munge_format_impl(const GeomVertexFormat *orig,
           if (used_stages.insert(name).second) {
             // This is the first time we've encountered this texcoord name.
             const GeomVertexColumn *texcoord_type = format->get_column(name);
-            
+
             if (texcoord_type != (const GeomVertexColumn *)NULL) {
               new_array_format->add_column
                 (name, texcoord_type->get_num_values(), NT_stdfloat, C_texcoord,
@@ -230,9 +234,13 @@ CPT(GeomVertexFormat) CLP(GeomMunger)::
 premunge_format_impl(const GeomVertexFormat *orig) {
   PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig);
 
+  CLP(GraphicsStateGuardian) *glgsg;
+  DCAST_INTO_R(glgsg, get_gsg(), NULL);
+
   const GeomVertexColumn *color_type = orig->get_color_column();
   if (color_type != (GeomVertexColumn *)NULL &&
-      color_type->get_numeric_type() == NT_packed_dabc) {
+      color_type->get_numeric_type() == NT_packed_dabc &&
+      !glgsg->_supports_packed_dabc) {
     // We need to convert the color format; OpenGL doesn't support the
     // byte order of DirectX's packed ARGB format.
     int color_array = orig->get_array_with(InternalName::get_color());
@@ -259,7 +267,7 @@ premunge_format_impl(const GeomVertexFormat *orig) {
       new_format->add_array(new_array_format);
     }
     format = GeomVertexFormat::register_format(new_format);
-  
+
   } else {
     // Combine the primary data columns into a single array.  Unlike
     // the munge case, above, in the premunge case, we do this even if
@@ -269,11 +277,11 @@ premunge_format_impl(const GeomVertexFormat *orig) {
     // at run time.
     new_format = new GeomVertexFormat(*format);
     PT(GeomVertexArrayFormat) new_array_format = new GeomVertexArrayFormat;
-  
+
     const GeomVertexColumn *column = format->get_vertex_column();
     if (column != (const GeomVertexColumn *)NULL) {
       new_array_format->add_column
-        (column->get_name(), column->get_num_components(), 
+        (column->get_name(), column->get_num_components(),
          column->get_numeric_type(), column->get_contents(),
          -1, column->get_column_alignment());
       new_format->remove_column(column->get_name());
@@ -282,7 +290,7 @@ premunge_format_impl(const GeomVertexFormat *orig) {
     column = format->get_normal_column();
     if (column != (const GeomVertexColumn *)NULL) {
       new_array_format->add_column
-        (column->get_name(), column->get_num_components(), 
+        (column->get_name(), column->get_num_components(),
          column->get_numeric_type(), column->get_contents(),
          -1, column->get_column_alignment());
       new_format->remove_column(column->get_name());
@@ -291,7 +299,7 @@ premunge_format_impl(const GeomVertexFormat *orig) {
     column = format->get_color_column();
     if (column != (const GeomVertexColumn *)NULL) {
       new_array_format->add_column
-        (column->get_name(), column->get_num_components(), 
+        (column->get_name(), column->get_num_components(),
          column->get_numeric_type(), column->get_contents(),
          -1, column->get_column_alignment());
       new_format->remove_column(column->get_name());
@@ -303,7 +311,7 @@ premunge_format_impl(const GeomVertexFormat *orig) {
     if (_texture != (TextureAttrib *)NULL) {
       typedef pset<const InternalName *> UsedStages;
       UsedStages used_stages;
-      
+
       int num_stages = _texture->get_num_on_stages();
       for (int i = 0; i < num_stages; ++i) {
         TextureStage *stage = _texture->get_on_stage(i);
@@ -313,7 +321,7 @@ premunge_format_impl(const GeomVertexFormat *orig) {
           if (used_stages.insert(name).second) {
             // This is the first time we've encountered this texcoord name.
             const GeomVertexColumn *texcoord_type = format->get_column(name);
-            
+
             if (texcoord_type != (const GeomVertexColumn *)NULL) {
               new_array_format->add_column
                 (name, texcoord_type->get_num_values(), NT_stdfloat, C_texcoord,

+ 92 - 45
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -73,9 +73,8 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
   _rb_size_x = 0;
   _rb_size_y = 0;
   _rb_size_z = 0;
-  for (int i=0; i<RTP_COUNT; i++) {
+  for (int i = 0; i < RTP_COUNT; ++i) {
     _rb[i] = 0;
-    _tex[i] = 0;
     _rbm[i] = 0;
   }
 
@@ -170,6 +169,24 @@ begin_frame(FrameMode mode, Thread *current_thread) {
       // rebuild_bitplanes().
       return false;
     }
+
+    // In case of multisample rendering, we don't need to issue
+    // the barrier until we call glBlitFramebuffer.
+    if (gl_enable_memory_barriers && _fbo_multisample == 0) {
+      CLP(GraphicsStateGuardian) *glgsg;
+      DCAST_INTO_R(glgsg, _gsg, false);
+
+      pvector<CLP(TextureContext)*>::iterator it;
+      for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
+        CLP(TextureContext) *gtc = *it;
+
+        if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) {
+          glgsg->issue_memory_barrier(GL_FRAMEBUFFER_BARRIER_BIT);
+          // If we've done it for one, we've done it for all.
+          break;
+        }
+      }
+    }
   }
 
   _gsg->set_current_properties(&get_fb_properties());
@@ -248,7 +265,9 @@ rebuild_bitplanes() {
   DCAST_INTO_V(glgsg, _gsg);
 
   if (!_needs_rebuild) {
-    if (_fbo.size() > 0) {
+    if (_fbo_multisample != 0) {
+      glgsg->bind_fbo(_fbo_multisample);
+    } else if (_fbo.size() > 0) {
       glgsg->bind_fbo(_fbo[0]);
     } else {
       glgsg->bind_fbo(0);
@@ -284,6 +303,7 @@ rebuild_bitplanes() {
   // These variables indicate what should be bound to each bitplane.
   Texture *attach[RTP_COUNT];
   memset(attach, 0, sizeof(Texture *) * RTP_COUNT);
+  _texture_contexts.clear();
 
   // Sort the textures list into appropriate slots.
   {
@@ -437,12 +457,13 @@ rebuild_bitplanes() {
       bind_slot(layer, rb_resize, attach, RTP_color, next++);
 
       if (_fb_properties.is_stereo()) {
-        // The texture has already been initialized, so bind it straight away.
+        // The second tex view has already been initialized, so bind it straight away.
         if (attach[RTP_color] != NULL) {
           attach_tex(layer, 1, attach[RTP_color], next++);
         } else {
           //XXX hack: I needed a slot to use, and we don't currently use RTP_stencil
-          // which is treated as a color attachment below, so this fits the bill.
+          // and it's treated as a color attachment below, so this fits the bill.
+          // Eventually, we might want to add RTP_color_left and RTP_color_right.
           bind_slot(layer, rb_resize, attach, RTP_stencil, next++);
         }
       }
@@ -553,7 +574,6 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
   DCAST_INTO_V(glgsg, _gsg);
 
   Texture *tex = attach[slot];
-  _tex[slot] = tex;
 
   if (tex && layer >= tex->get_z_size()) {
     // If the requested layer index exceeds the number of layers
@@ -1047,7 +1067,10 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
   TextureContext *tc = attach->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
   nassertv(tc != (TextureContext *)NULL);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-  glgsg->update_texture(tc, true);
+
+  glgsg->update_texture(gtc, true);
+  gtc->set_active(true);
+  _texture_contexts.push_back(gtc);
 
 #ifndef OPENGLES
   GLclampf priority = 1.0f;
@@ -1098,23 +1121,26 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
 generate_mipmaps() {
+  if (gl_ignore_mipmaps && !gl_force_mipmaps) {
+    return;
+  }
+
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
 
-  for (int slot=0; slot<RTP_COUNT; slot++) {
-    Texture *tex = _tex[slot];
-    if ((tex != 0) && (tex->uses_mipmaps())) {
+  pvector<CLP(TextureContext)*>::iterator it;
+  for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
+    CLP(TextureContext) *gtc = *it;
+
+    if (gtc->_generate_mipmaps) {
       glgsg->_state_texture = 0;
-      TextureContext *tc = tex->prepare_now(0, glgsg->get_prepared_objects(), glgsg);
-      nassertv(tc != (TextureContext *)NULL);
-      CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-      glgsg->update_texture(tc, true);
-      GLenum target = glgsg->get_texture_target(tex->get_texture_type());
-      glBindTexture(target, gtc->_index);
-      glgsg->_glGenerateMipmap(target);
-      glBindTexture(target, 0);
+      glgsg->update_texture(gtc, true);
+      glgsg->apply_texture(gtc);
+      glgsg->_glGenerateMipmap(gtc->_target);
+      glBindTexture(gtc->_target, 0);
     }
   }
+
   report_my_gl_errors();
 }
 
@@ -1197,8 +1223,12 @@ select_target_tex_page(int page) {
         resolve_multisamples();
       }
     }
-    
-    glgsg->bind_fbo(_fbo[page]);
+
+    if (_fbo_multisample != 0) {
+      // TODO: re-issue clears?
+    } else {
+      glgsg->bind_fbo(_fbo[page]);
+    }
     _bound_tex_page = page;
   }
 
@@ -1305,7 +1335,8 @@ open_buffer() {
     _fb_properties.set_stencil_bits(0);
   }
   _fb_properties.set_accum_bits(0);
-  _fb_properties.set_multisamples(_host->get_fb_properties().get_multisamples());
+
+  _fb_properties.set_multisamples(_requested_multisamples);
 
   // Update aux settings to reflect the GL_MAX_DRAW_BUFFERS limit,
   // if we exceed it, that is.
@@ -1378,7 +1409,6 @@ close_buffer() {
       glgsg->_glDeleteRenderbuffers(1, &(_rb[i]));
       _rb[i] = 0;
     }
-    _tex[i] = 0;
   }
   // Delete the renderbuffers.
   for (int i=0; i<RTP_COUNT; i++) {
@@ -1386,7 +1416,6 @@ close_buffer() {
       glgsg->_glDeleteRenderbuffers(1, &(_rbm[i]));
       _rb[i] = 0;
     }
-    _tex[i] = 0;
   }
   _rb_size_x = 0;
   _rb_size_y = 0;
@@ -1577,6 +1606,21 @@ resolve_multisamples() {
 
   nassertv(_fbo.size() > 0);
 
+  if (gl_enable_memory_barriers) {
+    // Issue memory barriers as necessary to make sure that the
+    // texture memory is synchronized before we blit to it.
+    pvector<CLP(TextureContext)*>::iterator it;
+    for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
+      CLP(TextureContext) *gtc = *it;
+
+      if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) {
+        glgsg->issue_memory_barrier(GL_FRAMEBUFFER_BARRIER_BIT);
+        // If we've done it for one, we've done it for all.
+        break;
+      }
+    }
+  }
+
   glgsg->report_my_gl_errors();
   GLuint fbo = _fbo[0];
   if (_bound_tex_page != -1) {
@@ -1586,31 +1630,34 @@ resolve_multisamples() {
   glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample);
   
   // If the depth buffer is shared, resolve it only on the last to render FBO.
-  int do_depth_blit = 0;
-  if (_shared_depth_buffer) {
-    CLP(GraphicsBuffer) *graphics_buffer = NULL;
-    CLP(GraphicsBuffer) *highest_sort_graphics_buffer = NULL;
-    list <CLP(GraphicsBuffer) *>::iterator graphics_buffer_iterator;
-    
-    int max_sort_order = 0;
-    for (graphics_buffer_iterator = _shared_depth_buffer_list.begin();
-         graphics_buffer_iterator != _shared_depth_buffer_list.end();
-         graphics_buffer_iterator++) {
-      graphics_buffer = (*graphics_buffer_iterator);
-      if (graphics_buffer) {
-        // this call removes the entry from the list
-        if ( graphics_buffer->get_sort() >= max_sort_order ) {
-          max_sort_order = graphics_buffer->get_sort();
-          highest_sort_graphics_buffer = graphics_buffer;
+  bool do_depth_blit = false;
+  if (_rbm[RTP_depth_stencil] != 0 || _rbm[RTP_depth] != 0) {
+    if (_shared_depth_buffer) {
+      CLP(GraphicsBuffer) *graphics_buffer = NULL;
+      CLP(GraphicsBuffer) *highest_sort_graphics_buffer = NULL;
+      list <CLP(GraphicsBuffer) *>::iterator graphics_buffer_iterator;
+
+      int max_sort_order = 0;
+      for (graphics_buffer_iterator = _shared_depth_buffer_list.begin();
+           graphics_buffer_iterator != _shared_depth_buffer_list.end();
+           graphics_buffer_iterator++) {
+        graphics_buffer = (*graphics_buffer_iterator);
+        if (graphics_buffer) {
+          // this call removes the entry from the list
+          if (graphics_buffer->get_sort() >= max_sort_order) {
+            max_sort_order = graphics_buffer->get_sort();
+            highest_sort_graphics_buffer = graphics_buffer;
+          }
         }
       }
+      if (max_sort_order == this->get_sort()) {
+        do_depth_blit = true;
+      }
+    } else {
+      do_depth_blit = true;
     }
-    if (max_sort_order == this->get_sort()) {
-      do_depth_blit = 1;
-    }
-  } else {
-    do_depth_blit = 1;
   }
+
   if (do_depth_blit) {
     glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y,
                               GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
@@ -1620,7 +1667,6 @@ resolve_multisamples() {
                               GL_COLOR_BUFFER_BIT,
                               GL_NEAREST);
   }
-#ifndef OPENGLES
   // Now handle the other color buffers.
   int next = GL_COLOR_ATTACHMENT1_EXT;
   if (_fb_properties.is_stereo()) {
@@ -1630,6 +1676,7 @@ resolve_multisamples() {
                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
     next += 1;
   }
+#ifndef OPENGLES
   for (int i = 0; i < _fb_properties.get_aux_rgba(); ++i) {
     glReadBuffer(next);
     glDrawBuffer(next);

+ 6 - 4
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -120,13 +120,15 @@ private:
   int         _rb_size_y;
   int         _rb_size_z;
 
-  // The texture or render buffer bound to each plane.
-  PT(Texture) _tex[RTP_COUNT];
+  // Stores the render buffers for each plane.
+  // _rbm stores the multisample renderbuffers.
   GLuint      _rb[RTP_COUNT];
-
-  // The render buffer for _fbo_multisample.
   GLuint      _rbm[RTP_COUNT];
 
+  // List of textures for which we might have to generate mipmaps
+  // after rendering one frame.
+  pvector<CLP(TextureContext)*> _texture_contexts;
+
   // The cube map face we are currently drawing to or have just
   // finished drawing to, or -1 if we are not drawing to a cube map.
   int _bound_tex_page;

File diff suppressed because it is too large
+ 399 - 213
panda/src/glstuff/glGraphicsStateGuardian_src.cxx


+ 51 - 9
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -134,6 +134,9 @@ typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXOESPROC) (GLuint matrixpalettei
 typedef void (APIENTRYP PFNGLLOADPALETTEFROMMODELVIEWMATRIXOESPROC) (void);
 typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 
 #ifndef OPENGLES_1
 // GLSL shader functions
@@ -177,12 +180,29 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size,
 typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
 typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
 typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
 typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
 typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
 typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
 typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
 typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufsize, GLsizei *length, GLenum *binaryFormat, void *binary);
 typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); 
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEPROC) (GLuint texture);
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEPROC) (GLuint texture, GLuint sampler);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTPROC) (GLuint64 handle);
+typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTPROC) (GLuint64 handle, GLenum access);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64PROC) (GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64PROC) (GLuint program, GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTPROC) (GLuint64 handle);
+typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64PROC) (GLuint index, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
 #endif  // OPENGLES
 #endif  // __EDG__
 
@@ -242,6 +262,8 @@ public:
                            bool force);
   virtual void end_draw_primitives();
 
+  void issue_memory_barrier(GLbitfield barrier);
+
   virtual TextureContext *prepare_texture(Texture *tex, int view);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual void release_texture(TextureContext *tc);
@@ -448,7 +470,7 @@ protected:
   bool specify_texture(CLP(TextureContext) *gtc);
   bool apply_texture(TextureContext *tc);
   bool upload_texture(CLP(TextureContext) *gtc, bool force);
-  bool upload_texture_image(CLP(TextureContext) *gtc,
+  bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
                             bool uses_mipmaps, int mipmap_bias,
                             GLenum texture_target, GLenum page_target, 
                             GLint internal_format, GLint external_format, 
@@ -506,12 +528,12 @@ protected:
   bool _vertex_blending_enabled;
 
 #ifndef OPENGLES_1
-  PT(Shader)  _current_shader;
-  CLP(ShaderContext)  *_current_shader_context;
-  PT(Shader)  _vertex_array_shader;
-  CLP(ShaderContext)  *_vertex_array_shader_context;
-  PT(Shader)  _texture_binding_shader;
-  CLP(ShaderContext)  *_texture_binding_shader_context;
+  PT(Shader) _current_shader;
+  ShaderContext *_current_shader_context;
+  PT(Shader) _vertex_array_shader;
+  ShaderContext *_vertex_array_shader_context;
+  PT(Shader) _texture_binding_shader;
+  ShaderContext *_texture_binding_shader_context;
 #endif
 #ifdef OPENGLES_2
   static PT(Shader)  _default_shader;
@@ -590,6 +612,11 @@ public:
   PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
   PFNGLCOPYTEXSUBIMAGE3DPROC _glCopyTexSubImage3D;
 
+  bool _supports_tex_storage;
+  PFNGLTEXSTORAGE1DPROC _glTexStorage1D;
+  PFNGLTEXSTORAGE2DPROC _glTexStorage2D;
+  PFNGLTEXSTORAGE3DPROC _glTexStorage3D;
+
   PFNGLCOMPRESSEDTEXIMAGE1DPROC _glCompressedTexImage1D;
   PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D;
   PFNGLCOMPRESSEDTEXIMAGE3DPROC _glCompressedTexImage3D;
@@ -600,6 +627,7 @@ public:
 
   bool _supports_bgr;
   bool _supports_rescale_normal;
+  bool _supports_packed_dabc;
 
   bool _supports_multitexture;
   PFNGLACTIVETEXTUREPROC _glActiveTexture;
@@ -661,6 +689,7 @@ public:
   PFNGLDRAWBUFFERSPROC _glDrawBuffers;
   int _max_fb_samples;
   bool _supports_viewport_arrays;
+  bool _supports_bindless_texture;
 
   PFNGLGENQUERIESPROC _glGenQueries;
   PFNGLBEGINQUERYPROC _glBeginQuery;
@@ -714,6 +743,7 @@ public:
   PFNGLPATCHPARAMETERIPROC _glPatchParameteri;
   PFNGLDRAWARRAYSINSTANCEDPROC _glDrawArraysInstanced;
   PFNGLDRAWELEMENTSINSTANCEDPROC _glDrawElementsInstanced;
+  PFNGLBINDTEXTURESPROC _glBindTextures;
   PFNGLBINDIMAGETEXTUREPROC _glBindImageTexture;
   PFNGLBINDIMAGETEXTURESPROC _glBindImageTextures;
   PFNGLDISPATCHCOMPUTEPROC _glDispatchCompute;
@@ -723,6 +753,11 @@ public:
   PFNGLVIEWPORTARRAYVPROC _glViewportArrayv;
   PFNGLSCISSORARRAYVPROC _glScissorArrayv;
   PFNGLDEPTHRANGEARRAYVPROC _glDepthRangeArrayv;
+  PFNGLGETTEXTUREHANDLEPROC _glGetTextureHandle;
+  PFNGLMAKETEXTUREHANDLERESIDENTPROC _glMakeTextureHandleResident;
+  PFNGLMAKETEXTUREHANDLENONRESIDENTPROC _glMakeTextureHandleNonResident;
+  PFNGLUNIFORMHANDLEUI64PROC _glUniformHandleui64;
+  PFNGLUNIFORMHANDLEUI64VPROC _glUniformHandleui64v;
 #endif  // OPENGLES
 
   GLenum _edge_clamp;
@@ -740,6 +775,15 @@ public:
   DeletedDisplayLists _deleted_display_lists;
   DeletedDisplayLists _deleted_queries;
 
+#ifndef OPENGLES
+  // Stores textures for which memory bariers should be issued.
+  typedef pset<TextureContext*> TextureSet;
+  TextureSet _textures_needing_fetch_barrier;
+  TextureSet _textures_needing_image_access_barrier;
+  TextureSet _textures_needing_update_barrier;
+  TextureSet _textures_needing_framebuffer_barrier;
+#endif
+
   //RenderState::SlotMask _inv_state_mask;
 
   bool _check_errors;
@@ -798,5 +842,3 @@ private:
 };
 
 #include "glGraphicsStateGuardian_src.I"
-
-

+ 204 - 149
panda/src/glstuff/glShaderContext_src.cxx

@@ -195,18 +195,12 @@ CLP(ShaderContext)::
 CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
   _glgsg = glgsg;
   _glsl_program = 0;
-  _glsl_vshader = 0;
-  _glsl_fshader = 0;
-  _glsl_gshader = 0;
-  _glsl_tcshader = 0;
-  _glsl_teshader = 0;
-  _glsl_cshader = 0;
   _uses_standard_vertex_arrays = false;
 
   nassertv(s->get_language() == Shader::SL_GLSL);
 
   // We compile and analyze the shader here, instead of in shader.cxx, to avoid gobj getting a dependency on GL stuff.
-  if (!glsl_compile_shader()) {
+  if (!glsl_compile_and_link()) {
     release_resources();
     s->_error_flag = true;
     return;
@@ -344,6 +338,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             continue;
           }
           if (size > 7 && noprefix.substr(0, 7) == "Texture") {
+            _glgsg->_glUniform1i(p, s->_tex_spec.size());
             Shader::ShaderTexSpec bind;
             bind._id = arg_id;
             bind._name = 0;
@@ -376,7 +371,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
               s->_mat_spec.push_back(bind);
               continue;
             } else if (noprefix == "Material.specular") {
-              bind._piece = Shader::SMP_row3;
+              bind._piece = Shader::SMP_row3x3;
               s->_mat_spec.push_back(bind);
               continue;
             }
@@ -463,6 +458,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             case GL_UNSIGNED_INT_SAMPLER_1D:
             case GL_SAMPLER_1D_SHADOW:
             case GL_SAMPLER_1D: {
+              _glgsg->_glUniform1i(p, s->_tex_spec.size());
               Shader::ShaderTexSpec bind;
               bind._id = arg_id;
               bind._name = InternalName::make(param_name);
@@ -475,6 +471,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             case GL_SAMPLER_2D_SHADOW:
 #endif
             case GL_SAMPLER_2D: {
+              _glgsg->_glUniform1i(p, s->_tex_spec.size());
               Shader::ShaderTexSpec bind;
               bind._id = arg_id;
               bind._name = InternalName::make(param_name);
@@ -487,6 +484,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             case GL_UNSIGNED_INT_SAMPLER_3D:
 #endif
             case GL_SAMPLER_3D: {
+              _glgsg->_glUniform1i(p, s->_tex_spec.size());
               Shader::ShaderTexSpec bind;
               bind._id = arg_id;
               bind._name = InternalName::make(param_name);
@@ -500,6 +498,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
             case GL_SAMPLER_CUBE_SHADOW:
 #endif
             case GL_SAMPLER_CUBE: {
+              _glgsg->_glUniform1i(p, s->_tex_spec.size());
               Shader::ShaderTexSpec bind;
               bind._id = arg_id;
               bind._name = InternalName::make(param_name);
@@ -508,7 +507,11 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
               s->_tex_spec.push_back(bind);
               continue; }
 #ifndef OPENGLES
+            case GL_INT_SAMPLER_2D_ARRAY:
+            case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+            case GL_SAMPLER_2D_ARRAY_SHADOW:
             case GL_SAMPLER_2D_ARRAY: {
+              _glgsg->_glUniform1i(p, s->_tex_spec.size());
               Shader::ShaderTexSpec bind;
               bind._id = arg_id;
               bind._name = InternalName::make(param_name);
@@ -584,6 +587,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
                 case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
                 case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
               }
+              bind._type = Shader::SPT_int;
               bind._arg = InternalName::make(param_name);
               bind._dim[0] = 1;
               bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
@@ -611,6 +615,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
               // bind once and then forget about it.
               _glgsg->_glUniform1i(p, imgunitno++);
               _glsl_img_inputs.push_back(InternalName::make(param_name));
+              _glsl_img_textures.push_back(NULL);
               continue;
 #endif
             default:
@@ -661,6 +666,23 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
               case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
               case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
             }
+            switch (param_type) {
+              case GL_BOOL:
+              case GL_BOOL_VEC2:
+              case GL_BOOL_VEC3:
+              case GL_BOOL_VEC4:
+                bind._type = Shader::SPT_unknown;
+                break;
+              case GL_INT:
+              case GL_INT_VEC2:
+              case GL_INT_VEC3:
+              case GL_INT_VEC4:
+                bind._type = Shader::SPT_int;
+                break;
+              default:
+                bind._type = Shader::SPT_float;
+                break;
+            }
             bind._arg = InternalName::make(param_name);
             bind._dim[0] = param_size;
             bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
@@ -783,51 +805,20 @@ release_resources() {
     return;
   }
   if (_glsl_program != 0) {
-    if (_glsl_vshader != 0) {
-      _glgsg->_glDetachShader(_glsl_program, _glsl_vshader);
-    }
-    if (_glsl_fshader != 0) {
-      _glgsg->_glDetachShader(_glsl_program, _glsl_fshader);
-    }
-    if (_glsl_gshader != 0) {
-      _glgsg->_glDetachShader(_glsl_program, _glsl_gshader);
-    }
-    if (_glsl_tcshader != 0) {
-      _glgsg->_glDetachShader(_glsl_program, _glsl_tcshader);
-    }
-    if (_glsl_teshader != 0) {
-      _glgsg->_glDetachShader(_glsl_program, _glsl_teshader);
-    }
-    if (_glsl_cshader != 0) {
-      _glgsg->_glDetachShader(_glsl_program, _glsl_cshader);
+    GLSLShaders::const_iterator it;
+    for (it = _glsl_shaders.begin(); it != _glsl_shaders.end(); ++it) {
+      _glgsg->_glDetachShader(_glsl_program, *it);
     }
     _glgsg->_glDeleteProgram(_glsl_program);
     _glsl_program = 0;
   }
-  if (_glsl_vshader != 0) {
-    _glgsg->_glDeleteShader(_glsl_vshader);
-    _glsl_vshader = 0;
-  }
-  if (_glsl_fshader != 0) {
-    _glgsg->_glDeleteShader(_glsl_fshader);
-    _glsl_fshader = 0;
-  }
-  if (_glsl_gshader != 0) {
-    _glgsg->_glDeleteShader(_glsl_gshader);
-    _glsl_gshader = 0;
-  }
-  if (_glsl_tcshader != 0) {
-    _glgsg->_glDeleteShader(_glsl_tcshader);
-    _glsl_tcshader = 0;
-  }
-  if (_glsl_teshader != 0) {
-    _glgsg->_glDeleteShader(_glsl_teshader);
-    _glsl_teshader = 0;
-  }
-  if (_glsl_cshader != 0) {
-    _glgsg->_glDeleteShader(_glsl_cshader);
-    _glsl_cshader = 0;
+
+  GLSLShaders::const_iterator it;
+  for (it = _glsl_shaders.begin(); it != _glsl_shaders.end(); ++it) {
+    _glgsg->_glDeleteShader(*it);
   }
+
+  _glsl_shaders.clear();
   
   _glgsg->report_my_gl_errors();
 }
@@ -890,32 +881,33 @@ issue_parameters(int altered) {
 
   // Iterate through _ptr parameters
   for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
-    if(altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])) {
-      const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i];
+    const Shader::ShaderPtrSpec& spec = _shader->_ptr_spec[i];
+
+    if (altered & (spec._dep[0] | spec._dep[1])) {
       Shader::ShaderPtrData* ptr_data =
-        const_cast< Shader::ShaderPtrData*>(_glgsg->fetch_ptr_parameter(_ptr));
+        const_cast< Shader::ShaderPtrData*>(_glgsg->fetch_ptr_parameter(spec));
       if (ptr_data == NULL) { //the input is not contained in ShaderPtrData
         release_resources();
         return;
       }
-      GLint p = _glsl_parameter_map[_shader->_ptr_spec[i]._id._seqno];
 
+      GLint p = _glsl_parameter_map[spec._id._seqno];
       switch (ptr_data->_type) {
       case Shader::SPT_float:
-        switch (_ptr._dim[1]) {
-          case 1: _glgsg->_glUniform1fv(p, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
-          case 2: _glgsg->_glUniform2fv(p, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
-          case 3: _glgsg->_glUniform3fv(p, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
-          case 4: _glgsg->_glUniform4fv(p, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
-          case 9: _glgsg->_glUniformMatrix3fv(p, _ptr._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
-          case 16: _glgsg->_glUniformMatrix4fv(p, _ptr._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
+        switch (spec._dim[1]) {
+          case 1: _glgsg->_glUniform1fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
+          case 2: _glgsg->_glUniform2fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
+          case 3: _glgsg->_glUniform3fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
+          case 4: _glgsg->_glUniform4fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
+          case 9: _glgsg->_glUniformMatrix3fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
+          case 16: _glgsg->_glUniformMatrix4fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
         }
       case Shader::SPT_int:
-        switch (_ptr._dim[1]) {
-          case 1: _glgsg->_glUniform1iv(p, _ptr._dim[0], (int*)ptr_data->_ptr); continue;
-          case 2: _glgsg->_glUniform2iv(p, _ptr._dim[0], (int*)ptr_data->_ptr); continue;
-          case 3: _glgsg->_glUniform3iv(p, _ptr._dim[0], (int*)ptr_data->_ptr); continue;
-          case 4: _glgsg->_glUniform4iv(p, _ptr._dim[0], (int*)ptr_data->_ptr); continue;
+        switch (spec._dim[1]) {
+          case 1: _glgsg->_glUniform1iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
+          case 2: _glgsg->_glUniform2iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
+          case 3: _glgsg->_glUniform3iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
+          case 4: _glgsg->_glUniform4iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
         }
       case Shader::SPT_double:
         GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n";
@@ -1002,7 +994,9 @@ disable_shader_vertex_arrays() {
 ////////////////////////////////////////////////////////////////////
 bool CLP(ShaderContext)::
 update_shader_vertex_arrays(ShaderContext *prev, bool force) {
-  if (prev) prev->disable_shader_vertex_arrays();
+  if (prev) {
+    prev->disable_shader_vertex_arrays();
+  }
   if (!valid()) {
     return true;
   }
@@ -1040,14 +1034,20 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
 
         const GLint p = _glsl_parameter_map[_shader->_var_spec[i]._id._seqno];
         _glgsg->_glEnableVertexAttribArray(p);
-        _glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
-                                    GL_TRUE, stride, client_pointer + start);
+
+        if (numeric_type == GeomEnums::NT_packed_dabc) {
+          _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
+                                         GL_TRUE, stride, client_pointer + start);
+        } else {
+          _glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
+                                         GL_TRUE, stride, client_pointer + start);
+        }
       }
     }
   }
 
   _glgsg->report_my_gl_errors();
-  
+
   return true;
 }
 
@@ -1062,13 +1062,27 @@ disable_shader_texture_bindings() {
     return;
   }
 
-#ifndef OPENGLES_2
-  for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
-    if (_shader->_tex_spec[i]._name == 0) {
-      _glgsg->_glActiveTexture(GL_TEXTURE0 + _shader->_tex_spec[i]._stage);
-    } else {
-      _glgsg->_glActiveTexture(GL_TEXTURE0 + _shader->_tex_spec[i]._stage + _stage_offset);
+  for (int i = 0; i < _shader->_tex_spec.size(); ++i) {
+#ifndef OPENGLES
+    // Check if bindless was used, if so, there's nothing to unbind.
+    if (_glgsg->_supports_bindless_texture) {
+      GLint p = _glsl_parameter_map[_shader->_tex_spec[i]._id._seqno];
+
+      if (_glsl_uniform_handles.count(p) > 0) {
+        continue;
+      }
+    }
+
+    if (_glgsg->_supports_multi_bind) {
+      // There are non-bindless textures to unbind, and we're lazy,
+      // so let's go and unbind everything after this point using one
+      // multi-bind call, and then break out of the loop.
+      _glgsg->_glBindTextures(i, _shader->_tex_spec.size() - i, NULL);
+      break;
     }
+#endif
+
+    _glgsg->_glActiveTexture(GL_TEXTURE0 + i);
 
 #ifndef OPENGLES
     glBindTexture(GL_TEXTURE_1D, 0);
@@ -1087,22 +1101,29 @@ disable_shader_texture_bindings() {
     if (_glgsg->_supports_cube_map) {
       glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
     }
-    // This is probably faster - but maybe not as safe?
-    // cgGLDisableTextureParameter(p);
   }
-#endif  // OPENGLES_2
-  _stage_offset = 0;
 
 #ifndef OPENGLES
   // Now unbind all the image units.  Not sure if we *have* to do this.
   int num_image_units = min(_glsl_img_inputs.size(), (size_t)_glgsg->_max_image_units);
 
-  if (_glgsg->_supports_multi_bind) {
-    _glgsg->_glBindImageTextures(0, num_image_units, NULL);
+  if (num_image_units > 0) {
+    if (_glgsg->_supports_multi_bind) {
+      _glgsg->_glBindImageTextures(0, num_image_units, NULL);
 
-  } else {
-    for (int i = 0; i < num_image_units; ++i) {
-      _glgsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
+    } else {
+      for (int i = 0; i < num_image_units; ++i) {
+        _glgsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
+      }
+    }
+
+    if (gl_enable_memory_barriers) {
+      for (int i = 0; i < num_image_units; ++i) {
+        // We don't distinguish between read-only and read-write/write-only
+        // image access, so we have to assume that the shader wrote to it.
+        _glsl_img_textures[i]->mark_incoherent();
+        _glsl_img_textures[i] = NULL;
+      }
     }
   }
 #endif
@@ -1132,6 +1153,8 @@ update_shader_texture_bindings(ShaderContext *prev) {
   }
 
 #ifndef OPENGLES
+  GLbitfield barriers = 0;
+
   // First bind all the 'image units'; a bit of an esoteric OpenGL feature right now.
   int num_image_units = min(_glsl_img_inputs.size(), (size_t)_glgsg->_max_image_units);
 
@@ -1152,8 +1175,14 @@ update_shader_texture_bindings(ShaderContext *prev) {
 
         CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
         if (gtc != (TextureContext*)NULL) {
+          _glsl_img_textures[i] = gtc;
+
           gl_tex = gtc->_index;
           _glgsg->update_texture(gtc, true);
+
+          if (gtc->needs_barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)) {
+            barriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
+          }
         }
       }
 
@@ -1185,28 +1214,26 @@ update_shader_texture_bindings(ShaderContext *prev) {
   // filtered TextureAttrib in _target_texture.
   const TextureAttrib *texattrib = DCAST(TextureAttrib, _glgsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
   nassertv(texattrib != (TextureAttrib *)NULL);
-  _stage_offset = texattrib->get_num_on_stages();
 
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
-    InternalName *id = _shader->_tex_spec[i]._name;
+    const InternalName *id = _shader->_tex_spec[i]._name;
     int texunit = _shader->_tex_spec[i]._stage;
-    if (id != 0) {
-      texunit += _stage_offset;
-    }
 
-    Texture *tex = 0;
+    Texture *tex = NULL;
     int view = _glgsg->get_current_tex_view_offset();
-    if (id != 0) {
+    if (id != NULL) {
       const ShaderInput *input = _glgsg->_target_shader->get_shader_input(id);
       tex = input->get_texture();
+
     } else {
-      if (_shader->_tex_spec[i]._stage >= texattrib->get_num_on_stages()) {
+      if (texunit >= texattrib->get_num_on_stages()) {
         continue;
       }
-      TextureStage *stage = texattrib->get_on_stage(_shader->_tex_spec[i]._stage);
+      TextureStage *stage = texattrib->get_on_stage(texunit);
       tex = texattrib->get_on_texture(stage);
       view += stage->get_tex_view_offset();
     }
+
     if (_shader->_tex_spec[i]._suffix != 0) {
       // The suffix feature is inefficient. It is a temporary hack.
       if (tex == 0) {
@@ -1218,27 +1245,64 @@ update_shader_texture_bindings(ShaderContext *prev) {
       continue;
     }
 
-    _glgsg->_glActiveTexture(GL_TEXTURE0 + texunit);
-
-    TextureContext *tc = tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg);
-    if (tc == (TextureContext*)NULL) {
+    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
+    if (gtc == NULL) {
       continue;
     }
 
-    GLenum target = _glgsg->get_texture_target(tex->get_texture_type());
-    if (target == GL_NONE) {
-      // Unsupported texture mode.
-      continue;
+    GLint p = _glsl_parameter_map[_shader->_tex_spec[i]._id._seqno];
+
+#ifndef OPENGLES
+    // If it was recently written to, we will have to issue a memory barrier soon.
+    if (gtc->needs_barrier(GL_TEXTURE_FETCH_BARRIER_BIT)) {
+      barriers |= GL_TEXTURE_FETCH_BARRIER_BIT;
     }
 
-    GLint p = _glsl_parameter_map[_shader->_tex_spec[i]._id._seqno];
-    _glgsg->_glUniform1i(p, texunit);
+    // Try bindless texturing first, if supported.
+    if (gl_use_bindless_texture && _glgsg->_supports_bindless_texture) {
+      // We demand the real texture, since we won't be able
+      // to change the texture properties after this point.
+      if (!_glgsg->update_texture(gtc, true)) {
+        continue;
+      }
 
-    if (!_glgsg->update_texture(tc, false)) {
+      GLuint64 handle = gtc->get_handle();
+      if (handle != 0) {
+        gtc->make_handle_resident();
+        gtc->set_active(true);
+
+        // Check if we have already specified this texture handle.
+        // If so, no need to call glUniformHandle again.
+        pmap<GLint, GLuint64>::const_iterator it;
+        it = _glsl_uniform_handles.find(p);
+        if (it != _glsl_uniform_handles.end() && it->second == handle) {
+          // Already specified.
+          continue;
+        } else {
+          _glgsg->_glUniformHandleui64(p, handle);
+          _glsl_uniform_handles[p] = handle;
+        }
+        continue;
+      }
+    }
+#endif
+
+    // Bindless texturing wasn't supported or didn't work, so
+    // let's just bind the texture normally.
+    _glgsg->_glActiveTexture(GL_TEXTURE0 + i);
+    if (!_glgsg->update_texture(gtc, false)) {
       continue;
     }
+    _glgsg->apply_texture(gtc);
   }
 
+#ifndef OPENGLES
+  if (barriers != 0) {
+    // Issue a memory barrier.
+    _glgsg->issue_memory_barrier(barriers);
+  }
+#endif
+
   _glgsg->report_my_gl_errors();
 }
 
@@ -1248,7 +1312,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
 //  Description: This subroutine prints the infolog for a shader.
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
-glsl_report_shader_errors(unsigned int shader) {
+glsl_report_shader_errors(GLuint shader) {
   char *info_log;
   GLint length = 0;
   GLint num_chars  = 0;
@@ -1271,7 +1335,7 @@ glsl_report_shader_errors(unsigned int shader) {
 //  Description: This subroutine prints the infolog for a program.
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
-glsl_report_program_errors(unsigned int program) {
+glsl_report_program_errors(GLuint program) {
   char *info_log;
   GLint length = 0;
   GLint num_chars  = 0;
@@ -1289,13 +1353,13 @@ glsl_report_program_errors(unsigned int program) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Shader::glsl_compile_entry_point
+//     Function: Shader::glsl_compile_shader
 //       Access: Private
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-unsigned int CLP(ShaderContext)::
-glsl_compile_entry_point(Shader::ShaderType type) {
-  unsigned int handle = 0;
+bool CLP(ShaderContext)::
+glsl_compile_shader(Shader::ShaderType type) {
+  GLuint handle = 0;
   switch (type) {
     case Shader::ST_vertex:
       handle = _glgsg->_glCreateShader(GL_VERTEX_SHADER);
@@ -1327,8 +1391,10 @@ glsl_compile_entry_point(Shader::ShaderType type) {
 #endif
   }
   if (!handle) {
+    GLCAT.error()
+      << "Could not create a GLSL shader of the requested type.\n";
     _glgsg->report_my_gl_errors();
-    return 0;
+    return false;
   }
 
   string text_str = _shader->get_text(type);
@@ -1345,79 +1411,68 @@ glsl_compile_entry_point(Shader::ShaderType type) {
     glsl_report_shader_errors(handle);
     _glgsg->_glDeleteShader(handle);
     _glgsg->report_my_gl_errors();
-    return 0;
+    return false;
   }
 
-  return handle;
+  _glgsg->_glAttachShader(_glsl_program, handle);
+  _glsl_shaders.push_back(handle);
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Shader::glsl_compile_shader
+//     Function: Shader::glsl_compile_and_link
 //       Access: Private
 //  Description: This subroutine compiles a GLSL shader.
 ////////////////////////////////////////////////////////////////////
 bool CLP(ShaderContext)::
-glsl_compile_shader() {
+glsl_compile_and_link() {
+  _glsl_shaders.clear();
   _glsl_program = _glgsg->_glCreateProgram();
-  if (!_glsl_program) return false;
+  if (!_glsl_program) {
+    return false;
+  }
+  bool valid = true;
 
   if (!_shader->get_text(Shader::ST_vertex).empty()) {
-    _glsl_vshader = glsl_compile_entry_point(Shader::ST_vertex);
-    if (!_glsl_vshader) return false;
-    _glgsg->_glAttachShader(_glsl_program, _glsl_vshader);
+    valid &= glsl_compile_shader(Shader::ST_vertex);
   }
 
   if (!_shader->get_text(Shader::ST_fragment).empty()) {
-    _glsl_fshader = glsl_compile_entry_point(Shader::ST_fragment);
-    if (!_glsl_fshader) return false;
-    _glgsg->_glAttachShader(_glsl_program, _glsl_fshader);
+    valid &= glsl_compile_shader(Shader::ST_fragment);
   }
 
-  if (!_shader->get_text(Shader::ST_geometry).empty()) {
-    _glsl_gshader = glsl_compile_entry_point(Shader::ST_geometry);
-    if (!_glsl_gshader) return false;
-    _glgsg->_glAttachShader(_glsl_program, _glsl_gshader);
-
 #ifdef OPENGLES
     nassertr(false, false); // OpenGL ES has no geometry shaders.
 #else
-    // Set the vertex output limit to the maximum
+  if (!_shader->get_text(Shader::ST_geometry).empty()) {
+    valid &= glsl_compile_shader(Shader::ST_geometry);
+
+    // Set the vertex output limit to the maximum.
+    // This is slow, but it is probably reasonable to require
+    // the user to override this in his shader using layout().
     nassertr(_glgsg->_glProgramParameteri != NULL, false);
     GLint max_vertices;
     glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &max_vertices);
     _glgsg->_glProgramParameteri(_glsl_program, GL_GEOMETRY_VERTICES_OUT_ARB, max_vertices); 
-#endif
   }
+#endif
 
   if (!_shader->get_text(Shader::ST_tess_control).empty()) {
-    _glsl_tcshader = glsl_compile_entry_point(Shader::ST_tess_control);
-    if (!_glsl_tcshader) return false;
-    _glgsg->_glAttachShader(_glsl_program, _glsl_tcshader);
+    valid &= glsl_compile_shader(Shader::ST_tess_control);
   }
 
   if (!_shader->get_text(Shader::ST_tess_evaluation).empty()) {
-    _glsl_teshader = glsl_compile_entry_point(Shader::ST_tess_evaluation);
-    if (!_glsl_teshader) return false;
-    _glgsg->_glAttachShader(_glsl_program, _glsl_teshader);
+    valid &= glsl_compile_shader(Shader::ST_tess_evaluation);
   }
 
   if (!_shader->get_text(Shader::ST_compute).empty()) {
-    _glsl_cshader = glsl_compile_entry_point(Shader::ST_compute);
-    if (!_glsl_cshader) return false;
-    _glgsg->_glAttachShader(_glsl_program, _glsl_cshader);
+    valid &= glsl_compile_shader(Shader::ST_compute);
   }
 
-  // There might be warnings. Only report them for one shader program.
-  if (_glsl_vshader != 0) {
-    glsl_report_shader_errors(_glsl_vshader);
-  } else if (_glsl_fshader != 0) {
-    glsl_report_shader_errors(_glsl_fshader);
-  } else if (_glsl_gshader != 0) {
-    glsl_report_shader_errors(_glsl_gshader);
-  } else if (_glsl_tcshader != 0) {
-    glsl_report_shader_errors(_glsl_tcshader);
-  } else if (_glsl_teshader != 0) {
-    glsl_report_shader_errors(_glsl_teshader);
+  // There might be warnings, so report those.
+  GLSLShaders::const_iterator it;
+  for (it = _glsl_shaders.begin(); it != _glsl_shaders.end(); ++it) {
+    glsl_report_shader_errors(*it);
   }
 
   // If we requested to retrieve the shader, we should indicate that before linking.
@@ -1454,7 +1509,7 @@ glsl_compile_shader() {
     _glgsg->_glGetProgramBinary(_glsl_program, length, &num_bytes, &format, (void*)binary);
 
     pofstream s;
-    s.open(filename, ios::out | ios::binary);
+    s.open(filename, ios::out | ios::binary | ios::trunc);
     s.write(binary, num_bytes);
     s.close();
 

+ 20 - 13
panda/src/glstuff/glShaderContext_src.h

@@ -50,26 +50,33 @@ public:
 
 private:
   GLuint _glsl_program;
-  GLuint _glsl_vshader;
-  GLuint _glsl_fshader;
-  GLuint _glsl_gshader;
-  GLuint _glsl_tcshader;
-  GLuint _glsl_teshader;
-  GLuint _glsl_cshader;
-
-  pvector <GLint> _glsl_parameter_map;
+  typedef pvector<GLuint> GLSLShaders;
+  GLSLShaders _glsl_shaders;
+
+  //struct ParamContext {
+  //  CPT(InternalName) _name;
+  //  GLint _location;
+  //  GLsizei _count;
+  //  WPT(ParamValue) _value;
+  //  UpdateSeq _updated;
+  //};
+  //typedef pvector<ParamContext> ParamContexts;
+  //ParamContexts _params;
+
+  pvector<GLint> _glsl_parameter_map;
+  pmap<GLint, GLuint64> _glsl_uniform_handles;
 
   pvector<CPT(InternalName)> _glsl_img_inputs;
+  pvector<CLP(TextureContext)*> _glsl_img_textures;
 
-  int _stage_offset;
   CLP(GraphicsStateGuardian) *_glgsg;
 
   bool _uses_standard_vertex_arrays;
 
-  void glsl_report_shader_errors(unsigned int shader);
-  void glsl_report_program_errors(unsigned int program);
-  unsigned int glsl_compile_entry_point(Shader::ShaderType type);
-  bool glsl_compile_shader();
+  void glsl_report_shader_errors(GLuint shader);
+  void glsl_report_program_errors(GLuint program);
+  bool glsl_compile_shader(Shader::ShaderType type);
+  bool glsl_compile_and_link();
   bool parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *s);
   void release_resources();
 

+ 11 - 3
panda/src/glstuff/glTextureContext_src.I

@@ -19,12 +19,20 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(TextureContext)::
-CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
+CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
+  PreparedGraphicsObjects *pgo, Texture *tex, int view) :
   TextureContext(pgo, tex, view)
 {
-  _index = 0;
-  _already_applied = false;
+  _glgsg = glgsg;
+
+  glGenTextures(1, &_index);
+
+  _handle = 0;
+  _needs_barrier = false;
+  _has_storage = false;
+  _immutable = false;
   _uses_mipmaps = false;
+  _generate_mipmaps = false;
   _internal_format = 0;
   _width = 0;
   _height = 0;

+ 129 - 2
panda/src/glstuff/glTextureContext_src.cxx

@@ -16,6 +16,23 @@
 
 TypeHandle CLP(TextureContext)::_type_handle;
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(TextureContext)::Denstructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CLP(TextureContext)::
+~CLP(TextureContext)() {
+  if (gl_enable_memory_barriers) {
+    _glgsg->_textures_needing_fetch_barrier.erase(this);
+    _glgsg->_textures_needing_image_access_barrier.erase(this);
+    _glgsg->_textures_needing_update_barrier.erase(this);
+    _glgsg->_textures_needing_framebuffer_barrier.erase(this);
+  }
+
+  glDeleteTextures(1, &_index);
+  _index = 0;
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GLTextureContext::evict_lru
@@ -35,7 +52,16 @@ TypeHandle CLP(TextureContext)::_type_handle;
 void CLP(TextureContext)::
 evict_lru() {
   dequeue_lru();
-  reset_data();
+
+  if (_handle != 0) {
+    if (_handle_resident) {
+      _glgsg->_glMakeTextureHandleNonResident(_handle);
+    }
+    _handle_resident = false;
+  } else {
+    reset_data();
+  }
+
   update_data_size_bytes(0);
   mark_unloaded();
 }
@@ -48,6 +74,10 @@ evict_lru() {
 ////////////////////////////////////////////////////////////////////
 void CLP(TextureContext)::
 reset_data() {
+  if (_handle != 0 && _handle_resident) {
+    _glgsg->_glMakeTextureHandleNonResident(_handle);
+  }
+
   // Free the texture resources.
   glDeleteTextures(1, &_index);
 
@@ -55,5 +85,102 @@ reset_data() {
   // re-load the texture later.
   glGenTextures(1, &_index);
 
-  _already_applied = false;
+  _handle = 0;
+  _handle_resident = false;
+  _needs_barrier = false;
+  _has_storage = false;
+  _immutable = false;
+
+#ifndef OPENGLES
+  // Mark the texture as coherent.
+  if (gl_enable_memory_barriers) {
+    _glgsg->_textures_needing_fetch_barrier.erase(this);
+    _glgsg->_textures_needing_image_access_barrier.erase(this);
+    _glgsg->_textures_needing_update_barrier.erase(this);
+    _glgsg->_textures_needing_framebuffer_barrier.erase(this);
+  }
+#endif
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLTextureContext::make_handle_resident
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void CLP(TextureContext)::
+make_handle_resident() {
+  if (_handle != 0) {
+    if (!_handle_resident) {
+      _glgsg->_glMakeTextureHandleResident(_handle);
+      _handle_resident = true;
+    }
+    set_resident(true);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(TextureContext)::get_handle
+//       Access: Public
+//  Description: Returns a handle for this texture.  Once this has
+//               been created, the texture data may still be updated,
+//               but its properties may not.
+////////////////////////////////////////////////////////////////////
+INLINE GLuint64 CLP(TextureContext)::
+get_handle() {
+#ifdef OPENGLES
+  return 0;
+#else
+  if (!_glgsg->_supports_bindless_texture) {
+    return false;
+  }
+
+  if (_handle == 0) {
+    _handle = _glgsg->_glGetTextureHandle(_index);
+  }
+
+  _immutable = true;
+  return _handle;
+#endif
+}
+
+#ifndef OPENGLES
+////////////////////////////////////////////////////////////////////
+//     Function: GLTextureContext::needs_barrier
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+bool CLP(TextureContext)::
+needs_barrier(GLbitfield barrier) {
+  if (!gl_enable_memory_barriers) {
+    return false;
+  }
+
+  return (((barrier & GL_TEXTURE_FETCH_BARRIER_BIT) &&
+           _glgsg->_textures_needing_fetch_barrier.count(this)))
+      || (((barrier & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) &&
+           _glgsg->_textures_needing_image_access_barrier.count(this)))
+      || (((barrier & GL_TEXTURE_UPDATE_BARRIER_BIT) &&
+           _glgsg->_textures_needing_update_barrier.count(this)))
+      || (((barrier & GL_FRAMEBUFFER_BARRIER_BIT) &&
+           _glgsg->_textures_needing_framebuffer_barrier.count(this)));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLTextureContext::mark_incoherent
+//       Access: Public
+//  Description: Mark a texture as needing a memory barrier, since
+//               a non-coherent write just happened to it.
+////////////////////////////////////////////////////////////////////
+void CLP(TextureContext)::
+mark_incoherent() {
+  if (!gl_enable_memory_barriers) {
+    return;
+  }
+
+  _glgsg->_textures_needing_fetch_barrier.insert(this);
+  _glgsg->_textures_needing_image_access_barrier.insert(this);
+  _glgsg->_textures_needing_update_barrier.insert(this);
+  _glgsg->_textures_needing_framebuffer_barrier.insert(this);
+}
+
+#endif // OPENGLES

+ 32 - 4
panda/src/glstuff/glTextureContext_src.h

@@ -16,32 +16,60 @@
 #include "textureContext.h"
 #include "deletedChain.h"
 
+class CLP(GraphicsStateGuardian);
+
 ////////////////////////////////////////////////////////////////////
 //       Class : GLTextureContext
 // Description :
 ////////////////////////////////////////////////////////////////////
 class EXPCL_GL CLP(TextureContext) : public TextureContext {
 public:
-  INLINE CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex, int view);
+  INLINE CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
+                             PreparedGraphicsObjects *pgo,
+                             Texture *tex, int view);
   ALLOC_DELETED_CHAIN(CLP(TextureContext));
 
+  virtual ~CLP(TextureContext)();
   virtual void evict_lru();
   void reset_data();
 
+  void make_handle_resident();
+  GLuint64 get_handle();
+
+#ifdef OPENGLES
+  CONSTEXPR bool needs_barrier(GLbitfield barrier) { return false; };
+#else
+  bool needs_barrier(GLbitfield barrier);
+  void mark_incoherent();
+#endif
+
   // This is the GL "name" of the texture object.
   GLuint _index;
 
+  // This is the bindless "handle" to the texture object.
+  GLuint64 _handle;
+  bool _handle_resident;
+
+  // This is true if the texture was recently written to in a
+  // non-coherent way, and Panda may have to call glMemoryBarrier
+  // for the results of this write to become visible.
+  bool _needs_barrier;
+
   // These are the parameters that we specified with the last
-  // glTexImage2D() call.  If none of these have changed, we can
-  // reload the texture image with a glTexSubImage2D().
-  bool _already_applied;
+  // glTexImage2D() or glTexStorage2D() call.  If none of these have
+  // changed, we can reload the texture image with a glTexSubImage2D().
+  bool _has_storage;
+  bool _immutable;
   bool _uses_mipmaps;
+  bool _generate_mipmaps;
   GLint _internal_format;
   GLsizei _width;
   GLsizei _height;
   GLsizei _depth;
   GLenum _target;
 
+  CLP(GraphicsStateGuardian) *_glgsg;
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 28 - 0
panda/src/glstuff/glmisc_src.cxx

@@ -208,6 +208,34 @@ ConfigVariableBool gl_dump_compiled_shaders
             "programs to disk with a filename like glsl_program0.dump "
             "into the current directory."));
 
+ConfigVariableBool gl_immutable_texture_storage
+  ("gl-immutable-texture-storage", true,
+   PRC_DESC("This configures Panda to pre-allocate immutable storage "
+            "for each texture.  This improves runtime performance, but "
+            "changing the size or type of a texture will be slower."));
+
+ConfigVariableBool gl_use_bindless_texture
+  ("gl-use-bindless-texture", false,
+   PRC_DESC("Set this to let Panda use OpenGL's bindless texture "
+            "extension for all textures passed to shaders, for improved "
+            "performance.  This is an experimental feature and comes "
+            "with a few caveats; for one, it requires that all sampler "
+            "uniforms have a layout(bindless_sampler) qualifier, and "
+            "it also requires that the texture properties are not "
+            "modified after the texture handle has been initialized."));
+
+ConfigVariableBool gl_enable_memory_barriers
+  ("gl-enable-memory-barriers", true,
+   PRC_DESC("If this is set, Panda will make sure that every write "
+            "to an image using an image2D (et al) binding will cause "
+            "Panda to issue a memory barrier before the next use of "
+            "said texture, to ensure that all reads and writes are "
+            "properly synchronized.  This may not be strictly necessary "
+            "when using the 'coherent' qualifier, but Panda has no "
+            "way to detect whether you are using those.  Turning "
+            "this off may give a slight performance increase, but you "
+            "have to know what you're doing."));
+
 extern ConfigVariableBool gl_parallel_arrays;
 
 void CLP(init_classes)() {

+ 3 - 0
panda/src/glstuff/glmisc_src.h

@@ -67,6 +67,9 @@ extern ConfigVariableBool gl_force_flush;
 extern ConfigVariableBool gl_separate_specular_color;
 extern ConfigVariableBool gl_cube_map_seamless;
 extern ConfigVariableBool gl_dump_compiled_shaders;
+extern ConfigVariableBool gl_immutable_texture_storage;
+extern ConfigVariableBool gl_use_bindless_texture;
+extern ConfigVariableBool gl_enable_memory_barriers;
 
 extern EXPCL_GL void CLP(init_classes)();
 

Some files were not shown because too many files changed in this diff