From abb6af14fb632d32d8cce83b4042acd6f9a4767e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Fri, 22 Sep 2017 11:12:57 +0200 Subject: Fix viewport resizing bug in renderer After the recent fix for rendering intersecting quads, DelegatedFrameNode no longer builds scene graph nodes for DrawQuads that are outside the visible area. This means that the structure of the scene graph now depends on the size of the visible area, however the logic for deciding whether to update or rebuild the scene graph was not updated to reflect this fact. As a result we may try to update e.g. a QSGImageNode as if it were a QSGRectangleNode leading to a crash. Task-number: QTBUG-62112 Change-Id: I6e2e9dee4238d208fc2be98669281c2d4d4962d7 Reviewed-by: Peter Varga Reviewed-by: Allan Sandfeld Jensen --- src/core/delegated_frame_node.cpp | 24 ++++++++++++++++-------- src/core/delegated_frame_node.h | 1 + src/core/type_conversion.h | 5 +++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index be0858310..73e0420af 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -850,8 +850,8 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // countering the scale of devicePixel-scaled tiles when rendering them // to the final surface. QMatrix4x4 matrix; - matrix.scale(1 / m_chromiumCompositorData->frameDevicePixelRatio, - 1 / m_chromiumCompositorData->frameDevicePixelRatio); + const float devicePixelRatio = m_chromiumCompositorData->frameDevicePixelRatio; + matrix.scale(1 / devicePixelRatio, 1 / devicePixelRatio); if (QSGTransformNode::matrix() != matrix) setMatrix(matrix); @@ -873,12 +873,21 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, frameData->resource_list.clear(); QScopedPointer nodeHandler; + const QSizeF viewportSizeInPt = apiDelegate->screenRect().size(); + const QSize viewportSize = (viewportSizeInPt * devicePixelRatio).toSize(); + // We first compare if the render passes from the previous frame data are structurally // equivalent to the render passes in the current frame data. If they are, we are going // to reuse the old nodes. Otherwise, we will delete the old nodes and build a new tree. + // + // Additionally, because we clip (i.e. don't build scene graph nodes for) quads outside + // of the visible area, we also have to rebuild the tree whenever the window is resized. #if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) cc::DelegatedFrameData *previousFrameData = m_chromiumCompositorData->previousFrameData.get(); - const bool buildNewTree = !areRenderPassStructuresEqual(frameData, previousFrameData) || m_sceneGraphNodes.empty(); + const bool buildNewTree = + !areRenderPassStructuresEqual(frameData, previousFrameData) || + m_sceneGraphNodes.empty() || + viewportSize != m_previousViewportSize; #else // No updates possible with old scenegraph nodes const bool buildNewTree = true; @@ -912,10 +921,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // All RenderPasses except the last one are rendered to an FBO. cc::RenderPass *rootRenderPass = frameData->render_pass_list.back().get(); - QRectF screenRectQt = apiDelegate->screenRect(); - gfx::Size thisSize(int(screenRectQt.width() * m_chromiumCompositorData->frameDevicePixelRatio), - int(screenRectQt.height() * m_chromiumCompositorData->frameDevicePixelRatio)); - + gfx::Rect viewportRect(toGfx(viewportSize)); for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) { cc::RenderPass *pass = frameData->render_pass_list.at(i).get(); @@ -947,7 +953,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, scissorRect = pass->output_rect; } else { renderPassParent = this; - scissorRect = gfx::Rect(thisSize); + scissorRect = viewportRect; scissorRect += rootRenderPass->output_rect.OffsetFromOrigin(); } @@ -1015,6 +1021,8 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, ResourceHolderIterator end = resourceCandidates.constEnd(); for (ResourceHolderIterator it = resourceCandidates.constBegin(); it != end ; ++it) resourcesToRelease->push_back((*it)->returnResource()); + + m_previousViewportSize = viewportSize; } void DelegatedFrameNode::flushPolygons( diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index cc682988d..3b6453a4c 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -143,6 +143,7 @@ private: bool m_contextShared; QScopedPointer m_offsurface; #endif + QSize m_previousViewportSize; }; } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index ed02a9db9..39c4f610c 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -139,6 +139,11 @@ inline QRectF toQt(const gfx::RectF &rect) return QRectF(rect.x(), rect.y(), rect.width(), rect.height()); } +inline gfx::Size toGfx(const QSize &size) +{ + return gfx::Size(size.width(), size.height()); +} + inline QSize toQt(const gfx::Size &size) { return QSize(size.width(), size.height()); -- cgit v1.2.3