Print this page
rev 54883 : JDK-8220154 Improve java2d rendering performance on macOS by using Metal framework
Split |
Close |
Expand all |
Collapse all |
--- old/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java
+++ new/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java
1 1 /*
2 2 * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 package sun.java2d.opengl;
27 27
28 28 import java.awt.AWTException;
29 29 import java.awt.BufferCapabilities;
30 30 import java.awt.Component;
31 31 import java.awt.Graphics;
32 32 import java.awt.Graphics2D;
33 33 import java.awt.Image;
34 34 import java.awt.ImageCapabilities;
35 35 import java.awt.Rectangle;
36 36 import java.awt.Transparency;
37 37 import java.awt.color.ColorSpace;
38 38 import java.awt.image.BufferedImage;
39 39 import java.awt.image.ColorModel;
40 40 import java.awt.image.DataBuffer;
41 41 import java.awt.image.DirectColorModel;
42 42 import java.awt.image.VolatileImage;
43 43 import java.awt.image.WritableRaster;
44 44
45 45 import sun.awt.CGraphicsConfig;
46 46 import sun.awt.CGraphicsDevice;
47 47 import sun.awt.image.OffScreenImage;
↓ open down ↓ |
47 lines elided |
↑ open up ↑ |
48 48 import sun.awt.image.SunVolatileImage;
49 49 import sun.java2d.Disposer;
50 50 import sun.java2d.DisposerRecord;
51 51 import sun.java2d.Surface;
52 52 import sun.java2d.SurfaceData;
53 53 import sun.java2d.opengl.OGLContext.OGLContextCaps;
54 54 import sun.java2d.pipe.hw.AccelSurface;
55 55 import sun.java2d.pipe.hw.AccelTypedVolatileImage;
56 56 import sun.java2d.pipe.hw.ContextCapabilities;
57 57 import sun.lwawt.LWComponentPeer;
58 +import sun.lwawt.macosx.CFRetainedResource;
58 59 import sun.lwawt.macosx.CPlatformView;
59 60
60 61 import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_DOUBLEBUFFERED;
61 62 import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_EXT_FBOBJECT;
62 63 import static sun.java2d.opengl.OGLSurfaceData.FBOBJECT;
63 64 import static sun.java2d.opengl.OGLSurfaceData.TEXTURE;
64 65
65 66 public final class CGLGraphicsConfig extends CGraphicsConfig
66 67 implements OGLGraphicsConfig
67 68 {
68 69 //private static final int kOpenGLSwapInterval =
69 70 // RuntimeOptions.getCurrentOptions().OpenGLSwapInterval;
70 71 private static final int kOpenGLSwapInterval = 0; // TODO
71 72 private static boolean cglAvailable;
72 73 private static ImageCapabilities imageCaps = new CGLImageCaps();
73 74
74 75 private int pixfmt;
75 76 private BufferCapabilities bufferCaps;
76 77 private long pConfigInfo;
77 78 private ContextCapabilities oglCaps;
78 79 private OGLContext context;
79 80 private final Object disposerReferent = new Object();
80 81 private final int maxTextureSize;
81 82
82 83 private static native boolean initCGL();
83 84 private static native long getCGLConfigInfo(int displayID, int visualnum,
84 85 int swapInterval);
85 86 private static native int getOGLCapabilities(long configInfo);
86 87
87 88 /**
88 89 * Returns GL_MAX_TEXTURE_SIZE from the shared opengl context. Must be
89 90 * called under OGLRQ lock, because this method change current context.
90 91 *
91 92 * @return GL_MAX_TEXTURE_SIZE
92 93 */
93 94 private static native int nativeGetMaxTextureSize();
94 95
95 96 static {
96 97 cglAvailable = initCGL();
97 98 }
98 99
99 100 private CGLGraphicsConfig(CGraphicsDevice device, int pixfmt,
100 101 long configInfo, int maxTextureSize,
101 102 ContextCapabilities oglCaps) {
102 103 super(device);
103 104
104 105 this.pixfmt = pixfmt;
105 106 this.pConfigInfo = configInfo;
106 107 this.oglCaps = oglCaps;
107 108 this.maxTextureSize = maxTextureSize;
108 109 context = new OGLContext(OGLRenderQueue.getInstance(), this);
109 110
110 111 // add a record to the Disposer so that we destroy the native
111 112 // CGLGraphicsConfigInfo data when this object goes away
112 113 Disposer.addRecord(disposerReferent,
113 114 new CGLGCDisposerRecord(pConfigInfo));
114 115 }
115 116
116 117 @Override
117 118 public Object getProxyKey() {
118 119 return this;
119 120 }
120 121
121 122 @Override
122 123 public SurfaceData createManagedSurface(int w, int h, int transparency) {
123 124 return CGLSurfaceData.createData(this, w, h,
124 125 getColorModel(transparency),
125 126 null,
126 127 OGLSurfaceData.TEXTURE);
127 128 }
128 129
129 130 public static CGLGraphicsConfig getConfig(CGraphicsDevice device,
130 131 int displayID, int pixfmt)
131 132 {
132 133 if (!cglAvailable) {
133 134 return null;
134 135 }
135 136
136 137 long cfginfo = 0;
137 138 int textureSize = 0;
138 139 final String[] ids = new String[1];
139 140 OGLRenderQueue rq = OGLRenderQueue.getInstance();
140 141 rq.lock();
141 142 try {
142 143 // getCGLConfigInfo() creates and destroys temporary
143 144 // surfaces/contexts, so we should first invalidate the current
144 145 // Java-level context and flush the queue...
145 146 OGLContext.invalidateCurrentContext();
146 147 cfginfo = getCGLConfigInfo(displayID, pixfmt, kOpenGLSwapInterval);
147 148 if (cfginfo != 0L) {
148 149 textureSize = nativeGetMaxTextureSize();
149 150 // 7160609: GL still fails to create a square texture of this
150 151 // size. Half should be safe enough.
151 152 // Explicitly not support a texture more than 2^14, see 8010999.
152 153 textureSize = textureSize <= 16384 ? textureSize / 2 : 8192;
153 154 OGLContext.setScratchSurface(cfginfo);
154 155 rq.flushAndInvokeNow(() -> {
155 156 ids[0] = OGLContext.getOGLIdString();
156 157 });
157 158 }
158 159 } finally {
159 160 rq.unlock();
160 161 }
161 162 if (cfginfo == 0) {
162 163 return null;
163 164 }
164 165
165 166 int oglCaps = getOGLCapabilities(cfginfo);
166 167 ContextCapabilities caps = new OGLContextCaps(oglCaps, ids[0]);
167 168 return new CGLGraphicsConfig(device, pixfmt, cfginfo, textureSize, caps);
168 169 }
169 170
170 171 public static boolean isCGLAvailable() {
171 172 return cglAvailable;
172 173 }
173 174
174 175 /**
175 176 * Returns true if the provided capability bit is present for this config.
176 177 * See OGLContext.java for a list of supported capabilities.
177 178 */
178 179 @Override
179 180 public boolean isCapPresent(int cap) {
180 181 return ((oglCaps.getCaps() & cap) != 0);
181 182 }
182 183
183 184 @Override
184 185 public long getNativeConfigInfo() {
185 186 return pConfigInfo;
186 187 }
187 188
188 189 @Override
189 190 public OGLContext getContext() {
190 191 return context;
191 192 }
192 193
193 194 @Override
194 195 public BufferedImage createCompatibleImage(int width, int height) {
195 196 ColorModel model = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
196 197 WritableRaster
197 198 raster = model.createCompatibleWritableRaster(width, height);
198 199 return new BufferedImage(model, raster, model.isAlphaPremultiplied(),
199 200 null);
200 201 }
201 202
202 203 @Override
203 204 public ColorModel getColorModel(int transparency) {
204 205 switch (transparency) {
205 206 case Transparency.OPAQUE:
206 207 // REMIND: once the ColorModel spec is changed, this should be
207 208 // an opaque premultiplied DCM...
208 209 return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
209 210 case Transparency.BITMASK:
210 211 return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
211 212 case Transparency.TRANSLUCENT:
212 213 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
213 214 return new DirectColorModel(cs, 32,
214 215 0xff0000, 0xff00, 0xff, 0xff000000,
215 216 true, DataBuffer.TYPE_INT);
216 217 default:
217 218 return null;
218 219 }
219 220 }
220 221
221 222 public boolean isDoubleBuffered() {
222 223 return isCapPresent(CAPS_DOUBLEBUFFERED);
223 224 }
224 225
225 226 private static class CGLGCDisposerRecord implements DisposerRecord {
226 227 private long pCfgInfo;
227 228 public CGLGCDisposerRecord(long pCfgInfo) {
228 229 this.pCfgInfo = pCfgInfo;
229 230 }
230 231 public void dispose() {
231 232 if (pCfgInfo != 0) {
232 233 OGLRenderQueue.disposeGraphicsConfig(pCfgInfo);
233 234 pCfgInfo = 0;
234 235 }
235 236 }
236 237 }
237 238
238 239 // TODO: CGraphicsConfig doesn't implement displayChanged() yet
239 240 //@Override
240 241 public synchronized void displayChanged() {
241 242 //super.displayChanged();
242 243
243 244 // the context could hold a reference to a CGLSurfaceData, which in
244 245 // turn has a reference back to this CGLGraphicsConfig, so in order
245 246 // for this instance to be disposed we need to break the connection
246 247 OGLRenderQueue rq = OGLRenderQueue.getInstance();
247 248 rq.lock();
248 249 try {
249 250 OGLContext.invalidateCurrentContext();
250 251 } finally {
251 252 rq.unlock();
252 253 }
253 254 }
254 255
255 256 @Override
256 257 public String toString() {
↓ open down ↓ |
189 lines elided |
↑ open up ↑ |
257 258 String display = getDevice().getIDstring();
258 259 return ("CGLGraphicsConfig[" + display + ", pixfmt=" + pixfmt + "]");
259 260 }
260 261
261 262 @Override
262 263 public SurfaceData createSurfaceData(CPlatformView pView) {
263 264 return CGLSurfaceData.createData(pView);
264 265 }
265 266
266 267 @Override
267 - public SurfaceData createSurfaceData(CGLLayer layer) {
268 - return CGLSurfaceData.createData(layer);
268 + public SurfaceData createSurfaceData(CFRetainedResource layer) {
269 + return CGLSurfaceData.createData((CGLLayer) layer);
269 270 }
270 271
271 272 @Override
272 273 public Image createAcceleratedImage(Component target,
273 274 int width, int height)
274 275 {
275 276 ColorModel model = getColorModel(Transparency.OPAQUE);
276 277 WritableRaster wr = model.createCompatibleWritableRaster(width, height);
277 278 return new OffScreenImage(target, model, wr,
278 279 model.isAlphaPremultiplied());
279 280 }
280 281
281 282 @Override
282 283 public void assertOperationSupported(final int numBuffers,
283 284 final BufferCapabilities caps)
284 285 throws AWTException {
285 286 // Assume this method is never called with numBuffers != 2, as 0 is
286 287 // unsupported, and 1 corresponds to a SingleBufferStrategy which
287 288 // doesn't depend on the peer. Screen is considered as a separate
288 289 // "buffer".
289 290 if (numBuffers != 2) {
290 291 throw new AWTException("Only double buffering is supported");
291 292 }
292 293 final BufferCapabilities configCaps = getBufferCapabilities();
293 294 if (!configCaps.isPageFlipping()) {
294 295 throw new AWTException("Page flipping is not supported");
295 296 }
296 297 if (caps.getFlipContents() == BufferCapabilities.FlipContents.PRIOR) {
297 298 throw new AWTException("FlipContents.PRIOR is not supported");
298 299 }
299 300 }
300 301
301 302 @Override
302 303 public Image createBackBuffer(final LWComponentPeer<?, ?> peer) {
303 304 final Rectangle r = peer.getBounds();
304 305 // It is possible for the component to have size 0x0, adjust it to
305 306 // be at least 1x1 to avoid IAE
306 307 final int w = Math.max(1, r.width);
307 308 final int h = Math.max(1, r.height);
308 309 final int transparency = peer.isTranslucent() ? Transparency.TRANSLUCENT
309 310 : Transparency.OPAQUE;
310 311 return new SunVolatileImage(this, w, h, transparency, null);
311 312 }
312 313
313 314 @Override
314 315 public void destroyBackBuffer(final Image backBuffer) {
315 316 if (backBuffer != null) {
316 317 backBuffer.flush();
317 318 }
318 319 }
319 320
320 321 @Override
321 322 public void flip(final LWComponentPeer<?, ?> peer, final Image backBuffer,
322 323 final int x1, final int y1, final int x2, final int y2,
323 324 final BufferCapabilities.FlipContents flipAction) {
324 325 final Graphics g = peer.getGraphics();
325 326 try {
326 327 g.drawImage(backBuffer, x1, y1, x2, y2, x1, y1, x2, y2, null);
327 328 } finally {
328 329 g.dispose();
329 330 }
330 331 if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) {
331 332 final Graphics2D bg = (Graphics2D) backBuffer.getGraphics();
332 333 try {
333 334 bg.setBackground(peer.getBackground());
334 335 bg.clearRect(0, 0, backBuffer.getWidth(null),
335 336 backBuffer.getHeight(null));
336 337 } finally {
337 338 bg.dispose();
338 339 }
339 340 }
340 341 }
341 342
342 343 private static class CGLBufferCaps extends BufferCapabilities {
343 344 public CGLBufferCaps(boolean dblBuf) {
344 345 super(imageCaps, imageCaps,
345 346 dblBuf ? FlipContents.UNDEFINED : null);
346 347 }
347 348 }
348 349
349 350 @Override
350 351 public BufferCapabilities getBufferCapabilities() {
351 352 if (bufferCaps == null) {
352 353 bufferCaps = new CGLBufferCaps(isDoubleBuffered());
353 354 }
354 355 return bufferCaps;
355 356 }
356 357
357 358 private static class CGLImageCaps extends ImageCapabilities {
358 359 private CGLImageCaps() {
359 360 super(true);
360 361 }
361 362 public boolean isTrueVolatile() {
362 363 return true;
363 364 }
364 365 }
365 366
366 367 @Override
367 368 public ImageCapabilities getImageCapabilities() {
368 369 return imageCaps;
369 370 }
370 371
371 372 @Override
372 373 public VolatileImage createCompatibleVolatileImage(int width, int height,
373 374 int transparency,
374 375 int type) {
375 376 if ((type != FBOBJECT && type != TEXTURE)
376 377 || transparency == Transparency.BITMASK
377 378 || type == FBOBJECT && !isCapPresent(CAPS_EXT_FBOBJECT)) {
378 379 return null;
379 380 }
380 381 SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,
381 382 transparency, type);
382 383 Surface sd = vi.getDestSurface();
383 384 if (!(sd instanceof AccelSurface) ||
384 385 ((AccelSurface)sd).getType() != type)
385 386 {
386 387 vi.flush();
387 388 vi = null;
388 389 }
389 390
390 391 return vi;
391 392 }
392 393
393 394 @Override
394 395 public ContextCapabilities getContextCapabilities() {
395 396 return oglCaps;
396 397 }
397 398
398 399 @Override
399 400 public int getMaxTextureWidth() {
400 401 return Math.max(maxTextureSize / getDevice().getScaleFactor(),
401 402 getBounds().width);
402 403 }
403 404
404 405 @Override
405 406 public int getMaxTextureHeight() {
406 407 return Math.max(maxTextureSize / getDevice().getScaleFactor(),
407 408 getBounds().height);
408 409 }
409 410 }
↓ open down ↓ |
131 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX