1 /* 2 * Copyright (c) 2008, 2018, 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 }