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