Buffer Orphaning vs Persistent Mapping for Per-Frame Vertex Streaming
0 reputation · 18 Mar 2023, 05:12 UTC
0 reputation · 18 Mar 2023, 05:12 UTC
For per-frame dynamic vertex buffer updates where the CPU must write geometry each iteration without introducing stalls, two documented OpenGL approaches compete: buffer orphaning via glBufferData(GL_STREAM_DRAW) and persistent mapping via glMapBufferRange with GL_MAP_UNSYNCHRONIZED_BIT. Buffer orphaning supplies a new data pointer each frame, enabling the driver to retire the previous buffer asynchronously while the GPU completes prior draws, yet the specification leaves orphan allocation and stall behavior implementation‑defined across vendors. Persistent mapping returns a write pointer that remains valid across frames, eliminating driver synchronization overhead but requiring the application to manage coherency, typically through fences or offset ranges, and the technique requires OpenGL 3.0 or the ARB_map_buffer_range extension. The choice between these paths involves trading off driver‑managed retirement against application‑controlled coherency, each with version and hardware dependencies that influence real‑world stall profiles. What are the practical limits of buffer orphaning when GPU command queues are near full capacity? How does persistent mapping’s coherency model affect frame pacing on integrated versus discrete GPUs? Which approach offers more predictable latency under a strict no‑stall CPU constraint?
34775 reputation · 18 Mar 2023, 12:22 UTC
Prefer persistent mapping with a fixed multi-frame ring and per-frame fences. It gives more predictable CPU latency under a strict no-stall constraint than buffer orphaning, because the CPU writes to a stable pointer and only skips a slot when a fence shows the GPU is still using it. Buffer orphaning with glBufferData(GL_STREAM_DRAW) hands the driver a new allocation each frame, but stall behavior is implementation-defined and becomes less predictable as the command queue fills.
glBufferData blocks are implementation-defined; no API guarantee of stall-free behavior exists.ARB_map_buffer_range. GL_MAP_UNSYNCHRONIZED_BIT permits unsynchronized CPU writes, but the application must not overwrite a range the GPU may still read.GL_MAP_COHERENT_BIT requires OpenGL 4.4 or ARB_buffer_storage; without it, use explicit glFlushMappedBufferRange or memory barriers.Near a full queue, orphaning can still block the CPU because the driver must retain the old buffer until in-flight draws finish. Frequent large reallocations add memory pressure and may cause hidden synchronization or frame-time spikes. On integrated GPUs, coherent mapped writes share system memory with the CPU, so coherency is simpler but memory-controller contention affects pacing. On discrete GPUs, mapped writes use CPU-writable PCIe memory; exceeding ring depth forces a CPU wait or a dropped frame. These are likely vendor- and driver-dependent outcomes, not specification guarantees.
ARB_map_buffer_range and ARB_sync are available, and whether ARB_buffer_storage with GL_MAP_COHERENT_BIT is supported.GLsync per ring slot with glFenceSync after the draw that consumes that slot.glClientWaitSync at zero timeout. Write only when it reports ALREADY_SIGNALED or CONDITION_SATISFIED. If it reports TIMEOUT_EXPIRED, the ring is too small or the GPU is behind; skip the frame or enlarge the ring.Does the target context support OpenGL 4.4/ARB_buffer_storage with GL_MAP_COHERENT_BIT? This changes the recommendation: without coherent mapping, persistent writes require explicit flushes and add coherency management, narrowing the predictability gap with orphaning.
glBufferData each frame with a nearly full queue; sporadic multi-millisecond spikes indicate driver synchronization.TIMEOUT_EXPIRED confirms the no-stall path.Assumptions: desktop OpenGL core profile, one CPU producer and one GPU consumer, vertex data written once per frame per slot. Behavior marked likely is implementation-dependent and should be validated on the target hardware.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 18 Mar 2023, 05:51 UTC
A subtle limit of buffer orphaning is that glBufferData(GL_STREAM_DRAW) with a NULL pointer is an allocation hint, not a retirement guarantee. When the GPU command queue is near full, previously orphaned stores can remain referenced by in-flight draws, so the driver may still block inside the orphan call or the next draw to free memory. A practical check is to insert a GLsync after each draw that consumes the orphaned buffer and poll it with timeout zero before the next frame’s upload. If the sync is rarely signaled, orphaning is effectively serializing the CPU on that driver/hardware combination, making persistent mapping with explicit non-blocking fences the more predictable path for strict no-stall pacing.