Smarter way of the overlay rendering (overlay is always refreshed, while cached&noncached targets only if the viewport or items have changed).

This commit is contained in:
Maciej Suminski 2013-08-19 11:02:38 +02:00
parent e87eea7abc
commit 43ae1cb98d
14 changed files with 279 additions and 103 deletions

View File

@ -127,6 +127,8 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
void EDA_DRAW_PANEL_GAL::onSize( wxSizeEvent& aEvent ) void EDA_DRAW_PANEL_GAL::onSize( wxSizeEvent& aEvent )
{ {
m_gal->ResizeScreen( aEvent.GetSize().x, aEvent.GetSize().y ); 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__ #ifdef __WXDEBUG__
prof_counter time; prof_counter time;
prof_start( &time, false ); prof_start( &time, false );
#endif /* __WXDEBUG__ */ #endif /* __WXDEBUG__ */
printf("Refresh!\n");
m_gal->BeginDrawing(); m_gal->BeginDrawing();
m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) ); m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
m_gal->ClearScreen(); m_gal->ClearScreen();
m_gal->DrawGrid();
m_view->Redraw(); m_view->Redraw();
m_gal->EndDrawing(); m_gal->EndDrawing();
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
prof_end( &time ); prof_end( &time );
wxLogDebug( wxT( "EDA_DRAW_PANEL_GAL::Refresh: %.0f ms (%.0f fps)" ), wxLogDebug( wxT( "EDA_DRAW_PANEL_GAL::Refresh: %.0f ms (%.0f fps)" ),
static_cast<double>( time.value ) / 1000.0, 1000000.0 / static_cast<double>( time.value ) ); static_cast<double>( time.value ) / 1000.0, 1000000.0 / static_cast<double>( time.value ) );
#endif /* __WXDEBUG__ */ #endif /* __WXDEBUG__ */
@ -184,6 +181,9 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
m_gal->SetScreenDPI( 106 ); // Display resolution setting m_gal->SetScreenDPI( 106 ); // Display resolution setting
m_gal->ComputeWorldScreenMatrix(); m_gal->ComputeWorldScreenMatrix();
wxSize size = GetClientSize();
m_gal->ResizeScreen( size.GetX(), size.GetY() );
if( m_painter ) if( m_painter )
m_painter->SetGAL( m_gal ); m_painter->SetGAL( m_gal );
@ -193,9 +193,6 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
m_view->RecacheAllItems( true ); m_view->RecacheAllItems( true );
} }
wxSize size = GetClientSize();
m_gal->ResizeScreen( size.GetX(), size.GetY() );
m_currentGal = aGalType; m_currentGal = aGalType;
} }

View File

