]> source.dussan.org Git - tigervnc.git/commitdiff
Optimised drawing routines for X11, roughly based on how the old Unix viewer
authorPierre Ossman <ossman@cendio.se>
Mon, 13 Jun 2011 11:23:08 +0000 (11:23 +0000)
committerPierre Ossman <ossman@cendio.se>
Mon, 13 Jun 2011 11:23:08 +0000 (11:23 +0000)
did things.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4493 3789f03b-4d11-0410-bbf8-ca57d06f2519

vncviewer/CMakeLists.txt
vncviewer/Viewport.h
vncviewer/X11PixelBuffer.cxx [new file with mode: 0644]
vncviewer/X11PixelBuffer.h [new file with mode: 0644]

index 54c9344469f034f6b73f7a45f13d7a7fbf181ac0..faa1f75566d40c78d7ab9e9185724c4048bf72c5 100644 (file)
@@ -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})
index f385a245e7011816aa5a13b179383836b2d9907b..2613b6ddf3721f654ca8a691e521e47c849c4e57 100644 (file)
@@ -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 (file)
index 0000000..79fa76a
--- /dev/null
@@ -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;
+}
diff --git a/vncviewer/X11PixelBuffer.h b/vncviewer/X11PixelBuffer.h
new file mode 100644 (file)
index 0000000..0b0cee0
--- /dev/null
@@ -0,0 +1,47 @@
+/* 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.
+ */
+
+#ifndef __X11PIXELBUFFER_H__
+#define __X11PIXELBUFFER_H__
+
+#include <X11/Xlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+
+#include <rfb/PixelBuffer.h>
+
+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