Browse Source

(multiview) texture preparation changes:

Multiview textures are now handled as a single texture context instead of as one texture context per view. This should be marginally more efficient, but more importantly, it paves the way for implementing multiview textures as subviews of an array texture down the line, which paves the way for hardware-accelerated stereo rendering (where the left and right views get rendered simultaneously to different layers of an array texture).

The difference between a multiview texture done this way and an array texture is that the views of a multiview texture will still be treated as individual textures from the shader's point of view, only the views will be sharing the same storage on the GPU.  This can be done by using a feature offered by graphics APIs that is (serendipitously) also called "texture views", where it's possible to create multiple texture objects that point to layer ranges of a bigger array texture.

That part has not yet been done as doing this in OpenGL will be a little tricky due to texture views being an optional feature (so both paths would need to be implemented), but texture views are native in Vulkan (and D3D10+ for that matter), so doing this now allows me to implement multiview textures natively on the Vulkan end right from the start, and OpenGL can follow later if desired.

Furthermore, this commit includes:
- OpenGL: Overhaul texture creation and binding
- OpenGL: Change how reloading a texture with mipmaps works
- OpenGL: Use DSA in a couple of places
- OpenGL ES: Add support for buffer textures
- OpenGL: Remove support for bindless textures for now; this was never implemented in a very useful way, not used to my knowledge, and it is better to re-implement it later after the new shader pipeline lands
- DirectX9: All views of a texture are uploaded at the same time
- TinyDisplay: Support multiview textures natively (consecutive storage in memory)
- General: Per-page texture update tracking is working properly now for multiview textures
rdb 2 years ago
parent
commit
07f9f9d897
38 changed files with 1457 additions and 1269 deletions
  1. 1 1
      panda/src/display/graphicsStateGuardian.cxx
  2. 1 1
      panda/src/display/graphicsStateGuardian.h
  3. 15 24
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  4. 2 2
      panda/src/dxgsg9/dxGraphicsStateGuardian9.h
  5. 2 2
      panda/src/dxgsg9/dxShaderContext9.cxx
  6. 9 8
      panda/src/dxgsg9/dxTextureContext9.I
  7. 394 338
      panda/src/dxgsg9/dxTextureContext9.cxx
  8. 10 9
      panda/src/dxgsg9/dxTextureContext9.h
  9. 12 12
      panda/src/dxgsg9/wdxGraphicsBuffer9.cxx
  10. 17 0
      panda/src/gles2gsg/gles2gsg.h
  11. 32 20
      panda/src/glstuff/glCgShaderContext_src.cxx
  12. 1 1
      panda/src/glstuff/glGeomMunger_src.cxx
  13. 42 45
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  14. 1 1
      panda/src/glstuff/glGraphicsBuffer_src.h
  15. 437 302
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  16. 14 8
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  17. 39 104
      panda/src/glstuff/glShaderContext_src.cxx
  18. 0 3
      panda/src/glstuff/glShaderContext_src.h
  19. 29 9
      panda/src/glstuff/glTextureContext_src.I
  20. 68 56
      panda/src/glstuff/glTextureContext_src.cxx
  21. 15 14
      panda/src/glstuff/glTextureContext_src.h
  22. 0 10
      panda/src/glstuff/glmisc_src.cxx
  23. 0 1
      panda/src/glstuff/glmisc_src.h
  24. 9 11
      panda/src/gobj/preparedGraphicsObjects.cxx
  25. 1 1
      panda/src/gobj/preparedGraphicsObjects.h
  26. 105 131
      panda/src/gobj/texture.cxx
  27. 6 4
      panda/src/gobj/texture.h
  28. 13 7
      panda/src/gobj/textureContext.I
  29. 2 2
      panda/src/gobj/textureContext.h
  30. 1 1
      panda/src/gsgbase/graphicsStateGuardianBase.h
  31. 148 125
      panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx
  32. 9 9
      panda/src/tinydisplay/tinyGraphicsStateGuardian.h
  33. 4 2
      panda/src/tinydisplay/tinyTextureContext.I
  34. 8 0
      panda/src/tinydisplay/tinyTextureContext.cxx
  35. 1 1
      panda/src/tinydisplay/tinyTextureContext.h
  36. 1 1
      panda/src/tinydisplay/zbuffer.h
  37. 6 1
      panda/src/tinydisplay/zgl.h
  38. 2 2
      panda/src/wgldisplay/wglGraphicsBuffer.cxx

+ 1 - 1
panda/src/display/graphicsStateGuardian.cxx

