From: Brian Hinz Date: Mon, 5 Mar 2012 23:57:05 +0000 (+0000) Subject: Improve performance of Java viewer by using buffered image as drawing surface. Simpli... X-Git-Tag: v1.2.90~220 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=44bc7d23d109cbab01555ddc3933eea65caa5a1f;p=tigervnc.git Improve performance of Java viewer by using buffered image as drawing surface. Simplified soft cursor construction. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4860 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- diff --git a/java/com/tigervnc/rfb/CMsgHandler.java b/java/com/tigervnc/rfb/CMsgHandler.java index 533bfbc2..731362d7 100644 --- a/java/com/tigervnc/rfb/CMsgHandler.java +++ b/java/com/tigervnc/rfb/CMsgHandler.java @@ -89,7 +89,7 @@ abstract public class CMsgHandler { public void serverCutText(String str, int len) {} public void fillRect(Rect r, int pix) {} - public void imageRect(Rect r, int[] pixels) {} + public void imageRect(Rect r, Object pixels) {} public void copyRect(Rect r, int srcX, int srcY) {} abstract public PixelFormat getPreferredPF(); diff --git a/java/com/tigervnc/rfb/TightDecoder.java b/java/com/tigervnc/rfb/TightDecoder.java index cfc259e5..74244572 100644 --- a/java/com/tigervnc/rfb/TightDecoder.java +++ b/java/com/tigervnc/rfb/TightDecoder.java @@ -23,7 +23,7 @@ import com.tigervnc.rdr.InStream; import com.tigervnc.rdr.ZlibInStream; import java.util.ArrayList; import java.io.InputStream; -import java.awt.image.PixelGrabber; +import java.awt.image.*; import java.awt.*; public class TightDecoder extends Decoder { @@ -249,20 +249,18 @@ public class TightDecoder extends Decoder { // Create an Image object from the JPEG data. Image jpeg = tk.createImage(netbuf); - - int w = r.width(); - int h = r.height(); - - int[] buf = reader.getImageBuf(w*h); - PixelGrabber pg = new PixelGrabber(jpeg, 0, 0, w, h, buf, 0, w); - try { - pg.grabPixels(0); - } catch (InterruptedException e) { - System.out.println("Tight Decoding: Wrong JPEG data received."); - } - + tk.prepareImage(jpeg, -1, -1, null); + synchronized(this) { + while ((tk.checkImage(jpeg, -1, -1, null) & ImageObserver.ALLBITS) == 0) { + try { + this.wait(1); + } catch (InterruptedException e) { + throw new Exception("Error decoding JPEG data"); + } + } + } + handler.imageRect(r, jpeg); jpeg.flush(); - handler.imageRect(r, buf); } final private void FilterGradient24(byte[] netbuf, int[] buf, int stride, diff --git a/java/com/tigervnc/vncviewer/CConn.java b/java/com/tigervnc/vncviewer/CConn.java index b20b82ea..e74cad56 100644 --- a/java/com/tigervnc/vncviewer/CConn.java +++ b/java/com/tigervnc/vncviewer/CConn.java @@ -514,7 +514,7 @@ public class CConn extends CConnection desktop.fillRect(r.tl.x, r.tl.y, r.width(), r.height(), p); } - public void imageRect(Rect r, int[] p) { + public void imageRect(Rect r, Object p) { desktop.imageRect(r.tl.x, r.tl.y, r.width(), r.height(), p); } diff --git a/java/com/tigervnc/vncviewer/DesktopWindow.java b/java/com/tigervnc/vncviewer/DesktopWindow.java index 814b9d06..aa019625 100644 --- a/java/com/tigervnc/vncviewer/DesktopWindow.java +++ b/java/com/tigervnc/vncviewer/DesktopWindow.java @@ -86,7 +86,7 @@ class DesktopWindow extends JPanel implements // to work. synchronized public void initGraphics() { - graphics = this.getGraphics(); + graphics = im.image.getGraphics(); prepareImage(im.image, scaledWidth, scaledHeight, this); } @@ -131,20 +131,16 @@ class DesktopWindow extends JPanel implements cursor.data = new int[cursor.width() * cursor.height()]; cursor.mask = new byte[cursor.maskLen()]; - // set the masked pixels of the cursor transparent by using an extra bit in - // the colormap. We'll OR this into the data based on the values in the mask. - if (cursor.getPF().bpp == 8) { - cursor.cm = new DirectColorModel(9, 7, (7 << 3), (3 << 6), (1 << 8)); - } - int maskBytesPerRow = (w + 7) / 8; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int byte_ = y * maskBytesPerRow + x / 8; int bit = 7 - x % 8; if ((mask[byte_] & (1 << bit)) > 0) { - cursor.data[y * cursor.width() + x] = (cursor.getPF().bpp == 8) ? - data[y * w + x] | (1 << 8) : data[y * w + x]; + cursor.data[y * cursor.width() + x] = (0xff << 24) | + (im.cm.getRed(data[y * w + x]) << 16) | + (im.cm.getGreen(data[y * w + x]) << 8) | + (im.cm.getBlue(data[y * w + x])); } } System.arraycopy(mask, y * maskBytesPerRow, cursor.mask, @@ -152,7 +148,7 @@ class DesktopWindow extends JPanel implements } MemoryImageSource bitmap = - new MemoryImageSource(cursor.width(), cursor.height(), cursor.cm, + new MemoryImageSource(cursor.width(), cursor.height(), ColorModel.getRGBdefault(), cursor.data, 0, cursor.width()); int cw = (int)Math.floor((float)cursor.width() * scaleWidthRatio); int ch = (int)Math.floor((float)cursor.height() * scaleHeightRatio); @@ -198,7 +194,6 @@ class DesktopWindow extends JPanel implements im.setColourMapEntries(firstColour, nColours, rgbs); if (nColours <= 256) { im.updateColourMap(); - im.put(0, 0, im.width(), im.height(), graphics); } else { if (setColourMapEntriesTimerThread == null) { setColourMapEntriesTimerThread = new Thread(this); @@ -233,7 +228,9 @@ class DesktopWindow extends JPanel implements invalidRect = false; synchronized (im) { - im.put(x, y, w, h, graphics); + graphics.setClip(x, y, w, h); + repaint(x, y, w, h); + graphics.setClip(0, 0, im.width(), im.height()); } } @@ -268,7 +265,7 @@ class DesktopWindow extends JPanel implements } final public void imageRect(int x, int y, int w, int h, - int[] pix) { + Object pix) { if (overlapsCursor(x, y, w, h)) hideLocalCursor(); synchronized (im) { im.imageRect(x, y, w, h, pix); @@ -283,11 +280,9 @@ class DesktopWindow extends JPanel implements if (overlapsCursor(x, y, w, h) || overlapsCursor(srcX, srcY, w, h)) hideLocalCursor(); synchronized (im) { - im.copyRect(x, y, w, h, srcX, srcY, graphics); - } - if (!cc.viewer.fastCopyRect.getValue()) { - invalidate(x, y, w, h); + im.copyRect(x, y, w, h, srcX, srcY); } + invalidate(x, y, w, h); } @@ -480,8 +475,6 @@ class DesktopWindow extends JPanel implements cursorVisible = false; im.imageRect(cursorBackingX, cursorBackingY, cursorBacking.width(), cursorBacking.height(), cursorBacking.data); - im.put(cursorBackingX, cursorBackingY, cursorBacking.width(), - cursorBacking.height(), graphics); } } @@ -516,7 +509,6 @@ class DesktopWindow extends JPanel implements im.maskRect(cursorLeft, cursorTop, cursor.width(), cursor.height(), cursor.data, cursor.mask); - im.put(x, y, w, h, graphics); } } @@ -528,7 +520,6 @@ class DesktopWindow extends JPanel implements Thread.sleep(100); } catch (InterruptedException e) {} im.updateColourMap(); - im.put(0, 0, im.width(), im.height(), graphics); setColourMapEntriesTimerThread = null; } diff --git a/java/com/tigervnc/vncviewer/PixelBufferImage.java b/java/com/tigervnc/vncviewer/PixelBufferImage.java index 0efc3c1d..5f666487 100644 --- a/java/com/tigervnc/vncviewer/PixelBufferImage.java +++ b/java/com/tigervnc/vncviewer/PixelBufferImage.java @@ -30,7 +30,7 @@ import java.nio.ByteOrder; import com.tigervnc.rfb.*; -public class PixelBufferImage extends PixelBuffer implements ImageProducer +public class PixelBufferImage extends PixelBuffer { public PixelBufferImage(int w, int h, CConn cc_, DesktopWindow desktop_) { cc = cc_; @@ -48,25 +48,31 @@ public class PixelBufferImage extends PixelBuffer implements ImageProducer public void resize(int w, int h) { if (w == width() && h == height()) return; - int rowsToCopy = h < height() ? h : height(); - int copyWidth = w < width() ? w : width(); - int[] oldData = data; - width_ = w; height_ = h; - image = desktop.createImage(this); + switch (format.depth) { + case 3: + // Fall-through to depth 8 + case 6: + // Fall-through to depth 8 + case 8: + image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED); + break; + default: + GraphicsEnvironment ge = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + image = gc.createCompatibleImage(w, h, Transparency.OPAQUE); + break; + } image.setAccelerationPriority(1); - - data = new int[width() * height()]; - - for (int i = 0; i < rowsToCopy; i++) - System.arraycopy(oldData, copyWidth * i, - data, width() * i, copyWidth); + graphics = image.createGraphics(); } public PixelFormat getNativePF() { PixelFormat pf; - cm = java.awt.Toolkit.getDefaultToolkit().getColorModel(); + cm = tk.getColorModel(); if (cm.getColorSpace().getType() == java.awt.color.ColorSpace.TYPE_RGB) { int depth = cm.getPixelSize(); int bpp = (depth > 16 ? 32 : (depth > 8 ? 16 : 8)); @@ -90,24 +96,33 @@ public class PixelBufferImage extends PixelBuffer implements ImageProducer return pf; } - // put() causes the given rectangle to be drawn using the given graphics - // context. - public void put(int x, int y, int w, int h, Graphics g) { - if (ic != null) { - ic.setPixels(x, y, w, h, cm, data, width() * y + x, width()); - desktop.repaint(x, y, w, h); + public void fillRect(int x, int y, int w, int h, int pix) { + switch (format.depth) { + case 24: + graphics.setColor(new Color(pix)); + graphics.fillRect(x, y, w, h); + break; + default: + Color color = new Color((0xff << 24) | (cm.getRed(pix) << 16) | + (cm.getGreen(pix) << 8) | (cm.getBlue(pix))); + graphics.setColor(color); + graphics.fillRect(x, y, w, h); + break; } } - // fillRect(), imageRect(), maskRect() are inherited from PixelBuffer. For - // copyRect() we also need to tell the ImageConsumer that the pixels have - // changed (this is done in the put() call for the others). + public void imageRect(int x, int y, int w, int h, Object pix) { + if (pix instanceof java.awt.Image) { + graphics.drawImage((Image)pix, x, y, w, h, null); + } else { + Image img = tk.createImage(new MemoryImageSource(w, h, cm, (int[])pix, 0, w)); + graphics.drawImage(img, x, y, w, h, null); + img.flush(); + } + } - public void copyRect(int x, int y, int w, int h, int srcX, int srcY, Graphics g) { - super.copyRect(x, y, w, h, srcX, srcY); - if (ic == null) return; - ic.setPixels(x, y, w, h, cm, data, width() * y + x, width()); - desktop.repaint(x, y, w, h); + public void copyRect(int x, int y, int w, int h, int srcX, int srcY) { + graphics.copyArea(srcX, srcY, w, h, x - srcX, y - srcY); } // setColourMapEntries() changes some of the entries in the colourmap. @@ -128,40 +143,14 @@ public class PixelBufferImage extends PixelBuffer implements ImageProducer } } - // ImageProducer methods - public void updateColourMap() { cm = new IndexColorModel(8, nColours, reds, greens, blues); } - public void addConsumer(ImageConsumer c) { - if (ic == c) return; - - vlog.debug("adding consumer "+c); - - if (ic != null) - vlog.error("Only one ImageConsumer allowed - discarding old one"); - - ic = c; - ic.setDimensions(width(), height()); - ic.setHints(ImageConsumer.RANDOMPIXELORDER); - // Calling ic.setColorModel(cm) seemed to help in some earlier versions of - // the JDK, but it shouldn't be necessary because we pass the ColorModel - // with each setPixels() call. - ic.setPixels(0, 0, width(), height(), cm, data, 0, width()); - ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); - } - - public void removeConsumer(ImageConsumer c) { - System.err.println("removeConsumer "+c); - if (ic == c) ic = null; - } - - public boolean isConsumer(ImageConsumer c) { return ic == c; } - public void requestTopDownLeftRightResend(ImageConsumer c) {} - public void startProduction(ImageConsumer c) { addConsumer(c); } + private static Toolkit tk = java.awt.Toolkit.getDefaultToolkit(); - Image image; + Graphics2D graphics; + BufferedImage image; ImageConsumer ic; int nColours;