summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2017-02-17 10:58:08 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2017-02-17 10:58:08 +0100
commit35730491ef90528be367b5c59261ec82984b50e0 (patch)
tree8318453dd40404ddcb02ff86e10403f8698c2a75
parent27942ce1947d3fcd18b67702f4565bb399441bb8 (diff)
Add partial rendering support when rendering widgets to window pixel buffer and also when rendering window pixel buffer to native window. Win32 only partially implemented.
-rw-r--r--plugingui/guievent.h7
-rw-r--r--plugingui/nativewindow.h4
-rw-r--r--plugingui/nativewindow_win32.cc5
-rw-r--r--plugingui/nativewindow_win32.h2
-rw-r--r--plugingui/nativewindow_x11.cc61
-rw-r--r--plugingui/nativewindow_x11.h5
-rw-r--r--plugingui/widget.cc1
-rw-r--r--plugingui/window.cc79
8 files changed, 115 insertions, 49 deletions
diff --git a/plugingui/guievent.h b/plugingui/guievent.h
index 2d4cc6f..11a7b9b 100644
--- a/plugingui/guievent.h
+++ b/plugingui/guievent.h
@@ -174,5 +174,12 @@ public:
using EventQueue = std::list<std::shared_ptr<Event>>;
+struct Rect
+{
+ std::size_t x1;
+ std::size_t y1;
+ std::size_t x2;
+ std::size_t y2;
+};
} // GUI::
diff --git a/plugingui/nativewindow.h b/plugingui/nativewindow.h
index 7b7fd39..c6ca7c8 100644
--- a/plugingui/nativewindow.h
+++ b/plugingui/nativewindow.h
@@ -29,6 +29,8 @@
#include <string>
#include <memory>
#include <queue>
+#include <tuple>
+#include <vector>
#include "guievent.h"
@@ -70,7 +72,7 @@ public:
virtual void setCaption(const std::string &caption) = 0;
//! Draw the internal rendering buffer to the window buffer.
- virtual void redraw() = 0;
+ virtual void redraw(const Rect& dirty_rect) = 0;
//! Toggle capture mouse mode.
virtual void grabMouse(bool grab) = 0;
diff --git a/plugingui/nativewindow_win32.cc b/plugingui/nativewindow_win32.cc
index 669ec13..dce14cc 100644
--- a/plugingui/nativewindow_win32.cc
+++ b/plugingui/nativewindow_win32.cc
@@ -384,12 +384,13 @@ void NativeWindowWin32::hide()
ShowWindow(m_hwnd, SW_HIDE);
}
-void NativeWindowWin32::redraw()
+void NativeWindowWin32::redraw(const Rect& dirty_rect)
{
// Send WM_PAINT message. Buffer transfering is handled in MessageHandler.
if(parent_window == nullptr)
{
- RedrawWindow(m_hwnd, nullptr, nullptr, RDW_ERASE|RDW_INVALIDATE);
+ RECT rect = {dirty_rect.x1, dirty_rect.y1, dirty_rect.x2, dirty_rect.y2 };
+ RedrawWindow(m_hwnd, &rect, nullptr, RDW_INVALIDATE);
UpdateWindow(m_hwnd);
}
else
diff --git a/plugingui/nativewindow_win32.h b/plugingui/nativewindow_win32.h
index 69324e3..630d853 100644
--- a/plugingui/nativewindow_win32.h
+++ b/plugingui/nativewindow_win32.h
@@ -52,7 +52,7 @@ public:
void show() override;
void setCaption(const std::string &caption) override;
void hide() override;
- void redraw() override;
+ void redraw(const Rect& dirty_rect) override;
void grabMouse(bool grab) override;
EventQueue getEvents() override;
diff --git a/plugingui/nativewindow_x11.cc b/plugingui/nativewindow_x11.cc
index 80c0e81..1482d47 100644
--- a/plugingui/nativewindow_x11.cc
+++ b/plugingui/nativewindow_x11.cc
@@ -223,18 +223,23 @@ void NativeWindowX11::hide()
XUnmapWindow(display, xwindow);
}
-void NativeWindowX11::redraw()
+void NativeWindowX11::redraw(const Rect& dirty_rect)
{
if(display == nullptr)
{
return;
}
- updateImageFromBuffer();
- XShmPutImage(display, xwindow, gc, image, 0, 0, 0, 0,
- std::min(image->width, (int)window.width()),
- std::min(image->height, (int)window.height()), false);
+ auto x1 = dirty_rect.x1;
+ auto y1 = dirty_rect.y1;
+ auto x2 = dirty_rect.x2;
+ auto y2 = dirty_rect.y2;
+ updateImageFromBuffer(x1, y1, x2, y2);
+
+ XShmPutImage(display, xwindow, gc, image, x1, y1, x1, y1,
+ std::min((std::size_t)image->width, (x2 - x1)),
+ std::min((std::size_t)image->height, (y2 - y1)), false);
XFlush(display);
}
@@ -510,7 +515,8 @@ void NativeWindowX11::deallocateShmImage()
shmdt(shm_info.shmaddr);
}
-void NativeWindowX11::updateImageFromBuffer()
+void NativeWindowX11::updateImageFromBuffer(std::size_t x1, std::size_t y1,
+ std::size_t x2, std::size_t y2)
{
//DEBUG(x11, "depth: %d", depth);
@@ -527,50 +533,47 @@ void NativeWindowX11::updateImageFromBuffer()
std::size_t new_width = ((width / step_size) + 1) * step_size;
std::size_t new_height = ((height / step_size) + 1) * step_size;
allocateShmImage(new_width, new_height);
+ x1 = 0;
+ y1 = 0;
+ x2 = width;
+ y2 = height;
}
auto stride = image->width;
std::uint8_t* pixel_buffer = (std::uint8_t*)window.wpixbuf.buf;
-
if(depth >= 24) // RGB 888 format
{
std::uint32_t* shm_addr = (std::uint32_t*)shm_info.shmaddr;
- std::size_t x_stride = 0;
- std::size_t x_pos = 0;
- for(std::size_t y = 0; y < height; ++y)
+ for(std::size_t y = y1; y < y2; ++y)
{
- for(std::size_t x = 0; x < width; ++x)
+ for(std::size_t x = x1; x < x2; ++x)
{
- const std::uint8_t red = pixel_buffer[x_pos * 3];
- const std::uint8_t green = pixel_buffer[x_pos * 3 + 1];
- const std::uint8_t blue = pixel_buffer[x_pos * 3 + 2];
- shm_addr[x_stride] = (red << 16) | (green << 8) | blue;
- ++x_pos;
- ++x_stride;
+ const std::size_t pin = y * width + x;
+ const std::size_t pout = y * stride + x;
+ const std::uint8_t red = pixel_buffer[pin * 3];
+ const std::uint8_t green = pixel_buffer[pin * 3 + 1];
+ const std::uint8_t blue = pixel_buffer[pin * 3 + 2];
+ shm_addr[pout] = (red << 16) | (green << 8) | blue;
}
- x_stride += (stride - width);
}
}
else if(depth >= 15) // RGB 565 format
{
std::uint16_t* shm_addr = (std::uint16_t*)shm_info.shmaddr;
- std::size_t x_stride = 0;
- std::size_t x_pos = 0;
- for(std::size_t y = 0; y < height; ++y)
+ for(std::size_t y = y1; y < y2; ++y)
{
- for(std::size_t x = 0; x < width; ++x)
+ for(std::size_t x = x1; x < x2; ++x)
{
- const std::uint8_t red = pixel_buffer[x_pos * 3];
- const std::uint8_t green = pixel_buffer[x_pos * 3 + 1];
- const std::uint8_t blue = pixel_buffer[x_pos * 3 + 2];
- shm_addr[x_stride] = (red << 11) | (green << 5) | blue;
- ++x_pos;
- ++x_stride;
+ const std::size_t pin = y * width + x;
+ const std::size_t pout = y * stride + x;
+ const std::uint8_t red = pixel_buffer[pin * 3];
+ const std::uint8_t green = pixel_buffer[pin * 3 + 1];
+ const std::uint8_t blue = pixel_buffer[pin * 3 + 2];
+ shm_addr[pout] = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
}
- x_stride += (stride - width);
}
}
}
diff --git a/plugingui/nativewindow_x11.h b/plugingui/nativewindow_x11.h
index f98f151..1604734 100644
--- a/plugingui/nativewindow_x11.h
+++ b/plugingui/nativewindow_x11.h
@@ -54,7 +54,7 @@ public:
void show() override;
void hide() override;
void setCaption(const std::string &caption) override;
- void redraw() override;
+ void redraw(const Rect& dirty_rect) override;
void grabMouse(bool grab) override;
EventQueue getEvents() override;
@@ -69,7 +69,8 @@ private:
void deallocateShmImage();
//! Copy data from the pixel buffer into the shared memory
- void updateImageFromBuffer();
+ void updateImageFromBuffer(std::size_t x1, std::size_t y1,
+ std::size_t x2, std::size_t y2);
XShmSegmentInfo shm_info;
XImage* image{nullptr};
diff --git a/plugingui/widget.cc b/plugingui/widget.cc
index 239c233..7d92a22 100644
--- a/plugingui/widget.cc
+++ b/plugingui/widget.cc
@@ -212,6 +212,7 @@ std::vector<PixelBufferAlpha*> Widget::getPixelBuffers()
if(dirty)
{
repaintEvent(nullptr);
+ pixbuf.dirty = true;
dirty = false;
}
diff --git a/plugingui/window.cc b/plugingui/window.cc
index 44c8e12..e2a5b58 100644
--- a/plugingui/window.cc
+++ b/plugingui/window.cc
@@ -26,6 +26,8 @@
*/
#include "window.h"
+#include <cstring>
+
#include "painter.h"
#ifndef PUGL
@@ -224,39 +226,88 @@ bool Window::updateBuffer()
return false;
}
- for(const auto& pixelBuffer : getPixelBuffers())
+ bool has_dirty_rect{false};
+ Rect dirty_rect;
+
+ auto pixel_buffers = getPixelBuffers();
+ for(auto& pixel_buffer : pixel_buffers)
{
- size_t updateWidth = pixelBuffer->width;
- size_t updateHeight = pixelBuffer->height;
+ 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
+ };
+ }
+ }
+ }
+
+ for(auto& pixel_buffer : pixel_buffers)
+ {
+ int update_width = pixel_buffer->width;
+ int update_height = pixel_buffer->height;
// Skip buffer if not inside window.
- if((wpixbuf.width < pixelBuffer->x) || (wpixbuf.height < pixelBuffer->y))
+ if(((int)wpixbuf.width < pixel_buffer->x) ||
+ ((int)wpixbuf.height < pixel_buffer->y))
{
continue;
}
- if(updateWidth > (wpixbuf.width - pixelBuffer->x))
+ if(update_width > ((int)wpixbuf.width - pixel_buffer->x))
{
- updateWidth = (wpixbuf.width - pixelBuffer->x);
+ update_width = ((int)wpixbuf.width - pixel_buffer->x);
}
- if(updateHeight > (wpixbuf.height - pixelBuffer->y))
+ if(update_height > ((int)wpixbuf.height - pixel_buffer->y))
{
- updateHeight = (wpixbuf.height - pixelBuffer->y);
+ update_height = ((int)wpixbuf.height - pixel_buffer->y);
}
- unsigned char r,g,b,a;
- for(size_t y = 0; y < updateHeight; y++)
+ std::uint8_t r, g, b, a;
+
+ 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);
+
+ for(int y = from_y; y < to_y; y++)
{
- for(size_t x = 0; x < updateWidth; x++)
+ for(int x = from_x; x < to_x; x++)
{
- pixelBuffer->pixel(x, y, &r, &g, &b, &a);
- wpixbuf.setPixel(x + pixelBuffer->x, y + pixelBuffer->y, r, g, b, a);
+ pixel_buffer->pixel(x, y, &r, &g, &b, &a);
+ wpixbuf.setPixel(x + pixel_buffer->x, y + pixel_buffer->y, r, g, b, a);
}
}
}
- native->redraw();
+ native->redraw(dirty_rect);
needs_redraw = false;
return true;