Improve performance flipping the dirty region only

This commit is contained in:
David Capello 2015-08-24 10:14:25 -03:00
parent 8cc3cf3eb8
commit de3d4c3662
8 changed files with 100 additions and 19 deletions

View File

@ -469,19 +469,23 @@ NonDisposableSurface* Alleg4Display::getSurface()
return static_cast<NonDisposableSurface*>(m_surface);
}
void Alleg4Display::flip()
void Alleg4Display::flip(const gfx::Rect& bounds)
{
if (is_display_resize_awaiting())
return;
BITMAP* bmp = reinterpret_cast<BITMAP*>(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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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.

View File

@ -61,6 +61,7 @@ typedef std::list<Message*> Messages;
typedef std::list<Filter*> 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();
}

View File

@ -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;

View File

@ -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())));
}
}