From da28e163d2aef547949c89809c6adbbd6e8db7a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= <tomasz.wlostowski@cern.ch>
Date: Wed, 7 Dec 2016 10:20:31 +0100
Subject: [PATCH] Optimizations/fixes to the VIEW/GAL classes: - much faster
 Cairo rendering (outperforms legacy) - improvements in VIEW update handling -
 fixed issue with grid rendering in flip view mode

---
 CMakeLists.txt                            |   1 +
 common/CMakeLists.txt                     |   1 +
 common/gal/cairo/cairo_compositor.cpp     |   2 +-
 common/gal/cairo/cairo_gal.cpp            | 172 +++++++++++++++-------
 common/gal/graphics_abstraction_layer.cpp |   5 +-
 common/gal/opengl/opengl_gal.cpp          |   5 +-
 common/view/view.cpp                      |  54 ++-----
 common/view/view_group.cpp                |   4 +-
 include/class_draw_panel_gal.h            |   2 +-
 include/gal/cairo/cairo_gal.h             |   5 +-
 include/profile.h                         |   2 +
 include/view/view.h                       |   4 +-
 pcbnew/pcb_draw_panel_gal.cpp             |  14 ++
 pcbnew/pcb_draw_panel_gal.h               |   2 +
 14 files changed, 168 insertions(+), 105 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42afeabcb1..8d71af2c60 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -531,6 +531,7 @@ endif()
 # Find Cairo library, required
 #
 find_package( Cairo 1.8.8 REQUIRED )
+find_package( Pixman 1.0 REQUIRED )
 
 #
 # Find Boost library, required.
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index c89470c55a..034fa552dd 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -4,6 +4,7 @@ include_directories(
     ./widgets
     ./dialog_about
     ${CAIRO_INCLUDE_DIR}
+    ${PIXMAN_INCLUDE_DIR}
     ${GLEW_INCLUDE_DIR}
     ${GLM_INCLUDE_DIR}
     ${CURL_INCLUDE_DIRS}
diff --git a/common/gal/cairo/cairo_compositor.cpp b/common/gal/cairo/cairo_compositor.cpp
index f81cb5a0bd..813c554c76 100644
--- a/common/gal/cairo/cairo_compositor.cpp
+++ b/common/gal/cairo/cairo_compositor.cpp
@@ -89,7 +89,7 @@ unsigned int CAIRO_COMPOSITOR::CreateBuffer()
 #endif /* __WXDEBUG__ */
 
     // Set default settings for the buffer
-    cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL );
+    cairo_set_antialias( context, CAIRO_ANTIALIAS_NONE );
     cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND );
     cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND );
 
diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp
index 0328eccb82..89f4f97933 100644
--- a/common/gal/cairo/cairo_gal.cpp
+++ b/common/gal/cairo/cairo_gal.cpp
@@ -33,11 +33,11 @@
 
 #include <limits>
 
+#include <pixman.h>
+
 using namespace KIGFX;
 
 
-const float CAIRO_GAL::LAYER_ALPHA = 0.8;
-
 
 CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
         wxEvtHandler* aPaintListener, const wxString& aName ) :
@@ -111,46 +111,94 @@ void CAIRO_GAL::BeginDrawing()
     compositor->SetBuffer( mainBuffer );
 
     // Cairo grouping prevents display of overlapping items on the same layer in the lighter color
-    cairo_push_group( currentContext );
+    //cairo_push_group( currentContext );
 }
 
