draw rect optimization

This commit is contained in:
Jorijn van der Graaf 2025-11-26 23:36:08 +01:00
commit 615d90c36f
3 changed files with 113 additions and 30 deletions

View file

@ -111,10 +111,27 @@ void Window::AddDirtyRect(ScaleData scale) {
return; return;
} }
//merging logic should work so that no pixel is drawn twice, and that no pixel not marked dirty is drawn. for(ClipRect existing : dirtyRects) {
//so lets say there is already an existing horizontal bar and the new rect is a vertical bar making a cross shape, the center of the cross will currently be drawn twice //fully enclosed
//so we need to turn it into 3 rects, the top part of the vertical bar, the horizontal bar, and the bottom part of the vertical bar if(rect.left >= existing.left && rect.right <= existing.right && rect.top >= existing.top && rect.bottom <= existing.bottom) {
//in this way no pixel is drawn twice and no area not marked dirty is included return;
}
//horizontal line
if(rect.top == existing.top && rect.bottom == existing.bottom) {
existing.left = std::min(rect.left, existing.left);
existing.right = std::max(rect.right, existing.right);
return;
}
//vertical line
if(rect.left == existing.left && rect.right == existing.right) {
existing.top = std::min(rect.top, existing.top);
existing.bottom = std::max(rect.bottom, existing.bottom);
return;
}
}
//no overlap
dirtyRects.push_back(rect); dirtyRects.push_back(rect);
} }

View file

@ -212,37 +212,104 @@ void WindowWayland::Render() {
elements.erase(std::remove(elements.begin(), elements.end(), static_cast<Transform*>(nullptr)), elements.end()); elements.erase(std::remove(elements.begin(), elements.end(), static_cast<Transform*>(nullptr)), elements.end());
std::sort(elements.begin(), elements.end(), [](Transform* a, Transform* b){ return a->z < b->z; }); std::sort(elements.begin(), elements.end(), [](Transform* a, Transform* b){ return a->z < b->z; });
for(uint_fast32_t i = 0; i < width*height; i++) { std::vector<ClipRect> newClip;
framebuffer[i] = {0, 0, 0, 255};
for (std::uint_fast32_t i = 0; i < dirtyRects.size(); i++) {
ClipRect rect = dirtyRects[i];
for (std::uint_fast32_t i2 = i + 1; i2 < dirtyRects.size(); i2++) {
ClipRect existing = dirtyRects[i2];
if(rect.bottom >= existing.top && rect.top <= existing.top) {
newClip.push_back({
.left = rect.left,
.right = rect.right,
.top = rect.top,
.bottom = existing.top,
});
//-| shape
if(rect.right > existing.right) {
newClip.push_back({
.left = existing.right,
.right = rect.right,
.top = existing.top,
.bottom = existing.bottom,
});
}
//|- shape
if(rect.left < existing.left) {
newClip.push_back({
.left = rect.left,
.right = existing.left,
.top = existing.top,
.bottom = existing.bottom,
});
}
//-| or |- shape where rect extends further down
if(rect.bottom > existing.bottom) {
newClip.push_back({
.left = rect.left,
.right = rect.right,
.top = existing.bottom,
.bottom = rect.bottom,
});
}
goto inner;
}
if (rect.left <= existing.right && rect.right >= existing.left) {
newClip.push_back({
.left = rect.left,
.right = existing.left,
.top = rect.top,
.bottom = rect.bottom,
});
if (rect.right > existing.right) {
newClip.push_back({
.left = existing.right,
.right = rect.right,
.top = rect.top,
.bottom = rect.bottom,
});
}
goto inner;
}
}
newClip.push_back(rect);
inner:;
}
dirtyRects = std::move(newClip);
// for(uint_fast32_t i = 0; i < width*height; i++) {
// framebuffer[i] = {0, 0, 0, 255};
// }
// std::cout << dirtyRects.size() << std::endl;
// for (ClipRect rect : dirtyRects) {
// //std::cout << std::format("{}, {}, {}, {}", rect.left, rect.top, rect.right, rect.bottom) << std::endl;
// for (std::int_fast32_t y = rect.top; y < rect.bottom; y++) {
// for (std::int_fast32_t x = rect.left; x < rect.right; x++) {
// framebuffer[y * width + x].r += 30;
// }
// }
// }
if (!dirtyRects.empty()) {
for (ClipRect rect : dirtyRects) {
for (std::int_fast32_t y = rect.top; y < rect.bottom; y++) {
for (std::int_fast32_t x = rect.left; x < rect.right; x++) {
framebuffer[y * width + x] = {0, 0, 0, 0};
}
}
}
for(Transform* child : elements) {
RenderElement(child);
} }
for (ClipRect rect : dirtyRects) { for (ClipRect rect : dirtyRects) {
//std::cout << std::format("{}, {}, {}, {}", rect.left, rect.top, rect.right, rect.bottom) << std::endl; wl_surface_damage(surface, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top);
for (std::int_fast32_t y = rect.top; y < rect.bottom; y++) {
for (std::int_fast32_t x = rect.left; x < rect.right; x++) {
framebuffer[y * width + x].r += 30;
} }
dirtyRects.clear();
} }
}
// if (!dirtyRects.empty()) {
// for (ClipRect rect : dirtyRects) {
// for (std::int_fast32_t y = rect.top; y < rect.bottom; y++) {
// for (std::int_fast32_t x = rect.left; x < rect.right; x++) {
// framebuffer[y * width + x] = {0, 0, 0, 0};
// }
// }
// }
// for(Transform* child : elements) {
// RenderElement(child);
// }
// for (ClipRect rect : dirtyRects) {
// wl_surface_damage(surface, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top);
// }
// dirtyRects.clear();
// }
dirtyRects.clear(); dirtyRects.clear();
wl_surface_damage(surface, 0, 0, width, height); wl_surface_damage(surface, 0, 0, width, height);

View file

@ -56,9 +56,7 @@ export namespace Crafter {
Event<FrameTime> onUpdate; Event<FrameTime> onUpdate;
bool open = true; bool open = true;
bool updating = false; bool updating = false;
std::vector<ClipRect> dirtyRects; std::vector<ClipRect> dirtyRects;
void AddDirtyRect(ScaleData rect);
Window() = default; Window() = default;
Window(std::int_fast32_t width, std::int_fast32_t height); Window(std::int_fast32_t width, std::int_fast32_t height);
@ -66,6 +64,7 @@ export namespace Crafter {
Window(Window&&) = delete; Window(Window&&) = delete;
virtual ~Window() = default; virtual ~Window() = default;
Window& operator=(const Window&) = delete; Window& operator=(const Window&) = delete;
void AddDirtyRect(ScaleData rect);
virtual void StartSync() = 0; virtual void StartSync() = 0;
virtual void StartUpdate() = 0; virtual void StartUpdate() = 0;
virtual void StopUpdate() = 0; virtual void StopUpdate() = 0;