From de3d4c3662f6b0f4f959e6e2ff027452fae99b4a Mon Sep 17 00:00:00 2001 From: David Capello Date: Mon, 24 Aug 2015 10:14:25 -0300 Subject: [PATCH] Improve performance flipping the dirty region only --- src/she/alleg4/alleg_display.cpp | 12 ++++-- src/she/alleg4/alleg_display.h | 2 +- src/she/display.h | 2 +- src/ui/graphics.cpp | 63 ++++++++++++++++++++++++++------ src/ui/graphics.h | 5 +++ src/ui/manager.cpp | 15 +++++++- src/ui/manager.h | 6 +++ src/ui/overlay.cpp | 14 ++++++- 8 files changed, 100 insertions(+), 19 deletions(-) diff --git a/src/she/alleg4/alleg_display.cpp b/src/she/alleg4/alleg_display.cpp index 20c61e569..c42bc20d2 100644 --- a/src/she/alleg4/alleg_display.cpp +++ b/src/she/alleg4/alleg_display.cpp @@ -469,19 +469,23 @@ NonDisposableSurface* Alleg4Display::getSurface() return static_cast(m_surface); } -void Alleg4Display::flip() +void Alleg4Display::flip(const gfx::Rect& bounds) { if (is_display_resize_awaiting()) return; BITMAP* bmp = reinterpret_cast(m_surface->nativeHandle()); if (m_scale == 1) { - blit(bmp, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); + blit(bmp, screen, + bounds.x, bounds.y, + bounds.x, bounds.y, + bounds.w, bounds.h); } else { stretch_blit(bmp, screen, - 0, 0, bmp->w, bmp->h, - 0, 0, SCREEN_W, SCREEN_H); + bounds.x, bounds.y, bounds.w, bounds.h, + bounds.x*m_scale, bounds.y*m_scale, + bounds.w*m_scale, bounds.h*m_scale); } } diff --git a/src/she/alleg4/alleg_display.h b/src/she/alleg4/alleg_display.h index e4e83a2bb..9b5a74894 100644 --- a/src/she/alleg4/alleg_display.h +++ b/src/she/alleg4/alleg_display.h @@ -28,7 +28,7 @@ namespace she { void setScale(int scale) override; void recreateSurface(); NonDisposableSurface* getSurface() override; - void flip() override; + void flip(const gfx::Rect& bounds) override; void maximize() override; bool isMaximized() const override; void setTitleBar(const std::string& title) override; diff --git a/src/she/display.h b/src/she/display.h index b87bbf723..bc2dec602 100644 --- a/src/she/display.h +++ b/src/she/display.h @@ -49,7 +49,7 @@ namespace she { virtual NonDisposableSurface* getSurface() = 0; // Flips all graphics in the surface to the real display. - virtual void flip() = 0; + virtual void flip(const gfx::Rect& bounds) = 0; virtual void maximize() = 0; virtual bool isMaximized() const = 0; diff --git a/src/ui/graphics.cpp b/src/ui/graphics.cpp index b80884ca4..122a80268 100644 --- a/src/ui/graphics.cpp +++ b/src/ui/graphics.cpp @@ -21,6 +21,7 @@ #include "she/scoped_surface_lock.h" #include "she/surface.h" #include "she/system.h" +#include "ui/manager.h" #include "ui/theme.h" namespace ui { @@ -34,6 +35,14 @@ Graphics::Graphics(she::Surface* surface, int dx, int dy) Graphics::~Graphics() { + // If we were drawing in the screen surface, we mark these regions + // as dirty for the final flip. + if (m_surface == she::instance()->defaultDisplay()->getSurface()) { + gfx::Region& dirty = Manager::getDirtyRegion(); + Manager::getDirtyRegion().createUnion( + Manager::getDirtyRegion(), + gfx::Region(m_dirtyBounds)); + } } int Graphics::width() const @@ -84,40 +93,56 @@ gfx::Color Graphics::getPixel(int x, int y) void Graphics::putPixel(gfx::Color color, int x, int y) { + dirty(gfx::Rect(m_dx+x, m_dy+y, 1, 1)); + she::ScopedSurfaceLock dst(m_surface); dst->putPixel(color, m_dx+x, m_dy+y); } void Graphics::drawHLine(gfx::Color color, int x, int y, int w) { + dirty(gfx::Rect(m_dx+x, m_dy+y, w, 1)); + she::ScopedSurfaceLock dst(m_surface); dst->drawHLine(color, m_dx+x, m_dy+y, w); } void Graphics::drawVLine(gfx::Color color, int x, int y, int h) { + dirty(gfx::Rect(m_dx+x, m_dy+y, 1, h)); + she::ScopedSurfaceLock dst(m_surface); dst->drawVLine(color, m_dx+x, m_dy+y, h); } -void Graphics::drawLine(gfx::Color color, const gfx::Point& a, const gfx::Point& b) +void Graphics::drawLine(gfx::Color color, const gfx::Point& _a, const gfx::Point& _b) { + gfx::Point a(m_dx+_a.x, m_dy+_a.y); + gfx::Point b(m_dx+_b.x, m_dy+_b.y); + dirty(gfx::Rect(a, b)); + she::ScopedSurfaceLock dst(m_surface); - dst->drawLine(color, - gfx::Point(m_dx+a.x, m_dy+a.y), - gfx::Point(m_dx+b.x, m_dy+b.y)); + dst->drawLine(color, a, b); } -void Graphics::drawRect(gfx::Color color, const gfx::Rect& rc) +void Graphics::drawRect(gfx::Color color, const gfx::Rect& rcOrig) { + gfx::Rect rc(rcOrig); + rc.offset(m_dx, m_dy); + dirty(rc); + she::ScopedSurfaceLock dst(m_surface); - dst->drawRect(color, gfx::Rect(rc).offset(m_dx, m_dy)); + dst->drawRect(color, rc); } -void Graphics::fillRect(gfx::Color color, const gfx::Rect& rc) +void Graphics::fillRect(gfx::Color color, const gfx::Rect& rcOrig) { + gfx::Rect rc(rcOrig); + rc.offset(m_dx, m_dy); + dirty(rc); + she::ScopedSurfaceLock dst(m_surface); - dst->fillRect(color, gfx::Rect(rc).offset(m_dx, m_dy)); + dst->fillRect(color, rc); } void Graphics::fillRegion(gfx::Color color, const gfx::Region& rgn) @@ -140,6 +165,8 @@ void Graphics::fillAreaBetweenRects(gfx::Color color, void Graphics::drawSurface(she::Surface* surface, int x, int y) { + dirty(gfx::Rect(m_dx+x, m_dy+y, surface->width(), surface->height())); + she::ScopedSurfaceLock src(surface); she::ScopedSurfaceLock dst(m_surface); dst->drawSurface(src, m_dx+x, m_dy+y); @@ -147,6 +174,8 @@ void Graphics::drawSurface(she::Surface* surface, int x, int y) void Graphics::drawRgbaSurface(she::Surface* surface, int x, int y) { + dirty(gfx::Rect(m_dx+x, m_dy+y, surface->width(), surface->height())); + she::ScopedSurfaceLock src(surface); she::ScopedSurfaceLock dst(m_surface); dst->drawRgbaSurface(src, m_dx+x, m_dy+y); @@ -154,6 +183,8 @@ void Graphics::drawRgbaSurface(she::Surface* surface, int x, int y) void Graphics::drawColoredRgbaSurface(she::Surface* surface, gfx::Color color, int x, int y) { + dirty(gfx::Rect(m_dx+x, m_dy+y, surface->width(), surface->height())); + she::ScopedSurfaceLock src(surface); she::ScopedSurfaceLock dst(m_surface); dst->drawColoredRgbaSurface(src, color, gfx::ColorNone, @@ -162,6 +193,8 @@ void Graphics::drawColoredRgbaSurface(she::Surface* surface, gfx::Color color, i void Graphics::blit(she::Surface* srcSurface, int srcx, int srcy, int dstx, int dsty, int w, int h) { + dirty(gfx::Rect(m_dx+dstx, m_dy+dsty, w, h)); + she::ScopedSurfaceLock src(srcSurface); she::ScopedSurfaceLock dst(m_surface); src->blitTo(dst, srcx, srcy, m_dx+dstx, m_dy+dsty, w, h); @@ -174,14 +207,19 @@ void Graphics::setFont(she::Font* font) void Graphics::drawChar(int chr, gfx::Color fg, gfx::Color bg, int x, int y) { + dirty(gfx::Rect(gfx::Point(m_dx+x, m_dy+y), measureChar(chr))); + she::ScopedSurfaceLock dst(m_surface); dst->drawChar(m_font, fg, bg, m_dx+x, m_dy+y, chr); } -void Graphics::drawString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt) +void Graphics::drawString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& ptOrig) { + gfx::Point pt(m_dx+ptOrig.x, m_dy+ptOrig.y); + dirty(gfx::Rect(pt.x, pt.y, m_font->textLength(str), m_font->height())); + she::ScopedSurfaceLock dst(m_surface); - dst->drawString(m_font, fg, bg, m_dx+pt.x, m_dy+pt.y, str); + dst->drawString(m_font, fg, bg, pt.x, pt.y, str); } void Graphics::drawUIString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt, @@ -207,11 +245,14 @@ void Graphics::drawUIString(const std::string& str, gfx::Color fg, gfx::Color bg ++it; } + y += m_font->height(); if (drawUnderscore && underscored_w > 0) { - y += m_font->height(); dst->fillRect(fg, gfx::Rect(underscored_x, y, underscored_w, guiscale())); + y += guiscale(); } + + dirty(gfx::Rect(pt, gfx::Point(x, y))); } void Graphics::drawAlignedUIString(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, int align) diff --git a/src/ui/graphics.h b/src/ui/graphics.h index 6d8040652..4d33e7435 100644 --- a/src/ui/graphics.h +++ b/src/ui/graphics.h @@ -92,11 +92,16 @@ namespace ui { private: gfx::Size doUIStringAlgorithm(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, int align, bool draw); + void dirty(const gfx::Rect& bounds) { + m_dirtyBounds |= bounds; + } + she::Surface* m_surface; int m_dx; int m_dy; gfx::Rect m_clipBounds; she::Font* m_font; + gfx::Rect m_dirtyBounds; }; // Class to draw directly in the screen. diff --git a/src/ui/manager.cpp b/src/ui/manager.cpp index 47cadfcd9..c81a1bc0a 100644 --- a/src/ui/manager.cpp +++ b/src/ui/manager.cpp @@ -61,6 +61,7 @@ typedef std::list Messages; typedef std::list Filters; Manager* Manager::m_defaultManager = NULL; +gfx::Region Manager::m_dirtyRegion; static WidgetsList new_windows; // Windows that we should show static WidgetsList mouse_widgets_list; // List of widgets to send mouse events @@ -106,6 +107,8 @@ Manager::Manager() setBounds(gfx::Rect(0, 0, ui::display_w(), ui::display_h())); setVisible(true); + m_dirtyRegion = getBounds(); + // Default manager is the first one (and is always visible). if (!m_defaultManager) m_defaultManager = this; @@ -181,7 +184,17 @@ void Manager::flipDisplay() overlays->captureOverlappedAreas(); overlays->drawOverlays(); - m_display->flip(); + // Flip dirty region. + { + m_dirtyRegion.createIntersection( + m_dirtyRegion, + gfx::Region(gfx::Rect(0, 0, ui::display_w(), ui::display_h()))); + + for (auto& rc : m_dirtyRegion) + m_display->flip(rc); + + m_dirtyRegion.clear(); + } overlays->restoreOverlappedAreas(); } diff --git a/src/ui/manager.h b/src/ui/manager.h index 20b4a9688..602b68a0c 100644 --- a/src/ui/manager.h +++ b/src/ui/manager.h @@ -8,6 +8,7 @@ #define UI_MANAGER_H_INCLUDED #pragma once +#include "gfx/region.h" #include "ui/message_type.h" #include "ui/mouse_buttons.h" #include "ui/widget.h" @@ -30,6 +31,10 @@ namespace ui { return m_defaultManager; } + static gfx::Region& getDirtyRegion() { + return m_dirtyRegion; + } + Manager(); ~Manager(); @@ -116,6 +121,7 @@ namespace ui { void broadcastKeyMsg(Message* msg); static Manager* m_defaultManager; + static gfx::Region m_dirtyRegion; WidgetsList m_garbage; she::Display* m_display; diff --git a/src/ui/overlay.cpp b/src/ui/overlay.cpp index a6ab24c52..e7f81ab41 100644 --- a/src/ui/overlay.cpp +++ b/src/ui/overlay.cpp @@ -1,5 +1,5 @@ // Aseprite UI Library -// Copyright (C) 2001-2013 David Capello +// Copyright (C) 2001-2013, 2015 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -62,6 +62,12 @@ void Overlay::drawOverlay(she::LockedSurface* screen) she::ScopedSurfaceLock lockedSurface(m_surface); screen->drawRgbaSurface(lockedSurface, m_pos.x, m_pos.y); + + Manager::getDirtyRegion().createUnion( + Manager::getDirtyRegion(), + gfx::Region(gfx::Rect(m_pos.x, m_pos.y, + m_surface->width(), + m_surface->height()))); } void Overlay::moveOverlay(const gfx::Point& newPos) @@ -93,6 +99,12 @@ void Overlay::restoreOverlappedArea(she::LockedSurface* screen) she::ScopedSurfaceLock lock(m_overlap); lock->blitTo(screen, 0, 0, m_pos.x, m_pos.y, m_overlap->width(), m_overlap->height()); + + Manager::getDirtyRegion().createUnion( + Manager::getDirtyRegion(), + gfx::Region(gfx::Rect(m_pos.x, m_pos.y, + m_overlap->width(), + m_overlap->height()))); } }