+#include <profile.h>
 
 void CAIRO_GAL::EndDrawing()
 {
+
+    printf("EndDRAW!\n\n\n");
     // Force remaining objects to be drawn
     Flush();
 
     // Cairo grouping prevents display of overlapping items on the same layer in the lighter color
-    cairo_pop_group_to_source( currentContext );
-    cairo_paint_with_alpha( currentContext, LAYER_ALPHA );
+    //cairo_pop_group_to_source( currentContext );
+    //cairo_paint_with_alpha( currentContext, LAYER_ALPHA );
 
     // Merge buffers on the screen
+    PROF_COUNTER comp("cairo-comp");
     compositor->DrawBuffer( mainBuffer );
     compositor->DrawBuffer( overlayBuffer );
+    comp.show();
 
     // This code was taken from the wxCairo example - it's not the most efficient one
     // Here is a good place for optimizations
 
     // Now translate the raw context data from the format stored
     // by cairo into a format understood by wxImage.
+
+    PROF_COUNTER draw("cairo-draw");
+
     unsigned char* wxOutputPtr = wxOutput;
 
-    for( size_t count = 0; count < bufferSize; count++ )
+    printf("W %d sw %d\n", wxBufferWidth, screenSize.x);
+
+    pixman_image_t *dstImg = pixman_image_create_bits (PIXMAN_r8g8b8, screenSize.x, screenSize.y, (uint32_t*)wxOutput, wxBufferWidth * 3);
+    pixman_image_t *srcImg = pixman_image_create_bits (PIXMAN_a8b8g8r8, screenSize.x, screenSize.y, (uint32_t*)bitmapBuffer, wxBufferWidth * 4);
+
+    pixman_image_composite (PIXMAN_OP_SRC, srcImg, NULL, dstImg,
+    			    0, 0, 0, 0, 0, 0, screenSize.x, screenSize.y );
+
+    pixman_image_unref (srcImg);
+//    free (srcImg);
+    pixman_image_unref (dstImg);
+//free (dstImg);
+
+    /*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
-    }
+    }*/
+
+    draw.show();
+
+    PROF_COUNTER wxd1("wx-draw");
+
+
+    wxImage      img( wxBufferWidth, screenSize.y, (unsigned char*) wxOutput, true );
+    wxd1.show();
+
+        PROF_COUNTER wxd2("wx-draw2");
 
-    wxImage      img( screenSize.x, screenSize.y, (unsigned char*) wxOutput, true );
     wxBitmap     bmp( img );
-    wxClientDC   client_dc( this );
-    wxBufferedDC dc;
-    dc.Init( &client_dc, bmp );
+    wxd2.show();
+    PROF_COUNTER wxd3("wx-draw2");
+
+    wxMemoryDC mdc ( bmp );
+    wxd3.show();
+    PROF_COUNTER wxd("wx-drawf");
+
+    wxClientDC   clientDC( this );
+    //wxBufferedDC dc;
+    //dc.Init( &client_dc, bmp );
+    wxd.show();
+
+    PROF_COUNTER wxb("wx-blt");
+
+
+    blitCursor( mdc );
+
+    clientDC.Blit( 0, 0, screenSize.x, screenSize.y, &mdc, 0, 0, wxCOPY );
+    wxb.show();
+
+
+
 
     // Now it is the time to blit the mouse cursor
-    blitCursor( dc );
 
     deinitSurface();
 }
@@ -158,8 +206,12 @@ void CAIRO_GAL::EndDrawing()
 
 void CAIRO_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
 {
+
     cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
     cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
+    flushPath();
+//    cairo_set_source_rgb( currentContext, gridColor.r, gridColor.g, gridColor.b );
+    //cairo_stroke( currentContext );
     isElementAdded = true;
 }
 
@@ -174,6 +226,8 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo
 
         cairo_move_to( currentContext, (double) aStartPoint.x, (double) aStartPoint.y );
         cairo_line_to( currentContext, (double) aEndPoint.x, (double) aEndPoint.y );
+        cairo_set_source_rgba( currentContext, fillColor.r, fillColor.g, fillColor.b, fillColor.a);
+        cairo_stroke( currentContext );
     }
     else
     {
@@ -197,6 +251,7 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo
         cairo_line_to( currentContext, lineLength, -aWidth / 2.0 );
 
         cairo_restore( currentContext );
+        flushPath();
     }
 
     isElementAdded = true;
@@ -205,10 +260,9 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo
 
 void CAIRO_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
 {
-    // A circle is drawn using an arc
     cairo_new_sub_path( currentContext );
     cairo_arc( currentContext, aCenterPoint.x, aCenterPoint.y, aRadius, 0.0, 2 * M_PI );
-
+    flushPath();
     isElementAdded = true;
 }
 
@@ -233,6 +287,7 @@ void CAIRO_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aS
         cairo_line_to( currentContext, endPoint.x, endPoint.y );
         cairo_close_path( currentContext );
     }
+    flushPath();
 
     isElementAdded = true;
 }
@@ -250,6 +305,7 @@ void CAIRO_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd
     cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
     cairo_line_to( currentContext, diagonalPointB.x, diagonalPointB.y );
     cairo_close_path( currentContext );
+    flushPath();
 
     isElementAdded = true;
 }
@@ -263,6 +319,7 @@ void CAIRO_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControl
                     aControlPointB.y, aEndPoint.x, aEndPoint.y );
     cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
 
+    flushPath();
     isElementAdded = true;
 }
 
@@ -408,10 +465,10 @@ void CAIRO_GAL::SetLayerDepth( double aLayerDepth )
     {
         storePath();
 
-        cairo_pop_group_to_source( currentContext );
-        cairo_paint_with_alpha( currentContext, LAYER_ALPHA );
+        //cairo_pop_group_to_source( currentContext );
+        //cairo_paint_with_alpha( currentContext, LAYER_ALPHA );
 
-        cairo_push_group( currentContext );
+        //cairo_push_group( currentContext );
     }
 }
 
@@ -593,7 +650,7 @@ void CAIRO_GAL::DrawGroup( int aGroupNumber )
         case CMD_STROKE_PATH:
             cairo_set_source_rgb( currentContext, strokeColor.r, strokeColor.g, strokeColor.b );
             cairo_append_path( currentContext, it->cairoPath );
-            cairo_stroke( currentContext );
+                cairo_stroke( currentContext );
             break;
 
         case CMD_FILL_PATH:
@@ -734,8 +791,8 @@ void CAIRO_GAL::SetTarget( RENDER_TARGET aTarget )
     {
         storePath();
 
-        cairo_pop_group_to_source( currentContext );
-        cairo_paint_with_alpha( currentContext, LAYER_ALPHA );
+        //cairo_pop_group_to_source( currentContext );
+        //cairo_paint_with_alpha( currentContext, LAYER_ALPHA );
     }
 
     switch( aTarget )
@@ -751,8 +808,8 @@ void CAIRO_GAL::SetTarget( RENDER_TARGET aTarget )
         break;
     }
 
-    if( isInitialized )
-        cairo_push_group( currentContext );
+    //if( isInitialized )
+        //cairo_push_group( currentContext );
 
     currentTarget = aTarget;
 }
@@ -799,21 +856,36 @@ void CAIRO_GAL::SetCursorSize( unsigned int aCursorSize )
 
 void CAIRO_GAL::DrawCursor( const VECTOR2D& aCursorPosition )
 {
-    // Now we should only store the position of the mouse cursor
-    // The real drawing routines are in blitCursor()
-    cursorPosition = VECTOR2D( aCursorPosition.x - cursorSize / 2,
-                               aCursorPosition.y - cursorSize / 2 );
+    cursorPosition = aCursorPosition;
 }
 
-
 void CAIRO_GAL::drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
 {
     cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
     cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
-    cairo_set_source_rgb( currentContext, gridColor.r, gridColor.g, gridColor.b );
+    cairo_set_source_rgba( currentContext, gridColor.r, gridColor.g, gridColor.b, strokeColor.a );
     cairo_stroke( currentContext );
 }
 
+void CAIRO_GAL::flushPath()
+{
+        if( isFillEnabled )
+        {
+            cairo_set_source_rgba( currentContext, fillColor.r, fillColor.g, fillColor.b, fillColor.a );
+            if( isStrokeEnabled )
+                cairo_fill_preserve( currentContext );
+            else
+                cairo_fill( currentContext );
+        }
+
+        if( isStrokeEnabled )
+        {
+            cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g,
+                                  strokeColor.b, strokeColor.a );
+            cairo_stroke( currentContext );
+        }
+}
+
 
 void CAIRO_GAL::storePath()
 {
@@ -902,47 +974,32 @@ void CAIRO_GAL::initCursor()
 }
 
 
-void CAIRO_GAL::blitCursor( wxBufferedDC& clientDC )
+void CAIRO_GAL::blitCursor( wxMemoryDC& clientDC )
 {
     if( !isCursorEnabled )
         return;
 
-    wxMemoryDC cursorSave( *cursorPixelsSaved );
-    wxMemoryDC cursorShape( *cursorPixels );
+    auto p = ToScreen( cursorPosition );
 
-    if( !isDeleteSavedPixels )
-    {
-        // Restore pixels that were overpainted by the previous cursor
-        clientDC.Blit( savedCursorPosition.x, savedCursorPosition.y,
-                       cursorSize, cursorSize, &cursorSave, 0, 0 );
-    }
-    else
-    {
-        isDeleteSavedPixels = false;
-    }
+    clientDC.SetPen( *wxWHITE_PEN );
+    clientDC.DrawLine ( p.x - cursorSize / 2, p.y, p.x + cursorSize / 2, p.y );
+    clientDC.DrawLine ( p.x, p.y - cursorSize / 2, p.x, p.y + cursorSize / 2 );
 
-    // Store pixels that are going to be overpainted
-    VECTOR2D cursorScreen = ToScreen( cursorPosition ) - cursorSize / 2.0f;
-    cursorSave.Blit( 0, 0, cursorSize, cursorSize, &clientDC, cursorScreen.x, cursorScreen.y );
-
-    // Draw the cursor
-    clientDC.Blit( cursorScreen.x, cursorScreen.y, cursorSize, cursorSize,
-                   &cursorShape, 0, 0, wxOR );
-
-    savedCursorPosition.x = (wxCoord) cursorScreen.x;
-    savedCursorPosition.y = (wxCoord) cursorScreen.y;
 }
 
 
 void CAIRO_GAL::allocateBitmaps()
 {
+    wxBufferWidth = screenSize.x;
+    while( ((wxBufferWidth * 3) % 4) != 0 ) wxBufferWidth++;
+
     // Create buffer, use the system independent Cairo context backend
-    stride     = cairo_format_stride_for_width( GAL_FORMAT, screenSize.x );
+    stride     = cairo_format_stride_for_width( GAL_FORMAT, wxBufferWidth );
     bufferSize = stride * screenSize.y;
 
     bitmapBuffer        = new unsigned int[bufferSize];
     bitmapBufferBackup  = new unsigned int[bufferSize];
-    wxOutput            = new unsigned char[bufferSize * 3];
+    wxOutput            = new unsigned char[wxBufferWidth * 3 * screenSize.y];
 }
 
 
@@ -961,7 +1018,7 @@ void CAIRO_GAL::initSurface()
 
     // Create the Cairo surface
     surface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer, GAL_FORMAT,
-                                                   screenSize.x, screenSize.y, stride );
+                                                   wxBufferWidth, screenSize.y, stride );
     context = cairo_create( surface );
 #ifdef __WXDEBUG__
     cairo_status_t status = cairo_status( context );
@@ -969,7 +1026,7 @@ void CAIRO_GAL::initSurface()
 #endif /* __WXDEBUG__ */
     currentContext = context;
 
-    cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL );
+    cairo_set_antialias( context, CAIRO_ANTIALIAS_NONE );
 
     // Clear the screen
     ClearScreen( backgroundColor );
@@ -1037,6 +1094,9 @@ void CAIRO_GAL::drawPoly( const std::deque<VECTOR2D>& aPointList )
         cairo_line_to( currentContext, it->x, it->y );
     }
 
+    flushPath();
+    //cairo_fill( currentContext );
+
     isElementAdded = true;
 }
 
@@ -1054,6 +1114,8 @@ void CAIRO_GAL::drawPoly( const VECTOR2D aPointList[], int aListSize )
         cairo_line_to( currentContext, ptr->x, ptr->y );
     }
 
+    flushPath();
+
     isElementAdded = true;
 }
 
