From 43ae1cb98d152a3d0b2eba4dbde567c2400575ae Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 19 Aug 2013 11:02:38 +0200 Subject: [PATCH] Smarter way of the overlay rendering (overlay is always refreshed, while cached&noncached targets only if the viewport or items have changed). --- common/drawpanel_gal.cpp | 13 ++-- common/gal/cairo/cairo_compositor.cpp | 68 +++++++---------- common/gal/cairo/cairo_gal.cpp | 50 ++++++++++-- common/gal/opengl/opengl_compositor.cpp | 22 +++--- common/gal/opengl/opengl_gal.cpp | 38 ++++++++-- common/view/view.cpp | 96 ++++++++++++++++++------ include/gal/cairo/cairo_compositor.h | 25 +++++- include/gal/cairo/cairo_gal.h | 4 + include/gal/compositor.h | 12 ++- include/gal/definitions.h | 3 + include/gal/graphics_abstraction_layer.h | 7 ++ include/gal/opengl/opengl_compositor.h | 16 +++- include/gal/opengl/opengl_gal.h | 3 + include/view/view.h | 25 ++++++ 14 files changed, 279 insertions(+), 103 deletions(-) diff --git a/common/drawpanel_gal.cpp b/common/drawpanel_gal.cpp index ba7e5b38b7..d99f2b0920 100644 --- a/common/drawpanel_gal.cpp +++ b/common/drawpanel_gal.cpp @@ -127,6 +127,8 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) void EDA_DRAW_PANEL_GAL::onSize( wxSizeEvent& aEvent ) { m_gal->ResizeScreen( aEvent.GetSize().x, aEvent.GetSize().y ); + m_view->SetTargetDirty( KiGfx::TARGET_CACHED ); + m_view->SetTargetDirty( KiGfx::TARGET_NONCACHED ); } @@ -134,24 +136,19 @@ void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect ) { #ifdef __WXDEBUG__ prof_counter time; - prof_start( &time, false ); #endif /* __WXDEBUG__ */ - printf("Refresh!\n"); - m_gal->BeginDrawing(); m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) ); m_gal->ClearScreen(); - m_gal->DrawGrid(); m_view->Redraw(); m_gal->EndDrawing(); #ifdef __WXDEBUG__ prof_end( &time ); - wxLogDebug( wxT( "EDA_DRAW_PANEL_GAL::Refresh: %.0f ms (%.0f fps)" ), static_cast( time.value ) / 1000.0, 1000000.0 / static_cast( time.value ) ); #endif /* __WXDEBUG__ */ @@ -184,6 +181,9 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) m_gal->SetScreenDPI( 106 ); // Display resolution setting m_gal->ComputeWorldScreenMatrix(); + wxSize size = GetClientSize(); + m_gal->ResizeScreen( size.GetX(), size.GetY() ); + if( m_painter ) m_painter->SetGAL( m_gal ); @@ -193,9 +193,6 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) m_view->RecacheAllItems( true ); } - wxSize size = GetClientSize(); - m_gal->ResizeScreen( size.GetX(), size.GetY() ); - m_currentGal = aGalType; } diff --git a/common/gal/cairo/cairo_compositor.cpp b/common/gal/cairo/cairo_compositor.cpp index d5b101493a..b700dc6874 100644 --- a/common/gal/cairo/cairo_compositor.cpp +++ b/common/gal/cairo/cairo_compositor.cpp @@ -36,8 +36,6 @@ using namespace KiGfx; CAIRO_COMPOSITOR::CAIRO_COMPOSITOR( cairo_t** aMainContext ) : m_current( 0 ), m_currentContext( aMainContext ), m_mainContext( *aMainContext ) { - // Obtain the transformation matrix used in the main context - cairo_get_matrix( m_mainContext, &m_matrix ); } @@ -65,11 +63,10 @@ void CAIRO_COMPOSITOR::Resize( unsigned int aWidth, unsigned int aHeight ) } -unsigned int CAIRO_COMPOSITOR::GetBuffer() +unsigned int CAIRO_COMPOSITOR::CreateBuffer() { // Pixel storage BitmapPtr bitmap( new unsigned int[m_bufferSize] ); - memset( bitmap.get(), 0x00, m_bufferSize * sizeof(int) ); // Create the Cairo surface @@ -78,10 +75,10 @@ unsigned int CAIRO_COMPOSITOR::GetBuffer() CAIRO_FORMAT_ARGB32, m_width, m_height, m_stride ); cairo_t* context = cairo_create( surface ); - #ifdef __WXDEBUG__ - cairo_status_t status = cairo_status( context ); - wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" ); - #endif /* __WXDEBUG__ */ +#ifdef __WXDEBUG__ + cairo_status_t status = cairo_status( context ); + wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" ); +#endif /* __WXDEBUG__ */ // Set default settings for the buffer cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL ); @@ -89,6 +86,7 @@ unsigned int CAIRO_COMPOSITOR::GetBuffer() cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND ); // Use the same transformation matrix as the main context + cairo_get_matrix( m_mainContext, &m_matrix ); cairo_set_matrix( context, &m_matrix ); // Store the new buffer @@ -101,53 +99,41 @@ unsigned int CAIRO_COMPOSITOR::GetBuffer() void CAIRO_COMPOSITOR::SetBuffer( unsigned int aBufferHandle ) { - if( aBufferHandle <= usedBuffers() ) - { - m_current = aBufferHandle - 1; - *m_currentContext = m_buffers[m_current].context; - } + wxASSERT_MSG( aBufferHandle <= usedBuffers(), wxT( "Tried to use a not existing buffer" ) ); -#ifdef __WXDEBUG__ - else - wxLogDebug( wxT( "Tried to use a not existing buffer" ) ); -#endif + // Get currently used transformation matrix, so it can be applied to the new buffer + cairo_get_matrix( *m_currentContext, &m_matrix ); + + m_current = aBufferHandle - 1; + *m_currentContext = m_buffers[m_current].context; + + // Apply the current transformation matrix + cairo_set_matrix( *m_currentContext, &m_matrix ); } void CAIRO_COMPOSITOR::ClearBuffer() { - // Reset the transformation matrix, so it is possible to composite images using - // screen coordinates instead of world coordinates - cairo_identity_matrix( m_buffers[m_current].context ); - - cairo_set_source_rgba( m_buffers[m_current].context, 0.0, 0.0, 0.0, 0.0 ); - cairo_rectangle( m_buffers[m_current].context, 0.0, 0.0, m_width, m_height ); - cairo_fill( m_buffers[m_current].context ); - - // Restore the transformation matrix - cairo_set_matrix( m_buffers[m_current].context, &m_matrix ); + // Clear the pixel storage + memset( m_buffers[m_current].bitmap.get(), 0x00, m_bufferSize * sizeof(int) ); } void CAIRO_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle ) { - if( aBufferHandle <= usedBuffers() ) - { - // Reset the transformation matrix, so it is possible to composite images using - // screen coordinates instead of world coordinates - cairo_identity_matrix( m_mainContext ); + wxASSERT_MSG( aBufferHandle <= usedBuffers(), wxT( "Tried to use a not existing buffer" ) ); - cairo_set_source_surface( m_mainContext, m_buffers[aBufferHandle - 1].surface, 0.0, 0.0 ); - cairo_paint( m_mainContext ); + // Reset the transformation matrix, so it is possible to composite images using + // screen coordinates instead of world coordinates + cairo_get_matrix( m_mainContext, &m_matrix ); + cairo_identity_matrix( m_mainContext ); - // Restore the transformation matrix - cairo_set_matrix( m_mainContext, &m_matrix ); - } + // Draw the selected buffer contents + cairo_set_source_surface( m_mainContext, m_buffers[aBufferHandle - 1].surface, 0.0, 0.0 ); + cairo_paint( m_mainContext ); -#ifdef __WXDEBUG__ - else - wxLogDebug( wxT( "Tried to use a not existing buffer" ) ); -#endif + // Restore the transformation matrix + cairo_set_matrix( m_mainContext, &m_matrix ); } diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index 91e614f8fa..7b4f6972f7 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -48,6 +48,7 @@ CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, isGrouping = false; isInitialized = false; isDeleteSavedPixels = false; + validCompositor = false; groupCounter = 0; // Connecting the event handlers @@ -90,7 +91,11 @@ CAIRO_GAL::~CAIRO_GAL() void CAIRO_GAL::BeginDrawing() { initSurface(); - setCompositor(); + if( !validCompositor ) + setCompositor(); + + compositor->SetMainContext( context ); + compositor->SetBuffer( mainBuffer ); // Cairo grouping prevents display of overlapping items on the same layer in the lighter color cairo_push_group( currentContext ); @@ -120,9 +125,9 @@ void CAIRO_GAL::EndDrawing() for( size_t count = 0; count < bufferSize; count++ ) { unsigned int value = bitmapBuffer[count]; - *wxOutputPtr++ = (value >> 16) & 0xff; // Red pixel - *wxOutputPtr++ = (value >> 8) & 0xff; // Green pixel - *wxOutputPtr++ = value & 0xff; // Blue pixel + *wxOutputPtr++ = ( value >> 16 ) & 0xff; // Red pixel + *wxOutputPtr++ = ( value >> 8 ) & 0xff; // Green pixel + *wxOutputPtr++ = value & 0xff; // Blue pixel } wxImage img( (int) screenSize.x, (int) screenSize.y, (unsigned char*) wxOutput, true ); @@ -273,6 +278,10 @@ void CAIRO_GAL::ResizeScreen( int aWidth, int aHeight ) deleteBitmaps(); allocateBitmaps(); + if( validCompositor ) + compositor->Resize( aWidth, aHeight ); + validCompositor = false; + SetSize( wxSize( aWidth, aHeight ) ); } @@ -719,7 +728,7 @@ void CAIRO_GAL::SetTarget( RenderTarget aTarget ) { // If the compositor is not set, that means that there is a recaching process going on // and we do not need the compositor now - if( !compositor ) + if( !validCompositor ) return; // Cairo grouping prevents display of overlapping items on the same layer in the lighter color @@ -751,6 +760,31 @@ RenderTarget CAIRO_GAL::GetTarget() const } +void CAIRO_GAL::ClearTarget( RenderTarget aTarget ) +{ + // Save the current state + unsigned int currentBuffer = compositor->GetBuffer(); + + switch( aTarget ) + { + // Cached and noncached items are rendered to the same buffer + default: + case TARGET_CACHED: + case TARGET_NONCACHED: + compositor->SetBuffer( mainBuffer ); + break; + + case TARGET_OVERLAY: + compositor->SetBuffer( overlayBuffer ); + break; + } + compositor->ClearBuffer(); + + // Restore the previous state + compositor->SetBuffer( currentBuffer ); +} + + VECTOR2D CAIRO_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition ) { MATRIX3x3D inverseMatrix = worldScreenMatrix.Inverse(); @@ -972,8 +1006,10 @@ void CAIRO_GAL::setCompositor() compositor->Resize( screenSize.x, screenSize.y ); // Prepare buffers - mainBuffer = compositor->GetBuffer(); - overlayBuffer = compositor->GetBuffer(); + mainBuffer = compositor->CreateBuffer(); + overlayBuffer = compositor->CreateBuffer(); + + validCompositor = true; } diff --git a/common/gal/opengl/opengl_compositor.cpp b/common/gal/opengl/opengl_compositor.cpp index 9357d8dbbe..3485131aa7 100644 --- a/common/gal/opengl/opengl_compositor.cpp +++ b/common/gal/opengl/opengl_compositor.cpp @@ -74,7 +74,7 @@ void OPENGL_COMPOSITOR::Initialize() GL_RENDERBUFFER, m_depthBuffer ); // Unbind the framebuffer, so by default all the rendering goes directly to the display - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glBindFramebuffer( GL_FRAMEBUFFER, DIRECT_RENDERING ); m_currentFbo = 0; m_initialized = true; @@ -91,7 +91,7 @@ void OPENGL_COMPOSITOR::Resize( unsigned int aWidth, unsigned int aHeight ) } -unsigned int OPENGL_COMPOSITOR::GetBuffer() +unsigned int OPENGL_COMPOSITOR::CreateBuffer() { wxASSERT( m_initialized ); @@ -169,8 +169,8 @@ unsigned int OPENGL_COMPOSITOR::GetBuffer() ClearBuffer(); - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - m_currentFbo = 0; + glBindFramebuffer( GL_FRAMEBUFFER, DIRECT_RENDERING ); + m_currentFbo = DIRECT_RENDERING; // Store the new buffer OPENGL_BUFFER buffer = { textureTarget, attachmentPoint }; @@ -186,10 +186,10 @@ void OPENGL_COMPOSITOR::SetBuffer( unsigned int aBufferHandle ) return; // Change the rendering destination to the selected attachment point - if( aBufferHandle == 0 ) + if( aBufferHandle == DIRECT_RENDERING ) { - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - m_currentFbo = 0; + glBindFramebuffer( GL_FRAMEBUFFER, DIRECT_RENDERING ); + m_currentFbo = DIRECT_RENDERING; } else if( m_currentFbo != m_framebuffer ) { @@ -197,7 +197,7 @@ void OPENGL_COMPOSITOR::SetBuffer( unsigned int aBufferHandle ) m_currentFbo = m_framebuffer; } - if( m_currentFbo != 0 && m_current != aBufferHandle - 1 ) + if( m_currentFbo != DIRECT_RENDERING ) { m_current = aBufferHandle - 1; glDrawBuffer( m_buffers[m_current].attachmentPoint ); @@ -219,8 +219,8 @@ void OPENGL_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle ) wxASSERT( m_initialized ); // Switch to the main framebuffer and blit the scene - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - m_currentFbo = 0; + glBindFramebuffer( GL_FRAMEBUFFER, DIRECT_RENDERING ); + m_currentFbo = DIRECT_RENDERING; // Depth test has to be disabled to make transparency working glDisable( GL_DEPTH_TEST ); @@ -279,4 +279,4 @@ void OPENGL_COMPOSITOR::clean() } -GLuint OPENGL_COMPOSITOR::m_currentFbo = 0; +GLuint OPENGL_COMPOSITOR::m_currentFbo = DIRECT_RENDERING; diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 9b6b17ff8b..0325a173fe 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -130,8 +130,8 @@ void OPENGL_GAL::BeginDrawing() // Prepare rendering target buffers compositor.Initialize(); - mainBuffer = compositor.GetBuffer(); - overlayBuffer = compositor.GetBuffer(); + mainBuffer = compositor.CreateBuffer(); + overlayBuffer = compositor.CreateBuffer(); isFramebufferInitialized = true; } @@ -187,13 +187,10 @@ void OPENGL_GAL::BeginDrawing() SetFillColor( fillColor ); SetStrokeColor( strokeColor ); - // Prepare buffers for drawing - compositor.SetBuffer( mainBuffer ); - compositor.ClearBuffer(); - compositor.SetBuffer( overlayBuffer ); - compositor.ClearBuffer(); - compositor.SetBuffer( 0 ); // Unbind buffers + // Unbind buffers - set compositor for direct drawing + compositor.SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING ); + // Remove all previously stored items nonCachedManager.Clear(); overlayManager.Clear(); @@ -711,6 +708,31 @@ RenderTarget OPENGL_GAL::GetTarget() const } +void OPENGL_GAL::ClearTarget( RenderTarget aTarget ) +{ + // Save the current state + unsigned int oldTarget = compositor.GetBuffer(); + + switch( aTarget ) + { + // Cached and noncached items are rendered to the same buffer + default: + case TARGET_CACHED: + case TARGET_NONCACHED: + compositor.SetBuffer( mainBuffer ); + break; + + case TARGET_OVERLAY: + compositor.SetBuffer( overlayBuffer ); + break; + } + compositor.ClearBuffer(); + + // Restore the previous state + compositor.SetBuffer( oldTarget ); +} + + VECTOR2D OPENGL_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition ) { VECTOR2D cursorPosition = aCursorPosition; diff --git a/common/view/view.cpp b/common/view/view.cpp index 133707f7ad..3caed45b8b 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -39,6 +39,28 @@ using namespace KiGfx; +VIEW::VIEW( bool aIsDynamic ) : + m_enableOrderModifier( false ), + m_scale( 1.0 ), + m_painter( NULL ), + m_gal( NULL ), + m_dynamic( aIsDynamic ) +{ + // Redraw everything at the beginning + for( int i = 0; i < TARGETS_NUMBER; ++i ) + SetTargetDirty( i ); +} + + +VIEW::~VIEW() +{ + BOOST_FOREACH( LayerMap::value_type& l, m_layers ) + { + delete l.second.items; + } +} + + void VIEW::AddLayer( int aLayer, bool aDisplayOnly ) { if( m_layers.find( aLayer ) == m_layers.end() ) @@ -197,25 +219,6 @@ int VIEW::Query( const BOX2I& aRect, std::vector& aResult ) } -VIEW::VIEW( bool aIsDynamic ) : - m_enableOrderModifier( false ), - m_scale( 1.0 ), - m_painter( NULL ), - m_gal( NULL ), - m_dynamic( aIsDynamic ) -{ -} - - -VIEW::~VIEW() -{ - BOOST_FOREACH( LayerMap::value_type& l, m_layers ) - { - delete l.second.items; - } -} - - VECTOR2D VIEW::ToWorld( const VECTOR2D& aCoord, bool aAbsolute ) const { MATRIX3x3D matrix = m_gal->GetWorldScreenMatrix().Inverse(); @@ -267,6 +270,11 @@ void VIEW::SetGAL( GAL* aGal ) // clear group numbers, so everything is going to be recached clearGroupCache(); + // every target has to be refreshed + SetTargetDirty( TARGET_CACHED ); + SetTargetDirty( TARGET_NONCACHED ); + SetTargetDirty( TARGET_OVERLAY ); + // force the new GAL to display the current viewport. SetCenter( m_center ); SetScale( m_scale ); @@ -326,6 +334,10 @@ void VIEW::SetScale( double aScale, const VECTOR2D& aAnchor ) SetCenter( m_center - delta ); m_scale = aScale; + + // Redraw everything after the viewport has changed + SetTargetDirty( TARGET_CACHED ); + SetTargetDirty( TARGET_NONCACHED ); } @@ -334,6 +346,10 @@ void VIEW::SetCenter( const VECTOR2D& aCenter ) m_center = aCenter; m_gal->SetLookAtPoint( m_center ); m_gal->ComputeWorldScreenMatrix(); + + // Redraw everything after the viewport has changed + SetTargetDirty( TARGET_CACHED ); + SetTargetDirty( TARGET_NONCACHED ); } @@ -347,6 +363,8 @@ void VIEW::sortLayers() m_orderedLayers[n++] = &i->second; sort( m_orderedLayers.begin(), m_orderedLayers.end(), compareRenderingOrder ); + + SetTargetDirty( TARGET_CACHED ); } @@ -554,15 +572,15 @@ void VIEW::redrawRect( const BOX2I& aRect ) { BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers ) { - if( l->enabled && areRequiredLayersEnabled( l->id ) ) + if( l->enabled && isTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) ) { drawItem drawFunc( this, l ); m_gal->SetTarget( l->target ); m_gal->SetLayerDepth( l->renderingOrder ); l->items->Query( aRect, drawFunc ); - l->isDirty = false; } + l->isDirty = false; } } @@ -648,9 +666,27 @@ void VIEW::Redraw() VECTOR2D screenSize = m_gal->GetScreenPixelSize(); BOX2I rect( ToWorld( VECTOR2D( 0, 0 ) ), ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) ); - rect.Normalize(); + + if( isTargetDirty( TARGET_CACHED ) || isTargetDirty( TARGET_NONCACHED ) ) + { + // TARGET_CACHED and TARGET_NONCACHED have to be redrawn together, as they contain + // layers that rely on each other (eg. netnames are noncached, but tracks - are cached) + m_gal->ClearTarget( TARGET_NONCACHED ); + m_gal->ClearTarget( TARGET_CACHED ); + + SetTargetDirty( TARGET_NONCACHED ); + SetTargetDirty( TARGET_CACHED ); + + m_gal->DrawGrid(); + } + m_gal->ClearTarget( TARGET_OVERLAY ); + redrawRect( rect ); + + // All targets were redrawn, so nothing is dirty + SetTargetDirty( TARGET_CACHED, false ); + SetTargetDirty( TARGET_NONCACHED, false ); } @@ -801,3 +837,19 @@ void VIEW::RecacheAllItems( bool aImmediately ) wxLogDebug( wxT( "RecacheAllItems::%.1f ms" ), (double) totalRealTime.value / 1000.0 ); #endif /* __WXDEBUG__ */ } + + +bool VIEW::isTargetDirty( int aTarget ) const +{ + wxASSERT( aTarget < TARGETS_NUMBER ); + + // Check if any of layers belonging to the target is dirty + BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers ) + { + if( l->target == aTarget && l->isDirty ) + return true; + } + + // If no layer is dirty, just check the target status itself + return m_dirtyTargets[aTarget]; +} diff --git a/include/gal/cairo/cairo_compositor.h b/include/gal/cairo/cairo_compositor.h index b638b56a0a..116cfd7c0d 100644 --- a/include/gal/cairo/cairo_compositor.h +++ b/include/gal/cairo/cairo_compositor.h @@ -50,8 +50,14 @@ public: /// @copydoc COMPOSITOR::Resize() virtual void Resize( unsigned int aWidth, unsigned int aHeight ); + /// @copydoc COMPOSITOR::CreateBuffer() + virtual unsigned int CreateBuffer(); + /// @copydoc COMPOSITOR::GetBuffer() - virtual unsigned int GetBuffer(); + inline virtual unsigned int GetBuffer() const + { + return m_current + 1; + } /// @copydoc COMPOSITOR::SetBuffer() virtual void SetBuffer( unsigned int aBufferHandle ); @@ -62,6 +68,21 @@ public: /// @copydoc COMPOSITOR::DrawBuffer() virtual void DrawBuffer( unsigned int aBufferHandle ); + /** + * Function SetMainContext() + * Sets a context to be treated as the main context (ie. as a target of buffers rendering and + * as a source of settings for newly created buffers). + * + * @param aMainContext is the context that should be treated as the main one. + */ + inline virtual void SetMainContext( cairo_t* aMainContext ) + { + m_mainContext = aMainContext; + + // Use the context's transformation matrix + cairo_get_matrix( m_mainContext, &m_matrix ); + } + protected: typedef boost::shared_array BitmapPtr; typedef struct @@ -71,7 +92,7 @@ protected: BitmapPtr bitmap; ///< Pixel storage } CAIRO_BUFFER; - unsigned int m_current; ///< Currently used buffer handle + unsigned int m_current; ///< Currently used buffer handle typedef std::deque CAIRO_BUFFERS; /// Pointer to the current context, so it can be changed diff --git a/include/gal/cairo/cairo_gal.h b/include/gal/cairo/cairo_gal.h index 818cf0a84a..0c584049f1 100644 --- a/include/gal/cairo/cairo_gal.h +++ b/include/gal/cairo/cairo_gal.h @@ -221,6 +221,9 @@ public: /// @copydoc GAL::GetTarget() virtual RenderTarget GetTarget() const; + /// @copydoc GAL::ClearTarget() + virtual void ClearTarget( RenderTarget aTarget ); + // ------- // Cursor // ------- @@ -267,6 +270,7 @@ private: unsigned int mainBuffer; ///< Handle to the main buffer unsigned int overlayBuffer; ///< Handle to the overlay buffer RenderTarget currentTarget; ///< Current rendering target + bool validCompositor; ///< Compositor initialization flag // Variables related to wxWidgets wxWindow* parentWindow; ///< Parent window diff --git a/include/gal/compositor.h b/include/gal/compositor.h index db601d5617..1a9d924426 100644 --- a/include/gal/compositor.h +++ b/include/gal/compositor.h @@ -57,12 +57,20 @@ public: virtual void Resize( unsigned int aWidth, unsigned int aHeight ) = 0; /** - * Function GetBuffer() + * Function CreateBuffer() * prepares a new buffer that may be used as a rendering target. * * @return is the handle of the buffer. In case of failure 0 (zero) is returned as the handle. */ - virtual unsigned int GetBuffer() = 0; + virtual unsigned int CreateBuffer() = 0; + + /** + * Function GetBuffer() + * returns currently used buffer handle. + * + * @return Currently used buffer handle. + */ + virtual unsigned int GetBuffer() const = 0; /** * Function SetBuffer() diff --git a/include/gal/definitions.h b/include/gal/definitions.h index 5e9059a2df..ce18235bd1 100644 --- a/include/gal/definitions.h +++ b/include/gal/definitions.h @@ -42,6 +42,9 @@ namespace KiGfx TARGET_NONCACHED, ///< Auxiliary rendering target (noncached) TARGET_OVERLAY ///< Items that may change while the view stays the same (noncached) }; + + /// Number of available rendering targets + static const int TARGETS_NUMBER = 3; } #endif /* DEFINITIONS_H_ */ diff --git a/include/gal/graphics_abstraction_layer.h b/include/gal/graphics_abstraction_layer.h index 677cc28ac1..03da4451bf 100644 --- a/include/gal/graphics_abstraction_layer.h +++ b/include/gal/graphics_abstraction_layer.h @@ -579,6 +579,13 @@ public: */ virtual RenderTarget GetTarget() const = 0; + /** + * @brief Clears the target for rendering. + * + * @param aTarget is the target to be cleared. + */ + virtual void ClearTarget( RenderTarget aTarget ) = 0; + // ------------- // Grid methods // ------------- diff --git a/include/gal/opengl/opengl_compositor.h b/include/gal/opengl/opengl_compositor.h index 88d36f91fa..8b587fd3c6 100644 --- a/include/gal/opengl/opengl_compositor.h +++ b/include/gal/opengl/opengl_compositor.h @@ -49,18 +49,30 @@ public: /// @copydoc COMPOSITOR::Resize() virtual void Resize( unsigned int aWidth, unsigned int aHeight ); - /// @copydoc COMPOSITOR::GetBuffer() - virtual unsigned int GetBuffer(); + /// @copydoc COMPOSITOR::CreateBuffer() + virtual unsigned int CreateBuffer(); /// @copydoc COMPOSITOR::SetBuffer() virtual void SetBuffer( unsigned int aBufferHandle ); + /// @copydoc COMPOSITOR::GetBuffer() + inline virtual unsigned int GetBuffer() const + { + if( m_currentFbo == DIRECT_RENDERING ) + return DIRECT_RENDERING; + + return m_current + 1; + } + /// @copydoc COMPOSITOR::ClearBuffer() virtual void ClearBuffer(); /// @copydoc COMPOSITOR::DrawBuffer() virtual void DrawBuffer( unsigned int aBufferHandle ); + // Constant used by glBindFramebuffer to turn off rendering to framebuffers + static const unsigned int DIRECT_RENDERING = 0; + protected: typedef struct { diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 795f1e7622..66a2fd1712 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -214,6 +214,9 @@ public: /// @copydoc GAL::GetTarget() virtual RenderTarget GetTarget() const; + /// @copydoc GAL::ClearTarget() + virtual void ClearTarget( RenderTarget aTarget ); + // ------- // Cursor // ------- diff --git a/include/view/view.h b/include/view/view.h index 2d6ad6a0e5..f0caf95d02 100644 --- a/include/view/view.h +++ b/include/view/view.h @@ -392,6 +392,20 @@ public: */ bool IsDirty() const; + /** + * Function SetTargetDirty() + * Sets or clears target 'dirty' flag. + * @param aTarget is the target to set. + * @param aState says if the flag should be set or cleared. + */ + inline void SetTargetDirty( int aTarget, bool aState = true ) + { + wxASSERT( aTarget < TARGETS_NUMBER ); + + m_dirtyTargets[aTarget] = aState; + } + + static const int VIEW_MAX_LAYERS = 128; ///* maximum number of layers that may be shown private: @@ -462,6 +476,14 @@ private: return ( m_layers.at( aLayer ).target == TARGET_CACHED ); } + /** + * Function isTargetDirty() + * Returns true if any of layers belonging to the target or the target itself should be + * redrawn. + * @return True if the above condition is fulfilled. + */ + bool isTargetDirty( int aTarget ) const; + /// Contains set of possible displayed layers and its properties LayerMap m_layers; @@ -487,6 +509,9 @@ private: /// static (eg. image/PDF) - does not. bool m_dynamic; + /// Flags to mark targets as dirty, so they have to be redrawn on the next refresh event + bool m_dirtyTargets[TARGETS_NUMBER]; + /// Rendering order modifier for layers that are marked as top layers static const int TOP_LAYER_MODIFIER = -VIEW_MAX_LAYERS; };