mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-16 10:20:50 +00:00
Improve cmd::CopyRegion() performance
Here we replace std::stringstream with a base::buffer (std::vector<uint8_t>) and pre-allocating the required size.
This commit is contained in:
parent
6a88713213
commit
7af4365588
@ -575,6 +575,7 @@ add_library(app-lib
|
||||
transformation.cpp
|
||||
ui/layer_frame_comboboxes.cpp
|
||||
util/autocrop.cpp
|
||||
util/buffer_region.cpp
|
||||
util/create_cel_copy.cpp
|
||||
util/expand_cel_canvas.cpp
|
||||
util/filetoks.cpp
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -10,10 +11,9 @@
|
||||
|
||||
#include "app/cmd/copy_region.h"
|
||||
|
||||
#include "app/util/buffer_region.h"
|
||||
#include "doc/image.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
|
||||
@ -22,7 +22,6 @@ CopyRegion::CopyRegion(Image* dst, const Image* src,
|
||||
const gfx::Point& dstPos,
|
||||
bool alreadyCopied)
|
||||
: WithImage(dst)
|
||||
, m_size(0)
|
||||
, m_alreadyCopied(alreadyCopied)
|
||||
{
|
||||
// Create region to save/swap later
|
||||
@ -38,16 +37,7 @@ CopyRegion::CopyRegion(Image* dst, const Image* src,
|
||||
m_region.createUnion(m_region, gfx::Region(clip.dstBounds()));
|
||||
}
|
||||
|
||||
// Save region pixels
|
||||
for (const auto& rc : m_region) {
|
||||
for (int y=0; y<rc.h; ++y) {
|
||||
m_stream.write(
|
||||
(const char*)src->getPixelAddress(rc.x-dstPos.x,
|
||||
rc.y-dstPos.y+y),
|
||||
src->getRowStrideSize(rc.w));
|
||||
}
|
||||
}
|
||||
m_size = size_t(m_stream.tellp());
|
||||
save_image_region_in_buffer(m_region, src, dstPos, m_buffer);
|
||||
}
|
||||
|
||||
void CopyRegion::onExecute()
|
||||
@ -69,29 +59,7 @@ void CopyRegion::onRedo()
|
||||
void CopyRegion::swap()
|
||||
{
|
||||
Image* image = this->image();
|
||||
|
||||
// Save current image region in "tmp" stream
|
||||
std::stringstream tmp;
|
||||
for (const auto& rc : m_region)
|
||||
for (int y=0; y<rc.h; ++y)
|
||||
tmp.write(
|
||||
(const char*)image->getPixelAddress(rc.x, rc.y+y),
|
||||
image->getRowStrideSize(rc.w));
|
||||
|
||||
// Restore m_stream into the image
|
||||
m_stream.seekg(0, std::ios_base::beg);
|
||||
for (const auto& rc : m_region) {
|
||||
for (int y=0; y<rc.h; ++y) {
|
||||
m_stream.read(
|
||||
(char*)image->getPixelAddress(rc.x, rc.y+y),
|
||||
image->getRowStrideSize(rc.w));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO use m_stream.swap(tmp) when clang and gcc support it
|
||||
m_stream.str(tmp.str());
|
||||
m_stream.clear();
|
||||
|
||||
swap_image_region_with_buffer(m_region, image, m_buffer);
|
||||
image->incrementVersion();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -10,11 +11,10 @@
|
||||
|
||||
#include "app/cmd.h"
|
||||
#include "app/cmd/with_image.h"
|
||||
#include "base/buffer.h"
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/region.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
using namespace doc;
|
||||
@ -36,16 +36,15 @@ namespace cmd {
|
||||
void onUndo() override;
|
||||
void onRedo() override;
|
||||
size_t onMemSize() const override {
|
||||
return sizeof(*this) + m_size;
|
||||
return sizeof(*this) + m_buffer.size();
|
||||
}
|
||||
|
||||
private:
|
||||
void swap();
|
||||
|
||||
size_t m_size;
|
||||
bool m_alreadyCopied;
|
||||
gfx::Region m_region;
|
||||
std::stringstream m_stream;
|
||||
base::buffer m_buffer;
|
||||
};
|
||||
|
||||
} // namespace cmd
|
||||
|
63
src/app/util/buffer_region.cpp
Normal file
63
src/app/util/buffer_region.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/util/buffer_region.h"
|
||||
|
||||
#include "doc/image.h"
|
||||
#include "gfx/region.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace app {
|
||||
|
||||
void save_image_region_in_buffer(
|
||||
const gfx::Region& region,
|
||||
const doc::Image* image,
|
||||
const gfx::Point& imagePos,
|
||||
base::buffer& buffer)
|
||||
{
|
||||
// Calculate buffer size for the region
|
||||
const size_t bytesPerPixel = image->getRowStrideSize(1);
|
||||
size_t reqBytes = 0;
|
||||
for (const auto& rc : region)
|
||||
reqBytes += bytesPerPixel*rc.w*rc.h;
|
||||
|
||||
// Save region pixels
|
||||
buffer.resize(reqBytes);
|
||||
auto it = buffer.begin();
|
||||
for (const auto& rc : region) {
|
||||
for (int y=0; y<rc.h; ++y) {
|
||||
auto p = (const uint8_t*)image->getPixelAddress(rc.x-imagePos.x,
|
||||
rc.y-imagePos.y+y);
|
||||
const size_t rowBytes = bytesPerPixel*rc.w;
|
||||
std::copy(p, p+rowBytes, it);
|
||||
it += rowBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void swap_image_region_with_buffer(
|
||||
const gfx::Region& region,
|
||||
doc::Image* image,
|
||||
base::buffer& buffer)
|
||||
{
|
||||
const size_t bytesPerPixel = image->getRowStrideSize(1);
|
||||
auto it = buffer.begin();
|
||||
for (const auto& rc : region) {
|
||||
for (int y=0; y<rc.h; ++y) {
|
||||
auto p = (uint8_t*)image->getPixelAddress(rc.x, rc.y+y);
|
||||
const size_t rowBytes = bytesPerPixel*rc.w;
|
||||
std::swap_ranges(it, it+rowBytes, p);
|
||||
it += rowBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
33
src/app/util/buffer_region.h
Normal file
33
src/app/util/buffer_region.h
Normal file
@ -0,0 +1,33 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UTIL_BUFFER_REGION_H_INCLUDED
|
||||
#define APP_UTIL_BUFFER_REGION_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/buffer.h"
|
||||
#include "gfx/fwd.h"
|
||||
|
||||
namespace doc {
|
||||
class Image;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
void save_image_region_in_buffer(
|
||||
const gfx::Region& region,
|
||||
const doc::Image* image,
|
||||
const gfx::Point& imagePos,
|
||||
base::buffer& buffer);
|
||||
|
||||
void swap_image_region_with_buffer(
|
||||
const gfx::Region& region,
|
||||
doc::Image* image,
|
||||
base::buffer& buffer);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user