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)); addInput(new InputCamera(this, tr("Camera"), _camera));
addInputInt(tr("Quality"), &_params.quality, 1, 10, 1, 1); addInputInt(tr("Quality"), &_params.quality, 1, 10, 1, 1);
addInputInt(tr("Image width"), &_params.width, 100, 2000, 10, 100); addInputInt(tr("Image width"), &_params.width, 100, 4000, 10, 100);
addInputInt(tr("Image height"), &_params.height, 100, 1200, 10, 100); addInputInt(tr("Image height"), &_params.height, 100, 3000, 10, 100);
addInputInt(tr("Anti aliasing"), &_params.antialias, 1, 4, 1, 1); addInputInt(tr("Anti aliasing"), &_params.antialias, 1, 4, 1, 1);
button = addButton(tr("Start new render")); button = addButton(tr("Start new render"));

View file

@ -67,8 +67,13 @@ void Canvas::setSize(int width, int height)
this->width = width; this->width = width;
this->height = height; this->height = height;
// TODO Smaller preview // Smaller preview
preview->setSize(width, height, width, height); 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 CanvasPortion *Canvas::at(int x, int y) const

View file

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

View file

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

View file

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

View file

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

View file

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