Kaydet (Commit) d335ab62 authored tarafından Caolán McNamara's avatar Caolán McNamara

make gtk3 performance usable

only render into the backbuffer once, don't re-render on "draw".

In order that make that possible the back-buffer has to be refilled
on resize events and a whole pile of things had to be fixed in the
underlying svp backend.

now it scrolls like the wind, well comparitively anyway, and while
you probably wouldn't want to use it yet, you could in a pinch

Change-Id: I8938fa099e5594fd44c32baaad9043946280212c
üst bcf3897d
...@@ -174,7 +174,6 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider ...@@ -174,7 +174,6 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider
SalX11Screen m_nXScreen; SalX11Screen m_nXScreen;
GtkWidget* m_pWindow; GtkWidget* m_pWindow;
int m_nDuringRender;
GdkWindow* m_pForeignParent; GdkWindow* m_pForeignParent;
GdkNativeWindow m_aForeignParentWindow; GdkNativeWindow m_aForeignParentWindow;
GdkWindow* m_pForeignTopLevel; GdkWindow* m_pForeignTopLevel;
...@@ -237,8 +236,11 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider ...@@ -237,8 +236,11 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider
// signals // signals
static gboolean signalButton( GtkWidget*, GdkEventButton*, gpointer ); static gboolean signalButton( GtkWidget*, GdkEventButton*, gpointer );
static void signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer ); static void signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer );
#if GTK_CHECK_VERSION(3,0,0)
static gboolean signalDraw( GtkWidget*, cairo_t *cr, gpointer ); static gboolean signalDraw( GtkWidget*, cairo_t *cr, gpointer );
#else
static gboolean signalExpose( GtkWidget*, GdkEventExpose*, gpointer ); static gboolean signalExpose( GtkWidget*, GdkEventExpose*, gpointer );
#endif
static gboolean signalFocus( GtkWidget*, GdkEventFocus*, gpointer ); static gboolean signalFocus( GtkWidget*, GdkEventFocus*, gpointer );
static gboolean signalMap( GtkWidget*, GdkEvent*, gpointer ); static gboolean signalMap( GtkWidget*, GdkEvent*, gpointer );
static gboolean signalUnmap( GtkWidget*, GdkEvent*, gpointer ); static gboolean signalUnmap( GtkWidget*, GdkEvent*, gpointer );
...@@ -300,6 +302,7 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider ...@@ -300,6 +302,7 @@ class GtkSalFrame : public SalFrame, public X11WindowProvider
void askForXEmbedFocus( sal_Int32 nTimecode ); void askForXEmbedFocus( sal_Int32 nTimecode );
void AllocateFrame(); void AllocateFrame();
void TriggerPaintEvent();
void updateWMClass(); void updateWMClass();
void SetScreen( unsigned int nNewScreen, int eType, Rectangle *pSize = NULL ); void SetScreen( unsigned int nNewScreen, int eType, Rectangle *pSize = NULL );
...@@ -342,10 +345,8 @@ public: ...@@ -342,10 +345,8 @@ public:
#if GTK_CHECK_VERSION(3,0,0) #if GTK_CHECK_VERSION(3,0,0)
// only for gtk3 ... // only for gtk3 ...
cairo_t* getCairoContext(); cairo_t* getCairoContext();
void pushIgnoreDamage();
void popIgnoreDamage();
bool isDuringRender();
void renderArea( cairo_t *cr, cairo_rectangle_t *src ); void renderArea( cairo_t *cr, cairo_rectangle_t *src );
void damaged (const basegfx::B2IBox& rDamageRect);
#endif #endif
virtual ~GtkSalFrame(); virtual ~GtkSalFrame();
...@@ -446,8 +447,6 @@ public: ...@@ -446,8 +447,6 @@ public:
static GtkSalFrame *getFromWindow( GtkWindow *pWindow ); static GtkSalFrame *getFromWindow( GtkWindow *pWindow );
void damaged (const basegfx::B2IBox& rDamageRect);
virtual Window GetX11Window() SAL_OVERRIDE; virtual Window GetX11Window() SAL_OVERRIDE;
}; };
......
...@@ -37,10 +37,6 @@ class GtkSalGraphics : public SvpSalGraphics ...@@ -37,10 +37,6 @@ class GtkSalGraphics : public SvpSalGraphics
GtkSalFrame *mpFrame; GtkSalFrame *mpFrame;
public: public:
GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow ); GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow );
virtual void copyArea( long nDestX, long nDestY,
long nSrcX, long nSrcY,
long nSrcWidth, long nSrcHeight,
sal_uInt16 /*nFlags*/ ) SAL_OVERRIDE;
virtual bool drawNativeControl( ControlType nType, ControlPart nPart, virtual bool drawNativeControl( ControlType nType, ControlPart nPart,
const Rectangle& rControlRegion, const Rectangle& rControlRegion,
ControlState nState, const ImplControlValue& aValue, ControlState nState, const ImplControlValue& aValue,
......
...@@ -498,7 +498,6 @@ GtkSalFrame::GtkSalFrame( SalFrame* pParent, sal_uLong nStyle ) ...@@ -498,7 +498,6 @@ GtkSalFrame::GtkSalFrame( SalFrame* pParent, sal_uLong nStyle )
: m_nXScreen( getDisplay()->GetDefaultXScreen() ) : m_nXScreen( getDisplay()->GetDefaultXScreen() )
{ {
getDisplay()->registerFrame( this ); getDisplay()->registerFrame( this );
m_nDuringRender = 0;
m_bDefaultPos = true; m_bDefaultPos = true;
m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent ); m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
m_bWindowIsGtkPlug = false; m_bWindowIsGtkPlug = false;
...@@ -1500,7 +1499,10 @@ SalGraphics* GtkSalFrame::AcquireGraphics() ...@@ -1500,7 +1499,10 @@ SalGraphics* GtkSalFrame::AcquireGraphics()
#if GTK_CHECK_VERSION(3,0,0) #if GTK_CHECK_VERSION(3,0,0)
m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow ); m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow );
if( !m_aFrame.get() ) if( !m_aFrame.get() )
{
AllocateFrame(); AllocateFrame();
TriggerPaintEvent();
}
m_aGraphics[i].pGraphics->setDevice( m_aFrame ); m_aGraphics[i].pGraphics->setDevice( m_aFrame );
#else // common case: #else // common case:
m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow, m_nXScreen ); m_aGraphics[i].pGraphics = new GtkSalGraphics( this, m_pWindow, m_nXScreen );
...@@ -1866,6 +1868,7 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate ) ...@@ -1866,6 +1868,7 @@ void GtkSalFrame::Show( bool bVisible, bool bNoActivate )
Flush(); Flush();
} }
CallCallback( SALEVENT_RESIZE, NULL ); CallCallback( SALEVENT_RESIZE, NULL );
TriggerPaintEvent();
} }
} }
...@@ -2073,6 +2076,9 @@ void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_u ...@@ -2073,6 +2076,9 @@ void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_u
CallCallback( SALEVENT_MOVE, NULL ); CallCallback( SALEVENT_MOVE, NULL );
else if( bMoved && bSized ) else if( bMoved && bSized )
CallCallback( SALEVENT_MOVERESIZE, NULL ); CallCallback( SALEVENT_MOVERESIZE, NULL );
if (bSized)
TriggerPaintEvent();
} }
void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight ) void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight )
...@@ -2129,7 +2135,6 @@ void GtkSalFrame::SetWindowState( const SalFrameState* pState ) ...@@ -2129,7 +2135,6 @@ void GtkSalFrame::SetWindowState( const SalFrameState* pState )
maGeometry.nWidth = pState->mnMaximizedWidth; maGeometry.nWidth = pState->mnMaximizedWidth;
maGeometry.nHeight = pState->mnMaximizedHeight; maGeometry.nHeight = pState->mnMaximizedHeight;
updateScreenNumber(); updateScreenNumber();
AllocateFrame();
m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED ); m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ), m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
...@@ -2176,6 +2181,7 @@ void GtkSalFrame::SetWindowState( const SalFrameState* pState ) ...@@ -2176,6 +2181,7 @@ void GtkSalFrame::SetWindowState( const SalFrameState* pState )
else else
gtk_window_deiconify( GTK_WINDOW(m_pWindow) ); gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
} }
TriggerPaintEvent();
} }
bool GtkSalFrame::GetWindowState( SalFrameState* pState ) bool GtkSalFrame::GetWindowState( SalFrameState* pState )
...@@ -3355,47 +3361,32 @@ cairo_t* GtkSalFrame::getCairoContext() ...@@ -3355,47 +3361,32 @@ cairo_t* GtkSalFrame::getCairoContext()
cairo_t* cr = cairo_create(target); cairo_t* cr = cairo_create(target);
cairo_surface_destroy(target); cairo_surface_destroy(target);
return cr; return cr;
// return gdk_cairo_create(gtk_widget_get_window(mpFrame->getWindow()));
}
void GtkSalFrame::pushIgnoreDamage()
{
m_nDuringRender++;
}
void GtkSalFrame::popIgnoreDamage()
{
m_nDuringRender--;
} }
bool GtkSalFrame::isDuringRender()
{
return m_nDuringRender;
}
#endif
void GtkSalFrame::damaged (const basegfx::B2IBox& rDamageRect) void GtkSalFrame::damaged (const basegfx::B2IBox& rDamageRect)
{ {
#if !GTK_CHECK_VERSION(3,0,0)
(void)rDamageRect;
#else
if ( isDuringRender() )
return;
#if OSL_DEBUG_LEVEL > 1 #if OSL_DEBUG_LEVEL > 1
long long area = rDamageRect.getWidth() * rDamageRect.getHeight(); long long area = rDamageRect.getWidth() * rDamageRect.getHeight();
if( area > 32 * 1024 ) if( area > 32 * 1024 )
{ {
fprintf( stderr, "bitmap damaged %d %d (%dx%d) area %lld widget\n", fprintf( stderr, "bitmap damaged %d %d (%dx%d) area %lld widget\n",
(int) rDamageRect.getMinX(), (int) rDamageRect.getMinX(),
(int) rDamageRect.getMinY(), (int) rDamageRect.getMinY(),
(int) rDamageRect.getWidth(), (int) rDamageRect.getWidth(),
(int) rDamageRect.getHeight(), (int) rDamageRect.getHeight(),
area ); area );
} }
#if FRAME_BY_FRAME_DEBUG
static int frame;
OString tmp("/tmp/frame" + OString::number(frame++) + ".png");
cairo_surface_write_to_png(cairo_get_target(getCairoContext()), tmp.getStr());
#endif #endif
#endif
/* FIXME: this is a dirty hack, to render buttons correctly, we /* FIXME: this is a dirty hack, to render buttons correctly, we
* should of course remove the -100 and + 200, but the whole area * should of course remove the -1 and +2, but the whole area
* won't be rendered then. * won't be rendered then.
*/ */
gtk_widget_queue_draw_area( m_pWindow, gtk_widget_queue_draw_area( m_pWindow,
...@@ -3403,10 +3394,8 @@ void GtkSalFrame::damaged (const basegfx::B2IBox& rDamageRect) ...@@ -3403,10 +3394,8 @@ void GtkSalFrame::damaged (const basegfx::B2IBox& rDamageRect)
rDamageRect.getMinY() - 1, rDamageRect.getMinY() - 1,
rDamageRect.getWidth() + 2, rDamageRect.getWidth() + 2,
rDamageRect.getHeight() + 2 ); rDamageRect.getHeight() + 2 );
#endif
} }
#if GTK_CHECK_VERSION(3,0,0)
// blit our backing basebmp buffer to the target cairo context cr // blit our backing basebmp buffer to the target cairo context cr
void GtkSalFrame::renderArea( cairo_t *cr, cairo_rectangle_t *area ) void GtkSalFrame::renderArea( cairo_t *cr, cairo_rectangle_t *area )
{ {
...@@ -3415,6 +3404,7 @@ void GtkSalFrame::renderArea( cairo_t *cr, cairo_rectangle_t *area ) ...@@ -3415,6 +3404,7 @@ void GtkSalFrame::renderArea( cairo_t *cr, cairo_rectangle_t *area )
cairo_surface_t *pSurface = cairo_get_target(getCairoContext()); cairo_surface_t *pSurface = cairo_get_target(getCairoContext());
cairo_set_operator( cr, CAIRO_OPERATOR_OVER ); cairo_set_operator( cr, CAIRO_OPERATOR_OVER );
cairo_set_source_surface( cr, pSurface, 0, 0 ); cairo_set_source_surface( cr, pSurface, 0, 0 );
SAL_INFO("vcl.gtk3", "rendering" << area->x << "," << area->y << " " << area->width << "x" << area->height);
cairo_rectangle( cr, area->x, area->y, area->width, area->height ); cairo_rectangle( cr, area->x, area->y, area->width, area->height );
cairo_fill( cr ); cairo_fill( cr );
...@@ -3448,10 +3438,6 @@ gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame ) ...@@ -3448,10 +3438,6 @@ gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
return FALSE; return FALSE;
} }
// FIXME: we quite probably want to stop re-rendering of pieces
// that we know are just damaged by us and hence already re-rendered
pThis->pushIgnoreDamage();
// FIXME: we need to profile whether re-rendering the entire // FIXME: we need to profile whether re-rendering the entire
// clip region, and just pushing (with renderArea) smaller pieces // clip region, and just pushing (with renderArea) smaller pieces
// is faster ... // is faster ...
...@@ -3460,20 +3446,14 @@ gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame ) ...@@ -3460,20 +3446,14 @@ gboolean GtkSalFrame::signalDraw( GtkWidget*, cairo_t *cr, gpointer frame )
for (int i = 0; i < rects->num_rectangles; i++) { for (int i = 0; i < rects->num_rectangles; i++) {
cairo_rectangle_t rect = rects->rectangles[i]; cairo_rectangle_t rect = rects->rectangles[i];
SAL_INFO("vcl.gtk3", "\t" << i << " -> " << rect.x << "," << rect.y << " " << rect.width << "x" << rect.height); SAL_INFO("vcl.gtk3", "\t" << i << " -> " << rect.x << "," << rect.y << " " << rect.width << "x" << rect.height);
struct SalPaintEvent aEvent( rect.x, rect.y, rect.width, rect.height );
aEvent.mbImmediateUpdate = true;
pThis->CallCallback( SALEVENT_PAINT, &aEvent );
pThis->renderArea( cr, &rect ); pThis->renderArea( cr, &rect );
} }
pThis->popIgnoreDamage();
cairo_surface_flush(cairo_get_target(cr)); cairo_surface_flush(cairo_get_target(cr));
return FALSE; return FALSE;
} }
#endif // GTK_CHECK_VERSION(3,0,0) #else
gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame ) gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
{ {
GtkSalFrame* pThis = (GtkSalFrame*)frame; GtkSalFrame* pThis = (GtkSalFrame*)frame;
...@@ -3485,6 +3465,30 @@ gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer ...@@ -3485,6 +3465,30 @@ gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer
return false; return false;
} }
#endif // GTK_CHECK_VERSION(3,0,0)
void GtkSalFrame::TriggerPaintEvent()
{
//Under gtk2 we can basically paint directly into the XWindow and on
//additional "expose-event" events we can re-render the missing pieces
//
//Under gtk3 we have to keep our own buffer up to date and flush it into
//the given cairo context on "draw". So we emit a paint event on
//opportune resize trigger events to initially fill our backbuffer and then
//keep it up to date with our direct paints and tell gtk those regions
//have changed and then blit them into the provided cairo context when
//we get the "draw"
//
//The other alternative was to always paint everything on "draw", but
//that duplicates the amount of drawing and is hideously slow
#if GTK_CHECK_VERSION(3,0,0)
SAL_INFO("vcl.gtk3", "force painting" << 0 << "," << 0 << " " << maGeometry.nWidth << "x" << maGeometry.nHeight);
SalPaintEvent aPaintEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight, true);
CallCallback(SALEVENT_PAINT, &aPaintEvt);
gtk_widget_queue_draw(m_pWindow);
#endif
}
gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame ) gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
{ {
GtkSalFrame* pThis = (GtkSalFrame*)frame; GtkSalFrame* pThis = (GtkSalFrame*)frame;
...@@ -3588,6 +3592,7 @@ gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame ) ...@@ -3588,6 +3592,7 @@ gboolean GtkSalFrame::signalMap( GtkWidget *pWidget, GdkEvent*, gpointer frame )
#endif #endif
pThis->CallCallback( SALEVENT_RESIZE, NULL ); pThis->CallCallback( SALEVENT_RESIZE, NULL );
pThis->TriggerPaintEvent();
return false; return false;
} }
...@@ -3682,6 +3687,8 @@ gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gp ...@@ -3682,6 +3687,8 @@ gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gp
else if( bSized ) else if( bSized )
pThis->CallCallback( SALEVENT_RESIZE, NULL ); pThis->CallCallback( SALEVENT_RESIZE, NULL );
if (bSized)
pThis->TriggerPaintEvent();
return false; return false;
} }
...@@ -3855,7 +3862,10 @@ gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame ...@@ -3855,7 +3862,10 @@ gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame
{ {
GtkSalFrame* pThis = (GtkSalFrame*)frame; GtkSalFrame* pThis = (GtkSalFrame*)frame;
if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) ) if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
{
pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE ); pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
pThis->TriggerPaintEvent();
}
if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) ) ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
......
...@@ -1546,46 +1546,6 @@ GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow ) ...@@ -1546,46 +1546,6 @@ GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow )
gtk_widget_path_free(path); gtk_widget_path_free(path);
} }
void GtkSalGraphics::copyArea( long nDestX, long nDestY,
long nSrcX, long nSrcY,
long nSrcWidth, long nSrcHeight,
sal_uInt16 nFlags )
{
#if 1
SvpSalGraphics::copyArea( nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, nFlags );
#else
mpFrame->pushIgnoreDamage();
mpFrame->popIgnoreDamage();
cairo_rectangle_int_t rect = { (int)nSrcX, (int)nSrcY, (int)nSrcWidth, (int)nSrcHeight };
cairo_region_t *region = cairo_region_create_rectangle( &rect );
if (!m_aClipRegion.IsEmpty())
{
// get clip region and translate it in the opposite direction & intersect ...
cairo_region_t *clip_region = cairo_region_create();
RectangleVector aRectangles;
m_aClipRegion.GetRegionRectangles(aRectangles);
for (RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
{
cairo_rectangle_int_t aRect = { (int)aRectIter->Left(), (int)aRectIter->Top(),
(int)aRectIter->GetWidth(), (int)aRectIter->GetHeight() };
cairo_region_union_rectangle( clip_region, &aRect );
}
cairo_region_translate( clip_region, - (nDestX - nSrcX), - (nDestY - nSrcY) );
cairo_region_intersect( region, clip_region );
cairo_region_destroy( clip_region );
}
// FIXME: this will queue (duplicate) gtk+ re-rendering for the exposed area, c'est la vie
gdk_window_move_region( gtk_widget_get_window( mpFrame->getWindow() ),
region, nDestX - nSrcX, nDestY - nSrcY );
cairo_region_destroy( region );
#endif
}
cairo_t* GtkSalGraphics::getCairoContext() cairo_t* GtkSalGraphics::getCairoContext()
{ {
return mpFrame->getCairoContext(); return mpFrame->getCairoContext();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment