From 403ac27d2377df4fed8bf5039125f6d89aaa6955 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 2 Jan 2017 17:00:41 +0100 Subject: [PATCH] Abstract platform rendering to "surfaces" This will allow us to render more things than just the framebuffer. --- tests/CMakeLists.txt | 10 +- tests/fbperf.cxx | 94 +++++-- vncviewer/CMakeLists.txt | 8 +- vncviewer/OSXPixelBuffer.cxx | 114 --------- vncviewer/PlatformPixelBuffer.cxx | 166 ++++++++++++- vncviewer/PlatformPixelBuffer.h | 29 ++- vncviewer/{Win32PixelBuffer.h => Surface.cxx} | 35 +-- vncviewer/{OSXPixelBuffer.h => Surface.h} | 49 +++- vncviewer/Surface_OSX.cxx | 162 +++++++++++++ vncviewer/Surface_Win32.cxx | 146 +++++++++++ vncviewer/Surface_X11.cxx | 139 +++++++++++ vncviewer/Viewport.cxx | 36 +-- vncviewer/Viewport.h | 2 - vncviewer/Win32PixelBuffer.cxx | 93 ------- vncviewer/X11PixelBuffer.cxx | 229 ------------------ vncviewer/X11PixelBuffer.h | 47 ---- 16 files changed, 774 insertions(+), 585 deletions(-) delete mode 100644 vncviewer/OSXPixelBuffer.cxx rename vncviewer/{Win32PixelBuffer.h => Surface.cxx} (64%) rename vncviewer/{OSXPixelBuffer.h => Surface.h} (51%) create mode 100644 vncviewer/Surface_OSX.cxx create mode 100644 vncviewer/Surface_Win32.cxx create mode 100644 vncviewer/Surface_X11.cxx delete mode 100644 vncviewer/Win32PixelBuffer.cxx delete mode 100644 vncviewer/X11PixelBuffer.cxx delete mode 100644 vncviewer/X11PixelBuffer.h diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7c994539..5fbaa11a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,14 +22,14 @@ target_link_libraries(hostport rfb) set(FBPERF_SOURCES fbperf.cxx - ../vncviewer/FLTKPixelBuffer.cxx - ../vncviewer/PlatformPixelBuffer.cxx) + ../vncviewer/PlatformPixelBuffer.cxx + ../vncviewer/Surface.cxx) if(WIN32) - set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/Win32PixelBuffer.cxx) + set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/Surface_Win32.cxx) elseif(APPLE) - set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/OSXPixelBuffer.cxx) + set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/Surface_OSX.cxx) else() - set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/X11PixelBuffer.cxx) + set(FBPERF_SOURCES ${FBPERF_SOURCES} ../vncviewer/Surface_X11.cxx) endif() add_executable(fbperf ${FBPERF_SOURCES}) target_link_libraries(fbperf test_util rfb ${FLTK_LIBRARIES} ${GETTEXT_LIBRARIES}) diff --git a/tests/fbperf.cxx b/tests/fbperf.cxx index 5c37b0f7..8c71d966 100644 --- a/tests/fbperf.cxx +++ b/tests/fbperf.cxx @@ -27,15 +27,6 @@ #include #include "../vncviewer/PlatformPixelBuffer.h" -#include "../vncviewer/FLTKPixelBuffer.h" - -#if defined(WIN32) -#include "../vncviewer/Win32PixelBuffer.h" -#elif defined(__APPLE__) -#include "../vncviewer/OSXPixelBuffer.h" -#else -#include "../vncviewer/X11PixelBuffer.h" -#endif #include "util.h" @@ -70,6 +61,19 @@ protected: virtual void changefb(); }; +class OverlayTestWindow: public PartialTestWindow { +public: + OverlayTestWindow(); + + virtual void start(int width, int height); + virtual void stop(); + + virtual void draw(); + +protected: + Surface* overlay; +}; + TestWindow::TestWindow() : Fl_Window(0, 0, "Framebuffer Performance Test"), fb(NULL) @@ -93,17 +97,7 @@ void TestWindow::start(int width, int height) frames = 0; time = 0; - try { -#if defined(WIN32) - fb = new Win32PixelBuffer(w(), h()); -#elif defined(__APPLE__) - fb = new OSXPixelBuffer(w(), h()); -#else - fb = new X11PixelBuffer(w(), h()); -#endif - } catch (rdr::Exception& e) { - fb = new FLTKPixelBuffer(w(), h()); - } + fb = new PlatformPixelBuffer(w(), h()); pixel = 0; fb->fillRect(fb->getRect(), &pixel); @@ -207,6 +201,60 @@ void PartialTestWindow::changefb() fb->fillRect(r, &pixel); } +OverlayTestWindow::OverlayTestWindow() : + overlay(NULL) +{ +} + +void OverlayTestWindow::start(int width, int height) +{ + PartialTestWindow::start(width, height); + + overlay = new Surface(400, 200); + overlay->clear(0xff, 0x80, 0x00, 0xcc); +} + +void OverlayTestWindow::stop() +{ + PartialTestWindow::stop(); + + delete overlay; + overlay = NULL; +} + +void OverlayTestWindow::draw() +{ + int ox, oy, ow, oh; + int X, Y, W, H; + + // Check what actually needs updating + fl_clip_box(0, 0, w(), h(), X, Y, W, H); + if ((W == 0) || (H == 0)) + return; + + PartialTestWindow::draw(); + + // We might get a redraw before we are fully ready + if (!overlay) + return; + + // Simplify the clip region to a simple rectangle in order to + // properly draw all the layers even if they only partially overlap + fl_push_no_clip(); + fl_push_clip(X, Y, W, H); + + ox = (w() - overlay->width()) / 2; + oy = h() / 4 - overlay->height() / 2; + ow = overlay->width(); + oh = overlay->height(); + fl_clip_box(ox, oy, ow, oh, X, Y, W, H); + if ((W != 0) && (H != 0)) + overlay->draw(X - ox, Y - oy, X, Y, W, H); + + fl_pop_clip(); + fl_pop_clip(); +} + static void dosubtest(TestWindow* win, int width, int height, unsigned long long* pixels, unsigned long long* frames, @@ -311,5 +359,11 @@ int main(int argc, char** argv) delete win; fprintf(stderr, "\n"); + fprintf(stderr, "Partial window update with overlay:\n\n"); + win = new OverlayTestWindow(); + dotest(win); + delete win; + fprintf(stderr, "\n"); + return 0; } diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt index f11bae3f..d6a1b585 100644 --- a/vncviewer/CMakeLists.txt +++ b/vncviewer/CMakeLists.txt @@ -6,9 +6,9 @@ set(VNCVIEWER_SOURCES menukey.cxx CConn.cxx DesktopWindow.cxx - FLTKPixelBuffer.cxx UserDialog.cxx ServerDialog.cxx + Surface.cxx OptionsDialog.cxx PlatformPixelBuffer.cxx Viewport.cxx @@ -33,11 +33,11 @@ elseif(APPLE) endif() if(WIN32) - set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} Win32PixelBuffer.cxx) + set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} Surface_Win32.cxx) elseif(APPLE) - set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} OSXPixelBuffer.cxx) + set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} Surface_OSX.cxx) else() - set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} X11PixelBuffer.cxx) + set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} Surface_X11.cxx) endif() if(WIN32 AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/vncviewer/OSXPixelBuffer.cxx b/vncviewer/OSXPixelBuffer.cxx deleted file mode 100644 index 5c9611cd..00000000 --- a/vncviewer/OSXPixelBuffer.cxx +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright 2011-2014 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include -#include - -#include "i18n.h" -#include "OSXPixelBuffer.h" - -using namespace rfb; - -static rfb::LogWriter vlog("OSXPixelBuffer"); - -OSXPixelBuffer::OSXPixelBuffer(int width, int height) : - PlatformPixelBuffer(rfb::PixelFormat(32, 24, false, true, - 255, 255, 255, 16, 8, 0), - width, height, NULL, width), - image(NULL) -{ - CGColorSpaceRef lut; - CGDataProviderRef provider; - - data = new rdr::U8[width * height * format.bpp/8]; - if (data == NULL) - throw rfb::Exception(_("Not enough memory for framebuffer")); - - lut = CGDisplayCopyColorSpace(kCGDirectMainDisplay); - if (!lut) { - vlog.error(_("Could not get screen color space. Using slower fallback.")); - lut = CGColorSpaceCreateDeviceRGB(); - if (!lut) - throw rfb::Exception("CGColorSpaceCreateDeviceRGB"); - } - - provider = CGDataProviderCreateWithData(NULL, data, - width * height * 4, NULL); - if (!provider) - throw rfb::Exception("CGDataProviderCreateWithData"); - - image = CGImageCreate(width, height, 8, 32, width * 4, lut, - kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, - provider, NULL, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(lut); - CGDataProviderRelease(provider); - if (!image) - throw rfb::Exception("CGImageCreate"); -} - - -OSXPixelBuffer::~OSXPixelBuffer() -{ - CGImageRelease(image); - delete [] data; -} - - -void OSXPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) -{ - CGContextRef gc; - CGRect rect; - - gc = fl_gc; - - CGContextSaveGState(gc); - - // macOS Coordinates are from bottom left, not top left - src_y = height() - (src_y + h); - y = Fl_Window::current()->h() - (y + h); - - // Reset the transformation matrix back to the default identity - // matrix as otherwise we get a massive performance hit - CGContextConcatCTM(gc, CGAffineTransformInvert(CGContextGetCTM(gc))); - - // We have to use clipping to partially display an image - rect.origin.x = x; - rect.origin.y = y; - rect.size.width = w; - rect.size.height = h; - - CGContextClipToRect(gc, rect); - - rect.origin.x = x - src_x; - rect.origin.y = y - src_y; - rect.size.width = width(); - rect.size.height = height(); - - CGContextDrawImage(gc, rect, image); - - CGContextRestoreGState(gc); -} diff --git a/vncviewer/PlatformPixelBuffer.cxx b/vncviewer/PlatformPixelBuffer.cxx index 522bad3f..4802ba46 100644 --- a/vncviewer/PlatformPixelBuffer.cxx +++ b/vncviewer/PlatformPixelBuffer.cxx @@ -1,4 +1,4 @@ -/* Copyright 2011-2014 Pierre Ossman for Cendio AB +/* Copyright 2011-2016 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,13 +16,70 @@ * USA. */ +#include + +#if !defined(WIN32) && !defined(__APPLE__) +#include +#include +#endif + +#include +#include + +#include +#include + #include "PlatformPixelBuffer.h" -PlatformPixelBuffer::PlatformPixelBuffer(const rfb::PixelFormat& pf, - int width, int height, - rdr::U8* data, int stride) : - FullFramePixelBuffer(pf, width, height, data, stride) +static rfb::LogWriter vlog("PlatformPixelBuffer"); + +PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : + FullFramePixelBuffer(rfb::PixelFormat(32, 24, false, true, + 255, 255, 255, 16, 8, 0), + width, height, 0, stride), + Surface(width, height) +#if !defined(WIN32) && !defined(__APPLE__) + , shminfo(NULL), xim(NULL) +#endif { +#if !defined(WIN32) && !defined(__APPLE__) + if (!setupShm()) { + xim = XCreateImage(fl_display, CopyFromParent, 32, + ZPixmap, 0, 0, width, height, 32, 0); + if (!xim) + throw rdr::Exception("XCreateImage"); + + xim->data = (char*)malloc(xim->bytes_per_line * xim->height); + if (!xim->data) + throw rdr::Exception("malloc"); + + vlog.debug("Using standard XImage"); + } + + data = (rdr::U8*)xim->data; + stride = xim->bytes_per_line / (getPF().bpp/8); +#else + FullFramePixelBuffer::data = (rdr::U8*)Surface::data; + stride = width; +#endif +} + +PlatformPixelBuffer::~PlatformPixelBuffer() +{ +#if !defined(WIN32) && !defined(__APPLE__) + if (shminfo) { + vlog.debug("Freeing shared memory XImage"); + shmdt(shminfo->shmaddr); + shmctl(shminfo->shmid, IPC_RMID, 0); + delete shminfo; + shminfo = NULL; + } + + // XDestroyImage() will free(xim->data) if appropriate + if (xim) + XDestroyImage(xim); + xim = NULL; +#endif } void PlatformPixelBuffer::commitBufferRW(const rfb::Rect& r) @@ -42,5 +99,104 @@ rfb::Rect PlatformPixelBuffer::getDamage(void) damage.clear(); mutex.unlock(); +#if !defined(WIN32) && !defined(__APPLE__) + GC gc; + + gc = XCreateGC(fl_display, pixmap, 0, NULL); + if (shminfo) { + XShmPutImage(fl_display, pixmap, gc, xim, + r.tl.x, r.tl.y, r.tl.x, r.tl.y, + r.width(), r.height(), False); + // Need to make sure the X server has finished reading the + // shared memory before we return + XSync(fl_display, False); + } else { + XPutImage(fl_display, pixmap, gc, xim, + r.tl.x, r.tl.y, r.tl.x, r.tl.y, r.width(), r.height()); + } + XFreeGC(fl_display, gc); +#endif + return r; } + +#if !defined(WIN32) && !defined(__APPLE__) + +static bool caughtError; + +static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error) +{ + caughtError = true; + return 0; +} + +bool PlatformPixelBuffer::setupShm() +{ + int major, minor; + Bool pixmaps; + XErrorHandler old_handler; + const char *display_name = XDisplayName (NULL); + + /* Don't use MIT-SHM on remote displays */ + if (*display_name && *display_name != ':') + return false; + + if (!XShmQueryVersion(fl_display, &major, &minor, &pixmaps)) + return false; + + shminfo = new XShmSegmentInfo; + + xim = XShmCreateImage(fl_display, CopyFromParent, 32, + ZPixmap, 0, shminfo, width(), height()); + if (!xim) + goto free_shminfo; + + shminfo->shmid = shmget(IPC_PRIVATE, + xim->bytes_per_line * xim->height, + IPC_CREAT|0777); + if (shminfo->shmid == -1) + goto free_xim; + + shminfo->shmaddr = xim->data = (char*)shmat(shminfo->shmid, 0, 0); + shmctl(shminfo->shmid, IPC_RMID, 0); // to avoid memory leakage + if (shminfo->shmaddr == (char *)-1) + goto free_xim; + + shminfo->readOnly = True; + + // This is the only way we can detect that shared memory won't work + // (e.g. because we're accessing a remote X11 server) + caughtError = false; + old_handler = XSetErrorHandler(XShmAttachErrorHandler); + + if (!XShmAttach(fl_display, shminfo)) { + XSetErrorHandler(old_handler); + goto free_shmaddr; + } + + XSync(fl_display, False); + + XSetErrorHandler(old_handler); + + if (caughtError) + goto free_shmaddr; + + vlog.debug("Using shared memory XImage"); + + return true; + +free_shmaddr: + shmdt(shminfo->shmaddr); + +free_xim: + XDestroyImage(xim); + xim = NULL; + +free_shminfo: + delete shminfo; + shminfo = NULL; + + return 0; +} + +#endif diff --git a/vncviewer/PlatformPixelBuffer.h b/vncviewer/PlatformPixelBuffer.h index 795273a9..26ae7ca3 100644 --- a/vncviewer/PlatformPixelBuffer.h +++ b/vncviewer/PlatformPixelBuffer.h @@ -1,4 +1,4 @@ -/* Copyright 2011-2014 Pierre Ossman for Cendio AB +/* Copyright 2011-2016 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,24 +19,43 @@ #ifndef __PLATFORMPIXELBUFFER_H__ #define __PLATFORMPIXELBUFFER_H__ +#if !defined(WIN32) && !defined(__APPLE__) +#include +#endif + +#include + #include #include #include -class PlatformPixelBuffer: public rfb::FullFramePixelBuffer { +#include "Surface.h" + +class PlatformPixelBuffer: public rfb::FullFramePixelBuffer, public Surface { public: - PlatformPixelBuffer(const rfb::PixelFormat& pf, int width, int height, - rdr::U8* data, int stride); + PlatformPixelBuffer(int width, int height); + ~PlatformPixelBuffer(); virtual void commitBufferRW(const rfb::Rect& r); - virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0; rfb::Rect getDamage(void); + using rfb::FullFramePixelBuffer::width; + using rfb::FullFramePixelBuffer::height; + protected: os::Mutex mutex; rfb::Region damage; + +#if !defined(WIN32) && !defined(__APPLE__) +protected: + bool setupShm(); + +protected: + XShmSegmentInfo *shminfo; + XImage *xim; +#endif }; #endif diff --git a/vncviewer/Win32PixelBuffer.h b/vncviewer/Surface.cxx similarity index 64% rename from vncviewer/Win32PixelBuffer.h rename to vncviewer/Surface.cxx index 728e5948..fbd41437 100644 --- a/vncviewer/Win32PixelBuffer.h +++ b/vncviewer/Surface.cxx @@ -1,4 +1,4 @@ -/* Copyright 2011-2014 Pierre Ossman for Cendio AB +/* Copyright 2016 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,23 +16,24 @@ * USA. */ -#ifndef __WIN32PIXELBUFFER_H__ -#define __WIN32PIXELBUFFER_H__ +#include -#include +#include "Surface.h" -#include "PlatformPixelBuffer.h" +Surface::Surface(int width, int height) : + w(width), h(height) +{ + alloc(); +} -class Win32PixelBuffer: public PlatformPixelBuffer { -public: - Win32PixelBuffer(int width, int height); - ~Win32PixelBuffer(); +Surface::Surface(const Fl_RGB_Image* image) : + w(image->w()), h(image->h()) +{ + alloc(); + update(image); +} - virtual void draw(int src_x, int src_y, int x, int y, int w, int h); - -protected: - HBITMAP bitmap; -}; - - -#endif +Surface::~Surface() +{ + dealloc(); +} diff --git a/vncviewer/OSXPixelBuffer.h b/vncviewer/Surface.h similarity index 51% rename from vncviewer/OSXPixelBuffer.h rename to vncviewer/Surface.h index 958b1eae..02917e31 100644 --- a/vncviewer/OSXPixelBuffer.h +++ b/vncviewer/Surface.h @@ -1,4 +1,4 @@ -/* Copyright 2011-2014 Pierre Ossman for Cendio AB +/* Copyright 2016 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,24 +16,53 @@ * USA. */ -#ifndef __OSXPIXELBUFFER_H__ -#define __OSXPIXELBUFFER_H__ - -#include "PlatformPixelBuffer.h" +#ifndef __SURFACE_H__ +#define __SURFACE_H__ +#if defined(WIN32) +#include +#elif defined(__APPLE__) // Apple headers conflict with FLTK, so redefine types here typedef struct CGImage* CGImageRef; +#else +#include +#endif + +class Fl_RGB_Image; -class OSXPixelBuffer: public PlatformPixelBuffer { +class Surface { public: - OSXPixelBuffer(int width, int height); - ~OSXPixelBuffer(); + Surface(int width, int height); + Surface(const Fl_RGB_Image* image); + ~Surface(); - virtual void draw(int src_x, int src_y, int x, int y, int w, int h); + int width() { return w; } + int height() { return h; } + + void clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a=255); + + void draw(int src_x, int src_y, int x, int y, int w, int h); protected: + void alloc(); + void dealloc(); + void update(const Fl_RGB_Image* image); + +protected: + int w, h; + +#if defined(WIN32) + RGBQUAD* data; + HBITMAP bitmap; +#elif defined(__APPLE__) + unsigned char* data; CGImageRef image; +#else + Pixmap pixmap; + Picture picture; + XRenderPictFormat* visFormat; +#endif }; - #endif + diff --git a/vncviewer/Surface_OSX.cxx b/vncviewer/Surface_OSX.cxx new file mode 100644 index 00000000..c51e47f5 --- /dev/null +++ b/vncviewer/Surface_OSX.cxx @@ -0,0 +1,162 @@ +/* Copyright 2016 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include + +#include + +#include +#include +#include + +#include + +#include "Surface.h" + +void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + unsigned char* out; + int x, y; + + r = (unsigned)r * a / 255; + g = (unsigned)g * a / 255; + b = (unsigned)b * a / 255; + + out = data; + for (y = 0;y < width();y++) { + for (x = 0;x < height();x++) { + *out++ = b; + *out++ = g; + *out++ = r; + *out++ = a; + } + } +} + +void Surface::draw(int src_x, int src_y, int x, int y, int w, int h) +{ + CGRect rect; + + CGContextSaveGState(fl_gc); + + // Reset the transformation matrix back to the default identity + // matrix as otherwise we get a massive performance hit + CGContextConcatCTM(fl_gc, CGAffineTransformInvert(CGContextGetCTM(fl_gc))); + + // macOS Coordinates are from bottom left, not top left + src_y = height() - (src_y + h); + y = Fl_Window::current()->h() - (y + h); + + // We have to use clipping to partially display an image + rect.origin.x = x; + rect.origin.y = y; + rect.size.width = w; + rect.size.height = h; + + CGContextClipToRect(fl_gc, rect); + + rect.origin.x = x - src_x; + rect.origin.y = y - src_y; + rect.size.width = width(); + rect.size.height = height(); + + CGContextDrawImage(fl_gc, rect, image); + + CGContextRestoreGState(fl_gc); +} + +void Surface::alloc() +{ + CGColorSpaceRef lut; + CGDataProviderRef provider; + + data = new unsigned char[width() * height() * 4]; + + lut = CGDisplayCopyColorSpace(kCGDirectMainDisplay); + if (!lut) { + lut = CGColorSpaceCreateDeviceRGB(); + if (!lut) + throw rdr::Exception("CGColorSpaceCreateDeviceRGB"); + } + + provider = CGDataProviderCreateWithData(NULL, data, + width() * height() * 4, NULL); + if (!provider) + throw rdr::Exception("CGDataProviderCreateWithData"); + + image = CGImageCreate(width(), height(), 8, 32, width() * 4, lut, + kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, + provider, NULL, false, kCGRenderingIntentDefault); + CGColorSpaceRelease(lut); + CGDataProviderRelease(provider); + if (!image) + throw rdr::Exception("CGImageCreate"); +} + +void Surface::dealloc() +{ + CGImageRelease(image); + delete [] data; +} + +void Surface::update(const Fl_RGB_Image* image) +{ + int x, y; + const unsigned char* in; + unsigned char* out; + + assert(image->w() == width()); + assert(image->h() == height()); + + // Convert data and pre-multiply alpha + in = (const unsigned char*)image->data()[0]; + out = data; + for (y = 0;y < image->h();y++) { + for (x = 0;x < image->w();x++) { + switch (image->d()) { + case 1: + *out++ = in[0]; + *out++ = in[0]; + *out++ = in[0]; + *out++ = 0xff; + break; + case 2: + *out++ = (unsigned)in[0] * in[1] / 255; + *out++ = (unsigned)in[0] * in[1] / 255; + *out++ = (unsigned)in[0] * in[1] / 255; + *out++ = in[1]; + break; + case 3: + *out++ = in[2]; + *out++ = in[1]; + *out++ = in[0]; + *out++ = 0xff; + break; + case 4: + *out++ = (unsigned)in[2] * in[3] / 255; + *out++ = (unsigned)in[1] * in[3] / 255; + *out++ = (unsigned)in[0] * in[3] / 255; + *out++ = in[3]; + break; + } + in += image->d(); + } + if (image->ld() != 0) + in += image->ld() - image->w() * image->d(); + } +} diff --git a/vncviewer/Surface_Win32.cxx b/vncviewer/Surface_Win32.cxx new file mode 100644 index 00000000..5a9a6546 --- /dev/null +++ b/vncviewer/Surface_Win32.cxx @@ -0,0 +1,146 @@ +/* Copyright 2016 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include + +#include +#include + +#include + +#include "Surface.h" + +void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + RGBQUAD* out; + int x, y; + + r = (unsigned)r * a / 255; + g = (unsigned)g * a / 255; + b = (unsigned)b * a / 255; + + out = data; + for (y = 0;y < width();y++) { + for (x = 0;x < height();x++) { + out->rgbRed = r; + out->rgbGreen = g; + out->rgbBlue = b; + out->rgbReserved = a; + out++; + } + } +} + +void Surface::draw(int src_x, int src_y, int x, int y, int w, int h) +{ + HDC dc; + + dc = CreateCompatibleDC(fl_gc); + if (!dc) + throw rdr::SystemException("CreateCompatibleDC", GetLastError()); + + if (!SelectObject(dc, bitmap)) + throw rdr::SystemException("SelectObject", GetLastError()); + + if (!BitBlt(fl_gc, x, y, w, h, dc, src_x, src_y, SRCCOPY)) { + // If the desktop we're rendering to is inactive (like when the screen + // is locked or the UAC is active), then GDI calls will randomly fail. + // This is completely undocumented so we have no idea how best to deal + // with it. For now, we've only seen this error and for this function + // so only ignore this combination. + if (GetLastError() != ERROR_INVALID_HANDLE) + throw rdr::SystemException("BitBlt", GetLastError()); + } + + DeleteDC(dc); +} + +void Surface::alloc() +{ + BITMAPINFOHEADER bih; + + data = new RGBQUAD[width() * height()]; + + memset(&bih, 0, sizeof(bih)); + + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biBitCount = 32; + bih.biPlanes = 1; + bih.biWidth = width(); + bih.biHeight = -height(); // Negative to get top-down + bih.biCompression = BI_RGB; + + bitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih, + DIB_RGB_COLORS, (void**)&data, NULL, 0); + if (!bitmap) + throw rdr::SystemException("CreateDIBSection", GetLastError()); +} + +void Surface::dealloc() +{ + DeleteObject(bitmap); +} + +void Surface::update(const Fl_RGB_Image* image) +{ + const unsigned char* in; + RGBQUAD* out; + int x, y; + + assert(image->w() == width()); + assert(image->h() == height()); + + // Convert data and pre-multiply alpha + in = (const unsigned char*)image->data()[0]; + out = data; + for (y = 0;y < image->w();y++) { + for (x = 0;x < image->h();x++) { + switch (image->d()) { + case 1: + out->rgbBlue = in[0]; + out->rgbGreen = in[0]; + out->rgbRed = in[0]; + out->rgbReserved = 0xff; + break; + case 2: + out->rgbBlue = (unsigned)in[0] * in[1] / 255; + out->rgbGreen = (unsigned)in[0] * in[1] / 255; + out->rgbRed = (unsigned)in[0] * in[1] / 255; + out->rgbReserved = in[1]; + break; + case 3: + out->rgbBlue = in[2]; + out->rgbGreen = in[1]; + out->rgbRed = in[0]; + out->rgbReserved = 0xff; + break; + case 4: + out->rgbBlue = (unsigned)in[2] * in[3] / 255; + out->rgbGreen = (unsigned)in[1] * in[3] / 255; + out->rgbRed = (unsigned)in[0] * in[3] / 255; + out->rgbReserved = in[3]; + break; + } + in += image->d(); + out++; + } + if (image->ld() != 0) + in += image->ld() - image->w() * image->d(); + } +} + diff --git a/vncviewer/Surface_X11.cxx b/vncviewer/Surface_X11.cxx new file mode 100644 index 00000000..c7e3778e --- /dev/null +++ b/vncviewer/Surface_X11.cxx @@ -0,0 +1,139 @@ +/* Copyright 2016 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include + +#include +#include + +#include + +#include "Surface.h" + +void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + XRenderColor color; + + color.red = (unsigned)r * 65535 / 255 * a / 255; + color.green = (unsigned)g * 65535 / 255 * a / 255; + color.blue = (unsigned)b * 65535 / 255 * a / 255; + color.alpha = (unsigned)a * 65535 / 255; + + XRenderFillRectangle(fl_display, PictOpSrc, picture, &color, + 0, 0, width(), height()); +} + +void Surface::draw(int src_x, int src_y, int x, int y, int w, int h) +{ + Picture winPict; + + winPict = XRenderCreatePicture(fl_display, fl_window, visFormat, 0, NULL); + XRenderComposite(fl_display, PictOpSrc, picture, None, winPict, + src_x, src_y, 0, 0, x, y, w, h); + XRenderFreePicture(fl_display, winPict); +} + +void Surface::alloc() +{ + XRenderPictFormat* format; + + // Might not be open at this point + fl_open_display(); + + pixmap = XCreatePixmap(fl_display, XDefaultRootWindow(fl_display), + width(), height(), 32); + + format = XRenderFindStandardFormat(fl_display, PictStandardARGB32); + picture = XRenderCreatePicture(fl_display, pixmap, format, 0, NULL); + + visFormat = XRenderFindVisualFormat(fl_display, fl_visual->visual); +} + +void Surface::dealloc() +{ + XRenderFreePicture(fl_display, picture); + XFreePixmap(fl_display, pixmap); +} + +void Surface::update(const Fl_RGB_Image* image) +{ + XImage* img; + GC gc; + + int x, y; + const unsigned char* in; + unsigned char* out; + + assert(image->w() == width()); + assert(image->h() == height()); + + img = XCreateImage(fl_display, CopyFromParent, 32, + ZPixmap, 0, NULL, width(), height(), + 32, 0); + if (!img) + throw rdr::Exception("XCreateImage"); + + img->data = (char*)malloc(img->bytes_per_line * img->height); + if (!img->data) + throw rdr::Exception("malloc"); + + // Convert data and pre-multiply alpha + in = (const unsigned char*)image->data()[0]; + out = (unsigned char*)img->data; + for (y = 0;y < img->height;y++) { + for (x = 0;x < img->width;x++) { + switch (image->d()) { + case 1: + *out++ = in[0]; + *out++ = in[0]; + *out++ = in[0]; + *out++ = 0xff; + break; + case 2: + *out++ = (unsigned)in[0] * in[1] / 255; + *out++ = (unsigned)in[0] * in[1] / 255; + *out++ = (unsigned)in[0] * in[1] / 255; + *out++ = in[1]; + break; + case 3: + *out++ = in[2]; + *out++ = in[1]; + *out++ = in[0]; + *out++ = 0xff; + break; + case 4: + *out++ = (unsigned)in[2] * in[3] / 255; + *out++ = (unsigned)in[1] * in[3] / 255; + *out++ = (unsigned)in[0] * in[3] / 255; + *out++ = in[3]; + break; + } + in += image->d(); + } + if (image->ld() != 0) + in += image->ld() - image->w() * image->d(); + } + + gc = XCreateGC(fl_display, pixmap, 0, NULL); + XPutImage(fl_display, pixmap, gc, img, + 0, 0, 0, 0, img->width, img->height); + XFreeGC(fl_display, gc); + + XDestroyImage(img); +} + diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 1e4ee1aa..7b3487c4 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -62,15 +62,6 @@ #include "vncviewer.h" #include "PlatformPixelBuffer.h" -#include "FLTKPixelBuffer.h" - -#if defined(WIN32) -#include "Win32PixelBuffer.h" -#elif defined(__APPLE__) -#include "OSXPixelBuffer.h" -#else -#include "X11PixelBuffer.h" -#endif #include #include @@ -111,7 +102,7 @@ Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) // We need to intercept keyboard events early Fl::add_system_handler(handleSystemEvent, this); - frameBuffer = createFramebuffer(w, h); + frameBuffer = new PlatformPixelBuffer(w, h); assert(frameBuffer); cc->setFramebuffer(frameBuffer); @@ -272,7 +263,7 @@ void Viewport::resize(int x, int y, int w, int h) vlog.debug("Resizing framebuffer from %dx%d to %dx%d", frameBuffer->width(), frameBuffer->height(), w, h); - frameBuffer = createFramebuffer(w, h); + frameBuffer = new PlatformPixelBuffer(w, h); assert(frameBuffer); cc->setFramebuffer(frameBuffer); } @@ -374,29 +365,6 @@ int Viewport::handle(int event) return Fl_Widget::handle(event); } - -PlatformPixelBuffer* Viewport::createFramebuffer(int w, int h) -{ - PlatformPixelBuffer *fb; - - try { -#if defined(WIN32) - fb = new Win32PixelBuffer(w, h); -#elif defined(__APPLE__) - fb = new OSXPixelBuffer(w, h); -#else - fb = new X11PixelBuffer(w, h); -#endif - } catch (rdr::Exception& e) { - vlog.error(_("Unable to create platform specific framebuffer: %s"), e.str()); - vlog.error(_("Using platform independent framebuffer")); - fb = new FLTKPixelBuffer(w, h); - } - - return fb; -} - - void Viewport::handleClipboardChange(int source, void *data) { Viewport *self = (Viewport *)data; diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index b50c8157..ac1ec338 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -56,8 +56,6 @@ public: private: - PlatformPixelBuffer* createFramebuffer(int w, int h); - static void handleClipboardChange(int source, void *data); void handlePointerEvent(const rfb::Point& pos, int buttonMask); diff --git a/vncviewer/Win32PixelBuffer.cxx b/vncviewer/Win32PixelBuffer.cxx deleted file mode 100644 index 002d4c82..00000000 --- a/vncviewer/Win32PixelBuffer.cxx +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011-2014 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include - -#include -#include - -#include "i18n.h" -#include "Win32PixelBuffer.h" - -using namespace rfb; - -static rfb::LogWriter vlog("Win32PixelBuffer"); - -Win32PixelBuffer::Win32PixelBuffer(int width, int height) : - PlatformPixelBuffer(rfb::PixelFormat(32, 24, false, true, - 255, 255, 255, 16, 8, 0), - width, height, NULL, width), - bitmap(NULL) -{ - BITMAPINFOHEADER bih; - - memset(&bih, 0, sizeof(bih)); - - bih.biSize = sizeof(BITMAPINFOHEADER); - bih.biBitCount = getPF().bpp; - bih.biSizeImage = (getPF().bpp / 8) * width * height; - bih.biPlanes = 1; - bih.biWidth = width; - bih.biHeight = -height; // Negative to get top-down - bih.biCompression = BI_RGB; - - bitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih, - DIB_RGB_COLORS, (void**)&data, NULL, 0); - if (!bitmap) - throw rdr::SystemException("CreateDIBSection", GetLastError()); -} - - -Win32PixelBuffer::~Win32PixelBuffer() -{ - DeleteObject(bitmap); -} - - -void Win32PixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) -{ - HDC dc; - - dc = CreateCompatibleDC(fl_gc); - if (!dc) - throw rdr::SystemException("CreateCompatibleDC", GetLastError()); - - if (!SelectObject(dc, bitmap)) - throw rdr::SystemException("SelectObject", GetLastError()); - - if (!BitBlt(fl_gc, x, y, w, h, dc, src_x, src_y, SRCCOPY)) { - // If the desktop we're rendering to is inactive (like when the screen - // is locked or the UAC is active), then GDI calls will randomly fail. - // This is completely undocumented so we have no idea how best to deal - // with it. For now, we've only seen this error and for this function - // so only ignore this combination. - if (GetLastError() != ERROR_INVALID_HANDLE) - throw rdr::SystemException("BitBlt", GetLastError()); - } - - DeleteDC(dc); -} diff --git a/vncviewer/X11PixelBuffer.cxx b/vncviewer/X11PixelBuffer.cxx deleted file mode 100644 index e23f7771..00000000 --- a/vncviewer/X11PixelBuffer.cxx +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011-2014 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#include -#include - -#include "i18n.h" -#include "X11PixelBuffer.h" - -using namespace rfb; - -static rfb::LogWriter vlog("X11PixelBuffer"); - -static PixelFormat display_pf() -{ - int i; - - int bpp; - int trueColour, bigEndian; - int redShift, greenShift, blueShift; - int redMax, greenMax, blueMax; - - int nformats; - XPixmapFormatValues* format; - - // Might not be open at this point - fl_open_display(); - - format = XListPixmapFormats(fl_display, &nformats); - - for (i = 0; i < nformats; i++) - if (format[i].depth == fl_visual->depth) break; - - if (i == nformats) - // TRANSLATORS: "pixmap" is an X11 concept and may not be suitable - // to translate. - throw rfb::Exception(_("Display lacks pixmap format for default depth")); - - switch (format[i].bits_per_pixel) { - case 8: - case 16: - case 32: - bpp = format[i].bits_per_pixel; - break; - default: - // TRANSLATORS: "pixmap" is an X11 concept and may not be suitable - // to translate. - throw rfb::Exception(_("Couldn't find suitable pixmap format")); - } - - XFree(format); - - bigEndian = (ImageByteOrder(fl_display) == MSBFirst); - trueColour = (fl_visual->c_class == TrueColor); - - if (!trueColour) - throw rfb::Exception(_("Only true colour displays supported")); - - vlog.info(_("Using default colormap and visual, TrueColor, depth %d."), - fl_visual->depth); - - redShift = ffs(fl_visual->red_mask) - 1; - greenShift = ffs(fl_visual->green_mask) - 1; - blueShift = ffs(fl_visual->blue_mask) - 1; - redMax = fl_visual->red_mask >> redShift; - greenMax = fl_visual->green_mask >> greenShift; - blueMax = fl_visual->blue_mask >> blueShift; - - return PixelFormat(bpp, fl_visual->depth, bigEndian, trueColour, - redMax, greenMax, blueMax, - redShift, greenShift, blueShift); -} - -X11PixelBuffer::X11PixelBuffer(int width, int height) : - PlatformPixelBuffer(display_pf(), width, height, NULL, 0), - shminfo(NULL), xim(NULL) -{ - // Might not be open at this point - fl_open_display(); - - if (!setupShm()) { - xim = XCreateImage(fl_display, fl_visual->visual, fl_visual->depth, - ZPixmap, 0, 0, width, height, BitmapPad(fl_display), 0); - if (!xim) - throw rfb::Exception("XCreateImage"); - - xim->data = (char*)malloc(xim->bytes_per_line * xim->height); - if (!xim->data) - throw rfb::Exception(_("Not enough memory for framebuffer")); - - vlog.debug("Using standard XImage"); - } - - data = (rdr::U8*)xim->data; - stride = xim->bytes_per_line / (getPF().bpp/8); -} - - -X11PixelBuffer::~X11PixelBuffer() -{ - if (shminfo) { - vlog.debug("Freeing shared memory XImage"); - shmdt(shminfo->shmaddr); - shmctl(shminfo->shmid, IPC_RMID, 0); - delete shminfo; - shminfo = NULL; - } - - // XDestroyImage() will free(xim->data) if appropriate - if (xim) - XDestroyImage(xim); - xim = NULL; -} - - -void X11PixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) -{ - if (shminfo) { - XShmPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h, False); - // Need to make sure the X server has finished reading the - // shared memory before we return - XSync(fl_display, False); - } else { - XPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h); - } -} - -static bool caughtError; - -static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error) -{ - caughtError = true; - return 0; -} - -int X11PixelBuffer::setupShm() -{ - int major, minor; - Bool pixmaps; - XErrorHandler old_handler; - const char *display_name = XDisplayName (NULL); - - /* Don't use MIT-SHM on remote displays */ - if (*display_name && *display_name != ':') - return 0; - - if (!XShmQueryVersion(fl_display, &major, &minor, &pixmaps)) - return 0; - - shminfo = new XShmSegmentInfo; - - xim = XShmCreateImage(fl_display, fl_visual->visual, fl_visual->depth, - ZPixmap, 0, shminfo, width(), height()); - if (!xim) - goto free_shminfo; - - shminfo->shmid = shmget(IPC_PRIVATE, - xim->bytes_per_line * xim->height, - IPC_CREAT|0777); - if (shminfo->shmid == -1) - goto free_xim; - - shminfo->shmaddr = xim->data = (char*)shmat(shminfo->shmid, 0, 0); - shmctl(shminfo->shmid, IPC_RMID, 0); // to avoid memory leakage - if (shminfo->shmaddr == (char *)-1) - goto free_xim; - - shminfo->readOnly = True; - - // This is the only way we can detect that shared memory won't work - // (e.g. because we're accessing a remote X11 server) - caughtError = false; - old_handler = XSetErrorHandler(XShmAttachErrorHandler); - - if (!XShmAttach(fl_display, shminfo)) { - XSetErrorHandler(old_handler); - goto free_shmaddr; - } - - XSync(fl_display, False); - - XSetErrorHandler(old_handler); - - if (caughtError) - goto free_shmaddr; - - vlog.debug("Using shared memory XImage"); - - return 1; - -free_shmaddr: - shmdt(shminfo->shmaddr); - -free_xim: - XDestroyImage(xim); - xim = NULL; - -free_shminfo: - delete shminfo; - shminfo = NULL; - - return 0; -} diff --git a/vncviewer/X11PixelBuffer.h b/vncviewer/X11PixelBuffer.h deleted file mode 100644 index fdd88b75..00000000 --- a/vncviewer/X11PixelBuffer.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2011-2014 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __X11PIXELBUFFER_H__ -#define __X11PIXELBUFFER_H__ - -#include -#include -#include -#include - -#include - -#include "PlatformPixelBuffer.h" - -class X11PixelBuffer: public PlatformPixelBuffer { -public: - X11PixelBuffer(int width, int height); - ~X11PixelBuffer(); - - virtual void draw(int src_x, int src_y, int x, int y, int w, int h); - -protected: - int setupShm(); - -protected: - XShmSegmentInfo *shminfo; - XImage *xim; -}; - - -#endif -- 2.39.5