speedups when the calling application knows the dirty rectangle covered by a complex operation.tags/v0.99.beta17
@@ -156,7 +156,8 @@ int caca_put_attr(caca_canvas_t *cv, int x, int y, uint32_t attr) | |||
xmax++; | |||
} | |||
caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1); | |||
return 0; | |||
} | |||
@@ -240,6 +240,8 @@ __extern int caca_set_canvas_boundaries(caca_canvas_t *, int, int, int, int); | |||
* | |||
* These functions manipulate dirty rectangles for optimised blitting. | |||
* @{ */ | |||
__extern int caca_disable_dirty_rect(caca_canvas_t *); | |||
__extern int caca_enable_dirty_rect(caca_canvas_t *); | |||
__extern int caca_get_dirty_rect_count(caca_canvas_t *); | |||
__extern int caca_get_dirty_rect(caca_canvas_t *, int, int *, int *, | |||
int *, int *); | |||
@@ -60,7 +60,7 @@ struct caca_canvas | |||
void *resize_data; | |||
/* Dirty rectangles */ | |||
int ndirty; | |||
int ndirty, dirty_disabled; | |||
struct | |||
{ | |||
int xmin, ymin, xmax, ymax; | |||
@@ -433,7 +433,9 @@ int caca_resize(caca_canvas_t *cv, int width, int height) | |||
} | |||
} | |||
caca_add_dirty_rect(cv, old_width, 0, width - old_width, old_height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, old_width, 0, | |||
width - old_width, old_height); | |||
} | |||
else | |||
{ | |||
@@ -474,12 +476,15 @@ int caca_resize(caca_canvas_t *cv, int width, int height) | |||
} | |||
} | |||
caca_add_dirty_rect(cv, 0, old_height, old_width, height - old_height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, old_height, | |||
old_width, height - old_height); | |||
} | |||
/* 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) | |||
if(!cv->dirty_disabled && | |||
width > old_width && height > old_height) | |||
caca_add_dirty_rect(cv, old_width, old_height, | |||
width - old_width, height - old_height); | |||
@@ -36,6 +36,51 @@ | |||
static void merge_new_rect(caca_canvas_t *cv, int n); | |||
/** \brief Disable dirty rectangles. | |||
* | |||
* Disable dirty rectangle handling for all \e libcaca graphic calls. This | |||
* is handy when the calling application needs to do slow operations within | |||
* a known area. Just call caca_add_dirty_rect() afterwards. | |||
* | |||
* This function is recursive. Dirty rectangles are only reenabled when | |||
* caca_enable_dirty_rect() is called as many times. | |||
* | |||
* This function never fails. | |||
* | |||
* \param cv A libcaca canvas. | |||
* \return This function always returns 0. | |||
*/ | |||
int caca_disable_dirty_rect(caca_canvas_t *cv) | |||
{ | |||
cv->dirty_disabled++; | |||
return 0; | |||
} | |||
/** \brief Enable dirty rectangles. | |||
* | |||
* This function can only be called after caca_disable_dirty_rect() was | |||
* called. | |||
* | |||
* If an error occurs, -1 is returned and \b errno is set accordingly: | |||
* - \c EINVAL Dirty rectangles were not disabled. | |||
* | |||
* \param cv A libcaca canvas. | |||
* \return 0 in case of success, -1 if an error occurred. | |||
*/ | |||
int caca_enable_dirty_rect(caca_canvas_t *cv) | |||
{ | |||
if(cv->dirty_disabled <= 0) | |||
{ | |||
seterrno(EINVAL); | |||
return -1; | |||
} | |||
cv->dirty_disabled--; | |||
return 0; | |||
} | |||
/** \brief Get the number of dirty rectangles in the canvas. | |||
* | |||
* Get the number of dirty rectangles in a canvas. Dirty rectangles are | |||
@@ -72,7 +72,8 @@ int caca_set_frame(caca_canvas_t *cv, int id) | |||
cv->frame = id; | |||
_caca_load_frame_info(cv); | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -236,7 +237,8 @@ int caca_free_frame(caca_canvas_t *cv, int id) | |||
{ | |||
cv->frame = 0; | |||
_caca_load_frame_info(cv); | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
} | |||
return 0; | |||
@@ -180,7 +180,8 @@ int caca_put_char(caca_canvas_t *cv, int x, int y, uint32_t ch) | |||
* or attribute at that place. This does not account for inconsistencies | |||
* in the canvas, ie. if CACA_MAGIC_FULLWIDTH lies at illegal places, | |||
* but it's the caller's responsibility not to corrupt the contents. */ | |||
if(curchar[0] != ch || curattr[0] != attr) | |||
if(!cv->dirty_disabled | |||
&& (curchar[0] != ch || curattr[0] != attr)) | |||
caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1); | |||
curchar[0] = ch; | |||
@@ -327,7 +328,8 @@ int caca_clear_canvas(caca_canvas_t *cv) | |||
cv->attrs[n] = attr; | |||
} | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -453,7 +455,8 @@ int caca_blit(caca_canvas_t *dst, int x, int y, | |||
{ | |||
dst->chars[dstix + i] = src->chars[srcix + i]; | |||
dst->attrs[dstix + i] = src->attrs[srcix + i]; | |||
caca_add_dirty_rect(dst, x + starti + i, y + j, 1, 1); | |||
if(!dst->dirty_disabled) | |||
caca_add_dirty_rect(dst, x + starti + i, y + j, 1, 1); | |||
} | |||
} | |||
} | |||
@@ -465,7 +468,8 @@ int caca_blit(caca_canvas_t *dst, int x, int y, | |||
/* FIXME be more precise ? */ | |||
memcpy(dst->chars + dstix, src->chars + srcix, stride * 4); | |||
memcpy(dst->attrs + dstix, src->attrs + srcix, stride * 4); | |||
caca_add_dirty_rect(dst, x + starti, y + j, stride, 1); | |||
if(!dst->dirty_disabled) | |||
caca_add_dirty_rect(dst, x + starti, y + j, stride, 1); | |||
} | |||
} | |||
@@ -542,7 +546,8 @@ int caca_set_canvas_boundaries(caca_canvas_t *cv, int x, int y, int w, int h) | |||
_caca_load_frame_info(cv); | |||
/* FIXME: this may be optimised somewhat */ | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -54,7 +54,8 @@ int caca_invert(caca_canvas_t *cv) | |||
attrs++; | |||
} | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -115,7 +116,8 @@ int caca_flip(caca_canvas_t *cv) | |||
} | |||
} | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -162,7 +164,8 @@ int caca_flop(caca_canvas_t *cv) | |||
*ctop = flopchar(*ctop); | |||
} | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -221,7 +224,8 @@ int caca_rotate_180(caca_canvas_t *cv) | |||
} | |||
} | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -340,7 +344,8 @@ int caca_rotate_left(caca_canvas_t *cv) | |||
/* Reset the current frame shortcuts */ | |||
_caca_load_frame_info(cv); | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -459,7 +464,8 @@ int caca_rotate_right(caca_canvas_t *cv) | |||
/* Reset the current frame shortcuts */ | |||
_caca_load_frame_info(cv); | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
if(!cv->dirty_disabled) | |||
caca_add_dirty_rect(cv, 0, 0, cv->width, cv->height); | |||
return 0; | |||
} | |||
@@ -1,2 +1,3 @@ | |||
simple | |||
bench | |||
caca-test | |||
simple |
@@ -47,16 +47,23 @@ static void blit(int mask, int clear) | |||
caca_free_canvas(cv2); | |||
} | |||
static void putchars(void) | |||
static void putchars(int optim) | |||
{ | |||
caca_canvas_t *cv; | |||
int i; | |||
cv = caca_create_canvas(40, 40); | |||
if(optim) | |||
caca_disable_dirty_rect(cv); | |||
for (i = 0; i < PUTCHAR_LOOPS; i++) | |||
{ | |||
caca_put_char(cv, 1, 1, 'x'); | |||
caca_put_char(cv, 1, 1, 'o'); | |||
} | |||
if(optim) | |||
{ | |||
caca_enable_dirty_rect(cv); | |||
caca_add_dirty_rect(cv, 1, 1, 1, 1); | |||
} | |||
caca_free_canvas(cv); | |||
} | |||
@@ -66,7 +73,8 @@ int main(int argc, char *argv[]) | |||
TIME("blit no mask, clear", blit(0, 1)); | |||
TIME("blit mask, no clear", blit(1, 0)); | |||
TIME("blit mask, clear", blit(1, 1)); | |||
TIME("putchars", putchars()); | |||
TIME("putchars, no optim", putchars(0)); | |||
TIME("putchars, optim", putchars(1)); | |||
return 0; | |||
} | |||