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