@ -36,8 +36,6 @@ using namespace KiGfx;
CAIRO_COMPOSITOR::CAIRO_COMPOSITOR( cairo_t** aMainContext ) : CAIRO_COMPOSITOR::CAIRO_COMPOSITOR( cairo_t** aMainContext ) :
m_current( 0 ), m_currentContext( aMainContext ), m_mainContext( *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 // Pixel storage
BitmapPtr bitmap( new unsigned int[m_bufferSize] ); BitmapPtr bitmap( new unsigned int[m_bufferSize] );
memset( bitmap.get(), 0x00, m_bufferSize * sizeof(int) ); memset( bitmap.get(), 0x00, m_bufferSize * sizeof(int) );
// Create the Cairo surface // Create the Cairo surface
@ -78,10 +75,10 @@ unsigned int CAIRO_COMPOSITOR::GetBuffer()
CAIRO_FORMAT_ARGB32, m_width, CAIRO_FORMAT_ARGB32, m_width,
m_height, m_stride ); m_height, m_stride );
cairo_t* context = cairo_create( surface ); cairo_t* context = cairo_create( surface );
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
cairo_status_t status = cairo_status( context ); cairo_status_t status = cairo_status( context );
wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" ); wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" );
#endif /* __WXDEBUG__ */ #endif /* __WXDEBUG__ */
// Set default settings for the buffer // Set default settings for the buffer
cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL ); 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 ); cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND );
// Use the same transformation matrix as the main context // Use the same transformation matrix as the main context
cairo_get_matrix( m_mainContext, &m_matrix );
cairo_set_matrix( context, &m_matrix ); cairo_set_matrix( context, &m_matrix );
// Store the new buffer // Store the new buffer
@ -101,53 +99,41 @@ unsigned int CAIRO_COMPOSITOR::GetBuffer()
void CAIRO_COMPOSITOR::SetBuffer( unsigned int aBufferHandle ) void CAIRO_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
{ {
if( aBufferHandle <= usedBuffers() ) wxASSERT_MSG( aBufferHandle <= usedBuffers(), wxT( "Tried to use a not existing buffer" ) );
{
m_current = aBufferHandle - 1;
*m_currentContext = m_buffers[m_current].context;
}
#ifdef __WXDEBUG__ // Get currently used transformation matrix, so it can be applied to the new buffer
else cairo_get_matrix( *m_currentContext, &m_matrix );
wxLogDebug( wxT( "Tried to use a not existing buffer" ) );
#endif 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() void CAIRO_COMPOSITOR::ClearBuffer()
{ {
// Reset the transformation matrix, so it is possible to composite images using // Clear the pixel storage
// screen coordinates instead of world coordinates memset( m_buffers[m_current].bitmap.get(), 0x00, m_bufferSize * sizeof(int) );
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 );
} }
void CAIRO_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle ) void CAIRO_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle )
{ {
if( aBufferHandle <= usedBuffers() ) wxASSERT_MSG( aBufferHandle <= usedBuffers(), wxT( "Tried to use a not existing buffer" ) );
{
// Reset the transformation matrix, so it is possible to composite images using
// screen coordinates instead of world coordinates
cairo_identity_matrix( m_mainContext );
cairo_set_source_surface( m_mainContext, m_buffers[aBufferHandle - 1].surface, 0.0, 0.0 ); // Reset the transformation matrix, so it is possible to composite images using
cairo_paint( m_mainContext ); // screen coordinates instead of world coordinates
cairo_get_matrix( m_mainContext, &m_matrix );
cairo_identity_matrix( m_mainContext );
// Restore the transformation matrix // Draw the selected buffer contents
cairo_set_matrix( m_mainContext, &m_matrix ); cairo_set_source_surface( m_mainContext, m_buffers[aBufferHandle - 1].surface, 0.0, 0.0 );
} cairo_paint( m_mainContext );
#ifdef __WXDEBUG__ // Restore the transformation matrix
else cairo_set_matrix( m_mainContext, &m_matrix );
wxLogDebug( wxT( "Tried to use a not existing buffer" ) );
#endif
} }

View File

