Browse Source

Store dirty rectangles in a structure list. For now there is still only

one dirty rectangle, but this is the first step to improvement.
tags/v0.99.beta17
Sam Hocevar sam 15 years ago
parent
commit
10719139e6
3 changed files with 102 additions and 42 deletions
  1. +9
    -1
      caca/caca_internals.h
  2. +9
    -3
      caca/canvas.c
  3. +84
    -38
      caca/dirty.c

+ 9
- 1
caca/caca_internals.h View File

@@ -23,6 +23,7 @@ typedef struct caca_figfont caca_figfont_t;

#if !defined(_DOXYGEN_SKIP_ME)
# define EVENTBUF_LEN 10
# define MAX_DIRTY_COUNT 1
#endif

struct caca_frame
@@ -60,7 +61,11 @@ struct caca_canvas

/* Dirty rectangles */
int ndirty;
int dirty_xmin, dirty_xmax, dirty_ymin, dirty_ymax;
struct
{
int xmin, xmax, ymin, ymax;
}
dirty[MAX_DIRTY_COUNT];

/* Shortcut to the active frame information */
int width, height;
@@ -216,6 +221,9 @@ struct caca_display
} events;
};

/* Dirty rectangle functions */
extern void _caca_clip_dirty_rect_list(caca_canvas_t *);

/* Colour functions */
extern uint32_t _caca_attr_to_rgb24fg(uint32_t);
extern uint32_t _caca_attr_to_rgb24bg(uint32_t);


+ 9
- 3
caca/canvas.c View File

@@ -370,10 +370,17 @@ int caca_resize(caca_canvas_t *cv, int width, int height)

_caca_save_frame_info(cv);

/* Preload new width and height values into the canvas to optimise
* dirty rectangle handling */
cv->width = width;
cv->height = height;
new_size = width * height;

/* If width or height is smaller (or both), we have the opportunity to
* reduce or even remove dirty rectangles */
if(width < old_width || height < old_height)
_caca_clip_dirty_rect_list(cv);

/* Step 1: if new area is bigger, resize the memory area now. */
if(new_size > old_size)
{
@@ -470,9 +477,8 @@ int caca_resize(caca_canvas_t *cv, int width, int height)
caca_add_dirty_rect(cv, 0, old_height, old_width, height - old_height);
}

/* XXX: technically we should not worry about the dirty rectangle in
* the bottom-right corner, because we only handle one dirty rectangle,
* but in case the API changes later, we make sure this is handled. */
/* If both width and height are larger, there is a new dirty rectangle
* that needs to be created in the lower right corner. */
if(width > old_width && height > old_height)
caca_add_dirty_rect(cv, old_width, old_height,
width - old_width, height - old_height);


+ 84
- 38
caca/dirty.c View File

@@ -14,6 +14,14 @@

/*
* This file contains the dirty rectangle handling functions.
*
*
* About dirty rectangles:
*
* * Dirty rectangles MUST NOT be larger than the canvas. If the user
* provides a large rectangle through caca_add_dirty_rect(), or if the
* canvas changes size to become smaller, all dirty rectangles MUST
* immediately be clipped to the canvas size.
*/

#include "config.h"
@@ -77,23 +85,12 @@ int caca_get_dirty_rect(caca_canvas_t *cv, int r,
return -1;
}

/* Normalise dirty rectangle so that the values can be directly used. */
if(cv->dirty_xmin < 0)
cv->dirty_xmin = 0;

if(cv->dirty_xmax > cv->width - 1)
cv->dirty_xmax = cv->width - 1;
*x = cv->dirty[r].xmin;
*y = cv->dirty[r].ymin;
*width = cv->dirty[r].xmax - cv->dirty[r].xmin + 1;
*height = cv->dirty[r].ymax - cv->dirty[r].ymin + 1;

if(cv->dirty_ymin < 0)
cv->dirty_ymin = 0;

if(cv->dirty_ymax > cv->height - 1)
cv->dirty_ymax = cv->height - 1;

*x = cv->dirty_xmin;
*y = cv->dirty_ymin;
*width = cv->dirty_xmax - cv->dirty_xmin + 1;
*height = cv->dirty_ymax - cv->dirty_ymin + 1;
debug("dirty #%i: %ix%i at (%i,%i)\n", r, *width, *height, *x, *y);

