Browse Source

texture optimizations

David Rose 21 years ago
parent
commit
ec83e7f9c6

+ 1 - 5
panda/src/display/graphicsBuffer.cxx

@@ -43,11 +43,7 @@ GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
   }
   }
 
 
   if (want_texture) {
   if (want_texture) {
-    _texture = new Texture();
-    _texture->set_name(_name);
-    _texture->set_wrapu(Texture::WM_clamp);
-    _texture->set_wrapv(Texture::WM_clamp);
-    _copy_texture = true;
+    setup_copy_texture(_name);
   }
   }
 
 
   _x_size = x_size;
   _x_size = x_size;

+ 2 - 9
panda/src/display/graphicsEngine.cxx

@@ -256,11 +256,7 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name,
       window->request_properties(props);
       window->request_properties(props);
 
 
       if (want_texture) {
       if (want_texture) {
-        window->_texture = new Texture();
-        window->_texture->set_name(name);
-        window->_texture->set_wrapu(Texture::WM_clamp);
-        window->_texture->set_wrapv(Texture::WM_clamp);
-        window->_copy_texture = true;
+        window->setup_copy_texture(name);
       }
       }
 
 
       return window;
       return window;
@@ -309,10 +305,7 @@ make_parasite(GraphicsOutput *host, const string &name,
       props.set_fixed_size(true);
       props.set_fixed_size(true);
       props.set_title(name);
       props.set_title(name);
       window->request_properties(props);
       window->request_properties(props);
-
-      window->_texture = new Texture();
-      window->_texture->set_name(name);
-      window->_copy_texture = true;
+      window->setup_copy_texture(name);
 
 
       return window;
       return window;
     }
     }

+ 37 - 0
panda/src/display/graphicsOutput.cxx

@@ -686,6 +686,43 @@ declare_channel(int index, GraphicsChannel *chan) {
   _channels[index] = chan;
   _channels[index] = chan;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsOutput::setup_copy_texture
+//       Access: Protected
+//  Description: Creates a new Texture object, suitable for copying
+//               the contents of this buffer into, and stores it in
+//               _texture.
+////////////////////////////////////////////////////////////////////
+void GraphicsOutput::
+setup_copy_texture(const string &name) {
+  _texture = new Texture();
+  _texture->set_name(name);
+  _texture->set_wrapu(Texture::WM_clamp);
+  _texture->set_wrapv(Texture::WM_clamp);
+
+  // We should match the texture format up with the framebuffer
+  // format.  Easier said than done!
+  if (_gsg != (GraphicsStateGuardian *)NULL) {
+    int mode = _gsg->get_properties().get_frame_buffer_mode();
+    PixelBuffer *pb = _texture->_pbuffer;
+
+    if (mode & FrameBufferProperties::FM_alpha) {
+      pb->set_format(PixelBuffer::F_rgba8);
+      pb->set_num_components(4);
+      pb->set_component_width(1);
+      pb->set_image_type(PixelBuffer::T_unsigned_byte);
+
+    } else {
+      pb->set_format(PixelBuffer::F_rgb8);
+      pb->set_num_components(3);
+      pb->set_component_width(1);
+      pb->set_image_type(PixelBuffer::T_unsigned_byte);
+    }
+  }
+
+  _copy_texture = true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsOutput::do_determine_display_regions
 //     Function: GraphicsOutput::do_determine_display_regions
 //       Access: Private
 //       Access: Private

+ 1 - 0
panda/src/display/graphicsOutput.h

@@ -145,6 +145,7 @@ public:
 
 
 protected:
 protected:
   void declare_channel(int index, GraphicsChannel *chan);
   void declare_channel(int index, GraphicsChannel *chan);
+  void setup_copy_texture(const string &name);
   
   
 protected:
 protected:
   PT(GraphicsStateGuardian) _gsg;
   PT(GraphicsStateGuardian) _gsg;

+ 1 - 5
panda/src/display/parasiteBuffer.cxx

@@ -44,11 +44,7 @@ ParasiteBuffer(GraphicsOutput *host, const string &name,
       << " on " << _host->get_name() << "\n";
       << " on " << _host->get_name() << "\n";
   }
   }
 
 
-  _texture = new Texture();
-  _texture->set_name(_name);
-  _texture->set_wrapu(Texture::WM_clamp);
-  _texture->set_wrapv(Texture::WM_clamp);
-  _copy_texture = true;
+  setup_copy_texture(_name);
 
 
   _x_size = x_size;
   _x_size = x_size;
   _y_size = y_size;
   _y_size = y_size;

+ 113 - 53
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -302,6 +302,8 @@ reset() {
 
 
   _supports_bgr = has_extension("GL_EXT_bgra");
   _supports_bgr = has_extension("GL_EXT_bgra");
   _supports_multisample = has_extension("GL_ARB_multisample");
   _supports_multisample = has_extension("GL_ARB_multisample");
+  _supports_generate_mipmap = 
+    has_extension("GL_SGIS_generate_mipmap") || is_at_least_version(1, 4);
 
 
   _supports_multitexture = false;
   _supports_multitexture = false;
     
     
@@ -1824,13 +1826,11 @@ TextureContext *CLP(GraphicsStateGuardian)::
 prepare_texture(Texture *tex) {
 prepare_texture(Texture *tex) {
   CLP(TextureContext) *gtc = new CLP(TextureContext)(tex);
   CLP(TextureContext) *gtc = new CLP(TextureContext)(tex);
   GLP(GenTextures)(1, &gtc->_index);
   GLP(GenTextures)(1, &gtc->_index);
-  //cerr << "preparing texture " << tex->get_name() << ", assigning "
-  //     << gtc->_index << "\n";
 
 
   bind_texture(gtc);
   bind_texture(gtc);
   GLP(PrioritizeTextures)(1, &gtc->_index, &gtc->_priority);
   GLP(PrioritizeTextures)(1, &gtc->_index, &gtc->_priority);
   specify_texture(tex);
   specify_texture(tex);
-  apply_texture_immediate(tex);
+  apply_texture_immediate(gtc, tex);
 
 
   report_my_gl_errors();
   report_my_gl_errors();
   return gtc;
   return gtc;
@@ -1844,20 +1844,22 @@ prepare_texture(Texture *tex) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 apply_texture(TextureContext *tc) {
 apply_texture(TextureContext *tc) {
-  add_to_texture_record(tc);
-  bind_texture(tc);
+  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+
+  add_to_texture_record(gtc);
+  bind_texture(gtc);
 
 
-  int dirty = tc->get_dirty_flags();
+  int dirty = gtc->get_dirty_flags();
   if ((dirty & (Texture::DF_wrap | Texture::DF_filter)) != 0) {
   if ((dirty & (Texture::DF_wrap | Texture::DF_filter)) != 0) {
     // We need to re-specify the texture properties.
     // We need to re-specify the texture properties.
-    specify_texture(tc->_texture);
+    specify_texture(gtc->_texture);
   }
   }
   if ((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
   if ((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
     // We need to re-apply the image.
     // We need to re-apply the image.
-    apply_texture_immediate(tc->_texture);
+    apply_texture_immediate(gtc, gtc->_texture);
   }
   }
 
 
-  tc->clear_dirty_flags();
+  gtc->clear_dirty_flags();
 
 
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
@@ -3201,21 +3203,28 @@ bind_texture(TextureContext *tc) {
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 specify_texture(Texture *tex) {
 specify_texture(Texture *tex) {
   GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
   GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
-                  get_texture_wrap_mode(tex->get_wrapu()));
+                     get_texture_wrap_mode(tex->get_wrapu()));
   GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
   GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
-                  get_texture_wrap_mode(tex->get_wrapv()));
+                     get_texture_wrap_mode(tex->get_wrapv()));
 
 
-  if (CLP(force_mipmaps)) {
-    GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-                    GL_LINEAR_MIPMAP_LINEAR);
-    GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  Texture::FilterType minfilter = tex->get_minfilter();
+  Texture::FilterType magfilter = tex->get_magfilter();
 
 
-  } else {
-    GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-                    get_texture_filter_type(tex->get_minfilter()));
-    GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-                    get_texture_filter_type(tex->get_magfilter()));
+  bool uses_mipmaps = tex->uses_mipmaps();
+
+#ifndef NDEBUG
+  if (CLP(force_mipmaps)) {
+    minfilter = Texture::FT_linear_mipmap_linear;
+    magfilter = Texture::FT_linear;
+    uses_mipmaps = true;
   }
   }
+#endif
+ 
+  GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                     get_texture_filter_type(tex->get_minfilter()));
+  GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+                     get_texture_filter_type(tex->get_magfilter()));
+
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
@@ -3292,20 +3301,22 @@ compute_gl_image_size(int xsize, int ysize, int external_format, int type) {
 //               the texture has no image.
 //               the texture has no image.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 bool CLP(GraphicsStateGuardian)::
-apply_texture_immediate(Texture *tex) {
+apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex) {
   PixelBuffer *pb = tex->get_ram_image();
   PixelBuffer *pb = tex->get_ram_image();
   if (pb == (PixelBuffer *)NULL) {
   if (pb == (PixelBuffer *)NULL) {
     return false;
     return false;
   }
   }
 
 
-  int xsize = pb->get_xsize();
-  int ysize = pb->get_ysize();
+  int width = pb->get_xsize();
+  int height = pb->get_ysize();
 
 
-  GLenum internal_format = get_internal_image_format(pb->get_format());
-  GLenum external_format = get_external_image_format(pb->get_format());
+  GLint internal_format = get_internal_image_format(pb->get_format());
+  GLint external_format = get_external_image_format(pb->get_format());
   GLenum type = get_image_type(pb->get_image_type());
   GLenum type = get_image_type(pb->get_image_type());
 
 
   PTA_uchar image = pb->_image;
   PTA_uchar image = pb->_image;
+  nassertr(!image.empty(), false);
+
   if (!_supports_bgr) {
   if (!_supports_bgr) {
     // If the GL doesn't claim to support BGR, we may have to reverse
     // If the GL doesn't claim to support BGR, we may have to reverse
     // the component ordering of the image.
     // the component ordering of the image.
@@ -3314,7 +3325,7 @@ apply_texture_immediate(Texture *tex) {
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
   int wanted_size = 
   int wanted_size = 
-    compute_gl_image_size(xsize, ysize, external_format, type);
+    compute_gl_image_size(width, height, external_format, type);
   nassertr(wanted_size == (int)pb->_image.size(), false);
   nassertr(wanted_size == (int)pb->_image.size(), false);
 #endif  // NDEBUG
 #endif  // NDEBUG
 
 
@@ -3324,46 +3335,95 @@ apply_texture_immediate(Texture *tex) {
   GLCAT.debug()
   GLCAT.debug()
     << "glTexImage2D(GL_TEXTURE_2D, "
     << "glTexImage2D(GL_TEXTURE_2D, "
     << (int)internal_format << ", "
     << (int)internal_format << ", "
-    << xsize << ", " << ysize << ", "
+    << width << ", " << height << ", "
     << pb->get_border() << ", " << (int)external_format << ", "
     << pb->get_border() << ", " << (int)external_format << ", "
     << (int)type << ", " << tex->get_name() << ")\n";
     << (int)type << ", " << tex->get_name() << ")\n";
 #endif
 #endif
 
 
-  if (!CLP(ignore_mipmaps) || CLP(force_mipmaps)) {
-    if (tex->uses_mipmaps() || CLP(force_mipmaps)) {
+  bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
+
 #ifndef NDEBUG
 #ifndef NDEBUG
-      if (CLP(show_mipmaps)) {
-        build_phony_mipmaps(tex);
-      } else 
+  if (CLP(force_mipmaps)) {
+    uses_mipmaps = true;
+  }
 #endif
 #endif
-        {
-          GLUP(Build2DMipmaps)(GL_TEXTURE_2D, internal_format,
-                            xsize, ysize,
-                            external_format, type, image);
+
+  if (uses_mipmaps) {
 #ifndef NDEBUG
 #ifndef NDEBUG
-          if (CLP(save_mipmaps)) {
-            save_mipmap_images(tex);
-          }
-#endif
-        }
+    if (CLP(show_mipmaps)) {
+      build_phony_mipmaps(tex);
       report_my_gl_errors();
       report_my_gl_errors();
-
       return true;
       return true;
+      
+    } else 
+#endif 
+      if (_supports_generate_mipmap) {
+        GLP(TexParameteri)(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+
+      } else {
+        // We only need to build the mipmaps by hand if the GL
+        // doesn't support generating them automatically.
+        GLUP(Build2DMipmaps)(GL_TEXTURE_2D, internal_format,
+                             width, height,
+                             external_format, type, image);
+        
+        gtc->_already_applied = false;
+        gtc->_internal_format = internal_format;
+        gtc->_width = width;
+        gtc->_height = height;
+        gtc->_border = 0;
+        
+#ifndef NDEBUG
+        if (CLP(save_mipmaps)) {
+          save_mipmap_images(tex);
+        }
+#endif
+        report_my_gl_errors();
+        return true;
+      }
+  } else {
+    if (_supports_generate_mipmap) {
+      GLP(TexParameteri)(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
     }
     }
   }
   }
 
 
-  nassertr(!pb->_image.empty(), false);
-  GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
-               xsize, ysize, pb->get_border(),
-               external_format, type, image);
+  GLint border = pb->get_border();
+
+  if (!gtc->_already_applied || 
+      gtc->_internal_format != internal_format ||
+      gtc->_width != width ||
+      gtc->_height != height ||
+      gtc->_border != border) {
+    // We need to reload a new image.
+    GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format,
+                    width, height, pb->get_border(),
+                    external_format, type, image);
+    gtc->_already_applied = true;
+    gtc->_internal_format = internal_format;
+    gtc->_width = width;
+    gtc->_height = height;
+    gtc->_border = border;
+
+  } else {
+    // We can reload the image over the previous image, saving on
+    // texture memory fragmentation.
+    GLP(TexSubImage2D)(GL_TEXTURE_2D, 0, 0, 0, width, height,
+                       external_format, type, image);
+  }
 
 
   //report_my_gl_errors();
   //report_my_gl_errors();
   // want to give explict error for texture creation failure
   // want to give explict error for texture creation failure
   GLenum error_code = GLP(GetError)();
   GLenum error_code = GLP(GetError)();
-  if(error_code != GL_NO_ERROR) {
+  if (error_code != GL_NO_ERROR) {
     const GLubyte *error_string = GLUP(ErrorString)(error_code);
     const GLubyte *error_string = GLUP(ErrorString)(error_code);
-    GLCAT.error() << "GL texture creation failed for " << tex->get_name() << 
-                        ((error_string != (const GLubyte *)NULL) ? " : " : "") << endl;
+    GLCAT.error()
+      << "GL texture creation failed for " << tex->get_name();
+    if (error_string != (const GLubyte *)NULL) {
+      GLCAT.error(false)
+        << " : " << error_string;
+    }
+    GLCAT.error(false)
+      << "\n";
   }
   }
 
 
   return true;
   return true;
@@ -3696,7 +3756,7 @@ get_image_type(PixelBuffer::Type type) {
 //  Description: Maps from the PixelBuffer's Format symbols
 //  Description: Maps from the PixelBuffer's Format symbols
 //               to GL's.
 //               to GL's.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLenum CLP(GraphicsStateGuardian)::
+GLint CLP(GraphicsStateGuardian)::
 get_external_image_format(PixelBuffer::Format format) {
 get_external_image_format(PixelBuffer::Format format) {
   switch (format) {
   switch (format) {
   case PixelBuffer::F_color_index:
   case PixelBuffer::F_color_index:
@@ -3744,7 +3804,7 @@ get_external_image_format(PixelBuffer::Format format) {
 //  Description: Maps from the PixelBuffer's Format symbols to a
 //  Description: Maps from the PixelBuffer's Format symbols to a
 //               suitable internal format for GL textures.
 //               suitable internal format for GL textures.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLenum CLP(GraphicsStateGuardian)::
+GLint CLP(GraphicsStateGuardian)::
 get_internal_image_format(PixelBuffer::Format format) {
 get_internal_image_format(PixelBuffer::Format format) {
   switch (format) {
   switch (format) {
   case PixelBuffer::F_rgba:
   case PixelBuffer::F_rgba:
@@ -4621,8 +4681,8 @@ build_phony_mipmap_level(int level, int xsize, int ysize) {
   GLenum type = get_image_type(pb->get_image_type());
   GLenum type = get_image_type(pb->get_image_type());
 
 
   GLP(TexImage2D)(GL_TEXTURE_2D, level, internal_format,
   GLP(TexImage2D)(GL_TEXTURE_2D, level, internal_format,
-               pb->get_xsize(), pb->get_ysize(), pb->get_border(),
-               external_format, type, pb->_image );
+                  pb->get_xsize(), pb->get_ysize(), pb->get_border(),
+                  external_format, type, pb->_image );
 
 
   delete pb;
   delete pb;
 }
 }

+ 4 - 3
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -222,7 +222,7 @@ protected:
 
 
   void bind_texture(TextureContext *tc);
   void bind_texture(TextureContext *tc);
   void specify_texture(Texture *tex);
   void specify_texture(Texture *tex);
-  bool apply_texture_immediate(Texture *tex);
+  bool apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex);
 
 
   void draw_texture(TextureContext *tc, const DisplayRegion *dr);
   void draw_texture(TextureContext *tc, const DisplayRegion *dr);
   void draw_texture(TextureContext *tc, const DisplayRegion *dr, 
   void draw_texture(TextureContext *tc, const DisplayRegion *dr, 
@@ -234,8 +234,8 @@ protected:
   GLenum get_texture_wrap_mode(Texture::WrapMode wm);
   GLenum get_texture_wrap_mode(Texture::WrapMode wm);
   GLenum get_texture_filter_type(Texture::FilterType ft);
   GLenum get_texture_filter_type(Texture::FilterType ft);
   GLenum get_image_type(PixelBuffer::Type type);
   GLenum get_image_type(PixelBuffer::Type type);
-  GLenum get_external_image_format(PixelBuffer::Format format);
-  GLenum get_internal_image_format(PixelBuffer::Format format);
+  GLint get_external_image_format(PixelBuffer::Format format);
+  GLint get_internal_image_format(PixelBuffer::Format format);
   GLint get_texture_apply_mode_type(TextureStage::Mode am) const;
   GLint get_texture_apply_mode_type(TextureStage::Mode am) const;
   GLint get_texture_combine_type(TextureStage::CombineMode cm) const;
   GLint get_texture_combine_type(TextureStage::CombineMode cm) const;
   GLint get_texture_src_type(TextureStage::CombineSource cs) const;
   GLint get_texture_src_type(TextureStage::CombineSource cs) const;
@@ -330,6 +330,7 @@ protected:
 public:
 public:
   bool _supports_bgr;
   bool _supports_bgr;
   bool _supports_multisample;
   bool _supports_multisample;
+  bool _supports_generate_mipmap;
 
 
   bool _supports_multitexture;
   bool _supports_multitexture;
   PFNGLACTIVETEXTUREPROC _glActiveTexture;
   PFNGLACTIVETEXTUREPROC _glActiveTexture;

+ 2 - 0
panda/src/glstuff/glTextureContext_src.I

@@ -28,4 +28,6 @@ CLP(TextureContext)(Texture *tex) :
 {
 {
   _index = 0;
   _index = 0;
   _priority = 0.5; // For keeping resident in texture memory
   _priority = 0.5; // For keeping resident in texture memory
+
+  _already_applied = false;
 }
 }

+ 9 - 0
panda/src/glstuff/glTextureContext_src.h

@@ -33,6 +33,15 @@ public:
   // This is a GL texture priority.
   // This is a GL texture priority.
   GLfloat _priority;
   GLfloat _priority;
 
 
+  // 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;
+  GLint _internal_format;
+  GLsizei _width;
+  GLsizei _height;
+  GLint _border;
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;