Only allocate canvas portion pixels when needed

This will allow for larger renders in constant memory footprint
This commit is contained in:
Michaël Lemaire 2014-08-18 17:16:17 +02:00
parent c9fa33984b
commit 3a2ec1c75f
7 changed files with 66 additions and 17 deletions

View file

@ -36,8 +36,8 @@ BaseForm(parent, true)
addInput(new InputCamera(this, tr("Camera"), _camera));
addInputInt(tr("Quality"), &_params.quality, 1, 10, 1, 1);
addInputInt(tr("Image width"), &_params.width, 100, 2000, 10, 100);
addInputInt(tr("Image height"), &_params.height, 100, 1200, 10, 100);
addInputInt(tr("Image width"), &_params.width, 100, 4000, 10, 100);
addInputInt(tr("Image height"), &_params.height, 100, 3000, 10, 100);
addInputInt(tr("Anti aliasing"), &_params.antialias, 1, 4, 1, 1);
button = addButton(tr("Start new render"));

View file

@ -67,8 +67,13 @@ void Canvas::setSize(int width, int height)
this->width = width;
this->height = height;
// TODO Smaller preview
preview->setSize(width, height, width, height);
// Smaller preview
while (width > 800 and height > 800)
{
width = width / 2;
height = height / 2;
}
preview->setSize(this->width, this->height, width, height);
}
CanvasPortion *Canvas::at(int x, int y) const

View file

@ -8,19 +8,23 @@
#define CHECK_COORDINATES() assert(x >= 0); \
assert(x < width); \
assert(y >= 0); \
assert(y < height)
assert(y < height); \
assert(pixels != NULL)
CanvasPortion::CanvasPortion(CanvasPreview* preview):
preview(preview)
{
width = 1;
height = 1;
pixels = new CanvasPixel[1];
pixels = NULL;
}
CanvasPortion::~CanvasPortion()
{
delete[] pixels;
if (pixels)
{
delete[] pixels;
}
}
int CanvasPortion::getFragmentCount(int x, int y) const
@ -50,9 +54,16 @@ void CanvasPortion::setSize(int width, int height)
{
this->width = width;
this->height = height;
}
delete[] pixels;
void CanvasPortion::preparePixels()
{
if (pixels)
{
delete[] pixels;
}
pixels = new CanvasPixel[width * height];
clear();
}
void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment)

View file

@ -10,6 +10,8 @@ namespace software {
* Rectangular portion of a Canvas.
*
* Contains the pixels of a canvas region (CanvasPixel).
*
* Pixels are not allocated until preparePixels is called.
*/
class SOFTWARESHARED_EXPORT CanvasPortion
{
@ -25,6 +27,11 @@ public:
void clear();
void setSize(int width, int height);
/**
* Prepare (allocate in memory) the pixels area.
*/
void preparePixels();
/**
* Add a fragment to the pixel located at (x, y).
*

View file

@ -18,6 +18,11 @@ CanvasPreview::CanvasPreview()
dirty_down = 1;
dirty_up = -1;
scaled = false;
factor = 1.0;
factor_x = 1.0;
factor_y = 1.0;
lock = new Mutex();
profile = new ColorProfile();
}
@ -44,6 +49,11 @@ void CanvasPreview::setSize(int real_width, int real_height, int preview_width,
dirty_down = height;
dirty_up = -1;
scaled = (real_width != preview_height or real_height != preview_height);
factor_x = (double)real_width / (double)preview_width;
factor_y = (double)real_height / (double)preview_height;
factor = factor_x * factor_y;
lock->release();
reset();
@ -94,17 +104,26 @@ void CanvasPreview::updateLive(CanvasLiveClient *client)
void CanvasPreview::pushPixel(int real_x, int real_y, const Color &old_color, const Color &new_color)
{
int x, y;
lock->acquire();
// TODO Assert-check and transform coordinates
int x = real_x;
int y = real_y;
double fact = 1.0;
// TODO Assert-check
if (scaled)
{
x = round(real_x / factor_x);
y = round(real_y / factor_y);
}
else
{
x = real_x;
y = real_y;
}
Color* pixel = pixels + (real_y * width + real_x);
pixel->r = pixel->r - old_color.r * fact + new_color.r * fact;
pixel->g = pixel->g - old_color.g * fact + new_color.g * fact;
pixel->b = pixel->b - old_color.b * fact + new_color.b * fact;
Color* pixel = pixels + (y * width + x);
pixel->r = pixel->r - old_color.r / factor + new_color.r / factor;
pixel->g = pixel->g - old_color.g / factor + new_color.g / factor;
pixel->b = pixel->b - old_color.b / factor + new_color.b / factor;
// Set pixel dirty
if (x < dirty_left)

View file

@ -42,6 +42,11 @@ private:
int dirty_right;
int dirty_down;
int dirty_up;
bool scaled;
double factor;
double factor_x;
double factor_y;
};
}

View file

@ -43,7 +43,6 @@ void SoftwareCanvasRenderer::render()
{
// TEMP
started = true;
CanvasPortion *portion = canvas->at(0, 0);
render_width = canvas->getWidth();
render_height = canvas->getHeight();
render_quality = 3;
@ -52,6 +51,9 @@ void SoftwareCanvasRenderer::render()
prepare();
// TODO Iterate portions
CanvasPortion *portion = canvas->at(0, 0);
portion->preparePixels();
rasterize(portion, true);
postProcess(portion, true);
}