From 35730491ef90528be367b5c59261ec82984b50e0 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Fri, 17 Feb 2017 10:58:08 +0100 Subject: 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. --- plugingui/guievent.h | 7 ++++ plugingui/nativewindow.h | 4 ++- plugingui/nativewindow_win32.cc | 5 +-- plugingui/nativewindow_win32.h | 2 +- plugingui/nativewindow_x11.cc | 61 ++++++++++++++++--------------- plugingui/nativewindow_x11.h | 5 +-- plugingui/widget.cc | 1 + plugingui/window.cc | 79 +++++++++++++++++++++++++++++++++-------- 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>; +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 #include #include +#include +#include #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 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 + #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; -- cgit v1.2.3