@ -48,6 +48,7 @@ CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
isGrouping = false; isGrouping = false;
isInitialized = false; isInitialized = false;
isDeleteSavedPixels = false; isDeleteSavedPixels = false;
validCompositor = false;
groupCounter = 0; groupCounter = 0;
// Connecting the event handlers // Connecting the event handlers
@ -90,7 +91,11 @@ CAIRO_GAL::~CAIRO_GAL()
void CAIRO_GAL::BeginDrawing() void CAIRO_GAL::BeginDrawing()
{ {
initSurface(); 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 grouping prevents display of overlapping items on the same layer in the lighter color
cairo_push_group( currentContext ); cairo_push_group( currentContext );
@ -120,9 +125,9 @@ void CAIRO_GAL::EndDrawing()
for( size_t count = 0; count < bufferSize; count++ ) for( size_t count = 0; count < bufferSize; count++ )
{ {
unsigned int value = bitmapBuffer[count]; unsigned int value = bitmapBuffer[count];
*wxOutputPtr++ = (value >> 16) & 0xff; // Red pixel *wxOutputPtr++ = ( value >> 16 ) & 0xff; // Red pixel
*wxOutputPtr++ = (value >> 8) & 0xff; // Green pixel *wxOutputPtr++ = ( value >> 8 ) & 0xff; // Green pixel
*wxOutputPtr++ = value & 0xff; // Blue pixel *wxOutputPtr++ = value & 0xff; // Blue pixel
} }
wxImage img( (int) screenSize.x, (int) screenSize.y, (unsigned char*) wxOutput, true ); 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(); deleteBitmaps();
allocateBitmaps(); allocateBitmaps();
if( validCompositor )
compositor->Resize( aWidth, aHeight );
validCompositor = false;
SetSize( wxSize( aWidth, aHeight ) ); 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 // If the compositor is not set, that means that there is a recaching process going on
// and we do not need the compositor now // and we do not need the compositor now
if( !compositor ) if( !validCompositor )
return; return;
// Cairo grouping prevents display of overlapping items on the same layer in the lighter color // 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 ) VECTOR2D CAIRO_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition )
{ {
MATRIX3x3D inverseMatrix = worldScreenMatrix.Inverse(); MATRIX3x3D inverseMatrix = worldScreenMatrix.Inverse();
@ -972,8 +1006,10 @@ void CAIRO_GAL::setCompositor()
compositor->Resize( screenSize.x, screenSize.y ); compositor->Resize( screenSize.x, screenSize.y );
// Prepare buffers // Prepare buffers
mainBuffer = compositor->GetBuffer(); mainBuffer = compositor->CreateBuffer();
overlayBuffer = compositor->GetBuffer(); overlayBuffer = compositor->CreateBuffer();
validCompositor = true;
} }

View File

@ -74,7 +74,7 @@ void OPENGL_COMPOSITOR::Initialize()
GL_RENDERBUFFER, m_depthBuffer ); GL_RENDERBUFFER, m_depthBuffer );
// Unbind the framebuffer, so by default all the rendering goes directly to the display // 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_currentFbo = 0;
m_initialized = true; 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 ); wxASSERT( m_initialized );
@ -169,8 +169,8 @@ unsigned int OPENGL_COMPOSITOR::GetBuffer()
ClearBuffer(); ClearBuffer();
glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glBindFramebuffer( GL_FRAMEBUFFER, DIRECT_RENDERING );
m_currentFbo = 0; m_currentFbo = DIRECT_RENDERING;
// Store the new buffer // Store the new buffer
OPENGL_BUFFER buffer = { textureTarget, attachmentPoint }; OPENGL_BUFFER buffer = { textureTarget, attachmentPoint };
@ -186,10 +186,10 @@ void OPENGL_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
return; return;
// Change the rendering destination to the selected attachment point // Change the rendering destination to the selected attachment point
if( aBufferHandle == 0 ) if( aBufferHandle == DIRECT_RENDERING )
{ {
glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glBindFramebuffer( GL_FRAMEBUFFER, DIRECT_RENDERING );
m_currentFbo = 0; m_currentFbo = DIRECT_RENDERING;
} }
else if( m_currentFbo != m_framebuffer ) else if( m_currentFbo != m_framebuffer )
{ {
@ -197,7 +197,7 @@ void OPENGL_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
m_currentFbo = m_framebuffer; m_currentFbo = m_framebuffer;
} }
if( m_currentFbo != 0 && m_current != aBufferHandle - 1 ) if( m_currentFbo != DIRECT_RENDERING )
{ {
m_current = aBufferHandle - 1; m_current = aBufferHandle - 1;
glDrawBuffer( m_buffers[m_current].attachmentPoint ); glDrawBuffer( m_buffers[m_current].attachmentPoint );
@ -219,8 +219,8 @@ void OPENGL_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle )
wxASSERT( m_initialized ); wxASSERT( m_initialized );
// Switch to the main framebuffer and blit the scene // Switch to the main framebuffer and blit the scene
glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glBindFramebuffer( GL_FRAMEBUFFER, DIRECT_RENDERING );
m_currentFbo = 0; m_currentFbo = DIRECT_RENDERING;
// Depth test has to be disabled to make transparency working // Depth test has to be disabled to make transparency working
glDisable( GL_DEPTH_TEST ); 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;

View File

@ -130,8 +130,8 @@ void OPENGL_GAL::BeginDrawing()
// Prepare rendering target buffers // Prepare rendering target buffers
compositor.Initialize(); compositor.Initialize();
mainBuffer = compositor.GetBuffer(); mainBuffer = compositor.CreateBuffer();
overlayBuffer = compositor.GetBuffer(); overlayBuffer = compositor.CreateBuffer();
isFramebufferInitialized = true; isFramebufferInitialized = true;
} }
@ -187,13 +187,10 @@ void OPENGL_GAL::BeginDrawing()
SetFillColor( fillColor ); SetFillColor( fillColor );
SetStrokeColor( strokeColor ); SetStrokeColor( strokeColor );
// Prepare buffers for drawing // Unbind buffers - set compositor for direct drawing
compositor.SetBuffer( mainBuffer ); compositor.SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING );
compositor.ClearBuffer();
compositor.SetBuffer( overlayBuffer );
compositor.ClearBuffer();
compositor.SetBuffer( 0 ); // Unbind buffers
// Remove all previously stored items
nonCachedManager.Clear(); nonCachedManager.Clear();
overlayManager.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 OPENGL_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition )
{ {
VECTOR2D cursorPosition = aCursorPosition; VECTOR2D cursorPosition = aCursorPosition;

View File

@ -39,6 +39,28 @@
using namespace KiGfx; 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 ) void VIEW::AddLayer( int aLayer, bool aDisplayOnly )
{ {
if( m_layers.find( aLayer ) == m_layers.end() ) if( m_layers.find( aLayer ) == m_layers.end() )
@ -197,25 +219,6 @@ int VIEW::Query( const BOX2I& aRect, std::vector<LayerItemPair>& 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 VECTOR2D VIEW::ToWorld( const VECTOR2D& aCoord, bool aAbsolute ) const
{ {
MATRIX3x3D matrix = m_gal->GetWorldScreenMatrix().Inverse(); 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 // clear group numbers, so everything is going to be recached
clearGroupCache(); 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. // force the new GAL to display the current viewport.
SetCenter( m_center ); SetCenter( m_center );
SetScale( m_scale ); SetScale( m_scale );
@ -326,6 +334,10 @@ void VIEW::SetScale( double aScale, const VECTOR2D& aAnchor )
SetCenter( m_center - delta ); SetCenter( m_center - delta );
m_scale = aScale; 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_center = aCenter;
m_gal->SetLookAtPoint( m_center ); m_gal->SetLookAtPoint( m_center );
m_gal->ComputeWorldScreenMatrix(); 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; m_orderedLayers[n++] = &i->second;
sort( m_orderedLayers.begin(), m_orderedLayers.end(), compareRenderingOrder ); 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 ) 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 ); drawItem drawFunc( this, l );
m_gal->SetTarget( l->target ); m_gal->SetTarget( l->target );
m_gal->SetLayerDepth( l->renderingOrder ); m_gal->SetLayerDepth( l->renderingOrder );
l->items->Query( aRect, drawFunc ); l->items->Query( aRect, drawFunc );
l->isDirty = false;
} }
l->isDirty = false;
} }
} }
@ -648,9 +666,27 @@ void VIEW::Redraw()
VECTOR2D screenSize = m_gal->GetScreenPixelSize(); VECTOR2D screenSize = m_gal->GetScreenPixelSize();
BOX2I rect( ToWorld( VECTOR2D( 0, 0 ) ), BOX2I rect( ToWorld( VECTOR2D( 0, 0 ) ),
ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) ); ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) );
rect.Normalize(); 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 ); 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 ); wxLogDebug( wxT( "RecacheAllItems::%.1f ms" ), (double) totalRealTime.value / 1000.0 );
#endif /* __WXDEBUG__ */ #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];
}

