diff options
author | Pierre Ossman <ossman@cendio.se> | 2011-06-13 11:23:08 +0000 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2011-06-13 11:23:08 +0000 |
commit | 1350069127f4817cb34c2112acfc1a7abeea0d3d (patch) | |
tree | a44534c3902b19239d1ebbb069c6a115941ed78c /vncviewer/X11PixelBuffer.cxx | |
parent | 132b3d0f752c9c1a352c765e5bb9dc3370ac7320 (diff) | |
download | tigervnc-1350069127f4817cb34c2112acfc1a7abeea0d3d.tar.gz tigervnc-1350069127f4817cb34c2112acfc1a7abeea0d3d.zip |
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
Diffstat (limited to 'vncviewer/X11PixelBuffer.cxx')
-rw-r--r-- | vncviewer/X11PixelBuffer.cxx | 188 |
1 files changed, 188 insertions, 0 deletions
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 <ossman@cendio.se> 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 <assert.h> +#include <stdlib.h> + +#include <FL/x.H> + +#include <rfb/LogWriter.h> +#include <rfb/Exception.h> + +#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; +} |