Only allocate canvas portion pixels when needed
This will allow for larger renders in constant memory footprint
This commit is contained in:
parent
c9fa33984b
commit
3a2ec1c75f
7 changed files with 66 additions and 17 deletions
|
@ -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"));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -8,19 +8,23 @@
|
||||||
#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()
|
||||||
{
|
{
|
||||||
delete[] pixels;
|
if (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;
|
||||||
|
}
|
||||||
|
|
||||||
delete[] pixels;
|
void CanvasPortion::preparePixels()
|
||||||
|
{
|
||||||
|
if (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)
|
||||||
|
|
|
@ -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).
|
||||||
*
|
*
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue