mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-27 02:37:16 +00:00
Improve filters preview performance (fix #1400)
Now several filter steps are applied in a background thread and a UI timer refresh several rows in screen at the same time (instead of one row per time). (This is something in my personal to-do list from long time ago too.)
This commit is contained in:
parent
fbb0cdcbe2
commit
f381cb972c
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -110,7 +110,7 @@ void FilterManagerImpl::beginForPreview()
|
||||
m_previewMask->replace(m_site.sprite()->bounds());
|
||||
}
|
||||
|
||||
m_row = 0;
|
||||
m_row = m_nextRowToFlush = 0;
|
||||
m_mask = m_previewMask;
|
||||
|
||||
{
|
||||
@ -257,17 +257,24 @@ void FilterManagerImpl::applyToTarget()
|
||||
|
||||
void FilterManagerImpl::flush()
|
||||
{
|
||||
if (m_row >= 0) {
|
||||
int h = m_row - m_nextRowToFlush;
|
||||
|
||||
if (m_row >= 0 && h > 0) {
|
||||
Editor* editor = current_editor;
|
||||
|
||||
// We expand the region one pixel at the top and bottom of the
|
||||
// region [m_row,m_nextRowToFlush) to be updated on the screen to
|
||||
// avoid screen artifacts when we apply filters like convolution
|
||||
// matrices.
|
||||
gfx::Rect rect(
|
||||
editor->editorToScreen(
|
||||
gfx::Point(
|
||||
m_bounds.x,
|
||||
m_bounds.y+m_row-1)),
|
||||
m_bounds.y+m_nextRowToFlush-1)),
|
||||
gfx::Size(
|
||||
editor->projection().applyX(m_bounds.w),
|
||||
(editor->projection().scaleY() >= 1 ? editor->projection().applyY(1):
|
||||
editor->projection().removeY(1))));
|
||||
(editor->projection().scaleY() >= 1 ? editor->projection().applyY(h+2):
|
||||
editor->projection().removeY(h+2))));
|
||||
|
||||
gfx::Region reg1(rect);
|
||||
gfx::Region reg2;
|
||||
@ -275,6 +282,7 @@ void FilterManagerImpl::flush()
|
||||
reg1.createIntersection(reg1, reg2);
|
||||
|
||||
editor->invalidateRegion(reg1);
|
||||
m_nextRowToFlush = m_row+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -120,6 +120,7 @@ namespace app {
|
||||
doc::ImageRef m_src;
|
||||
doc::ImageRef m_dst;
|
||||
int m_row;
|
||||
int m_nextRowToFlush;
|
||||
gfx::Rect m_bounds;
|
||||
doc::Mask* m_mask;
|
||||
base::UniquePtr<doc::Mask> m_previewMask;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -13,6 +13,8 @@
|
||||
#include "app/commands/filters/filter_manager_impl.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/scoped_lock.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "ui/manager.h"
|
||||
@ -28,6 +30,7 @@ FilterPreview::FilterPreview(FilterManagerImpl* filterMgr)
|
||||
: Widget(kGenericWidget)
|
||||
, m_filterMgr(filterMgr)
|
||||
, m_timer(1, this)
|
||||
, m_filterThread(nullptr)
|
||||
{
|
||||
setVisible(false);
|
||||
}
|
||||
@ -39,25 +42,32 @@ FilterPreview::~FilterPreview()
|
||||
|
||||
void FilterPreview::stop()
|
||||
{
|
||||
if (m_timer.isRunning()) {
|
||||
ASSERT(m_filterMgr != NULL);
|
||||
|
||||
m_filterMgr->end();
|
||||
{
|
||||
base::scoped_lock lock(m_filterMgrMutex);
|
||||
if (m_timer.isRunning()) {
|
||||
ASSERT(m_filterMgr);
|
||||
m_filterMgr->end();
|
||||
}
|
||||
}
|
||||
|
||||
m_filterMgr = NULL;
|
||||
m_timer.stop();
|
||||
|
||||
if (m_filterThread) {
|
||||
m_filterThread->join();
|
||||
m_filterThread.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void FilterPreview::restartPreview()
|
||||
{
|
||||
m_filterMgr->beginForPreview();
|
||||
m_timer.start();
|
||||
}
|
||||
base::scoped_lock lock(m_filterMgrMutex);
|
||||
|
||||
FilterManagerImpl* FilterPreview::getFilterManager() const
|
||||
{
|
||||
return m_filterMgr;
|
||||
m_filterMgr->beginForPreview();
|
||||
m_filterIsDone = false;
|
||||
m_filterThread.reset(new base::thread(
|
||||
base::Bind<void>(&FilterPreview::onFilterThread, this)));
|
||||
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
bool FilterPreview::onProcessMessage(Message* msg)
|
||||
@ -80,17 +90,30 @@ bool FilterPreview::onProcessMessage(Message* msg)
|
||||
m_timer.stop();
|
||||
break;
|
||||
|
||||
case kTimerMessage:
|
||||
case kTimerMessage: {
|
||||
base::scoped_lock lock(m_filterMgrMutex);
|
||||
if (m_filterMgr) {
|
||||
if (m_filterMgr->applyStep())
|
||||
m_filterMgr->flush();
|
||||
else
|
||||
m_filterMgr->flush();
|
||||
if (m_filterIsDone)
|
||||
m_timer.stop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Widget::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
// This is executed in other thread.
|
||||
void FilterPreview::onFilterThread()
|
||||
{
|
||||
while (!m_filterIsDone && m_timer.isRunning()) {
|
||||
{
|
||||
base::scoped_lock lock(m_filterMgrMutex);
|
||||
m_filterIsDone = !m_filterMgr->applyStep();
|
||||
}
|
||||
base::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -8,6 +8,9 @@
|
||||
#define APP_COMMANDS_FILTERS_FILTER_PREVIEW_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/mutex.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "ui/timer.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
@ -23,14 +26,18 @@ namespace app {
|
||||
|
||||
void stop();
|
||||
void restartPreview();
|
||||
FilterManagerImpl* getFilterManager() const;
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
|
||||
private:
|
||||
void onFilterThread();
|
||||
|
||||
FilterManagerImpl* m_filterMgr;
|
||||
ui::Timer m_timer;
|
||||
base::mutex m_filterMgrMutex;
|
||||
base::UniquePtr<base::thread> m_filterThread;
|
||||
bool m_filterIsDone;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -121,6 +121,8 @@ void FilterWindow::restartPreview()
|
||||
|
||||
void FilterWindow::setNewTarget(Target target)
|
||||
{
|
||||
stopPreview();
|
||||
|
||||
m_filterMgr->setTarget(target);
|
||||
m_targetButton.setTarget(target);
|
||||
}
|
||||
@ -143,6 +145,8 @@ void FilterWindow::onShowPreview(Event& ev)
|
||||
// Called when the user changes the target-buttons.
|
||||
void FilterWindow::onTargetButtonChange()
|
||||
{
|
||||
stopPreview();
|
||||
|
||||
// Change the targets in the filter manager and restart the filter preview.
|
||||
m_filterMgr->setTarget(m_targetButton.getTarget());
|
||||
restartPreview();
|
||||
@ -150,7 +154,8 @@ void FilterWindow::onTargetButtonChange()
|
||||
|
||||
void FilterWindow::onTiledChange()
|
||||
{
|
||||
ASSERT(m_tiledCheck != NULL);
|
||||
ASSERT(m_tiledCheck);
|
||||
stopPreview();
|
||||
|
||||
// Call derived class implementation of setupTiledMode() so the
|
||||
// filter is modified.
|
||||
@ -162,4 +167,9 @@ void FilterWindow::onTiledChange()
|
||||
restartPreview();
|
||||
}
|
||||
|
||||
void FilterWindow::stopPreview()
|
||||
{
|
||||
m_preview.stop();
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -62,6 +62,8 @@ namespace app {
|
||||
virtual void setupTiledMode(TiledMode tiledMode) { }
|
||||
|
||||
private:
|
||||
void stopPreview();
|
||||
|
||||
const char* m_cfgSection;
|
||||
FilterManagerImpl* m_filterMgr;
|
||||
ui::Box m_hbox;
|
||||
|
Loading…
x
Reference in New Issue
Block a user