diff --git a/common/gal/graphics_abstraction_layer.cpp b/common/gal/graphics_abstraction_layer.cpp
index b6206c790e..a4432f66c7 100644
--- a/common/gal/graphics_abstraction_layer.cpp
+++ b/common/gal/graphics_abstraction_layer.cpp
@@ -151,8 +151,6 @@ void GAL::DrawGrid()
         int gridEndX    = KiROUND( worldEndPoint.x / gridSize.x );
         int gridStartY  = KiROUND( worldStartPoint.y / gridSize.y );
         int gridEndY    = KiROUND( worldEndPoint.y / gridSize.y );
-		int dirX = gridEndX >= gridStartX ? 1 : -1;
-		int dirY = gridEndY >= gridStartY ? 1 : -1;
 
         // Correct the index, else some lines are not correctly painted
         gridStartX -= std::abs( gridOrigin.x / gridSize.x ) + 1;
@@ -160,6 +158,9 @@ void GAL::DrawGrid()
         gridEndX += std::abs( gridOrigin.x / gridSize.x ) + 1;
         gridEndY += std::abs( gridOrigin.y / gridSize.y ) + 1;
 
+        int dirX = gridEndX >= gridStartX ? 1 : -1;
+        int dirY = gridEndY >= gridStartY ? 1 : -1;
+
         // Draw the grid behind all other layers
         SetLayerDepth( depthRange.y * 0.75 );
 
diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp
index 2fba9a2c2c..515050101c 100644
--- a/common/gal/opengl/opengl_gal.cpp
+++ b/common/gal/opengl/opengl_gal.cpp
@@ -878,8 +878,6 @@ void OPENGL_GAL::DrawGrid()
     int gridEndX = KiROUND( worldEndPoint.x / gridSize.x );
     int gridStartY = KiROUND( worldStartPoint.y / gridSize.y );
     int gridEndY = KiROUND( worldEndPoint.y / gridSize.y );
-	int dirX = gridStartX >= gridEndX ? -1 : 1;
-	int dirY = gridStartY >= gridEndY ? -1 : 1;
 
     // Correct the index, else some lines are not correctly painted
     gridStartX -= std::abs( gridOrigin.x / gridSize.x ) + 1;
@@ -887,6 +885,9 @@ void OPENGL_GAL::DrawGrid()
     gridEndX += std::abs( gridOrigin.x / gridSize.x ) + 1;
     gridEndY += std::abs( gridOrigin.y / gridSize.y ) + 1;
 
+    int dirX = gridStartX >= gridEndX ? -1 : 1;
+    int dirY = gridStartY >= gridEndY ? -1 : 1;
+
     glDisable( GL_DEPTH_TEST );
     glDisable( GL_TEXTURE_2D );
 
