ソースを参照

more aggressive dxgsg8/9 deferred loading

David Rose 18 年 前
コミット
823524e43c

+ 37 - 14
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -303,9 +303,9 @@ prepare_vertex_buffer(GeomVertexArrayData *data) {
 //  Description: Updates the vertex buffer with the current data, and
 //               makes it the current vertex buffer for rendering.
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian8::
+bool DXGraphicsStateGuardian8::
 apply_vertex_buffer(VertexBufferContext *vbc,
-                    const GeomVertexArrayDataHandle *reader) {
+                    const GeomVertexArrayDataHandle *reader, bool force) {
   DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc);
 
   if (dvbc->_vbuffer == NULL) {
@@ -316,7 +316,9 @@ apply_vertex_buffer(VertexBufferContext *vbc,
     }
 
     if (dvbc->_vbuffer != NULL) {
-      dvbc->upload_data(reader);
+      if (!dvbc->upload_data(reader, force)) {
+        return false;
+      }
 
       dvbc->mark_loaded(reader);
 
@@ -338,7 +340,9 @@ apply_vertex_buffer(VertexBufferContext *vbc,
         dvbc->create_vbuffer(*_screen, reader);
       }
 
-      dvbc->upload_data(reader);
+      if (!dvbc->upload_data(reader, force)) {
+        return false;
+      }
       dvbc->mark_loaded(reader);
       _active_vbuffer = NULL;
     }
@@ -360,6 +364,7 @@ apply_vertex_buffer(VertexBufferContext *vbc,
       << ") failed" << D3DERRORSTRING(hr);
   }
 #endif
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -401,9 +406,9 @@ prepare_index_buffer(GeomPrimitive *data) {
 //  Description: Updates the index buffer with the current data, and
 //               makes it the current index buffer for rendering.
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian8::
+bool DXGraphicsStateGuardian8::
 apply_index_buffer(IndexBufferContext *ibc,
-                   const GeomPrimitivePipelineReader *reader) {
+                   const GeomPrimitivePipelineReader *reader, bool force) {
   DXIndexBufferContext8 *dibc = DCAST(DXIndexBufferContext8, ibc);
 
   if (dibc->_ibuffer == NULL) {
@@ -411,7 +416,9 @@ apply_index_buffer(IndexBufferContext *ibc,
     dibc->create_ibuffer(*_screen, reader);
 
     if (dibc->_ibuffer != NULL) {
-      dibc->upload_data(reader);
+      if (!dibc->upload_data(reader, force)) {
+        return false;
+      }
       dibc->mark_loaded(reader);
 
       _d3d_device->SetIndices(dibc->_ibuffer, 0);
@@ -431,7 +438,9 @@ apply_index_buffer(IndexBufferContext *ibc,
         dibc->create_ibuffer(*_screen, reader);
       }
 
-      dibc->upload_data(reader);
+      if (!dibc->upload_data(reader, force)) {
+        return false;
+      }
 
       dibc->mark_loaded(reader);
       _active_ibuffer = NULL;
@@ -443,6 +452,8 @@ apply_index_buffer(IndexBufferContext *ibc,
       dibc->set_active(true);
     }
   }
+
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -812,7 +823,9 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
 
   VertexBufferContext *vbc = ((GeomVertexArrayData *)(data->get_object()))->prepare_now(get_prepared_objects(), this);
   nassertr(vbc != (VertexBufferContext *)NULL, false);
-  apply_vertex_buffer(vbc, data);
+  if (!apply_vertex_buffer(vbc, data, force)) {
+    return false;
+  }
 
   const GeomVertexAnimationSpec &animation =
     data_reader->get_format()->get_animation();
@@ -917,7 +930,9 @@ draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
       // Indexed, vbuffers.
       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
       nassertr(ibc != (IndexBufferContext *)NULL, false);
-      apply_index_buffer(ibc, reader);
+      if (!apply_index_buffer(ibc, reader, force)) {
+        return false;
+      }
 
       _d3d_device->DrawIndexedPrimitive
         (D3DPT_TRIANGLELIST,
@@ -987,7 +1002,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
         // Indexed, vbuffers, one line triangle strip.
         IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
         nassertr(ibc != (IndexBufferContext *)NULL, false);
-        apply_index_buffer(ibc, reader);
+        if (!apply_index_buffer(ibc, reader, force)) {
+          return false;
+        }
 
         _d3d_device->DrawIndexedPrimitive
           (D3DPT_TRIANGLESTRIP,
@@ -1055,7 +1072,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
         // Indexed, vbuffers, individual triangle strips.
         IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
         nassertr(ibc != (IndexBufferContext *)NULL, false);
-        apply_index_buffer(ibc, reader);
+        if (!apply_index_buffer(ibc, reader, force)) {
+          return false;
+        }
 
         unsigned int start = 0;
         for (size_t i = 0; i < ends.size(); i++) {
@@ -1165,7 +1184,9 @@ draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
       // Indexed, vbuffers.
       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
       nassertr(ibc != (IndexBufferContext *)NULL, false);
-      apply_index_buffer(ibc, reader);
+      if (!apply_index_buffer(ibc, reader, force)) {
+        return false;
+      }
 
       unsigned int start = 0;
       for (size_t i = 0; i < ends.size(); i++) {
@@ -1265,7 +1286,9 @@ draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
       // Indexed, vbuffers.
       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
       nassertr(ibc != (IndexBufferContext *)NULL, false);
-      apply_index_buffer(ibc, reader);
+      if (!apply_index_buffer(ibc, reader, force)) {
+        return false;
+      }
 
       _d3d_device->DrawIndexedPrimitive
         (D3DPT_LINELIST,

+ 4 - 4
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -56,13 +56,13 @@ public:
   virtual void release_texture(TextureContext *tc);
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
-  void apply_vertex_buffer(VertexBufferContext *vbc,
-                           const GeomVertexArrayDataHandle *reader);
+  bool apply_vertex_buffer(VertexBufferContext *vbc,
+                           const GeomVertexArrayDataHandle *reader, bool force);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
 
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
-  void apply_index_buffer(IndexBufferContext *ibc,
-                          const GeomPrimitivePipelineReader *reader);
+  bool apply_index_buffer(IndexBufferContext *ibc,
+                          const GeomPrimitivePipelineReader *reader, bool force);
   virtual void release_index_buffer(IndexBufferContext *ibc);
 
   virtual PT(GeomMunger) make_geom_munger(const RenderState *state,

+ 14 - 8
panda/src/dxgsg8/dxIndexBufferContext8.cxx

@@ -104,15 +104,17 @@ create_ibuffer(DXScreenData &scrn,
 //  Description: Copies the latest data from the client store to
 //               DirectX.
 ////////////////////////////////////////////////////////////////////
-void DXIndexBufferContext8::
-upload_data(const GeomPrimitivePipelineReader *reader) {
-  nassertv(reader->get_object() == get_data());
+bool DXIndexBufferContext8::
+upload_data(const GeomPrimitivePipelineReader *reader, bool force) {
+  nassertr(reader->get_object() == get_data(), false);
   Thread *current_thread = reader->get_current_thread();
 
-  nassertv(_ibuffer != NULL);
-  PStatTimer timer(GraphicsStateGuardian::_load_index_buffer_pcollector,
-                   current_thread);
+  nassertr(_ibuffer != NULL, false);
 
+  const unsigned char *data_pointer = reader->get_read_pointer(force);
+  if (data_pointer == NULL) {
+    return false;
+  }
   int data_size = reader->get_data_size_bytes();
 
   if (dxgsg8_cat.is_spam()) {
@@ -121,18 +123,22 @@ upload_data(const GeomPrimitivePipelineReader *reader) {
       << " bytes into index buffer " << _ibuffer << "\n";
   }
 
+  PStatTimer timer(GraphicsStateGuardian::_load_index_buffer_pcollector,
+                   current_thread);
+
   BYTE *local_pointer;
 //  HRESULT hr = _ibuffer->Lock(0, data_size, &local_pointer, 0);
   HRESULT hr = _ibuffer->Lock(0, data_size, &local_pointer, D3DLOCK_DISCARD);
   if (FAILED(hr)) {
     dxgsg8_cat.error()
       << "IndexBuffer::Lock failed" << D3DERRORSTRING(hr);
-    return;
+    return false;
   }
 
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
-  memcpy(local_pointer, reader->get_read_pointer(true), data_size);
+  memcpy(local_pointer, data_pointer, data_size);
 
   _ibuffer->Unlock();
+  return true;
 }
 

+ 1 - 1
panda/src/dxgsg8/dxIndexBufferContext8.h

@@ -35,7 +35,7 @@ public:
 
   void create_ibuffer(DXScreenData &scrn,
                       const GeomPrimitivePipelineReader *reader);
-  void upload_data(const GeomPrimitivePipelineReader *reader);
+  bool upload_data(const GeomPrimitivePipelineReader *reader, bool force);
 
   IDirect3DIndexBuffer8 *_ibuffer;
 

+ 14 - 8
panda/src/dxgsg8/dxVertexBufferContext8.cxx

@@ -231,14 +231,16 @@ create_vbuffer(DXScreenData &scrn,
 //  Description: Copies the latest data from the client store to
 //               DirectX.
 ////////////////////////////////////////////////////////////////////
-void DXVertexBufferContext8::
-upload_data(const GeomVertexArrayDataHandle *reader) {
-  nassertv(reader->get_object() == get_data());
-  nassertv(_vbuffer != NULL);
+bool DXVertexBufferContext8::
+upload_data(const GeomVertexArrayDataHandle *reader, bool force) {
+  nassertr(reader->get_object() == get_data(), false);
+  nassertr(_vbuffer != NULL, false);
   Thread *current_thread = reader->get_current_thread();
-  PStatTimer timer(GraphicsStateGuardian::_load_vertex_buffer_pcollector,
-                   current_thread);
 
+  const unsigned char *data_pointer = reader->get_read_pointer(force);
+  if (data_pointer == NULL) {
+    return false;
+  }
   int data_size = reader->get_data_size_bytes();
 
   if (dxgsg8_cat.is_spam()) {
@@ -247,18 +249,22 @@ upload_data(const GeomVertexArrayDataHandle *reader) {
       << " bytes into vertex buffer " << _vbuffer << "\n";
   }
 
+  PStatTimer timer(GraphicsStateGuardian::_load_vertex_buffer_pcollector,
+                   current_thread);
+
   BYTE *local_pointer;
 //  HRESULT hr = _vbuffer->Lock(0, data_size, &local_pointer, 0);
   HRESULT hr = _vbuffer->Lock(0, data_size, &local_pointer, D3DLOCK_DISCARD);
   if (FAILED(hr)) {
     dxgsg8_cat.error()
       << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr);
-    return;
+    return false;
   }
 
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
-  memcpy(local_pointer, reader->get_read_pointer(true), data_size);
+  memcpy(local_pointer, data_pointer, data_size);
 
   _vbuffer->Unlock();
+  return true;
 }
 

+ 1 - 1
panda/src/dxgsg8/dxVertexBufferContext8.h

@@ -35,7 +35,7 @@ public:
 
   void create_vbuffer(DXScreenData &scrn,
                       const GeomVertexArrayDataHandle *reader);
-  void upload_data(const GeomVertexArrayDataHandle *reader);
+  bool upload_data(const GeomVertexArrayDataHandle *reader, bool force);
 
   IDirect3DVertexBuffer8 *_vbuffer;
   int _fvf;

+ 68 - 16
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -62,6 +62,7 @@
 #include "pStatTimer.h"
 #include "pStatCollector.h"
 #include "wdxGraphicsBuffer9.h"
+#include "config_pgraph.h"
 #ifdef HAVE_CG
 #include "Cg/cgD3D9.h"
 #endif
@@ -391,10 +392,10 @@ prepare_vertex_buffer(GeomVertexArrayData *data) {
 //  Description: Updates the vertex buffer with the current data, and
 //               makes it the current vertex buffer for rendering.
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian9::
+bool DXGraphicsStateGuardian9::
 apply_vertex_buffer(VertexBufferContext *vbc,
                     CLP(ShaderContext) *shader_context,
-                    const GeomVertexArrayDataHandle *reader) {
+                    const GeomVertexArrayDataHandle *reader, bool force) {
   DXVertexBufferContext9 *dvbc = DCAST(DXVertexBufferContext9, vbc);
 
   DBG_SH3 dxgsg9_cat.debug ( ) << "apply_vertex_buffer\n"; DBG_E
@@ -420,7 +421,9 @@ apply_vertex_buffer(VertexBufferContext *vbc,
     }
 
     if (dvbc->_vbuffer != NULL) {
-      dvbc->upload_data(reader);
+      if (!dvbc->upload_data(reader, force)) {
+        return false;
+      }
 
       dvbc->mark_loaded(reader);
 
@@ -438,7 +441,9 @@ apply_vertex_buffer(VertexBufferContext *vbc,
         dvbc->create_vbuffer(*_screen, reader);
       }
 
-      dvbc->upload_data(reader);
+      if (!dvbc->upload_data(reader, force)) {
+        return false;
+      }
 
       dvbc->mark_loaded(reader);
       _active_vbuffer = NULL;
@@ -565,6 +570,8 @@ apply_vertex_buffer(VertexBufferContext *vbc,
       }
     }
   }
+
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -606,9 +613,9 @@ prepare_index_buffer(GeomPrimitive *data) {
 //  Description: Updates the index buffer with the current data, and
 //               makes it the current index buffer for rendering.
 ////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian9::
+bool DXGraphicsStateGuardian9::
 apply_index_buffer(IndexBufferContext *ibc,
-                   const GeomPrimitivePipelineReader *reader) {
+                   const GeomPrimitivePipelineReader *reader, bool force) {
   DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc);
 
   if (_lru) {
@@ -620,7 +627,9 @@ apply_index_buffer(IndexBufferContext *ibc,
     dibc->create_ibuffer(*_screen, reader);
 
     if (dibc->_ibuffer != NULL) {
-      dibc->upload_data(reader);
+      if (!dibc->upload_data(reader, force)) {
+        return false;
+      }
       dibc->mark_loaded(reader);
 
       _d3d_device->SetIndices(dibc->_ibuffer);
@@ -640,7 +649,9 @@ apply_index_buffer(IndexBufferContext *ibc,
         dibc->create_ibuffer(*_screen, reader);
       }
 
-      dibc->upload_data(reader);
+      if (!dibc->upload_data(reader, force)) {
+        return false;
+      }
 
       dibc->mark_loaded(reader);
       _active_ibuffer = NULL;
@@ -652,6 +663,8 @@ apply_index_buffer(IndexBufferContext *ibc,
       dibc->set_active(true);
     }
   }
+
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1367,7 +1380,9 @@ vertex_element_array -> vertex_element_type_array;
 
   VertexBufferContext *vbc = ((GeomVertexArrayData *)(data->get_object()))->prepare_now(get_prepared_objects(), this);
   nassertr(vbc != (VertexBufferContext *)NULL, false);
-  apply_vertex_buffer(vbc, _current_shader_context, data);
+  if (!apply_vertex_buffer(vbc, _current_shader_context, data, force)) {
+    return false;
+  }
 
   const GeomVertexAnimationSpec &animation =
     data_reader->get_format()->get_animation();
@@ -1475,7 +1490,9 @@ draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
       // Indexed, vbuffers.
       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
       nassertr(ibc != (IndexBufferContext *)NULL, false);
-      apply_index_buffer(ibc, reader);
+      if (!apply_index_buffer(ibc, reader, force)) {
+        return false;
+      }
 
 //DBG_SH2 dxgsg9_cat.debug ( ) << "DrawIndexedPrimitive \n"; DBG_E
 
@@ -1561,7 +1578,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
         // Indexed, vbuffers, one line triangle strip.
         IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
         nassertr(ibc != (IndexBufferContext *)NULL, false);
-        apply_index_buffer(ibc, reader);
+        if (!apply_index_buffer(ibc, reader, force)) {
+          return false;
+        }
 
 //dxgsg9_cat.error ( ) << "DrawIndexedPrimitive D3DPT_TRIANGLESTRIP VERTICES: " << reader->get_num_vertices ( ) << "\n";
 
@@ -1637,7 +1656,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
         // Indexed, vbuffers, individual triangle strips.
         IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
         nassertr(ibc != (IndexBufferContext *)NULL, false);
-        apply_index_buffer(ibc, reader);
+        if (!apply_index_buffer(ibc, reader, force)) {
+          return false;
+        }
 
         unsigned int start = 0;
         for (size_t i = 0; i < ends.size(); i++) {
@@ -1751,7 +1772,9 @@ draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
       // Indexed, vbuffers.
       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
       nassertr(ibc != (IndexBufferContext *)NULL, false);
-      apply_index_buffer(ibc, reader);
+      if (!apply_index_buffer(ibc, reader, force)) {
+        return false;
+      }
 
       unsigned int start = 0;
       for (size_t i = 0; i < ends.size(); i++) {
@@ -1851,7 +1874,9 @@ draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
       // Indexed, vbuffers.
       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
       nassertr(ibc != (IndexBufferContext *)NULL, false);
-      apply_index_buffer(ibc, reader);
+      if (!apply_index_buffer(ibc, reader, force)) {
+        return false;
+      }
 
       _d3d_device->DrawIndexedPrimitive
         (D3DPT_LINELIST,
@@ -2349,10 +2374,23 @@ bool vertex_buffer_page_in_function (LruPage *lru_page)
   // allocate vertex buffer
   Thread *current_thread = Thread::get_current_thread();
   CPT(GeomVertexArrayDataHandle) reader = vertex_buffer->get_data()->get_handle(current_thread);
+
+  /*
+    Not sure if this is the correct thing to do.  Can we return false
+    from the page_in function?  Will we get called again next frame if
+    we do?
+  if (allow_incomplete_render) {
+    // Check if the data is resident before continuing.
+    const unsigned char *data_pointer = reader->get_read_pointer(false);
+    if (data_pointer == NULL) {
+      return false;
+    }
+  }
+  */
   vertex_buffer -> allocate_vbuffer (*(gsg->_screen), reader);
 
   // update vertex buffer
-  vertex_buffer -> upload_data(reader);
+  vertex_buffer -> upload_data(reader, true);
   vertex_buffer -> set_resident(true);
 
   if (DEBUG_LRU && dxgsg9_cat.is_debug())
@@ -2390,10 +2428,24 @@ bool index_buffer_page_in_function (LruPage *lru_page)
   // allocate vertex buffer
   Thread *current_thread = Thread::get_current_thread();
   GeomPrimitivePipelineReader reader(index_buffer->get_data(), current_thread);
+
+  /*
+    Not sure if this is the correct thing to do.  Can we return false
+    from the page_in function?  Will we get called again next frame if
+    we do?
+  if (allow_incomplete_render) {
+    // Check if the data is resident before continuing.
+    const unsigned char *data_pointer = reader.get_read_pointer(false);
+    if (data_pointer == NULL) {
+      return false;
+    }
+  }
+  */
+
   index_buffer -> allocate_ibuffer (*(gsg->_screen), &reader);
 
   // update vertex buffer
-  index_buffer -> upload_data (&reader);
+  index_buffer -> upload_data (&reader, true);
   index_buffer -> set_resident(true);
 
   if (DEBUG_LRU && dxgsg9_cat.is_debug())

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

@@ -93,13 +93,13 @@ public:
   void release_shader(ShaderContext *sc);
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
-  void apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context,
-                           const GeomVertexArrayDataHandle *reader);
+  bool apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context,
+                           const GeomVertexArrayDataHandle *reader, bool force);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
 
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
-  void apply_index_buffer(IndexBufferContext *ibc,
-                          const GeomPrimitivePipelineReader *reader);
+  bool apply_index_buffer(IndexBufferContext *ibc,
+                          const GeomPrimitivePipelineReader *reader, bool force);
   virtual void release_index_buffer(IndexBufferContext *ibc);
 
   virtual void begin_occlusion_query();

+ 13 - 8
panda/src/dxgsg9/dxIndexBufferContext9.cxx

@@ -202,15 +202,17 @@ create_ibuffer(DXScreenData &scrn,
 //  Description: Copies the latest data from the client store to
 //               DirectX.
 ////////////////////////////////////////////////////////////////////
-void DXIndexBufferContext9::
-upload_data(const GeomPrimitivePipelineReader *reader) {
-  nassertv(reader->get_object() == get_data());
+bool DXIndexBufferContext9::
+upload_data(const GeomPrimitivePipelineReader *reader, bool force) {
+  nassertr(reader->get_object() == get_data(), false);
   Thread *current_thread = reader->get_current_thread();
 
-  nassertv(_ibuffer != NULL);
-  PStatTimer timer(GraphicsStateGuardian::_load_index_buffer_pcollector,
-                   current_thread);
+  nassertr(_ibuffer != NULL, false);
 
+  const unsigned char *data_pointer = reader->get_read_pointer(force);
+  if (data_pointer == NULL) {
+    return false;
+  }
   int data_size = reader->get_data_size_bytes();
 
   if (dxgsg9_cat.is_spam()) {
@@ -218,6 +220,8 @@ upload_data(const GeomPrimitivePipelineReader *reader) {
       << "copying " << data_size
       << " bytes into index buffer " << _ibuffer << "\n";
   }
+  PStatTimer timer(GraphicsStateGuardian::_load_index_buffer_pcollector,
+                   current_thread);
 
   HRESULT hr;
   BYTE *local_pointer;
@@ -233,11 +237,12 @@ upload_data(const GeomPrimitivePipelineReader *reader) {
   if (FAILED(hr)) {
     dxgsg9_cat.error()
       << "IndexBuffer::Lock failed" << D3DERRORSTRING(hr);
-    return;
+    return false;
   }
 
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
-  memcpy(local_pointer, reader->get_read_pointer(true), data_size);
+  memcpy(local_pointer, data_pointer, data_size);
 
   _ibuffer->Unlock();
+  return true;
 }

+ 1 - 1
panda/src/dxgsg9/dxIndexBufferContext9.h

@@ -36,7 +36,7 @@ public:
   void free_ibuffer();
   void allocate_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader);
   void create_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader);
-  void upload_data(const GeomPrimitivePipelineReader *reader);
+  bool upload_data(const GeomPrimitivePipelineReader *reader, bool force);
 
   IDirect3DIndexBuffer9 *_ibuffer;
   int _managed;

+ 13 - 8
panda/src/dxgsg9/dxVertexBufferContext9.cxx

@@ -441,14 +441,16 @@ create_vbuffer(DXScreenData &scrn,
 //  Description: Copies the latest data from the client store to
 //               DirectX.
 ////////////////////////////////////////////////////////////////////
-void DXVertexBufferContext9::
-upload_data(const GeomVertexArrayDataHandle *reader) {
-  nassertv(reader->get_object() == get_data());
-  nassertv(_vbuffer != NULL);
+bool DXVertexBufferContext9::
+upload_data(const GeomVertexArrayDataHandle *reader, bool force) {
+  nassertr(reader->get_object() == get_data(), false);
+  nassertr(_vbuffer != NULL, false);
   Thread *current_thread = reader->get_current_thread();
-  PStatTimer timer(GraphicsStateGuardian::_load_vertex_buffer_pcollector,
-                   current_thread);
 
+  const unsigned char *data_pointer = reader->get_read_pointer(force);
+  if (data_pointer == NULL) {
+    return false;
+  }
   int data_size = reader->get_data_size_bytes();
 
   if (dxgsg9_cat.is_spam()) {
@@ -456,6 +458,8 @@ upload_data(const GeomVertexArrayDataHandle *reader) {
       << "copying " << data_size
       << " bytes into vertex buffer " << _vbuffer << "\n";
   }
+  PStatTimer timer(GraphicsStateGuardian::_load_vertex_buffer_pcollector,
+                   current_thread);
 
   HRESULT hr;
   BYTE *local_pointer;
@@ -469,11 +473,12 @@ upload_data(const GeomVertexArrayDataHandle *reader) {
   if (FAILED(hr)) {
     dxgsg9_cat.error()
       << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr);
-    return;
+    return false;
   }
 
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
-  memcpy(local_pointer, reader->get_read_pointer(true), data_size);
+  memcpy(local_pointer, data_pointer, data_size);
 
   _vbuffer->Unlock();
+  return true;
 }

+ 1 - 1
panda/src/dxgsg9/dxVertexBufferContext9.h

@@ -36,7 +36,7 @@ public:
   void free_vbuffer();
   void allocate_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader);
   void create_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader);
-  void upload_data(const GeomVertexArrayDataHandle *reader);
+  bool upload_data(const GeomVertexArrayDataHandle *reader, bool force);
 
   IDirect3DVertexBuffer9 *_vbuffer;
   int _fvf;

+ 1 - 1
panda/src/pgraph/config_pgraph.h

@@ -69,7 +69,7 @@ extern ConfigVariableBool m_dual_flash;
 
 extern ConfigVariableList load_file_type;
 extern ConfigVariableString default_model_extension;
-extern ConfigVariableBool allow_incomplete_render;
+extern EXPCL_PANDA ConfigVariableBool allow_incomplete_render;
 
 extern EXPCL_PANDA void init_libpgraph();