@@ -548,7 +548,7 @@ get_scene() const {
  * call Texture::prepare().
  * call Texture::prepare().
  */
  */
 TextureContext *GraphicsStateGuardian::
 TextureContext *GraphicsStateGuardian::
-prepare_texture(Texture *, int view) {
+prepare_texture(Texture *) {
   return nullptr;
   return nullptr;
 }
 }
 
 

+ 1 - 1
panda/src/display/graphicsStateGuardian.h

@@ -289,7 +289,7 @@ PUBLISHED:
   MAKE_PROPERTY(scene, get_scene, set_scene);
   MAKE_PROPERTY(scene, get_scene, set_scene);
 
 
 public:
 public:
-  virtual TextureContext *prepare_texture(Texture *tex, int view);
+  virtual TextureContext *prepare_texture(Texture *tex);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
   virtual void release_textures(const pvector<TextureContext *> &contexts);
   virtual void release_textures(const pvector<TextureContext *> &contexts);

+ 15 - 24
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -189,8 +189,8 @@ DXGraphicsStateGuardian9::
  * call Texture::prepare().
  * call Texture::prepare().
  */
  */
 TextureContext *DXGraphicsStateGuardian9::
 TextureContext *DXGraphicsStateGuardian9::
-prepare_texture(Texture *tex, int view) {
-  DXTextureContext9 *dtc = new DXTextureContext9(_prepared_objects, tex, view);
+prepare_texture(Texture *tex) {
+  DXTextureContext9 *dtc = new DXTextureContext9(_prepared_objects, tex);
 
 
   if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
   if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
@@ -206,7 +206,7 @@ prepare_texture(Texture *tex, int view) {
  * stage.
  * stage.
  */
  */
 void DXGraphicsStateGuardian9::
 void DXGraphicsStateGuardian9::
-apply_texture(int i, TextureContext *tc, const SamplerState &sampler) {
+apply_texture(int i, TextureContext *tc, int view, const SamplerState &sampler) {
   if (tc == nullptr) {
   if (tc == nullptr) {
     // The texture wasn't bound properly or something, so ensure texturing is
     // The texture wasn't bound properly or something, so ensure texturing is
     // disabled and just return.
     // disabled and just return.
@@ -296,7 +296,7 @@ apply_texture(int i, TextureContext *tc, const SamplerState &sampler) {
   float lod_bias = sampler.get_lod_bias();
   float lod_bias = sampler.get_lod_bias();
   set_sampler_state(i, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lod_bias);
   set_sampler_state(i, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lod_bias);
 
 
-  _d3d_device->SetTexture(i, dtc->get_d3d_texture());
+  _d3d_device->SetTexture(i, dtc->get_d3d_texture(view));
 }
 }
 
 
 /**
 /**
@@ -384,20 +384,10 @@ release_texture(TextureContext *tc) {
  */
  */
 bool DXGraphicsStateGuardian9::
 bool DXGraphicsStateGuardian9::
 extract_texture_data(Texture *tex) {
 extract_texture_data(Texture *tex) {
-  bool success = true;
-
-  int num_views = tex->get_num_views();
-  for (int view = 0; view < num_views; ++view) {
-    TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
-    nassertr(tc != nullptr, false);
-    DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
-
-    if (!dtc->extract_texture_data(*_screen)) {
-      success = false;
-    }
-  }
-
-  return success;
+  TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
+  nassertr(tc != nullptr, false);
+  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
+  return dtc->extract_texture_data(*_screen);
 }
 }
 
 
 /**
 /**
@@ -1851,7 +1841,7 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
   // must use a render target type texture for StretchRect
   // must use a render target type texture for StretchRect
   tex->set_render_to_texture(true);
   tex->set_render_to_texture(true);
 
 
-  TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
+  TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   if (tc == nullptr) {
   if (tc == nullptr) {
     return false;
     return false;
   }
   }
@@ -1868,10 +1858,11 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
     // for now.
     // for now.
     return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
     return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
   }
   }
-  nassertr(dtc->get_d3d_2d_texture() != nullptr, false);
+  IDirect3DTexture9 *d3d_2d_texture = dtc->get_d3d_2d_texture(view);
+  nassertr(d3d_2d_texture != nullptr, false);
 
 
   IDirect3DSurface9 *tex_level_0;
   IDirect3DSurface9 *tex_level_0;
-  hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
+  hr = d3d_2d_texture->GetSurfaceLevel(0, &tex_level_0);
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
     dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
     return false;
     return false;
@@ -1896,7 +1887,7 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
           << "Unable to re-create texture " << *dtc->get_texture() << endl;
           << "Unable to re-create texture " << *dtc->get_texture() << endl;
         return false;
         return false;
       }
       }
-      hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
+      hr = d3d_2d_texture->GetSurfaceLevel(0, &tex_level_0);
       if (FAILED(hr)) {
       if (FAILED(hr)) {
         dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
         dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
         return false;
         return false;
@@ -3663,8 +3654,8 @@ update_standard_texture_bindings() {
     // We always reissue every stage in DX, just in case the texcoord index or
     // We always reissue every stage in DX, just in case the texcoord index or
     // texgen mode or some other property has changed.
     // texgen mode or some other property has changed.
     int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
     int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
-    TextureContext *tc = texture->prepare_now(view, _prepared_objects, this);
-    apply_texture(si, tc, sampler);
+    TextureContext *tc = texture->prepare_now(_prepared_objects, this);
+    apply_texture(si, tc, view, sampler);
     set_texture_blend_mode(si, stage);
     set_texture_blend_mode(si, stage);
 
 
     int texcoord_dimensions = 2;
     int texcoord_dimensions = 2;

+ 2 - 2
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -63,8 +63,8 @@ public:
     calc_fb_properties(DWORD cformat, DWORD dformat,
     calc_fb_properties(DWORD cformat, DWORD dformat,
                        DWORD multisampletype, DWORD multisamplequality);
                        DWORD multisampletype, DWORD multisamplequality);
 
 
-  virtual TextureContext *prepare_texture(Texture *tex, int view);
-  void apply_texture(int i, TextureContext *tc, const SamplerState &sampler);
+  virtual TextureContext *prepare_texture(Texture *tex);
+  void apply_texture(int i, TextureContext *tc, int view, const SamplerState &sampler);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual bool update_texture(TextureContext *tc, bool force);
   bool upload_texture(DXTextureContext9 *dtc, bool force);
   bool upload_texture(DXTextureContext9 *dtc, bool force);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);

+ 2 - 2
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -730,13 +730,13 @@ update_shader_texture_bindings(DXShaderContext9 *prev, GSG *gsg) {
         continue;
         continue;
       }
       }
 
 
-      TextureContext *tc = tex->prepare_now(view, gsg->_prepared_objects, gsg);
+      TextureContext *tc = tex->prepare_now(gsg->_prepared_objects, gsg);
       if (tc == nullptr) {
       if (tc == nullptr) {
         continue;
         continue;
       }
       }
 
 
       int texunit = cgGetParameterResourceIndex(p);
       int texunit = cgGetParameterResourceIndex(p);
-      gsg->apply_texture(texunit, tc, sampler);
+      gsg->apply_texture(texunit, tc, view, sampler);
     }
     }
   }
   }
 #endif
 #endif

+ 9 - 8
panda/src/dxgsg9/dxTextureContext9.I

@@ -24,8 +24,9 @@ has_mipmaps() const {
  * texture it is.
  * texture it is.
  */
  */
 INLINE IDirect3DBaseTexture9 *DXTextureContext9::
 INLINE IDirect3DBaseTexture9 *DXTextureContext9::
-get_d3d_texture() const {
-  return _d3d_texture;
+get_d3d_texture(int view) const {
+  view = (std::max)((std::min)(view, (int)_d3d_textures.size() - 1), 0);
+  return _d3d_textures[view];
 }
 }
 
 
 /**
 /**
@@ -33,8 +34,8 @@ get_d3d_texture() const {
  * 1-d or 2-d texture.
  * 1-d or 2-d texture.
  */
  */
 INLINE IDirect3DTexture9 *DXTextureContext9::
 INLINE IDirect3DTexture9 *DXTextureContext9::
-get_d3d_2d_texture() const {
-  return _d3d_2d_texture;
+get_d3d_2d_texture(int view) const {
+  return (IDirect3DTexture9 *)get_d3d_texture(view);
 }
 }
 
 
 /**
 /**
@@ -42,8 +43,8 @@ get_d3d_2d_texture() const {
  * 3-d texture.
  * 3-d texture.
  */
  */
 INLINE IDirect3DVolumeTexture9 *DXTextureContext9::
 INLINE IDirect3DVolumeTexture9 *DXTextureContext9::
-get_d3d_volume_texture() const {
-  return _d3d_volume_texture;
+get_d3d_volume_texture(int view) const {
+  return (IDirect3DVolumeTexture9 *)get_d3d_texture(view);
 }
 }
 
 
 /**
 /**
@@ -51,6 +52,6 @@ get_d3d_volume_texture() const {
  * cube map texture.
  * cube map texture.
  */
  */
 INLINE IDirect3DCubeTexture9 *DXTextureContext9::
 INLINE IDirect3DCubeTexture9 *DXTextureContext9::
-get_d3d_cube_texture() const {
-  return _d3d_cube_texture;
+get_d3d_cube_texture(int view) const {
+  return (IDirect3DCubeTexture9 *)get_d3d_texture(view);
 }
 }

+ 394 - 338
panda/src/dxgsg9/dxTextureContext9.cxx

@@ -36,18 +36,14 @@ static const DWORD g_LowByteMask = 0x000000FF;
  *
  *
  */
  */
 DXTextureContext9::
 DXTextureContext9::
-DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
-  TextureContext(pgo, tex, view) {
+DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex) :
+  TextureContext(pgo, tex) {
 
 
   if (dxgsg9_cat.is_spam()) {
   if (dxgsg9_cat.is_spam()) {
     dxgsg9_cat.spam()
     dxgsg9_cat.spam()
       << "Creating DX texture [" << tex->get_name() << "], minfilter(" << tex->get_minfilter() << "), magfilter(" << tex->get_magfilter() << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n";
       << "Creating DX texture [" << tex->get_name() << "], minfilter(" << tex->get_minfilter() << "), magfilter(" << tex->get_magfilter() << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n";
   }
   }
 
 
-  _d3d_texture = nullptr;
-  _d3d_2d_texture = nullptr;
-  _d3d_volume_texture = nullptr;
-  _d3d_cube_texture = nullptr;
   _has_mipmaps = false;
   _has_mipmaps = false;
   _is_render_target = false;
   _is_render_target = false;
   _managed = -1;
   _managed = -1;
@@ -101,7 +97,7 @@ bool DXTextureContext9::
 create_texture(DXScreenData &scrn) {
 create_texture(DXScreenData &scrn) {
 
 
   // check if the texture has already been created
   // check if the texture has already been created
-  if (_d3d_2d_texture || _d3d_cube_texture || _d3d_volume_texture) {
+  if (!_d3d_textures.empty()) {
     // texture already created, no need to create
     // texture already created, no need to create
     return true;
     return true;
   }
   }
@@ -146,21 +142,22 @@ create_texture(DXScreenData &scrn) {
     }
     }
   }
   }
 
 
-  switch (tex->get_texture_type()) {
-    case Texture::TT_1d_texture:
-    case Texture::TT_2d_texture:
-    case Texture::TT_cube_map:
-      // no compression for render target textures, or very small textures
-      if (!tex->get_render_to_texture() &&
-          orig_width >= 4 && orig_height >= 4) {
-        if (texture_wants_compressed){
-          compress_texture = true;
-        }
+  Texture::TextureType texture_type = tex->get_texture_type();
+  switch (texture_type) {
+  case Texture::TT_1d_texture:
+  case Texture::TT_2d_texture:
+  case Texture::TT_cube_map:
+    // no compression for render target textures, or very small textures
+    if (!tex->get_render_to_texture() && orig_width >= 4 && orig_height >= 4) {
+      if (texture_wants_compressed){
+        compress_texture = true;
       }
       }
-      break;
-    case Texture::TT_3d_texture:
-      // compression of 3d textures not supported by all video chips
-      break;
+    }
+    break;
+
+  case Texture::TT_3d_texture:
+    // compression of 3d textures not supported by all video chips
+    break;
   }
   }
 
 
   if (texture_stored_compressed && !compress_texture) {
   if (texture_stored_compressed && !compress_texture) {
@@ -259,7 +256,7 @@ create_texture(DXScreenData &scrn) {
 
 
   DWORD filter_caps;
   DWORD filter_caps;
 
 
-  switch (tex->get_texture_type()) {
+  switch (texture_type) {
   case Texture::TT_1d_texture:
   case Texture::TT_1d_texture:
   case Texture::TT_2d_texture:
   case Texture::TT_2d_texture:
     filter_caps = scrn._d3dcaps.TextureFilterCaps;
     filter_caps = scrn._d3dcaps.TextureFilterCaps;
@@ -353,7 +350,7 @@ create_texture(DXScreenData &scrn) {
 
 
   if (orig_width != target_width || orig_height != target_height ||
   if (orig_width != target_width || orig_height != target_height ||
       orig_depth != target_depth) {
       orig_depth != target_depth) {
-    if (tex->get_texture_type() == Texture::TT_3d_texture) {
+    if (texture_type == Texture::TT_3d_texture) {
       dxgsg9_cat.info()
       dxgsg9_cat.info()
         << "Reducing size of " << tex->get_name()
         << "Reducing size of " << tex->get_name()
         << " from " << orig_width << "x" << orig_height << "x" << orig_depth
         << " from " << orig_width << "x" << orig_height << "x" << orig_depth
@@ -970,17 +967,18 @@ create_texture(DXScreenData &scrn) {
       << "D3D create_texture ( ) unknown texture format\n";
       << "D3D create_texture ( ) unknown texture format\n";
   }
   }
 
 
-  int data_size;
 
 
-  data_size = target_width * target_height * target_depth;
+  int num_views = tex->get_num_views();
+
+  size_t data_size = target_width * target_height * target_depth;
   if (_has_mipmaps) {
   if (_has_mipmaps) {
-    data_size = (int) ((PN_stdfloat) data_size * 1.3333333);
+    data_size += data_size / 3;
   }
   }
-  data_size = (int) ((PN_stdfloat) data_size * bytes_per_texel);
-  if (tex->get_texture_type() == Texture::TT_cube_map) {
+  data_size *= bytes_per_texel;
+  if (texture_type == Texture::TT_cube_map) {
     data_size *= 6;
     data_size *= 6;
   }
   }
-  update_data_size_bytes(data_size);
+  update_data_size_bytes((size_t)data_size * (size_t)num_views);
 
 
   int attempts;
   int attempts;
 
 
@@ -991,14 +989,14 @@ create_texture(DXScreenData &scrn) {
       << " reported available.\n";
       << " reported available.\n";
     dxgsg9_cat.debug()
     dxgsg9_cat.debug()
       << " size is " << target_width << " w * " << target_height << " h * "
       << " size is " << target_width << " w * " << target_height << " h * "
-      << target_depth << " d";
+      << target_depth << " d * " << num_views << " v";
     if (_has_mipmaps) {
     if (_has_mipmaps) {
       dxgsg9_cat.debug(false)
       dxgsg9_cat.debug(false)
         << " * 1.3333333 mipmaps";
         << " * 1.3333333 mipmaps";
     }
     }
     dxgsg9_cat.debug(false)
     dxgsg9_cat.debug(false)
       << " * " << bytes_per_texel << " bpt";
       << " * " << bytes_per_texel << " bpt";
-    if (tex->get_texture_type() == Texture::TT_cube_map) {
+    if (texture_type == Texture::TT_cube_map) {
       dxgsg9_cat.debug(false)
       dxgsg9_cat.debug(false)
         << " * 6 faces";
         << " * 6 faces";
     }
     }
@@ -1006,45 +1004,55 @@ create_texture(DXScreenData &scrn) {
       << "\n";
       << "\n";
   }
   }
 
 
-  attempts = 0;
-  do
-  {
-    switch (tex->get_texture_type()) {
-    case Texture::TT_1d_texture:
-    case Texture::TT_2d_texture:
-      hr = scrn._d3d_device->CreateTexture
-        (target_width, target_height, mip_level_count, usage,
-         target_pixel_format, pool, &_d3d_2d_texture, nullptr);
-      _d3d_texture = _d3d_2d_texture;
-      break;
+  for (int view = 0; view < num_views; ++view) {
+    IDirect3DBaseTexture9 *d3d_texture = nullptr;
+    IDirect3DTexture9 *d3d_2d_texture;
+    IDirect3DVolumeTexture9 *d3d_volume_texture;
+    IDirect3DCubeTexture9 *d3d_cube_texture;
+
+    attempts = 0;
+    do {
+      switch (texture_type) {
+      case Texture::TT_1d_texture:
+      case Texture::TT_2d_texture:
+        hr = scrn._d3d_device->CreateTexture
+          (target_width, target_height, mip_level_count, usage,
+           target_pixel_format, pool, &d3d_2d_texture, nullptr);
+        d3d_texture = d3d_2d_texture;
+        break;
 
 
-    case Texture::TT_3d_texture:
-      hr = scrn._d3d_device->CreateVolumeTexture
-        (target_width, target_height, target_depth, mip_level_count, usage,
-         target_pixel_format, pool, &_d3d_volume_texture, nullptr);
-      _d3d_texture = _d3d_volume_texture;
-      break;
+      case Texture::TT_3d_texture:
+        hr = scrn._d3d_device->CreateVolumeTexture
+          (target_width, target_height, target_depth, mip_level_count, usage,
+           target_pixel_format, pool, &d3d_volume_texture, nullptr);
+        d3d_texture = d3d_volume_texture;
+        break;
 
 
-    case Texture::TT_cube_map:
-      hr = scrn._d3d_device->CreateCubeTexture
-        (target_width, mip_level_count, usage,
-         target_pixel_format, pool, &_d3d_cube_texture, nullptr);
-      _d3d_texture = _d3d_cube_texture;
+      case Texture::TT_cube_map:
+        hr = scrn._d3d_device->CreateCubeTexture
+          (target_width, mip_level_count, usage,
+           target_pixel_format, pool, &d3d_cube_texture, nullptr);
+        d3d_texture = d3d_cube_texture;
 
 
-      target_height = target_width;
-      break;
+        target_height = target_width;
+        break;
+      }
+
+      attempts++;
     }
     }
+    while (scrn._dxgsg9->check_dx_allocation(hr, data_size, attempts));
 
 
-    attempts++;
-  } while (scrn._dxgsg9 -> check_dx_allocation (hr, data_size, attempts));
+    if (FAILED(hr)) {
+      dxgsg9_cat.error()
+        << "D3D create_texture failed!" << D3DERRORSTRING(hr);
+      dxgsg9_cat.error()
+        << "  width = " << target_width << " height = " << target_height
+        << " target_pixel_format = " << target_pixel_format << "\n";
 
 
-  if (FAILED(hr)) {
-    dxgsg9_cat.error()
-      << "D3D create_texture failed!" << D3DERRORSTRING(hr);
-    dxgsg9_cat.error()
-      << "  width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n";
+      goto error_exit;
+    }
 
 
-    goto error_exit;
+    _d3d_textures.push_back(d3d_texture);
   }
   }
 
 
   if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
   if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
@@ -1088,12 +1096,11 @@ create_texture(DXScreenData &scrn) {
 
 
   return true;
   return true;
 
 
- error_exit:
-
-  RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
-  _d3d_2d_texture = nullptr;
-  _d3d_volume_texture = nullptr;
-  _d3d_cube_texture = nullptr;
+error_exit:
+  for (IDirect3DBaseTexture9 *d3d_texture : _d3d_textures) {
+    RELEASE(d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
+  }
+  _d3d_textures.clear();
   return false;
   return false;
 }
 }
 
 
@@ -1121,18 +1128,20 @@ create_simple_texture(DXScreenData &scrn) {
 
 
   int data_size = target_width * target_height * 4;
   int data_size = target_width * target_height * 4;
 
 
+  IDirect3DTexture9 *d3d_2d_texture = nullptr;
   hr = scrn._d3d_device->CreateTexture
   hr = scrn._d3d_device->CreateTexture
     (target_width, target_height, mip_level_count, usage,
     (target_width, target_height, mip_level_count, usage,
-     target_pixel_format, pool, &_d3d_2d_texture, nullptr);
-  _d3d_texture = _d3d_2d_texture;
+     target_pixel_format, pool, &d3d_2d_texture, nullptr);
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
       << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr);
       << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr);
     dxgsg9_cat.error()
     dxgsg9_cat.error()
-      << "  width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n";
+      << "  width = " << target_width << " height = " << target_height
+      << " target_pixel_format = " << target_pixel_format << "\n";
 
 
     goto error_exit;
     goto error_exit;
   }
   }
+  _d3d_textures.push_back(d3d_2d_texture);
 
 
   if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
   if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
     dxgsg9_cat.debug()
     dxgsg9_cat.debug()
@@ -1144,10 +1153,10 @@ create_simple_texture(DXScreenData &scrn) {
     CPTA_uchar image = get_texture()->get_simple_ram_image();
     CPTA_uchar image = get_texture()->get_simple_ram_image();
 
 
     hr = -1;
     hr = -1;
-    // hr = fill_d3d_texture_pixels(scrn);
+    // hr = fill_d3d_texture_pixels(view, scrn);
 
 
     IDirect3DSurface9 *surface = nullptr;
     IDirect3DSurface9 *surface = nullptr;
-    _d3d_2d_texture->GetSurfaceLevel(0, &surface);
+    d3d_2d_texture->GetSurfaceLevel(0, &surface);
 
 
     RECT source_size;
     RECT source_size;
     source_size.left = source_size.top = 0;
     source_size.left = source_size.top = 0;
@@ -1176,11 +1185,11 @@ create_simple_texture(DXScreenData &scrn) {
   mark_loaded();
   mark_loaded();
   return true;
   return true;
 
 
- error_exit:
-  RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
-  _d3d_2d_texture = nullptr;
-  _d3d_volume_texture = nullptr;
-  _d3d_cube_texture = nullptr;
+error_exit:
+  for (IDirect3DBaseTexture9 *d3d_texture : _d3d_textures) {
+    RELEASE(d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
+  }
+  _d3d_textures.clear();
   return false;
   return false;
 }
 }
 
 
@@ -1189,16 +1198,15 @@ create_simple_texture(DXScreenData &scrn) {
  */
  */
 void DXTextureContext9::
 void DXTextureContext9::
 delete_texture() {
 delete_texture() {
-
-  if (_d3d_texture == nullptr) {
+  if (_d3d_textures.empty()) {
     // don't bother printing the msg below, since we already released it.
     // don't bother printing the msg below, since we already released it.
     return;
     return;
   }
   }
 
 
-  RELEASE(_d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
-  _d3d_2d_texture = nullptr;
-  _d3d_volume_texture = nullptr;
-  _d3d_cube_texture = nullptr;
+  for (IDirect3DBaseTexture9 *d3d_texture : _d3d_textures) {
+    RELEASE(d3d_texture, dxgsg9, "texture", RELEASE_ONCE);
+  }
+  _d3d_textures.clear();
 }
 }
 
 
 /**
 /**
@@ -1219,10 +1227,13 @@ extract_texture_data(DXScreenData &screen) {
       << "\n";
       << "\n";
     return state;
     return state;
   }
   }
-  nassertr(IS_VALID_PTR(_d3d_2d_texture), false);
+  nassertr(!_d3d_textures.empty(), false);
+
+  //FIXME: support for multiview textures
+  IDirect3DTexture9 *d3d_2d_texture = get_d3d_2d_texture(0);
 
 
   D3DSURFACE_DESC desc;
   D3DSURFACE_DESC desc;
-  hr = _d3d_2d_texture->GetLevelDesc(0, &desc);
+  hr = d3d_2d_texture->GetLevelDesc(0, &desc);
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
       << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr);
       << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr);
@@ -1299,11 +1310,12 @@ extract_texture_data(DXScreenData &screen) {
     return state;
     return state;
   }
   }
 
 
-  int num_levels = _d3d_2d_texture->GetLevelCount();
+  int num_levels = d3d_2d_texture->GetLevelCount();
 
 
   tex->set_x_size(desc.Width);
   tex->set_x_size(desc.Width);
   tex->set_y_size(desc.Height);
   tex->set_y_size(desc.Height);
   tex->set_z_size(1);
   tex->set_z_size(1);
+  tex->set_num_views(1);
   tex->set_component_type(Texture::T_unsigned_byte);
   tex->set_component_type(Texture::T_unsigned_byte);
   tex->set_format(format);
   tex->set_format(format);
   tex->clear_ram_image();
   tex->clear_ram_image();
@@ -1315,7 +1327,7 @@ extract_texture_data(DXScreenData &screen) {
     source_surface = 0;
     source_surface = 0;
     destination_surface = 0;
     destination_surface = 0;
 
 
-    hr = _d3d_2d_texture -> GetSurfaceLevel (0, &source_surface);
+    hr = d3d_2d_texture->GetSurfaceLevel(0, &source_surface);
     if (hr == D3D_OK) {
     if (hr == D3D_OK) {
 
 
       D3DPOOL pool;
       D3DPOOL pool;
@@ -1389,7 +1401,7 @@ extract_texture_data(DXScreenData &screen) {
   else {
   else {
     for (int n = 0; n < num_levels; ++n) {
     for (int n = 0; n < num_levels; ++n) {
       D3DLOCKED_RECT rect;
       D3DLOCKED_RECT rect;
-      hr = _d3d_2d_texture->LockRect(n, &rect, nullptr, D3DLOCK_READONLY);
+      hr = d3d_2d_texture->LockRect(n, &rect, nullptr, D3DLOCK_READONLY);
       if (FAILED(hr)) {
       if (FAILED(hr)) {
         dxgsg9_cat.error()
         dxgsg9_cat.error()
           << "Texture::LockRect() failed!  level = " << n << " " << D3DERRORSTRING(hr);
           << "Texture::LockRect() failed!  level = " << n << " " << D3DERRORSTRING(hr);
@@ -1428,7 +1440,7 @@ extract_texture_data(DXScreenData &screen) {
         memcpy(image.p(), rect.pBits, size);
         memcpy(image.p(), rect.pBits, size);
       }
       }
 
 
-      _d3d_2d_texture->UnlockRect(n);
+      d3d_2d_texture->UnlockRect(n);
       if (n == 0) {
       if (n == 0) {
         tex->set_ram_image(image, compression);
         tex->set_ram_image(image, compression);
       } else {
       } else {
@@ -1741,62 +1753,49 @@ static UINT calculate_row_byte_length (int width, int num_color_channels, D3DFOR
  * with texture data.  Takes care of all necessary conversions and error
  * with texture data.  Takes care of all necessary conversions and error
  * handling.
  * handling.
  */
  */
-HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format)
-{
+HRESULT DXTextureContext9::
+fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format) {
   // This whole function was refactored out of fill_d3d_texture_pixels to make
   // This whole function was refactored out of fill_d3d_texture_pixels to make
   // the code more readable and to avoid code duplication.
   // the code more readable and to avoid code duplication.
-  IDirect3DSurface9 *mip_surface = nullptr;
-  bool using_temp_buffer = false;
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
   CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
   CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level);
-  BYTE *pixels = (BYTE*) image.p();
-  DWORD width  = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level);
-  DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level);
+  DWORD width  = (DWORD)get_texture()->get_expected_mipmap_x_size(mip_level);
+  DWORD height = (DWORD)get_texture()->get_expected_mipmap_y_size(mip_level);
+  DWORD num_color_channels = get_texture()->get_num_components();
   int component_width = get_texture()->get_component_width();
   int component_width = get_texture()->get_component_width();
 
 
   size_t page_size = get_texture()->get_expected_ram_mipmap_page_size(mip_level);
   size_t page_size = get_texture()->get_expected_ram_mipmap_page_size(mip_level);
   size_t view_size;
   size_t view_size;
+  size_t view_stride;
   vector_uchar clear_data;
   vector_uchar clear_data;
+  BYTE *image_pixels;
   if (page_size > 0) {
   if (page_size > 0) {
     if (image.is_null()) {
     if (image.is_null()) {
       // Make an image, filled with the texture's clear color.
       // Make an image, filled with the texture's clear color.
       image = get_texture()->make_ram_mipmap_image(mip_level);
       image = get_texture()->make_ram_mipmap_image(mip_level);
       nassertr(!image.is_null(), E_FAIL);
       nassertr(!image.is_null(), E_FAIL);
-      pixels = (BYTE *)image.p();
     }
     }
-    view_size = image.size();
-    pixels += view_size * get_view();
-    pixels += page_size * depth_index;
+    image_pixels = (BYTE *)image.p();
+    view_size = get_texture()->get_ram_mipmap_view_size(mip_level);
+    view_stride = view_size;
+    image_pixels += page_size * depth_index;
   } else {
   } else {
     // This is a 0x0 texture, which gets loaded as though it were 1x1.
     // This is a 0x0 texture, which gets loaded as though it were 1x1.
     width = 1;
     width = 1;
     height = 1;
     height = 1;
     clear_data = get_texture()->get_clear_data();
     clear_data = get_texture()->get_clear_data();
-    pixels = clear_data.data();
+    image_pixels = clear_data.data();
     view_size = clear_data.size();
     view_size = clear_data.size();
+    view_stride = 0;
   }
   }
-
-  if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
-    nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
-    hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface);
-  } else {
-    nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL);
-    hr = _d3d_2d_texture->GetSurfaceLevel(mip_level, &mip_surface);
-  }
-
-  if (FAILED(hr)) {
-    dxgsg9_cat.error()
-      << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
-      << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
-    return E_FAIL;
-  }
+  nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
 
 
   RECT source_size;
   RECT source_size;
   source_size.left = source_size.top = 0;
   source_size.left = source_size.top = 0;
   source_size.right = width;
   source_size.right = width;
   source_size.bottom = height;
   source_size.bottom = height;
 
 
-  UINT source_row_byte_length = calculate_row_byte_length(width, get_texture()->get_num_components(), source_format);
+  UINT source_row_byte_length = calculate_row_byte_length(width, num_color_channels, source_format);
 
 
   DWORD mip_filter;
   DWORD mip_filter;
   // need filtering if size changes, (also if bitdepth reduced (need
   // need filtering if size changes, (also if bitdepth reduced (need
@@ -1807,87 +1806,128 @@ HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
     mip_filter |= D3DX_FILTER_SRGB;
     mip_filter |= D3DX_FILTER_SRGB;
   }
   }
 
 
-  // D3DXLoadSurfaceFromMemory will load black luminance and we want full
-  // white, so convert to explicit luminance-alpha format
-  if (_d3d_format == D3DFMT_A8) {
-    // alloc buffer for explicit D3DFMT_A8L8
-    USHORT *temp_buffer = new USHORT[width * height];
-    if (!IS_VALID_PTR(temp_buffer)) {
-      dxgsg9_cat.error()
-        << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
-      goto exit_FillMipmapSurf;
-    }
-    using_temp_buffer = true;
-
-    USHORT *out_pixels = temp_buffer;
-    BYTE *source_pixels = pixels + component_width - 1;
-    for (UINT y = 0; y < height; y++) {
-      for (UINT x = 0; x < width; x++, source_pixels += component_width, out_pixels++) {
-        // add full white, which is our interpretation of alpha-only (similar
-        // to default adding full opaque alpha 0xFF to RGB-only textures)
-        *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
-      }
+  // Preallocate temporary buffer for conversion
+  BYTE *temp_buffer = nullptr;
+  if (source_format == D3DFMT_A8 || component_width != 1) {
+    int num_pixels = width * height;
+    if (source_format == D3DFMT_A8) {
+      num_pixels *= 2;
+      source_format = D3DFMT_A8L8;
+      source_row_byte_length *= 2;
+    } else {
+      num_pixels *= num_color_channels;
     }
     }
-
-    source_format = D3DFMT_A8L8;
-    source_row_byte_length = width * sizeof(USHORT);
-    pixels = (BYTE*)temp_buffer;
-  }
-  else if (component_width != 1) {
-    // Convert from 16-bit per channel (or larger) format down to 8-bit per
-    // channel.  This throws away precision in the original image, but dx8
-    // doesn't support high-precision images anyway.
-
-    int num_components = get_texture()->get_num_components();
-    int num_pixels = width * height * num_components;
-    BYTE *temp_buffer = new BYTE[num_pixels];
+    temp_buffer = new BYTE[num_pixels];
     if (!IS_VALID_PTR(temp_buffer)) {
     if (!IS_VALID_PTR(temp_buffer)) {
-      dxgsg9_cat.error() << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n";
-      goto exit_FillMipmapSurf;
-    }
-    using_temp_buffer = true;
-
-    BYTE *source_pixels = pixels + component_width - 1;
-    for (int i = 0; i < num_pixels; i++) {
-      temp_buffer[i] = *source_pixels;
-      source_pixels += component_width;
+      dxgsg9_cat.error()
+        << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
+      return E_FAIL;
     }
     }
-    pixels = (BYTE*)temp_buffer;
   }
   }
 
 
   // filtering may be done here if texture if targetsize != origsize
   // filtering may be done here if texture if targetsize != origsize
+  int num_views = (int)_d3d_textures.size();
+
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
-  GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * height);
+  GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * height * num_views);
 #endif
 #endif
-  if (source_format == D3DFMT_ATI1 || source_format == D3DFMT_ATI2) {
-    // These formats are not supported by D3DXLoadSurfaceFromMemory.
-    D3DLOCKED_RECT rect;
-    _d3d_2d_texture->LockRect(mip_level, &rect, 0, D3DLOCK_DISCARD);
 
 
-    unsigned char *dest = (unsigned char *)rect.pBits;
-    memcpy(dest, pixels, view_size);
+  for (int view = 0; view < num_views; ++view) {
+    BYTE *pixels = image_pixels;
+    image_pixels += view_stride;
 
 
-    _d3d_2d_texture->UnlockRect(mip_level);
+    if (source_format == D3DFMT_ATI1 || source_format == D3DFMT_ATI2) {
+      // These formats are not supported by D3DXLoadSurfaceFromMemory.
+      D3DLOCKED_RECT rect;
 
 
-  } else {
-    hr = D3DXLoadSurfaceFromMemory
-      (mip_surface, nullptr, nullptr, (LPCVOID)pixels,
-        source_format, source_row_byte_length, nullptr,
-        &source_size, mip_filter, (D3DCOLOR)0x0);
-    if (FAILED(hr)) {
-      dxgsg9_cat.error()
-        << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
-        << ", mip_level " << mip_level
-        << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
+      if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
+        IDirect3DCubeTexture9 *d3d_cube_texture = get_d3d_cube_texture(view);
+        nassertr(IS_VALID_PTR(d3d_cube_texture), E_FAIL);
+        d3d_cube_texture->LockRect((D3DCUBEMAP_FACES)depth_index, mip_level, &rect, 0, D3DLOCK_DISCARD);
+
+        unsigned char *dest = (unsigned char *)rect.pBits;
+        memcpy(dest, pixels, view_size);
+
+        d3d_cube_texture->UnlockRect((D3DCUBEMAP_FACES)depth_index, mip_level);
+      } else {
+        IDirect3DTexture9 *d3d_2d_texture = get_d3d_2d_texture(view);
+        nassertr(IS_VALID_PTR(d3d_2d_texture), E_FAIL);
+        d3d_2d_texture->LockRect(mip_level, &rect, 0, D3DLOCK_DISCARD);
+
+        unsigned char *dest = (unsigned char *)rect.pBits;
+        memcpy(dest, pixels, view_size);
+
+        d3d_2d_texture->UnlockRect(mip_level);
+      }
+    }
+    else {
+      if (_d3d_format == D3DFMT_A8 && source_format == D3DFMT_A8L8) {
+        USHORT *out_pixels = (USHORT *)temp_buffer;
+        BYTE *source_pixels = pixels + component_width - 1;
+        for (UINT y = 0; y < height; y++) {
+          for (UINT x = 0; x < width; x++, source_pixels += component_width, out_pixels++) {
+            // add full white, which is our interpretation of alpha-only
+            // (similar to default adding full opaque alpha 0xFF to RGB-only
+            // textures)
+            *out_pixels = ((*source_pixels) << 8) | 0xFF;
+          }
+        }
+        pixels = (BYTE *)temp_buffer;
+      }
+      else if (component_width != 1) {
+        // Convert from 16-bit per channel (or larger) format down to 8-bit per
+        // channel.  This throws away precision in the original image, but dx8
+        // doesn't support high-precision images anyway.
+
+        int num_components = get_texture()->get_num_components();
+        int num_pixels = width * height * num_components;
+
+        BYTE *source_pixels = pixels + component_width - 1;
+        for (int i = 0; i < num_pixels; i++) {
+          temp_buffer[i] = *source_pixels;
+          source_pixels += component_width;
+        }
+        pixels = (BYTE *)temp_buffer;
+      }
+
+      IDirect3DSurface9 *mip_surface = nullptr;
+      if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
+        IDirect3DCubeTexture9 *d3d_cube_texture = get_d3d_cube_texture(view);
+        nassertr(IS_VALID_PTR(d3d_cube_texture), E_FAIL);
+        hr = d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface);
+      } else {
+        IDirect3DTexture9 *d3d_2d_texture = get_d3d_2d_texture(view);
+        nassertr(IS_VALID_PTR(d3d_2d_texture), E_FAIL);
+        hr = d3d_2d_texture->GetSurfaceLevel(mip_level, &mip_surface);
+      }
+
+      if (FAILED(hr)) {
+        dxgsg9_cat.error()
+          << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
+          << ", view " << view << ", mip_level " << mip_level
+          << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
+        return E_FAIL;
+      }
+
+      hr = D3DXLoadSurfaceFromMemory
+        (mip_surface, nullptr, nullptr, (LPCVOID)pixels,
+          source_format, source_row_byte_length, nullptr,
+          &source_size, mip_filter, (D3DCOLOR)0x0);
+      if (FAILED(hr)) {
+        dxgsg9_cat.error()
+          << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name()
+          << ", view " << view << ", mip_level " << mip_level
+          << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
+      }
+
+      RELEASE(mip_surface, dxgsg9, "FillDDTextureMipmapPixels MipSurface texture ptr", RELEASE_ONCE);
     }
     }
   }
   }
 
 
-exit_FillMipmapSurf:
-  if (using_temp_buffer) {
-    SAFE_DELETE_ARRAY(pixels);
+  if (temp_buffer != nullptr) {
+    delete[] temp_buffer;
   }
   }
 
 
-  RELEASE(mip_surface, dxgsg9, "FillDDTextureMipmapPixels MipSurface texture ptr", RELEASE_ONCE);
   return hr;
   return hr;
 }
 }
 
 
@@ -1899,7 +1939,8 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
   IDirect3DDevice9 *device = scrn._d3d_device;
   IDirect3DDevice9 *device = scrn._d3d_device;
   Texture *tex = get_texture();
   Texture *tex = get_texture();
   nassertr(IS_VALID_PTR(tex), E_FAIL);
   nassertr(IS_VALID_PTR(tex), E_FAIL);
-  if (tex->get_texture_type() == Texture::TT_3d_texture) {
+  Texture::TextureType texture_type = tex->get_texture_type();
+  if (texture_type == Texture::TT_3d_texture) {
     return fill_d3d_volume_texture_pixels(scrn);
     return fill_d3d_volume_texture_pixels(scrn);
   }
   }
 
 
@@ -1924,14 +1965,15 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
   if (image.is_null()) {
   if (image.is_null()) {
     // The texture doesn't have an image to load.  That's ok; it might be a
     // The texture doesn't have an image to load.  That's ok; it might be a
     // texture we've rendered to by frame buffer operations or something.
     // texture we've rendered to by frame buffer operations or something.
-    if (tex->get_render_to_texture()) {
+    if (tex->get_render_to_texture() && texture_type != Texture::TT_cube_map) {
       HRESULT result;
       HRESULT result;
 
 
-      if (_d3d_2d_texture) {
+      for (int view = 0; view < (int)_d3d_textures.size(); ++view) {
+        IDirect3DTexture9 *d3d_2d_texture = get_d3d_2d_texture(view);
+
         // clear render to texture
         // clear render to texture
         IDirect3DSurface9 *surface;
         IDirect3DSurface9 *surface;
-
-        result = _d3d_2d_texture -> GetSurfaceLevel (0, &surface);
+        result = d3d_2d_texture->GetSurfaceLevel(0, &surface);
         if (result == D3D_OK) {
         if (result == D3D_OK) {
           D3DSURFACE_DESC surface_description;
           D3DSURFACE_DESC surface_description;
 
 
@@ -1981,7 +2023,6 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
     }
     }
   }
   }
   //nassertr(IS_VALID_PTR((BYTE*)image.p()), E_FAIL);
   //nassertr(IS_VALID_PTR((BYTE*)image.p()), E_FAIL);
-  nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
 
 
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
 
 
@@ -2017,6 +2058,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
     break;
     break;
   }
   }
 
 
+  int num_views = (int)_d3d_textures.size();
   for (unsigned int di = 0; di < orig_depth; di++) {
   for (unsigned int di = 0; di < orig_depth; di++) {
 
 
     // fill top level mipmap
     // fill top level mipmap
@@ -2028,7 +2070,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
     if (_has_mipmaps) {
     if (_has_mipmaps) {
       // if we have pre-calculated mipmap levels, use them, otherwise generate
       // if we have pre-calculated mipmap levels, use them, otherwise generate
       // on the fly
       // on the fly
-      int miplevel_count = _d3d_texture->GetLevelCount();
+      int miplevel_count = _d3d_textures[0]->GetLevelCount();
       if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
       if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) {
         if (dxgsg9_cat.is_debug()) {
         if (dxgsg9_cat.is_debug()) {
           dxgsg9_cat.debug()
           dxgsg9_cat.debug()
@@ -2041,45 +2083,51 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
             return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
             return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
           }
           }
         }
         }
+
+        return D3D_OK;
       }
       }
       else {
       else {
         // mipmaps need to be generated, either use autogen or d3dx functions
         // mipmaps need to be generated, either use autogen or d3dx functions
+        for (int view = 0; view < num_views; ++view) {
+          IDirect3DBaseTexture9 *d3d_texture = get_d3d_texture(view);
+          nassertr(IS_VALID_PTR(d3d_texture), E_FAIL);
+
+          if (_managed == false && scrn._supports_automatic_mipmap_generation) {
+            if (false) {
+              IDirect3DBaseTexture9 *d3d_texture = get_d3d_texture(view);
+              nassertr(IS_VALID_PTR(d3d_texture), E_FAIL);
+              //hr = d3d_texture->SetAutoGenFilterType(D3DTEXF_PYRAMIDALQUAD);
+              //hr = d3d_texture->SetAutoGenFilterType(D3DTEXF_GAUSSIANQUAD);
+              //hr = d3d_texture->SetAutoGenFilterType(D3DTEXF_ANISOTROPIC);
+              hr = d3d_texture->SetAutoGenFilterType(D3DTEXF_LINEAR);
+              if (FAILED(hr)) {
+                dxgsg9_cat.error() << "SetAutoGenFilterType failed " << D3DERRORSTRING(hr);
+              }
 
 
-        if (_managed == false && scrn._supports_automatic_mipmap_generation) {
-          if (false)
-          {
-            // hr = _d3d_texture -> SetAutoGenFilterType
-            // (D3DTEXF_PYRAMIDALQUAD); hr = _d3d_texture ->
-            // SetAutoGenFilterType (D3DTEXF_GAUSSIANQUAD); hr = _d3d_texture
-            // -> SetAutoGenFilterType (D3DTEXF_ANISOTROPIC);
-            hr = _d3d_texture -> SetAutoGenFilterType (D3DTEXF_LINEAR);
-            if (FAILED(hr)) {
-              dxgsg9_cat.error() << "SetAutoGenFilterType failed " << D3DERRORSTRING(hr);
+              d3d_texture->GenerateMipSubLevels();
             }
             }
-
-            _d3d_texture -> GenerateMipSubLevels ( );
-          }
-        }
-        else {
-          DWORD mip_filter_flags;
-          if (!dx_use_triangle_mipgen_filter) {
-            mip_filter_flags = D3DX_FILTER_BOX;
-          } else {
-            mip_filter_flags = D3DX_FILTER_TRIANGLE;
           }
           }
+          else {
+            DWORD mip_filter_flags;
+            if (!dx_use_triangle_mipgen_filter) {
+              mip_filter_flags = D3DX_FILTER_BOX;
+            } else {
+              mip_filter_flags = D3DX_FILTER_TRIANGLE;
+            }
 
 
-          if (Texture::is_srgb(tex->get_format())) {
-            mip_filter_flags |= D3DX_FILTER_SRGB;
-          }
+            if (Texture::is_srgb(tex->get_format())) {
+              mip_filter_flags |= D3DX_FILTER_SRGB;
+            }
 
 
-          // mip_filter_flags |= D3DX_FILTER_DITHER;
-          hr = D3DXFilterTexture(_d3d_texture, nullptr, 0,
-                                mip_filter_flags);
+            // mip_filter_flags |= D3DX_FILTER_DITHER;
+            hr = D3DXFilterTexture(d3d_texture, nullptr, 0, mip_filter_flags);
 
 
-          if (FAILED(hr)) {
-            dxgsg9_cat.error()
-              << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
-              << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
+            if (FAILED(hr)) {
+              dxgsg9_cat.error()
+                << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
+                << " view " << view << ", D3DXFilterTex failed"
+                << D3DERRORSTRING(hr);
+            }
           }
           }
         }
         }
       }
       }
@@ -2126,158 +2174,166 @@ fill_d3d_volume_texture_pixels(DXScreenData &scrn) {
 
 
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
 
 
-  nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
+  nassertr(!_d3d_textures.empty(), E_FAIL);
   nassertr(tex->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
   nassertr(tex->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
 
 
-  DWORD orig_width  = (DWORD) tex->get_x_size();
-  DWORD orig_height = (DWORD) tex->get_y_size();
-  DWORD orig_depth = (DWORD) tex->get_z_size();
+  DWORD orig_width  = (DWORD)tex->get_x_size();
+  DWORD orig_height = (DWORD)tex->get_y_size();
+  DWORD orig_depth = (DWORD)tex->get_z_size();
   DWORD num_color_channels = tex->get_num_components();
   DWORD num_color_channels = tex->get_num_components();
-  D3DFORMAT source_format = _d3d_format;
-  BYTE *image_pixels = (BYTE*)image.p();
   int component_width = tex->get_component_width();
   int component_width = tex->get_component_width();
 
 
+  D3DFORMAT source_format = _d3d_format;
+  UINT source_row_byte_length = orig_width * num_color_channels;
+  UINT source_page_byte_length = orig_height * source_row_byte_length;
+
+  // Preallocate temporary buffer for conversion
+  BYTE *temp_buffer = nullptr;
+  if (_d3d_format == D3DFMT_A8 || component_width != 1) {
+    int num_pixels = orig_width * orig_height * orig_depth;
+    if (_d3d_format == D3DFMT_A8) {
+      num_pixels *= 2;
+      source_format = D3DFMT_A8L8;
+      source_row_byte_length *= 2;
+      source_page_byte_length *= 2;
+    } else {
+      num_pixels *= num_color_channels;
+    }
+    temp_buffer = new BYTE[num_pixels];
+    if (!IS_VALID_PTR(temp_buffer)) {
+      dxgsg9_cat.error()
+        << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
+      return E_FAIL;
+    }
+  }
+
+  BYTE *image_pixels = (BYTE *)image.p();
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
 
 
   size_t view_size = tex->get_ram_mipmap_view_size(0);
   size_t view_size = tex->get_ram_mipmap_view_size(0);
-  image_pixels += view_size * get_view();
+  int num_views = (int)_d3d_textures.size();
 
 
-  IDirect3DVolume9 *mip_level_0 = nullptr;
-  bool using_temp_buffer = false;
-  BYTE *pixels = image_pixels;
+#ifdef DO_PSTATS
+  GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth * num_views);
+#endif
 
 
-  nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL);
-  hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0);
+  bool success = true;
 
 
-  if (FAILED(hr)) {
-    dxgsg9_cat.error()
-      << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
-      << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
-    return E_FAIL;
-  }
+  for (int view = 0; view < num_views; ++view) {
+    IDirect3DVolumeTexture9 *d3d_volume_texture = get_d3d_volume_texture(view);
+    nassertr(IS_VALID_PTR(d3d_volume_texture), E_FAIL);
 
 
-  D3DBOX source_size;
-  source_size.Left = source_size.Top = source_size.Front = 0;
-  source_size.Right = orig_width;
-  source_size.Bottom = orig_height;
-  source_size.Back = orig_depth;
+    IDirect3DVolume9 *mip_level_0 = nullptr;
+    BYTE *pixels = image_pixels;
+    image_pixels += view_size;
 
 
-  UINT source_row_byte_length = orig_width * num_color_channels;
-  UINT source_page_byte_length = orig_height * source_row_byte_length;
+    hr = d3d_volume_texture->GetVolumeLevel(0, &mip_level_0);
+    if (FAILED(hr)) {
+      dxgsg9_cat.error()
+        << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
+        << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
+      success = false;
+      continue;
+    }
 
 
-  DWORD level_0_filter, mip_filter_flags;
-  using_temp_buffer = false;
+    D3DBOX source_size;
+    source_size.Left = source_size.Top = source_size.Front = 0;
+    source_size.Right = orig_width;
+    source_size.Bottom = orig_height;
+    source_size.Back = orig_depth;
 
 
-  // need filtering if size changes, (also if bitdepth reduced (need
-  // dithering)??)
-  level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
+    DWORD level_0_filter, mip_filter_flags;
 
 
-  if (Texture::is_srgb(tex->get_format())) {
-    level_0_filter |= D3DX_FILTER_SRGB;
-  }
+    // need filtering if size changes, (also if bitdepth reduced (need
+    // dithering)??)
+    level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
 
 
-  // D3DXLoadSurfaceFromMemory will load black luminance and we want full
-  // white, so convert to explicit luminance-alpha format
-  if (_d3d_format == D3DFMT_A8) {
-    // alloc buffer for explicit D3DFMT_A8L8
-    USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth];
-    if (!IS_VALID_PTR(temp_buffer)) {
-      dxgsg9_cat.error()
-        << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
-      goto exit_FillDDSurf;
-    }
-    using_temp_buffer = true;
-
-    USHORT *out_pixels = temp_buffer;
-    BYTE *source_pixels = pixels + component_width - 1;
-    for (UINT z = 0; z < orig_depth; z++) {
-      for (UINT y = 0; y < orig_height; y++) {
-        for (UINT x = 0;
-             x < orig_width;
-             x++, source_pixels += component_width, out_pixels++) {
-          // add full white, which is our interpretation of alpha-only
-          // (similar to default adding full opaque alpha 0xFF to RGB-only
-          // textures)
-          *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
+    if (Texture::is_srgb(tex->get_format())) {
+      level_0_filter |= D3DX_FILTER_SRGB;
+    }
+
+    // D3DXLoadSurfaceFromMemory will load black luminance and we want full
+    // white, so convert to explicit luminance-alpha format
+    if (_d3d_format == D3DFMT_A8 && source_format == D3DFMT_A8L8) {
+      USHORT *out_pixels = (USHORT *)temp_buffer;
+      BYTE *source_pixels = pixels + component_width - 1;
+      for (UINT z = 0; z < orig_depth; z++) {
+        for (UINT y = 0; y < orig_height; y++) {
+          for (UINT x = 0;
+               x < orig_width;
+               x++, source_pixels += component_width, out_pixels++) {
+            // add full white, which is our interpretation of alpha-only
+            // (similar to default adding full opaque alpha 0xFF to RGB-only
+            // textures)
+            *out_pixels = ((*source_pixels) << 8) | 0xFF;
+          }
         }
         }
       }
       }
-    }
 
 
-    source_format = D3DFMT_A8L8;
-    source_row_byte_length = orig_width * sizeof(USHORT);
-    source_page_byte_length = orig_height * source_row_byte_length;
-    pixels = (BYTE*)temp_buffer;
+      pixels = (BYTE *)temp_buffer;
+    }
+    else if (component_width != 1) {
+      // Convert from 16-bit per channel (or larger) format down to 8-bit per
+      // channel.  This throws away precision in the original image, but dx8
+      // doesn't support high-precision images anyway.
 
 
-  } else if (component_width != 1) {
-    // Convert from 16-bit per channel (or larger) format down to 8-bit per
-    // channel.  This throws away precision in the original image, but dx8
-    // doesn't support high-precision images anyway.
+      int num_components = tex->get_num_components();
+      int num_pixels = orig_width * orig_height * orig_depth * num_components;
 
 
-    int num_components = tex->get_num_components();
-    int num_pixels = orig_width * orig_height * orig_depth * num_components;
-    BYTE *temp_buffer = new BYTE[num_pixels];
-    if (!IS_VALID_PTR(temp_buffer)) {
-      dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
-      goto exit_FillDDSurf;
+      BYTE *source_pixels = pixels + component_width - 1;
+      for (int i = 0; i < num_pixels; i++) {
+        temp_buffer[i] = *source_pixels;
+        source_pixels += component_width;
+      }
+      pixels = (BYTE *)temp_buffer;
     }
     }
-    using_temp_buffer = true;
 
 
-    BYTE *source_pixels = pixels + component_width - 1;
-    for (int i = 0; i < num_pixels; i++) {
-      temp_buffer[i] = *source_pixels;
-      source_pixels += component_width;
+    // filtering may be done here if texture if targetsize != origsize
+    hr = D3DXLoadVolumeFromMemory
+      (mip_level_0, nullptr, nullptr, (LPCVOID)pixels,
+       source_format, source_row_byte_length, source_page_byte_length,
+       nullptr,
+       &source_size, level_0_filter, (D3DCOLOR)0x0);
+    if (FAILED(hr)) {
+      dxgsg9_cat.error()
+        << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
+        << " view " << view << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
+      success = false;
+      continue;
     }
     }
-    pixels = (BYTE*)temp_buffer;
-  }
 
 
+    if (_has_mipmaps) {
+      if (!dx_use_triangle_mipgen_filter) {
+        mip_filter_flags = D3DX_FILTER_BOX;
+      } else {
+        mip_filter_flags = D3DX_FILTER_TRIANGLE;
+      }
 
 
-  // filtering may be done here if texture if targetsize != origsize
-#ifdef DO_PSTATS
-  GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth);
-#endif
-  hr = D3DXLoadVolumeFromMemory
-    (mip_level_0, nullptr, nullptr, (LPCVOID)pixels,
-     source_format, source_row_byte_length, source_page_byte_length,
-     nullptr,
-     &source_size, level_0_filter, (D3DCOLOR)0x0);
-  if (FAILED(hr)) {
-    dxgsg9_cat.error()
-      << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
-      << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
-    goto exit_FillDDSurf;
-  }
+      if (Texture::is_srgb(tex->get_format())) {
+        mip_filter_flags |= D3DX_FILTER_SRGB;
+      }
 
 
-  if (_has_mipmaps) {
-    if (!dx_use_triangle_mipgen_filter) {
-      mip_filter_flags = D3DX_FILTER_BOX;
-    } else {
-      mip_filter_flags = D3DX_FILTER_TRIANGLE;
-    }
+      // mip_filter_flags| = D3DX_FILTER_DITHER;
 
 
-    if (Texture::is_srgb(tex->get_format())) {
-      mip_filter_flags |= D3DX_FILTER_SRGB;
+      hr = D3DXFilterTexture(d3d_volume_texture, nullptr, 0, mip_filter_flags);
+      if (FAILED(hr)) {
+        dxgsg9_cat.error()
+          << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
+          << " view " << view << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
+        success = false;
+        continue;
+      }
     }
     }
 
 
-    // mip_filter_flags| = D3DX_FILTER_DITHER;
-
-    hr = D3DXFilterTexture(_d3d_texture, nullptr, 0,
-                           mip_filter_flags);
-    if (FAILED(hr)) {
-      dxgsg9_cat.error()
-        << "FillDDSurfaceTexturePixels failed for " << tex->get_name()
-        << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
-      goto exit_FillDDSurf;
-    }
+    RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE);
   }
   }
 
 
- exit_FillDDSurf:
-  if (using_temp_buffer) {
-    SAFE_DELETE_ARRAY(pixels);
+  if (temp_buffer != nullptr) {
+    delete[] temp_buffer;
   }
   }
-  RELEASE(mip_level_0, dxgsg9, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE);
-  return hr;
-}
 
 
+  return success ? D3D_OK : E_FAIL;
+}
 
 
 /**
 /**
  * Returns the largest power of 2 less than or equal to value.
  * Returns the largest power of 2 less than or equal to value.

+ 10 - 9
panda/src/dxgsg9/dxTextureContext9.h

@@ -17,13 +17,14 @@
 #include "dxgsg9base.h"
 #include "dxgsg9base.h"
 #include "texture.h"
 #include "texture.h"
 #include "textureContext.h"
 #include "textureContext.h"
+#include "small_vector.h"
 
 
 /**
 /**
  *
  *
  */
  */
 class EXPCL_PANDADX DXTextureContext9 : public TextureContext {
 class EXPCL_PANDADX DXTextureContext9 : public TextureContext {
 public:
 public:
-  DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex, int view);
+  DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex);
   virtual ~DXTextureContext9();
   virtual ~DXTextureContext9();
 
 
   virtual void evict_lru();
   virtual void evict_lru();
@@ -34,10 +35,10 @@ public:
   bool extract_texture_data(DXScreenData &scrn);
   bool extract_texture_data(DXScreenData &scrn);
 
 
   INLINE bool has_mipmaps() const;
   INLINE bool has_mipmaps() const;
