1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.awt.windows; 26 27 import java.awt.AlphaComposite; 28 import java.awt.Color; 29 import java.awt.Graphics2D; 30 import java.awt.GraphicsConfiguration; 31 import java.awt.Image; 32 import java.awt.Window; 33 import java.awt.image.BufferedImage; 34 import java.awt.image.DataBufferInt; 35 import java.awt.image.VolatileImage; 36 import java.security.AccessController; 37 import sun.awt.image.BufImgSurfaceData; 38 import sun.java2d.DestSurfaceProvider; 39 import sun.java2d.InvalidPipeException; 40 import sun.java2d.Surface; 41 import sun.java2d.pipe.RenderQueue; 42 import sun.java2d.pipe.BufferedContext; 43 import sun.java2d.pipe.hw.AccelGraphicsConfig; 44 import sun.java2d.pipe.hw.AccelSurface; 45 import sun.security.action.GetPropertyAction; 46 47 import static java.awt.image.VolatileImage.*; 48 import static sun.java2d.pipe.hw.AccelSurface.*; 49 import static sun.java2d.pipe.hw.ContextCapabilities.*; 50 51 /** 52 * This class handles the updates of the non-opaque windows. 53 * The window associated with the peer is updated either given an image or 54 * the window is repainted to an internal buffer which is then used to update 55 * the window. 56 * 57 * Note: this class does not attempt to be thread safe, it is expected to be 58 * called from a single thread (EDT). 59 */ 60 abstract class TranslucentWindowPainter { 61 62 protected Window window; 63 protected WWindowPeer peer; 64 65 // REMIND: we probably would want to remove this later 66 private static final boolean forceOpt = 67 Boolean.valueOf(AccessController.doPrivileged( 68 new GetPropertyAction("sun.java2d.twp.forceopt", "false"))); 69 private static final boolean forceSW = 70 Boolean.valueOf(AccessController.doPrivileged( 71 new GetPropertyAction("sun.java2d.twp.forcesw", "false"))); 72 73 /** 74 * Creates an instance of the painter for particular peer. 75 */ 76 public static TranslucentWindowPainter createInstance(WWindowPeer peer) { 77 GraphicsConfiguration gc = peer.getGraphicsConfiguration(); 78 if (!forceSW && gc instanceof AccelGraphicsConfig) { 79 String gcName = gc.getClass().getSimpleName(); 80 AccelGraphicsConfig agc = (AccelGraphicsConfig)gc; 81 // this is a heuristic to check that we have a pcix board 82 // (those have higher transfer rate from gpu to cpu) 83 if ((agc.getContextCapabilities().getCaps() & CAPS_PS30) != 0 || 84 forceOpt) 85 { 86 // we check for name to avoid loading classes unnecessarily if 87 // a pipeline isn't enabled 88 if (gcName.startsWith("D3D")) { 89 return new VIOptD3DWindowPainter(peer); 90 } else if (forceOpt && gcName.startsWith("WGL")) { 91 // on some boards (namely, ATI, even on pcix bus) ogl is 92 // very slow reading pixels back so for now it is disabled 93 // unless forced 94 return new VIOptWGLWindowPainter(peer); 95 } 96 } 97 } 98 return new BIWindowPainter(peer); 99 } 100 101 protected TranslucentWindowPainter(WWindowPeer peer) { 102 this.peer = peer; 103 this.window = (Window)peer.getTarget(); 104 } 105 106 /** 107 * Creates (if needed), clears (if requested) and returns the buffer 108 * for this painter. 109 */ 110 protected abstract Image getBackBuffer(boolean clear); 111 112 /** 113 * Updates the window associated with this painter with the contents 114 * of the passed image. 115 * The image can not be null, and NPE will be thrown if it is. 116 */ 117 protected abstract boolean update(Image bb); 118 119 /** 120 * Flushes the resources associated with the painter. They will be 121 * recreated as needed. 122 */ 123 public abstract void flush(); 124 125 /** 126 * Updates the window associated with the painter. 127 * 128 * @param repaint indicates if the window should be completely repainted 129 * to the back buffer using {@link java.awt.Window#paintAll} before update. 130 */ 131 public void updateWindow(boolean repaint) { 132 boolean done = false; 133 Image bb = getBackBuffer(repaint); 134 while (!done) { 135 if (repaint) { 136 Graphics2D g = (Graphics2D)bb.getGraphics(); 137 try { 138 window.paintAll(g); 139 } finally { 140 g.dispose(); 141 } 142 } 143 144 done = update(bb); 145 if (!done) { 146 repaint = true; 147 bb = getBackBuffer(true); 148 } 149 } 150 } 151 152 private static final Image clearImage(Image bb) { 153 Graphics2D g = (Graphics2D)bb.getGraphics(); 154 int w = bb.getWidth(null); 155 int h = bb.getHeight(null); 156 157 g.setComposite(AlphaComposite.Src); 158 g.setColor(new Color(0, 0, 0, 0)); 159 g.fillRect(0, 0, w, h); 160 161 return bb; 162 } 163 164 /** 165 * A painter which uses BufferedImage as the internal buffer. The window 166 * is painted into this buffer, and the contents then are uploaded 167 * into the layered window. 168 * 169 * This painter handles all types of images passed to its paint(Image) 170 * method (VI, BI, regular Images). 171 */ 172 private static class BIWindowPainter extends TranslucentWindowPainter { 173 private BufferedImage backBuffer; 174 175 protected BIWindowPainter(WWindowPeer peer) { 176 super(peer); 177 } 178 179 @Override 180 protected Image getBackBuffer(boolean clear) { 181 int w = window.getWidth(); 182 int h = window.getHeight(); 183 if (backBuffer == null || 184 backBuffer.getWidth() != w || 185 backBuffer.getHeight() != h) 186 { 187 flush(); 188 backBuffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); 189 } 190 return clear ? (BufferedImage)clearImage(backBuffer) : backBuffer; 191 } 192 193 @Override 194 protected boolean update(Image bb) { 195 VolatileImage viBB = null; 196 197 if (bb instanceof BufferedImage) { 198 BufferedImage bi = (BufferedImage)bb; 199 int data[] = 200 ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); 201 peer.updateWindowImpl(data, bi.getWidth(), bi.getHeight()); 202 return true; 203 } else if (bb instanceof VolatileImage) { 204 viBB = (VolatileImage)bb; 205 if (bb instanceof DestSurfaceProvider) { 206 Surface s = ((DestSurfaceProvider)bb).getDestSurface(); 207 if (s instanceof BufImgSurfaceData) { 208 // the image is probably lost, upload the data from the 209 // backup surface to avoid creating another heap-based 210 // image (the parent's buffer) 211 int w = viBB.getWidth(); 212 int h = viBB.getHeight(); 213 BufImgSurfaceData bisd = (BufImgSurfaceData)s; 214 int data[] = ((DataBufferInt)bisd.getRaster(0,0,w,h). 215 getDataBuffer()).getData(); 216 peer.updateWindowImpl(data, w, h); 217 return true; 218 } 219 } 220 } 221 222 // copy the passed image into our own buffer, then upload 223 BufferedImage bi = (BufferedImage)clearImage(backBuffer); 224 225 int data[] = 226 ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); 227 peer.updateWindowImpl(data, bi.getWidth(), bi.getHeight()); 228 229 return (viBB != null ? !viBB.contentsLost() : true); 230 } 231 232 @Override 233 public void flush() { 234 if (backBuffer != null) { 235 backBuffer.flush(); 236 backBuffer = null; 237 } 238 } 239 } 240 241 /** 242 * A version of the painter which uses VolatileImage as the internal buffer. 243 * The window is painted into this VI and then copied into the parent's 244 * Java heap-based buffer (which is then uploaded to the layered window) 245 */ 246 private static class VIWindowPainter extends BIWindowPainter { 247 private VolatileImage viBB; 248 249 protected VIWindowPainter(WWindowPeer peer) { 250 super(peer); 251 } 252 253 @Override 254 protected Image getBackBuffer(boolean clear) { 255 int w = window.getWidth(); 256 int h = window.getHeight(); 257 GraphicsConfiguration gc = peer.getGraphicsConfiguration(); 258 259 if (viBB == null || viBB.getWidth() != w || viBB.getHeight() != h || 260 viBB.validate(gc) == IMAGE_INCOMPATIBLE) 261 { 262 flush(); 263 264 if (gc instanceof AccelGraphicsConfig) { 265 AccelGraphicsConfig agc = ((AccelGraphicsConfig)gc); 266 viBB = agc.createCompatibleVolatileImage(w, h, 267 TRANSLUCENT, 268 RT_PLAIN); 269 } 270 if (viBB == null) { 271 viBB = gc.createCompatibleVolatileImage(w, h, TRANSLUCENT); 272 } 273 viBB.validate(gc); 274 } 275 276 return clear ? clearImage(viBB) : viBB; 277 } 278 279 @Override 280 public void flush() { 281 if (viBB != null) { 282 viBB.flush(); 283 viBB = null; 284 } 285 } 286 } 287 288 /** 289 * Optimized version of hw painter. Uses VolatileImages for the 290 * buffer, and uses an optimized path to pull the data from those into 291 * the layered window, bypassing Java heap-based image. 292 */ 293 private abstract static class VIOptWindowPainter extends VIWindowPainter { 294 295 protected VIOptWindowPainter(WWindowPeer peer) { 296 super(peer); 297 } 298 299 protected abstract boolean updateWindowAccel(long psdops, int w, int h); 300 301 @Override 302 protected boolean update(Image bb) { 303 if (bb instanceof DestSurfaceProvider) { 304 Surface s = ((DestSurfaceProvider)bb).getDestSurface(); 305 if (s instanceof AccelSurface) { 306 final int w = bb.getWidth(null); 307 final int h = bb.getHeight(null); 308 final boolean arr[] = { false }; 309 final AccelSurface as = (AccelSurface)s; 310 RenderQueue rq = as.getContext().getRenderQueue(); 311 rq.lock(); 312 try { 313 BufferedContext.validateContext(as); 314 rq.flushAndInvokeNow(new Runnable() { 315 @Override 316 public void run() { 317 long psdops = as.getNativeOps(); 318 arr[0] = updateWindowAccel(psdops, w, h); 319 } 320 }); 321 } catch (InvalidPipeException e) { 322 // ignore, false will be returned 323 } finally { 324 rq.unlock(); 325 } 326 return arr[0]; 327 } 328 } 329 return super.update(bb); 330 } 331 } 332 333 private static class VIOptD3DWindowPainter extends VIOptWindowPainter { 334 335 protected VIOptD3DWindowPainter(WWindowPeer peer) { 336 super(peer); 337 } 338 339 @Override 340 protected boolean updateWindowAccel(long psdops, int w, int h) { 341 // note: this method is executed on the toolkit thread, no sync is 342 // necessary at the native level, and a pointer to peer can be used 343 return sun.java2d.d3d.D3DSurfaceData. 344 updateWindowAccelImpl(psdops, peer.getData(), w, h); 345 } 346 } 347 348 private static class VIOptWGLWindowPainter extends VIOptWindowPainter { 349 350 protected VIOptWGLWindowPainter(WWindowPeer peer) { 351 super(peer); 352 } 353 354 @Override 355 protected boolean updateWindowAccel(long psdops, int w, int h) { 356 // note: part of this method which deals with GDI will be on the 357 // toolkit thread 358 return sun.java2d.opengl.WGLSurfaceData. 359 updateWindowAccelImpl(psdops, peer, w, h); 360 } 361 } 362 }