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++; | 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; | 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. | * 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_count(caca_canvas_t *); | ||||
__extern int caca_get_dirty_rect(caca_canvas_t *, int, int *, int *, | __extern int caca_get_dirty_rect(caca_canvas_t *, int, int *, int *, | ||||
int *, int *); | int *, int *); | ||||
@@ -60,7 +60,7 @@ struct caca_canvas | |||||
void *resize_data; | void *resize_data; | ||||
/* Dirty rectangles */ | /* Dirty rectangles */ | ||||
int ndirty; | |||||
int ndirty, dirty_disabled; | |||||
struct | struct | ||||
{ | { | ||||
int xmin, ymin, xmax, ymax; | 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 | 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 | /* If both width and height are larger, there is a new dirty rectangle | ||||
* that needs to be created in the lower right corner. */ | * 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, | caca_add_dirty_rect(cv, old_width, old_height, | ||||
width - old_width, height - old_height); | width - old_width, height - old_height); | ||||
@@ -36,6 +36,51 @@ | |||||
static void merge_new_rect(caca_canvas_t *cv, int n); | 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. | /** \brief Get the number of dirty rectangles in the canvas. | ||||
* | * | ||||
* Get the number of dirty rectangles in a canvas. Dirty rectangles are | * 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; | cv->frame = id; | ||||
_caca_load_frame_info(cv); | _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; | return 0; | ||||
} | } | ||||
@@ -236,7 +237,8 @@ int caca_free_frame(caca_canvas_t *cv, int id) | |||||
{ | { | ||||
cv->frame = 0; | cv->frame = 0; | ||||
_caca_load_frame_info(cv); | _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; | 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 | * or attribute at that place. This does not account for inconsistencies | ||||
* in the canvas, ie. if CACA_MAGIC_FULLWIDTH lies at illegal places, | * in the canvas, ie. if CACA_MAGIC_FULLWIDTH lies at illegal places, | ||||
* but it's the caller's responsibility not to corrupt the contents. */ | * 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); | caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1); | ||||
curchar[0] = ch; | curchar[0] = ch; | ||||
@@ -327,7 +328,8 @@ int caca_clear_canvas(caca_canvas_t *cv) | |||||
cv->attrs[n] = attr; | 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; | 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->chars[dstix + i] = src->chars[srcix + i]; | ||||
dst->attrs[dstix + i] = src->attrs[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 ? */ | /* FIXME be more precise ? */ | ||||
memcpy(dst->chars + dstix, src->chars + srcix, stride * 4); | memcpy(dst->chars + dstix, src->chars + srcix, stride * 4); | ||||
memcpy(dst->attrs + dstix, src->attrs + 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); | _caca_load_frame_info(cv); | ||||
/* FIXME: this may be optimised somewhat */ | /* 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; | return 0; | ||||
} | } | ||||
@@ -54,7 +54,8 @@ int caca_invert(caca_canvas_t *cv) | |||||
attrs++; | 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; | 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; | return 0; | ||||
} | } | ||||
@@ -162,7 +164,8 @@ int caca_flop(caca_canvas_t *cv) | |||||
*ctop = flopchar(*ctop); | *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; | 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; | return 0; | ||||
} | } | ||||
@@ -340,7 +344,8 @@ int caca_rotate_left(caca_canvas_t *cv) | |||||
/* Reset the current frame shortcuts */ | /* Reset the current frame shortcuts */ | ||||
_caca_load_frame_info(cv); | _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; | return 0; | ||||
} | } | ||||
@@ -459,7 +464,8 @@ int caca_rotate_right(caca_canvas_t *cv) | |||||
/* Reset the current frame shortcuts */ | /* Reset the current frame shortcuts */ | ||||
_caca_load_frame_info(cv); | _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; | return 0; | ||||
} | } | ||||
@@ -1,2 +1,3 @@ | |||||
simple | |||||
bench | |||||
caca-test | caca-test | ||||
simple |
@@ -47,16 +47,23 @@ static void blit(int mask, int clear) | |||||
caca_free_canvas(cv2); | caca_free_canvas(cv2); | ||||
} | } | ||||
static void putchars(void) | |||||
static void putchars(int optim) | |||||
{ | { | ||||
caca_canvas_t *cv; | caca_canvas_t *cv; | ||||
int i; | int i; | ||||
cv = caca_create_canvas(40, 40); | cv = caca_create_canvas(40, 40); | ||||
if(optim) | |||||
caca_disable_dirty_rect(cv); | |||||
for (i = 0; i < PUTCHAR_LOOPS; i++) | for (i = 0; i < PUTCHAR_LOOPS; i++) | ||||
{ | { | ||||
caca_put_char(cv, 1, 1, 'x'); | caca_put_char(cv, 1, 1, 'x'); | ||||
caca_put_char(cv, 1, 1, 'o'); | 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); | caca_free_canvas(cv); | ||||
} | } | ||||
@@ -66,7 +73,8 @@ int main(int argc, char *argv[]) | |||||
TIME("blit no mask, clear", blit(0, 1)); | TIME("blit no mask, clear", blit(0, 1)); | ||||
TIME("blit mask, no clear", blit(1, 0)); | TIME("blit mask, no clear", blit(1, 0)); | ||||
TIME("blit mask, clear", blit(1, 1)); | TIME("blit mask, clear", blit(1, 1)); | ||||
TIME("putchars", putchars()); | |||||
TIME("putchars, no optim", putchars(0)); | |||||
TIME("putchars, optim", putchars(1)); | |||||
return 0; | return 0; | ||||
} | } | ||||