[SOLVED]Help with asynchronous creation of vertex data bufrs

Is there a way to asynchronously create and upload (to GPU) vertex data buffers in Panda3D?

I’m developing a streaming terrain system for a virtual world that retrieves imagery and heightmaps over the network via the WMS protocol, but I’m encountering serious frame stutters while writing vertex data to my GeomVertexWriters. My application currently fetches data from the server, translates the data into arrays of floats for vertex data, and creates PNMImages for terrain textures all in a separate thread from the main thread. My trouble is in creating the Panda vertex buffers using GeomVertexWriters and converting PNMImages into Panda Textures; since these actions seemingly must be performed in the main thread.

I’m starting to look into the Panda source to maybe coerce some of the asynchronous BAM file loading functionality to work with my application-side vertex buffers.

Does anyone have any advice on how to accomplish my goals in a relatively painless way? I just want to upload dynamically created large vertex buffers and textures to the GPU without frame stutter.


I don’t know any reason why you can’t create the GeomVertexData objects and fill them using GeomVertexWriters in a child thread. Similarly with filling a Texture up with a PNMImage. You do have to be sure you’re not operating on a GeomVertexData or Texture object that you’ve already attached to the scene graph, of course (because the draw thread might be in the middle of processing that).


All of the actual uploading will of course have to happen on the draw thread.

I’ve followed drwr’s advice, and am now writing to my GeomVertexWriters and Textures in my worker threads, attaching the resulting nodes to the scene graph in my main thread. This makes a significant improvement in performance and overall user experience.

However, there are still two problems:

  1. Filling the GeomVertexWriters is eating up way too much CPU in my worker threads. The calculation of geometry verts themselves is fairly cheap; it’s the repeated calls to add_data()/add_vertex() that seem to be my problem.

  2. Attaching a resulting terrain patch node to the scene graph causes a noticeable frame stutter. One node contains ~30,000 triangles across 128 triangle strips and a 512x512x3 Texture – this causes a ~0.07 second pause where I suspect the data is being transferred to GPU.

Is there any way to solve these issues?

Our target hardware is NVidia GTX 680 or newer, so if it is necessary, any recommendation on where to begin hacking on the source to take advantage of asynchronous buffer upload would be welcome.

Thanks again,

  1. If you know the number of rows beforehand, then you can significantly speed up the writing by calling reserve_num_rows before adding the rows. This causes the allocation to happen beforehand and not in add_dat.

  2. You can call node.prepare_scene(window->get_gsg()) to prematurely prepare the geometry if it’s more convenient to do it earlier (instead of the first time it is rendered). That probably doesn’t solve your problem though.

I’ve finally met success in generating my terrain tile geometry very quickly, and thought I’d report my results here so that others may benefit.

Using repeated add_data()/add_vertex() calls, it took about 200ms to calculate vertex data and fill GeomVertexData and GeomTristrips objects for a single terrain tile (~30000 triangles across 128 triangle strips). Even when calling reserve_num_rows beforehand, my execution time per tile only dropped to 195ms.

Instead, I used the undocumented functionality of calling GeomVertexArrayData’s modify_handle(), followed by GeomVertexArrayDataHandle’s unclean_set_num_rows() and get_write_pointer() to directly write interleaved vertex data into my GeomVertexArrayData object. I did the same for my index buffer for the GeomTristrips. My final geometry generation time is now 8ms (yes, eight!) per tile.

I understand the reasons that the add_data()/add_vertex() interface exists for geometry generation, but it might be a useful if the ability to provide Panda with entire buffers of vertex and index data were more readily exposed to users in a future version. The performance improvement of directly writing the data without all that overhead is astounding.

I’m still working on improving the texture upload step… I’m not sure what can be done about that yet.


You used get_write_pointer() exactly as it was meant to be used. If this is undocumented, it is only unintentionally, perhaps because our online documentation system overlooks C+±only methods.

Python users can also take advantage of set_data() to fill up a buffer with already-formatted data.