From d77782ea931b9fa3e7e2a31628f6ec1d35a47884 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 7 Jan 2022 15:24:20 +0100 Subject: [PATCH] CameraView: sync pbo with glFence instead of calling glFinish (#23409) * CameraView: sync pbo with glFence instead of calling glFinish (#23293) * Sync pbo with fence * use std::unique_ptr * cameraview.cc: call glFlush after creating fence Co-authored-by: Dean Lee --- selfdrive/ui/qt/widgets/cameraview.cc | 49 +++++++++++++++++---------- selfdrive/ui/qt/widgets/cameraview.h | 12 +++++-- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 9050122765..a16923894d 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -202,9 +202,15 @@ void CameraViewWidget::paintGL() { glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + std::lock_guard lk(lock); + if (latest_texture_id == -1) return; glViewport(0, 0, width(), height()); + // sync with the PBO + if (wait_fence) { + wait_fence->wait(); + } glBindVertexArray(frame_vao); glActiveTexture(GL_TEXTURE0); @@ -289,26 +295,33 @@ void CameraViewWidget::vipcThread() { } if (VisionBuf *buf = vipc_client->recv(nullptr, 1000)) { - if (!Hardware::EON()) { - void *texture_buffer = gl_buffer->map(QOpenGLBuffer::WriteOnly); - - if (texture_buffer == nullptr) { - LOGE("gl_buffer->map returned nullptr"); - continue; + { + std::lock_guard lk(lock); + if (!Hardware::EON()) { + void *texture_buffer = gl_buffer->map(QOpenGLBuffer::WriteOnly); + + if (texture_buffer == nullptr) { + LOGE("gl_buffer->map returned nullptr"); + continue; + } + + memcpy(texture_buffer, buf->addr, buf->len); + gl_buffer->unmap(); + + // copy pixels from PBO to texture object + glBindTexture(GL_TEXTURE_2D, texture[buf->idx]->frame_tex); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, buf->width, buf->height, GL_RGB, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, 0); + assert(glGetError() == GL_NO_ERROR); + + wait_fence.reset(new WaitFence()); + + // Ensure the fence is in the GPU command queue, or waiting on it might block + // https://www.khronos.org/opengl/wiki/Sync_Object#Flushing_and_contexts + glFlush(); } - - memcpy(texture_buffer, buf->addr, buf->len); - gl_buffer->unmap(); - - // copy pixels from PBO to texture object - glBindTexture(GL_TEXTURE_2D, texture[buf->idx]->frame_tex); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, buf->width, buf->height, GL_RGB, GL_UNSIGNED_BYTE, 0); - glBindTexture(GL_TEXTURE_2D, 0); - assert(glGetError() == GL_NO_ERROR); - // use glFinish to ensure that the texture has been uploaded. - glFinish(); + latest_texture_id = buf->idx; } - latest_texture_id = buf->idx; // Schedule update. update() will be invoked on the gui thread. QMetaObject::invokeMethod(this, "update"); diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index 4cfba3c6fb..03709cbdd8 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -36,11 +36,20 @@ protected: virtual void updateFrameMat(int w, int h); void vipcThread(); + struct WaitFence { + WaitFence() { sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); } + ~WaitFence() { glDeleteSync(sync); } + void wait() { glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); } + GLsync sync = 0; + }; + bool zoomed_view; - std::atomic latest_texture_id = -1; + std::mutex lock; + int latest_texture_id = -1; GLuint frame_vao, frame_vbo, frame_ibo; mat4 frame_mat; std::unique_ptr texture[UI_BUF_COUNT]; + std::unique_ptr wait_fence; std::unique_ptr program; QColor bg = QColor("#000000"); @@ -50,7 +59,6 @@ protected: std::atomic stream_type; QThread *vipc_thread = nullptr; - protected slots: void vipcConnected(VisionIpcClient *vipc_client); };