diff --git a/common/view/view.cpp b/common/view/view.cpp
index 459474fd50..3403a2afd0 100644
--- a/common/view/view.cpp
+++ b/common/view/view.cpp
@@ -262,7 +262,7 @@ VIEW::VIEW( bool aIsDynamic ) :
     m_dynamic( aIsDynamic )
 {
     m_boundary.SetMaximum();
-    m_needsUpdate.reserve( 32768 );
+    m_allItems.reserve( 32768 );
 
     // Redraw everything at the beginning
     MarkDirty();
@@ -310,6 +310,8 @@ void VIEW::Add( VIEW_ITEM* aItem )
     aItem->ViewGetLayers( layers, layers_count );
     aItem->viewPrivData()->saveLayers( layers, layers_count );
 
+    m_allItems.push_back(aItem);
+
     for( int i = 0; i < layers_count; ++i )
     {
         VIEW_LAYER& l = m_layers[layers[i]];
@@ -326,21 +328,18 @@ void VIEW::Remove( VIEW_ITEM* aItem )
 {
     if ( !aItem )
         return;
+
     auto viewData = aItem->viewPrivData();
 
     if ( !viewData )
         return;
 
-    if( viewData->requiredUpdate() != NONE )    // prevent from updating a removed item
-    {
-        std::vector<VIEW_ITEM*>::iterator item = std::find( m_needsUpdate.begin(),
-                                                            m_needsUpdate.end(), aItem );
+    auto item = std::find( m_allItems.begin(), m_allItems.end(), aItem );
 
-        if( item != m_needsUpdate.end() )
-        {
-            m_needsUpdate.erase( item );
-            viewData->clearUpdateFlags();
-        }
+    if( item != m_allItems.end() )
+    {
+        m_allItems.erase( item );
+        viewData->clearUpdateFlags();
     }
 
     int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
@@ -360,6 +359,7 @@ void VIEW::Remove( VIEW_ITEM* aItem )
     }
 
     viewData->deleteGroups();
+
     aItem->m_viewPrivData = nullptr;
 }
 
@@ -946,10 +946,7 @@ void VIEW::Clear()
 
     r.SetMaximum();
 
-    for( VIEW_ITEM* item : m_needsUpdate )
-        item->viewPrivData()->clearUpdateFlags();
-
-    m_needsUpdate.clear();
+    m_allItems.clear();
 
     for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
     {
@@ -1237,16 +1234,16 @@ void VIEW::UpdateItems()
 {
     m_gal->BeginUpdate();
 
-    for( VIEW_ITEM* item : m_needsUpdate )
+    for( VIEW_ITEM* item : m_allItems )
     {
         auto viewData = item->viewPrivData();
-        assert( viewData->m_requiredUpdate != NONE );
 
-        invalidateItem( item, viewData->m_requiredUpdate );
+        if ( viewData->m_requiredUpdate != NONE )
+            invalidateItem( item, viewData->m_requiredUpdate );
+        viewData->m_requiredUpdate = NONE;
     }
 
     m_gal->EndUpdate();
-    m_needsUpdate.clear();
 }
 
 
@@ -1341,31 +1338,10 @@ void VIEW::Update( VIEW_ITEM *aItem, int aUpdateFlags )
 
     assert( aUpdateFlags != NONE );
 
-    bool firstTime = (viewData->m_requiredUpdate == NONE);
-
     viewData->m_requiredUpdate |= aUpdateFlags;
 
-    if( firstTime )
-    {
-        MarkForUpdate( aItem );
-    }
-
-
-}
-
-void VIEW::MarkForUpdate( VIEW_ITEM* aItem )
-{
-    auto viewData = aItem->viewPrivData();
-
-	assert( viewData->m_requiredUpdate != NONE );
-
-    for ( auto item : m_needsUpdate )
-        assert(item != aItem);
-
-    m_needsUpdate.push_back( aItem );
 }
 
 const int VIEW::TOP_LAYER_MODIFIER = -VIEW_MAX_LAYERS;
 
-
 };
diff --git a/common/view/view_group.cpp b/common/view/view_group.cpp
index b55b1a4dba..3926090b11 100644
--- a/common/view/view_group.cpp
+++ b/common/view/view_group.cpp
@@ -118,7 +118,7 @@ void VIEW_GROUP::ViewDraw( int aLayer, VIEW* aView ) const
 
         for( int i = 0; i < layers_count; i++ )
         {
-            if( aView->IsCached( layers[i] ) && aView->IsLayerVisible( layers[i] ) )
+            if( aView->IsLayerVisible( layers[i] ) )
             {
                 gal->AdvanceDepth();
 
@@ -172,5 +172,5 @@ void VIEW_GROUP::ItemsViewUpdate( VIEW_ITEM::VIEW_UPDATE_FLAGS aFlags )
 
 void VIEW_GROUP::updateBbox()
 {
-   
+
 }
diff --git a/include/class_draw_panel_gal.h b/include/class_draw_panel_gal.h
index 77133d9fcf..d7f026fd6c 100644
--- a/include/class_draw_panel_gal.h
+++ b/include/class_draw_panel_gal.h
@@ -72,7 +72,7 @@ public:
      * Switches method of rendering graphics.
      * @param aGalType is a type of rendering engine that you want to use.
      */
-    bool SwitchBackend( GAL_TYPE aGalType );
+    virtual bool SwitchBackend( GAL_TYPE aGalType );
 
     /**
      * Function GetBackend
diff --git a/include/gal/cairo/cairo_gal.h b/include/gal/cairo/cairo_gal.h
index 9e5f249f32..9785613d82 100644
--- a/include/gal/cairo/cairo_gal.h
+++ b/include/gal/cairo/cairo_gal.h
@@ -346,6 +346,9 @@ private:
     bool                isInitialized;          ///< Are Cairo image & surface ready to use
     COLOR4D             backgroundColor;        ///< Background color
 
+    int wxBufferWidth;
+
+    void flushPath();
     // Methods
     void storePath();                           ///< Store the actual path
 
@@ -372,7 +375,7 @@ private:
     /**
      * @brief Blits cursor into the current screen.
      */
-    virtual void blitCursor( wxBufferedDC& clientDC );
+    virtual void blitCursor( wxMemoryDC& clientDC );
 
     /// Prepare Cairo surfaces for drawing
     void initSurface();
diff --git a/include/profile.h b/include/profile.h
index d14f29d889..780e68e826 100644
--- a/include/profile.h
+++ b/include/profile.h
@@ -119,7 +119,9 @@ public:
   {
     stop();
     fprintf(stderr,"%s took %.1f milliseconds.\n", m_name.c_str(), (double)m_cnt.msecs());
+    start();
   }
+  
   double msecs() const {
       return m_cnt.msecs();
   }
diff --git a/include/view/view.h b/include/view/view.h
index 451bc4ab01..806d875b01 100644
--- a/include/view/view.h
+++ b/include/view/view.h
@@ -751,8 +751,8 @@ private:
     /// Rendering order modifier for layers that are marked as top layers
     static const int TOP_LAYER_MODIFIER;
 
-    /// Items to be updated
-    std::vector<VIEW_ITEM*> m_needsUpdate;
+    /// Flat list of all items
+    std::vector<VIEW_ITEM*> m_allItems;
 };
 } // namespace KIGFX
 
diff --git a/pcbnew/pcb_draw_panel_gal.cpp b/pcbnew/pcb_draw_panel_gal.cpp
index c7b37a0245..93bcf83798 100644
--- a/pcbnew/pcb_draw_panel_gal.cpp
+++ b/pcbnew/pcb_draw_panel_gal.cpp
@@ -379,6 +379,12 @@ void PCB_DRAW_PANEL_GAL::setDefaultLayerOrder()
     }
 }
 
