From 1c22fa0669811b1d4d3dfb900484311821166969 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 25 May 2026 15:50:30 +1000 Subject: [PATCH] Use bound overlay uploads Update the overlay renderer's dynamic VBO uploads to bind the buffer and use glBufferData/glBufferSubData instead of direct-state glNamedBufferData/glNamedBufferSubData. This avoids Windows/NVIDIA driver corruption seen with overlay axes, pick markers, HUD rects, and marquee rectangles while keeping the same overlay geometry and draw paths. Generated with the assistance of an AI coding tool. --- src/ifcviewer/OverlayRenderer.cpp | 42 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/ifcviewer/OverlayRenderer.cpp b/src/ifcviewer/OverlayRenderer.cpp index 228b2ee49c..3dc9bb7866 100644 --- a/src/ifcviewer/OverlayRenderer.cpp +++ b/src/ifcviewer/OverlayRenderer.cpp @@ -224,11 +224,29 @@ void uploadFloats(QOpenGLFunctions_4_5_Core* gl, if (bytes == 0) return; if (bytes > capacity_bytes) { const size_t new_cap = bytes + bytes / 2; - gl->glNamedBufferData(vbo, GLsizeiptr(new_cap), - nullptr, GL_DYNAMIC_DRAW); + gl->glBindBuffer(GL_ARRAY_BUFFER, vbo); + gl->glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(new_cap), nullptr, GL_DYNAMIC_DRAW); capacity_bytes = new_cap; } - gl->glNamedBufferSubData(vbo, 0, GLsizeiptr(bytes), data.data()); + gl->glBindBuffer(GL_ARRAY_BUFFER, vbo); + gl->glBufferSubData(GL_ARRAY_BUFFER, 0, GLsizeiptr(bytes), data.data()); + gl->glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void uploadFloatBytes(QOpenGLFunctions_4_5_Core* gl, + GLuint vbo, size_t& capacity_bytes, + const float* data, size_t float_count) { + const size_t bytes = float_count * sizeof(float); + if (bytes == 0) return; + if (bytes > capacity_bytes) { + const size_t new_cap = bytes + bytes / 2; + gl->glBindBuffer(GL_ARRAY_BUFFER, vbo); + gl->glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(new_cap), nullptr, GL_DYNAMIC_DRAW); + capacity_bytes = new_cap; + } + gl->glBindBuffer(GL_ARRAY_BUFFER, vbo); + gl->glBufferSubData(GL_ARRAY_BUFFER, 0, GLsizeiptr(bytes), data); + gl->glBindBuffer(GL_ARRAY_BUFFER, 0); } // CPU expansion of N segments (3 floats * 2 verts per segment, packed) into @@ -572,13 +590,6 @@ void OverlayRenderer::render(const float view_proj[16], // Each piece is its own draw so we can switch alpha between // fill and outline. All five share the same VBO slot — we // stream-overwrite per draw. - const size_t bytes = 12 * sizeof(float); - if (bytes > vbo_rect_capacity_) { - const size_t new_cap = bytes + bytes / 2; - gl_->glNamedBufferData(vbo_rect_, GLsizeiptr(new_cap), - nullptr, GL_DYNAMIC_DRAW); - vbo_rect_capacity_ = new_cap; - } for (int i = 0; i < 5; ++i) { const float x0 = px_to_ndc_x(pieces[i].x0); const float x1 = px_to_ndc_x(pieces[i].x1); @@ -588,7 +599,7 @@ void OverlayRenderer::render(const float view_proj[16], x0, y0, x1, y0, x0, y1, x0, y1, x1, y0, x1, y1 }; - gl_->glNamedBufferSubData(vbo_rect_, 0, GLsizeiptr(bytes), ndc); + uploadFloatBytes(gl_, vbo_rect_, vbo_rect_capacity_, ndc, 12); gl_->glUniform4f(u_rect_color_, colors[i][0], colors[i][1], colors[i][2], colors[i][3]); @@ -672,14 +683,7 @@ void OverlayRenderer::render(const float view_proj[16], x0, y1, x1, y0, x1, y1 }); } - const size_t bytes = ndc.size() * sizeof(float); - if (bytes > vbo_rect_capacity_) { - const size_t new_cap = bytes + bytes / 2; - gl_->glNamedBufferData(vbo_rect_, GLsizeiptr(new_cap), - nullptr, GL_DYNAMIC_DRAW); - vbo_rect_capacity_ = new_cap; - } - gl_->glNamedBufferSubData(vbo_rect_, 0, GLsizeiptr(bytes), ndc.data()); + uploadFloats(gl_, vbo_rect_, vbo_rect_capacity_, ndc); // GL_TRIANGLES respects GL_CULL_FACE; the NDC→window y-flip turns // our CCW NDC quads into window-CW which get back-culled if cull