Skip to content

Commit

Permalink
Bitmap: optimize drawing of other images
Browse files Browse the repository at this point in the history
The main idea is to remove calls to put/get pixels. This means we remove
the offsets computations, range checks, and stack windings. Now, when
the tab widgets window is maximized, I can almost change tabs
"immediatelly" (before it took "a few moments").

Using valgrind, after this fix the hot function from (number is
instruction set, as calculate by valgrind):

Before:
put_pixel: ~340,000,000
get_pixel: ~276,000,000
draw: ~259,000,000

After:
draw: ~360,000,000
gnu_cxx::__enable_if_scalar: ~167,000,000
std::vector::insert: ~127,000,000

Which means we still have things to optimize (maybe using more direct
access to memory?) and then even using some `memmove()` or something
similar instead of the X axis loop (this will gain a lot of memory). We
also need to take care of the extra layouts in the tab widget.

Specific optimizations:

1. Optimize rectangle drawing: We can write directly
   to the buffer, instead of using `put_pixel()` this  will gain:
     * speed up for not checking ranges
     * speed up for not calculating offsets on every pixel (a
       multiplication)
     * calling to another function

2. Optimize drawing another bitmap:  reading the color other other image,
   by bypassing the  `get_pixel()` function as we did before.

3. Optimize drawing image - `put_pixel()`:  call to `put_pixel()` is removed,
    in favor of using offsets in the target image.
  • Loading branch information
diegoiast committed May 17, 2024
1 parent f44cb0d commit e9bc409
Showing 1 changed file with 23 additions and 12 deletions.
35 changes: 23 additions & 12 deletions src/bitmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,13 @@ auto Bitmap::rescale_from(const Bitmap &other, int width, int height) -> void {
auto Bitmap::fill_rect(int x, int y, int w, int h, uint32_t c) -> void {
w = std::min(w, size.width);
h = std::min(h, size.height);
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
put_pixel(x + col, y + row, c);
auto offset = y * size.width + x;
for (int yy = 0; yy < h; yy++) {
for (int xx = 0; xx < w; xx++) {
this->buffer[offset] = c;
offset += 1;
}
offset += this->size.width - w;
}
}

Expand All @@ -246,11 +249,14 @@ auto Bitmap::fill_rect_gradient(int x, int y, int w, int h, uint32_t color1, uin
return;
}
auto gradient = Gradient(color1, color2, h);
auto offset = y * size.width + x;
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
put_pixel(x + col, y + row, gradient.get_color());
this->buffer[offset] = gradient.get_color();
offset += 1;
}
gradient.next();
offset += this->size.width - w;
}
}

Expand Down Expand Up @@ -505,17 +511,22 @@ auto Bitmap::fill(int x, int y, uint32_t old, uint32_t c) -> void {
}

auto Bitmap::draw(Position position, const Bitmap &other) -> void {
auto other_offset = 0;
auto my_offset = position.y * size.width + position.x;

for (auto y = 0; y < other.size.height; y++) {
auto yy = y + position.y;
if (yy > size.height) {
break;
}
for (auto x = 0; x < other.size.width; x++) {
auto xx = x + position.x;
if (xx > size.width) {
break;
if (yy >= 0 && yy < size.height) {
for (auto x = 0; x < other.size.width; x++) {
auto xx = x + position.x;
if (xx >= 0 && xx < size.width) {
auto c2 = other.buffer[other_offset];
this->buffer[my_offset] = c2;
}
other_offset += 1;
my_offset += 1;
}
put_pixel(xx, yy, other.get_pixel(x, y));
}
my_offset += size.width - other.size.width;
}
}

0 comments on commit e9bc409

Please sign in to comment.