Support hidpi in Cairo GAL canvas; performance improvements.
We now draw onto wxBitmap directly, reducing the amount of copying. Also moves the bitmap blit into paint event handler. Modifies ClearScreen to work universally between Cairo/OpenGL backends.
This commit is contained in:
parent
31a0652c58
commit
8e90063258
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2017 CERN
|
||||
* Copyright (C) 2013-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2013-2024, 2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
|
@ -281,20 +281,10 @@ bool EDA_DRAW_PANEL_GAL::DoRePaint()
|
|||
m_gal->SetGridColor( settings->GetGridColor() );
|
||||
m_gal->SetCursorColor( settings->GetCursorColor() );
|
||||
|
||||
// TODO: find why ClearScreen() must be called here in opengl mode
|
||||
// and only if m_view->IsDirty() in Cairo mode to avoid display artifacts
|
||||
// when moving the mouse cursor
|
||||
if( m_backend == GAL_TYPE_OPENGL )
|
||||
m_gal->ClearScreen();
|
||||
m_gal->ClearScreen();
|
||||
|
||||
if( m_view->IsDirty() )
|
||||
{
|
||||
if( m_backend != GAL_TYPE_OPENGL // Already called in opengl
|
||||
&& m_view->IsTargetDirty( KIGFX::TARGET_NONCACHED ) )
|
||||
{
|
||||
m_gal->ClearScreen();
|
||||
}
|
||||
|
||||
m_view->ClearTargets();
|
||||
|
||||
// Grid has to be redrawn only when the NONCACHED target is redrawn
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2012-2023 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2012-2024 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2017-2018 CERN
|
||||
*
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <wx/image.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/rawbmp.h>
|
||||
|
||||
#include <gal/cairo/cairo_gal.h>
|
||||
#include <gal/cairo/cairo_compositor.h>
|
||||
|
@ -583,6 +584,9 @@ void CAIRO_GAL_BASE::DrawBitmap( const BITMAP_BASE& aBitmap, double alphaBlend )
|
|||
void CAIRO_GAL_BASE::ResizeScreen( int aWidth, int aHeight )
|
||||
{
|
||||
m_screenSize = VECTOR2I( aWidth, aHeight );
|
||||
|
||||
m_bitmapSize = VECTOR2I( std::ceil( m_screenSize.x * getScalingFactor() ),
|
||||
std::ceil( m_screenSize.y * getScalingFactor() ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -594,9 +598,9 @@ void CAIRO_GAL_BASE::Flush()
|
|||
|
||||
void CAIRO_GAL_BASE::ClearScreen()
|
||||
{
|
||||
cairo_set_source_rgb( m_currentContext, m_clearColor.r, m_clearColor.g, m_clearColor.b );
|
||||
cairo_rectangle( m_currentContext, 0.0, 0.0, m_screenSize.x, m_screenSize.y );
|
||||
cairo_fill( m_currentContext );
|
||||
cairo_set_source_rgb( m_context, m_clearColor.r, m_clearColor.g, m_clearColor.b );
|
||||
cairo_rectangle( m_context, 0.0, 0.0, m_bitmapSize.x, m_bitmapSize.y );
|
||||
cairo_fill( m_context );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1021,15 +1025,15 @@ void CAIRO_GAL_BASE::resetContext()
|
|||
|
||||
m_imageSurfaces.clear();
|
||||
|
||||
ClearScreen();
|
||||
|
||||
// Compute the world <-> screen transformations
|
||||
ComputeWorldScreenMatrix();
|
||||
|
||||
cairo_matrix_init( &m_cairoWorldScreenMatrix, m_worldScreenMatrix.m_data[0][0],
|
||||
m_worldScreenMatrix.m_data[1][0], m_worldScreenMatrix.m_data[0][1],
|
||||
m_worldScreenMatrix.m_data[1][1], m_worldScreenMatrix.m_data[0][2],
|
||||
m_worldScreenMatrix.m_data[1][2] );
|
||||
double sf = getScalingFactor();
|
||||
|
||||
cairo_matrix_init( &m_cairoWorldScreenMatrix,
|
||||
m_worldScreenMatrix.m_data[0][0] * sf, m_worldScreenMatrix.m_data[1][0] * sf,
|
||||
m_worldScreenMatrix.m_data[0][1] * sf, m_worldScreenMatrix.m_data[1][1] * sf,
|
||||
m_worldScreenMatrix.m_data[0][2] * sf, m_worldScreenMatrix.m_data[1][2] * sf );
|
||||
|
||||
// we work in screen-space coordinates and do the transforms outside.
|
||||
cairo_identity_matrix( m_context );
|
||||
|
@ -1337,8 +1341,10 @@ CAIRO_GAL::CAIRO_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
|
|||
m_currentTarget = TARGET_NONCACHED;
|
||||
SetTarget( TARGET_NONCACHED );
|
||||
|
||||
SetBackgroundStyle( wxBG_STYLE_PAINT );
|
||||
|
||||
m_bitmapBuffer = nullptr;
|
||||
m_wxOutput = nullptr;
|
||||
m_wxBitmap = nullptr;
|
||||
|
||||
m_parentWindow = aParent;
|
||||
m_mouseListener = aMouseListener;
|
||||
|
@ -1374,10 +1380,6 @@ CAIRO_GAL::CAIRO_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
|
|||
#endif
|
||||
|
||||
SetSize( aParent->GetClientSize() );
|
||||
m_screenSize = ToVECTOR2I( aParent->GetClientSize() );
|
||||
|
||||
// Allocate memory for pixel storage
|
||||
allocateBitmaps();
|
||||
|
||||
m_isInitialized = false;
|
||||
}
|
||||
|
@ -1413,45 +1415,44 @@ void CAIRO_GAL::EndDrawing()
|
|||
|
||||
// Now translate the raw context data from the format stored
|
||||
// by cairo into a format understood by wxImage.
|
||||
int height = m_screenSize.y;
|
||||
int height = m_bitmapSize.y;
|
||||
int stride = m_stride;
|
||||
|
||||
unsigned char* srcRow = m_bitmapBuffer;
|
||||
unsigned char* dst = m_wxOutput;
|
||||
|
||||
wxNativePixelData dstData( *m_wxBitmap );
|
||||
wxNativePixelData::Iterator di( dstData );
|
||||
|
||||
for( int y = 0; y < height; y++ )
|
||||
{
|
||||
for( int x = 0; x < stride; x += 4 )
|
||||
wxNativePixelData::Iterator rowStart = di;
|
||||
|
||||
for( int x = 0; x < stride; x += 4, ++di )
|
||||
{
|
||||
const unsigned char* src = srcRow + x;
|
||||
|
||||
#if defined( __BYTE_ORDER__ ) && ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ )
|
||||
// XRGB
|
||||
dst[0] = src[1];
|
||||
dst[1] = src[2];
|
||||
dst[2] = src[3];
|
||||
di.Red() = src[1];
|
||||
di.Green() = src[2];
|
||||
di.Blue() = src[3];
|
||||
#else
|
||||
// BGRX
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[0];
|
||||
di.Red() = src[2];
|
||||
di.Green() = src[1];
|
||||
di.Blue() = src[0];
|
||||
#endif
|
||||
dst += 3;
|
||||
}
|
||||
|
||||
srcRow += stride;
|
||||
|
||||
di = rowStart;
|
||||
di.OffsetY( dstData, 1 );
|
||||
}
|
||||
|
||||
wxImage img( m_wxBufferWidth, m_screenSize.y, m_wxOutput, true );
|
||||
wxBitmap bmp( img );
|
||||
wxMemoryDC mdc( bmp );
|
||||
wxClientDC clientDC( this );
|
||||
|
||||
// Now it is the time to blit the mouse cursor
|
||||
blitCursor( mdc );
|
||||
clientDC.Blit( 0, 0, m_screenSize.x, m_screenSize.y, &mdc, 0, 0, wxCOPY );
|
||||
|
||||
deinitSurface();
|
||||
|
||||
Refresh(); // Trigger repaint
|
||||
}
|
||||
|
||||
|
||||
|
@ -1472,7 +1473,7 @@ void CAIRO_GAL::ResizeScreen( int aWidth, int aHeight )
|
|||
allocateBitmaps();
|
||||
|
||||
if( m_validCompositor )
|
||||
m_compositor->Resize( aWidth, aHeight );
|
||||
m_compositor->Resize( m_bitmapSize.x, m_bitmapSize.y );
|
||||
|
||||
m_validCompositor = false;
|
||||
|
||||
|
@ -1563,7 +1564,7 @@ void CAIRO_GAL::initSurface()
|
|||
return;
|
||||
|
||||
m_surface = cairo_image_surface_create_for_data( m_bitmapBuffer, GAL_FORMAT, m_wxBufferWidth,
|
||||
m_screenSize.y, m_stride );
|
||||
m_bitmapSize.y, m_stride );
|
||||
|
||||
m_context = cairo_create( m_surface );
|
||||
|
||||
|
@ -1594,17 +1595,18 @@ void CAIRO_GAL::deinitSurface()
|
|||
|
||||
void CAIRO_GAL::allocateBitmaps()
|
||||
{
|
||||
m_wxBufferWidth = m_screenSize.x;
|
||||
m_wxBufferWidth = m_bitmapSize.x;
|
||||
|
||||
// Create buffer, use the system independent Cairo context backend
|
||||
m_stride = cairo_format_stride_for_width( GAL_FORMAT, m_wxBufferWidth );
|
||||
m_bufferSize = m_stride * m_screenSize.y;
|
||||
m_bufferSize = m_stride * m_bitmapSize.y;
|
||||
|
||||
wxASSERT( m_bitmapBuffer == nullptr );
|
||||
m_bitmapBuffer = new unsigned char[m_bufferSize];
|
||||
|
||||
wxASSERT( m_wxOutput == nullptr );
|
||||
m_wxOutput = new unsigned char[m_wxBufferWidth * 3 * m_screenSize.y];
|
||||
wxASSERT( m_wxBitmap == nullptr );
|
||||
m_wxBitmap = new wxBitmap( m_wxBufferWidth, m_bitmapSize.y, 24 );
|
||||
m_wxBitmap->SetScaleFactor( getScalingFactor() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1613,8 +1615,8 @@ void CAIRO_GAL::deleteBitmaps()
|
|||
delete[] m_bitmapBuffer;
|
||||
m_bitmapBuffer = nullptr;
|
||||
|
||||
delete[] m_wxOutput;
|
||||
m_wxOutput = nullptr;
|
||||
delete m_wxBitmap;
|
||||
m_wxBitmap = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1622,7 +1624,7 @@ void CAIRO_GAL::setCompositor()
|
|||
{
|
||||
// Recreate the compositor with the new Cairo context
|
||||
m_compositor.reset( new CAIRO_COMPOSITOR( &m_currentContext ) );
|
||||
m_compositor->Resize( m_screenSize.x, m_screenSize.y );
|
||||
m_compositor->Resize( m_bitmapSize.x, m_bitmapSize.y );
|
||||
m_compositor->SetAntialiasingMode( m_options.cairo_antialiasing_mode );
|
||||
|
||||
// Prepare buffers
|
||||
|
@ -1636,7 +1638,22 @@ void CAIRO_GAL::setCompositor()
|
|||
|
||||
void CAIRO_GAL::onPaint( wxPaintEvent& aEvent )
|
||||
{
|
||||
PostPaint( aEvent );
|
||||
// We should have the rendered image in m_wxBitmap after EDA_DRAW_PANEL_GAL::onPaint
|
||||
|
||||
if( !m_wxBitmap )
|
||||
{
|
||||
wxLogDebug( "CAIRO_GAL::onPaint null output bitmap buffer" );
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Now it is the time to blit the mouse cursor
|
||||
wxMemoryDC mdc( *m_wxBitmap );
|
||||
blitCursor( mdc );
|
||||
}
|
||||
|
||||
wxPaintDC paintDC( this );
|
||||
paintDC.DrawBitmap( *m_wxBitmap, 0, 0 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1672,6 +1689,12 @@ bool CAIRO_GAL::updatedGalDisplayOptions( const GAL_DISPLAY_OPTIONS& aOptions )
|
|||
}
|
||||
|
||||
|
||||
double CAIRO_GAL::getScalingFactor()
|
||||
{
|
||||
return GetContentScaleFactor();
|
||||
};
|
||||
|
||||
|
||||
bool CAIRO_GAL::SetNativeCursorStyle( KICURSOR aCursor, bool aHiDPI )
|
||||
{
|
||||
// Store the current cursor type and get the wxCursor for it
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2012-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2017-2018 CERN
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
|
@ -252,6 +252,9 @@ protected:
|
|||
const VECTOR2D xform( double x, double y ); // rotation, scale and offset
|
||||
const VECTOR2D xform( const VECTOR2D& aP ); // rotation, scale and offset
|
||||
|
||||
// Return the scaling factor for current window.
|
||||
virtual double getScalingFactor() { return 1.0; }
|
||||
|
||||
/**
|
||||
* Transform according to the rotation from m_currentWorld2Screen transform matrix.
|
||||
*
|
||||
|
@ -452,6 +455,8 @@ public:
|
|||
/// @copydoc GAL::EndDrawing()
|
||||
void EndDrawing() override;
|
||||
|
||||
protected:
|
||||
|
||||
/// Prepare Cairo surfaces for drawing
|
||||
void initSurface();
|
||||
|
||||
|
@ -492,6 +497,9 @@ public:
|
|||
///< Cairo-specific update handlers
|
||||
bool updatedGalDisplayOptions( const GAL_DISPLAY_OPTIONS& aOptions ) override;
|
||||
|
||||
///< For HiDPI support
|
||||
double getScalingFactor() override;
|
||||
|
||||
protected:
|
||||
// Compositor related variables
|
||||
std::shared_ptr<CAIRO_COMPOSITOR> m_compositor; ///< Object for layers compositing
|
||||
|
@ -507,7 +515,7 @@ protected:
|
|||
wxEvtHandler* m_mouseListener; ///< Mouse listener
|
||||
wxEvtHandler* m_paintListener; ///< Paint listener
|
||||
unsigned int m_bufferSize; ///< Size of buffers cairoOutput, bitmapBuffers
|
||||
unsigned char* m_wxOutput; ///< wxImage compatible buffer
|
||||
wxBitmap* m_wxBitmap; ///< Output buffer bitmap
|
||||
|
||||
// Variables related to Cairo <-> wxWidgets
|
||||
unsigned char* m_bitmapBuffer; ///< Storage of the Cairo image
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* Graphics Abstraction Layer (GAL) - base class
|
||||
*
|
||||
|
@ -1038,7 +1038,8 @@ protected:
|
|||
UTIL::LINK m_observerLink;
|
||||
|
||||
std::stack<double> m_depthStack; ///< Stored depth values
|
||||
VECTOR2I m_screenSize; ///< Screen size in screen coordinates
|
||||
VECTOR2I m_screenSize; ///< Screen size in screen (wx logical) coordinates
|
||||
VECTOR2I m_bitmapSize; ///< Bitmap size, in physical pixels
|
||||
|
||||
double m_worldUnitLength; ///< The unit length of the world coordinates [inch]
|
||||
double m_screenDPI; ///< The dots per inch of the screen
|
||||
|
|
Loading…
Reference in New Issue