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; | |||
| } | |||