return 0;
}
@@ -118,35 +115,49 @@ int caca_get_dirty_rect(caca_canvas_t *cv, int r,
* \param height The height of the additional dirty rectangle.
* \return 0 in case of success, -1 if an error occurred.
*/
int caca_add_dirty_rect(caca_canvas_t *cv, int x, int y,
int width, int height)
int caca_add_dirty_rect(caca_canvas_t *cv, int x, int y, int width, int height)
{
/* Ignore empty and out-of-bounds rectangles */
if(width <= 0 || height <= 0 || x + width <= 0 || x >= cv->width
|| y + height <= 0 || y >= cv->height)
debug("new dirty: %ix%i at (%i,%i)\n", width, height, x, y);

/* Clip arguments to canvas */
if(x < 0) { width += x; x = 0; }

if(x + width > cv->width)
width = cv->width - x;

if(y < 0) { height += y; y = 0; }

if(y + height > cv->height)
height = cv->height - y;

/* Ignore empty and out-of-canvas rectangles */
if(width <= 0 || height <= 0)
{
seterrno(EINVAL);
return -1;
}

if(cv->ndirty == 0)
/* Add dirty rectangle to list. Current strategy: if there is room
* for rectangles, just append it to the list. Otherwise, merge the
* new rectangle with the first in the list. */
if(cv->ndirty < MAX_DIRTY_COUNT)
{
cv->ndirty = 1;
cv->dirty_xmin = x;
cv->dirty_xmax = x + width - 1;
cv->dirty_ymin = y;
cv->dirty_ymax = y + height - 1;
cv->dirty[cv->ndirty].xmin = x;
cv->dirty[cv->ndirty].xmax = x + width - 1;
cv->dirty[cv->ndirty].ymin = y;
cv->dirty[cv->ndirty].ymax = y + height - 1;
cv->ndirty++;
}
else
{
if(x < cv->dirty_xmin)
cv->dirty_xmin = x;
if(x + width - 1 > cv->dirty_xmax)
cv->dirty_xmax = x + width - 1;
if(y < cv->dirty_ymin)
cv->dirty_ymin = y;
if(y + height - 1 > cv->dirty_ymax)
cv->dirty_ymax = y + height - 1;
if(x < cv->dirty[0].xmin)
cv->dirty[0].xmin = x;
if(x + width - 1 > cv->dirty[0].xmax)
cv->dirty[0].xmax = x + width - 1;
if(y < cv->dirty[0].ymin)
cv->dirty[0].ymin = y;
if(y + height - 1 > cv->dirty[0].ymax)
cv->dirty[0].ymax = y + height - 1;
}

return 0;
@@ -173,9 +184,19 @@ int caca_add_dirty_rect(caca_canvas_t *cv, int x, int y,
int caca_remove_dirty_rect(caca_canvas_t *cv, int x, int y,
int width, int height)
{
/* Ignore empty and out-of-bounds rectangles */
if(width <= 0 || height <= 0 || x + width <= 0 || x >= cv->width
|| y + height <= 0 || y >= cv->height)
/* Clip arguments to canvas size */
if(x < 0) { width += x; x = 0; }

if(x + width > cv->width)
width = cv->width - x;

if(y < 0) { height += y; y = 0; }

if(y + height > cv->height)
height = cv->height - y;

/* Ignore empty and out-of-canvas rectangles */
if(width <= 0 || height <= 0)
{
seterrno(EINVAL);
return -1;
@@ -204,3 +225,28 @@ int caca_clear_dirty_rect_list(caca_canvas_t *cv)
return 0;
}

/*
* XXX: the following functions are local.
*/

/* Clip all dirty rectangles in case they're larger than the canvas */
void _caca_clip_dirty_rect_list(caca_canvas_t *cv)
{
int i;

for(i = 0; i < cv->ndirty; i++)
{
if(cv->dirty[i].xmin < 0)
cv->dirty[i].xmin = 0;

if(cv->dirty[i].ymin < 0)
cv->dirty[i].ymin = 0;

if(cv->dirty[i].xmax >= cv->width)
cv->dirty[i].xmax = cv->width - 1;

if(cv->dirty[i].ymax >= cv->height)
cv->dirty[i].ymax = cv->height - 1;
}
}


Loading…
Cancel
Save