mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-30 04:20:23 +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
|
// Aseprite
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -110,7 +110,7 @@ void FilterManagerImpl::beginForPreview()
|
|||||||
m_previewMask->replace(m_site.sprite()->bounds());
|
m_previewMask->replace(m_site.sprite()->bounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_row = 0;
|
m_row = m_nextRowToFlush = 0;
|
||||||
m_mask = m_previewMask;
|
m_mask = m_previewMask;
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -257,17 +257,24 @@ void FilterManagerImpl::applyToTarget()
|
|||||||
|
|
||||||
void FilterManagerImpl::flush()
|
void FilterManagerImpl::flush()
|
||||||
{
|
{
|
||||||
if (m_row >= 0) {
|
int h = m_row - m_nextRowToFlush;
|
||||||
|
|
||||||
|
if (m_row >= 0 && h > 0) {
|
||||||
Editor* editor = current_editor;
|
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(
|
gfx::Rect rect(
|
||||||
editor->editorToScreen(
|
editor->editorToScreen(
|
||||||
gfx::Point(
|
gfx::Point(
|
||||||
m_bounds.x,
|
m_bounds.x,
|
||||||
m_bounds.y+m_row-1)),
|
m_bounds.y+m_nextRowToFlush-1)),
|
||||||
gfx::Size(
|
gfx::Size(
|
||||||
editor->projection().applyX(m_bounds.w),
|
editor->projection().applyX(m_bounds.w),
|
||||||
(editor->projection().scaleY() >= 1 ? editor->projection().applyY(1):
|
(editor->projection().scaleY() >= 1 ? editor->projection().applyY(h+2):
|
||||||
editor->projection().removeY(1))));
|
editor->projection().removeY(h+2))));
|
||||||
|
|
||||||
gfx::Region reg1(rect);
|
gfx::Region reg1(rect);
|
||||||
gfx::Region reg2;
|
gfx::Region reg2;
|
||||||
@ -275,6 +282,7 @@ void FilterManagerImpl::flush()
|
|||||||
reg1.createIntersection(reg1, reg2);
|
reg1.createIntersection(reg1, reg2);
|
||||||
|
|
||||||
editor->invalidateRegion(reg1);
|
editor->invalidateRegion(reg1);
|
||||||
|
m_nextRowToFlush = m_row+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -120,6 +120,7 @@ namespace app {
|
|||||||
doc::ImageRef m_src;
|
doc::ImageRef m_src;
|
||||||
doc::ImageRef m_dst;
|
doc::ImageRef m_dst;
|
||||||
int m_row;
|
int m_row;
|
||||||
|
int m_nextRowToFlush;
|
||||||
gfx::Rect m_bounds;
|
gfx::Rect m_bounds;
|
||||||
doc::Mask* m_mask;
|
doc::Mask* m_mask;
|
||||||
base::UniquePtr<doc::Mask> m_previewMask;
|
base::UniquePtr<doc::Mask> m_previewMask;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -13,6 +13,8 @@
|
|||||||
#include "app/commands/filters/filter_manager_impl.h"
|
#include "app/commands/filters/filter_manager_impl.h"
|
||||||
#include "app/modules/editors.h"
|
#include "app/modules/editors.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "base/bind.h"
|
||||||
|
#include "base/scoped_lock.h"
|
||||||
#include "doc/layer.h"
|
#include "doc/layer.h"
|
||||||
#include "doc/sprite.h"
|
#include "doc/sprite.h"
|
||||||
#include "ui/manager.h"
|
#include "ui/manager.h"
|
||||||
@ -28,6 +30,7 @@ FilterPreview::FilterPreview(FilterManagerImpl* filterMgr)
|
|||||||
: Widget(kGenericWidget)
|
: Widget(kGenericWidget)
|
||||||
, m_filterMgr(filterMgr)
|
, m_filterMgr(filterMgr)
|
||||||
, m_timer(1, this)
|
, m_timer(1, this)
|
||||||
|
, m_filterThread(nullptr)
|
||||||
{
|
{
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}
|
}
|
||||||
@ -39,25 +42,32 @@ FilterPreview::~FilterPreview()
|
|||||||
|
|
||||||
void FilterPreview::stop()
|
void FilterPreview::stop()
|
||||||
{
|
{
|
||||||
if (m_timer.isRunning()) {
|
{
|
||||||
ASSERT(m_filterMgr != NULL);
|
base::scoped_lock lock(m_filterMgrMutex);
|
||||||
|
if (m_timer.isRunning()) {
|
||||||
m_filterMgr->end();
|
ASSERT(m_filterMgr);
|
||||||
|
m_filterMgr->end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_filterMgr = NULL;
|
|
||||||
m_timer.stop();
|
m_timer.stop();
|
||||||
|
|
||||||
|
if (m_filterThread) {
|
||||||
|
m_filterThread->join();
|
||||||
|
m_filterThread.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilterPreview::restartPreview()
|
void FilterPreview::restartPreview()
|
||||||
{
|
{
|
||||||
m_filterMgr->beginForPreview();
|
base::scoped_lock lock(m_filterMgrMutex);
|
||||||
m_timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
FilterManagerImpl* FilterPreview::getFilterManager() const
|
m_filterMgr->beginForPreview();
|
||||||
{
|
m_filterIsDone = false;
|
||||||
return m_filterMgr;
|
m_filterThread.reset(new base::thread(
|
||||||
|
base::Bind<void>(&FilterPreview::onFilterThread, this)));
|
||||||
|
|
||||||
|
m_timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilterPreview::onProcessMessage(Message* msg)
|
bool FilterPreview::onProcessMessage(Message* msg)
|
||||||
@ -80,17 +90,30 @@ bool FilterPreview::onProcessMessage(Message* msg)
|
|||||||
m_timer.stop();
|
m_timer.stop();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kTimerMessage:
|
case kTimerMessage: {
|
||||||
|
base::scoped_lock lock(m_filterMgrMutex);
|
||||||
if (m_filterMgr) {
|
if (m_filterMgr) {
|
||||||
if (m_filterMgr->applyStep())
|
m_filterMgr->flush();
|
||||||
m_filterMgr->flush();
|
if (m_filterIsDone)
|
||||||
else
|
|
||||||
m_timer.stop();
|
m_timer.stop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Widget::onProcessMessage(msg);
|
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
|
} // namespace app
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2015 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -8,6 +8,9 @@
|
|||||||
#define APP_COMMANDS_FILTERS_FILTER_PREVIEW_H_INCLUDED
|
#define APP_COMMANDS_FILTERS_FILTER_PREVIEW_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/mutex.h"
|
||||||
|
#include "base/thread.h"
|
||||||
|
#include "base/unique_ptr.h"
|
||||||
#include "ui/timer.h"
|
#include "ui/timer.h"
|
||||||
#include "ui/widget.h"
|
#include "ui/widget.h"
|
||||||
|
|
||||||
@ -23,14 +26,18 @@ namespace app {
|
|||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
void restartPreview();
|
void restartPreview();
|
||||||
FilterManagerImpl* getFilterManager() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool onProcessMessage(ui::Message* msg) override;
|
bool onProcessMessage(ui::Message* msg) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void onFilterThread();
|
||||||
|
|
||||||
FilterManagerImpl* m_filterMgr;
|
FilterManagerImpl* m_filterMgr;
|
||||||
ui::Timer m_timer;
|
ui::Timer m_timer;
|
||||||
|
base::mutex m_filterMgrMutex;
|
||||||
|
base::UniquePtr<base::thread> m_filterThread;
|
||||||
|
bool m_filterIsDone;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2015 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -121,6 +121,8 @@ void FilterWindow::restartPreview()
|
|||||||
|
|
||||||
void FilterWindow::setNewTarget(Target target)
|
void FilterWindow::setNewTarget(Target target)
|
||||||
{
|
{
|
||||||
|
stopPreview();
|
||||||
|
|
||||||
m_filterMgr->setTarget(target);
|
m_filterMgr->setTarget(target);
|
||||||
m_targetButton.setTarget(target);
|
m_targetButton.setTarget(target);
|
||||||
}
|
}
|
||||||
@ -143,6 +145,8 @@ void FilterWindow::onShowPreview(Event& ev)
|
|||||||
// Called when the user changes the target-buttons.
|
// Called when the user changes the target-buttons.
|
||||||
void FilterWindow::onTargetButtonChange()
|
void FilterWindow::onTargetButtonChange()
|
||||||
{
|
{
|
||||||
|
stopPreview();
|
||||||
|
|
||||||
// Change the targets in the filter manager and restart the filter preview.
|
// Change the targets in the filter manager and restart the filter preview.
|
||||||
m_filterMgr->setTarget(m_targetButton.getTarget());
|
m_filterMgr->setTarget(m_targetButton.getTarget());
|
||||||
restartPreview();
|
restartPreview();
|
||||||
@ -150,7 +154,8 @@ void FilterWindow::onTargetButtonChange()
|
|||||||
|
|
||||||
void FilterWindow::onTiledChange()
|
void FilterWindow::onTiledChange()
|
||||||
{
|
{
|
||||||
ASSERT(m_tiledCheck != NULL);
|
ASSERT(m_tiledCheck);
|
||||||
|
stopPreview();
|
||||||
|
|
||||||
// Call derived class implementation of setupTiledMode() so the
|
// Call derived class implementation of setupTiledMode() so the
|
||||||
// filter is modified.
|
// filter is modified.
|
||||||
@ -162,4 +167,9 @@ void FilterWindow::onTiledChange()
|
|||||||
restartPreview();
|
restartPreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FilterWindow::stopPreview()
|
||||||
|
{
|
||||||
|
m_preview.stop();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2015 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -62,6 +62,8 @@ namespace app {
|
|||||||
virtual void setupTiledMode(TiledMode tiledMode) { }
|
virtual void setupTiledMode(TiledMode tiledMode) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void stopPreview();
|
||||||
|
|
||||||
const char* m_cfgSection;
|
const char* m_cfgSection;
|
||||||
FilterManagerImpl* m_filterMgr;
|
FilterManagerImpl* m_filterMgr;
|
||||||
ui::Box m_hbox;
|
ui::Box m_hbox;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user