-  INLINE IDirect3DBaseTexture9 *get_d3d_texture() const;
-  INLINE IDirect3DTexture9 *get_d3d_2d_texture() const;
-  INLINE IDirect3DVolumeTexture9 *get_d3d_volume_texture() const;
-  INLINE IDirect3DCubeTexture9 *get_d3d_cube_texture() const;
+  INLINE IDirect3DBaseTexture9 *get_d3d_texture(int view) const;
+  INLINE IDirect3DTexture9 *get_d3d_2d_texture(int view) const;
+  INLINE IDirect3DVolumeTexture9 *get_d3d_volume_texture(int view) const;
+  INLINE IDirect3DCubeTexture9 *get_d3d_cube_texture(int view) const;
 
 
   static HRESULT d3d_surface_to_texture(RECT &source_rect,
   static HRESULT d3d_surface_to_texture(RECT &source_rect,
           IDirect3DSurface9 *d3d_surface,
           IDirect3DSurface9 *d3d_surface,
@@ -54,10 +55,10 @@ private:
 
 
 private:
 private:
   D3DFORMAT _d3d_format;    // the 'D3DFORMAT' the Panda TextureBuffer fmt corresponds to
   D3DFORMAT _d3d_format;    // the 'D3DFORMAT' the Panda TextureBuffer fmt corresponds to
-  IDirect3DBaseTexture9 *_d3d_texture;
-  IDirect3DTexture9 *_d3d_2d_texture;
-  IDirect3DVolumeTexture9 *_d3d_volume_texture;
-  IDirect3DCubeTexture9 *_d3d_cube_texture;
+  small_vector<IDirect3DBaseTexture9 *> _d3d_textures;
+  //IDirect3DTexture9 *_d3d_2d_texture;
+  //IDirect3DVolumeTexture9 *_d3d_volume_texture;
+  //IDirect3DCubeTexture9 *_d3d_cube_texture;
 
 
   int _managed;
   int _managed;
 
 

+ 12 - 12
panda/src/dxgsg9/wdxGraphicsBuffer9.cxx

@@ -364,7 +364,7 @@ rebuild_bitplanes() {
 // color_tex->set_format(Texture::F_rgba);
 // color_tex->set_format(Texture::F_rgba);
     color_ctx =
     color_ctx =
       DCAST(DXTextureContext9,
       DCAST(DXTextureContext9,
-            color_tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg));
+            color_tex->prepare_now(_gsg->get_prepared_objects(), _gsg));
 
 
     if (color_ctx) {
     if (color_ctx) {
       if (!color_ctx->create_texture(*_dxgsg->_screen)) {
       if (!color_ctx->create_texture(*_dxgsg->_screen)) {
@@ -373,7 +373,7 @@ rebuild_bitplanes() {
         return false;
         return false;
       }
       }
       if (color_tex->get_texture_type() == Texture::TT_2d_texture) {
       if (color_tex->get_texture_type() == Texture::TT_2d_texture) {
-        color_d3d_tex = color_ctx->_d3d_2d_texture;
+        color_d3d_tex = color_ctx->get_d3d_2d_texture(0);
         nassertr(color_d3d_tex != 0, false);
         nassertr(color_d3d_tex != 0, false);
         hr = color_d3d_tex -> GetSurfaceLevel(0, &color_surf);
         hr = color_d3d_tex -> GetSurfaceLevel(0, &color_surf);
         if (!SUCCEEDED(hr)) {
         if (!SUCCEEDED(hr)) {
@@ -381,7 +381,7 @@ rebuild_bitplanes() {
         }
         }
       }
       }
       if (color_tex->get_texture_type() == Texture::TT_cube_map) {
       if (color_tex->get_texture_type() == Texture::TT_cube_map) {
-        color_cube = color_ctx->_d3d_cube_texture;
+        color_cube = color_ctx->get_d3d_cube_texture(0);
         nassertr(color_cube != 0, false);
         nassertr(color_cube != 0, false);
 
 
         if (_cube_map_index >= 0 && _cube_map_index < 6) {
         if (_cube_map_index >= 0 && _cube_map_index < 6) {
@@ -443,7 +443,7 @@ rebuild_bitplanes() {
     depth_tex->set_format(Texture::F_depth_stencil);
     depth_tex->set_format(Texture::F_depth_stencil);
     depth_ctx =
     depth_ctx =
       DCAST(DXTextureContext9,
       DCAST(DXTextureContext9,
-            depth_tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg));
+            depth_tex->prepare_now(_gsg->get_prepared_objects(), _gsg));
     if (depth_ctx) {
     if (depth_ctx) {
       if (!depth_ctx->create_texture(*_dxgsg->_screen)) {
       if (!depth_ctx->create_texture(*_dxgsg->_screen)) {
         dxgsg9_cat.error()
         dxgsg9_cat.error()
@@ -451,7 +451,7 @@ rebuild_bitplanes() {
         return false;
         return false;
       }
       }
       if (depth_tex->get_texture_type() == Texture::TT_2d_texture) {
       if (depth_tex->get_texture_type() == Texture::TT_2d_texture) {
-        depth_d3d_tex = depth_ctx->_d3d_2d_texture;
+        depth_d3d_tex = depth_ctx->get_d3d_2d_texture(0);
         nassertr(depth_d3d_tex != 0, false);
         nassertr(depth_d3d_tex != 0, false);
         hr = depth_d3d_tex -> GetSurfaceLevel(0, &depth_surf);
         hr = depth_d3d_tex -> GetSurfaceLevel(0, &depth_surf);
         if (!SUCCEEDED(hr)) {
         if (!SUCCEEDED(hr)) {
@@ -459,7 +459,7 @@ rebuild_bitplanes() {
         }
         }
       }
       }
       if (depth_tex->get_texture_type() == Texture::TT_cube_map) {
       if (depth_tex->get_texture_type() == Texture::TT_cube_map) {
-        depth_cube = depth_ctx->_d3d_cube_texture;
+        depth_cube = depth_ctx->get_d3d_cube_texture(0);
         nassertr(depth_cube != 0, false);
         nassertr(depth_cube != 0, false);
         hr = depth_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &depth_surf);
         hr = depth_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &depth_surf);
         if (!SUCCEEDED(hr)) {
         if (!SUCCEEDED(hr)) {
@@ -518,7 +518,7 @@ rebuild_bitplanes() {
           IDirect3DSurface9 *color_surf = 0;
           IDirect3DSurface9 *color_surf = 0;
           IDirect3DCubeTexture9 *color_cube = 0;
           IDirect3DCubeTexture9 *color_cube = 0;
 
 
-          color_ctx = DCAST(DXTextureContext9, tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg));
+          color_ctx = DCAST(DXTextureContext9, tex->prepare_now(_gsg->get_prepared_objects(), _gsg));
           if (color_ctx) {
           if (color_ctx) {
             if (!color_ctx->create_texture(*_dxgsg->_screen)) {
             if (!color_ctx->create_texture(*_dxgsg->_screen)) {
               dxgsg9_cat.error()
               dxgsg9_cat.error()
@@ -526,7 +526,7 @@ rebuild_bitplanes() {
               return false;
               return false;
             }
             }
             if (tex->get_texture_type() == Texture::TT_2d_texture) {
             if (tex->get_texture_type() == Texture::TT_2d_texture) {
-              color_d3d_tex = color_ctx->_d3d_2d_texture;
+              color_d3d_tex = color_ctx->get_d3d_2d_texture(0);
               nassertr(color_d3d_tex != 0, false);
               nassertr(color_d3d_tex != 0, false);
 
 
               hr = color_d3d_tex -> GetSurfaceLevel(0, &color_surf);
               hr = color_d3d_tex -> GetSurfaceLevel(0, &color_surf);
@@ -613,8 +613,8 @@ select_target_tex_page(int page) {
   if (color_tex) {
   if (color_tex) {
     color_ctx =
     color_ctx =
       DCAST(DXTextureContext9,
       DCAST(DXTextureContext9,
-            color_tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg));
-    color_cube = color_ctx->_d3d_cube_texture;
+            color_tex->prepare_now(_gsg->get_prepared_objects(), _gsg));
+    color_cube = color_ctx->get_d3d_cube_texture(0);
     if (color_cube && _cube_map_index >= 0 && _cube_map_index < 6) {
     if (color_cube && _cube_map_index >= 0 && _cube_map_index < 6) {
       hr = color_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &color_surf);
       hr = color_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &color_surf);
       if (!SUCCEEDED(hr)) {
       if (!SUCCEEDED(hr)) {
@@ -657,7 +657,7 @@ select_target_tex_page(int page) {
           IDirect3DSurface9 *color_surf = 0;
           IDirect3DSurface9 *color_surf = 0;
           IDirect3DCubeTexture9 *color_cube = 0;
           IDirect3DCubeTexture9 *color_cube = 0;
 
 
-          color_ctx = DCAST(DXTextureContext9, tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg));
+          color_ctx = DCAST(DXTextureContext9, tex->prepare_now(_gsg->get_prepared_objects(), _gsg));
           if (color_ctx) {
           if (color_ctx) {
             if (tex->get_texture_type() == Texture::TT_cube_map) {
             if (tex->get_texture_type() == Texture::TT_cube_map) {
 
 
@@ -665,7 +665,7 @@ select_target_tex_page(int page) {
                 printf ("CUBEMAP i = %d, RenderTexturePlane = %d, _cube_map_index %d \n", i, plane, _cube_map_index);
                 printf ("CUBEMAP i = %d, RenderTexturePlane = %d, _cube_map_index %d \n", i, plane, _cube_map_index);
               }
               }
 
 
-              color_cube = color_ctx->_d3d_cube_texture;
+              color_cube = color_ctx->get_d3d_cube_texture(0);
               if (color_cube && _cube_map_index >= 0 && _cube_map_index < 6) {
               if (color_cube && _cube_map_index >= 0 && _cube_map_index < 6) {
                 hr = color_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &color_surf);
                 hr = color_cube -> GetCubeMapSurface ((D3DCUBEMAP_FACES) _cube_map_index, 0, &color_surf);
                 if (!SUCCEEDED(hr)) {
                 if (!SUCCEEDED(hr)) {

+ 17 - 0
panda/src/gles2gsg/gles2gsg.h

@@ -151,6 +151,8 @@ typedef char GLchar;
 #define GL_COLOR 0x1800
 #define GL_COLOR 0x1800
 #define GL_DEPTH 0x1801
 #define GL_DEPTH 0x1801
 #define GL_STENCIL 0x1802
 #define GL_STENCIL 0x1802
+#define GL_GREEN 0x1904
+#define GL_BLUE 0x1905
 #define GL_RGB10_A2 0x8059
 #define GL_RGB10_A2 0x8059
 #define GL_TEXTURE_WRAP_R 0x8072
 #define GL_TEXTURE_WRAP_R 0x8072
 #define GL_TEXTURE_MIN_LOD 0x813A
 #define GL_TEXTURE_MIN_LOD 0x813A
@@ -203,6 +205,7 @@ typedef char GLchar;
 #define GL_FLOAT_MAT4x3 0x8B6A
 #define GL_FLOAT_MAT4x3 0x8B6A
 #define GL_TEXTURE_2D_ARRAY 0x8C1A
 #define GL_TEXTURE_2D_ARRAY 0x8C1A
 #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
 #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
+#define GL_TEXTURE_BUFFER 0x8C2A
 #define GL_R11F_G11F_B10F 0x8C3A
 #define GL_R11F_G11F_B10F 0x8C3A
 #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
 #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
 #define GL_RGB9_E5 0x8C3D
 #define GL_RGB9_E5 0x8C3D
@@ -228,6 +231,7 @@ typedef char GLchar;
 #define GL_RGB_INTEGER 0x8D98
 #define GL_RGB_INTEGER 0x8D98
 #define GL_RGBA_INTEGER 0x8D99
 #define GL_RGBA_INTEGER 0x8D99
 #define GL_SAMPLER_2D_ARRAY 0x8DC1
 #define GL_SAMPLER_2D_ARRAY 0x8DC1
+#define GL_SAMPLER_BUFFER 0x8DC2
 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5
 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5
 #define GL_UNSIGNED_INT_VEC2 0x8DC6
 #define GL_UNSIGNED_INT_VEC2 0x8DC6
@@ -237,24 +241,37 @@ typedef char GLchar;
 #define GL_INT_SAMPLER_3D 0x8DCB
 #define GL_INT_SAMPLER_3D 0x8DCB
 #define GL_INT_SAMPLER_CUBE 0x8DCC
 #define GL_INT_SAMPLER_CUBE 0x8DCC
 #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
 #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#define GL_INT_SAMPLER_BUFFER 0x8DD0
 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
 #define GL_MAX_IMAGE_UNITS 0x8F38
 #define GL_MAX_IMAGE_UNITS 0x8F38
 #define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
 #define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
+#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
 #define GL_IMAGE_2D 0x904D
 #define GL_IMAGE_2D 0x904D
 #define GL_IMAGE_3D 0x904E
 #define GL_IMAGE_3D 0x904E
 #define GL_IMAGE_CUBE 0x9050
 #define GL_IMAGE_CUBE 0x9050
+#define GL_IMAGE_BUFFER 0x9051
 #define GL_IMAGE_2D_ARRAY 0x9053
 #define GL_IMAGE_2D_ARRAY 0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
 #define GL_INT_IMAGE_2D 0x9058
 #define GL_INT_IMAGE_2D 0x9058
 #define GL_INT_IMAGE_3D 0x9059
 #define GL_INT_IMAGE_3D 0x9059
 #define GL_INT_IMAGE_CUBE 0x905B
 #define GL_INT_IMAGE_CUBE 0x905B
+#define GL_INT_IMAGE_BUFFER 0x905C
 #define GL_INT_IMAGE_2D_ARRAY 0x905E
 #define GL_INT_IMAGE_2D_ARRAY 0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
 #define GL_UNSIGNED_INT_IMAGE_2D 0x9063
 #define GL_UNSIGNED_INT_IMAGE_2D 0x9063
 #define GL_UNSIGNED_INT_IMAGE_3D 0x9064
 #define GL_UNSIGNED_INT_IMAGE_3D 0x9064
 #define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
 #define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
 #define GL_UNSIGNALED 0x9118
 #define GL_UNSIGNALED 0x9118
 #define GL_SIGNALED 0x9119
 #define GL_SIGNALED 0x9119

+ 32 - 20
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -1054,26 +1054,38 @@ disable_shader_texture_bindings() {
     return;
     return;
   }
   }
 
 
-  for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
-    CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
-    if (p == 0) continue;
+  if (_glgsg->_supports_dsa) {
+    // The DSA extension has a single call for unbinding all targets for a
+    // given texture unit.
+    for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
+      CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
+      if (p == 0) continue;
+
+      int texunit = cgGetParameterResourceIndex(p);
+      _glgsg->_glBindTextureUnit(texunit, 0);
+    }
+  } else {
+    for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
+      CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
+      if (p == 0) continue;
 
 
-    int texunit = cgGetParameterResourceIndex(p);
-    _glgsg->set_active_texture_stage(texunit);
+      int texunit = cgGetParameterResourceIndex(p);
+      _glgsg->set_active_texture_stage(texunit);
 
 
-    glBindTexture(GL_TEXTURE_1D, 0);
-    glBindTexture(GL_TEXTURE_2D, 0);
-    if (_glgsg->_supports_3d_texture) {
-      glBindTexture(GL_TEXTURE_3D, 0);
-    }
-    if (_glgsg->_supports_2d_texture_array) {
-      glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, 0);
-    }
-    if (_glgsg->_supports_cube_map) {
-      glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+      glBindTexture(GL_TEXTURE_1D, 0);
+      glBindTexture(GL_TEXTURE_2D, 0);
+      if (_glgsg->_supports_3d_texture) {
+        glBindTexture(GL_TEXTURE_3D, 0);
+      }
+      if (_glgsg->_supports_2d_texture_array) {
+        glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, 0);
+      }
+      if (_glgsg->_supports_cube_map) {
+        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+      }
+      // This is probably faster - but maybe not as safe?
+      // cgGLDisableTextureParameter(p);
     }
     }
-    // This is probably faster - but maybe not as safe?
-    // cgGLDisableTextureParameter(p);
   }
   }
 
 
   cg_report_errors();
   cg_report_errors();
@@ -1132,7 +1144,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
 
 
     _glgsg->set_active_texture_stage(texunit);
     _glgsg->set_active_texture_stage(texunit);
 
 
-    TextureContext *tc = tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg);
+    TextureContext *tc = tex->prepare_now(_glgsg->_prepared_objects, _glgsg);
     if (tc == nullptr) {
     if (tc == nullptr) {
       continue;
       continue;
     }
     }
@@ -1148,8 +1160,8 @@ update_shader_texture_bindings(ShaderContext *prev) {
     }
     }
 
 
     CLP(TextureContext) *gtc = (CLP(TextureContext) *)tc;
     CLP(TextureContext) *gtc = (CLP(TextureContext) *)tc;
-    _glgsg->apply_texture(gtc);
-    _glgsg->apply_sampler(texunit, sampler, gtc);
+    _glgsg->apply_texture(gtc, view);
+    _glgsg->apply_sampler(texunit, sampler, gtc, view);
   }
   }
 
 
   cg_report_errors();
   cg_report_errors();

+ 1 - 1
panda/src/glstuff/glGeomMunger_src.cxx

@@ -274,7 +274,7 @@ munge_format_impl(const GeomVertexFormat *orig,
               column_alignment = texcoord_type->get_column_alignment();
               column_alignment = texcoord_type->get_column_alignment();
               num_values = texcoord_type->get_num_values();
               num_values = texcoord_type->get_num_values();
             }
             }
-            if (start + num_values * sizeof(PN_stdfloat) > glgsg->get_max_vertex_attrib_stride()) {
+            if (start + num_values * sizeof(PN_stdfloat) > (size_t)glgsg->get_max_vertex_attrib_stride()) {
               // We are exceeding the limit for stride reported by the driver.
               // We are exceeding the limit for stride reported by the driver.
               // Start a new array.
               // Start a new array.
               new_format->insert_array(insert_at++, new_array_format);
               new_format->insert_array(insert_at++, new_array_format);

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

@@ -268,11 +268,8 @@ begin_frame(FrameMode mode, Thread *current_thread) {
     if (gl_enable_memory_barriers && _fbo_multisample == 0) {
     if (gl_enable_memory_barriers && _fbo_multisample == 0) {
       CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
       CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
 
-      TextureContexts::iterator it;
-      for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
-        CLP(TextureContext) *gtc = *it;
-
-        if (gtc != nullptr && gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) {
+      for (CLP(TextureContext) *gtc : _texture_contexts) {
+        if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) {
           glgsg->issue_memory_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.
           // If we've done it for one, we've done it for all.
           break;
           break;
@@ -478,6 +475,12 @@ rebuild_bitplanes() {
 
 
       // Assign the texture to this slot.
       // Assign the texture to this slot.
       attach[plane] = tex;
       attach[plane] = tex;
+
+      if (plane == RTP_color && _fb_properties.is_stereo()) {
+        if (tex->get_num_views() < 2) {
+          tex->set_num_views(2);
+        }
+      }
     }
     }
   }
   }
 
 
@@ -581,7 +584,9 @@ rebuild_bitplanes() {
         // The second tex view has already been initialized, so bind it
         // The second tex view has already been initialized, so bind it
         // straight away.
         // straight away.
         if (attach[RTP_color] != nullptr) {
         if (attach[RTP_color] != nullptr) {
-          attach_tex(layer, 1, attach[RTP_color], next++);
+          CLP(TextureContext) *gtc = _texture_contexts.back();
+          nassertv(gtc->get_texture() == attach[RTP_color]);
+          attach_tex(next++, gtc, 1, layer);
         } else {
         } else {
           // XXX hack: I needed a slot to use, and we don't currently use
           // XXX hack: I needed a slot to use, and we don't currently use
           // RTP_stencil and it's treated as a color attachment below, so this
           // RTP_stencil and it's treated as a color attachment below, so this
@@ -776,7 +781,15 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
       _fb_properties.setup_color_texture(tex);
       _fb_properties.setup_color_texture(tex);
     }
     }
 
 
-    GLenum target = glgsg->get_texture_target(tex->get_texture_type());
+    TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg);
+    nassertv(tc != nullptr);
+    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+
+    glgsg->update_texture(gtc, true);
+    gtc->set_active(true);
+    _texture_contexts.push_back(gtc);
+
+    GLenum target = gtc->_target;
     if (target == GL_TEXTURE_CUBE_MAP) {
     if (target == GL_TEXTURE_CUBE_MAP) {
       target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
       target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
     }
     }
@@ -793,7 +806,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
         _rb[RTP_depth_stencil] = 0;
         _rb[RTP_depth_stencil] = 0;
       }
       }
 
 
-      attach_tex(layer, 0, tex, GL_DEPTH_ATTACHMENT_EXT);
+      attach_tex(GL_DEPTH_ATTACHMENT_EXT, gtc, 0, layer);
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
       GLint depth_size = 0;
       GLint depth_size = 0;
@@ -806,7 +819,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
           GLCAT.debug() << "Binding texture " << *tex << " to stencil attachment.\n";
           GLCAT.debug() << "Binding texture " << *tex << " to stencil attachment.\n";
         }
         }
 
 
-        attach_tex(layer, 0, tex, GL_STENCIL_ATTACHMENT_EXT);
+        attach_tex(GL_STENCIL_ATTACHMENT_EXT, gtc, 0, layer);
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
         GLint stencil_size = 0;
         GLint stencil_size = 0;
@@ -820,7 +833,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
         GLCAT.debug() << "Binding texture " << *tex << " to color attachment.\n";
         GLCAT.debug() << "Binding texture " << *tex << " to color attachment.\n";
       }
       }
 
 
-      attach_tex(layer, 0, tex, attachpoint);
+      attach_tex(attachpoint, gtc, 0, layer);
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
       if (attachpoint == GL_COLOR_ATTACHMENT0_EXT) {
       if (attachpoint == GL_COLOR_ATTACHMENT0_EXT) {
@@ -1344,30 +1357,22 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot,
  * This function attaches the given texture to the given attachment point.
  * This function attaches the given texture to the given attachment point.
  */
  */
 void CLP(GraphicsBuffer)::
 void CLP(GraphicsBuffer)::
-attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
-  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
-
-  if (view >= attach->get_num_views()) {
-    attach->set_num_views(view + 1);
-  }
+attach_tex(GLenum attachpoint, CLP(TextureContext) *gtc, int view, int layer) {
+  // We should have created the right number of views ahead of time.
+  nassertv(view < gtc->_num_views);
 
 
-  // Create the OpenGL texture object.
-  TextureContext *tc = attach->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
-  nassertv(tc != nullptr);
-  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-
-  glgsg->update_texture(gtc, true);
-  gtc->set_active(true);
-  _texture_contexts.push_back(gtc);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
 
   // It seems that binding the texture is necessary before binding to a
   // It seems that binding the texture is necessary before binding to a
   // framebuffer attachment.
   // framebuffer attachment.
-  glgsg->apply_texture(gtc);
+  glgsg->apply_texture(gtc, view);
+
+  GLuint index = gtc->get_view_index(view);
 
 
 #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION)
 #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION)
   if (glgsg->has_fixed_function_pipeline()) {
   if (glgsg->has_fixed_function_pipeline()) {
     GLclampf priority = 1.0f;
     GLclampf priority = 1.0f;
-    glPrioritizeTextures(1, &gtc->_index, &priority);
+    glPrioritizeTextures(1, &index, &priority);
   }
   }
 #endif
 #endif
 
 
@@ -1375,31 +1380,29 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
   if (_rb_size_z != 1) {
   if (_rb_size_z != 1) {
     // Bind all of the layers of the texture.
     // Bind all of the layers of the texture.
     nassertv(glgsg->_glFramebufferTexture != nullptr);
     nassertv(glgsg->_glFramebufferTexture != nullptr);
-    glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, attachpoint,
-                                 gtc->_index, 0);
+    glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, attachpoint, index, 0);
     return;
     return;
   }
   }
 #endif
 #endif
 
 
-  GLenum target = glgsg->get_texture_target(attach->get_texture_type());
-  if (target == GL_TEXTURE_CUBE_MAP) {
-    target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
-  }
-
+  GLenum target = gtc->_target;
   switch (target) {
   switch (target) {
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
   case GL_TEXTURE_3D:
   case GL_TEXTURE_3D:
     glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, attachpoint,
     glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, attachpoint,
-                                   target, gtc->_index, 0, layer);
+                                   target, index, 0, layer);
     break;
     break;
   case GL_TEXTURE_2D_ARRAY:
   case GL_TEXTURE_2D_ARRAY:
     glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, attachpoint,
     glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, attachpoint,
-                                      gtc->_index, 0, layer);
+                                      index, 0, layer);
     break;
     break;
 #endif
 #endif
+  case GL_TEXTURE_CUBE_MAP:
+    target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
+    // fall through
   default:
   default:
     glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
     glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
-                                   target, gtc->_index, 0);
+                                   target, index, 0);
   }
   }
 }
 }
 
 
@@ -1419,10 +1422,7 @@ generate_mipmaps() {
 
 
   // PStatGPUTimer timer(glgsg, _generate_mipmap_pcollector);
   // PStatGPUTimer timer(glgsg, _generate_mipmap_pcollector);
 
 
-  pvector<CLP(TextureContext)*>::iterator it;
-  for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
-    CLP(TextureContext) *gtc = *it;
-
+  for (CLP(TextureContext) *gtc : _texture_contexts) {
     if (gtc->_generate_mipmaps) {
     if (gtc->_generate_mipmaps) {
       glgsg->generate_mipmaps(gtc);
       glgsg->generate_mipmaps(gtc);
     }
     }
@@ -1954,11 +1954,8 @@ resolve_multisamples() {
   if (gl_enable_memory_barriers) {
   if (gl_enable_memory_barriers) {
     // Issue memory barriers as necessary to make sure that the texture memory
     // Issue memory barriers as necessary to make sure that the texture memory
     // is synchronized before we blit to it.
     // 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 != nullptr && gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) {
+    for (CLP(TextureContext) *gtc : _texture_contexts) {
+      if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) {
         glgsg->issue_memory_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.
         // If we've done it for one, we've done it for all.
         break;
         break;

+ 1 - 1
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -92,7 +92,7 @@ protected:
                  RenderTexturePlane plane, GLenum attachpoint);
                  RenderTexturePlane plane, GLenum attachpoint);
   void bind_slot_multisample(bool rb_resize, Texture **attach,
   void bind_slot_multisample(bool rb_resize, Texture **attach,
                  RenderTexturePlane plane, GLenum attachpoint);
                  RenderTexturePlane plane, GLenum attachpoint);
-  void attach_tex(int layer, int view, Texture *attach, GLenum attachpoint);
+  void attach_tex(GLenum attachpoint, CLP(TextureContext) *gtc, int view, int layer);
   bool check_fbo();
   bool check_fbo();
   void generate_mipmaps();
   void generate_mipmaps();
   void rebuild_bitplanes();
   void rebuild_bitplanes();

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


+ 14 - 8
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -143,6 +143,7 @@ typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
 typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
 typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
 typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
 typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
 typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
 typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
 // GLSL shader functions
 // GLSL shader functions
@@ -343,7 +344,7 @@ public:
   void issue_memory_barrier(GLbitfield barrier);
   void issue_memory_barrier(GLbitfield barrier);
 #endif
 #endif
 
 
-  virtual TextureContext *prepare_texture(Texture *tex, int view);
+  virtual TextureContext *prepare_texture(Texture *tex);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
   virtual void release_textures(const pvector<TextureContext *> &contexts);
   virtual void release_textures(const pvector<TextureContext *> &contexts);
@@ -632,12 +633,12 @@ protected:
 #endif  // NDEBUG
 #endif  // NDEBUG
 
 
   bool specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler);
   bool specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler);
-  bool apply_texture(CLP(TextureContext) *gtc);
-  bool apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc);
+  bool apply_texture(CLP(TextureContext) *gtc, int view);
+  bool apply_sampler(GLuint unit, const SamplerState &sampler,
+                     CLP(TextureContext) *gtc, int view);
   bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps);
   bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps);
-  bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
-                            bool uses_mipmaps, int mipmap_bias,
-                            GLenum texture_target,
+  bool upload_texture_image(CLP(TextureContext) *gtc, int view,
+                            bool needs_reload, int mipmap_bias, int num_levels,
                             GLint internal_format, GLint external_format,
                             GLint internal_format, GLint external_format,
                             GLenum component_type,
                             GLenum component_type,
                             Texture::CompressionMode image_compression);
                             Texture::CompressionMode image_compression);
@@ -646,7 +647,7 @@ protected:
 
 
   size_t get_texture_memory_size(CLP(TextureContext) *gtc);
   size_t get_texture_memory_size(CLP(TextureContext) *gtc);
   void check_nonresident_texture(BufferContextChain &chain);
   void check_nonresident_texture(BufferContextChain &chain);
-  bool do_extract_texture_data(CLP(TextureContext) *gtc);
+  bool do_extract_texture_data(CLP(TextureContext) *gtc, int view);
   bool extract_texture_image(PTA_uchar &image, size_t &page_size,
   bool extract_texture_image(PTA_uchar &image, size_t &page_size,
            Texture *tex, GLenum target, GLenum page_target,
            Texture *tex, GLenum target, GLenum page_target,
            Texture::ComponentType type,
            Texture::ComponentType type,
@@ -833,7 +834,7 @@ public:
   PFNGLTEXSTORAGE2DPROC _glTexStorage2D;
   PFNGLTEXSTORAGE2DPROC _glTexStorage2D;
   PFNGLTEXSTORAGE3DPROC _glTexStorage3D;
   PFNGLTEXSTORAGE3DPROC _glTexStorage3D;
 
 
-#ifndef OPENGLES
+#ifndef OPENGLES_1
   PFNGLTEXBUFFERPROC _glTexBuffer;
   PFNGLTEXBUFFERPROC _glTexBuffer;
 #endif
 #endif
 
 
@@ -967,7 +968,12 @@ public:
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
   bool _supports_dsa;
   bool _supports_dsa;
+  PFNGLCREATETEXTURESPROC _glCreateTextures;
+  PFNGLTEXTURESTORAGE2DPROC _glTextureStorage2D;
+  PFNGLTEXTURESUBIMAGE2DPROC _glTextureSubImage2D;
+  PFNGLTEXTUREPARAMETERIPROC _glTextureParameteri;
   PFNGLGENERATETEXTUREMIPMAPPROC _glGenerateTextureMipmap;
   PFNGLGENERATETEXTUREMIPMAPPROC _glGenerateTextureMipmap;
+  PFNGLBINDTEXTUREUNITPROC _glBindTextureUnit;
 #endif
 #endif
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1

+ 39 - 104
panda/src/glstuff/glShaderContext_src.cxx

@@ -1461,6 +1461,15 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
   if (param_size == 1) {
   if (param_size == 1) {
     // A single uniform (not an array, or an array of size 1).
     // A single uniform (not an array, or an array of size 1).
     switch (param_type) {
     switch (param_type) {
+#ifndef OPENGLES
+      case GL_INT_SAMPLER_1D:
+      case GL_INT_SAMPLER_1D_ARRAY:
+      case GL_UNSIGNED_INT_SAMPLER_1D:
+      case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+      case GL_SAMPLER_1D:
+      case GL_SAMPLER_1D_ARRAY:
+      case GL_SAMPLER_1D_SHADOW:
+#endif
       case GL_INT_SAMPLER_2D:
       case GL_INT_SAMPLER_2D:
       case GL_INT_SAMPLER_3D:
       case GL_INT_SAMPLER_3D:
       case GL_INT_SAMPLER_2D_ARRAY:
       case GL_INT_SAMPLER_2D_ARRAY:
@@ -1472,22 +1481,13 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_SAMPLER_CUBE_SHADOW:
       case GL_SAMPLER_CUBE_SHADOW:
       case GL_SAMPLER_2D_ARRAY:
       case GL_SAMPLER_2D_ARRAY:
       case GL_SAMPLER_2D_ARRAY_SHADOW:
       case GL_SAMPLER_2D_ARRAY_SHADOW:
-#ifndef OPENGLES
-      case GL_INT_SAMPLER_1D:
-      case GL_INT_SAMPLER_1D_ARRAY:
       case GL_INT_SAMPLER_BUFFER:
       case GL_INT_SAMPLER_BUFFER:
       case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
       case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
-      case GL_UNSIGNED_INT_SAMPLER_1D:
-      case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
       case GL_UNSIGNED_INT_SAMPLER_BUFFER:
       case GL_UNSIGNED_INT_SAMPLER_BUFFER:
       case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
       case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
-      case GL_SAMPLER_1D:
-      case GL_SAMPLER_1D_ARRAY:
-      case GL_SAMPLER_1D_SHADOW:
       case GL_SAMPLER_BUFFER:
       case GL_SAMPLER_BUFFER:
       case GL_SAMPLER_CUBE_MAP_ARRAY:
       case GL_SAMPLER_CUBE_MAP_ARRAY:
       case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
       case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
-#endif  // !OPENGLES
       case GL_SAMPLER_2D:
       case GL_SAMPLER_2D:
       case GL_SAMPLER_2D_SHADOW:
       case GL_SAMPLER_2D_SHADOW:
       case GL_SAMPLER_3D:
       case GL_SAMPLER_3D:
@@ -1679,18 +1679,22 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
       case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
 #ifndef OPENGLES
 #ifndef OPENGLES
       case GL_IMAGE_1D:
       case GL_IMAGE_1D:
+      case GL_INT_IMAGE_1D:
+      case GL_UNSIGNED_INT_IMAGE_1D:
+#endif
       case GL_IMAGE_CUBE_MAP_ARRAY:
       case GL_IMAGE_CUBE_MAP_ARRAY:
       case GL_IMAGE_BUFFER:
       case GL_IMAGE_BUFFER:
-      case GL_INT_IMAGE_1D:
       case GL_INT_IMAGE_CUBE_MAP_ARRAY:
       case GL_INT_IMAGE_CUBE_MAP_ARRAY:
       case GL_INT_IMAGE_BUFFER:
       case GL_INT_IMAGE_BUFFER:
-      case GL_UNSIGNED_INT_IMAGE_1D:
       case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
       case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
       case GL_UNSIGNED_INT_IMAGE_BUFFER:
       case GL_UNSIGNED_INT_IMAGE_BUFFER:
-#endif
         // This won't really change at runtime, so we might as well bind once
         // This won't really change at runtime, so we might as well bind once
         // and then forget about it.
         // and then forget about it.
+        // Note that OpenGL ES doesn't support changing this at runtime, so we
+        // rely on the shader using a layout declaration.
+#ifndef OPENGLES
         _glgsg->_glUniform1i(p, _glsl_img_inputs.size());
         _glgsg->_glUniform1i(p, _glsl_img_inputs.size());
+#endif
         {
         {
           ImageInput input;
           ImageInput input;
           input._name = InternalName::make(param_name);
           input._name = InternalName::make(param_name);
@@ -1881,7 +1885,6 @@ get_sampler_texture_type(int &out, GLenum param_type) {
       return false;
       return false;
     }
     }
 
 
-#ifndef OPENGLES
   case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
   case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
     if (!_glgsg->_supports_shadow_filter) {
     if (!_glgsg->_supports_shadow_filter) {
       GLCAT.error()
       GLCAT.error()
@@ -1913,7 +1916,6 @@ get_sampler_texture_type(int &out, GLenum param_type) {
         << "GLSL shader uses buffer texture, which is unsupported by the driver.\n";
         << "GLSL shader uses buffer texture, which is unsupported by the driver.\n";
       return false;
       return false;
     }
     }
-#endif  // !OPENGLES
 
 
   default:
   default:
     GLCAT.error()
     GLCAT.error()
@@ -2598,56 +2600,25 @@ disable_shader_texture_bindings() {
 
 
   DO_PSTATS_STUFF(_glgsg->_texture_state_pcollector.add_level(1));
   DO_PSTATS_STUFF(_glgsg->_texture_state_pcollector.add_level(1));
 
 
-  for (size_t i = 0; i < _shader->_tex_spec.size(); ++i) {
 #ifndef OPENGLES
 #ifndef OPENGLES
-    // Check if bindless was used, if so, there's nothing to unbind.
-    if (_glgsg->_supports_bindless_texture) {
-      GLint p = _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, nullptr);
-      break;
+  if (_glgsg->_supports_multi_bind) {
+    _glgsg->_glBindTextures(0, _shader->_tex_spec.size(), nullptr);
+  }
+  else if (_glgsg->_supports_dsa) {
+    for (size_t i = 0; i < _shader->_tex_spec.size(); ++i) {
+      _glgsg->_glBindTextureUnit(i, 0);
     }
     }
+  }
+  else
 #endif
 #endif
+  {
+    for (size_t i = 0; i < _shader->_tex_spec.size(); ++i) {
+      _glgsg->set_active_texture_stage(i);
 
 
-    _glgsg->set_active_texture_stage(i);
-
-    switch (_shader->_tex_spec[i]._desired_type) {
-    case Texture::TT_1d_texture:
-#ifndef OPENGLES
-      glBindTexture(GL_TEXTURE_1D, 0);
-#endif
-      break;
-
-    case Texture::TT_2d_texture:
-      glBindTexture(GL_TEXTURE_2D, 0);
-      break;
-
-    case Texture::TT_3d_texture:
-      glBindTexture(GL_TEXTURE_3D, 0);
-      break;
-
-    case Texture::TT_2d_texture_array:
-      glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
-      break;
-
-    case Texture::TT_cube_map:
-      glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
-      break;
-
-    case Texture::TT_buffer_texture:
-#ifndef OPENGLES
-      glBindTexture(GL_TEXTURE_BUFFER, 0);
-#endif
-      break;
+      GLenum target = _glgsg->get_texture_target((Texture::TextureType)_shader->_tex_spec[i]._desired_type);
+      if (target != GL_NONE) {
+        glBindTexture(target, 0);
+      }
     }
     }
   }
   }
 
 
@@ -2738,14 +2709,14 @@ update_shader_texture_bindings(ShaderContext *prev) {
       CLP(TextureContext) *gtc;
       CLP(TextureContext) *gtc;
 
 
       if (tex != nullptr) {
       if (tex != nullptr) {
-        int view = _glgsg->get_current_tex_view_offset();
-
-        gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
+        gtc = DCAST(CLP(TextureContext), tex->prepare_now(_glgsg->_prepared_objects, _glgsg));
         if (gtc != nullptr) {
         if (gtc != nullptr) {
           input._gtc = gtc;
           input._gtc = gtc;
 
 
           _glgsg->update_texture(gtc, true);
           _glgsg->update_texture(gtc, true);
-          gl_tex = gtc->_index;
+
+          int view = _glgsg->get_current_tex_view_offset();
+          gl_tex = gtc->get_view_index(view);
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
           if (gtc->needs_barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)) {
           if (gtc->needs_barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)) {
@@ -2880,7 +2851,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
       // enabled.
       // enabled.
     }
     }
 
 
-    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
+    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(_glgsg->_prepared_objects, _glgsg));
     if (gtc == nullptr) {
     if (gtc == nullptr) {
       if (multi_bind) {
       if (multi_bind) {
         textures[i] = 0;
         textures[i] = 0;
@@ -2890,49 +2861,13 @@ update_shader_texture_bindings(ShaderContext *prev) {
     }
     }
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
-    GLint p = spec._id._seqno;
-
     // If it was recently written to, we will have to issue a memory barrier
     // If it was recently written to, we will have to issue a memory barrier
     // soon.
     // soon.
     if (gtc->needs_barrier(GL_TEXTURE_FETCH_BARRIER_BIT)) {
     if (gtc->needs_barrier(GL_TEXTURE_FETCH_BARRIER_BIT)) {
       barriers |= GL_TEXTURE_FETCH_BARRIER_BIT;
       barriers |= GL_TEXTURE_FETCH_BARRIER_BIT;
     }
     }
-
-    // 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 (multi_bind) {
-        textures[i] = 0;
-        samplers[i] = 0;
-      }
-      if (!_glgsg->update_texture(gtc, true)) {
-        continue;
-      }
-
-      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
 #endif
 
 
-    // Bindless texturing wasn't supported or didn't work, so let's just bind
-    // the texture normally.
     // Note that simple RAM images are always 2-D for now, so to avoid errors,
     // Note that simple RAM images are always 2-D for now, so to avoid errors,
     // we must load the real texture if this is not for a sampler2D.
     // we must load the real texture if this is not for a sampler2D.
     bool force = (spec._desired_type != Texture::TT_2d_texture);
     bool force = (spec._desired_type != Texture::TT_2d_texture);
@@ -2943,7 +2878,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
         textures[i] = 0;
         textures[i] = 0;
       } else {
       } else {
         gtc->set_active(true);
         gtc->set_active(true);
-        textures[i] = gtc->_index;
+        textures[i] = gtc->get_view_index(view);
       }
       }
 
 
       SamplerContext *sc = sampler.prepare_now(_glgsg->get_prepared_objects(), _glgsg);
       SamplerContext *sc = sampler.prepare_now(_glgsg->get_prepared_objects(), _glgsg);
@@ -2962,8 +2897,8 @@ update_shader_texture_bindings(ShaderContext *prev) {
       if (!_glgsg->update_texture(gtc, force)) {
       if (!_glgsg->update_texture(gtc, force)) {
         continue;
         continue;
       }
       }
-      _glgsg->apply_texture(gtc);
-      _glgsg->apply_sampler(i, sampler, gtc);
+      _glgsg->apply_texture(gtc, view);
+      _glgsg->apply_sampler(i, sampler, gtc, view);
     }
     }
   }
   }
 
 

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

@@ -93,9 +93,6 @@ private:
   GLsizei _slider_table_size;
   GLsizei _slider_table_size;
   GLint _frame_number_loc;
   GLint _frame_number_loc;
   GLint _frame_number;
   GLint _frame_number;
-#ifndef OPENGLES
-  pmap<GLint, GLuint64> _glsl_uniform_handles;
-#endif
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
   struct StorageBlock {
   struct StorageBlock {

+ 29 - 9
panda/src/glstuff/glTextureContext_src.I

@@ -16,26 +16,46 @@
  */
  */
 INLINE CLP(TextureContext)::
 INLINE CLP(TextureContext)::
 CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
 CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
-  PreparedGraphicsObjects *pgo, Texture *tex, int view) :
-  TextureContext(pgo, tex, view)
+  PreparedGraphicsObjects *pgo, Texture *tex) :
+  TextureContext(pgo, tex),
+  _num_views(0)
 {
 {
   _glgsg = glgsg;
   _glgsg = glgsg;
 
 
-  glGenTextures(1, &_index);
+  _index = 0;
+  _indices = &_index;
+
   _buffer = 0;
   _buffer = 0;
+  _buffers = nullptr;
 
 
-#ifndef OPENGLES
-  _handle = 0;
-  _handle_resident = false;
-#endif
   _has_storage = false;
   _has_storage = false;
-  _simple_loaded = false;
   _immutable = false;
   _immutable = false;
-  _uses_mipmaps = false;
+  _may_reload_with_mipmaps = false;
   _generate_mipmaps = false;
   _generate_mipmaps = false;
   _internal_format = 0;
   _internal_format = 0;
   _width = 0;
   _width = 0;
   _height = 0;
   _height = 0;
   _depth = 0;
   _depth = 0;
+  _num_levels = 0;
   _target = GL_NONE;
   _target = GL_NONE;
 }
 }
+
+/**
+ * Returns the index for the given view of the texture.
+ */
+INLINE GLuint CLP(TextureContext)::
+get_view_index(int view) const {
+  return _indices[std::min(std::max(view, 0), _num_views - 1)];
+}
+
+/**
+ * Returns the buffer index for the given view of the texture.
+ */
+INLINE GLuint CLP(TextureContext)::
+get_view_buffer(int view) const {
+  if (_buffers != nullptr) {
+    return _buffers[std::min(std::max(view, 0), _num_views - 1)];
+  } else {
+    return 0;
+  }
+}

+ 68 - 56
panda/src/glstuff/glTextureContext_src.cxx

@@ -37,53 +37,29 @@ void CLP(TextureContext)::
 evict_lru() {
 evict_lru() {
   dequeue_lru();
   dequeue_lru();
 
 
-#ifndef OPENGLES
-  if (_handle != 0) {
-    if (_handle_resident) {
-      _glgsg->_glMakeTextureHandleNonResident(_handle);
-    }
-    _handle_resident = false;
-  } else
-#endif
-  {
-    reset_data();
-  }
-
+  reset_data(_target);
   update_data_size_bytes(0);
   update_data_size_bytes(0);
   mark_unloaded();
   mark_unloaded();
 }
 }
 
 
 /**
 /**
  * Resets the texture object to a new one so a new GL texture object can be
  * Resets the texture object to a new one so a new GL texture object can be
- * uploaded.
+ * uploaded.  This call also allows the texture target to be changed.
  */
  */
 void CLP(TextureContext)::
 void CLP(TextureContext)::
-reset_data() {
-#ifndef OPENGLES
-  if (_handle != 0 && _handle_resident) {
-    _glgsg->_glMakeTextureHandleNonResident(_handle);
-  }
-#endif
-
+reset_data(GLenum target, int num_views) {
   // Free the texture resources.
   // Free the texture resources.
-  glDeleteTextures(1, &_index);
+  set_num_views(0);
 
 
-  if (_buffer != 0) {
-    _glgsg->_glDeleteBuffers(1, &_buffer);
-    _buffer = 0;
-  }
+  _target = target;
 
 
   // We still need a valid index number, though, in case we want to re-load
   // We still need a valid index number, though, in case we want to re-load
   // the texture later.
   // the texture later.
-  glGenTextures(1, &_index);
+  set_num_views(num_views);
 
 
-#ifndef OPENGLES
-  _handle = 0;
-  _handle_resident = false;
-#endif
   _has_storage = false;
   _has_storage = false;
-  _simple_loaded = false;
   _immutable = false;
   _immutable = false;
+  _may_reload_with_mipmaps = false;
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
   // Mark the texture as coherent.
   // Mark the texture as coherent.
@@ -118,41 +94,77 @@ get_native_buffer_id() const {
 }
 }
 
 
 /**
 /**
- *
+ * Changes the number of views in the texture.
  */
  */
-#ifndef OPENGLES
 void CLP(TextureContext)::
 void CLP(TextureContext)::
-make_handle_resident() {
-  if (_handle != 0) {
-    if (!_handle_resident) {
-      _glgsg->_glMakeTextureHandleResident(_handle);
-      _handle_resident = true;
+set_num_views(int num_views) {
+  if (_num_views > num_views) {
+    glDeleteTextures(_num_views - num_views, _indices + _num_views);
+
+    if (_buffers != nullptr) {
+      _glgsg->_glDeleteBuffers(_num_views - num_views, _buffers + num_views);
     }
     }
-    set_resident(true);
-  }
-}
+
+    if (num_views <= 1) {
+      _index = _indices[0];
+      if (_indices != &_index) {
+        delete[] _indices;
+        _indices = &_index;
+      }
+
+#ifndef OPENGLES_1
+      if (_buffers != nullptr) {
+        _buffer = _buffers[0];
+        if (_buffers != &_buffer) {
+          delete[] _buffers;
+          _buffers = &_buffer;
+        }
+        if (num_views == 0) {
+          _buffers = nullptr;
+        }
+      }
 #endif
 #endif
+    }
+  }
+  else if (_num_views == 0 && num_views == 1) {
+    glGenTextures(1, &_index);
+    _indices = &_index;
 
 
-/**
- * Returns a handle for this texture.  Once this has been created, the texture
- * data may still be updated, but its properties may not.
- */
-#ifndef OPENGLES
-INLINE GLuint64 CLP(TextureContext)::
-get_handle() {
-  return 0;
-  if (!_glgsg->_supports_bindless_texture) {
-    return false;
+#ifndef OPENGLES_1
+    if (_target == GL_TEXTURE_BUFFER) {
+      _glgsg->_glGenBuffers(1, &_buffer);
+      _buffers = &_buffer;
+    }
+#endif
   }
   }
+  else if (_num_views < num_views) {
+    GLuint *new_indices = new GLuint[num_views];
+    memcpy(new_indices, _indices, sizeof(GLuint) * _num_views);
+    glGenTextures(num_views - _num_views, new_indices + _num_views);
+    if (_indices != &_index) {
+      delete[] _indices;
+    }
+    _indices = new_indices;
 
 
-  if (_handle == 0) {
-    _handle = _glgsg->_glGetTextureHandle(_index);
+#ifndef OPENGLES_1
+    if (_target == GL_TEXTURE_BUFFER) {
+      GLuint *new_buffers = new GLuint[num_views];
+      if (_buffers != nullptr) {
+        memcpy(new_buffers, _buffers, sizeof(GLuint) * _num_views);
+        _glgsg->_glGenBuffers(num_views - _num_views, new_buffers + _num_views);
+        if (_buffers != &_buffer) {
+          delete[] _buffers;
+        }
+      } else {
+        _glgsg->_glGenBuffers(num_views, new_buffers);
+      }
+      _buffers = new_buffers;
+    }
+#endif
   }
   }
 
 
-  _immutable = true;
-  return _handle;
+  _num_views = num_views;
 }
 }
-#endif
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
 /**
 /**

+ 15 - 14
panda/src/glstuff/glTextureContext_src.h

@@ -25,21 +25,20 @@ class CLP(SamplerContext);
 class EXPCL_GL CLP(TextureContext) : public TextureContext {
 class EXPCL_GL CLP(TextureContext) : public TextureContext {
 public:
 public:
   INLINE CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
   INLINE CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
-                             PreparedGraphicsObjects *pgo,
-                             Texture *tex, int view);
+                             PreparedGraphicsObjects *pgo, Texture *tex);
   ALLOC_DELETED_CHAIN(CLP(TextureContext));
   ALLOC_DELETED_CHAIN(CLP(TextureContext));
 
 
   virtual ~CLP(TextureContext)();
   virtual ~CLP(TextureContext)();
   virtual void evict_lru();
   virtual void evict_lru();
-  void reset_data();
+  void reset_data(GLenum target, int num_views = 1);
 
 
   virtual uint64_t get_native_id() const;
   virtual uint64_t get_native_id() const;
   virtual uint64_t get_native_buffer_id() const;
   virtual uint64_t get_native_buffer_id() const;
 
 
-#ifndef OPENGLES
-  void make_handle_resident();
-  GLuint64 get_handle();
-#endif
+  void set_num_views(int num_views);
+
+  INLINE GLuint get_view_index(int view) const;
+  INLINE GLuint get_view_buffer(int view) const;
 
 
 #ifdef OPENGLES_1
 #ifdef OPENGLES_1
   static constexpr bool needs_barrier(GLbitfield barrier) { return false; };
   static constexpr bool needs_barrier(GLbitfield barrier) { return false; };
@@ -48,30 +47,32 @@ public:
   void mark_incoherent(bool wrote);
   void mark_incoherent(bool wrote);
 #endif
 #endif
 
 
+private:
   // This is the GL "name" of the texture object.
   // This is the GL "name" of the texture object.
   GLuint _index;
   GLuint _index;
 
 
   // This is only used for buffer textures.
   // This is only used for buffer textures.
   GLuint _buffer;
   GLuint _buffer;
 
 
-#ifndef OPENGLES
-  // This is the bindless "handle" to the texture object.
-  GLuint64 _handle;
-  bool _handle_resident;
-#endif
+public:
+  // Multiview textures have multiple of the above.  For a single-view texture,
+  // these are simply pointers to the above fields.
+  int _num_views;
+  GLuint *_indices;
+  GLuint *_buffers;
 
 
   // These are the parameters that we specified with the last glTexImage2D()
   // These are the parameters that we specified with the last glTexImage2D()
   // or glTexStorage2D() call.  If none of these have changed, we can reload
   // or glTexStorage2D() call.  If none of these have changed, we can reload
   // the texture image with a glTexSubImage2D().
   // the texture image with a glTexSubImage2D().
   bool _has_storage;
   bool _has_storage;
-  bool _simple_loaded;
   bool _immutable;
   bool _immutable;
-  bool _uses_mipmaps;
+  bool _may_reload_with_mipmaps;
   bool _generate_mipmaps;
   bool _generate_mipmaps;
   GLint _internal_format;
   GLint _internal_format;
   GLsizei _width;
   GLsizei _width;
   GLsizei _height;
   GLsizei _height;
   GLsizei _depth;
   GLsizei _depth;
+  int _num_levels;
   GLenum _target;
   GLenum _target;
   SamplerState _active_sampler;
   SamplerState _active_sampler;
 
 

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

@@ -250,16 +250,6 @@ ConfigVariableBool gl_immutable_texture_storage
             "for each texture.  This improves runtime performance, but "
             "for each texture.  This improves runtime performance, but "
             "changing the size or type of a texture will be slower."));
             "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
 ConfigVariableBool gl_enable_memory_barriers
   ("gl-enable-memory-barriers", true,
   ("gl-enable-memory-barriers", true,
    PRC_DESC("If this is set, Panda will make sure that every write "
    PRC_DESC("If this is set, Panda will make sure that every write "

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

@@ -74,7 +74,6 @@ extern ConfigVariableBool gl_cube_map_seamless;
 extern ConfigVariableBool gl_dump_compiled_shaders;
 extern ConfigVariableBool gl_dump_compiled_shaders;
 extern ConfigVariableBool gl_validate_shaders;
 extern ConfigVariableBool gl_validate_shaders;
 extern ConfigVariableBool gl_immutable_texture_storage;
 extern ConfigVariableBool gl_immutable_texture_storage;
-extern ConfigVariableBool gl_use_bindless_texture;
 extern ConfigVariableBool gl_enable_memory_barriers;
 extern ConfigVariableBool gl_enable_memory_barriers;
 extern ConfigVariableBool gl_vertex_array_objects;
 extern ConfigVariableBool gl_vertex_array_objects;
 extern ConfigVariableBool gl_fixed_vertex_attrib_locations;
 extern ConfigVariableBool gl_fixed_vertex_attrib_locations;

+ 9 - 11
panda/src/gobj/preparedGraphicsObjects.cxx

@@ -242,7 +242,7 @@ void PreparedGraphicsObjects::
 release_texture(TextureContext *tc) {
 release_texture(TextureContext *tc) {
   ReMutexHolder holder(_lock);
   ReMutexHolder holder(_lock);
 
 
-  tc->get_texture()->clear_prepared(tc->get_view(), this);
+  tc->get_texture()->clear_prepared(this);
 
 
   // We have to set the Texture pointer to NULL at this point, since the
   // We have to set the Texture pointer to NULL at this point, since the
   // Texture itself might destruct at any time after it has been released.
   // Texture itself might destruct at any time after it has been released.
@@ -275,7 +275,7 @@ release_all_textures() {
   int num_textures = (int)_prepared_textures.size() + (int)_enqueued_textures.size();
   int num_textures = (int)_prepared_textures.size() + (int)_enqueued_textures.size();
 
 
   for (TextureContext *tc : _prepared_textures) {
   for (TextureContext *tc : _prepared_textures) {
-    tc->get_texture()->clear_prepared(tc->get_view(), this);
+    tc->get_texture()->clear_prepared(this);
     tc->_object = nullptr;
     tc->_object = nullptr;
 
 
     _released_textures.push_back(tc);
     _released_textures.push_back(tc);
@@ -332,13 +332,13 @@ get_num_prepared_textures() const {
  * the TextureContext will be deleted.
  * the TextureContext will be deleted.
  */
  */
 TextureContext *PreparedGraphicsObjects::
 TextureContext *PreparedGraphicsObjects::
-prepare_texture_now(Texture *tex, int view, GraphicsStateGuardianBase *gsg) {
+prepare_texture_now(Texture *tex, GraphicsStateGuardianBase *gsg) {
   ReMutexHolder holder(_lock);
   ReMutexHolder holder(_lock);
 
 
   // Ask the GSG to create a brand new TextureContext.  There might be several
   // Ask the GSG to create a brand new TextureContext.  There might be several
   // GSG's sharing the same set of textures; if so, it doesn't matter which of
   // GSG's sharing the same set of textures; if so, it doesn't matter which of
   // them creates the context (since they're all shared anyway).
   // them creates the context (since they're all shared anyway).
-  TextureContext *tc = gsg->prepare_texture(tex, view);
+  TextureContext *tc = gsg->prepare_texture(tex);
 
 
   if (tc != nullptr) {
   if (tc != nullptr) {
     bool prepared = _prepared_textures.insert(tc).second;
     bool prepared = _prepared_textures.insert(tc).second;
@@ -1513,13 +1513,11 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) {
        qti != _enqueued_textures.end();
        qti != _enqueued_textures.end();
        ++qti) {
        ++qti) {
     Texture *tex = qti->first;
     Texture *tex = qti->first;
-    for (int view = 0; view < tex->get_num_views(); ++view) {
-      TextureContext *tc = tex->prepare_now(view, this, gsg);
-      if (tc != nullptr) {
-        gsg->update_texture(tc, true);
-        if (view == 0 && qti->second != nullptr) {
-          qti->second->set_result(tc);
-        }
+    TextureContext *tc = tex->prepare_now(this, gsg);
+    if (tc != nullptr) {
+      gsg->update_texture(tc, true);
+      if (qti->second != nullptr) {
+        qti->second->set_result(tc);
       }
       }
     }
     }
   }
   }

+ 1 - 1
panda/src/gobj/preparedGraphicsObjects.h

@@ -82,7 +82,7 @@ PUBLISHED:
   int get_num_queued_textures() const;
   int get_num_queued_textures() const;
   int get_num_prepared_textures() const;
   int get_num_prepared_textures() const;
 
 
-  TextureContext *prepare_texture_now(Texture *tex, int view,
+  TextureContext *prepare_texture_now(Texture *tex,
                                       GraphicsStateGuardianBase *gsg);
                                       GraphicsStateGuardianBase *gsg);
 
 
   void enqueue_sampler(const SamplerState &sampler);
   void enqueue_sampler(const SamplerState &sampler);

+ 105 - 131
panda/src/gobj/texture.cxx

@@ -1513,6 +1513,39 @@ get_image_modified_pages(UpdateSeq since, int n) const {
     return result;
     return result;
   }
   }
 
 
+  if (n > 0 && cdata->_texture_type == Texture::TT_3d_texture) {
+    // Don't bother handling this special case, just consider all mipmap pages
+    // modified.
+    result.set_range(0, do_get_expected_mipmap_num_pages(cdata, n));
+    return result;
+  }
+
+  size_t num_pages = cdata->_z_size * cdata->_num_views;
+  for (const ModifiedPageRange &range : cdata->_modified_pages) {
+    if (range._z_begin >= num_pages) {
+      break;
+    }
+    if (since < range._modified) {
+      result.set_range(range._z_begin, std::min(range._z_end, num_pages) - range._z_begin);
+    }
+  }
+
+  return result;
+}
+
+/**
+ * Like get_image_modified_pages, but returns the result for a particular view.
+ */
+SparseArray Texture::
+get_view_modified_pages(UpdateSeq since, int view, int n) const {
+  CDReader cdata(_cycler);
+
+  SparseArray result;
+  if (since == cdata->_image_modified) {
+    // Early-out since no range is more recent than _image_modified.
+    return result;
+  }
+
   if (n > 0 && cdata->_texture_type == Texture::TT_3d_texture) {
   if (n > 0 && cdata->_texture_type == Texture::TT_3d_texture) {
     // Don't bother handling this special case, just consider all mipmap pages
     // Don't bother handling this special case, just consider all mipmap pages
     // modified.
     // modified.
@@ -1520,12 +1553,17 @@ get_image_modified_pages(UpdateSeq since, int n) const {
     return result;
     return result;
   }
   }
 
 
+  size_t offset = cdata->_z_size * view;
   for (const ModifiedPageRange &range : cdata->_modified_pages) {
   for (const ModifiedPageRange &range : cdata->_modified_pages) {
-    if (range._z_begin >= cdata->_z_size) {
+    if (range._z_end <= offset) {
+      continue;
+    }
+    if (range._z_begin >= offset + (size_t)cdata->_z_size) {
       break;
       break;
     }
     }
     if (since < range._modified) {
     if (since < range._modified) {
-      result.set_range(range._z_begin, std::min(range._z_end, (size_t)cdata->_z_size) - range._z_begin);
+      size_t begin = std::max(range._z_begin, offset) - offset;
+      result.set_range(begin, std::min(range._z_end - offset, (size_t)cdata->_z_size) - begin);
     }
     }
   }
   }
 
 
@@ -1553,9 +1591,9 @@ prepare(PreparedGraphicsObjects *prepared_objects) {
 bool Texture::
 bool Texture::
 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
-  PreparedViews::const_iterator pvi;
-  pvi = _prepared_views.find(prepared_objects);
-  if (pvi != _prepared_views.end()) {
+  Contexts::const_iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
     return true;
     return true;
   }
   }
   return prepared_objects->is_texture_queued(this);
   return prepared_objects->is_texture_queued(this);
@@ -1569,24 +1607,11 @@ is_prepared(PreparedGraphicsObjects *prepared_objects) const {
 bool Texture::
 bool Texture::
 was_image_modified(PreparedGraphicsObjects *prepared_objects) const {
 was_image_modified(PreparedGraphicsObjects *prepared_objects) const {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
-  CDReader cdata(_cycler);
-
-  PreparedViews::const_iterator pvi;
-  pvi = _prepared_views.find(prepared_objects);
-  if (pvi != _prepared_views.end()) {
-    const Contexts &contexts = (*pvi).second;
-    for (int view = 0; view < cdata->_num_views; ++view) {
-      Contexts::const_iterator ci;
-      ci = contexts.find(view);
-      if (ci == contexts.end()) {
-        return true;
-      }
-      TextureContext *tc = (*ci).second;
-      if (tc->was_image_modified()) {
-        return true;
-      }
-    }
-    return false;
+  Contexts::const_iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    TextureContext *tc = (*ci).second;
+    return tc->was_image_modified();
   }
   }
   return true;
   return true;
 }
 }
@@ -1601,24 +1626,13 @@ was_image_modified(PreparedGraphicsObjects *prepared_objects) const {
 size_t Texture::
 size_t Texture::
 get_data_size_bytes(PreparedGraphicsObjects *prepared_objects) const {
 get_data_size_bytes(PreparedGraphicsObjects *prepared_objects) const {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
-  CDReader cdata(_cycler);
-
-  PreparedViews::const_iterator pvi;
-  size_t total_size = 0;
-  pvi = _prepared_views.find(prepared_objects);
-  if (pvi != _prepared_views.end()) {
-    const Contexts &contexts = (*pvi).second;
-    for (int view = 0; view < cdata->_num_views; ++view) {
-      Contexts::const_iterator ci;
-      ci = contexts.find(view);
-      if (ci != contexts.end()) {
-        TextureContext *tc = (*ci).second;
-        total_size += tc->get_data_size_bytes();
-      }
-    }
+  Contexts::const_iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    TextureContext *tc = (*ci).second;
+    return tc->get_data_size_bytes();
   }
   }
-
-  return total_size;
+  return 0;
 }
 }
 
 
 /**
 /**
@@ -1628,24 +1642,13 @@ get_data_size_bytes(PreparedGraphicsObjects *prepared_objects) const {
 bool Texture::
 bool Texture::
 get_active(PreparedGraphicsObjects *prepared_objects) const {
 get_active(PreparedGraphicsObjects *prepared_objects) const {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
-  CDReader cdata(_cycler);
-
-  PreparedViews::const_iterator pvi;
-  pvi = _prepared_views.find(prepared_objects);
-  if (pvi != _prepared_views.end()) {
-    const Contexts &contexts = (*pvi).second;
-    for (int view = 0; view < cdata->_num_views; ++view) {
-      Contexts::const_iterator ci;
-      ci = contexts.find(view);
-      if (ci != contexts.end()) {
-        TextureContext *tc = (*ci).second;
-        if (tc->get_active()) {
-          return true;
-        }
-      }
-    }
+  Contexts::const_iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    TextureContext *tc = (*ci).second;
+    return tc->get_active();
   }
   }
-  return false;
+  return 0;
 }
 }
 
 
 /**
 /**
@@ -1655,24 +1658,13 @@ get_active(PreparedGraphicsObjects *prepared_objects) const {
 bool Texture::
 bool Texture::
 get_resident(PreparedGraphicsObjects *prepared_objects) const {
 get_resident(PreparedGraphicsObjects *prepared_objects) const {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
-  CDReader cdata(_cycler);
-
-  PreparedViews::const_iterator pvi;
-  pvi = _prepared_views.find(prepared_objects);
-  if (pvi != _prepared_views.end()) {
-    const Contexts &contexts = (*pvi).second;
-    for (int view = 0; view < cdata->_num_views; ++view) {
-      Contexts::const_iterator ci;
-      ci = contexts.find(view);
-      if (ci != contexts.end()) {
-        TextureContext *tc = (*ci).second;
-        if (tc->get_resident()) {
-          return true;
-        }
-      }
-    }
+  Contexts::const_iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    TextureContext *tc = (*ci).second;
+    return tc->get_resident();
   }
   }
-  return false;
+  return 0;
 }
 }
 
 
 /**
 /**
@@ -1681,20 +1673,15 @@ get_resident(PreparedGraphicsObjects *prepared_objects) const {
  */
  */
 bool Texture::
 bool Texture::
 release(PreparedGraphicsObjects *prepared_objects) {
 release(PreparedGraphicsObjects *prepared_objects) {
-  MutexHolder holder(_lock);
-  PreparedViews::iterator pvi;
-  pvi = _prepared_views.find(prepared_objects);
-  if (pvi != _prepared_views.end()) {
-    Contexts temp;
-    temp.swap((*pvi).second);
-    Contexts::iterator ci;
-    for (ci = temp.begin(); ci != temp.end(); ++ci) {
-      TextureContext *tc = (*ci).second;
-      if (tc != nullptr) {
-        prepared_objects->release_texture(tc);
-      }
+  Contexts::iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    TextureContext *tc = (*ci).second;
+    if (tc != nullptr) {
+      prepared_objects->release_texture(tc);
+    } else {
+      _contexts.erase(ci);
     }
     }
-    _prepared_views.erase(pvi);
   }
   }
 
 
   // Maybe it wasn't prepared yet, but it's about to be.
   // Maybe it wasn't prepared yet, but it's about to be.
@@ -1709,25 +1696,19 @@ int Texture::
 release_all() {
 release_all() {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
 
 
-  // We have to traverse a copy of the _prepared_views list, because the
+  // We have to traverse a copy of the _contexts list, because the
   // PreparedGraphicsObjects object will call clear_prepared() in response to
   // PreparedGraphicsObjects object will call clear_prepared() in response to
   // each release_texture(), and we don't want to be modifying the
   // each release_texture(), and we don't want to be modifying the
-  // _prepared_views list while we're traversing it.
-  PreparedViews temp;
-  temp.swap(_prepared_views);
-  int num_freed = (int)temp.size();
+  // _contexts list while we're traversing it.
+  Contexts temp = _contexts;
+  int num_freed = (int)_contexts.size();
 
 
-  PreparedViews::iterator pvi;
-  for (pvi = temp.begin(); pvi != temp.end(); ++pvi) {
-    PreparedGraphicsObjects *prepared_objects = (*pvi).first;
-    Contexts temp;
-    temp.swap((*pvi).second);
-    Contexts::iterator ci;
-    for (ci = temp.begin(); ci != temp.end(); ++ci) {
-      TextureContext *tc = (*ci).second;
-      if (tc != nullptr) {
-        prepared_objects->release_texture(tc);
-      }
+  Contexts::const_iterator ci;
+  for (ci = temp.begin(); ci != temp.end(); ++ci) {
+    PreparedGraphicsObjects *prepared_objects = (*ci).first;
+    TextureContext *tc = (*ci).second;
+    if (tc != nullptr) {
+      prepared_objects->release_texture(tc);
     }
     }
   }
   }
 
 
@@ -2088,29 +2069,31 @@ set_orig_file_size(int x, int y, int z) {
  * be rendered.
  * be rendered.
  */
  */
 TextureContext *Texture::
 TextureContext *Texture::
-prepare_now(int view,
-            PreparedGraphicsObjects *prepared_objects,
+prepare_now(PreparedGraphicsObjects *prepared_objects,
             GraphicsStateGuardianBase *gsg) {
             GraphicsStateGuardianBase *gsg) {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
-  CDReader cdata(_cycler);
 
 
-  // Don't exceed the actual number of views.
-  view = max(min(view, cdata->_num_views - 1), 0);
-
-  // Get the list of PreparedGraphicsObjects for this view.
-  Contexts &contexts = _prepared_views[prepared_objects];
-  Contexts::const_iterator pvi;
-  pvi = contexts.find(view);
-  if (pvi != contexts.end()) {
-    return (*pvi).second;
+  Contexts::const_iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    return (*ci).second;
   }
   }
 
 
-  TextureContext *tc = prepared_objects->prepare_texture_now(this, view, gsg);
-  contexts[view] = tc;
+  TextureContext *tc = prepared_objects->prepare_texture_now(this, gsg);
+  _contexts[prepared_objects] = tc;
 
 
   return tc;
   return tc;
 }
 }
 
 
+/**
+ * @deprecated See prepare_now() without a view parameter.
+ */
+TextureContext *Texture::
+prepare_now(int view, PreparedGraphicsObjects *prepared_objects,
+            GraphicsStateGuardianBase *gsg) {
+  return prepare_now(prepared_objects, gsg);
+}
+
 /**
 /**
  * Returns the smallest power of 2 greater than or equal to value.
  * Returns the smallest power of 2 greater than or equal to value.
  */
  */
@@ -9277,20 +9260,11 @@ read_dds_level_bc5(Texture *tex, CData *cdata, const DDSHeader &header, int n, i
  * never be called by user code.
  * never be called by user code.
  */
  */
 void Texture::
 void Texture::
-clear_prepared(int view, PreparedGraphicsObjects *prepared_objects) {
-  PreparedViews::iterator pvi;
-  pvi = _prepared_views.find(prepared_objects);
-  if (pvi != _prepared_views.end()) {
-    Contexts &contexts = (*pvi).second;
-    Contexts::iterator ci;
-    ci = contexts.find(view);
-    if (ci != contexts.end()) {
-      contexts.erase(ci);
-    }
-
-    if (contexts.empty()) {
-      _prepared_views.erase(pvi);
-    }
+clear_prepared(PreparedGraphicsObjects *prepared_objects) {
+  Contexts::iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    _contexts.erase(ci);
   }
   }
 }
 }
 
 

+ 6 - 4
panda/src/gobj/texture.h

@@ -528,6 +528,7 @@ PUBLISHED:
   MAKE_PROPERTY(image_modified, get_image_modified);
   MAKE_PROPERTY(image_modified, get_image_modified);
 
 
   SparseArray get_image_modified_pages(UpdateSeq since, int n = 0) const;
   SparseArray get_image_modified_pages(UpdateSeq since, int n = 0) const;
+  SparseArray get_view_modified_pages(UpdateSeq since, int view, int n = 0) const;
 
 
   INLINE bool has_auto_texture_scale() const;
   INLINE bool has_auto_texture_scale() const;
   INLINE AutoTextureScale get_auto_texture_scale() const;
   INLINE AutoTextureScale get_auto_texture_scale() const;
@@ -597,6 +598,8 @@ PUBLISHED:
   MAKE_PROPERTY(post_load_store_cache, get_post_load_store_cache,
   MAKE_PROPERTY(post_load_store_cache, get_post_load_store_cache,
                                        set_post_load_store_cache);
                                        set_post_load_store_cache);
 
 
+  TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
+                              GraphicsStateGuardianBase *gsg);
   TextureContext *prepare_now(int view,
   TextureContext *prepare_now(int view,
                               PreparedGraphicsObjects *prepared_objects,
                               PreparedGraphicsObjects *prepared_objects,
                               GraphicsStateGuardianBase *gsg);
                               GraphicsStateGuardianBase *gsg);
@@ -859,7 +862,7 @@ private:
                                       const DDSHeader &header,
                                       const DDSHeader &header,
                                       int n, std::istream &in);
                                       int n, std::istream &in);
 
 
-  void clear_prepared(int view, PreparedGraphicsObjects *prepared_objects);
+  void clear_prepared(PreparedGraphicsObjects *prepared_objects);
 
 
   static void consider_downgrade(PNMImage &pnmimage, int num_channels, const std::string &name);
   static void consider_downgrade(PNMImage &pnmimage, int num_channels, const std::string &name);
 
 
@@ -1066,9 +1069,8 @@ protected:
   // conversely keeps a list (a set) of all the Textures that have been
   // conversely keeps a list (a set) of all the Textures that have been
   // prepared there.  When either destructs, it removes itself from the
   // prepared there.  When either destructs, it removes itself from the
   // other's list.
   // other's list.
-  typedef pmap<int, TextureContext *> Contexts;
-  typedef pmap<PreparedGraphicsObjects *, Contexts> PreparedViews;
-  PreparedViews _prepared_views;
+  typedef pmap<PreparedGraphicsObjects *, TextureContext *> Contexts;
+  Contexts _contexts;
 
 
   // It is common, when using normal maps, specular maps, gloss maps, and
   // It is common, when using normal maps, specular maps, gloss maps, and
   // such, to use a file naming convention where the filenames of the special
   // such, to use a file naming convention where the filenames of the special

+ 13 - 7
panda/src/gobj/textureContext.I

@@ -15,10 +15,9 @@
  *
  *
  */
  */
 INLINE TextureContext::
 INLINE TextureContext::
-TextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
+TextureContext(PreparedGraphicsObjects *pgo, Texture *tex) :
   BufferContext(&pgo->_texture_residency, tex),
   BufferContext(&pgo->_texture_residency, tex),
-  AdaptiveLruPage(0),
-  _view(view)
+  AdaptiveLruPage(0)
 {
 {
 }
 }
 
 
@@ -31,15 +30,13 @@ get_texture() const {
 }
 }
 
 
 /**
 /**
- * Returns the specific view of a multiview texture this context represents.
- * In the usual case, with a non-multiview texture, this will be 0.
+ * @deprecated since 1.11.0: always returns 0.
  */
  */
 INLINE int TextureContext::
 INLINE int TextureContext::
 get_view() const {
 get_view() const {
-  return _view;
+  return 0;
 }
 }
 
 
-
 /**
 /**
  * Returns true if the texture properties or image have been modified since
  * Returns true if the texture properties or image have been modified since
  * the last time mark_loaded() was called.
  * the last time mark_loaded() was called.
@@ -103,6 +100,15 @@ get_image_modified_pages(int n) const {
   return get_texture()->get_image_modified_pages(_image_modified, n);
   return get_texture()->get_image_modified_pages(_image_modified, n);
 }
 }
 
 
+/**
+ * Returns a SparseArray indicating which pages of the texture have been
+ * modified since the last call to mark_loaded().
+ */
+INLINE SparseArray TextureContext::
+get_view_modified_pages(int view, int n) const {
+  return get_texture()->get_view_modified_pages(_image_modified, view, n);
+}
+
 /**
 /**
  * Should be called (usually by a derived class) when the on-card size of this
  * Should be called (usually by a derived class) when the on-card size of this
  * object has changed.
  * object has changed.

+ 2 - 2
panda/src/gobj/textureContext.h

@@ -32,7 +32,7 @@
  */
  */
 class EXPCL_PANDA_GOBJ TextureContext : public BufferContext, public AdaptiveLruPage {
 class EXPCL_PANDA_GOBJ TextureContext : public BufferContext, public AdaptiveLruPage {
 public:
 public:
-  INLINE TextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view);
+  INLINE TextureContext(PreparedGraphicsObjects *pgo, Texture *tex);
 
 
 PUBLISHED:
 PUBLISHED:
   INLINE Texture *get_texture() const;
   INLINE Texture *get_texture() const;
@@ -49,6 +49,7 @@ PUBLISHED:
   INLINE UpdateSeq get_image_modified() const;
   INLINE UpdateSeq get_image_modified() const;
 
 
   INLINE SparseArray get_image_modified_pages(int n = 0) const;
   INLINE SparseArray get_image_modified_pages(int n = 0) const;
+  INLINE SparseArray get_view_modified_pages(int view, int n = 0) const;
 
 
 public:
 public:
   INLINE void update_data_size_bytes(size_t new_data_size_bytes);
   INLINE void update_data_size_bytes(size_t new_data_size_bytes);
@@ -60,7 +61,6 @@ public:
   virtual void write(std::ostream &out, int indent_level) const;
   virtual void write(std::ostream &out, int indent_level) const;
 
 
 private:
 private:
-  int _view;
   UpdateSeq _properties_modified;
   UpdateSeq _properties_modified;
   UpdateSeq _image_modified;
   UpdateSeq _image_modified;
 
 

+ 1 - 1
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -147,7 +147,7 @@ public:
   virtual PreparedGraphicsObjects *get_prepared_objects()=0;
   virtual PreparedGraphicsObjects *get_prepared_objects()=0;
 #endif
 #endif
 
 
-  virtual TextureContext *prepare_texture(Texture *tex, int view)=0;
+  virtual TextureContext *prepare_texture(Texture *tex)=0;
   virtual bool update_texture(TextureContext *tc, bool force)=0;
   virtual bool update_texture(TextureContext *tc, bool force)=0;
   virtual void release_texture(TextureContext *tc)=0;
   virtual void release_texture(TextureContext *tc)=0;
   virtual void release_textures(const pvector<TextureContext *> &contexts)=0;
   virtual void release_textures(const pvector<TextureContext *> &contexts)=0;

+ 148 - 125
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -1354,12 +1354,12 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
 
 
   tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgba);
   tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgba);
 
 
-  TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
+  TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   nassertr(tc != nullptr, false);
   nassertr(tc != nullptr, false);
   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
 
 
   GLTexture *gltex = &gtc->_gltex;
   GLTexture *gltex = &gtc->_gltex;
-  if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), 1)) {
+  if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), tex->get_num_views(), 1)) {
     return false;
     return false;
   }
   }
   LColor border_color = tex->get_border_color();
   LColor border_color = tex->get_border_color();
@@ -1369,7 +1369,7 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
   gltex->border_color.v[2] = border_color[2];
   gltex->border_color.v[2] = border_color[2];
   gltex->border_color.v[3] = border_color[3];
   gltex->border_color.v[3] = border_color[3];
 
 
-  PIXEL *ip = gltex->levels[0].pixmap + gltex->xsize * gltex->ysize;
+  PIXEL *ip = gltex->views[view].levels[0].pixmap + gltex->xsize * gltex->ysize;
   PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
   PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
   for (int y = 0; y < gltex->ysize; ++y) {
   for (int y = 0; y < gltex->ysize; ++y) {
     ip -= gltex->xsize;
     ip -= gltex->xsize;
@@ -1602,7 +1602,7 @@ set_state_and_transform(const RenderState *target,
  * call Texture::prepare().
  * call Texture::prepare().
  */
  */
 TextureContext *TinyGraphicsStateGuardian::
 TextureContext *TinyGraphicsStateGuardian::
-prepare_texture(Texture *tex, int view) {
+prepare_texture(Texture *tex) {
   switch (tex->get_texture_type()) {
   switch (tex->get_texture_type()) {
   case Texture::TT_1d_texture:
   case Texture::TT_1d_texture:
   case Texture::TT_2d_texture:
   case Texture::TT_2d_texture:
@@ -1629,7 +1629,7 @@ prepare_texture(Texture *tex, int view) {
   }
   }
   */
   */
 
 
-  TinyTextureContext *gtc = new TinyTextureContext(_prepared_objects, tex, view);
+  TinyTextureContext *gtc = new TinyTextureContext(_prepared_objects, tex);
 
 
   return gtc;
   return gtc;
 }
 }
@@ -1652,7 +1652,7 @@ update_texture(TextureContext *tc, bool force) {
 
 
   GLTexture *gltex = &gtc->_gltex;
   GLTexture *gltex = &gtc->_gltex;
 
 
-  if (gtc->was_image_modified() || gltex->num_levels == 0) {
+  if (gtc->was_image_modified() || gltex->num_views == 0 || gltex->num_levels == 0) {
     // If the texture image was modified, reload the texture.
     // If the texture image was modified, reload the texture.
     Texture *tex = gtc->get_texture();
     Texture *tex = gtc->get_texture();
     bool okflag = upload_texture(gtc, force, tex->uses_mipmaps());
     bool okflag = upload_texture(gtc, force, tex->uses_mipmaps());
@@ -1678,7 +1678,7 @@ update_texture(TextureContext *tc, bool force) {
  * (and if get_incomplete_render() is true).
  * (and if get_incomplete_render() is true).
  */
  */
 bool TinyGraphicsStateGuardian::
 bool TinyGraphicsStateGuardian::
-update_texture(TextureContext *tc, bool force, int stage_index, bool uses_mipmaps) {
+update_texture(TextureContext *tc, int view, bool force, int stage_index, bool uses_mipmaps) {
   if (!update_texture(tc, force)) {
   if (!update_texture(tc, force)) {
     return false;
     return false;
   }
   }
@@ -1699,8 +1699,15 @@ update_texture(TextureContext *tc, bool force, int stage_index, bool uses_mipmap
 
 
   _c->current_textures[stage_index] = gltex;
   _c->current_textures[stage_index] = gltex;
 
 
+  if (view < 0) {
+    view = 0;
+  }
+  if (view >= gltex->num_views) {
+    view = gltex->num_views - 1;
+  }
+
   ZTextureDef *texture_def = &_c->zb->current_textures[stage_index];
   ZTextureDef *texture_def = &_c->zb->current_textures[stage_index];
-  texture_def->levels = gltex->levels;
+  texture_def->levels = gltex->views[view].levels;
   texture_def->s_max = gltex->s_max;
   texture_def->s_max = gltex->s_max;
   texture_def->t_max = gltex->t_max;
   texture_def->t_max = gltex->t_max;
 
 
@@ -2155,7 +2162,7 @@ do_issue_texture() {
     nassertv(texture != nullptr);
     nassertv(texture != nullptr);
 
 
     int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
     int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
-    TextureContext *tc = texture->prepare_now(view, _prepared_objects, this);
+    TextureContext *tc = texture->prepare_now(_prepared_objects, this);
     if (tc == nullptr) {
     if (tc == nullptr) {
       // Something wrong with this texture; skip it.
       // Something wrong with this texture; skip it.
       return;
       return;
@@ -2165,7 +2172,7 @@ do_issue_texture() {
     const SamplerState &sampler = _target_texture->get_on_sampler(stage);
     const SamplerState &sampler = _target_texture->get_on_sampler(stage);
 
 
     // Then, turn on the current texture mode.
     // Then, turn on the current texture mode.
-    if (!update_texture(tc, false, si, sampler.uses_mipmaps())) {
+    if (!update_texture(tc, view, false, si, sampler.uses_mipmaps())) {
       return;
       return;
     }
     }
 
 
@@ -2418,7 +2425,7 @@ upload_texture(TinyTextureContext *gtc, bool force, bool uses_mipmaps) {
       << num_levels << ", uses_mipmaps = " << uses_mipmaps << "\n";
       << num_levels << ", uses_mipmaps = " << uses_mipmaps << "\n";
   }
   }
 
 
-  if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), num_levels)) {
+  if (!setup_gltex(gltex, tex->get_x_size(), tex->get_y_size(), tex->get_num_views(), num_levels)) {
     return false;
     return false;
   }
   }
   LColor border_color = tex->get_border_color();
   LColor border_color = tex->get_border_color();
@@ -2432,78 +2439,80 @@ upload_texture(TinyTextureContext *gtc, bool force, bool uses_mipmaps) {
   int xsize = gltex->xsize;
   int xsize = gltex->xsize;
   int ysize = gltex->ysize;
   int ysize = gltex->ysize;
 
 
-  for (int level = 0; level < gltex->num_levels; ++level) {
-    ZTextureLevel *dest = &gltex->levels[level];
-
-    if (tex->has_ram_mipmap_image(level)) {
-      switch (tex->get_format()) {
-      case Texture::F_rgb:
-      case Texture::F_rgb5:
-      case Texture::F_rgb8:
-      case Texture::F_rgb12:
-      case Texture::F_rgb332:
-        copy_rgb_image(dest, xsize, ysize, gtc, level);
-        break;
-
-      case Texture::F_rgba:
-      case Texture::F_rgbm:
-      case Texture::F_rgba4:
-      case Texture::F_rgba5:
-      case Texture::F_rgba8:
-      case Texture::F_rgba12:
-      case Texture::F_rgba16:
-      case Texture::F_rgba32:
-        copy_rgba_image(dest, xsize, ysize, gtc, level);
-        break;
-
-      case Texture::F_luminance:
-        copy_lum_image(dest, xsize, ysize, gtc, level);
-        break;
-
-      case Texture::F_red:
-        copy_one_channel_image(dest, xsize, ysize, gtc, level, 0);
-        break;
-
-      case Texture::F_green:
-        copy_one_channel_image(dest, xsize, ysize, gtc, level, 1);
-        break;
-
-      case Texture::F_blue:
-        copy_one_channel_image(dest, xsize, ysize, gtc, level, 2);
-        break;
-
-      case Texture::F_alpha:
-        copy_alpha_image(dest, xsize, ysize, gtc, level);
-        break;
-
-      case Texture::F_luminance_alphamask:
-      case Texture::F_luminance_alpha:
-        copy_la_image(dest, xsize, ysize, gtc, level);
-        break;
-
-      default:
-        tinydisplay_cat.error()
-          << "Unsupported texture format "
-          << tex->get_format() << "!\n";
-        return false;
-      }
-    } else {
-      // Fill the mipmap with a solid color.
-      LColor scaled = tex->get_clear_color().fmin(LColor(1)).fmax(LColor::zero());
-      scaled *= 255;
-      unsigned int clear = RGBA8_TO_PIXEL((int)scaled[0], (int)scaled[1],
-                                          (int)scaled[2], (int)scaled[3]);
-      unsigned int *dpix = (unsigned int *)dest->pixmap;
-      int pixel_count = xsize * ysize;
-      while (pixel_count-- > 0) {
-        *dpix = clear;
-        ++dpix;
+  for (int view = 0; view < gltex->num_views; ++view) {
+    for (int level = 0; level < gltex->num_levels; ++level) {
+      ZTextureLevel *dest = &gltex->views[view].levels[level];
+
+      if (tex->has_ram_mipmap_image(level)) {
+        switch (tex->get_format()) {
+        case Texture::F_rgb:
+        case Texture::F_rgb5:
+        case Texture::F_rgb8:
+        case Texture::F_rgb12:
+        case Texture::F_rgb332:
+          copy_rgb_image(dest, xsize, ysize, gtc, view, level);
+          break;
+
+        case Texture::F_rgba:
+        case Texture::F_rgbm:
+        case Texture::F_rgba4:
+        case Texture::F_rgba5:
+        case Texture::F_rgba8:
+        case Texture::F_rgba12:
+        case Texture::F_rgba16:
+        case Texture::F_rgba32:
+          copy_rgba_image(dest, xsize, ysize, gtc, view, level);
+          break;
+
+        case Texture::F_luminance:
+          copy_lum_image(dest, xsize, ysize, gtc, view, level);
+          break;
+
+        case Texture::F_red:
+          copy_one_channel_image(dest, xsize, ysize, gtc, view, level, 0);
+          break;
+
+        case Texture::F_green:
+          copy_one_channel_image(dest, xsize, ysize, gtc, view, level, 1);
+          break;
+
+        case Texture::F_blue:
+          copy_one_channel_image(dest, xsize, ysize, gtc, view, level, 2);
+          break;
+
+        case Texture::F_alpha:
+          copy_alpha_image(dest, xsize, ysize, gtc, view, level);
+          break;
+
+        case Texture::F_luminance_alphamask:
+        case Texture::F_luminance_alpha:
+          copy_la_image(dest, xsize, ysize, gtc, view, level);
+          break;
+
+        default:
+          tinydisplay_cat.error()
+            << "Unsupported texture format "
+            << tex->get_format() << "!\n";
+          return false;
+        }
+      } else {
+        // Fill the mipmap with a solid color.
+        LColor scaled = tex->get_clear_color().fmin(LColor(1)).fmax(LColor::zero());
+        scaled *= 255;
+        unsigned int clear = RGBA8_TO_PIXEL((int)scaled[0], (int)scaled[1],
+                                            (int)scaled[2], (int)scaled[3]);
+        unsigned int *dpix = (unsigned int *)dest->pixmap;
+        int pixel_count = xsize * ysize;
+        while (pixel_count-- > 0) {
+          *dpix = clear;
+          ++dpix;
+        }
       }
       }
-    }
 
 
-    bytecount += xsize * ysize * 4;
-    xsize = max(xsize >> 1, 1);
-    ysize = max(ysize >> 1, 1);
+      bytecount += xsize * ysize * 4;
+      xsize = max(xsize >> 1, 1);
+      ysize = max(ysize >> 1, 1);
+    }
   }
   }
 
 
   gtc->update_data_size_bytes(bytecount);
   gtc->update_data_size_bytes(bytecount);
@@ -2545,7 +2554,7 @@ upload_simple_texture(TinyTextureContext *gtc) {
       << "loading simple image for " << tex->get_name() << "\n";
       << "loading simple image for " << tex->get_name() << "\n";
   }
   }
 
 
-  if (!setup_gltex(gltex, width, height, 1)) {
+  if (!setup_gltex(gltex, width, height, 1, 1)) {
     return false;
     return false;
   }
   }
   LColor border_color = tex->get_border_color();
   LColor border_color = tex->get_border_color();
@@ -2555,7 +2564,7 @@ upload_simple_texture(TinyTextureContext *gtc) {
   gltex->border_color.v[2] = border_color[2];
   gltex->border_color.v[2] = border_color[2];
   gltex->border_color.v[3] = border_color[3];
   gltex->border_color.v[3] = border_color[3];
 
 
-  ZTextureLevel *dest = &gltex->levels[0];
+  ZTextureLevel *dest = &gltex->views[0].levels[0];
   memcpy(dest->pixmap, image_ptr, image_size);
   memcpy(dest->pixmap, image_ptr, image_size);
 
 
   gtc->mark_loaded();
   gtc->mark_loaded();
@@ -2569,7 +2578,7 @@ upload_simple_texture(TinyTextureContext *gtc) {
  * texture is a valid size, false otherwise.
  * texture is a valid size, false otherwise.
  */
  */
 bool TinyGraphicsStateGuardian::
 bool TinyGraphicsStateGuardian::
-setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
+setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_views, int num_levels) {
   if (x_size == 0 || y_size == 0) {
   if (x_size == 0 || y_size == 0) {
     // A texture without pixels gets turned into a 1x1 texture.
     // A texture without pixels gets turned into a 1x1 texture.
     x_size = 1;
     x_size = 1;
@@ -2588,6 +2597,7 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
     return false;
     return false;
   }
   }
 
 
+  num_views = max(num_views, 1);
   num_levels = min(num_levels, MAX_MIPMAP_LEVELS);
   num_levels = min(num_levels, MAX_MIPMAP_LEVELS);
 
 
   gltex->xsize = x_size;
   gltex->xsize = x_size;
@@ -2601,7 +2611,7 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
   // We allocate one big buffer, large enough to include all the mipmap
   // We allocate one big buffer, large enough to include all the mipmap
   // levels, and index into that buffer for each level.  This cuts down on the
   // levels, and index into that buffer for each level.  This cuts down on the
   // number of individual alloc calls we have to make for each texture.
   // number of individual alloc calls we have to make for each texture.
-  int total_bytecount = 0;
+  int view_size = 0;
 
 
   // Count up the total bytes required for all mipmap levels.
   // Count up the total bytes required for all mipmap levels.
   {
   {
@@ -2609,12 +2619,14 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
     int y = y_size;
     int y = y_size;
     for (int level = 0; level < num_levels; ++level) {
     for (int level = 0; level < num_levels; ++level) {
       int bytecount = x * y * 4;
       int bytecount = x * y * 4;
-      total_bytecount += bytecount;
+      view_size += bytecount;
       x = max((x >> 1), 1);
       x = max((x >> 1), 1);
       y = max((y >> 1), 1);
       y = max((y >> 1), 1);
     }
     }
   }
   }
 
 
+  int total_bytecount = view_size * num_views;
+
   if (gltex->total_bytecount != total_bytecount) {
   if (gltex->total_bytecount != total_bytecount) {
     if (gltex->allocated_buffer != nullptr) {
     if (gltex->allocated_buffer != nullptr) {
       TinyTextureContext::get_class_type().deallocate_array(gltex->allocated_buffer);
       TinyTextureContext::get_class_type().deallocate_array(gltex->allocated_buffer);
@@ -2623,37 +2635,48 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
     gltex->total_bytecount = total_bytecount;
     gltex->total_bytecount = total_bytecount;
   }
   }
 
 
-  char *next_buffer = (char *)gltex->allocated_buffer;
-  char *end_of_buffer = next_buffer + total_bytecount;
-
-  int level = 0;
-  ZTextureLevel *dest = nullptr;
-  while (level < num_levels) {
-    dest = &gltex->levels[level];
-    int bytecount = x_size * y_size * 4;
-    dest->pixmap = (PIXEL *)next_buffer;
-    next_buffer += bytecount;
-    nassertr(next_buffer <= end_of_buffer, false);
+  if (num_views != gltex->num_views) {
+    if (gltex->views != nullptr) {
+      TinyTextureContext::get_class_type().deallocate_array(gltex->views);
+    }
 
 
-    dest->s_mask = ((1 << (s_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
-    dest->t_mask = ((1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
-    dest->s_shift = (ZB_POINT_ST_FRAC_BITS + level);
-    dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits + level);
+    gltex->views = (ZTextureView *)TinyTextureContext::get_class_type().allocate_array(sizeof(ZTextureView) * num_views);
+    gltex->num_views = num_views;
+  }
 
 
-    x_size = max((x_size >> 1), 1);
-    y_size = max((y_size >> 1), 1);
-    s_bits = max(s_bits - 1, 0);
-    t_bits = max(t_bits - 1, 0);
+  char *next_buffer = (char *)gltex->allocated_buffer;
+  char *end_of_buffer = next_buffer + total_bytecount;
 
 
-    ++level;
-  }
+  for (int view = 0; view < num_views; ++view) {
+    int level = 0;
+    ZTextureLevel *dest = nullptr;
+    while (level < num_levels) {
+      dest = &gltex->views[view].levels[level];
+      int bytecount = x_size * y_size * 4;
+      dest->pixmap = (PIXEL *)next_buffer;
+      next_buffer += bytecount;
+      nassertr(next_buffer <= end_of_buffer, false);
+
+      dest->s_mask = ((1 << (s_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
+      dest->t_mask = ((1 << (t_bits + ZB_POINT_ST_FRAC_BITS)) - (1 << ZB_POINT_ST_FRAC_BITS)) << level;
+      dest->s_shift = (ZB_POINT_ST_FRAC_BITS + level);
+      dest->t_shift = (ZB_POINT_ST_FRAC_BITS - s_bits + level);
+
+      x_size = max((x_size >> 1), 1);
+      y_size = max((y_size >> 1), 1);
+      s_bits = max(s_bits - 1, 0);
+      t_bits = max(t_bits - 1, 0);
+
+      ++level;
+    }
 
 
-  // Fill out the remaining mipmap arrays with copies of the last level, so we
-  // don't have to be concerned with running off the end of this array while
-  // scanning out triangles.
-  while (level < MAX_MIPMAP_LEVELS) {
-    gltex->levels[level] = *dest;
-    ++level;
+    // Fill out the remaining mipmap arrays with copies of the last level, so we
+    // don't have to be concerned with running off the end of this array while
+    // scanning out triangles.
+    while (level < MAX_MIPMAP_LEVELS) {
+      gltex->views[view].levels[level] = *dest;
+      ++level;
+    }
   }
   }
 
 
   return true;
   return true;
@@ -2682,7 +2705,7 @@ get_tex_shift(int orig_size) {
  * indicated ZTexture pixmap.
  * indicated ZTexture pixmap.
  */
  */
 void TinyGraphicsStateGuardian::
 void TinyGraphicsStateGuardian::
-copy_lum_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
+copy_lum_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level) {
   Texture *tex = gtc->get_texture();
   Texture *tex = gtc->get_texture();
   nassertv(tex->get_num_components() == 1);
   nassertv(tex->get_num_components() == 1);
   nassertv(tex->get_expected_mipmap_x_size(level) == xsize &&
   nassertv(tex->get_expected_mipmap_x_size(level) == xsize &&
@@ -2692,7 +2715,7 @@ copy_lum_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gt
   nassertv(!src_image.is_null());
   nassertv(!src_image.is_null());
   const unsigned char *src = src_image.p();
   const unsigned char *src = src_image.p();
   size_t view_size = tex->get_ram_mipmap_view_size(level);
   size_t view_size = tex->get_ram_mipmap_view_size(level);
-  src += view_size * gtc->get_view();
+  src += view_size * view;
 
 
   // Component width, and offset to the high-order byte.
   // Component width, and offset to the high-order byte.
   int cw = tex->get_component_width();
   int cw = tex->get_component_width();
@@ -2720,7 +2743,7 @@ copy_lum_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gt
  * indicated ZTexture pixmap.
  * indicated ZTexture pixmap.
  */
  */
 void TinyGraphicsStateGuardian::
 void TinyGraphicsStateGuardian::
-copy_alpha_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
+copy_alpha_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level) {
   Texture *tex = gtc->get_texture();
   Texture *tex = gtc->get_texture();
   nassertv(tex->get_num_components() == 1);
   nassertv(tex->get_num_components() == 1);
 
 
@@ -2728,7 +2751,7 @@ copy_alpha_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *
   nassertv(!src_image.is_null());
   nassertv(!src_image.is_null());
   const unsigned char *src = src_image.p();
   const unsigned char *src = src_image.p();
   size_t view_size = tex->get_ram_mipmap_view_size(level);
   size_t view_size = tex->get_ram_mipmap_view_size(level);
-  src += view_size * gtc->get_view();
+  src += view_size * view;
 
 
   // Component width, and offset to the high-order byte.
   // Component width, and offset to the high-order byte.
   int cw = tex->get_component_width();
   int cw = tex->get_component_width();
@@ -2756,7 +2779,7 @@ copy_alpha_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *
  * green, or blue) from the texture into the indicated ZTexture pixmap.
  * green, or blue) from the texture into the indicated ZTexture pixmap.
  */
  */
 void TinyGraphicsStateGuardian::
 void TinyGraphicsStateGuardian::
-copy_one_channel_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level, int channel) {
+copy_one_channel_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level, int channel) {
   Texture *tex = gtc->get_texture();
   Texture *tex = gtc->get_texture();
   nassertv(tex->get_num_components() == 1);
   nassertv(tex->get_num_components() == 1);
 
 
@@ -2764,7 +2787,7 @@ copy_one_channel_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureCon
   nassertv(!src_image.is_null());
   nassertv(!src_image.is_null());
   const unsigned char *src = src_image.p();
   const unsigned char *src = src_image.p();
   size_t view_size = tex->get_ram_mipmap_view_size(level);
   size_t view_size = tex->get_ram_mipmap_view_size(level);
-  src += view_size * gtc->get_view();
+  src += view_size * view;
 
 
   // Component width, and offset to the high-order byte.
   // Component width, and offset to the high-order byte.
   int cw = tex->get_component_width();
   int cw = tex->get_component_width();
@@ -2821,7 +2844,7 @@ copy_one_channel_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureCon
  * into the indicated ZTexture pixmap.
  * into the indicated ZTexture pixmap.
  */
  */
 void TinyGraphicsStateGuardian::
 void TinyGraphicsStateGuardian::
-copy_la_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
+copy_la_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level) {
   Texture *tex = gtc->get_texture();
   Texture *tex = gtc->get_texture();
   nassertv(tex->get_num_components() == 2);
   nassertv(tex->get_num_components() == 2);
 
 
@@ -2829,7 +2852,7 @@ copy_la_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc
   nassertv(!src_image.is_null());
   nassertv(!src_image.is_null());
   const unsigned char *src = src_image.p();
   const unsigned char *src = src_image.p();
   size_t view_size = tex->get_ram_mipmap_view_size(level);
   size_t view_size = tex->get_ram_mipmap_view_size(level);
-  src += view_size * gtc->get_view();
+  src += view_size * view;
 
 
   // Component width, and offset to the high-order byte.
   // Component width, and offset to the high-order byte.
   int cw = tex->get_component_width();
   int cw = tex->get_component_width();
@@ -2858,7 +2881,7 @@ copy_la_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc
  * indicated ZTexture pixmap.
  * indicated ZTexture pixmap.
  */
  */
 void TinyGraphicsStateGuardian::
 void TinyGraphicsStateGuardian::
-copy_rgb_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
+copy_rgb_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level) {
   Texture *tex = gtc->get_texture();
   Texture *tex = gtc->get_texture();
   nassertv(tex->get_num_components() == 3);
   nassertv(tex->get_num_components() == 3);
 
 
@@ -2866,7 +2889,7 @@ copy_rgb_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gt
   nassertv(!src_image.is_null());
   nassertv(!src_image.is_null());
   const unsigned char *src = src_image.p();
   const unsigned char *src = src_image.p();
   size_t view_size = tex->get_ram_mipmap_view_size(level);
   size_t view_size = tex->get_ram_mipmap_view_size(level);
-  src += view_size * gtc->get_view();
+  src += view_size * view;
 
 
   // Component width, and offset to the high-order byte.
   // Component width, and offset to the high-order byte.
   int cw = tex->get_component_width();
   int cw = tex->get_component_width();
@@ -2895,7 +2918,7 @@ copy_rgb_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gt
  * indicated ZTexture pixmap.
  * indicated ZTexture pixmap.
  */
  */
 void TinyGraphicsStateGuardian::
 void TinyGraphicsStateGuardian::
-copy_rgba_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level) {
+copy_rgba_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level) {
   Texture *tex = gtc->get_texture();
   Texture *tex = gtc->get_texture();
   nassertv(tex->get_num_components() == 4);
   nassertv(tex->get_num_components() == 4);
 
 
@@ -2903,7 +2926,7 @@ copy_rgba_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *g
   nassertv(!src_image.is_null());
   nassertv(!src_image.is_null());
   const unsigned char *src = src_image.p();
   const unsigned char *src = src_image.p();
   size_t view_size = tex->get_ram_mipmap_view_size(level);
   size_t view_size = tex->get_ram_mipmap_view_size(level);
-  src += view_size * gtc->get_view();
+  src += view_size * view;
 
 
   // Component width, and offset to the high-order byte.
   // Component width, and offset to the high-order byte.
   int cw = tex->get_component_width();
   int cw = tex->get_component_width();

+ 9 - 9
panda/src/tinydisplay/tinyGraphicsStateGuardian.h

@@ -84,9 +84,9 @@ public:
   virtual void set_state_and_transform(const RenderState *state,
   virtual void set_state_and_transform(const RenderState *state,
                                        const TransformState *transform);
                                        const TransformState *transform);
 
 
-  virtual TextureContext *prepare_texture(Texture *tex, int view);
+  virtual TextureContext *prepare_texture(Texture *tex);
   virtual bool update_texture(TextureContext *tc, bool force);
   virtual bool update_texture(TextureContext *tc, bool force);
-  bool update_texture(TextureContext *tc, bool force, int stage_index, bool uses_mipmaps);
+  bool update_texture(TextureContext *tc, int view, bool force, int stage_index, bool uses_mipmaps);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
 
 
   virtual void do_issue_light();
   virtual void do_issue_light();
@@ -112,15 +112,15 @@ private:
   bool apply_texture(TextureContext *tc);
   bool apply_texture(TextureContext *tc);
   bool upload_texture(TinyTextureContext *gtc, bool force, bool uses_mipmaps);
   bool upload_texture(TinyTextureContext *gtc, bool force, bool uses_mipmaps);
   bool upload_simple_texture(TinyTextureContext *gtc);
   bool upload_simple_texture(TinyTextureContext *gtc);
-  bool setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels);
+  bool setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_views, int num_levels);
   int get_tex_shift(int orig_size);
   int get_tex_shift(int orig_size);
 
 
-  static void copy_lum_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level);
-  static void copy_alpha_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level);
-  static void copy_one_channel_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level, int channel);
-  static void copy_la_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level);
-  static void copy_rgb_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level);
-  static void copy_rgba_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int level);
+  static void copy_lum_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level);
+  static void copy_alpha_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level);
+  static void copy_one_channel_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level, int channel);
+  static void copy_la_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level);
+  static void copy_rgb_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level);
+  static void copy_rgba_image(ZTextureLevel *dest, int xsize, int ysize, TinyTextureContext *gtc, int view, int level);
 
 
   void setup_material(GLMaterial *gl_material, const Material *material);
   void setup_material(GLMaterial *gl_material, const Material *material);
   void do_auto_rescale_normal();
   void do_auto_rescale_normal();

+ 4 - 2
panda/src/tinydisplay/tinyTextureContext.I

@@ -15,9 +15,11 @@
  *
  *
  */
  */
 INLINE TinyTextureContext::
 INLINE TinyTextureContext::
-TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
-  TextureContext(pgo, tex, view)
+TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex) :
+  TextureContext(pgo, tex)
 {
 {
+  _gltex.views = nullptr;
+  _gltex.num_views = 0;
   _gltex.num_levels = 0;
   _gltex.num_levels = 0;
   _gltex.allocated_buffer = nullptr;
   _gltex.allocated_buffer = nullptr;
   _gltex.total_bytecount = 0;
   _gltex.total_bytecount = 0;

+ 8 - 0
panda/src/tinydisplay/tinyTextureContext.cxx

@@ -31,6 +31,14 @@ TinyTextureContext::
   } else {
   } else {
     nassertv(gltex->num_levels == 0);
     nassertv(gltex->num_levels == 0);
   }
   }
+  if (gltex->views != nullptr) {
+    nassertv(gltex->num_views != 0);
+    get_class_type().deallocate_array(gltex->views);
+    gltex->views = nullptr;
+    gltex->num_views = 0;
+  } else {
+    nassertv(gltex->num_views == 0);
+  }
 }
 }
 
 
 /**
 /**

+ 1 - 1
panda/src/tinydisplay/tinyTextureContext.h

@@ -24,7 +24,7 @@
  */
  */
 class EXPCL_TINYDISPLAY TinyTextureContext : public TextureContext {
 class EXPCL_TINYDISPLAY TinyTextureContext : public TextureContext {
 public:
 public:
-  INLINE TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex, int view);
+  INLINE TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex);
   ALLOC_DELETED_CHAIN(TinyTextureContext);
   ALLOC_DELETED_CHAIN(TinyTextureContext);
 
 
   ~TinyTextureContext();
   ~TinyTextureContext();

+ 1 - 1
panda/src/tinydisplay/zbuffer.h

@@ -252,7 +252,7 @@ int texcoord_mirror_once(int coord, int max_coord);
 /* linesize is in BYTES */
 /* linesize is in BYTES */
 void ZB_copyFrameBuffer(const ZBuffer *zb,void *buf,int linesize);
 void ZB_copyFrameBuffer(const ZBuffer *zb,void *buf,int linesize);
 void ZB_copyFrameBufferNoAlpha(const ZBuffer *zb,void *buf,int linesize);
 void ZB_copyFrameBufferNoAlpha(const ZBuffer *zb,void *buf,int linesize);
-void ZB_zoomFrameBuffer(ZBuffer *dest, int dest_xmin, int dest_ymin, 
+void ZB_zoomFrameBuffer(ZBuffer *dest, int dest_xmin, int dest_ymin,
                         int dest_xsize, int dest_ysize,
                         int dest_xsize, int dest_ysize,
                         const ZBuffer *source, int source_xmin, int source_ymin,
                         const ZBuffer *source, int source_xmin, int source_ymin,
                         int source_xsize, int source_ysize);
                         int source_xsize, int source_ysize);

+ 6 - 1
panda/src/tinydisplay/zgl.h

@@ -119,9 +119,14 @@ typedef struct GLVertex {
 
 
 /* textures */
 /* textures */
 
 
+typedef struct ZTextureView {
+  ZTextureLevel levels[MAX_MIPMAP_LEVELS];
+} ZTextureView;
+
 /* The combination of all mipmap levels: one complete texture. */
 /* The combination of all mipmap levels: one complete texture. */
 typedef struct GLTexture {
 typedef struct GLTexture {
-  ZTextureLevel levels[MAX_MIPMAP_LEVELS];
+  ZTextureView *views;
+  int num_views;
   int num_levels;
   int num_levels;
   int xsize, ysize;
   int xsize, ysize;
   int s_max, t_max;
   int s_max, t_max;

+ 2 - 2
panda/src/wgldisplay/wglGraphicsBuffer.cxx

@@ -170,7 +170,7 @@ bind_texture_to_pbuffer() {
         tex->set_format(Texture::F_rgb);
         tex->set_format(Texture::F_rgb);
       }
       }
     }
     }
-    TextureContext *tc = tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg);
+    TextureContext *tc = tex->prepare_now(_gsg->get_prepared_objects(), _gsg);
     nassertv(tc != nullptr);
     nassertv(tc != nullptr);
     CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
     CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
     GLenum target = wglgsg->get_texture_target(tex->get_texture_type());
     GLenum target = wglgsg->get_texture_target(tex->get_texture_type());
@@ -180,7 +180,7 @@ bind_texture_to_pbuffer() {
       cdataw->_textures[tex_index]._rtm_mode = RTM_copy_texture;
       cdataw->_textures[tex_index]._rtm_mode = RTM_copy_texture;
       return;
       return;
     }
     }
-    GLP(BindTexture)(target, gtc->_index);
+    GLP(BindTexture)(target, gtc->get_view_index(0));
     if (_fb_properties.is_single_buffered()) {
     if (_fb_properties.is_single_buffered()) {
       wglgsg->_wglBindTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
       wglgsg->_wglBindTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
     } else {
     } else {

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