+bool PCB_DRAW_PANEL_GAL::SwitchBackend( GAL_TYPE aGalType )
+{
+    bool rv = EDA_DRAW_PANEL_GAL::SwitchBackend ( aGalType );
+    setDefaultLayerDeps();
+    return rv;
+}
 
 void PCB_DRAW_PANEL_GAL::setDefaultLayerDeps()
 {
@@ -400,6 +406,13 @@ void PCB_DRAW_PANEL_GAL::setDefaultLayerDeps()
         }
     }
 
+	// caching makes no sense for Cairo and other software renderers
+    if ( m_backend != GAL_TYPE_OPENGL )
+    {
+        for (int i = 0; i < KIGFX::VIEW::VIEW_MAX_LAYERS; i++)
+           m_view->SetLayerTarget(i, KIGFX::TARGET_NONCACHED);
+    }
+
     m_view->SetLayerTarget( ITEM_GAL_LAYER( ANCHOR_VISIBLE ), KIGFX::TARGET_NONCACHED );
     m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( ANCHOR_VISIBLE ) );
 
@@ -438,4 +451,5 @@ void PCB_DRAW_PANEL_GAL::setDefaultLayerDeps()
     m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( WORKSHEET ) );
     m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( GRID_VISIBLE ) );
     m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( DRC_VISIBLE ) );
+
 }
diff --git a/pcbnew/pcb_draw_panel_gal.h b/pcbnew/pcb_draw_panel_gal.h
index f4e397dc15..7911919ebe 100644
--- a/pcbnew/pcb_draw_panel_gal.h
+++ b/pcbnew/pcb_draw_panel_gal.h
@@ -83,6 +83,8 @@ public:
     ///> @copydoc EDA_DRAW_PANEL_GAL::OnShow()
     void OnShow() override;
 
+    bool SwitchBackend( GAL_TYPE aGalType ) override;
+
 protected:
     ///> Reassigns layer order to the initial settings.
     void setDefaultLayerOrder();