1 /* 2 * Copyright (c) 2008, 2016, 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.Graphics; 30 import java.awt.Graphics2D; 31 import java.awt.GraphicsConfiguration; 32 import java.awt.Image; 33 import java.awt.Window; 34 import java.awt.geom.AffineTransform; 35 import java.awt.image.BufferedImage; 36 import java.awt.image.DataBufferInt; 37 import java.awt.image.VolatileImage; 38 import java.security.AccessController; 39 import sun.awt.image.BufImgSurfaceData; 40 import sun.java2d.DestSurfaceProvider; 41 import sun.java2d.InvalidPipeException; 42 import sun.java2d.Surface; 43 import sun.java2d.pipe.Region; 44 import sun.java2d.pipe.RenderQueue; 45 import sun.java2d.pipe.BufferedContext; 46 import sun.java2d.pipe.hw.AccelGraphicsConfig; 47 import sun.java2d.pipe.hw.AccelSurface; 48 import sun.security.action.GetPropertyAction; 49 50 import static java.awt.image.VolatileImage.*; 51 import static sun.java2d.pipe.hw.AccelSurface.*; 52 import static sun.java2d.pipe.hw.ContextCapabilities.*; 53 54 /** 55 * This class handles the updates of the non-opaque windows. 56 * The window associated with the peer is updated either given an image or 57 * the window is repainted to an internal buffer which is then used to update 58 * the window. 59 * 60 * Note: this class does not attempt to be thread safe, it is expected to be 61 * called from a single thread (EDT). 62 */ 63 abstract class TranslucentWindowPainter { 64 65 protected Window window; 66 protected WWindowPeer peer; 67 68 // REMIND: we probably would want to remove this later 69 private static final boolean forceOpt = 70 Boolean.valueOf(AccessController.doPrivileged( 71 new GetPropertyAction("sun.java2d.twp.forceopt", "false"))); 72 private static final boolean forceSW = 73 Boolean.valueOf(AccessController.doPrivileged( 74 new GetPropertyAction("sun.java2d.twp.forcesw", "false"))); 75 76 /** 77 * Creates an instance of the painter for particular peer. 78 */ 79 public static TranslucentWindowPainter createInstance(WWindowPeer peer) { 80 GraphicsConfiguration gc = peer.getGraphicsConfiguration(); 81 if (!forceSW && gc instanceof AccelGraphicsConfig) { 82 String gcName = gc.getClass().getSimpleName(); 83 AccelGraphicsConfig agc = (AccelGraphicsConfig)gc; 84 // this is a heuristic to check that we have a pcix board 85 // (those have higher transfer rate from gpu to cpu) 86 if ((agc.getContextCapabilities().getCaps() & CAPS_PS30) != 0 || 87 forceOpt) 88 { 89 // we check for name to avoid loading classes unnecessarily if 90 // a pipeline isn't enabled 91 if (gcName.startsWith("D3D")) { 92 return new VIOptD3DWindowPainter(peer); 93 } else if (forceOpt && gcName.startsWith("WGL")) { 94 // on some boards (namely, ATI, even on pcix bus) ogl is 95 // very slow reading pixels back so for now it is disabled 96 // unless forced 97 return new VIOptWGLWindowPainter(peer); 98 } 99 } 100 } 101 return new BIWindowPainter(peer); 102 } 103 104 protected TranslucentWindowPainter(WWindowPeer peer) { 105 this.peer = peer; 106 this.window = (Window)peer.getTarget(); 107 } 108 109 /** 110 * Creates (if needed), clears (if requested) and returns the buffer 111 * for this painter. 112 */ 113 protected abstract Image getBackBuffer(boolean clear); 114 115 /** 116 * Updates the window associated with this painter with the contents 117 * of the passed image. 118 * The image can not be null, and NPE will be thrown if it is. 119 */ 120 protected abstract boolean update(Image bb); 121 122 /** 123 * Create (if needed), clears back buffer (if requested) and return 124 * graphics for this class depending upon the buffer type 125 */ 126 protected abstract Graphics getGraphics(boolean clear); 127 128 /** 129 * Flushes the resources associated with the painter. They will be 130 * recreated as needed. 131 */ 132 public abstract void flush(); 133 134 /** 135 * Updates the window associated with the painter. 136 * 137 * @param repaint indicates if the window should be completely repainted 138 * to the back buffer using {@link java.awt.Window#paintAll} before update. 139 */ 140 public void updateWindow(boolean repaint) { 141 boolean done = false; 142 while (!done) { 143 if (repaint) { 144 Graphics2D g = (Graphics2D) getGraphics(repaint); 145 try { 146 window.paintAll(g); 147 } finally { 148 g.dispose(); 149 } 150 } 151 152 done = update(getBackBuffer(false)); 153 if (!done) { 154 repaint = true; 155 } 156 } 157 } 158 159 private static final Image clearImage(Image bb) { 160 Graphics2D g = (Graphics2D)bb.getGraphics(); 161 int w = bb.getWidth(null); 162 int h = bb.getHeight(null); 163 164 g.setComposite(AlphaComposite.Src); 165 g.setColor(new Color(0, 0, 0, 0)); 166 g.fillRect(0, 0, w, h); 167 168 return bb; 169 } 170 171 /** 172 * A painter which uses BufferedImage as the internal buffer. The window 173 * is painted into this buffer, and the contents then are uploaded 174 * into the layered window. 175 * 176 * This painter handles all types of images passed to its paint(Image) 177 * method (VI, BI, regular Images). 178 */ 179 private static class BIWindowPainter extends TranslucentWindowPainter { 180 private BufferedImage backBuffer; 181 182 protected BIWindowPainter(WWindowPeer peer) { 183 super(peer); 184 } 185 186 @Override 187 protected Image getBackBuffer(boolean clear) { 188 GraphicsConfiguration gc = peer.getGraphicsConfiguration(); 189 AffineTransform transform = gc.getDefaultTransform(); 190 int w = Region.clipRound( 191 window.getWidth() * transform.getScaleX()); 192 int h = Region.clipRound( 193 window.getHeight() * transform.getScaleY()); 194 if (backBuffer == null || 195 backBuffer.getWidth() != w || 196 backBuffer.getHeight() != h) 197 { 198 flush(); 199 backBuffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); 200 } 201 return clear ? (BufferedImage)clearImage(backBuffer) : backBuffer; 202 } 203 204 @Override 205 protected boolean update(Image bb) { 206 VolatileImage viBB = null; 207 208 if (bb instanceof BufferedImage) { 209 BufferedImage bi = (BufferedImage)bb; 210 int data[] = 211 ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); 212 peer.updateWindowImpl(data, bi.getWidth(), bi.getHeight()); 213 return true; 214 } else if (bb instanceof VolatileImage) { 215 viBB = (VolatileImage)bb; 216 if (bb instanceof DestSurfaceProvider) { 217 Surface s = ((DestSurfaceProvider)bb).getDestSurface(); 218 if (s instanceof BufImgSurfaceData) { 219 // the image is probably lost, upload the data from the 220 // backup surface to avoid creating another heap-based 221 // image (the parent's buffer) 222 int w = viBB.getWidth(); 223 int h = viBB.getHeight(); 224 BufImgSurfaceData bisd = (BufImgSurfaceData)s; 225 int data[] = ((DataBufferInt)bisd.getRaster(0,0,w,h). 226 getDataBuffer()).getData(); 227 peer.updateWindowImpl(data, w, h); 228 return true; 229 } 230 } 231 } 232 233 // copy the passed image into our own buffer, then upload 234 BufferedImage bi = (BufferedImage)clearImage(backBuffer); 235 236 int data[] = 237 ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); 238 peer.updateWindowImpl(data, bi.getWidth(), bi.getHeight()); 239 240 return (viBB != null ? !viBB.contentsLost() : true); 241 } 242 243 @Override 244 public void flush() { 245 if (backBuffer != null) { 246 backBuffer.flush(); 247 backBuffer = null; 248 } 249 } 250 251 @Override 252 protected Graphics getGraphics(boolean clear) { 253 Graphics g = getBackBuffer(clear).getGraphics(); 254 /* 255 This graphics object returned by BuffereImage is not scaled to 256 graphics configuration, but this graphics object can be used by 257 components inside this TranslucentWindow. So need to scale this 258 before returning. 259 */ 260 ((Graphics2D)g).transform(peer.getGraphicsConfiguration().getDefaultTransform()); 261 return g; 262 } 263 } 264 265 /** 266 * A version of the painter which uses VolatileImage as the internal buffer. 267 * The window is painted into this VI and then copied into the parent's 268 * Java heap-based buffer (which is then uploaded to the layered window) 269 */ 270 private static class VIWindowPainter extends BIWindowPainter { 271 private VolatileImage viBB; 272 273 protected VIWindowPainter(WWindowPeer peer) { 274 super(peer); 275 } 276 277 @Override 278 protected Image getBackBuffer(boolean clear) { 279 int w = window.getWidth(); 280 int h = window.getHeight(); 281 GraphicsConfiguration gc = peer.getGraphicsConfiguration(); 282 283 if (viBB == null || viBB.getWidth() != w || viBB.getHeight() != h || 284 viBB.validate(gc) == IMAGE_INCOMPATIBLE) 285 { 286 flush(); 287 288 if (gc instanceof AccelGraphicsConfig) { 289 AccelGraphicsConfig agc = ((AccelGraphicsConfig)gc); 290 viBB = agc.createCompatibleVolatileImage(w, h, 291 TRANSLUCENT, 292 RT_PLAIN); 293 } 294 if (viBB == null) { 295 viBB = gc.createCompatibleVolatileImage(w, h, TRANSLUCENT); 296 } 297 viBB.validate(gc); 298 } 299 300 return clear ? clearImage(viBB) : viBB; 301 } 302 303 @Override 304 public void flush() { 305 if (viBB != null) { 306 viBB.flush(); 307 viBB = null; 308 } 309 } 310 311 @Override 312 protected Graphics getGraphics(boolean clear) { 313 return getBackBuffer(clear).getGraphics(); 314 } 315 } 316 317 /** 318 * Optimized version of hw painter. Uses VolatileImages for the 319 * buffer, and uses an optimized path to pull the data from those into 320 * the layered window, bypassing Java heap-based image. 321 */ 322 private abstract static class VIOptWindowPainter extends VIWindowPainter { 323 324 protected VIOptWindowPainter(WWindowPeer peer) { 325 super(peer); 326 } 327 328 protected abstract boolean updateWindowAccel(long psdops, int w, int h); 329 330 @Override 331 protected boolean update(Image bb) { 332 if (bb instanceof DestSurfaceProvider) { 333 Surface s = ((DestSurfaceProvider)bb).getDestSurface(); 334 if (s instanceof AccelSurface) { 335 final boolean arr[] = { false }; 336 final AccelSurface as = (AccelSurface)s; 337 final int w = as.getBounds().width; 338 final int h = as.getBounds().height; 339 RenderQueue rq = as.getContext().getRenderQueue(); 340 rq.lock(); 341 try { 342 BufferedContext.validateContext(as); 343 rq.flushAndInvokeNow(new Runnable() { 344 @Override 345 public void run() { 346 long psdops = as.getNativeOps(); 347 arr[0] = updateWindowAccel(psdops, w, h); 348 } 349 }); 350 } catch (InvalidPipeException e) { 351 // ignore, false will be returned 352 } finally { 353 rq.unlock(); 354 } 355 return arr[0]; 356 } 357 } 358 return super.update(bb); 359 } 360 } 361 362 private static class VIOptD3DWindowPainter extends VIOptWindowPainter { 363 364 protected VIOptD3DWindowPainter(WWindowPeer peer) { 365 super(peer); 366 } 367 368 @Override 369 protected boolean updateWindowAccel(long psdops, int w, int h) { 370 // note: this method is executed on the toolkit thread, no sync is 371 // necessary at the native level, and a pointer to peer can be used 372 return sun.java2d.d3d.D3DSurfaceData. 373 updateWindowAccelImpl(psdops, peer.getData(), w, h); 374 } 375 } 376 377 private static class VIOptWGLWindowPainter extends VIOptWindowPainter { 378 379 protected VIOptWGLWindowPainter(WWindowPeer peer) { 380 super(peer); 381 } 382 383 @Override 384 protected boolean updateWindowAccel(long psdops, int w, int h) { 385 // note: part of this method which deals with GDI will be on the 386 // toolkit thread 387 return sun.java2d.opengl.WGLSurfaceData. 388 updateWindowAccelImpl(psdops, peer, w, h); 389 } 390 } 391 }