diff options
| author | Bent Bisballe Nyeng <deva@aasimon.org> | 2017-02-17 10:58:08 +0100 | 
|---|---|---|
| committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2017-02-17 10:58:08 +0100 | 
| commit | 35730491ef90528be367b5c59261ec82984b50e0 (patch) | |
| tree | 8318453dd40404ddcb02ff86e10403f8698c2a75 | |
| parent | 27942ce1947d3fcd18b67702f4565bb399441bb8 (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.h | 7 | ||||
| -rw-r--r-- | plugingui/nativewindow.h | 4 | ||||
| -rw-r--r-- | plugingui/nativewindow_win32.cc | 5 | ||||
| -rw-r--r-- | plugingui/nativewindow_win32.h | 2 | ||||
| -rw-r--r-- | plugingui/nativewindow_x11.cc | 61 | ||||
| -rw-r--r-- | plugingui/nativewindow_x11.h | 5 | ||||
| -rw-r--r-- | plugingui/widget.cc | 1 | ||||
| -rw-r--r-- | 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<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; | 