View File

@ -50,8 +50,14 @@ public:
/// @copydoc COMPOSITOR::Resize() /// @copydoc COMPOSITOR::Resize()
virtual void Resize( unsigned int aWidth, unsigned int aHeight ); virtual void Resize( unsigned int aWidth, unsigned int aHeight );
/// @copydoc COMPOSITOR::CreateBuffer()
virtual unsigned int CreateBuffer();
/// @copydoc COMPOSITOR::GetBuffer() /// @copydoc COMPOSITOR::GetBuffer()
virtual unsigned int GetBuffer(); inline virtual unsigned int GetBuffer() const
{
return m_current + 1;
}
/// @copydoc COMPOSITOR::SetBuffer() /// @copydoc COMPOSITOR::SetBuffer()
virtual void SetBuffer( unsigned int aBufferHandle ); virtual void SetBuffer( unsigned int aBufferHandle );
@ -62,6 +68,21 @@ public:
/// @copydoc COMPOSITOR::DrawBuffer() /// @copydoc COMPOSITOR::DrawBuffer()
virtual void DrawBuffer( unsigned int aBufferHandle ); 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: protected:
typedef boost::shared_array<unsigned int> BitmapPtr; typedef boost::shared_array<unsigned int> BitmapPtr;
typedef struct typedef struct
@ -71,7 +92,7 @@ protected:
BitmapPtr bitmap; ///< Pixel storage BitmapPtr bitmap; ///< Pixel storage
} CAIRO_BUFFER; } CAIRO_BUFFER;
unsigned int m_current; ///< Currently used buffer handle unsigned int m_current; ///< Currently used buffer handle
typedef std::deque<CAIRO_BUFFER> CAIRO_BUFFERS; typedef std::deque<CAIRO_BUFFER> CAIRO_BUFFERS;
/// Pointer to the current context, so it can be changed /// Pointer to the current context, so it can be changed

