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/native/libawt_lwawt/awt/CGraphicsDevice.m
+++ new/src/java.desktop/macosx/native/libawt_lwawt/awt/CGraphicsDevice.m
1 1 /*
2 2 * Copyright (c) 2012, 2018, 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,
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
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 #import "LWCToolkit.h"
27 27 #import "ThreadUtilities.h"
28 28 #include "GeomUtilities.h"
29 +#import <Metal/Metal.h>
30 +#import <MetalKit/MetalKit.h>
29 31
30 32 #import <JavaNativeFoundation/JavaNativeFoundation.h>
31 33
32 34 /**
33 35 * Some default values for invalid CoreGraphics display ID.
34 36 */
35 37 #define DEFAULT_DEVICE_WIDTH 1024
36 38 #define DEFAULT_DEVICE_HEIGHT 768
37 39 #define DEFAULT_DEVICE_DPI 72
38 40
39 41 /*
40 42 * Convert the mode string to the more convinient bits per pixel value
41 43 */
42 44 static int getBPPFromModeString(CFStringRef mode)
43 45 {
44 46 if ((CFStringCompare(mode, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
45 47 // This is a strange mode, where we using 10 bits per RGB component and pack it into 32 bits
46 48 // Java is not ready to work with this mode but we have to specify it as supported
47 49 return 30;
48 50 }
49 51 else if (CFStringCompare(mode, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
50 52 return 32;
51 53 }
52 54 else if (CFStringCompare(mode, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
53 55 return 16;
54 56 }
55 57 else if (CFStringCompare(mode, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
56 58 return 8;
57 59 }
58 60
59 61 return 0;
60 62 }
61 63
62 64 static BOOL isValidDisplayMode(CGDisplayModeRef mode){
63 65 return (1 < CGDisplayModeGetWidth(mode) && 1 < CGDisplayModeGetHeight(mode));
64 66 }
65 67
66 68 static CFMutableArrayRef getAllValidDisplayModes(jint displayID){
67 69 // CGDisplayCopyAllDisplayModes can return NULL if displayID is invalid
68 70 CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displayID, NULL);
69 71 CFMutableArrayRef validModes = nil;
70 72 if (allModes) {
71 73 CFIndex numModes = CFArrayGetCount(allModes);
72 74 validModes = CFArrayCreateMutable(kCFAllocatorDefault, numModes + 1, &kCFTypeArrayCallBacks);
73 75
74 76 CFIndex n;
75 77 for (n=0; n < numModes; n++) {
76 78 CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);
77 79 if (cRef != NULL && isValidDisplayMode(cRef)) {
78 80 CFArrayAppendValue(validModes, cRef);
79 81 }
80 82 }
81 83 CFRelease(allModes);
82 84
83 85 // CGDisplayCopyDisplayMode can return NULL if displayID is invalid
84 86 CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID);
85 87 if (currentMode) {
86 88 BOOL containsCurrentMode = NO;
87 89 numModes = CFArrayGetCount(validModes);
88 90 for (n=0; n < numModes; n++) {
89 91 if(CFArrayGetValueAtIndex(validModes, n) == currentMode){
90 92 containsCurrentMode = YES;
91 93 break;
92 94 }
93 95 }
94 96 if (!containsCurrentMode) {
95 97 CFArrayAppendValue(validModes, currentMode);
96 98 }
97 99 CGDisplayModeRelease(currentMode);
98 100 }
99 101 }
100 102
101 103 return validModes;
102 104 }
103 105
104 106 /*
105 107 * Find the best possible match in the list of display modes that we can switch to based on
106 108 * the provided parameters.
107 109 */
108 110 static CGDisplayModeRef getBestModeForParameters(CFArrayRef allModes, int w, int h, int bpp, int refrate) {
109 111 CGDisplayModeRef bestGuess = NULL;
110 112 CFIndex numModes = allModes ? CFArrayGetCount(allModes) : 0, n;
111 113 int thisBpp = 0;
112 114 for(n = 0; n < numModes; n++ ) {
113 115 CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);
114 116 if(cRef == NULL) {
115 117 continue;
116 118 }
117 119 CFStringRef modeString = CGDisplayModeCopyPixelEncoding(cRef);
118 120 thisBpp = getBPPFromModeString(modeString);
119 121 CFRelease(modeString);
120 122 if (thisBpp != bpp || (int)CGDisplayModeGetHeight(cRef) != h || (int)CGDisplayModeGetWidth(cRef) != w) {
121 123 // One of the key parameters does not match
122 124 continue;
123 125 }
124 126
125 127 if (refrate == 0) { // REFRESH_RATE_UNKNOWN
126 128 return cRef;
127 129 }
128 130
129 131 // Refresh rate might be 0 in display mode and we ask for specific display rate
130 132 // but if we do not find exact match then 0 refresh rate might be just Ok
131 133 if (CGDisplayModeGetRefreshRate(cRef) == refrate) {
132 134 // Exact match
133 135 return cRef;
134 136 }
135 137 if (CGDisplayModeGetRefreshRate(cRef) == 0) {
136 138 // Not exactly what was asked for, but may fit our needs if we don't find an exact match
137 139 bestGuess = cRef;
138 140 }
139 141 }
140 142 return bestGuess;
141 143 }
142 144
143 145 /*
144 146 * Create a new java.awt.DisplayMode instance based on provided
145 147 * CGDisplayModeRef, if CGDisplayModeRef is NULL, then some stub is returned.
146 148 */
147 149 static jobject createJavaDisplayMode(CGDisplayModeRef mode, JNIEnv *env) {
148 150 jobject ret = NULL;
149 151 jint h = DEFAULT_DEVICE_HEIGHT, w = DEFAULT_DEVICE_WIDTH, bpp = 0, refrate = 0;
150 152 JNF_COCOA_ENTER(env);
151 153 if (mode) {
152 154 CFStringRef currentBPP = CGDisplayModeCopyPixelEncoding(mode);
153 155 bpp = getBPPFromModeString(currentBPP);
154 156 refrate = CGDisplayModeGetRefreshRate(mode);
155 157 h = CGDisplayModeGetHeight(mode);
156 158 w = CGDisplayModeGetWidth(mode);
157 159 CFRelease(currentBPP);
158 160 }
159 161 static JNF_CLASS_CACHE(jc_DisplayMode, "java/awt/DisplayMode");
160 162 static JNF_CTOR_CACHE(jc_DisplayMode_ctor, jc_DisplayMode, "(IIII)V");
161 163 ret = JNFNewObject(env, jc_DisplayMode_ctor, w, h, bpp, refrate);
162 164 JNF_COCOA_EXIT(env);
163 165 return ret;
164 166 }
165 167
166 168
167 169 /*
168 170 * Class: sun_awt_CGraphicsDevice
169 171 * Method: nativeGetXResolution
170 172 * Signature: (I)D
171 173 */
172 174 JNIEXPORT jdouble JNICALL
173 175 Java_sun_awt_CGraphicsDevice_nativeGetXResolution
174 176 (JNIEnv *env, jclass class, jint displayID)
175 177 {
176 178 // CGDisplayScreenSize can return 0 if displayID is invalid
177 179 CGSize size = CGDisplayScreenSize(displayID);
178 180 CGRect rect = CGDisplayBounds(displayID);
179 181 // 1 inch == 25.4 mm
180 182 jfloat inches = size.width / 25.4f;
181 183 return inches > 0 ? rect.size.width / inches : DEFAULT_DEVICE_DPI;
182 184 }
183 185
184 186 /*
185 187 * Class: sun_awt_CGraphicsDevice
186 188 * Method: nativeGetYResolution
187 189 * Signature: (I)D
188 190 */
189 191 JNIEXPORT jdouble JNICALL
190 192 Java_sun_awt_CGraphicsDevice_nativeGetYResolution
191 193 (JNIEnv *env, jclass class, jint displayID)
192 194 {
193 195 // CGDisplayScreenSize can return 0 if displayID is invalid
194 196 CGSize size = CGDisplayScreenSize(displayID);
195 197 CGRect rect = CGDisplayBounds(displayID);
196 198 // 1 inch == 25.4 mm
197 199 jfloat inches = size.height / 25.4f;
198 200 return inches > 0 ? rect.size.height / inches : DEFAULT_DEVICE_DPI;
199 201 }
200 202
201 203 /*
202 204 * Class: sun_awt_CGraphicsDevice
203 205 * Method: nativeGetBounds
204 206 * Signature: (I)Ljava/awt/Rectangle;
205 207 */
206 208 JNIEXPORT jobject JNICALL
207 209 Java_sun_awt_CGraphicsDevice_nativeGetBounds
208 210 (JNIEnv *env, jclass class, jint displayID)
209 211 {
210 212 CGRect rect = CGDisplayBounds(displayID);
211 213 if (rect.size.width == 0) {
212 214 rect.size.width = DEFAULT_DEVICE_WIDTH;
213 215 }
214 216 if (rect.size.height == 0) {
215 217 rect.size.height = DEFAULT_DEVICE_HEIGHT;
216 218 }
217 219 return CGToJavaRect(env, rect);
218 220 }
219 221
220 222 /*
221 223 * Class: sun_awt_CGraphicsDevice
222 224 * Method: nativeGetScreenInsets
223 225 * Signature: (I)D
224 226 */
225 227 JNIEXPORT jobject JNICALL
226 228 Java_sun_awt_CGraphicsDevice_nativeGetScreenInsets
227 229 (JNIEnv *env, jclass class, jint displayID)
228 230 {
229 231 jobject ret = NULL;
230 232 __block NSRect frame = NSZeroRect;
231 233 __block NSRect visibleFrame = NSZeroRect;
232 234 JNF_COCOA_ENTER(env);
233 235
234 236 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
235 237 NSArray *screens = [NSScreen screens];
236 238 for (NSScreen *screen in screens) {
237 239 NSDictionary *screenInfo = [screen deviceDescription];
238 240 NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
239 241 if ([screenID unsignedIntValue] == displayID){
240 242 frame = [screen frame];
241 243 visibleFrame = [screen visibleFrame];
242 244 break;
243 245 }
244 246 }
245 247 }];
246 248 // Convert between Cocoa's coordinate system and Java.
247 249 jint bottom = visibleFrame.origin.y - frame.origin.y;
248 250 jint top = frame.size.height - visibleFrame.size.height - bottom;
249 251 jint left = visibleFrame.origin.x - frame.origin.x;
250 252 jint right = frame.size.width - visibleFrame.size.width - left;
251 253
252 254 static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets");
253 255 static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V");
254 256 ret = JNFNewObject(env, jc_Insets_ctor, top, left, bottom, right);
255 257
256 258 JNF_COCOA_EXIT(env);
257 259
258 260 return ret;
259 261 }
260 262
261 263 /*
262 264 * Class: sun_awt_CGraphicsDevice
263 265 * Method: nativeSetDisplayMode
264 266 * Signature: (IIIII)V
265 267 */
266 268 JNIEXPORT void JNICALL
267 269 Java_sun_awt_CGraphicsDevice_nativeSetDisplayMode
268 270 (JNIEnv *env, jclass class, jint displayID, jint w, jint h, jint bpp, jint refrate)
269 271 {
270 272 JNF_COCOA_ENTER(env);
271 273 CFArrayRef allModes = getAllValidDisplayModes(displayID);
272 274 CGDisplayModeRef closestMatch = getBestModeForParameters(allModes, (int)w, (int)h, (int)bpp, (int)refrate);
273 275
274 276 __block CGError retCode = kCGErrorSuccess;
275 277 if (closestMatch != NULL) {
276 278 CGDisplayModeRetain(closestMatch);
277 279 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
278 280 CGDisplayConfigRef config;
279 281 retCode = CGBeginDisplayConfiguration(&config);
280 282 if (retCode == kCGErrorSuccess) {
281 283 CGConfigureDisplayWithDisplayMode(config, displayID, closestMatch, NULL);
282 284 retCode = CGCompleteDisplayConfiguration(config, kCGConfigureForAppOnly);
283 285 }
284 286 CGDisplayModeRelease(closestMatch);
285 287 }];
286 288 } else {
287 289 [JNFException raise:env as:kIllegalArgumentException reason:"Invalid display mode"];
288 290 }
289 291
290 292 if (retCode != kCGErrorSuccess){
291 293 [JNFException raise:env as:kIllegalArgumentException reason:"Unable to set display mode!"];
292 294 }
293 295 CFRelease(allModes);
294 296 JNF_COCOA_EXIT(env);
295 297 }
296 298 /*
297 299 * Class: sun_awt_CGraphicsDevice
298 300 * Method: nativeGetDisplayMode
299 301 * Signature: (I)Ljava/awt/DisplayMode
300 302 */
301 303 JNIEXPORT jobject JNICALL
302 304 Java_sun_awt_CGraphicsDevice_nativeGetDisplayMode
303 305 (JNIEnv *env, jclass class, jint displayID)
304 306 {
305 307 jobject ret = NULL;
306 308 // CGDisplayCopyDisplayMode can return NULL if displayID is invalid
307 309 CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID);
308 310 ret = createJavaDisplayMode(currentMode, env);
309 311 CGDisplayModeRelease(currentMode);
310 312 return ret;
311 313 }
312 314
313 315 /*
314 316 * Class: sun_awt_CGraphicsDevice
315 317 * Method: nativeGetDisplayMode
316 318 * Signature: (I)[Ljava/awt/DisplayModes
317 319 */
318 320 JNIEXPORT jobjectArray JNICALL
319 321 Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes
320 322 (JNIEnv *env, jclass class, jint displayID)
321 323 {
322 324 jobjectArray jreturnArray = NULL;
323 325 JNF_COCOA_ENTER(env);
324 326 CFArrayRef allModes = getAllValidDisplayModes(displayID);
325 327
326 328 CFIndex numModes = allModes ? CFArrayGetCount(allModes): 0;
327 329 static JNF_CLASS_CACHE(jc_DisplayMode, "java/awt/DisplayMode");
328 330
329 331 jreturnArray = JNFNewObjectArray(env, &jc_DisplayMode, (jsize) numModes);
330 332 if (!jreturnArray) {
331 333 NSLog(@"CGraphicsDevice can't create java array of DisplayMode objects");
332 334 return nil;
333 335 }
334 336
335 337 CFIndex n;
336 338 for (n=0; n < numModes; n++) {
337 339 CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n);
338 340 if (cRef != NULL) {
339 341 jobject oneMode = createJavaDisplayMode(cRef, env);
340 342 (*env)->SetObjectArrayElement(env, jreturnArray, n, oneMode);
341 343 if ((*env)->ExceptionOccurred(env)) {
342 344 (*env)->ExceptionDescribe(env);
343 345 (*env)->ExceptionClear(env);
344 346 continue;
345 347 }
346 348 (*env)->DeleteLocalRef(env, oneMode);
347 349 }
348 350 }
349 351 if (allModes) {
350 352 CFRelease(allModes);
351 353 }
352 354 JNF_COCOA_EXIT(env);
353 355
354 356 return jreturnArray;
355 357 }
356 358
357 359 /*
358 360 * Class: sun_awt_CGraphicsDevice
359 361 * Method: nativeGetScaleFactor
360 362 * Signature: (I)D
361 363 */
362 364 JNIEXPORT jdouble JNICALL
363 365 Java_sun_awt_CGraphicsDevice_nativeGetScaleFactor
364 366 (JNIEnv *env, jclass class, jint displayID)
365 367 {
366 368 __block jdouble ret = 1.0f;
367 369
368 370 JNF_COCOA_ENTER(env);
369 371
370 372 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
371 373 NSArray *screens = [NSScreen screens];
372 374 for (NSScreen *screen in screens) {
373 375 NSDictionary *screenInfo = [screen deviceDescription];
374 376 NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"];
375 377 if ([screenID unsignedIntValue] == displayID){
↓ open down ↓ |
337 lines elided |
↑ open up ↑ |
376 378 if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
377 379 ret = [screen backingScaleFactor];
378 380 }
379 381 break;
380 382 }
381 383 }
382 384 }];
383 385
384 386 JNF_COCOA_EXIT(env);
385 387 return ret;
386 -}
388 +}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX