From: Pierre Ossman Date: Mon, 13 Jun 2011 11:23:08 +0000 (+0000) Subject: Optimised drawing routines for X11, roughly based on how the old Unix viewer X-Git-Tag: v1.1.90~289 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=1350069127f4817cb34c2112acfc1a7abeea0d3d;p=tigervnc.git Optimised drawing routines for X11, roughly based on how the old Unix viewer did things. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4493 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt index 54c93444..faa1f755 100644 --- a/vncviewer/CMakeLists.txt +++ b/vncviewer/CMakeLists.txt @@ -21,6 +21,10 @@ if(APPLE) set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} cocoa.mm) endif() +if((NOT APPLE) AND (NOT WIN32)) + set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} X11PixelBuffer.cxx) +endif() + add_executable(vncviewer ${VNCVIEWER_SOURCES}) target_link_libraries(vncviewer rfb network rdr os Xregion ${FLTK_LIBRARIES} ${GETTEXT_LIBRARIES}) diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index f385a245..2613b6dd 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -38,7 +38,7 @@ #elif defined(__APPLE__) #include "PlatformPixelBuffer.h" #else -#include "PlatformPixelBuffer.h" +#include "X11PixelBuffer.h" #endif class CConn; diff --git a/vncviewer/X11PixelBuffer.cxx b/vncviewer/X11PixelBuffer.cxx new file mode 100644 index 00000000..79fa76a2 --- /dev/null +++ b/vncviewer/X11PixelBuffer.cxx @@ -0,0 +1,188 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2011 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 "X11PixelBuffer.h" + +using namespace rfb; + +static rfb::LogWriter vlog("PlatformPixelBuffer"); + +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) + throw rfb::Exception("Error: 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: + throw rfb::Exception("Error: couldn't find suitable pixmap format"); + } + + XFree(format); + + bigEndian = (ImageByteOrder(fl_display) == MSBFirst); + trueColour = (fl_visual->c_class == TrueColor); + + if (!trueColour) + throw rfb::Exception("Error: only true colour displays supported"); + + vlog.info("Using default colormap and visual, %sdepth %d.", + (fl_visual->c_class == TrueColor) ? "TrueColor, " : + ((fl_visual->c_class == PseudoColor) ? "PseudoColor, " : ""), + 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); +} + +PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : + FullFramePixelBuffer(display_pf(), width, height, NULL, NULL), + 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); + assert(xim); + + xim->data = (char*)malloc(xim->bytes_per_line * xim->height); + assert(xim->data); + } + + data = (rdr::U8*)xim->data; +} + + +PlatformPixelBuffer::~PlatformPixelBuffer() +{ + 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 PlatformPixelBuffer::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); + else + XPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h); +} + + +int PlatformPixelBuffer::getStride() const +{ + return xim->bytes_per_line / (getPF().bpp/8); +} + + +int PlatformPixelBuffer::setupShm() +{ + int major, minor; + Bool pixmaps; + + 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); + if (shminfo->shmaddr == (char *)-1) + goto free_shm; + + shminfo->readOnly = True; + XShmAttach(fl_display, shminfo); + + vlog.debug("Using shared memory XImage"); + + return 1; + +free_shm: + shmctl(shminfo->shmid, IPC_RMID, 0); + +free_xim: + XDestroyImage(xim); + xim = NULL; + +free_shminfo: + delete shminfo; + shminfo = NULL; + + return 0; +} diff --git a/vncviewer/X11PixelBuffer.h b/vncviewer/X11PixelBuffer.h new file mode 100644 index 00000000..0b0cee01 --- /dev/null +++ b/vncviewer/X11PixelBuffer.h @@ -0,0 +1,47 @@ +/* Copyright 2011 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 + +class PlatformPixelBuffer: public rfb::FullFramePixelBuffer { +public: + PlatformPixelBuffer(int width, int height); + ~PlatformPixelBuffer(); + + void draw(int src_x, int src_y, int x, int y, int w, int h); + + int getStride() const; + +protected: + int setupShm(); + +protected: + XShmSegmentInfo *shminfo; + XImage *xim; +}; + + +#endif