View File

@ -221,6 +221,9 @@ public:
/// @copydoc GAL::GetTarget() /// @copydoc GAL::GetTarget()
virtual RenderTarget GetTarget() const; virtual RenderTarget GetTarget() const;
/// @copydoc GAL::ClearTarget()
virtual void ClearTarget( RenderTarget aTarget );
// ------- // -------
// Cursor // Cursor
// ------- // -------
@ -267,6 +270,7 @@ private:
unsigned int mainBuffer; ///< Handle to the main buffer unsigned int mainBuffer; ///< Handle to the main buffer
unsigned int overlayBuffer; ///< Handle to the overlay buffer unsigned int overlayBuffer; ///< Handle to the overlay buffer
RenderTarget currentTarget; ///< Current rendering target RenderTarget currentTarget; ///< Current rendering target
bool validCompositor; ///< Compositor initialization flag
// Variables related to wxWidgets // Variables related to wxWidgets
wxWindow* parentWindow; ///< Parent window wxWindow* parentWindow; ///< Parent window

View File

@ -57,12 +57,20 @@ public:
virtual void Resize( unsigned int aWidth, unsigned int aHeight ) = 0; 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. * 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. * @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() * Function SetBuffer()

View File

@ -42,6 +42,9 @@ namespace KiGfx
TARGET_NONCACHED, ///< Auxiliary rendering target (noncached) TARGET_NONCACHED, ///< Auxiliary rendering target (noncached)
TARGET_OVERLAY ///< Items that may change while the view stays the same (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_ */ #endif /* DEFINITIONS_H_ */

View File

@ -579,6 +579,13 @@ public:
*/ */
virtual RenderTarget GetTarget() const = 0; 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 // Grid methods
// ------------- // -------------

View File

@ -49,18 +49,30 @@ public:
/// @copydoc COMPOSITOR::Resize() /// @copydoc COMPOSITOR::Resize()
virtual void Resize( unsigned int aWidth, unsigned int aHeight ); virtual void Resize( unsigned int aWidth, unsigned int aHeight );
/// @copydoc COMPOSITOR::GetBuffer() /// @copydoc COMPOSITOR::CreateBuffer()
virtual unsigned int GetBuffer(); virtual unsigned int CreateBuffer();
/// @copydoc COMPOSITOR::SetBuffer() /// @copydoc COMPOSITOR::SetBuffer()
virtual void SetBuffer( unsigned int aBufferHandle ); 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() /// @copydoc COMPOSITOR::ClearBuffer()
virtual void ClearBuffer(); virtual void ClearBuffer();
/// @copydoc COMPOSITOR::DrawBuffer() /// @copydoc COMPOSITOR::DrawBuffer()
virtual void DrawBuffer( unsigned int aBufferHandle ); virtual void DrawBuffer( unsigned int aBufferHandle );
// Constant used by glBindFramebuffer to turn off rendering to framebuffers
static const unsigned int DIRECT_RENDERING = 0;
protected: protected:
typedef struct typedef struct
{ {

View File

@ -214,6 +214,9 @@ public:
/// @copydoc GAL::GetTarget() /// @copydoc GAL::GetTarget()
virtual RenderTarget GetTarget() const; virtual RenderTarget GetTarget() const;
/// @copydoc GAL::ClearTarget()
virtual void ClearTarget( RenderTarget aTarget );
// ------- // -------
// Cursor // Cursor
// ------- // -------

View File

@ -392,6 +392,20 @@ public:
*/ */
bool IsDirty() const; 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 static const int VIEW_MAX_LAYERS = 128; ///* maximum number of layers that may be shown
private: private:
@ -462,6 +476,14 @@ private:
return ( m_layers.at( aLayer ).target == TARGET_CACHED ); 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 /// Contains set of possible displayed layers and its properties
LayerMap m_layers; LayerMap m_layers;
@ -487,6 +509,9 @@ private:
/// static (eg. image/PDF) - does not. /// static (eg. image/PDF) - does not.
bool m_dynamic; 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 /// Rendering order modifier for layers that are marked as top layers
static const int TOP_LAYER_MODIFIER = -VIEW_MAX_LAYERS; static const int TOP_LAYER_MODIFIER = -VIEW_MAX_LAYERS;
}; };