Skip to content

Commit 6879c31

Browse files
perf: render RV viewport as a native GL window to fix Qt6 web-panel latency
The Qt6/PySide6 migration regressed the JS->Python QWebChannel bridge in docked QWebEngineView panels: pyevaluate round-trips grew unbounded (into the seconds) while media plays, where Qt5 stayed flat (~8 ms). Root cause is the per-presented-frame ~80-90 ms full-window QOpenGLWidget composite, which serializes on the GUI thread and starves QWebChannel delivery. The two prior fixes (edit-mode churn skip, settle-window removal) only address the non-playing path, so the regression persisted whenever a handler started playback. Render the RV viewport as a native QOpenGLWindow (new GLWindow) embedded via QWidget::createWindowContainer, instead of a QOpenGLWidget: - The top-level QMainWindow is no longer forced onto the OpenGL RHI backend, so docked QWebEngineView panels render on the platform-default backend and QT_QUICK_BACKEND=software is no longer needed (removed). - The viewport presents on its own surface, off the full-window widget composite, so playback no longer starves the bridge. Bridge latency stays flat and self-healing while playing. GLView becomes a plain QWidget host that delegates the API RV expects to the GLWindow; QTGLVideoDevice gains a window-backed path alongside the widget one. Also fixed, exposed by the surface change: - Presentation / second output: DesktopVideoDevice::open no longer dereferences the control device's (now-null) QOpenGLWidget; ScreenView shares a QOpenGLContext via new backing-agnostic QTGLVideoDevice::glShareContext()/ glSurfaceFormat(). - Set Qt::AA_ShareOpenGLContexts (documented QtWebEngine requirement) so the second-output and upload-worker GL surfaces share with the viewport, and drop a null-context dereference in newSharedContextWorkerDevice that crashed when Multithread GPU Upload was enabled. - The UI blocking overlay is reworked from a raster child widget into a frameless translucent top-level window so it can dim and block input over the native viewport. Validated on Windows (release): flat bridge latency under playback spam, all web panels render docked, and viewport/events/drag-drop/annotations/ presentation/blocking-overlay all work. macOS and HDPI passes still pending. Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>
1 parent ccd7094 commit 6879c31

14 files changed

Lines changed: 787 additions & 850 deletions

File tree

docs/rv-manuals/rv-reference-manual/rv-reference-manual-chapter-four.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,9 @@ import rv.qtutils
236236
# Gets the current RV session windows as a PySide QMainWindow.
237237
rvSessionWindow = rv.qtutils.sessionWindow()
238238

239-
# Gets the current RV session GL view as a PySide QGLWidget.
239+
# Gets the current RV session view host as a PySide QWidget. Note: the GL
240+
# viewport is now a native child window embedded in this host (via
241+
# createWindowContainer), so this is a plain QWidget, not a QOpenGLWidget.
240242
rvSessionGLView = rv.qtutils.sessionGLView()
241243

242244
# Gets the current RV session top tool bar as a PySide QToolBar.

src/bin/apps/rv/main.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,14 @@ int utf8Main(int argc, char* argv[])
356356
// Qt 5.12.1 specific
357357
// Disable Qt Quick hardware rendering because QwebEngineView conflicts with
358358
// QGLWidget
359-
setEnvVar("QT_QUICK_BACKEND", "software");
359+
//
360+
// Direction C: the RV viewport is now a native GL window (GLWindow) hosted
361+
// via createWindowContainer, not a QOpenGLWidget. The main window no longer
362+
// forces the OpenGL RHI backend, so QtWebEngine's QQuickWidget can composite
363+
// on the platform default backend at hardware speed. The old software Qt
364+
// Quick workaround (which caused the ~77 ms per-frame web-view composite) is
365+
// therefore no longer needed.
366+
// setEnvVar("QT_QUICK_BACKEND", "software");
360367

361368
#if defined(PLATFORM_LINUX)
362369
// Work around for Wacom Tablet issue on linux
@@ -369,6 +376,14 @@ int utf8Main(int argc, char* argv[])
369376
// (RV Preferences/Rendering/Multithread GPU Upload)
370377
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
371378

379+
// Share GL resources across every QOpenGLContext in the process. This is a
380+
// documented QtWebEngine requirement, and it lets RV's auxiliary GL
381+
// surfaces -- the second-output ScreenView and the multithreaded-upload
382+
// worker device -- share textures/FBOs with the main viewport context
383+
// without an explicit, ordering-sensitive setShareContext() call. Must be
384+
// set before the QApplication is constructed.
385+
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
386+
372387
TwkUtil::MemPool::initialize();
373388

374389
string altPrefsPath;

src/lib/app/RvCommon/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ SET(_sources
4848
RvApplication.cpp
4949
DiagnosticsView.cpp
5050
GLView.cpp
51+
GLWindow.cpp
5152
TwkQTAction.cpp
5253
MediaDirModel.cpp
5354
RvNetworkDialog.cpp

src/lib/app/RvCommon/DesktopVideoDevice.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,10 @@ namespace Rv
157157
{
158158
TWK_GLDEBUG;
159159

160-
QSurfaceFormat fmt = shareDevice()->widget()->format();
160+
QSurfaceFormat fmt = shareDevice()->glSurfaceFormat();
161161
fmt.setSwapInterval(m_vsync ? 1 : 0);
162162

163-
ScreenView* vw = new ScreenView(fmt, 0, shareDevice()->widget(), Qt::Window);
163+
ScreenView* vw = new ScreenView(fmt, 0, shareDevice()->glShareContext(), Qt::Window);
164164
setViewWidget(vw);
165165

166166
QTGLVideoDevice* vd = new QTGLVideoDevice(0, "local view", vw);
@@ -747,11 +747,11 @@ namespace Rv
747747

748748
void DesktopVideoDevice::sortVideoFormatsByWidth() { sort(m_videoFormats.begin(), m_videoFormats.end(), widthSort); }
749749

750-
DesktopVideoDevice::ScreenView::ScreenView(const QSurfaceFormat& fmt, QWidget* parent, QOpenGLWidget* glViewShare,
750+
DesktopVideoDevice::ScreenView::ScreenView(const QSurfaceFormat& fmt, QWidget* parent, QOpenGLContext* glShareContext,
751751
Qt::WindowFlags flags)
752752
: QOpenGLWidget(parent, flags)
753753
{
754-
m_glViewShare = glViewShare;
754+
m_glShareContext = glShareContext;
755755
setFormat(fmt);
756756

757757
// Important: set PartialUpdate, because otherwise
@@ -764,9 +764,9 @@ namespace Rv
764764
{
765765
QOpenGLWidget::initializeGL();
766766

767-
if (m_glViewShare && context() && context()->isValid())
767+
if (m_glShareContext && context() && context()->isValid())
768768
{
769-
context()->setShareContext(m_glViewShare->context());
769+
context()->setShareContext(m_glShareContext);
770770
}
771771
}
772772

0 commit comments

Comments
 (0)