From 588425a9d4d8553183009b7d4f1c62b3c97e30af Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 1 Sep 2016 21:23:08 +0200 Subject: [PATCH] Add caching of clipping box values for Direct2D graphics context Since retrieving actual clipping box is an expensive operation so to improve performance of wxD2DContext::GetClipBox() we need to store just retrieved clipping box data in the cache. These stored data will be then used in the forthcoming requests for clipping box values. Cached clipping box data are invalidated whenever clipping region is explicitly set using Clip()/ResetClip() or whenever transformation matrix is changed (to take into account new coordinates). If there is a call for clipping box (with GetClipBox) and cached data are marked as invalid then clipping box is retrieved/recalculated and stored in the cache. --- src/msw/graphicsd2d.cpp | 181 ++++++++++++++++++++++------------------ 1 file changed, 100 insertions(+), 81 deletions(-) diff --git a/src/msw/graphicsd2d.cpp b/src/msw/graphicsd2d.cpp index b240715b96..916f047b5a 100644 --- a/src/msw/graphicsd2d.cpp +++ b/src/msw/graphicsd2d.cpp @@ -54,6 +54,8 @@ #pragma hdrstop #endif +#include // for FLT_MAX, FLT_MIN + #ifndef WX_PRECOMP #include "wx/dc.h" #include "wx/dcclient.h" @@ -62,7 +64,6 @@ #include "wx/module.h" #include "wx/window.h" #include "wx/msw/private.h" - #include // for FLT_MAX #endif // !WX_PRECOMP #include "wx/graphics.h" @@ -3442,16 +3443,15 @@ private: private: ID2D1Factory* m_direct2dFactory; - wxSharedPtr m_renderTargetHolder; - wxStack m_stateStack; - wxStack m_layers; - ID2D1RenderTarget* m_cachedRenderTarget; - D2D1::Matrix3x2F m_initTransform; + // Clipping box + bool m_isClipBoxValid; + double m_clipX1, m_clipY1, m_clipX2, m_clipY2; + private: wxDECLARE_NO_COPY_CLASS(wxD2DContext); }; @@ -3510,6 +3510,8 @@ void wxD2DContext::Init() m_composition = wxCOMPOSITION_OVER; m_renderTargetHolder->Bind(this); m_enableOffset = true; + m_isClipBoxValid = false; + m_clipX1 = m_clipY1 = m_clipX2 = m_clipY2 = 0.0; EnsureInitialized(); } @@ -3575,6 +3577,8 @@ void wxD2DContext::SetClipLayer(ID2D1Geometry* clipGeometry) GetRenderTarget()->PushLayer(ld.params, clipLayer); // Store layer parameters. m_layers.push(ld); + + m_isClipBoxValid = false; } void wxD2DContext::ResetClip() @@ -3619,102 +3623,113 @@ void wxD2DContext::ResetClip() } // Restore current transformation matrix. GetRenderTarget()->SetTransform(&currTransform); + + m_isClipBoxValid = false; } void wxD2DContext::GetClipBox(wxDouble* x, wxDouble* y, wxDouble* w, wxDouble* h) { - // To obtain actual clipping box we have to start with rectangle - // covering the entire render target and interesect with this rectangle - // all clipping layers. Bounding box of the final geometry - // (being intersection of all clipping layers) is a clipping box. - - HRESULT hr; - wxCOMPtr rectGeometry; - hr = m_direct2dFactory->CreateRectangleGeometry( - D2D1::RectF(0.0F, 0.0F, (FLOAT)m_width, (FLOAT)m_height), - &rectGeometry); - wxCHECK_HRESULT_RET(hr); - - wxCOMPtr clipGeometry(rectGeometry); - - wxStack layers(m_layers); - while( !layers.empty() ) + if ( !m_isClipBoxValid ) { - LayerData ld = layers.top(); - layers.pop(); + // To obtain actual clipping box we have to start with rectangle + // covering the entire render target and interesect with this rectangle + // all clipping layers. Bounding box of the final geometry + // (being intersection of all clipping layers) is a clipping box. - if ( ld.type == CLIP_LAYER ) + HRESULT hr; + wxCOMPtr rectGeometry; + hr = m_direct2dFactory->CreateRectangleGeometry( + D2D1::RectF(0.0F, 0.0F, (FLOAT)m_width, (FLOAT)m_height), + &rectGeometry); + wxCHECK_HRESULT_RET(hr); + + wxCOMPtr clipGeometry(rectGeometry); + + wxStack layers(m_layers); + while( !layers.empty() ) { - // If current geometry is empty (null region) - // or there is no intersection between geometries - // then final result is "null" rectangle geometry. - FLOAT area; - hr = ld.geometry->ComputeArea(ld.transformMatrix, &area); - wxCHECK_HRESULT_RET(hr); - D2D1_GEOMETRY_RELATION geomRel; - hr = clipGeometry->CompareWithGeometry(ld.geometry, ld.transformMatrix, &geomRel); - wxCHECK_HRESULT_RET(hr); - if ( area <= FLT_MIN || geomRel == D2D1_GEOMETRY_RELATION_DISJOINT ) + LayerData ld = layers.top(); + layers.pop(); + + if ( ld.type == CLIP_LAYER ) { - wxCOMPtr nullGeometry; - hr = m_direct2dFactory->CreateRectangleGeometry( - D2D1::RectF(0.0F, 0.0F, 0.0F, 0.0F), &nullGeometry); + // If current geometry is empty (null region) + // or there is no intersection between geometries + // then final result is "null" rectangle geometry. + FLOAT area; + hr = ld.geometry->ComputeArea(ld.transformMatrix, &area); + wxCHECK_HRESULT_RET(hr); + D2D1_GEOMETRY_RELATION geomRel; + hr = clipGeometry->CompareWithGeometry(ld.geometry, ld.transformMatrix, &geomRel); + wxCHECK_HRESULT_RET(hr); + if ( area <= FLT_MIN || geomRel == D2D1_GEOMETRY_RELATION_DISJOINT ) + { + wxCOMPtr nullGeometry; + hr = m_direct2dFactory->CreateRectangleGeometry( + D2D1::RectF(0.0F, 0.0F, 0.0F, 0.0F), &nullGeometry); + wxCHECK_HRESULT_RET(hr); + + clipGeometry.reset(); + clipGeometry = nullGeometry; + break; + } + + wxCOMPtr pathGeometryClip; + hr = m_direct2dFactory->CreatePathGeometry(&pathGeometryClip); + wxCHECK_HRESULT_RET(hr); + wxCOMPtr pGeometrySink; + hr = pathGeometryClip->Open(&pGeometrySink); wxCHECK_HRESULT_RET(hr); - clipGeometry.reset(); - clipGeometry = nullGeometry; - break; + hr = clipGeometry->CombineWithGeometry(ld.geometry, D2D1_COMBINE_MODE_INTERSECT, + ld.transformMatrix, pGeometrySink); + wxCHECK_HRESULT_RET(hr); + hr = pGeometrySink->Close(); + wxCHECK_HRESULT_RET(hr); + pGeometrySink.reset(); + + clipGeometry = pathGeometryClip; + pathGeometryClip.reset(); } - - wxCOMPtr pathGeometryClip; - hr = m_direct2dFactory->CreatePathGeometry(&pathGeometryClip); - wxCHECK_HRESULT_RET(hr); - wxCOMPtr pGeometrySink; - hr = pathGeometryClip->Open(&pGeometrySink); - wxCHECK_HRESULT_RET(hr); - - hr = clipGeometry->CombineWithGeometry(ld.geometry, D2D1_COMBINE_MODE_INTERSECT, - ld.transformMatrix, pGeometrySink); - wxCHECK_HRESULT_RET(hr); - hr = pGeometrySink->Close(); - wxCHECK_HRESULT_RET(hr); - pGeometrySink.reset(); - - clipGeometry = pathGeometryClip; - pathGeometryClip.reset(); } - } - // Final clipping geometry is given in device coordinates - // so we need to transform its bounds to logical coordinates. - D2D1::Matrix3x2F currTransform; - GetRenderTarget()->GetTransform(&currTransform); - currTransform.Invert(); + // Final clipping geometry is given in device coordinates + // so we need to transform its bounds to logical coordinates. + D2D1::Matrix3x2F currTransform; + GetRenderTarget()->GetTransform(&currTransform); + currTransform.Invert(); - D2D1_RECT_F bounds; - // First check if clip region is empty. - FLOAT clipArea; - hr = clipGeometry->ComputeArea(currTransform, &clipArea); - wxCHECK_HRESULT_RET(hr); - if ( clipArea <= FLT_MIN ) - { - bounds.left = bounds.top = bounds.right = bounds.bottom = 0.0F; - } - else - { - // If it is not empty then get it bounds. - hr = clipGeometry->GetBounds(currTransform, &bounds); + D2D1_RECT_F bounds; + // First check if clip region is empty. + FLOAT clipArea; + hr = clipGeometry->ComputeArea(currTransform, &clipArea); wxCHECK_HRESULT_RET(hr); + if ( clipArea <= FLT_MIN ) + { + bounds.left = bounds.top = bounds.right = bounds.bottom = 0.0F; + } + else + { + // If it is not empty then get it bounds. + hr = clipGeometry->GetBounds(currTransform, &bounds); + wxCHECK_HRESULT_RET(hr); + } + + m_clipX1 = bounds.left; + m_clipY1 = bounds.top; + m_clipX2 = bounds.right; + m_clipY2 = bounds.bottom; + m_isClipBoxValid = true; } if ( x ) - *x = bounds.left; + *x = m_clipX1; if ( y ) - *y = bounds.top; + *y = m_clipY1; if ( w ) - *w = (double)bounds.right - bounds.left; + *w = m_clipX2 - m_clipX1; if ( h ) - *h = (double)bounds.bottom - bounds.top; + *h = m_clipY2 - m_clipY1; } void* wxD2DContext::GetNativeContext() @@ -3924,6 +3939,8 @@ void wxD2DContext::SetTransform(const wxGraphicsMatrix& matrix) D2D1::Matrix3x2F m; m.SetProduct(wxGetD2DMatrixData(matrix)->GetMatrix3x2F(), m_initTransform); GetRenderTarget()->SetTransform(&m); + + m_isClipBoxValid = false; } wxGraphicsMatrix wxD2DContext::GetTransform() const @@ -4043,6 +4060,8 @@ void wxD2DContext::PopState() // Restore drawing state. GetRenderTarget()->RestoreDrawingState(state.drawingState); + + m_isClipBoxValid = false; } void wxD2DContext::GetTextExtent(