-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[rmkit][fb] speed up draw_rect functions #78
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,9 @@ | |
#include "../../vendor/stb/stb_image.h" | ||
#include "../../vendor/stb/stb_image_write.h" | ||
|
||
#define likely(x) __builtin_expect(!!(x), 1) | ||
#define unlikely(x) __builtin_expect(!!(x), 0) | ||
|
||
using namespace std | ||
|
||
DEBUG_FB_INFO := getenv("DEBUG_FB_INFO") != NULL | ||
|
@@ -220,7 +223,7 @@ namespace framebuffer: | |
self._set_pixel(i, j, WHITE) | ||
break | ||
default: | ||
if dither != 1.0: | ||
if unlikely(dither != 1.0): | ||
if fast_rand() / float(2 << 15) < dither: | ||
self._set_pixel(i, j, color) | ||
else: | ||
|
@@ -248,6 +251,12 @@ namespace framebuffer: | |
// | ||
// note that dithering does not work with GRAY, RUBBER or ERASER | ||
inline void draw_rect(int o_x, o_y, w, h, color, fill=true, float dither=1.0): | ||
update_dirty(dirty_area, o_x, o_y) | ||
update_dirty(dirty_area, o_x+w, o_y+h) | ||
|
||
_draw_rect_fast(o_x, o_y, w, h, color, fill, dither) | ||
|
||
inline void _draw_rect_fast(int o_x, o_y, w, h, color, fill=true, float dither=1.0): | ||
self.dirty = 1 | ||
#ifdef DEBUG_FB | ||
fprintf(stderr, "DRAWING RECT X: %i Y: %i W: %i H: %i, COLOR: %i\n", o_x, o_y, w, h, color) | ||
|
@@ -256,19 +265,30 @@ namespace framebuffer: | |
if o_y >= self.height || o_x >= self.width || o_y < 0 || o_x < 0: | ||
return | ||
|
||
update_dirty(dirty_area, o_x, o_y) | ||
update_dirty(dirty_area, o_x+w, o_y+h) | ||
if likely(fill): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like almost every function calls this with What about making if fill:
_draw_rect_fast(x, y, w, h, ...)
else:
_draw_rect_fast(x, y, w, 1, ...) // top
_draw_rect_fast(x, y+h-1, w, 1, ...) // bottom
_draw_rect_fast(x, y, 1, h, ...) // left
_draw_rect_fast(x+w-1, y, 1, h, ...) // right The main difference I think is that do_dithering could still be inlined in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that looks good to me |
||
for j 0 h: | ||
if j+o_y >= self.height: | ||
break | ||
|
||
for j 0 h: | ||
if j+o_y >= self.height: | ||
break | ||
for i 0 w: | ||
if i+o_x >= self.width: | ||
break | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder how expensive these comparisons are (they might not be at all) compared to: w = min(w, self.width-x)
h = min(h, self.height-y)
for j 0 h:
for i 0 w:
do_dithering(self.fbmem, i+o_x, j+o_y, color, dither) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i had a little trouble with this just now (and had trouble the first couple times i tried it a while back) |
||
|
||
do_dithering(self.fbmem, i+o_x, j+o_y, color, dither) | ||
else: | ||
for j 0 h: | ||
if j+o_y >= self.height: | ||
break | ||
|
||
do_dithering(self.fbmem, o_x, j+o_y, color, dither) | ||
do_dithering(self.fbmem, w+o_x-1, j+o_y, color, dither) | ||
|
||
for i 0 w: | ||
if i+o_x >= self.width: | ||
break | ||
|
||
if fill || (j == 0 || i == 0 || j == h-1 || i == w-1): | ||
do_dithering(self.fbmem, i+o_x, j+o_y, color, dither) | ||
do_dithering(self.fbmem, i+o_x, o_y, color, dither) | ||
do_dithering(self.fbmem, i+o_x, h+o_y-1, color, dither) | ||
|
||
inline remarkable_color to_rgb565(char *src, int offset): | ||
r := src[offset] | ||
|
@@ -454,15 +474,18 @@ namespace framebuffer: | |
int w = stroke | ||
int h = stroke | ||
|
||
update_dirty(dirty_area, x0-radius, y0-radius) | ||
update_dirty(dirty_area, x0+radius, y0+radius) | ||
|
||
while(x <= y): | ||
self.draw_rect(x+x0, y+y0, w, h, color, true); | ||
self.draw_rect(-x+x0, y+y0, w, h, color, true); | ||
self.draw_rect(x+x0, -y+y0, w, h, color, true); | ||
self.draw_rect(-x+x0, -y+y0, w, h, color, true); | ||
self.draw_rect(y+x0, x+y0, w, h, color, true); | ||
self.draw_rect(-y+x0, x+y0, w, h, color, true); | ||
self.draw_rect(y+x0, -x+y0, w, h, color, true); | ||
self.draw_rect(-y+x0, -x+y0, w, h, color, true); | ||
_draw_rect_fast(x+x0, y+y0, w, h, color, true); | ||
_draw_rect_fast(-x+x0, y+y0, w, h, color, true); | ||
_draw_rect_fast(x+x0, -y+y0, w, h, color, true); | ||
_draw_rect_fast(-x+x0, -y+y0, w, h, color, true); | ||
_draw_rect_fast(y+x0, x+y0, w, h, color, true); | ||
_draw_rect_fast(-y+x0, x+y0, w, h, color, true); | ||
_draw_rect_fast(y+x0, -x+y0, w, h, color, true); | ||
_draw_rect_fast(-y+x0, -x+y0, w, h, color, true); | ||
|
||
if(d <= 0): | ||
x++; | ||
|
@@ -478,7 +501,10 @@ namespace framebuffer: | |
w := stroke | ||
h := stroke | ||
|
||
self.draw_rect(x, y, w, h, color, true); | ||
update_dirty(dirty_area, x0-r, y0-r) | ||
update_dirty(dirty_area, x0+r, y0+r) | ||
|
||
_draw_rect_fast(x, y, w, h, color, true); | ||
d := (3-2*(int)r); | ||
while (x <= y): | ||
if (d <= 0): | ||
|
@@ -488,21 +514,24 @@ namespace framebuffer: | |
y--; | ||
x++; | ||
|
||
self.draw_rect(x+x0, y+y0, w, h, color, true); | ||
self.draw_rect(-x+x0, y+y0, w, h, color, true); | ||
self.draw_rect(x+x0, -y+y0, w, h, color, true); | ||
self.draw_rect(-x+x0, -y+y0, w, h, color, true); | ||
self.draw_rect(y+x0, x+y0, w, h, color, true); | ||
self.draw_rect(-y+x0, x+y0, w, h, color, true); | ||
self.draw_rect(y+x0, -x+y0, w, h, color, true); | ||
_draw_rect_fast(x+x0, y+y0, w, h, color, true); | ||
_draw_rect_fast(-x+x0, y+y0, w, h, color, true); | ||
_draw_rect_fast(x+x0, -y+y0, w, h, color, true); | ||
_draw_rect_fast(-x+x0, -y+y0, w, h, color, true); | ||
_draw_rect_fast(y+x0, x+y0, w, h, color, true); | ||
_draw_rect_fast(-y+x0, x+y0, w, h, color, true); | ||
_draw_rect_fast(y+x0, -x+y0, w, h, color, true); | ||
|
||
self.draw_rect(-y+x0, -x+y0, w, h, color, true); | ||
_draw_rect_fast(-y+x0, -x+y0, w, h, color, true); | ||
|
||
def draw_circle_filled(int x0, y0, radius, stroke, color): | ||
update_dirty(dirty_area, x0-radius, y0-radius) | ||
update_dirty(dirty_area, x0+radius, y0+radius) | ||
|
||
for x := -radius; x <= radius; x++: | ||
for y := -radius; y <= radius; y++: | ||
if (x*x+y*y) <= radius*radius: | ||
self.draw_rect(x+x0, y+y0, stroke, stroke, color, true) | ||
_draw_rect_fast(x+x0, y+y0, stroke, stroke, color, true) | ||
|
||
// function: draw_circle | ||
// | ||
|
@@ -548,13 +577,17 @@ namespace framebuffer: | |
fprintf(stderr, "DRAWING LINE %i %i %i %i\n", x0, y0, x1, y1) | ||
#endif | ||
self.dirty = 1 | ||
|
||
update_dirty(dirty_area, x0, y0) | ||
update_dirty(dirty_area, x1, y1) | ||
|
||
dx := abs(x1-x0) | ||
sx := x0<x1 ? 1 : -1 | ||
dy := -abs(y1-y0) | ||
sy := y0<y1 ? 1 : -1 | ||
err := dx+dy /* error value e_xy */ | ||
while (true): /* loop */ | ||
self.draw_rect(x0, y0, width, width, color,true,dither) | ||
_draw_rect_fast(x0, y0, width, width, color,true,dither) | ||
// self.fbmem[y0*self.width + x0] = color | ||
if (x0==x1 && y0==y1) break; | ||
e2 := 2*err | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do see a huge reduction in the number of times update_dirty is called, which seems like a net benefit in any case, so this looks like a helpful part for sure.