summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2020-02-29 22:04:02 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2020-03-01 16:12:55 +0100
commita9ee71d8f1ccc634acdd9f0205855af1527c4bb9 (patch)
treeea0d288e59b9d4fa8f9679f063883afd9ae1d8fd
parent15e9d38d36573ba0e1ec6e0cc2768b12ca01bff0 (diff)
WIP: Move pixel buffer render code from Window to PixelBuffer for easier testing/benchmarking.
-rw-r--r--plugingui/guievent.h5
-rw-r--r--plugingui/pixelbuffer.cc141
-rw-r--r--plugingui/pixelbuffer.h5
-rw-r--r--plugingui/window.cc136
-rw-r--r--test/uitests/benchmarktest.cc28
5 files changed, 182 insertions, 133 deletions
diff --git a/plugingui/guievent.h b/plugingui/guievent.h
index fa42483..4ad0798 100644
--- a/plugingui/guievent.h
+++ b/plugingui/guievent.h
@@ -202,6 +202,11 @@ struct Rect
std::size_t y1;
std::size_t x2;
std::size_t y2;
+
+ bool empty() const
+ {
+ return x1 == x2 && y1 == y2;
+ }
};
} // GUI::
diff --git a/plugingui/pixelbuffer.cc b/plugingui/pixelbuffer.cc
index 1df1d5a..827d2fc 100644
--- a/plugingui/pixelbuffer.cc
+++ b/plugingui/pixelbuffer.cc
@@ -104,6 +104,147 @@ void PixelBuffer::writeLine(std::size_t x, std::size_t y,
}
}
+Rect PixelBuffer::updateBuffer(std::vector<PixelBufferAlpha*>& pixel_buffers)
+{
+ bool has_dirty_rect{false};
+ Rect dirty_rect;
+
+ for(const auto& pixel_buffer : pixel_buffers)
+ {
+ if(pixel_buffer->dirty)
+ {
+ auto x1 = (std::size_t)pixel_buffer->x;
+ auto x2 = (std::size_t)(pixel_buffer->x + pixel_buffer->width);
+ auto y1 = (std::size_t)pixel_buffer->y;
+ auto y2 = (std::size_t)(pixel_buffer->y + pixel_buffer->height);
+
+ pixel_buffer->dirty = false;
+ if(!has_dirty_rect)
+ {
+ // Insert this area:
+ dirty_rect = {x1, y1, x2, y2};
+ has_dirty_rect = true;
+ }
+ else
+ {
+ // Expand existing area:
+ auto x1_0 = dirty_rect.x1;
+ auto y1_0 = dirty_rect.y1;
+ auto x2_0 = dirty_rect.x2;
+ auto y2_0 = dirty_rect.y2;
+ dirty_rect = {
+ (x1_0 < x1) ? x1_0 : x1,
+ (y1_0 < y1) ? y1_0 : y1,
+ (x2_0 > x2) ? x2_0 : x2,
+ (y2_0 > y2) ? y2_0 : y2
+ };
+ }
+ }
+
+ if(pixel_buffer->has_last)
+ {
+ auto x1 = (std::size_t)pixel_buffer->last_x;
+ auto x2 = (std::size_t)(pixel_buffer->last_x + pixel_buffer->last_width);
+ auto y1 = (std::size_t)pixel_buffer->last_y;
+ auto y2 = (std::size_t)(pixel_buffer->last_y + pixel_buffer->last_height);
+
+ pixel_buffer->has_last = false;
+ if(!has_dirty_rect)
+ {
+ // Insert this area:
+ dirty_rect = {x1, y1, x2, y2};
+ has_dirty_rect = true;
+ }
+ else
+ {
+ // Expand existing area:
+ auto x1_0 = dirty_rect.x1;
+ auto y1_0 = dirty_rect.y1;
+ auto x2_0 = dirty_rect.x2;
+ auto y2_0 = dirty_rect.y2;
+ dirty_rect = {
+ (x1_0 < x1) ? x1_0 : x1,
+ (y1_0 < y1) ? y1_0 : y1,
+ (x2_0 > x2) ? x2_0 : x2,
+ (y2_0 > y2) ? y2_0 : y2
+ };
+ }
+ }
+ }
+
+ if(!has_dirty_rect)
+ {
+ return {};
+ }
+
+ for(const auto& pixel_buffer : pixel_buffers)
+ {
+ if(!pixel_buffer->visible)
+ {
+ continue;
+ }
+
+ int update_width = pixel_buffer->width;
+ int update_height = pixel_buffer->height;
+
+ // Skip buffer if not inside window.
+ if(((int)width < pixel_buffer->x) ||
+ ((int)height < pixel_buffer->y))
+ {
+ continue;
+ }
+
+ if(update_width > ((int)width - pixel_buffer->x))
+ {
+ update_width = ((int)width - pixel_buffer->x);
+ }
+
+ if(update_height > ((int)height - pixel_buffer->y))
+ {
+ update_height = ((int)height - pixel_buffer->y);
+ }
+
+ auto from_x = (int)dirty_rect.x1 - pixel_buffer->x;
+ from_x = std::max(0, from_x);
+ auto from_y = (int)dirty_rect.y1 - pixel_buffer->y;
+ from_y = std::max(0, from_y);
+
+ auto to_x = (int)dirty_rect.x2 - pixel_buffer->x;
+ to_x = std::min(to_x, (int)update_width);
+ auto to_y = (int)dirty_rect.y2 - pixel_buffer->y;
+ to_y = std::min(to_y, (int)update_height);
+
+ if(to_x < from_x)
+ {
+ continue;
+ }
+
+ for(int y = from_y; y < to_y; y++)
+ {
+ writeLine(pixel_buffer->x + from_x,
+ pixel_buffer->y + y,
+ pixel_buffer->getLine(from_x, y),
+ to_x - from_x);
+ }
+ }
+
+ dirty_rect.x2 = std::min(width, dirty_rect.x2);
+ dirty_rect.y2 = std::min(height, dirty_rect.y2);
+
+ // Make sure we don't try to paint a rect backwards.
+ if(dirty_rect.x1 > dirty_rect.x2)
+ {
+ std::swap(dirty_rect.x1, dirty_rect.x2);
+ }
+
+ if(dirty_rect.y1 > dirty_rect.y2)
+ {
+ std::swap(dirty_rect.y1, dirty_rect.y2);
+ }
+
+ return dirty_rect;
+}
+
PixelBufferAlpha::PixelBufferAlpha(std::size_t width, std::size_t height)
: managed(true)
diff --git a/plugingui/pixelbuffer.h b/plugingui/pixelbuffer.h
index 499940d..81921e5 100644
--- a/plugingui/pixelbuffer.h
+++ b/plugingui/pixelbuffer.h
@@ -29,6 +29,9 @@
#include "colour.h"
#include <cstddef>
+#include <vector>
+
+#include "guievent.h"
namespace GUI
{
@@ -46,6 +49,8 @@ public:
void writeLine(std::size_t x, std::size_t y,
const std::uint8_t* line, std::size_t len);
+ Rect updateBuffer(std::vector<class PixelBufferAlpha*>& pixel_buffers);
+
std::uint8_t* buf{nullptr};
std::size_t width{0};
std::size_t height{0};
diff --git a/plugingui/window.cc b/plugingui/window.cc
index acde008..5e0ad31 100644
--- a/plugingui/window.cc
+++ b/plugingui/window.cc
@@ -250,144 +250,14 @@ bool Window::updateBuffer()
return false;
}
- bool has_dirty_rect{false};
- Rect dirty_rect;
-
auto pixel_buffers = getPixelBuffers();
- for(auto& pixel_buffer : pixel_buffers)
- {
- if(pixel_buffer->dirty)
- {
- auto x1 = (std::size_t)pixel_buffer->x;
- auto x2 = (std::size_t)(pixel_buffer->x + pixel_buffer->width);
- auto y1 = (std::size_t)pixel_buffer->y;
- auto y2 = (std::size_t)(pixel_buffer->y + pixel_buffer->height);
-
- pixel_buffer->dirty = false;
- if(!has_dirty_rect)
- {
- // Insert this area:
- dirty_rect = {x1, y1, x2, y2};
- has_dirty_rect = true;
- }
- else
- {
- // Expand existing area:
- auto x1_0 = dirty_rect.x1;
- auto y1_0 = dirty_rect.y1;
- auto x2_0 = dirty_rect.x2;
- auto y2_0 = dirty_rect.y2;
- dirty_rect = {
- (x1_0 < x1) ? x1_0 : x1,
- (y1_0 < y1) ? y1_0 : y1,
- (x2_0 > x2) ? x2_0 : x2,
- (y2_0 > y2) ? y2_0 : y2
- };
- }
- }
-
- if(pixel_buffer->has_last)
- {
- auto x1 = (std::size_t)pixel_buffer->last_x;
- auto x2 = (std::size_t)(pixel_buffer->last_x + pixel_buffer->last_width);
- auto y1 = (std::size_t)pixel_buffer->last_y;
- auto y2 = (std::size_t)(pixel_buffer->last_y + pixel_buffer->last_height);
-
- pixel_buffer->has_last = false;
- if(!has_dirty_rect)
- {
- // Insert this area:
- dirty_rect = {x1, y1, x2, y2};
- has_dirty_rect = true;
- }
- else
- {
- // Expand existing area:
- auto x1_0 = dirty_rect.x1;
- auto y1_0 = dirty_rect.y1;
- auto x2_0 = dirty_rect.x2;
- auto y2_0 = dirty_rect.y2;
- dirty_rect = {
- (x1_0 < x1) ? x1_0 : x1,
- (y1_0 < y1) ? y1_0 : y1,
- (x2_0 > x2) ? x2_0 : x2,
- (y2_0 > y2) ? y2_0 : y2
- };
- }
- }
- }
-
- if(!has_dirty_rect)
- {
- return false;
- }
- for(auto& pixel_buffer : pixel_buffers)
- {
- if(!pixel_buffer->visible)
- {
- continue;
- }
-
- int update_width = pixel_buffer->width;
- int update_height = pixel_buffer->height;
-
- // Skip buffer if not inside window.
- if(((int)wpixbuf.width < pixel_buffer->x) ||
- ((int)wpixbuf.height < pixel_buffer->y))
- {
- continue;
- }
-
- if(update_width > ((int)wpixbuf.width - pixel_buffer->x))
- {
- update_width = ((int)wpixbuf.width - pixel_buffer->x);
- }
-
- if(update_height > ((int)wpixbuf.height - pixel_buffer->y))
- {
- update_height = ((int)wpixbuf.height - pixel_buffer->y);
- }
-
- auto from_x = (int)dirty_rect.x1 - pixel_buffer->x;
- from_x = std::max(0, from_x);
- auto from_y = (int)dirty_rect.y1 - pixel_buffer->y;
- from_y = std::max(0, from_y);
-
- auto to_x = (int)dirty_rect.x2 - pixel_buffer->x;
- to_x = std::min(to_x, (int)update_width);
- auto to_y = (int)dirty_rect.y2 - pixel_buffer->y;
- to_y = std::min(to_y, (int)update_height);
-
- if(to_x < from_x)
- {
- continue;
- }
-
- for(int y = from_y; y < to_y; y++)
- {
- wpixbuf.writeLine(pixel_buffer->x + from_x,
- pixel_buffer->y + y,
- pixel_buffer->getLine(from_x, y),
- to_x - from_x);
- }
- }
+ auto dirty_rect = wpixbuf.updateBuffer(pixel_buffers);
- dirty_rect.x2 = std::min(wpixbuf.width, dirty_rect.x2);
- dirty_rect.y2 = std::min(wpixbuf.height, dirty_rect.y2);
-
- // Make sure we don't try to paint a rect backwards.
- if(dirty_rect.x1 > dirty_rect.x2)
+ if(!dirty_rect.empty())
{
- std::swap(dirty_rect.x1, dirty_rect.x2);
+ native->redraw(dirty_rect);
}
-
- if(dirty_rect.y1 > dirty_rect.y2)
- {
- std::swap(dirty_rect.y1, dirty_rect.y2);
- }
-
- native->redraw(dirty_rect);
needs_redraw = false;
return true;
diff --git a/test/uitests/benchmarktest.cc b/test/uitests/benchmarktest.cc
index b240388..33defc6 100644
--- a/test/uitests/benchmarktest.cc
+++ b/test/uitests/benchmarktest.cc
@@ -116,6 +116,34 @@ int main()
}
{
+ GUI::PixelBuffer wpixbuf(800, 600);
+ std::vector<GUI::PixelBufferAlpha*> children;
+ for(int i = 0; i < 100; ++i)
+ {
+ auto child = new GUI::PixelBufferAlpha(300, 300);
+ child->x = i * 2;
+ child->y = i * 2;
+ children.push_back(child);
+ }
+
+ TimedScope timed("Buffer flattening", 100);
+ for(int i = 0; i < 100; ++i)
+ {
+ for(auto child : children)
+ {
+ child->dirty = true;
+ }
+
+ wpixbuf.updateBuffer(children);
+ }
+
+ for(auto child : children)
+ {
+ delete child;
+ }
+ }
+
+ {
TimedScope timed("Scaled 1:1 no alpha", 1000);
for(int i = 0; i < 1000; ++i)
{