Compare commits

...

109 Commits

Author SHA1 Message Date
Alexey Ushakov
da19b1c201 JBR-8738 Vulkan: Optimize ISO_BLIT
Remove unnecessary wait
2025-07-15 15:09:10 +02:00
Nikita Gubarkov
06cc75d80b JBR-8738 Vulkan: Optimize ISO_BLIT 2025-07-08 21:33:29 +02:00
Vitaly Provodin
203aad0e7d update exclude list on results of 21.0.7_b1050.5 test runs 2025-07-04 15:56:19 +04:00
Vitaly Provodin
fa662e668a JBR-8626 exclude java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java from Wayland runs 2025-07-04 15:56:18 +04:00
Nikita Gubarkov
f4eed0aabf JBR-9060 Vulkan: Fix MASK_FILL artifacts
Change local maskPos calculation from integer to floating point subtraction.
2025-07-03 19:25:19 +02:00
Alexey Ushakov
c43a8e77a9 JBR-9039 Vulkan: build failure on no vulkan build
Added native stubs for non vulkan builds
2025-07-03 16:34:11 +02:00
Gustavo Fão Valvassori
44c769baf2 JBR-9035 Support RTL on Decorated Window Title Bar (#540) 2025-07-02 10:54:02 +02:00
Alexey Ushakov
d65e4f3a69 JBR-8911 Backport: 8304825: MacOS metal pipeline - window isn't painted if created during display sleep
Adjusting OpenJDK patch for display link

(cherry picked from commit d1f83aace469f3fdc7e07e00dba9348560accb32)
2025-07-01 18:36:44 +02:00
Nikita Tsarev
01a88fa82d JBR-9043: Return null from getPlatformImageBytesForFormat for images with unknown extents on macOS 2025-07-01 11:26:33 +02:00
Nikita Tsarev
224651121f JBR-9044: Use getPlatformImageBytes to transfer TIFF images on macOS 2025-06-30 14:52:10 +02:00
Nikita Tsarev
333dbcb00f JBR-8952: Respect data flavor when encoding images on macOS 2025-06-27 12:21:11 +02:00
Nikita Gubarkov
c874bfb819 JBR-8737 Vulkan: Respect nonCoherentAtomSize in allocator 2025-06-26 20:42:37 +02:00
Alexey Ushakov
f14bfe0de9 JBR-7725 Vulkan: low performance in SwingMark
Removed extra synchronization in blits and extra copy

(cherry picked from commit 5411f2a1df5e6a6ed60c27837b414799b80d6fa5)
2025-06-26 19:21:41 +02:00
Alexey Ushakov
e948e68a1c JBR-9037 Vulkan: NPE in SwingMark
Added VKOffscreenGraphicsConfig check into UnixSurfaceManagerFactory
2025-06-26 17:44:12 +02:00
Alexey Ushakov
a40497a1a1 JBR-8479 Support Vulkan accelerated mode in perf scripts
Added the new option, minor refactoring

(cherry picked from commit b894b5fa96180c43d7a3f48d5c8b3ca35628b532)
2025-06-26 17:44:12 +02:00
Vitaly Provodin
221844284c JBR-7566 apply standard measurement scripts to Render
(cherry picked from commit be24b3e8ed)
(cherry picked from commit 64e4a227097331d53d9ec35172b5dfeaaa16a5da)
2025-06-26 17:44:12 +02:00
Alexey Ushakov
8ce1865667 JBR-6612 Provide standard scripts for performance measurements
Backported J2DBench, RenderPerfTest and SwingMark scripts from main

(cherry picked from commit 6f1ecb9b47)
(cherry picked from commit 00db5a29669d23a78f7c7e23efe99df3f6ab8ba2)
(cherry picked from commit e1cf099c09)
(cherry picked from commit 559015f5493e1177a044ec848e5e414a7424c201)
(cherry picked from commit fe09bf671b)
(cherry picked from commit f6e5fa71f2ad4247adf0038efd16515fcce4fd18)
2025-06-26 17:44:12 +02:00
Maxim Kartashev
dfa2f93ded JBR-9002 Wayland: deadlock with J2DDemo 2025-06-24 17:19:31 +04:00
Maxim Kartashev
a70d004636 JBR-8994 Wayland test runs cause agents to reboot, cannot be completed 2025-06-24 17:19:27 +04:00
Maxim Kartashev
bcaea044f6 JBR-8990 Wayland: make sure activating surface is valid when performing toFront() 2025-06-24 17:19:14 +04:00
Maxim Kartashev
62e4696d1a JBR-8991 Wayland: javax/swing/JMenu/bug4342646.java: PopupMenu is incorrectly placed at left of menu 2025-06-24 17:19:09 +04:00
Maxim Kartashev
3dd9b5b323 JBR-8626 Wayland: window shadow 2025-06-24 17:19:01 +04:00
Maxim Kartashev
9d1557ed3c JBR-8626 Wayland: sub-surface support 2025-06-24 17:18:46 +04:00
Maxim Kartashev
b6f8f9f1b7 JBR-8626 Wayland: proper encapsulation for WLComponentPeer 2025-06-24 17:08:37 +04:00
Maxim Kartashev
548521e162 JBR-8626 Wayland: uniform data access synhronization for WLComponentPeer 2025-06-24 17:08:30 +04:00
Maxim Kartashev
633895e1d8 JBR-8626 Wayland: relocate rounded corner painting to WLWindowPeer 2025-06-24 17:08:25 +04:00
Maxim Kartashev
fdc9dd44b6 JBR-8626 Wayland: fall-back client-side window decorations 2025-06-24 17:08:20 +04:00
Nikita Gubarkov
677d8edb87 JBR-8682 Vulkan: logicOpEnable Validation Error
(cherry picked from commit 196038a982b4bff0f96297ffd6734a14eb48bac4)
2025-06-23 15:17:11 +02:00
Nikita Gubarkov
52b213d96c JBR-8608 Vulkan: Cleanup capability checks
(cherry picked from commit 305cf4b2526dc6189e6715e7780ec9d8be44d1c6)
2025-06-23 15:14:41 +02:00
Nikita Gubarkov
df366c74c1 JBR-8601 Vulkan: Decouple from Wayland
(cherry picked from commit 91e7cb3969e7f06914cb4202cbe183d9e93c7d56)
2025-06-23 15:04:55 +02:00
Vladimir Dvorak
fc40612222 JBR-8890 DCEVM Handle exceptions in do_topological_class_sorting() 2025-06-21 10:51:04 +02:00
Nikita Gubarkov
8b7153234f JBR-8555 Vulkan: Do not flush the surface on transform change 2025-06-20 18:30:54 +02:00
Nikita Gubarkov
26f247ffb3 JBR-8553 Vulkan: Respect filtering hints in blits 2025-06-20 18:30:14 +02:00
Nikita Gubarkov
aa20c8b9f4 JBR-8525 Vulkan: Fix offscreen surface scaling 2025-06-20 18:29:38 +02:00
Nikita Gubarkov
120dd88dd0 JBR-8485 Vulkan: Blit surface into itself 2025-06-20 18:27:28 +02:00
Nikita Gubarkov
bb371ce7b0 JBR-8478 Vulkan: Pull real supported formats from the device 2025-06-20 18:26:35 +02:00
Nikita Gubarkov
abbf53d08e JBR-8473 Vulkan: Support for various source blit formats via swizzling 2025-06-20 18:26:04 +02:00
Nikita Gubarkov
921053cda6 JBR-8472 Vulkan: Respect source alpha type in blit routines 2025-06-20 18:24:11 +02:00
Nikita Gubarkov
1b0348f1b9 JBR-8471 Vulkan: Reuse descriptor sets in blit routines 2025-06-20 17:03:28 +02:00
Nikita Gubarkov
8120022a66 JBR-8448 Vulkan: Cleanup & fix Sw->Surface blit 2025-06-20 17:01:12 +02:00
Nikita Gubarkov
ac68b628c7 JBR-8447 Vulkan: Implement multi-view images 2025-06-20 16:55:07 +02:00
Nikita Gubarkov
99d3227951 JBR-8442 Vulkan: Fix OPAQUE mode rendering 2025-06-20 16:00:20 +02:00
Nikita Gubarkov
9116f5b953 JBR-8441 Vulkan: Update CArrayUtil.h 2025-06-20 15:59:56 +02:00
Nikita Gubarkov
13ddb27c38 JBR-8440 Vulkan: Pass the surface format to native code 2025-06-20 15:58:51 +02:00
Nikita Gubarkov
6e0ea66116 JBR-8439 Vulkan: Cleanup Surface->Surface blit 2025-06-20 15:48:45 +02:00
Nikita Gubarkov
f6b0380fd9 JBR-8424 Vulkan: Format-aware Surface->Sw blit 2025-06-20 15:46:07 +02:00
Nikita Gubarkov
70a658f57a JBR-8423 Vulkan: Expose VKFormat on Java side 2025-06-20 15:43:05 +02:00
Nikita Gubarkov
8fd5f9c426 JBR-8413 Vulkan: Make surfaces VKGPU-aware 2025-06-20 14:58:38 +02:00
Nikita Gubarkov
03cf016f2d JBR-8412 Vulkan: Add generic offscreen GraphicsConfig implementation 2025-06-20 14:55:23 +02:00
Nikita Gubarkov
1e1e4b38c6 JBR-8411 Vulkan: Move generic VKGraphicsConfig implementation into shared code 2025-06-20 14:53:35 +02:00
Nikita Gubarkov
3b4da58e2c JBR-8410 Vulkan: Expose VKDevice on Java side 2025-06-20 12:54:46 +02:00
Nikita Gubarkov
1b439f8a98 JBR-8391 Vulkan: Split instance and device into separate files 2025-06-20 12:29:41 +02:00
Nikita Gubarkov
4516560f65 JBR-8363 Vulkan: Organize usage of FlushRenderPass and FlushSurface 2025-06-20 12:23:31 +02:00
Alexey Ushakov
4a94eadd90 JBR-8418 Vulkan: RenderPerfTest Image test does not work properly
Passed transform to VKRenderer code
Flush content of the destination surface
2025-06-19 18:06:01 +02:00
Alexey Ushakov
42db39fb4e JBR-8430 Vulkan: move RenderingContext into Renderer
Moved context to the VKRenderer
2025-06-19 18:04:23 +02:00
Alexey Ushakov
cb751d0b52 JBR-8398 Vulkan: refactor shader code to use transforms
Replaced normalization logic with transform matrix
2025-06-19 16:29:36 +02:00
Vitaly Provodin
f711061895 update exclude list on results of 21.0.7_b1038.54 test runs 2025-06-17 13:39:48 +04:00
Vladimir Lagunov
6d0eb24888 Revert "JBR-7700 Disable java.io over java.nio.file in JBR21 by default"
This reverts commit 54817b2e8d.
2025-06-11 13:37:46 +02:00
Vitaly Provodin
3c90ecd46c update exclude list on results of 21.0.7_b1034.51 test runs 2025-06-11 03:53:12 +04:00
Vladimir Lagunov
54817b2e8d JBR-7700 Disable java.io over java.nio.file in JBR21 by default
The feature is ready month ago, but every time some new test appears that prevents the feature from being deployed.

By disabling the flag, it becomes possible to roll out the new functionality with the ability to enable it. So, it becomes possible to start verifying the new feature easier.

Meanwhile, we'll keep trying to enable the new feature by default.
2025-06-10 15:54:30 +02:00
Vitaly Provodin
c70e17b88b update exclude list after updating agents 2025-06-07 05:07:43 +04:00
Nikita Tsarev
bcd6f0c9c0 fixup! JBR-5860: Implement drag-and-drop [WLToolkit] 2025-06-06 18:42:33 +02:00
Dmitry Drobotov
646d2e478f JBR-8490 Improve searching for scroll bars in ScrollAreaAccessibility.
Use JScrollPane.getVerticalScrollBar/getHorizontalScrollBar methods to look for scroll bars. In some cases a scroll bar might be not a direct child of the scroll area, but it can still be assigned to the vertical/horizontalScrollBar property.
2025-06-06 18:36:25 +02:00
Dmitry Drobotov
4214897d5e JBR-8408 Post accessibility value changed events for scroll bars
3rd party apps might want to subscribe for scroll bar value changed events to track scroll position. VoiceOver and Zoom don't react on these events.
2025-06-06 18:08:05 +02:00
Nikita Tsarev
189907d2ae JBR-5860: Implement drag-and-drop [WLToolkit] 2025-06-06 16:51:01 +02:00
Maxim Kartashev
4b17fcc46e JBR-8949 Wayland: java/awt/Gtk/GtkVersionTest/GtkVersionTest.java: Wrong GTK library version: null 2025-06-06 12:19:16 +04:00
Nikita Tsarev
03804770b6 JBR-8912: Fix pasting unicode content from clipboard [WLToolkit] 2025-06-05 13:43:35 +02:00
Vladimir Dvorak
1d0cbadf05 JBR-8850 DCEVM: Enable interface replacement 2025-06-04 22:13:03 +02:00
Vladimir Dvorak
8cfd55e764 JBR-8636 DCEVM - eagerly set new_version in MagicAccessorImpl 2025-06-04 22:12:42 +02:00
Vitaly Provodin
b06068de9c JBR-8589 permit the case when lambda's parent is from the CDS archive, add omitted Outer.java 2025-06-03 14:01:42 +04:00
Vladimir Lagunov
eb027e2bc9 JBR-8859 Fix assertion in jtreg:test/jdk/com/sun/jdi/SetLocalWhileThreadInNative.java
The test relied on hard-coded constant that knows internals of FileInputStream.read calls, and these internals changed in JBR-7700.
2025-06-03 11:28:56 +02:00
Maxim Kartashev
5fbd7f38e0 JBR-7087 Wayland: enable more GTK tests 2025-06-03 10:03:19 +04:00
Maxim Kartashev
44754c75f9 JBR-8918 Wayland: javax/swing/LookAndFeel/8145547/DemandGTK2.sh fails due to no libgtk found 2025-06-03 09:59:26 +04:00
Vladimir Lagunov
0bf04b04b0 JBR-8852 Let tests that tune MaxDirectMemorySize work with io over nio
The problem is that java.nio.file always creates a direct buffer inside, and it's unavoidable. However, it's avoidable to tune java.nio.file that way, that direct buffers are never cached for latter use. This trick helps with tests that expect to be exclusive owners of the whole direct memory.
2025-06-02 18:10:12 +02:00
Vitaly Provodin
ca69af5c29 update exclude list on results of 21.0.7_b1021.38 test runs 2025-06-02 13:04:02 +04:00
Vitaly Provodin
1527cb78dd clean up fixed issues from exclude lists 2025-05-30 08:30:58 +04:00
Vitaly Provodin
bd8b5fa16f update exclude list on results of 21.0.7_b1020.35 test runs 2025-05-26 09:17:32 +04:00
Nikita Tsarev
c53afaf1c6 fixup! JBR-8833: Refactor Wayland data device abstraction [WLToolkit] 2025-05-23 18:27:35 +02:00
Sergey Shelomentsev
81b393aa37 fixup! JBR-4154 use -V to sort versions 2025-05-23 18:26:43 +03:00
Nikita Tsarev
8b4249aa00 JBR-8833: Refactor Wayland data device abstraction [WLToolkit] 2025-05-23 12:40:01 +02:00
Vitaly Provodin
a8b4f08808 fixup! JBR-4154 fix extracting version info from sources 2025-05-23 12:35:37 +04:00
Vitaly Provodin
88532ca2e1 fixup! clean up fixed issues from exclude lists 2025-05-23 09:30:08 +04:00
Vitaly Provodin
4b01cab791 clean up fixed issues from exclude lists 2025-05-23 06:18:47 +04:00
Vitaly Provodin
971aaf09d7 fixup! update exclude list on results of 21.0.7_b992.24 test runs 2025-05-23 03:50:30 +04:00
Vitaly Provodin
219ad23c66 JBR-8589 disable CDS specifically for Linux-x86 2025-05-22 02:48:11 +04:00
Vitaly Provodin
20015bc3b7 JBR-8589 replace system CDS with an actual one for IntelliJ 2025-05-21 09:20:01 +04:00
Vitaly Provodin
20bfe049b3 update exclude list on results of 21.0.7_b992.24 test runs 2025-05-21 09:12:19 +04:00
Artem Bochkarev
e32b9d4ebc fixup! JBR-8548 Add possibility to build without out-of-process part in Linux. 2025-05-21 08:17:43 +04:00
Artem Bochkarev
8ec3e80317 JBR-8548 Add possibility to build without out-of-process part in Linux. 2025-05-20 20:30:54 +04:00
Maxim Kartashev
c1325a3735 JBR-6979 Modernize more WaitForSingleObject on Windows
Use -XX:+UnlockExperimentalVMOptions -XX:-UseModernSynchAPI
to switch back to the original implementation
2025-05-19 17:25:34 +03:00
Maxim Kartashev
cc2280fd08 fixup! JBR-8664 Optimize sun.nio.fs.WindowsPath.compareTo 2025-05-19 17:44:06 +04:00
Maxim Kartashev
af4d8df355 JBR-8643 Wayland: popup will not appear if located outside of parent window 2025-05-19 17:27:12 +04:00
Nikita Tsarev
8fe8fb8108 JBR-8685: Add new macOS 15.4 shortcuts to the system shortcuts API 2025-05-19 11:29:07 +02:00
Vladimir Lagunov
997c61fdc5 JBR-8664 Optimize sun.nio.fs.WindowsPath.compareTo 2025-05-19 11:24:05 +04:00
Vladimir Lagunov
1651aa4318 JBR-8664 Optimize sun.nio.fs.UnixPath.compareTo 2025-05-16 10:53:40 +04:00
Vladimir Dvorak
a6cdff5987 JBR-8316 DCEVM: Allow idnum to exceed total method count 2025-05-15 18:17:40 +02:00
Maxim Kartashev
5fc78ed3da JBR-8304 Wayland: UI/UnninstallUIMemoryLeaks/UnninstallUIMemoryLeaks.java throws HeadlessException: No X11 DISPLAY variable was set
Pass JVM options to sub-tests in a more reliable and uniform fashion
2025-05-15 16:59:51 +04:00
Vladimir Dvorak
e09479f433 JBR-8636 DCEVM: Fix crashes when multiple class redefinitions are processed simultaneously 2025-05-14 20:25:07 +02:00
bourgesl
d54ab6c19b JBR-8276: fixed CPlaformWindow.flushBuffers() to use LWCTooolkit.invokeAndWait() discarded when CGDisplayRegisterReconfigurationCallback() is in progress (ThreadUtilities.blockingThread + removed isWithinPowerTransition code)
- fixed CVDisplayLink management on wake-ups/sleep and display reconfiguration
- restored opengl changes
2025-05-14 17:27:26 +02:00
bourgesl
8c3a5c3252 JBR-8278: fixed performOnMainThreadWaiting run block condition to fix FullscreenWindowProps and NoResizeEventOnDMChangeTest tests 2025-05-14 17:06:49 +02:00
Maxim Kartashev
d08c6eb496 JBR-8700 Wayland: Glitchy resize in J2Ddemo 2025-05-14 18:27:33 +04:00
Vitaly Provodin
baf55e9e53 update exclude list on results of 21.0.7_b982.16 test runs 2025-05-14 05:51:46 +04:00
Vitaly Provodin
4482618c0b update exclude list on results of 21.0.7_b968.14 test runs 2025-05-09 04:42:54 +04:00
Sergey Shelomentsev
2c7e868474 JBR-5819 fix custom title bar tests 2025-05-06 23:38:47 +03:00
Nikita Gubarkov
510b4fa816 fixup! JBR-8673 Disable watch.desktop.geometry on excessive event count 2025-05-03 12:53:40 +02:00
Nikita Tsarev
8ee1a7eece JBR-8684: Fix for a buffer overrun when reading system hotkey configuration with unexpected shortcuts on macOS 2025-04-30 11:34:20 +02:00
Vitaly Provodin
99bb681fc4 update exclude list on results of 21.0.7_b968.7 test runs 2025-04-29 04:06:19 +04:00
Nikita Gubarkov
d474af791d JBR-8673 Disable watch.desktop.geometry on excessive event count 2025-04-28 16:12:30 +02:00
Vitaly Provodin
146591e096 update exclude list on results of 21.0.7 test runs 2025-04-26 03:36:16 +04:00
227 changed files with 19708 additions and 6134 deletions

View File

@@ -40,8 +40,6 @@ architecture=${3:-x64} # aarch64 or x64
check_bundle_type_maketest
tag_prefix="jbr-"
OPENJDK_TAG=$(git log --simplify-by-decoration --decorate=short --pretty=short | grep "$tag_prefix" | cut -d "(" -f2 | cut -d ")" -f1 | awk '{print $2}' | sort -t "-" -k 2 -g | tail -n 1 | tr -d ",")
VERSION_FEATURE=$(getVersionProp "DEFAULT_VERSION_FEATURE")
VERSION_INTERIM=$(getVersionProp "DEFAULT_VERSION_INTERIM")
VERSION_UPDATE=$(getVersionProp "DEFAULT_VERSION_UPDATE")
@@ -49,8 +47,15 @@ VERSION_PATCH=$(getVersionProp "DEFAULT_VERSION_PATCH")
[[ $VERSION_UPDATE = 0 ]] && JBSDK_VERSION="$VERSION_FEATURE" || JBSDK_VERSION="${VERSION_FEATURE}.${VERSION_INTERIM}.${VERSION_UPDATE}"
[[ $VERSION_PATCH = 0 ]] || JBSDK_VERSION="${VERSION_FEATURE}.${VERSION_INTERIM}.${VERSION_UPDATE}.${VERSION_PATCH}"
echo "##teamcity[setParameter name='env.JBSDK_VERSION' value='${JBSDK_VERSION}']"
JDK_BUILD_NUMBER=${JDK_BUILD_NUMBER:=$(echo $OPENJDK_TAG | awk -F "-|[+]" '{print $3}')}
tag_prefix="jbr-"
OPENJDK_TAG=$(git log --simplify-by-decoration --decorate=short --pretty=short | grep "${tag_prefix}${JBSDK_VERSION}" | cut -d "(" -f2 | cut -d ")" -f1 | awk '{print $2}' | sort -t "-" -k 2 -V -f | tail -n 1 | tr -d ",")
JDK_BUILD_NUMBER=$(echo $OPENJDK_TAG | awk -F "-|[+]" '{print $3}')
[ -z $JDK_BUILD_NUMBER ] && JDK_BUILD_NUMBER=1
re='^[0-9]+$'
if ! [[ $JDK_BUILD_NUMBER =~ $re ]] ; then
echo "error: JDK_BUILD_NUMBER Not a number: $JDK_BUILD_NUMBER"
JDK_BUILD_NUMBER=1
fi
echo "##teamcity[setParameter name='env.JDK_UPDATE_NUMBER' value='${JDK_BUILD_NUMBER}']"
VENDOR_NAME="JetBrains s.r.o."

View File

@@ -32,6 +32,13 @@ function do_configure {
--build=x86_64-unknown-linux-gnu \
--openjdk-target=x86_64-unknown-linux-gnu"
fi
if [ -n "${JCEF_BUILD_LEGACY:-}" ]; then
WITH_VULKAN=""
else
WITH_VULKAN="--with-vulkan"
fi
sh configure \
$WITH_DEBUG_LEVEL \
--with-vendor-name="$VENDOR_NAME" \
@@ -42,7 +49,7 @@ function do_configure {
--with-version-opt=b"$build_number" \
--with-boot-jdk="$BOOT_JDK" \
--enable-cds=yes \
--with-vulkan \
$WITH_VULKAN \
$LINUX_TARGET \
$DISABLE_WARNINGS_AS_ERRORS \
$STATIC_CONF_ARGS \
@@ -95,7 +102,9 @@ function create_image_bundle {
# jmod does not preserve file permissions (JDK-8173610)
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/jcef_helper ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/jcef_helper
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/cef_server ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/cef_server
if [ ! -n "${JCEF_BUILD_LEGACY:-}" ]; then
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/cef_server ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/cef_server
fi
echo Creating "$JBR".tar.gz ...

View File

@@ -12,6 +12,7 @@ set -x
#
source jb/project/tools/common/scripts/common.sh
ENABLE_CDS="no"
function do_configure {
linux32 bash configure \
@@ -24,7 +25,7 @@ function do_configure {
--with-version-opt=b"$build_number" \
--with-boot-jdk="$BOOT_JDK" \
$STATIC_CONF_ARGS \
--enable-cds=yes \
--enable-cds=$ENABLE_CDS \
$DISABLE_WARNINGS_AS_ERRORS \
$REPRODUCIBLE_BUILD_OPTS \
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
@@ -51,7 +52,7 @@ function create_image_bundle {
__cds_opt=''
if is_musl; then libc_type_suffix='musl-' ; fi
__cds_opt="--generate-cds-archive"
[ "${ENABLE_CDS}" == "yes" ] && __cds_opt="--generate-cds-archive"
[ "$bundle_type" == "fd" ] && [ "$__arch_name" == "$JBRSDK_BUNDLE" ] && __bundle_name=$__arch_name && fastdebug_infix="fastdebug-"
JBR=${__bundle_name}-${JBSDK_VERSION}-linux-${libc_type_suffix}x86-${fastdebug_infix}b${build_number}

View File

@@ -0,0 +1,267 @@
prog.verbose=disabled
prog.printresults=enabled
global.env.outputwidth=640
global.env.outputheight=480
global.env.runcount=5
global.env.repcount=0
global.env.testtime=2500
global.results.workunits=units
global.results.timeunits=sec
global.results.ratio=unitspersec
global.dest.offscreen=disabled
global.dest.frame.defaultframe=enabled
global.dest.frame.transframe=disabled
global.dest.frame.shapedframe=disabled
global.dest.frame.shapedtransframe=disabled
global.dest.compatimg.compatimg=disabled
global.dest.compatimg.opqcompatimg=disabled
global.dest.compatimg.bmcompatimg=disabled
global.dest.compatimg.transcompatimg=disabled
global.dest.volimg.volimg=disabled
global.dest.volimg.opqvolimg=disabled
global.dest.volimg.bmvolimg=disabled
global.dest.volimg.transvolimg=disabled
global.dest.bufimg.IntXrgb=disabled
global.dest.bufimg.IntArgb=disabled
global.dest.bufimg.IntArgbPre=disabled
global.dest.bufimg.3ByteBgr=disabled
global.dest.bufimg.ByteIndexed=disabled
global.dest.bufimg.ByteGray=disabled
global.dest.bufimg.4ByteAbgr=disabled
global.dest.bufimg.4ByteAbgrPre=disabled
global.dest.bufimg.custom=disabled
graphics.opts.anim=2
graphics.opts.sizes=250
graphics.opts.alpharule=SrcOver
graphics.opts.transform=ident
graphics.opts.extraalpha=Off
graphics.opts.xormode=Off
graphics.opts.clip=Off
graphics.opts.renderhint=Default
graphics.render.opts.paint=random
graphics.render.opts.alphacolor=Off
graphics.render.opts.antialias=On
graphics.render.opts.stroke=width1
graphics.render.tests.drawLine=disabled
graphics.render.tests.drawLineHoriz=disabled
graphics.render.tests.drawLineVert=disabled
graphics.render.tests.fillRect=disabled
graphics.render.tests.drawRect=disabled
graphics.render.tests.fillOval=disabled
graphics.render.tests.drawOval=disabled
graphics.render.tests.fillPoly=disabled
graphics.render.tests.drawPoly=enabled
graphics.render.tests.shape.fillCubic=disabled
graphics.render.tests.shape.drawCubic=disabled
graphics.render.tests.shape.fillEllipse2D=disabled
graphics.render.tests.shape.drawEllipse2D=disabled
graphics.imaging.src.offscr.opaque=disabled
graphics.imaging.src.offscr.bitmask=disabled
graphics.imaging.src.offscr.translucent=disabled
graphics.imaging.src.opqcompatimg.opaque=disabled
graphics.imaging.src.opqcompatimg.bitmask=disabled
graphics.imaging.src.opqcompatimg.translucent=disabled
graphics.imaging.src.bmcompatimg.opaque=disabled
graphics.imaging.src.bmcompatimg.bitmask=disabled
graphics.imaging.src.bmcompatimg.translucent=disabled
graphics.imaging.src.transcompatimg.opaque=disabled
graphics.imaging.src.transcompatimg.bitmask=disabled
graphics.imaging.src.transcompatimg.translucent=disabled
graphics.imaging.src.opqvolimg.opaque=disabled
graphics.imaging.src.opqvolimg.bitmask=disabled
graphics.imaging.src.opqvolimg.translucent=disabled
graphics.imaging.src.bmvolimg.opaque=disabled
graphics.imaging.src.bmvolimg.bitmask=disabled
graphics.imaging.src.bmvolimg.translucent=disabled
graphics.imaging.src.transvolimg.opaque=disabled
graphics.imaging.src.transvolimg.bitmask=disabled
graphics.imaging.src.transvolimg.translucent=disabled
graphics.imaging.src.bufimg.IntXrgb.opaque=disabled
graphics.imaging.src.bufimg.IntXrgb.bitmask=disabled
graphics.imaging.src.bufimg.IntXrgb.translucent=disabled
graphics.imaging.src.bufimg.IntArgb.opaque=disabled
graphics.imaging.src.bufimg.IntArgb.bitmask=disabled
graphics.imaging.src.bufimg.IntArgb.translucent=disabled
graphics.imaging.src.bufimg.IntArgbPre.opaque=disabled
graphics.imaging.src.bufimg.IntArgbPre.bitmask=disabled
graphics.imaging.src.bufimg.IntArgbPre.translucent=disabled
graphics.imaging.src.bufimg.ByteGray.opaque=disabled
graphics.imaging.src.bufimg.ByteGray.bitmask=disabled
graphics.imaging.src.bufimg.ByteGray.translucent=disabled
graphics.imaging.src.bufimg.3ByteBgr.opaque=disabled
graphics.imaging.src.bufimg.3ByteBgr.bitmask=disabled
graphics.imaging.src.bufimg.3ByteBgr.translucent=disabled
graphics.imaging.src.bufimg.4ByteAbgr.opaque=disabled
graphics.imaging.src.bufimg.4ByteAbgr.bitmask=disabled
graphics.imaging.src.bufimg.4ByteAbgr.translucent=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.opaque=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.bitmask=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.translucent=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.opaque=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.bitmask=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.translucent=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.opaque=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.bitmask=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.translucent=disabled
graphics.imaging.benchmarks.opts.interpolation=Nearest neighbor
graphics.imaging.benchmarks.opts.touchsrc=Off
graphics.imaging.benchmarks.tests.drawimage=disabled
graphics.imaging.benchmarks.tests.drawimagebg=disabled
graphics.imaging.benchmarks.tests.drawimagescaleup=disabled
graphics.imaging.benchmarks.tests.drawimagescaledown=disabled
graphics.imaging.benchmarks.tests.drawimagescalesplit=disabled
graphics.imaging.benchmarks.tests.drawimagetxform=disabled
graphics.imaging.imageops.opts.op=convolve3x3zero
graphics.imaging.imageops.tests.graphics2d.drawimageop=disabled
graphics.imaging.imageops.tests.bufimgop.filternull=disabled
graphics.imaging.imageops.tests.bufimgop.filtercached=disabled
graphics.imaging.imageops.tests.rasterop.filternull=disabled
graphics.imaging.imageops.tests.rasterop.filtercached=disabled
graphics.misc.copytests.copyAreaVert=disabled
graphics.misc.copytests.copyAreaHoriz=disabled
graphics.misc.copytests.copyAreaDiag=disabled
pixel.opts.renderto=Off
pixel.opts.renderfrom=Off
pixel.src.1BitBinary=disabled
pixel.src.2BitBinary=disabled
pixel.src.4BitBinary=disabled
pixel.src.ByteIndexed=disabled
pixel.src.ByteGray=disabled
pixel.src.Short555=disabled
pixel.src.Short565=disabled
pixel.src.ShortGray=disabled
pixel.src.3ByteBgr=disabled
pixel.src.4ByteAbgr=disabled
pixel.src.IntXrgb=disabled
pixel.src.IntXbgr=disabled
pixel.src.IntArgb=disabled
pixel.bimgtests.getrgb=disabled
pixel.bimgtests.setrgb=disabled
pixel.rastests.getdataelem=disabled
pixel.rastests.setdataelem=disabled
pixel.rastests.getpixel=disabled
pixel.rastests.setpixel=disabled
pixel.dbtests.getelem=disabled
pixel.dbtests.setelem=disabled
text.opts.data.tlength=16
text.opts.data.tscript=english
text.opts.font.fname=serif,physical
text.opts.font.fstyle=0
text.opts.font.fsize=13.0
text.opts.font.ftx=Identity
text.opts.graphics.textaa=Off
text.opts.graphics.tfm=Off
text.opts.graphics.gaa=Off
text.opts.graphics.gtx=Identity
text.opts.advopts.gvstyle=0
text.opts.advopts.tlruns=1
text.opts.advopts.maptype=FONT
text.Rendering.tests.drawString=disabled
text.Rendering.tests.drawChars=disabled
text.Rendering.tests.drawBytes=disabled
text.Rendering.tests.drawGlyphVectors=disabled
text.Rendering.tests.drawTextLayout=disabled
text.Measuring.tests.stringWidth=disabled
text.Measuring.tests.stringBounds=disabled
text.Measuring.tests.charsWidth=disabled
text.Measuring.tests.charsBounds=disabled
text.Measuring.tests.fontcandisplay=disabled
text.Measuring.tests.gvWidth=disabled
text.Measuring.tests.gvLogicalBounds=disabled
text.Measuring.tests.gvVisualBounds=disabled
text.Measuring.tests.gvPixelBounds=disabled
text.Measuring.tests.gvOutline=disabled
text.Measuring.tests.gvGlyphLogicalBounds=disabled
text.Measuring.tests.gvGlyphVisualBounds=disabled
text.Measuring.tests.gvGlyphPixelBounds=disabled
text.Measuring.tests.gvGlyphOutline=disabled
text.Measuring.tests.gvGlyphTransform=disabled
text.Measuring.tests.gvGlyphMetrics=disabled
text.Measuring.tests.tlAdvance=disabled
text.Measuring.tests.tlAscent=disabled
text.Measuring.tests.tlBounds=disabled
text.Measuring.tests.tlGetCaretInfo=disabled
text.Measuring.tests.tlGetNextHit=disabled
text.Measuring.tests.tlGetCaretShape=disabled
text.Measuring.tests.tlGetLogicalHighlightShape=disabled
text.Measuring.tests.tlHitTest=disabled
text.Measuring.tests.tlOutline=disabled
text.construction.tests.gvfromfontstring=disabled
text.construction.tests.gvfromfontchars=disabled
text.construction.tests.gvfromfontci=disabled
text.construction.tests.gvfromfontglyphs=disabled
text.construction.tests.gvfromfontlayout=disabled
text.construction.tests.tlfromfont=disabled
text.construction.tests.tlfrommap=disabled
imageio.opts.size=250
imageio.opts.content=photo
imageio.input.opts.general.source.file=disabled
imageio.input.opts.general.source.url=disabled
imageio.input.opts.general.source.byteArray=disabled
imageio.input.opts.imageio.useCache=Off
imageio.input.image.toolkit.opts.format=
imageio.input.image.toolkit.tests.createImage=disabled
imageio.input.image.imageio.opts.format=
imageio.input.image.imageio.tests.imageioRead=disabled
imageio.input.image.imageio.reader.opts.seekForwardOnly=On
imageio.input.image.imageio.reader.opts.ignoreMetadata=On
imageio.input.image.imageio.reader.opts.installListener=Off
imageio.input.image.imageio.reader.tests.read=disabled
imageio.input.image.imageio.reader.tests.getImageMetadata=disabled
imageio.input.stream.tests.construct=disabled
imageio.input.stream.tests.read=disabled
imageio.input.stream.tests.readByteArray=disabled
imageio.input.stream.tests.readFullyByteArray=disabled
imageio.input.stream.tests.readBit=disabled
imageio.input.stream.tests.readByte=disabled
imageio.input.stream.tests.readUnsignedByte=disabled
imageio.input.stream.tests.readShort=disabled
imageio.input.stream.tests.readUnsignedShort=disabled
imageio.input.stream.tests.readInt=disabled
imageio.input.stream.tests.readUnsignedInt=disabled
imageio.input.stream.tests.readFloat=disabled
imageio.input.stream.tests.readLong=disabled
imageio.input.stream.tests.readDouble=disabled
imageio.input.stream.tests.skipBytes=disabled
imageio.output.opts.general.dest.file=disabled
imageio.output.opts.general.dest.byteArray=disabled
imageio.output.opts.imageio.useCache=Off
imageio.output.image.imageio.opts.format=
imageio.output.image.imageio.tests.imageioWrite=disabled
imageio.output.image.imageio.writer.opts.installListener=Off
imageio.output.image.imageio.writer.tests.write=disabled
imageio.output.stream.tests.construct=disabled
imageio.output.stream.tests.write=disabled
imageio.output.stream.tests.writeByteArray=disabled
imageio.output.stream.tests.writeBit=disabled
imageio.output.stream.tests.writeByte=disabled
imageio.output.stream.tests.writeShort=disabled
imageio.output.stream.tests.writeInt=disabled
imageio.output.stream.tests.writeFloat=disabled
imageio.output.stream.tests.writeLong=disabled
imageio.output.stream.tests.writeDouble=disabled
cmm.opts.profiles=1001
cmm.colorconv.data.fromRGB=disabled
cmm.colorconv.data.toRGB=disabled
cmm.colorconv.data.fromCIEXYZ=disabled
cmm.colorconv.data.toCIEXYZ=disabled
cmm.colorconv.ccop.ccopOptions.size=250
cmm.colorconv.ccop.ccopOptions.content=photo
cmm.colorconv.ccop.ccopOptions.srcType=INT_RGB
cmm.colorconv.ccop.ccopOptions.dstType=INT_RGB
cmm.colorconv.ccop.op_img=disabled
cmm.colorconv.ccop.op_rst=disabled
cmm.colorconv.ccop.op_draw=disabled
cmm.colorconv.embed.embedOptions.Images=512x512
cmm.colorconv.embed.embd_img_read=disabled
cmm.profiles.getHeader=disabled
cmm.profiles.getNumComponents=disabled

View File

@@ -0,0 +1,267 @@
prog.verbose=disabled
prog.printresults=enabled
global.env.outputwidth=640
global.env.outputheight=480
global.env.runcount=5
global.env.repcount=0
global.env.testtime=2500
global.results.workunits=units
global.results.timeunits=sec
global.results.ratio=unitspersec
global.dest.offscreen=disabled
global.dest.frame.defaultframe=enabled
global.dest.frame.transframe=disabled
global.dest.frame.shapedframe=disabled
global.dest.frame.shapedtransframe=disabled
global.dest.compatimg.compatimg=disabled
global.dest.compatimg.opqcompatimg=disabled
global.dest.compatimg.bmcompatimg=disabled
global.dest.compatimg.transcompatimg=disabled
global.dest.volimg.volimg=disabled
global.dest.volimg.opqvolimg=disabled
global.dest.volimg.bmvolimg=disabled
global.dest.volimg.transvolimg=disabled
global.dest.bufimg.IntXrgb=disabled
global.dest.bufimg.IntArgb=disabled
global.dest.bufimg.IntArgbPre=disabled
global.dest.bufimg.3ByteBgr=disabled
global.dest.bufimg.ByteIndexed=disabled
global.dest.bufimg.ByteGray=disabled
global.dest.bufimg.4ByteAbgr=disabled
global.dest.bufimg.4ByteAbgrPre=disabled
global.dest.bufimg.custom=disabled
graphics.opts.anim=2
graphics.opts.sizes=250
graphics.opts.alpharule=SrcOver
graphics.opts.transform=ident
graphics.opts.extraalpha=Off
graphics.opts.xormode=Off
graphics.opts.clip=Off
graphics.opts.renderhint=Default
graphics.render.opts.paint=random
graphics.render.opts.alphacolor=Off
graphics.render.opts.antialias=Off
graphics.render.opts.stroke=width1
graphics.render.tests.drawLine=disabled
graphics.render.tests.drawLineHoriz=disabled
graphics.render.tests.drawLineVert=disabled
graphics.render.tests.fillRect=disabled
graphics.render.tests.drawRect=disabled
graphics.render.tests.fillOval=disabled
graphics.render.tests.drawOval=disabled
graphics.render.tests.fillPoly=disabled
graphics.render.tests.drawPoly=enabled
graphics.render.tests.shape.fillCubic=disabled
graphics.render.tests.shape.drawCubic=disabled
graphics.render.tests.shape.fillEllipse2D=disabled
graphics.render.tests.shape.drawEllipse2D=disabled
graphics.imaging.src.offscr.opaque=disabled
graphics.imaging.src.offscr.bitmask=disabled
graphics.imaging.src.offscr.translucent=disabled
graphics.imaging.src.opqcompatimg.opaque=disabled
graphics.imaging.src.opqcompatimg.bitmask=disabled
graphics.imaging.src.opqcompatimg.translucent=disabled
graphics.imaging.src.bmcompatimg.opaque=disabled
graphics.imaging.src.bmcompatimg.bitmask=disabled
graphics.imaging.src.bmcompatimg.translucent=disabled
graphics.imaging.src.transcompatimg.opaque=disabled
graphics.imaging.src.transcompatimg.bitmask=disabled
graphics.imaging.src.transcompatimg.translucent=disabled
graphics.imaging.src.opqvolimg.opaque=disabled
graphics.imaging.src.opqvolimg.bitmask=disabled
graphics.imaging.src.opqvolimg.translucent=disabled
graphics.imaging.src.bmvolimg.opaque=disabled
graphics.imaging.src.bmvolimg.bitmask=disabled
graphics.imaging.src.bmvolimg.translucent=disabled
graphics.imaging.src.transvolimg.opaque=disabled
graphics.imaging.src.transvolimg.bitmask=disabled
graphics.imaging.src.transvolimg.translucent=disabled
graphics.imaging.src.bufimg.IntXrgb.opaque=disabled
graphics.imaging.src.bufimg.IntXrgb.bitmask=disabled
graphics.imaging.src.bufimg.IntXrgb.translucent=disabled
graphics.imaging.src.bufimg.IntArgb.opaque=disabled
graphics.imaging.src.bufimg.IntArgb.bitmask=disabled
graphics.imaging.src.bufimg.IntArgb.translucent=disabled
graphics.imaging.src.bufimg.IntArgbPre.opaque=disabled
graphics.imaging.src.bufimg.IntArgbPre.bitmask=disabled
graphics.imaging.src.bufimg.IntArgbPre.translucent=disabled
graphics.imaging.src.bufimg.ByteGray.opaque=disabled
graphics.imaging.src.bufimg.ByteGray.bitmask=disabled
graphics.imaging.src.bufimg.ByteGray.translucent=disabled
graphics.imaging.src.bufimg.3ByteBgr.opaque=disabled
graphics.imaging.src.bufimg.3ByteBgr.bitmask=disabled
graphics.imaging.src.bufimg.3ByteBgr.translucent=disabled
graphics.imaging.src.bufimg.4ByteAbgr.opaque=disabled
graphics.imaging.src.bufimg.4ByteAbgr.bitmask=disabled
graphics.imaging.src.bufimg.4ByteAbgr.translucent=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.opaque=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.bitmask=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.translucent=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.opaque=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.bitmask=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.translucent=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.opaque=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.bitmask=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.translucent=disabled
graphics.imaging.benchmarks.opts.interpolation=Nearest neighbor
graphics.imaging.benchmarks.opts.touchsrc=Off
graphics.imaging.benchmarks.tests.drawimage=disabled
graphics.imaging.benchmarks.tests.drawimagebg=disabled
graphics.imaging.benchmarks.tests.drawimagescaleup=disabled
graphics.imaging.benchmarks.tests.drawimagescaledown=disabled
graphics.imaging.benchmarks.tests.drawimagescalesplit=disabled
graphics.imaging.benchmarks.tests.drawimagetxform=disabled
graphics.imaging.imageops.opts.op=convolve3x3zero
graphics.imaging.imageops.tests.graphics2d.drawimageop=disabled
graphics.imaging.imageops.tests.bufimgop.filternull=disabled
graphics.imaging.imageops.tests.bufimgop.filtercached=disabled
graphics.imaging.imageops.tests.rasterop.filternull=disabled
graphics.imaging.imageops.tests.rasterop.filtercached=disabled
graphics.misc.copytests.copyAreaVert=disabled
graphics.misc.copytests.copyAreaHoriz=disabled
graphics.misc.copytests.copyAreaDiag=disabled
pixel.opts.renderto=Off
pixel.opts.renderfrom=Off
pixel.src.1BitBinary=disabled
pixel.src.2BitBinary=disabled
pixel.src.4BitBinary=disabled
pixel.src.ByteIndexed=disabled
pixel.src.ByteGray=disabled
pixel.src.Short555=disabled
pixel.src.Short565=disabled
pixel.src.ShortGray=disabled
pixel.src.3ByteBgr=disabled
pixel.src.4ByteAbgr=disabled
pixel.src.IntXrgb=disabled
pixel.src.IntXbgr=disabled
pixel.src.IntArgb=disabled
pixel.bimgtests.getrgb=disabled
pixel.bimgtests.setrgb=disabled
pixel.rastests.getdataelem=disabled
pixel.rastests.setdataelem=disabled
pixel.rastests.getpixel=disabled
pixel.rastests.setpixel=disabled
pixel.dbtests.getelem=disabled
pixel.dbtests.setelem=disabled
text.opts.data.tlength=16
text.opts.data.tscript=english
text.opts.font.fname=serif,physical
text.opts.font.fstyle=0
text.opts.font.fsize=13.0
text.opts.font.ftx=Identity
text.opts.graphics.textaa=Off
text.opts.graphics.tfm=Off
text.opts.graphics.gaa=Off
text.opts.graphics.gtx=Identity
text.opts.advopts.gvstyle=0
text.opts.advopts.tlruns=1
text.opts.advopts.maptype=FONT
text.Rendering.tests.drawString=disabled
text.Rendering.tests.drawChars=disabled
text.Rendering.tests.drawBytes=disabled
text.Rendering.tests.drawGlyphVectors=disabled
text.Rendering.tests.drawTextLayout=disabled
text.Measuring.tests.stringWidth=disabled
text.Measuring.tests.stringBounds=disabled
text.Measuring.tests.charsWidth=disabled
text.Measuring.tests.charsBounds=disabled
text.Measuring.tests.fontcandisplay=disabled
text.Measuring.tests.gvWidth=disabled
text.Measuring.tests.gvLogicalBounds=disabled
text.Measuring.tests.gvVisualBounds=disabled
text.Measuring.tests.gvPixelBounds=disabled
text.Measuring.tests.gvOutline=disabled
text.Measuring.tests.gvGlyphLogicalBounds=disabled
text.Measuring.tests.gvGlyphVisualBounds=disabled
text.Measuring.tests.gvGlyphPixelBounds=disabled
text.Measuring.tests.gvGlyphOutline=disabled
text.Measuring.tests.gvGlyphTransform=disabled
text.Measuring.tests.gvGlyphMetrics=disabled
text.Measuring.tests.tlAdvance=disabled
text.Measuring.tests.tlAscent=disabled
text.Measuring.tests.tlBounds=disabled
text.Measuring.tests.tlGetCaretInfo=disabled
text.Measuring.tests.tlGetNextHit=disabled
text.Measuring.tests.tlGetCaretShape=disabled
text.Measuring.tests.tlGetLogicalHighlightShape=disabled
text.Measuring.tests.tlHitTest=disabled
text.Measuring.tests.tlOutline=disabled
text.construction.tests.gvfromfontstring=disabled
text.construction.tests.gvfromfontchars=disabled
text.construction.tests.gvfromfontci=disabled
text.construction.tests.gvfromfontglyphs=disabled
text.construction.tests.gvfromfontlayout=disabled
text.construction.tests.tlfromfont=disabled
text.construction.tests.tlfrommap=disabled
imageio.opts.size=250
imageio.opts.content=photo
imageio.input.opts.general.source.file=disabled
imageio.input.opts.general.source.url=disabled
imageio.input.opts.general.source.byteArray=disabled
imageio.input.opts.imageio.useCache=Off
imageio.input.image.toolkit.opts.format=
imageio.input.image.toolkit.tests.createImage=disabled
imageio.input.image.imageio.opts.format=
imageio.input.image.imageio.tests.imageioRead=disabled
imageio.input.image.imageio.reader.opts.seekForwardOnly=On
imageio.input.image.imageio.reader.opts.ignoreMetadata=On
imageio.input.image.imageio.reader.opts.installListener=Off
imageio.input.image.imageio.reader.tests.read=disabled
imageio.input.image.imageio.reader.tests.getImageMetadata=disabled
imageio.input.stream.tests.construct=disabled
imageio.input.stream.tests.read=disabled
imageio.input.stream.tests.readByteArray=disabled
imageio.input.stream.tests.readFullyByteArray=disabled
imageio.input.stream.tests.readBit=disabled
imageio.input.stream.tests.readByte=disabled
imageio.input.stream.tests.readUnsignedByte=disabled
imageio.input.stream.tests.readShort=disabled
imageio.input.stream.tests.readUnsignedShort=disabled
imageio.input.stream.tests.readInt=disabled
imageio.input.stream.tests.readUnsignedInt=disabled
imageio.input.stream.tests.readFloat=disabled
imageio.input.stream.tests.readLong=disabled
imageio.input.stream.tests.readDouble=disabled
imageio.input.stream.tests.skipBytes=disabled
imageio.output.opts.general.dest.file=disabled
imageio.output.opts.general.dest.byteArray=disabled
imageio.output.opts.imageio.useCache=Off
imageio.output.image.imageio.opts.format=
imageio.output.image.imageio.tests.imageioWrite=disabled
imageio.output.image.imageio.writer.opts.installListener=Off
imageio.output.image.imageio.writer.tests.write=disabled
imageio.output.stream.tests.construct=disabled
imageio.output.stream.tests.write=disabled
imageio.output.stream.tests.writeByteArray=disabled
imageio.output.stream.tests.writeBit=disabled
imageio.output.stream.tests.writeByte=disabled
imageio.output.stream.tests.writeShort=disabled
imageio.output.stream.tests.writeInt=disabled
imageio.output.stream.tests.writeFloat=disabled
imageio.output.stream.tests.writeLong=disabled
imageio.output.stream.tests.writeDouble=disabled
cmm.opts.profiles=1001
cmm.colorconv.data.fromRGB=disabled
cmm.colorconv.data.toRGB=disabled
cmm.colorconv.data.fromCIEXYZ=disabled
cmm.colorconv.data.toCIEXYZ=disabled
cmm.colorconv.ccop.ccopOptions.size=250
cmm.colorconv.ccop.ccopOptions.content=photo
cmm.colorconv.ccop.ccopOptions.srcType=INT_RGB
cmm.colorconv.ccop.ccopOptions.dstType=INT_RGB
cmm.colorconv.ccop.op_img=disabled
cmm.colorconv.ccop.op_rst=disabled
cmm.colorconv.ccop.op_draw=disabled
cmm.colorconv.embed.embedOptions.Images=512x512
cmm.colorconv.embed.embd_img_read=disabled
cmm.profiles.getHeader=disabled
cmm.profiles.getNumComponents=disabled

View File

@@ -0,0 +1,267 @@
prog.verbose=disabled
prog.printresults=enabled
global.env.outputwidth=640
global.env.outputheight=480
global.env.runcount=5
global.env.repcount=0
global.env.testtime=2500
global.results.workunits=units
global.results.timeunits=sec
global.results.ratio=unitspersec
global.dest.offscreen=disabled
global.dest.frame.defaultframe=enabled
global.dest.frame.transframe=disabled
global.dest.frame.shapedframe=disabled
global.dest.frame.shapedtransframe=disabled
global.dest.compatimg.compatimg=disabled
global.dest.compatimg.opqcompatimg=disabled
global.dest.compatimg.bmcompatimg=disabled
global.dest.compatimg.transcompatimg=disabled
global.dest.volimg.volimg=disabled
global.dest.volimg.opqvolimg=disabled
global.dest.volimg.bmvolimg=disabled
global.dest.volimg.transvolimg=disabled
global.dest.bufimg.IntXrgb=disabled
global.dest.bufimg.IntArgb=disabled
global.dest.bufimg.IntArgbPre=disabled
global.dest.bufimg.3ByteBgr=disabled
global.dest.bufimg.ByteIndexed=disabled
global.dest.bufimg.ByteGray=disabled
global.dest.bufimg.4ByteAbgr=disabled
global.dest.bufimg.4ByteAbgrPre=disabled
global.dest.bufimg.custom=disabled
graphics.opts.anim=2
graphics.opts.sizes=250
graphics.opts.alpharule=SrcOver
graphics.opts.transform=ident
graphics.opts.extraalpha=Off
graphics.opts.xormode=Off
graphics.opts.clip=Off
graphics.opts.renderhint=Default
graphics.render.opts.paint=single
graphics.render.opts.alphacolor=Off
graphics.render.opts.antialias=Off
graphics.render.opts.stroke=width1
graphics.render.tests.drawLine=disabled
graphics.render.tests.drawLineHoriz=disabled
graphics.render.tests.drawLineVert=disabled
graphics.render.tests.fillRect=disabled
graphics.render.tests.drawRect=disabled
graphics.render.tests.fillOval=disabled
graphics.render.tests.drawOval=disabled
graphics.render.tests.fillPoly=disabled
graphics.render.tests.drawPoly=enabled
graphics.render.tests.shape.fillCubic=disabled
graphics.render.tests.shape.drawCubic=disabled
graphics.render.tests.shape.fillEllipse2D=disabled
graphics.render.tests.shape.drawEllipse2D=disabled
graphics.imaging.src.offscr.opaque=disabled
graphics.imaging.src.offscr.bitmask=disabled
graphics.imaging.src.offscr.translucent=disabled
graphics.imaging.src.opqcompatimg.opaque=disabled
graphics.imaging.src.opqcompatimg.bitmask=disabled
graphics.imaging.src.opqcompatimg.translucent=disabled
graphics.imaging.src.bmcompatimg.opaque=disabled
graphics.imaging.src.bmcompatimg.bitmask=disabled
graphics.imaging.src.bmcompatimg.translucent=disabled
graphics.imaging.src.transcompatimg.opaque=disabled
graphics.imaging.src.transcompatimg.bitmask=disabled
graphics.imaging.src.transcompatimg.translucent=disabled
graphics.imaging.src.opqvolimg.opaque=disabled
graphics.imaging.src.opqvolimg.bitmask=disabled
graphics.imaging.src.opqvolimg.translucent=disabled
graphics.imaging.src.bmvolimg.opaque=disabled
graphics.imaging.src.bmvolimg.bitmask=disabled
graphics.imaging.src.bmvolimg.translucent=disabled
graphics.imaging.src.transvolimg.opaque=disabled
graphics.imaging.src.transvolimg.bitmask=disabled
graphics.imaging.src.transvolimg.translucent=disabled
graphics.imaging.src.bufimg.IntXrgb.opaque=disabled
graphics.imaging.src.bufimg.IntXrgb.bitmask=disabled
graphics.imaging.src.bufimg.IntXrgb.translucent=disabled
graphics.imaging.src.bufimg.IntArgb.opaque=disabled
graphics.imaging.src.bufimg.IntArgb.bitmask=disabled
graphics.imaging.src.bufimg.IntArgb.translucent=disabled
graphics.imaging.src.bufimg.IntArgbPre.opaque=disabled
graphics.imaging.src.bufimg.IntArgbPre.bitmask=disabled
graphics.imaging.src.bufimg.IntArgbPre.translucent=disabled
graphics.imaging.src.bufimg.ByteGray.opaque=disabled
graphics.imaging.src.bufimg.ByteGray.bitmask=disabled
graphics.imaging.src.bufimg.ByteGray.translucent=disabled
graphics.imaging.src.bufimg.3ByteBgr.opaque=disabled
graphics.imaging.src.bufimg.3ByteBgr.bitmask=disabled
graphics.imaging.src.bufimg.3ByteBgr.translucent=disabled
graphics.imaging.src.bufimg.4ByteAbgr.opaque=disabled
graphics.imaging.src.bufimg.4ByteAbgr.bitmask=disabled
graphics.imaging.src.bufimg.4ByteAbgr.translucent=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.opaque=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.bitmask=disabled
graphics.imaging.src.bufimg.4ByteAbgrPre.translucent=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.opaque=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.bitmask=disabled
graphics.imaging.src.bufimg.ByteIndexedBm.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntXrgb.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntArgb.translucent=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.opaque=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.bitmask=disabled
graphics.imaging.src.bufimg.unmanagedIntArgbPre.translucent=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.opaque=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.bitmask=disabled
graphics.imaging.src.bufimg.unmanaged3ByteBgr.translucent=disabled
graphics.imaging.benchmarks.opts.interpolation=Nearest neighbor
graphics.imaging.benchmarks.opts.touchsrc=Off
graphics.imaging.benchmarks.tests.drawimage=disabled
graphics.imaging.benchmarks.tests.drawimagebg=disabled
graphics.imaging.benchmarks.tests.drawimagescaleup=disabled
graphics.imaging.benchmarks.tests.drawimagescaledown=disabled
graphics.imaging.benchmarks.tests.drawimagescalesplit=disabled
graphics.imaging.benchmarks.tests.drawimagetxform=disabled
graphics.imaging.imageops.opts.op=convolve3x3zero
graphics.imaging.imageops.tests.graphics2d.drawimageop=disabled
graphics.imaging.imageops.tests.bufimgop.filternull=disabled
graphics.imaging.imageops.tests.bufimgop.filtercached=disabled
graphics.imaging.imageops.tests.rasterop.filternull=disabled
graphics.imaging.imageops.tests.rasterop.filtercached=disabled
graphics.misc.copytests.copyAreaVert=disabled
graphics.misc.copytests.copyAreaHoriz=disabled
graphics.misc.copytests.copyAreaDiag=disabled
pixel.opts.renderto=Off
pixel.opts.renderfrom=Off
pixel.src.1BitBinary=disabled
pixel.src.2BitBinary=disabled
pixel.src.4BitBinary=disabled
pixel.src.ByteIndexed=disabled
pixel.src.ByteGray=disabled
pixel.src.Short555=disabled
pixel.src.Short565=disabled
pixel.src.ShortGray=disabled
pixel.src.3ByteBgr=disabled
pixel.src.4ByteAbgr=disabled
pixel.src.IntXrgb=disabled
pixel.src.IntXbgr=disabled
pixel.src.IntArgb=disabled
pixel.bimgtests.getrgb=disabled
pixel.bimgtests.setrgb=disabled
pixel.rastests.getdataelem=disabled
pixel.rastests.setdataelem=disabled
pixel.rastests.getpixel=disabled
pixel.rastests.setpixel=disabled
pixel.dbtests.getelem=disabled
pixel.dbtests.setelem=disabled
text.opts.data.tlength=16
text.opts.data.tscript=english
text.opts.font.fname=serif,physical
text.opts.font.fstyle=0
text.opts.font.fsize=13.0
text.opts.font.ftx=Identity
text.opts.graphics.textaa=Off
text.opts.graphics.tfm=Off
text.opts.graphics.gaa=Off
text.opts.graphics.gtx=Identity
text.opts.advopts.gvstyle=0
text.opts.advopts.tlruns=1
text.opts.advopts.maptype=FONT
text.Rendering.tests.drawString=disabled
text.Rendering.tests.drawChars=disabled
text.Rendering.tests.drawBytes=disabled
text.Rendering.tests.drawGlyphVectors=disabled
text.Rendering.tests.drawTextLayout=disabled
text.Measuring.tests.stringWidth=disabled
text.Measuring.tests.stringBounds=disabled
text.Measuring.tests.charsWidth=disabled
text.Measuring.tests.charsBounds=disabled
text.Measuring.tests.fontcandisplay=disabled
text.Measuring.tests.gvWidth=disabled
text.Measuring.tests.gvLogicalBounds=disabled
text.Measuring.tests.gvVisualBounds=disabled
text.Measuring.tests.gvPixelBounds=disabled
text.Measuring.tests.gvOutline=disabled
text.Measuring.tests.gvGlyphLogicalBounds=disabled
text.Measuring.tests.gvGlyphVisualBounds=disabled
text.Measuring.tests.gvGlyphPixelBounds=disabled
text.Measuring.tests.gvGlyphOutline=disabled
text.Measuring.tests.gvGlyphTransform=disabled
text.Measuring.tests.gvGlyphMetrics=disabled
text.Measuring.tests.tlAdvance=disabled
text.Measuring.tests.tlAscent=disabled
text.Measuring.tests.tlBounds=disabled
text.Measuring.tests.tlGetCaretInfo=disabled
text.Measuring.tests.tlGetNextHit=disabled
text.Measuring.tests.tlGetCaretShape=disabled
text.Measuring.tests.tlGetLogicalHighlightShape=disabled
text.Measuring.tests.tlHitTest=disabled
text.Measuring.tests.tlOutline=disabled
text.construction.tests.gvfromfontstring=disabled
text.construction.tests.gvfromfontchars=disabled
text.construction.tests.gvfromfontci=disabled
text.construction.tests.gvfromfontglyphs=disabled
text.construction.tests.gvfromfontlayout=disabled
text.construction.tests.tlfromfont=disabled
text.construction.tests.tlfrommap=disabled
imageio.opts.size=250
imageio.opts.content=photo
imageio.input.opts.general.source.file=disabled
imageio.input.opts.general.source.url=disabled
imageio.input.opts.general.source.byteArray=disabled
imageio.input.opts.imageio.useCache=Off
imageio.input.image.toolkit.opts.format=
imageio.input.image.toolkit.tests.createImage=disabled
imageio.input.image.imageio.opts.format=
imageio.input.image.imageio.tests.imageioRead=disabled
imageio.input.image.imageio.reader.opts.seekForwardOnly=On
imageio.input.image.imageio.reader.opts.ignoreMetadata=On
imageio.input.image.imageio.reader.opts.installListener=Off
imageio.input.image.imageio.reader.tests.read=disabled
imageio.input.image.imageio.reader.tests.getImageMetadata=disabled
imageio.input.stream.tests.construct=disabled
imageio.input.stream.tests.read=disabled
imageio.input.stream.tests.readByteArray=disabled
imageio.input.stream.tests.readFullyByteArray=disabled
imageio.input.stream.tests.readBit=disabled
imageio.input.stream.tests.readByte=disabled
imageio.input.stream.tests.readUnsignedByte=disabled
imageio.input.stream.tests.readShort=disabled
imageio.input.stream.tests.readUnsignedShort=disabled
imageio.input.stream.tests.readInt=disabled
imageio.input.stream.tests.readUnsignedInt=disabled
imageio.input.stream.tests.readFloat=disabled
imageio.input.stream.tests.readLong=disabled
imageio.input.stream.tests.readDouble=disabled
imageio.input.stream.tests.skipBytes=disabled
imageio.output.opts.general.dest.file=disabled
imageio.output.opts.general.dest.byteArray=disabled
imageio.output.opts.imageio.useCache=Off
imageio.output.image.imageio.opts.format=
imageio.output.image.imageio.tests.imageioWrite=disabled
imageio.output.image.imageio.writer.opts.installListener=Off
imageio.output.image.imageio.writer.tests.write=disabled
imageio.output.stream.tests.construct=disabled
imageio.output.stream.tests.write=disabled
imageio.output.stream.tests.writeByteArray=disabled
imageio.output.stream.tests.writeBit=disabled
imageio.output.stream.tests.writeByte=disabled
imageio.output.stream.tests.writeShort=disabled
imageio.output.stream.tests.writeInt=disabled
imageio.output.stream.tests.writeFloat=disabled
imageio.output.stream.tests.writeLong=disabled
imageio.output.stream.tests.writeDouble=disabled
cmm.opts.profiles=1001
cmm.colorconv.data.fromRGB=disabled
cmm.colorconv.data.toRGB=disabled
cmm.colorconv.data.fromCIEXYZ=disabled
cmm.colorconv.data.toCIEXYZ=disabled
cmm.colorconv.ccop.ccopOptions.size=250
cmm.colorconv.ccop.ccopOptions.content=photo
cmm.colorconv.ccop.ccopOptions.srcType=INT_RGB
cmm.colorconv.ccop.ccopOptions.dstType=INT_RGB
cmm.colorconv.ccop.op_img=disabled
cmm.colorconv.ccop.op_rst=disabled
cmm.colorconv.ccop.op_draw=disabled
cmm.colorconv.embed.embedOptions.Images=512x512
cmm.colorconv.embed.embd_img_read=disabled
cmm.profiles.getHeader=disabled
cmm.profiles.getNumComponents=disabled

View File

@@ -0,0 +1,137 @@
export LC_ALL=C
ST=1 # sleep between iterations
# number of iterations (jvm spawned)
N=5
# number of repeats (within jvm)
R=3
type datamash 2>&1 > /dev/null ; ec=$?
if [ $ec -ne 0 ] ; then
echo "Missing datamash utility"
exit 1
fi
DATAMASH_CMD="datamash --format=%.2f -H count x min x q1 x median x q3 x max x mad x"
J2D_OPTS=""
OS=""
case "$OSTYPE" in
linux*) echo "Linux"
;;
darwin*) echo "OSX"
;;
*) echo "unknown: $OSTYPE"
exit 1
;;
esac
read -r -d '' RENDER_OPS_DOC << EOM
rendering_options:
-opengl # OpenGL pipeline (windows, linux, macOS)
-metal # Metal pipeline (macOS)
-vulkan # Vulkan pipeline (WLToolkit)
-accelsd # Vulkan full acceleration (WLToolkit, Vulkan)
-devnum num # Provide Vulkan device for rendering
-tk tk_name # AWT toolkit (linux: WLToolkit|XToolkit)
-scale # UI scale
-N num # Number of iterations (JVM runs)
-R num # Number of repeats in the test
EOM
while [ $# -ge 1 ] ; do
case "$1" in
-opengl) J2D_OPTS=$J2D_OPTS" -Dsun.java2d.opengl=true"
shift
;;
-metal) J2D_OPTS=$J2D_OPTS" -Dsun.java2d.metal=true"
shift
;;
-vulkan) J2D_OPTS=$J2D_OPTS" -Dsun.java2d.vulkan=true"
shift
;;
-accelsd) J2D_OPTS=$J2D_OPTS" -Dsun.java2d.vulkan.accelsd=true"
shift
;;
-devnum) shift
if [ $# -ge 1 ] ; then
J2D_OPTS=$J2D_OPTS" -Dsun.java2d.vulkan.deviceNumber="$1
shift
else
echo "Invalid parameters for -devnum option. Use: -devnum num"
exit 1
fi
;;
-tk) shift
if [ $# -ge 1 ] ; then
J2D_OPTS=$J2D_OPTS" -Dawt.toolkit.name="$1
shift
else
echo "Invalid parameters for -tk option. Use: -tk tkname"
exit 1
fi
;;
-N) shift
if [ $# -ge 1 ] ; then
N=$1
shift
else
echo "Invalid parameters for -N option. Use: -N <number>"
exit 1
fi
;;
-R) shift
if [ $# -ge 1 ] ; then
R=$1
shift
else
echo "Invalid parameters for -R option. Use: -R <number>"
exit 1
fi
;;
-scale) shift
if [ $# -ge 1 ] ; then
J2D_OPTS=$J2D_OPTS" -Dsun.java2d.uiScale="$1
shift
else
echo "Invalid parameters for -scale option. Use: -scale scale"
exit 1
fi
;;
-dSync) shift
if [ $# -ge 1 ] ; then
J2D_OPTS=$J2D_OPTS" -Dsun.java2d.metal.displaySync="$1
shift
else
echo "Invalid parameters for -dSync option. Use: -dSync [true|false]"
exit 1
fi
;;
-jdk) shift
if [ $# -ge 1 ] ; then
JAVA=$1/bin/java
shift
else
echo "Invalid parameters for -jdk option"
exit 1
fi
;;
*) break
;;
esac
done
if [ -z "$JAVA" ] ; then
BUILD_DIR=`find $BASE_DIR/../../../../build -name '*-release' -type d | head -n 1`
JAVA=`find $BUILD_DIR/images/jdk -name java -type f | head -n 1`
fi
JAVA_HOME=`dirname $JAVA`/../
"$JAVA" -version
LANG=C
WS_ROOT=$BASE_DIR/../../../..
echo "N: $N"
echo "R: $R"
echo "J2D_OPTS: $J2D_OPTS"

View File

@@ -0,0 +1,53 @@
#!/bin/bash
BASE_DIR=$(dirname "$0")
source $BASE_DIR/run_inc.sh
J2DBENCH_DIR=$WS_ROOT/src/demo/share/java2d/J2DBench
if [ -z "$J2DBENCH" ]; then
if [ ! -f "$J2DBENCH_DIR/dist/J2DBench.jar" ]; then
PATH=$JAVA_HOME/bin:$PATH make -C $J2DBENCH_DIR
fi
if [ ! -f "$J2DBENCH_DIR/dist/J2DBench.jar" ]; then
echo "Cannot build J2DBench. You may use J2DBench env variable instead pointing to the J2DBench.jar."
exit 1
fi
J2DBENCH=$J2DBENCH_DIR/dist/J2DBench.jar
fi
if [ $# -ne 1 ] ; then
echo "Usage: run_j2b.sh [rendering_options] bench_name"
echo
echo "bench_name: poly250 poly250-rand_col poly250-AA-rand_col"
echo ""
echo "$RENDER_OPS_DOC"
exit 2
fi
if [ ! -f "$BASE_DIR/j2dbopts_$1.txt" ]; then
echo "Unknown test: $1"
exit 1
fi
OPTS="j2dbopts_$1.txt"
#OPTS=j2dbopts_poly250.txt
#OPTS=j2dbopts_poly250-rand_col.txt
#OPTS=j2dbopts_poly250-AA-rand_col.txt
echo "OPTS: $OPTS"
for i in `seq $N`; do
if [ $i -eq 1 ]; then
echo x
fi
echo `$JAVA $J2D_OPTS -jar $J2DBENCH \
-batch -loadopts $BASE_DIR/$OPTS -saveres pl.res \
-title pl -desc pl | awk '/averaged/{print $3}' | head -n1`
if [ $i -ne $N ]; then
sleep $ST
fi
done | $DATAMASH_CMD | expand -t12

88
jb/project/tools/perf/run_rp.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/bash
#set -euo pipefail
#set -x
BASE_DIR=$(dirname "$0")
source $BASE_DIR/run_inc.sh
RENDERPERFTEST_DIR=$WS_ROOT/test/jdk/performance/client/RenderPerfTest
RENDERPERFTEST=""
if [ -z "$RENDERPERFTEST" ]; then
if [ ! -f "$RENDERPERFTEST_DIR/dist/RenderPerfTest.jar" ]; then
PATH=$JAVA_HOME/bin:$PATH make -C $RENDERPERFTEST_DIR
fi
if [ ! -f "$RENDERPERFTEST_DIR/dist/RenderPerfTest.jar" ]; then
echo "Cannot build RenderPerfTest. You may use RENDERPERFTEST env variable instead pointing to the RenderPerfTest.jar."
exit 1
fi
RENDERPERFTEST=$RENDERPERFTEST_DIR/dist/RenderPerfTest.jar
fi
TRACE=false
# removes leading hyphen
mode_param="${1/-}"
MODE="Robot"
while [ $# -ge 1 ] ; do
case "$1" in
-onscreen) MODE="Robot"
shift
;;
-volatile) MODE="Volatile"
shift
;;
-buffer) MODE="Buffer"
shift
;;
*) break
;;
esac
done
if [[ ($# -eq 1 && "$1" == "-help") || ($# -eq 0) ]] ; then
echo "Usage: run_rp.sh [rp_rendering_mode] [rendering_options] bench_name"
echo
echo "bench_name: ArgbSurfaceBlitImage ArgbSwBlitImage BgrSurfaceBlitImage BgrSwBlitImage"
echo " Image ImageAA Image_XOR VolImage VolImageAA"
echo " ClipFlatBox ClipFlatBoxAA ClipFlatOval ClipFlatOvalAA"
echo " FlatBox FlatBoxAA FlatOval FlatOvalAA FlatOval_XOR FlatQuad FlatQuadAA"
echo " RotatedBox RotatedBoxAA RotatedBox_XOR RotatedOval RotatedOvalAA"
echo " WiredBox WiredBoxAA WiredBubbles WiredBubblesAA WiredQuad WiredQuadAA"
echo " Lines LinesAA Lines_XOR"
echo " TextGray TextLCD TextLCD_XOR TextNoAA TextNoAA_XOR"
echo " LargeTextGray LargeTextLCD LargeTextNoAA WhiteTextGray WhiteTextLCD WhiteTextNoAA"
echo " LinGrad3RotatedOval LinGrad3RotatedOvalAA LinGradRotatedOval LinGradRotatedOvalAA"
echo " RadGrad3RotatedOval RadGrad3RotatedOvalAA"
echo ""
echo "rp_rendering_mode: "
echo " -onscreen : rendering to the window and check it using Robot"
echo " -volatile : rendering to volatile image (default)"
echo " -buffer : rendering to buffered image"
echo "$RENDER_OPS_DOC"
exit 2
fi
OPTS=""
# use time + repeat
OPTS="$OPTS -t -n=$N -e$MODE $1"
echo "OPTS: $OPTS"
echo "Unit: Milliseconds (not FPS), lower is better"
for i in `seq $R` ; do
if [ $i -eq 1 ]; then
echo x
fi
# echo "[debug] " + "test run"
# $JAVA $J2D_OPTS -DTRACE=$TRACE \
# -jar $RENDERPERFTEST $OPTS 2>&1 | awk '/'$1'/{print $3 }' | tee test_run.log
$JAVA $J2D_OPTS -DTRACE=$TRACE \
-jar $RENDERPERFTEST $OPTS -v 2>&1 | tee render_$1_${mode_param}_$i.log | grep -v "^#" | tail -n 1 | \
awk '{print $3 }'
if [ $i -ne $N ]; then
sleep $ST
fi
done | $DATAMASH_CMD | expand -t12 | tee render_$1_${mode_param}.log

39
jb/project/tools/perf/run_sm.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/bash
BASE_DIR=$(dirname "$0")
source $BASE_DIR/run_inc.sh
SWINGMARK_DIR=$WS_ROOT/test/jdk/performance/client/SwingMark
if [ -z "$SWINGMARK" ]; then
if [ ! -f "$SWINGMARK_DIR/dist/SwingMark.jar" ]; then
PATH=$JAVA_HOME/bin:$PATH make -C $SWINGMARK_DIR
fi
if [ ! -f "$SWINGMARK_DIR/dist/SwingMark.jar" ]; then
echo "Cannot build SwingMark. You may use SWINGMARK env variable instead pointing to the SwingMark.jar."
exit 1
fi
SWINGMARK=$SWINGMARK_DIR/dist/SwingMark.jar
fi
if [ $# -eq 1 -a "$1" == "--help" ] ; then
shift
echo "Usage: run_sm [rendering_options]"
echo ""
echo "$RENDER_OPS_DOC"
exit 0
fi
for i in `seq $N` ; do
if [ $i -eq 1 ]; then
echo x
fi
# SwingMark gives 1 global 'Score: <value>'
echo `$JAVA $J2D_OPTS -jar $BASE_DIR/../../../../test/jdk/performance/client/SwingMark/dist/SwingMark.jar \
-r $R -q -lf javax.swing.plaf.metal.MetalLookAndFeel | awk '/Score/{print $2}'`
if [ $i -ne $N ]; then
sleep $ST
fi
done | $DATAMASH_CMD | expand -t12

View File

@@ -68,7 +68,7 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \
-Duser.language=en -Duser.country=US \
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
build.tools.classlist.HelloClasslist $(LOG_DEBUG)
build.tools.classlist.HelloClasslist jdk/src/classes/build/tools/classlist/clear.classlist $(LOG_DEBUG)
$(GREP) -v HelloClasslist $@.raw > $@.interim
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -Xshare:dump \
-XX:SharedClassListFile=$@.interim -XX:SharedArchiveFile=$@.jsa \
@@ -79,7 +79,7 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST
-Duser.language=en -Duser.country=US \
--module-path $(SUPPORT_OUTPUTDIR)/classlist.jar \
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
build.tools.classlist.HelloClasslist \
build.tools.classlist.HelloClasslist jdk/src/classes/build/tools/classlist/clear.classlist \
2> $(LINK_OPT_DIR)/stderr > $(JLI_TRACE_FILE) \
|| ( \
exitcode=$$? ; \

114
make/autoconf/lib-vulkan.m4 Normal file
View File

@@ -0,0 +1,114 @@
#
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2025, JetBrains s.r.o.. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
################################################################################
# Setup vulkan
################################################################################
AC_DEFUN_ONCE([LIB_SETUP_VULKAN],
[
AC_ARG_WITH(vulkan, [AS_HELP_STRING([--with-vulkan],
[specify whether we use vulkan])])
AC_ARG_WITH(vulkan-include, [AS_HELP_STRING([--with-vulkan-include],
[specify directory for the vulkan include files ({with-vulkan-include}/vulkan/vulkan.h)])])
AC_ARG_WITH(vulkan-shader-compiler, [AS_HELP_STRING([--with-vulkan-shader-compiler],
[specify which shader compiler to use: glslc/glslangValidator])])
VULKAN_ENABLED=false
VULKAN_FLAGS=
# Find Vulkan SDK
if test "x$NEEDS_LIB_VULKAN" = xtrue || test "x${with_vulkan}" = xyes || test "x${with_vulkan_include}" != x ; then
# Check custom directory
if test "x${with_vulkan_include}" != x; then
AC_MSG_CHECKING([for ${with_vulkan_include}/vulkan/vulkan.h])
if test -s "${with_vulkan_include}/vulkan/vulkan.h"; then
VULKAN_ENABLED=true
VULKAN_FLAGS="-I${with_vulkan_include}"
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([Can't find 'vulkan/vulkan.h' under '${with_vulkan_include}'])
fi
fi
# Check $VULKAN_SDK
if test "x$VULKAN_ENABLED" = xfalse && test "x${VULKAN_SDK}" != x; then
AC_MSG_CHECKING([for ${VULKAN_SDK}/include/vulkan/vulkan.h])
if test -s "${VULKAN_SDK}/include/vulkan/vulkan.h"; then
VULKAN_ENABLED=true
VULKAN_FLAGS="-I${VULKAN_SDK}/include"
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
fi
# Check default /usr/include location
if test "x$VULKAN_ENABLED" = xfalse; then
AC_CHECK_HEADERS([vulkan/vulkan.h],
[ VULKAN_ENABLED=true ], [ break ]
)
fi
if test "x$VULKAN_ENABLED" = xfalse; then
# Vulkan SDK not found
HELP_MSG_MISSING_DEPENDENCY([vulkan])
AC_MSG_ERROR([Could not find vulkan! $HELP_MSG ])
fi
fi
# Find shader compiler - glslc or glslangValidator
if test "x$VULKAN_ENABLED" = xtrue; then
SHADER_COMPILER=
# Check glslc
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslc); then
UTIL_LOOKUP_PROGS(GLSLC, glslc)
SHADER_COMPILER="$GLSLC"
VULKAN_SHADER_COMPILER="glslc --target-env=vulkan1.2 -mfmt=num -o"
fi
# Check glslangValidator
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslangValidator) && \
test "x$SHADER_COMPILER" = x; then
UTIL_LOOKUP_PROGS(GLSLANG, glslangValidator)
SHADER_COMPILER="$GLSLANG"
VULKAN_SHADER_COMPILER="glslangValidator --target-env vulkan1.2 -x -o"
fi
if test "x$SHADER_COMPILER" = x; then
# Compiler not found
VULKAN_ENABLED=false
VULKAN_FLAGS=
AC_MSG_ERROR([Can't find vulkan shader compiler])
fi
fi
AC_SUBST(VULKAN_ENABLED)
AC_SUBST(VULKAN_FLAGS)
AC_SUBST(VULKAN_SHADER_COMPILER)
])

View File

@@ -45,8 +45,6 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
fi
WAYLAND_CFLAGS=
WAYLAND_LIBS=
VULKAN_FLAGS=
VULKAN_ENABLED=false
else
WAYLAND_FOUND=no
@@ -79,7 +77,7 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
if test "x${with_wayland_lib}" != x; then
WAYLAND_LIBS="-L${with_wayland_lib} -lwayland-client -lwayland-cursor"
fi
if test "x$WAYLAND_FOUND" = xno; then
# Are the wayland headers installed in the default /usr/include location?
AC_CHECK_HEADERS([wayland-client.h wayland-cursor.h],
@@ -97,98 +95,7 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
AC_MSG_ERROR([Could not find wayland! $HELP_MSG ])
fi
# Checking for vulkan sdk
AC_ARG_WITH(vulkan, [AS_HELP_STRING([--with-vulkan],
[specify whether we use vulkan])])
AC_ARG_WITH(vulkan-include, [AS_HELP_STRING([--with-vulkan-include],
[specify directory for the vulkan include files ({with-vulkan-include}/vulkan/vulkan.h)])])
AC_ARG_WITH(vulkan-shader-compiler, [AS_HELP_STRING([--with-vulkan-shader-compiler],
[specify which shader compiler to use: glslc/glslangValidator])])
if test "x$SUPPORTS_LIB_VULKAN" = xfalse; then
if (test "x${with_vulkan}" != x && test "x${with_vulkan}" != xno) || \
(test "x${with_vulkan_include}" != x && test "x${with_vulkan_include}" != xno); then
AC_MSG_WARN([[vulkan not used, so --with-vulkan-include is ignored]])
fi
VULKAN_FLAGS=
VULKAN_ENABLED=false
else
# Do not build vulkan rendering pipeline by default
if (test "x${with_vulkan}" = x && test "x${with_vulkan_include}" = x) || \
test "x${with_vulkan}" = xno || test "x${with_vulkan_include}" = xno ; then
VULKAN_FLAGS=
VULKAN_ENABLED=false
else
VULKAN_FOUND=no
if test "x${with_vulkan_include}" != x; then
AC_MSG_CHECKING([for ${with_vulkan_include}/vulkan/vulkan.h])
if test -s "${with_vulkan_include}/vulkan/vulkan.h"; then
VULKAN_FOUND=yes
VULKAN_FLAGS="-DVK_USE_PLATFORM_WAYLAND_KHR -I${with_vulkan_include} -DVULKAN_ENABLED"
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([Can't find 'vulkan/vulkan.h' under '${with_vulkan_include}'])
fi
fi
if test "x$VULKAN_FOUND" = xno && test "x${VULKAN_SDK}" != x; then
AC_MSG_CHECKING([for ${VULKAN_SDK}/include/vulkan/vulkan.h])
if test -s "${VULKAN_SDK}/include/vulkan/vulkan.h"; then
VULKAN_FOUND=yes
VULKAN_FLAGS="-DVK_USE_PLATFORM_WAYLAND_KHR -I${VULKAN_SDK}/include -DVULKAN_ENABLED"
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
fi
if test "x$VULKAN_FOUND" = xno; then
# Check default /usr/include location
AC_CHECK_HEADERS([vulkan/vulkan.h],
[ VULKAN_FOUND=yes
VULKAN_FLAGS="-DVK_USE_PLATFORM_WAYLAND_KHR -DVULKAN_ENABLED"
],
[ VULKAN_FOUND=no; break ]
)
fi
if test "x$VULKAN_FOUND" = xno; then
HELP_MSG_MISSING_DEPENDENCY([vulkan])
AC_MSG_ERROR([Could not find vulkan! $HELP_MSG ])
else
# Find shader compiler - glslc or glslangValidator
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslc); then
UTIL_LOOKUP_PROGS(GLSLC, glslc)
SHADER_COMPILER="$GLSLC"
VULKAN_SHADER_COMPILER="glslc --target-env=vulkan1.2 -mfmt=num -o"
fi
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslangValidator) && \
test "x$SHADER_COMPILER" = x; then
UTIL_LOOKUP_PROGS(GLSLANG, glslangValidator)
SHADER_COMPILER="$GLSLANG"
VULKAN_SHADER_COMPILER="glslangValidator --target-env vulkan1.2 -x -o"
fi
if test "x$SHADER_COMPILER" != x; then
VULKAN_ENABLED=true
else
AC_MSG_ERROR([Can't find shader compiler])
fi
fi
fi
fi
fi
AC_SUBST(VULKAN_FLAGS)
AC_SUBST(VULKAN_SHADER_COMPILER)
AC_SUBST(VULKAN_ENABLED)
AC_SUBST(WAYLAND_CFLAGS)
AC_SUBST(WAYLAND_LIBS)
])

View File

@@ -35,8 +35,9 @@ m4_include([lib-std.m4])
m4_include([lib-x11.m4])
m4_include([lib-speechd.m4])
m4_include([lib-nvdacontrollerclient.m4])
m4_include([lib-wayland.m4])
m4_include([lib-dbus.m4])
m4_include([lib-vulkan.m4])
m4_include([lib-wayland.m4])
m4_include([lib-tests.m4])
################################################################################
@@ -50,23 +51,23 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES],
NEEDS_LIB_X11=false
NEEDS_LIB_SPEECHD=false
NEEDS_LIB_WAYLAND=false
SUPPORTS_LIB_VULKAN=false
elif test "x$ENABLE_HEADLESS_ONLY" = xtrue; then
# All other instances need X11, even if building headless only, libawt still
# needs X11 headers.
NEEDS_LIB_X11=true
NEEDS_LIB_SPEECHD=false
NEEDS_LIB_WAYLAND=false
SUPPORTS_LIB_VULKAN=false
else
# All other instances need X11 and wayland, even if building headless only, libawt still
# needs X11 headers.
NEEDS_LIB_X11=true
NEEDS_LIB_SPEECHD=true
NEEDS_LIB_WAYLAND=true
SUPPORTS_LIB_VULKAN=true
fi
# Vulkan is not built by default
NEEDS_LIB_VULKAN=false
# Check if fontconfig is needed
if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx; then
# No fontconfig support on windows or macosx
@@ -153,6 +154,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
LIB_SETUP_X11
LIB_SETUP_SPEECHD
LIB_SETUP_NVDACONTROLLERCLIENT
LIB_SETUP_VULKAN
LIB_SETUP_WAYLAND
LIB_SETUP_DBUS
LIB_TESTS_SETUP_GTEST
@@ -193,7 +195,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
if test "x$OPENJDK_TARGET_OS" = xwindows; then
BASIC_JVM_LIBS="$BASIC_JVM_LIBS kernel32.lib user32.lib gdi32.lib winspool.lib \
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib powrprof.lib uuid.lib \
ws2_32.lib winmm.lib version.lib psapi.lib"
ws2_32.lib winmm.lib version.lib psapi.lib Synchronization.lib"
fi
LIB_SETUP_JVM_LIBS(BUILD)
LIB_SETUP_JVM_LIBS(TARGET)

View File

@@ -487,9 +487,9 @@ A11Y_JAWS_ANNOUNCING_ENABLED:=@A11Y_JAWS_ANNOUNCING_ENABLED@
WAYLAND_CFLAGS:=@WAYLAND_CFLAGS@
WAYLAND_LIBS:=@WAYLAND_LIBS@
VULKAN_ENABLED:=@VULKAN_ENABLED@
VULKAN_FLAGS:=@VULKAN_FLAGS@
VULKAN_SHADER_COMPILER:=@VULKAN_SHADER_COMPILER@
VULKAN_ENABLED:=@VULKAN_ENABLED@
# The lowest required version of macosx
MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@

View File

@@ -36,6 +36,8 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.InetAddress;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
@@ -153,6 +155,20 @@ public class HelloClasslist {
// an inconsistency in the classlist between builds (see JDK-8295951).
// To avoid the problem, load the class explicitly.
Class<?> striped64Class = Class.forName("java.util.concurrent.atomic.Striped64$Cell");
Files.lines(Path.of(args[0])).forEach(line -> {
if (line.isEmpty() || line.charAt(0) == '#') {
return;
}
try {
int index = line.indexOf(' ');
if (index <= 0) {
return;
}
String className = line.substring(0, index).replace('/', '.');
Class.forName(className);
} catch (Exception e) {
}
});
}
public HelloClasslist() {}

File diff suppressed because it is too large Load Diff

View File

@@ -73,7 +73,6 @@ ifeq ($(call isTargetOs, macosx), true)
sun/awt/wl \
sun/java2d/wl \
sun/java2d/x11 \
sun/java2d/vulkan \
sun/java2d/jules \
sun/java2d/xr \
com/sun/java/swing/plaf/gtk \
@@ -139,6 +138,13 @@ ifeq ($(call isTargetOs, windows macosx), false)
EXCLUDE_FILES += sun/awt/AWTCharset.java
endif
ifneq ($(VULKAN_ENABLED), true)
# WLToolkit needs Vulkan java classes for initialization
ifneq ($(call isTargetOs, linux), true)
EXCLUDES += sun/java2d/vulkan
endif
endif
# These files do not appear in the build result of the old build. This
# is because they are generated sources, but the AUTO_JAVA_FILES won't
# pick them up since they aren't generated when the source dirs are

View File

@@ -164,10 +164,23 @@ ifeq ($(call isTargetOs, windows), true)
LIBAWT_CFLAGS += $(A11Y_JAWS_ANNOUNCING_CFLAGS)
endif
# Setup Vulkan
ifeq ($(VULKAN_ENABLED), true)
LIBAWT_EXTRA_SRC += common/font common/java2d/vulkan
LIBAWT_EXTRA_HEADER_DIRS += common/font common/java2d/vulkan common/java2d
LIBAWT_CFLAGS += $(VULKAN_FLAGS)
LIBAWT_EXTRA_FILES += $(TOPDIR)/src/$(MODULE)/share/native/common/java2d/AccelTexturePool.c
LIBAWT_EXFILES += $(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan/VKStubs.c
VULKAN_EXCLUDES := vulkan
else
LIBAWT_EXTRA_FILES += $(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan/VKStubs.c
VULKAN_EXCLUDES := vulkan java2d/vulkan
endif
$(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
NAME := awt, \
EXTRA_SRC := $(LIBAWT_EXTRA_SRC), \
EXCLUDES := $(LIBAWT_EXCLUDES), \
EXTRA_FILES := $(LIBAWT_EXTRA_FILES), \
EXCLUDE_FILES := $(LIBAWT_EXFILES), \
OPTIMIZATION := HIGHEST, \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS) $(DBUS_CFLAGS), \
@@ -237,7 +250,7 @@ spirv-name = $(strip $1).h
ifeq ($(VULKAN_ENABLED), true)
$(eval $(call SetupCopyFiles, COMPILE_VULKAN_SHADERS, \
SRC := $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan, \
FILES := $(call FindFiles, $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan), \
FILES := $(filter-out %.glsl, $(call FindFiles, $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan)), \
DEST := $(SUPPORT_OUTPUTDIR)/headers/java.desktop/vulkan/spirv, \
MACRO := compile-spirv, \
NAME_MACRO := spirv-name, \
@@ -245,14 +258,14 @@ ifeq ($(VULKAN_ENABLED), true)
VULKAN_SHADER_LIST = $(SUPPORT_OUTPUTDIR)/headers/java.desktop/vulkan/shader_list.h
$(VULKAN_SHADER_LIST): $(COMPILE_VULKAN_SHADERS)
> $(VULKAN_SHADER_LIST) $(NEWLINE) \
$(foreach f, $(patsubst $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan/%,%,$(call FindFiles, $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan)), \
$(foreach f, $(patsubst $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan/%,%,$(filter-out %.glsl, $(call FindFiles, $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan))), \
$(ECHO) SHADER_ENTRY\($(subst .,$(COMMA),$(subst /,_,$f))\) >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
$(ECHO) '#ifdef INCLUDE_BYTECODE' >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
$(ECHO) '#include "spirv/$f.h"' >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
$(ECHO) BYTECODE_END >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
$(ECHO) '#endif' >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
)
$(BUILD_LIBAWT): $(VULKAN_SHADER_LIST)
$(BUILD_LIBAWT_TARGET_DEPS): $(VULKAN_SHADER_LIST)
endif
TARGETS += $(BUILD_LIBAWT)
@@ -382,18 +395,13 @@ ifeq ($(call isTargetOs, windows macosx), false)
common/wayland \
#
LIBAWT_WLAWT_EXCLUDES := medialib debug opengl x11
LIBAWT_WLAWT_EXCLUDES := medialib debug opengl x11 $(VULKAN_EXCLUDES)
LIBAWT_WLAWT_EXCLUDE_FILES := common/awt/X11Color.c common/awt/awt_Font.c
# Substitute Vulkan with stubs if disabled.
ifeq ($(VULKAN_ENABLED), false)
LIBAWT_WLAWT_EXCLUDES += vulkan
LIBAWT_WLAWT_EXTRA_FILES += $(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan/VKStubs.c
endif
LIBAWT_WLAWT_EXTRA_HEADER_DIRS := \
$(LIBAWT_DEFAULT_HEADER_DIRS) \
libawt_wlawt/awt \
$(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/wayland \
include \
common/awt/debug \
common/awt/systemscale \
@@ -1103,8 +1111,7 @@ ifeq ($(call isTargetOs, macosx), true)
LIBAWT_LWAWT_CFLAGS := $(X_CFLAGS) $(X_LIBS)
LIBAWT_LWAWT_EXFILES := fontpath.c awt_Font.c X11Color.c
LIBAWT_LWAWT_EXCLUDES := \
$(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan \
LIBAWT_LWAWT_EXCLUDES := $(VULKAN_EXCLUDES) \
$(TOPDIR)/src/$(MODULE)/unix/native/common/awt/medialib \
#

View File

@@ -43,7 +43,10 @@ product(bool, UseOSErrorReporting, false, \
"Let VM fatal error propagate to the OS (ie. WER on Windows)") \
\
product(bool, UseCriticalSection, true, EXPERIMENTAL, \
"Use the critical section API instead of WaitForSingleObject")
"Use the critical section API instead of WaitForSingleObject") \
\
product(bool, UseModernSynchAPI, true, EXPERIMENTAL, \
"Use more modern WinAPI for synchronization instead of WaitForSingleObject")
// end of RUNTIME_OS_FLAGS

View File

@@ -5805,7 +5805,9 @@ int PlatformEvent::park(jlong Millis) {
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_ParkHandle != nullptr , "Invariant");
if (!UseModernSynchAPI) {
guarantee(_ParkHandle != nullptr , "Invariant");
}
guarantee(Millis > 0 , "Invariant");
// CONSIDER: defer assigning a CreateEvent() handle to the Event until
@@ -5837,22 +5839,34 @@ int PlatformEvent::park(jlong Millis) {
// adjust Millis accordingly if we encounter a spurious wakeup.
const int MAXTIMEOUT = 0x10000000;
DWORD rv = WAIT_TIMEOUT;
while (_Event < 0 && Millis > 0) {
DWORD prd = Millis; // set prd = MAX (Millis, MAXTIMEOUT)
if (Millis > MAXTIMEOUT) {
prd = MAXTIMEOUT;
}
if (UseModernSynchAPI) {
HighResolutionInterval *phri = nullptr;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval(prd);
phri = new HighResolutionInterval(Millis);
}
rv = ::WaitForSingleObject(_ParkHandle, prd);
assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed");
if (rv == WAIT_TIMEOUT) {
Millis -= prd;
if ((v = Atomic::load_acquire(&_Event)) < 0) {
::WaitOnAddress(&_Event, &v, sizeof(_Event), Millis);
}
delete phri; // if it is null, harmless
} else {
DWORD rv = WAIT_TIMEOUT;
while (_Event < 0 && Millis > 0) {
DWORD prd = Millis; // set prd = MAX (Millis, MAXTIMEOUT)
if (Millis > MAXTIMEOUT) {
prd = MAXTIMEOUT;
}
HighResolutionInterval *phri = nullptr;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval(prd);
}
rv = ::WaitForSingleObject(_ParkHandle, prd);
assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed");
if (rv == WAIT_TIMEOUT) {
Millis -= prd;
}
delete phri; // if it is null, harmless
}
}
v = _Event;
_Event = 0;
@@ -5870,7 +5884,9 @@ void PlatformEvent::park() {
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_ParkHandle != nullptr, "Invariant");
if (!UseModernSynchAPI) {
guarantee(_ParkHandle != nullptr, "Invariant");
}
// Invariant: Only the thread associated with the Event/PlatformEvent
// may call park().
// Consider: use atomic decrement instead of CAS-loop
@@ -5882,12 +5898,18 @@ void PlatformEvent::park() {
guarantee((v == 0) || (v == 1), "invariant");
if (v != 0) return;
// Do this the hard way by blocking ...
// TODO: consider a brief spin here, gated on the success of recent
// spin attempts by this thread.
while (_Event < 0) {
DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE);
assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed");
if (UseModernSynchAPI) {
while ((v = Atomic::load_acquire(&_Event)) < 0) {
::WaitOnAddress(&_Event, &v, sizeof(_Event), INFINITE);
}
} else {
// Do this the hard way by blocking ...
// TODO: consider a brief spin here, gated on the success of recent
// spin attempts by this thread.
while (_Event < 0) {
DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE);
assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed");
}
}
// Usually we'll find _Event == 0 at this point, but as
@@ -5899,7 +5921,9 @@ void PlatformEvent::park() {
}
void PlatformEvent::unpark() {
guarantee(_ParkHandle != nullptr, "Invariant");
if (!UseModernSynchAPI) {
guarantee(_ParkHandle != nullptr, "Invariant");
}
// Transitions for _Event:
// 0 => 1 : just return
@@ -5915,9 +5939,14 @@ void PlatformEvent::unpark() {
// from the first park() call after an unpark() call which will help
// shake out uses of park() and unpark() without condition variables.
if (Atomic::xchg(&_Event, 1) >= 0) return;
::SetEvent(_ParkHandle);
if (UseModernSynchAPI) {
if (Atomic::xchg(&_Event, 1) >= 0) return;
// Changed from -1 to 1; the target thread's WaitOnAddress() must return now
::WakeByAddressAll((PVOID) &_Event);
} else {
if (Atomic::xchg(&_Event, 1) >= 0) return;
::SetEvent(_ParkHandle);
}
}
@@ -5929,7 +5958,6 @@ void PlatformEvent::unpark() {
// use them directly.
void Parker::park(bool isAbsolute, jlong time) {
guarantee(_ParkHandle != nullptr, "invariant");
// First, demultiplex/decode time arguments
if (time < 0) { // don't wait
return;
@@ -5949,23 +5977,50 @@ void Parker::park(bool isAbsolute, jlong time) {
JavaThread* thread = JavaThread::current();
// Don't wait if interrupted or already triggered
if (thread->is_interrupted(false) ||
WaitForSingleObject(_ParkHandle, 0) == WAIT_OBJECT_0) {
ResetEvent(_ParkHandle);
return;
} else {
ThreadBlockInVM tbivm(thread);
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
if (UseModernSynchAPI) {
// Don't wait if interrupted or already triggered
if (thread->is_interrupted(false)) {
Atomic::release_store(&_TargetValue, 0);
return;
} else {
int curHandle = Atomic::load_acquire(&_TargetValue);
if (curHandle > 0) {
// Already unparked
Atomic::release_store(&_TargetValue, 0);
return;
} else {
ThreadBlockInVM tbivm(thread);
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
WaitForSingleObject(_ParkHandle, time);
ResetEvent(_ParkHandle);
// Spurios wakeups are fine as per Unsafe.park() promise
::WaitOnAddress(&_TargetValue, &curHandle, sizeof(_TargetValue), time);
Atomic::release_store(&_TargetValue, 0);
}
}
} else {
// Don't wait if interrupted or already triggered
if (thread->is_interrupted(false) ||
WaitForSingleObject(_ParkHandle, 0) == WAIT_OBJECT_0) {
ResetEvent(_ParkHandle);
return;
} else {
ThreadBlockInVM tbivm(thread);
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
WaitForSingleObject(_ParkHandle, time);
ResetEvent(_ParkHandle);
}
}
}
void Parker::unpark() {
guarantee(_ParkHandle != nullptr, "invariant");
SetEvent(_ParkHandle);
if (UseModernSynchAPI) {
Atomic::release_store(&_TargetValue, 1);
::WakeByAddressAll(&_TargetValue);
} else {
guarantee(_ParkHandle != nullptr, "invariant");
SetEvent(_ParkHandle);
}
}
// Platform Monitor implementation

View File

@@ -41,8 +41,10 @@ class PlatformEvent : public CHeapObj<mtSynchronizer> {
public:
PlatformEvent() {
_Event = 0 ;
_ParkHandle = CreateEvent (nullptr, false, false, nullptr) ;
guarantee (_ParkHandle != nullptr, "invariant") ;
if (!UseModernSynchAPI) {
_ParkHandle = CreateEvent (nullptr, false, false, nullptr) ;
guarantee (_ParkHandle != nullptr, "invariant") ;
}
}
// Exercise caution using reset() and fired() - they may require MEMBARs
@@ -57,16 +59,23 @@ class PlatformEvent : public CHeapObj<mtSynchronizer> {
class PlatformParker {
NONCOPYABLE(PlatformParker);
protected:
protected:
HANDLE _ParkHandle;
int _TargetValue;
public:
public:
PlatformParker() {
_ParkHandle = CreateEvent (nullptr, true, false, nullptr) ;
guarantee(_ParkHandle != nullptr, "invariant") ;
if (UseModernSynchAPI) {
_TargetValue = 0;
} else {
_ParkHandle = CreateEvent (nullptr, true, false, nullptr) ;
guarantee(_ParkHandle != nullptr, "invariant") ;
}
}
~PlatformParker() {
CloseHandle(_ParkHandle);
if (! UseModernSynchAPI) {
CloseHandle(_ParkHandle);
}
}
};

View File

@@ -404,7 +404,6 @@ bool SharedClassPathEntry::validate(bool is_class_path) const {
// filters out any archived module classes that do not have a matching runtime
// module path location.
log_warning(cds)("Required classpath entry does not exist: %s", name);
ok = false;
} else if (is_dir()) {
if (!os::dir_is_empty(name)) {
log_warning(cds)("directory is not empty: %s", name);
@@ -844,6 +843,20 @@ bool FileMapInfo::validate_boot_class_paths() {
num = rp_len;
}
mismatch = check_paths(1, num, rp_array, 0, 0);
if (mismatch) {
// To facilitate app deployment, we allow the JAR files to be moved *together* to
// a different location, as long as they are still stored under the same directory
// structure. E.g., the following is OK.
// Extends JDK-8279366 to boot classpath.
unsigned int dumptime_prefix_len = header()->common_app_classpath_prefix_size();
unsigned int runtime_prefix_len = longest_common_app_classpath_prefix_len(num, rp_array);
if (dumptime_prefix_len != 0 || runtime_prefix_len != 0) {
log_info(cds, path)("LCP length for boot classpath (dumptime: %u, runtime: %u)",
dumptime_prefix_len, runtime_prefix_len);
mismatch = check_paths(1, num, rp_array,
dumptime_prefix_len, runtime_prefix_len);
}
}
} else {
// create_path_array() ignores non-existing paths. Although the dump time and runtime boot classpath lengths
// are the same initially, after the call to create_path_array(), the runtime boot classpath length could become

View File

@@ -204,7 +204,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st,
class_name_sym,
cld,
cl_info,
false, // pick_newest
nullptr,
CHECK);
assert(result->java_mirror() != nullptr, "must be");

View File

@@ -5449,7 +5449,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
ClassLoaderData* loader_data,
const ClassLoadInfo* cl_info,
Publicity pub_level,
const bool pick_newest,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS) :
_stream(stream),
_class_name(nullptr),
@@ -5511,7 +5511,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_has_empty_finalizer(false),
_has_vanilla_constructor(false),
_max_bootstrap_specifier_index(-1),
_pick_newest(pick_newest) {
_old_2_new_klass_map(old_2_new_klass_map) {
_class_name = name != nullptr ? name : vmSymbols::unknown_class_name();
_class_name->increment_refcount();

View File

@@ -32,6 +32,7 @@
#include "oops/instanceKlass.hpp"
#include "oops/typeArrayOop.hpp"
#include "utilities/accessFlags.hpp"
#include "classFileParserDCEVM.hpp"
class Annotations;
template <typename T>
@@ -201,7 +202,7 @@ class ClassFileParser {
int _max_bootstrap_specifier_index; // detects BSS values
// (DCEVM) Enhanced class redefinition
const bool _pick_newest;
const Old2NewKlassMap* _old_2_new_klass_map;
void parse_stream(const ClassFileStream* const stream, TRAPS);
@@ -534,7 +535,13 @@ class ClassFileParser {
void update_class_name(Symbol* new_name);
// (DCEVM) Enhanced class redefinition
inline const Klass* maybe_newest(const Klass* klass) const { return klass != NULL && _pick_newest ? klass->newest_version() : klass; }
inline const Klass* maybe_newest(Klass* klass) const {
if (klass != nullptr && _old_2_new_klass_map != nullptr) {
Klass** new_klass = _old_2_new_klass_map->get(klass);
return (new_klass != nullptr) ? *new_klass : klass;
}
return klass;
}
public:
ClassFileParser(ClassFileStream* stream,
@@ -542,7 +549,7 @@ class ClassFileParser {
ClassLoaderData* loader_data,
const ClassLoadInfo* cl_info,
Publicity pub_level,
const bool pick_newest,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS);
~ClassFileParser();

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_CLASSFILE_CLASSFILEPARSER_DCEVM_HPP
#define SHARE_CLASSFILE_CLASSFILEPARSER_DCEVM_HPP
#include "utilities/resourceHash.hpp"
#include "memory/allocation.hpp"
#include "oops/klass.hpp"
inline bool old2new_ptr_equals(Klass* const& a, Klass* const& b) { return a == b; }
inline unsigned old2new_ptr_hash(Klass* const& p) { return (unsigned)((uintptr_t)p * 2654435761u); }
using Old2NewKlassMap =
ResourceHashtable<Klass*, Klass*, 1031, AnyObj::C_HEAP, mtInternal, old2new_ptr_hash, old2new_ptr_equals>;
#endif //SHARE_CLASSFILE_CLASSFILEPARSER_DCEVM_HPP

View File

@@ -1220,7 +1220,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
name,
loader_data,
cl_info,
false, // pick_newest
nullptr,
CHECK_NULL);
result->set_classpath_index(classpath_index);
return result;

View File

@@ -375,8 +375,6 @@ inline int Backtrace::get_line_number(Method* method, int bci) {
// "no LineNumberTable". JDK tests for -2.
line_number = -2;
} else {
// (DCEVM): Line numbers from the newest version must be used
method = method->newest_version();
// Returns -1 if no LineNumberTable, and otherwise actual line number
line_number = method->line_number_from_bci(bci);
}

View File

@@ -85,7 +85,7 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
loader_data,
&cl_info,
ClassFileParser::BROADCAST, // publicity level
false,
nullptr,
CHECK_NULL);
const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr();
InstanceKlass* new_ik = parser.create_instance_klass(true, // changed_by_loadhook
@@ -170,7 +170,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
Symbol* name,
ClassLoaderData* loader_data,
const ClassLoadInfo& cl_info,
const bool pick_newest,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS) {
assert(stream != nullptr, "invariant");
assert(loader_data != nullptr, "invariant");
@@ -200,7 +200,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
loader_data,
&cl_info,
ClassFileParser::BROADCAST, // publicity level
pick_newest,
old_2_new_klass_map,
CHECK_NULL);
const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr();

View File

@@ -27,6 +27,7 @@
#include "memory/allStatic.hpp"
#include "runtime/handles.hpp"
#include "classfile/classFileParserDCEVM.hpp"
class ClassFileStream;
class ClassLoaderData;
@@ -64,7 +65,7 @@ class KlassFactory : AllStatic {
Symbol* name,
ClassLoaderData* loader_data,
const ClassLoadInfo& cl_info,
const bool pick_newest,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS);
static InstanceKlass* check_shared_class_file_load_hook(
InstanceKlass* ik,

View File

@@ -804,12 +804,13 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
Handle class_loader,
const ClassLoadInfo& cl_info,
InstanceKlass* old_klass,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS) {
EventClassLoad class_load_start_event;
ClassLoaderData* loader_data;
bool is_redefining = (old_klass != NULL);
bool is_redefining = (old_klass != nullptr);
// - for hidden classes that are not strong: create a new CLD that has a class holder and
// whose loader is the Lookup class's loader.
@@ -826,7 +827,7 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
class_name,
loader_data,
cl_info,
is_redefining, // pick_newest
old_2_new_klass_map, // pick_newest
CHECK_NULL);
assert(k != NULL, "no klass created");
if (is_redefining && k != nullptr) {
@@ -869,6 +870,7 @@ InstanceKlass* SystemDictionary::resolve_class_from_stream(
Handle class_loader,
const ClassLoadInfo& cl_info,
InstanceKlass* old_klass,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS) {
HandleMark hm(THREAD);
@@ -899,7 +901,7 @@ InstanceKlass* SystemDictionary::resolve_class_from_stream(
#endif
if (k == nullptr) {
k = KlassFactory::create_from_stream(st, class_name, loader_data, cl_info, is_redefining, CHECK_NULL);
k = KlassFactory::create_from_stream(st, class_name, loader_data, cl_info, old_2_new_klass_map, CHECK_NULL);
}
if (is_redefining && k != nullptr) {
@@ -939,11 +941,12 @@ InstanceKlass* SystemDictionary::resolve_from_stream(ClassFileStream* st,
Handle class_loader,
const ClassLoadInfo& cl_info,
InstanceKlass* old_klass,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS) {
if (cl_info.is_hidden()) {
return resolve_hidden_class_from_stream(st, class_name, class_loader, cl_info, old_klass, CHECK_NULL);
return resolve_hidden_class_from_stream(st, class_name, class_loader, cl_info, old_klass, old_2_new_klass_map, CHECK_NULL);
} else {
return resolve_class_from_stream(st, class_name, class_loader, cl_info, old_klass, CHECK_NULL);
return resolve_class_from_stream(st, class_name, class_loader, cl_info, old_klass, old_2_new_klass_map, CHECK_NULL);
}
}
@@ -2334,7 +2337,7 @@ Handle SystemDictionary::link_method_handle_constant(Klass* caller,
// call java.lang.invoke.MethodHandleNatives::linkMethodHandleConstant(Class caller, int refKind, Class callee, String name, Object type) -> MethodHandle
JavaCallArguments args;
args.push_oop(Handle(THREAD, caller->newest_version()->java_mirror())); // the referring class
args.push_oop(Handle(THREAD, caller->active_version()->java_mirror())); // the referring class
args.push_int(ref_kind);
args.push_oop(Handle(THREAD, callee->java_mirror())); // the target class
args.push_oop(name_str);

View File

@@ -29,6 +29,7 @@
#include "runtime/handles.hpp"
#include "runtime/signature.hpp"
#include "utilities/vmEnums.hpp"
#include "classfile/classFileParserDCEVM.hpp"
// The dictionary in each ClassLoaderData stores all loaded classes, either
// initiatied by its class loader or defined by its class loader:
@@ -119,6 +120,7 @@ class SystemDictionary : AllStatic {
Handle class_loader,
const ClassLoadInfo& cl_info,
InstanceKlass* old_klass,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS);
// Resolve a class from stream (called by jni_DefineClass and JVM_DefineClass)
@@ -128,6 +130,7 @@ class SystemDictionary : AllStatic {
Handle class_loader,
const ClassLoadInfo& cl_info,
InstanceKlass* old_klass,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS);
static oop get_system_class_loader_impl(TRAPS);
@@ -140,6 +143,7 @@ class SystemDictionary : AllStatic {
Handle class_loader,
const ClassLoadInfo& cl_info,
InstanceKlass* old_klass,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS);
// Lookup an already loaded class. If not found null is returned.

View File

@@ -34,17 +34,31 @@
#include "oops/oop.inline.hpp"
#include "utilities/macros.hpp"
#include "utilities/copy.hpp"
#include "runtime/fieldDescriptor.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
DcevmSharedGC* DcevmSharedGC::_static_instance = nullptr;
void DcevmSharedGC::create_static_instance() {
_static_instance = new DcevmSharedGC();
}
void DcevmSharedGC::destroy_static_instance() {
if (_static_instance != nullptr) {
delete _static_instance;
_static_instance = nullptr;
}
}
void DcevmSharedGC::copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_oops, bool must_be_new) {
if (rescued_oops != NULL) {
if (rescued_oops != nullptr) {
copy_rescued_objects_back(rescued_oops, 0, rescued_oops->length(), must_be_new);
}
}
// (DCEVM) Copy the rescued objects to their destination address after compaction.
void DcevmSharedGC::copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_oops, int from, int to, bool must_be_new) {
if (rescued_oops != NULL) {
if (rescued_oops != nullptr) {
for (int i=from; i < to; i++) {
HeapWord* rescued_ptr = rescued_oops->at(i);
oop rescued_obj = cast_to_oop(rescued_ptr);
@@ -52,10 +66,10 @@ void DcevmSharedGC::copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_
size_t size = rescued_obj->size();
oop new_obj = rescued_obj->forwardee();
assert(!must_be_new || rescued_obj->klass()->new_version() != NULL, "Just checking");
assert(!must_be_new || rescued_obj->klass()->new_version() != nullptr, "Just checking");
Klass* new_klass = rescued_obj->klass()->new_version();
if (new_klass!= NULL) {
if (new_klass->update_information() != NULL) {
if (new_klass!= nullptr) {
if (new_klass->update_information() != nullptr) {
DcevmSharedGC::update_fields(rescued_obj, new_obj);
} else {
rescued_obj->set_klass(new_klass);
@@ -69,11 +83,10 @@ void DcevmSharedGC::copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_
assert(oopDesc::is_oop(new_obj), "must be a valid oop");
}
}
}
void DcevmSharedGC::clear_rescued_objects_resource(GrowableArray<HeapWord*>* rescued_oops) {
if (rescued_oops != NULL) {
if (rescued_oops != nullptr) {
for (int i=0; i < rescued_oops->length(); i++) {
HeapWord* rescued_ptr = rescued_oops->at(i);
size_t size = cast_to_oop(rescued_ptr)->size();
@@ -84,7 +97,7 @@ void DcevmSharedGC::clear_rescued_objects_resource(GrowableArray<HeapWord*>* res
}
void DcevmSharedGC::clear_rescued_objects_heap(GrowableArray<HeapWord*>* rescued_oops) {
if (rescued_oops != NULL) {
if (rescued_oops != nullptr) {
for (int i=0; i < rescued_oops->length(); i++) {
HeapWord* rescued_ptr = rescued_oops->at(i);
FREE_C_HEAP_ARRAY(HeapWord, rescued_ptr);
@@ -96,7 +109,7 @@ void DcevmSharedGC::clear_rescued_objects_heap(GrowableArray<HeapWord*>* rescued
// (DCEVM) Update instances of a class whose fields changed.
void DcevmSharedGC::update_fields(oop q, oop new_location) {
assert(q->klass()->new_version() != NULL, "class of old object must have new version");
assert(q->klass()->new_version() != nullptr, "class of old object must have new version");
Klass* old_klass_oop = q->klass();
Klass* new_klass_oop = q->klass()->new_version();
@@ -107,7 +120,7 @@ void DcevmSharedGC::update_fields(oop q, oop new_location) {
size_t size = q->size_given_klass(old_klass);
size_t new_size = q->size_given_klass(new_klass);
HeapWord* tmp = NULL;
HeapWord* tmp = nullptr;
oop tmp_obj = q;
// Save object somewhere, there is an overlap in fields
@@ -122,39 +135,141 @@ void DcevmSharedGC::update_fields(oop q, oop new_location) {
q->set_klass(new_klass_oop);
int *cur = new_klass_oop->update_information();
assert(cur != NULL, "just checking");
DcevmSharedGC::update_fields(new_location, q, cur);
assert(cur != nullptr, "just checking");
_static_instance->update_fields(new_location, q, cur, false);
if (tmp != NULL) {
if (tmp != nullptr) {
FREE_RESOURCE_ARRAY(HeapWord, tmp, size);
}
}
void DcevmSharedGC::update_fields(oop new_location, oop tmp_obj, int *cur) {
assert(cur != NULL, "just checking");
char* to = (char*)cast_from_oop<HeapWord*>(new_location);
void DcevmSharedGC::update_fields(oop new_obj, oop old_obj, int* cur, bool do_compat_check) {
assert(cur != nullptr, "just checking");
char* to = (char*)cast_from_oop<HeapWord*>(new_obj);
char* src_base = (char *)cast_from_oop<HeapWord*>(old_obj);
while (*cur != 0) {
int size = *cur;
if (size > 0) {
int raw = *cur;
if (raw > 0) {
cur++;
int offset = *cur;
HeapWord* from = (HeapWord*)(((char *)cast_from_oop<HeapWord*>(tmp_obj)) + offset);
if (size == HeapWordSize) {
*((HeapWord*)to) = *from;
} else if (size == HeapWordSize * 2) {
*((HeapWord*)to) = *from;
*(((HeapWord*)to) + 1) = *(from + 1);
int src_offset = *cur;
HeapWord* from = (HeapWord*)(src_base + src_offset);
bool compat_check = do_compat_check && ((raw & UpdateInfoCompatFlag) != 0);
int size = (raw & UpdateInfoLengthMask);
if (!compat_check) {
if (size == HeapWordSize) {
*((HeapWord *) to) = *from;
} else if (size == HeapWordSize * 2) {
*((HeapWord *) to) = *from;
*(((HeapWord *) to) + 1) = *(from + 1);
} else {
Copy::conjoint_jbytes(from, to, size);
}
} else {
Copy::conjoint_jbytes(from, to, size);
assert(size == heapOopSize, "Must be one oop");
int dst_offset = (int)(to - (char*)cast_from_oop<HeapWord*>(new_obj));
oop obj = old_obj->obj_field(src_offset);
if (obj == nullptr) {
new_obj->obj_field_put(dst_offset, nullptr);
} else {
bool compatible = is_compatible(new_obj, dst_offset, obj);
new_obj->obj_field_put(dst_offset, compatible ? obj : (oop)nullptr);
}
}
to += size;
cur++;
} else {
assert(size < 0, "");
int skip = -*cur;
Copy::fill_to_bytes(to, skip, 0);
to += skip;
Copy::fill_to_bytes(to, -raw, 0);
to += -raw;
cur++;
}
}
}
void DcevmSharedGC::update_fields_in_old(oop old_obj, int* cur) {
assert(cur != nullptr, "just checking");
int dst_offset = 0;
while (*cur != 0) {
int raw = *cur;
if (raw > 0) {
cur++;
int size = (raw & UpdateInfoLengthMask);
if ((raw & UpdateInfoCompatFlag) != 0) {
assert(size == heapOopSize, "Must be one oop");
int src_offset = *cur;
oop obj = old_obj->obj_field(src_offset);
if (obj != nullptr) {
bool compatible = is_compatible(old_obj, dst_offset, obj);
if (!compatible) {
old_obj->obj_field_put(src_offset, nullptr);
}
}
}
dst_offset += size;
cur++;
} else {
dst_offset += -raw;
cur++;
}
}
}
static inline bool signature_matches_name(Symbol* sig, Symbol* name) {
const int sig_len = sig->utf8_length();
const int name_len = name->utf8_length();
if (sig_len != name_len + 2) {
return false;
}
const u1* s = sig ->bytes();
const u1* n = name->bytes();
return (s[0] == 'L' && s[sig_len - 1] == ';' && memcmp(s + 1, n, name_len) == 0);
}
bool DcevmSharedGC::is_compatible(oop fld_holder, int fld_offset, oop fld_val) {
assert(oopDesc::is_oop(fld_val), "val has corrupted header");
bool result = false;
Symbol *sig_wanted;
InstanceKlass* holder_ik = InstanceKlass::cast(fld_holder->klass()->newest_version());
Symbol** sig_cached = _field_sig_table->get({holder_ik, fld_offset});
if (sig_cached != nullptr) {
sig_wanted = *sig_cached;
} else {
fieldDescriptor fd_new;
bool ok = holder_ik->find_field_from_offset(fld_offset, false, &fd_new);
assert(ok, "Must exist");
sig_wanted = fd_new.signature();
_field_sig_table->put({holder_ik, fld_offset}, sig_wanted);
}
InstanceKlass *ik = InstanceKlass::cast(fld_val->klass()->newest_version());
bool* hit = _compat_table->get({ik, sig_wanted });
if (hit != nullptr) {
result = *hit;
} else {
InstanceKlass* scan = ik;
while (scan != nullptr && !result) {
if (signature_matches_name(sig_wanted, scan->name())) {
result = true;
break;
}
Array<InstanceKlass*>* ifaces = scan->local_interfaces();
for (int j = 0; j < ifaces->length(); ++j) {
if (signature_matches_name(sig_wanted, ifaces->at(j)->name())) {
result = true;
break;
}
}
scan = (scan->super() != nullptr) ? InstanceKlass::cast(scan->super()) : nullptr;
}
_compat_table->put({ik, sig_wanted }, result);
}
return result;
}

View File

@@ -33,16 +33,76 @@
#include "runtime/timer.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/stack.hpp"
#include "utilities/resourceHash.hpp"
// Shared GC code used from different GC (Serial, CMS, G1) on enhanced redefinition
class DcevmSharedGC : AllStatic {
public:
class DcevmSharedGC : public CHeapObj<mtInternal> {
private:
struct SymbolKey {
InstanceKlass* ik;
Symbol* dst_sig;
};
static unsigned symbol_hash(const SymbolKey& k) {
return (uintptr_t)k.ik ^ (uintptr_t)k.dst_sig;
}
static bool symbol_eq(const SymbolKey& a, const SymbolKey& b) {
return a.ik == b.ik && a.dst_sig == b.dst_sig;
}
typedef ResourceHashtable<SymbolKey, bool, 512,
AnyObj::C_HEAP, mtInternal,
&symbol_hash, &symbol_eq> CompatTable;
struct OffsetKey {
InstanceKlass* ik;
int offset;
};
static unsigned offset_hash(const OffsetKey& k) {
return uintptr_t(k.ik) ^ k.offset;
}
static bool offset_eq(const OffsetKey& a, const OffsetKey& b) {
return a.ik == b.ik && a.offset == b.offset;
}
typedef ResourceHashtable<OffsetKey, Symbol*, 512,
AnyObj::C_HEAP, mtInternal,
&offset_hash, &offset_eq> FieldSigTable;
CompatTable* _compat_table;
FieldSigTable* _field_sig_table;
static DcevmSharedGC* _static_instance;
public:
// ------------------------------------------------------------------
// update info flags
//
// bit 31 : sign bit (<0 = fill, >0 = copy)
// bit 30 : UpdateInfoCompatFlag copy segment requires per-oop compatibility check
// bits 0-29 : raw byte length of the segment
// ------------------------------------------------------------------
static const int UpdateInfoCompatFlag = 1U << 30;
static const int UpdateInfoLengthMask = ~(1U << 31 | UpdateInfoCompatFlag);
DcevmSharedGC() {
_compat_table = new (mtInternal) CompatTable();
_field_sig_table = new (mtInternal) FieldSigTable();
}
~DcevmSharedGC() {
delete _compat_table;
delete _field_sig_table;
}
static void create_static_instance();
static void destroy_static_instance();
static void copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_oops, bool must_be_new);
static void copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_oops, int from, int to, bool must_be_new);
static void clear_rescued_objects_resource(GrowableArray<HeapWord*>* rescued_oops);
static void clear_rescued_objects_heap(GrowableArray<HeapWord*>* rescued_oops);
static void update_fields(oop q, oop new_location);
static void update_fields(oop new_location, oop tmp_obj, int *cur);
bool is_compatible(oop fld_holder, int fld_offset, oop fld_val);
void update_fields(oop new_obj, oop old_obj, int *cur, bool do_compat_check);
void update_fields_in_old(oop old_obj, int *cur);
};
#endif

View File

@@ -93,7 +93,9 @@ class SATBMarkQueueSet: public PtrQueueSet {
size_t _buffer_enqueue_threshold;
// SATB is only active during marking. Enqueuing is only done when active.
bool _all_active;
DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, 4 * sizeof(size_t));
#if ! (defined(_WIN64) && DEFAULT_CACHE_LINE_SIZE == 32)
DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, 4 * sizeof(size_t));
#endif
BufferNode* get_completed_buffer();
void abandon_completed_buffers();

View File

@@ -294,8 +294,8 @@ void LinkResolver::check_klass_accessibility(Klass* ref_klass, Klass* sel_klass,
Klass* refKlassNewest = ref_klass;
Klass* baseKlassNewest = base_klass;
if (AllowEnhancedClassRedefinition) {
refKlassNewest = ref_klass->newest_version();
baseKlassNewest = base_klass->newest_version();
refKlassNewest = ref_klass->active_version();
baseKlassNewest = base_klass->active_version();
}
Reflection::VerifyClassAccessResults vca_result =
Reflection::verify_class_access(refKlassNewest, InstanceKlass::cast(baseKlassNewest), true);
@@ -559,7 +559,7 @@ void LinkResolver::check_method_accessability(Klass* ref_klass,
// to be false (so we'll short-circuit out of these tests).
if (sel_method->name() == vmSymbols::clone_name() &&
( (!AllowEnhancedClassRedefinition && sel_klass == vmClasses::Object_klass()) ||
(AllowEnhancedClassRedefinition && sel_klass->newest_version() == vmClasses::Object_klass()->newest_version()) ) &&
(AllowEnhancedClassRedefinition && sel_klass->active_version() == vmClasses::Object_klass()->active_version()) ) &&
resolved_klass->is_array_klass()) {
// We need to change "protected" to "public".
assert(flags.is_protected(), "clone not protected?");
@@ -734,7 +734,7 @@ Method* LinkResolver::resolve_method(const LinkInfo& link_info,
Bytecodes::Code code, TRAPS) {
Handle nested_exception;
Klass* resolved_klass = link_info.resolved_klass();
Klass* resolved_klass = link_info.resolved_klass()->active_version();
// 1. For invokevirtual, cannot call an interface method
if (code == Bytecodes::_invokevirtual && resolved_klass->is_interface()) {

View File

@@ -1693,7 +1693,7 @@ static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStre
cld,
&cl_info,
ClassFileParser::INTERNAL, // internal visibility
false,
nullptr,
THREAD);
if (HAS_PENDING_EXCEPTION) {
log_pending_exception(PENDING_EXCEPTION);

View File

@@ -369,18 +369,6 @@ void ConstantPool::remove_unshareable_info() {
// we always set _on_stack to true to avoid having to change _flags during runtime.
_flags |= (_on_stack | _is_shared);
if (!_pool_holder->is_linked() && !_pool_holder->verified_at_dump_time()) {
return;
}
// Resolved references are not in the shared archive.
// Save the length for restoration. It is not necessarily the same length
// as reference_map.length() if invokedynamic is saved. It is needed when
// re-creating the resolved reference array if archived heap data cannot be map
// at runtime.
set_resolved_reference_length(
resolved_references() != nullptr ? resolved_references()->length() : 0);
set_resolved_references(OopHandle());
bool archived = false;
for (int index = 1; index < length(); index++) { // Index 0 is unused
switch (tag_at(index).value()) {
@@ -403,6 +391,19 @@ void ConstantPool::remove_unshareable_info() {
}
}
if (!_pool_holder->is_linked() && !_pool_holder->verified_at_dump_time()) {
return;
}
// Resolved references are not in the shared archive.
// Save the length for restoration. It is not necessarily the same length
// as reference_map.length() if invokedynamic is saved. It is needed when
// re-creating the resolved reference array if archived heap data cannot be map
// at runtime.
set_resolved_reference_length(
resolved_references() != nullptr ? resolved_references()->length() : 0);
set_resolved_references(OopHandle());
if (cache() != nullptr) {
// cache() is null if this class is not yet linked.
cache()->remove_unshareable_info();

View File

@@ -371,6 +371,11 @@ void InstanceKlass::set_nest_host(InstanceKlass* host) {
// Can't assert this as package is not set yet:
// assert(is_same_class_package(host), "proposed host is in wrong package");
// set dynamic nest host
_nest_host = host;
// Record dependency to keep nest host from being unloaded before this class.
ClassLoaderData* this_key = class_loader_data();
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm;
const char* msg = "";
@@ -379,18 +384,19 @@ void InstanceKlass::set_nest_host(InstanceKlass* host) {
msg = "(the NestHost attribute in the current class is ignored)";
} else if (_nest_members != nullptr && _nest_members != Universe::the_empty_short_array()) {
msg = "(the NestMembers attribute in the current class is ignored)";
} else if (this_key == nullptr) {
msg = "(the NestMembers classloader data in the current class is ignored)";
}
log_trace(class, nestmates)("Injected type %s into the nest of %s %s",
this->external_name(),
host->external_name(),
msg);
}
// set dynamic nest host
_nest_host = host;
// Record dependency to keep nest host from being unloaded before this class.
ClassLoaderData* this_key = class_loader_data();
assert(this_key != nullptr, "sanity");
this_key->record_dependency(host);
if (this_key != nullptr) {
this_key->record_dependency(host);
}
}
// check if 'this' and k are nestmates (same nest_host), or k is our nest_host,
@@ -1458,12 +1464,26 @@ bool InstanceKlass::implements_interface(Klass* k) const {
// (DCEVM)
bool InstanceKlass::implements_interface_any_version(Klass* k) const {
k = k->newest_version();
if (this->newest_version() == k) return true;
bool InstanceKlass::implements_interface_dcevm(Klass* k, Old2NewKlassMap* old_2_new_klass_map) const {
Klass** new_klass = old_2_new_klass_map->get(k);
if (new_klass != nullptr) {
k = *new_klass;
}
Klass* this_klass = (Klass*) this;
Klass** new_this = old_2_new_klass_map->get(this_klass);
if (new_this != nullptr) {
this_klass = *new_this;
}
if (this_klass == k) return true;
assert(k->is_interface(), "should be an interface class");
for (int i = 0; i < transitive_interfaces()->length(); i++) {
if (transitive_interfaces()->at(i)->newest_version() == k) {
Klass* ti = (Klass*) transitive_interfaces()->at(i);
Klass** new_ti = old_2_new_klass_map->get(ti);
if (new_ti != nullptr) {
ti = *new_ti;
}
if (ti == k) {
return true;
}
}
@@ -1767,6 +1787,18 @@ bool InstanceKlass::find_field_from_offset(int offset, bool is_static, fieldDesc
}
bool InstanceKlass::find_local_field_by_name(Symbol* name, fieldDescriptor* fd) const {
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
Symbol* f_name = fs.name();
if (f_name == name) {
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
return true;
}
}
return false;
}
void InstanceKlass::methods_do(void f(Method* method)) {
// Methods aren't stable until they are loaded. This can be read outside
// a lock through the ClassLoaderData for profiling
@@ -4419,15 +4451,19 @@ Method* InstanceKlass::method_with_idnum(int idnum) {
Method* InstanceKlass::method_with_orig_idnum(int idnum) {
if (idnum >= methods()->length()) {
return nullptr;
}
Method* m = methods()->at(idnum);
if (m != nullptr && m->orig_method_idnum() == idnum) {
return m;
// (DCEVM) The provided idnum may exceed the current number of methods.
if (!AllowEnhancedClassRedefinition) {
return nullptr;
}
} else {
Method* m = methods()->at(idnum);
if (m != nullptr && m->orig_method_idnum() == idnum) {
return m;
}
}
// Obsolete method idnum does not match the original idnum
for (int index = 0; index < methods()->length(); ++index) {
m = methods()->at(index);
Method* m = methods()->at(index);
if (m->orig_method_idnum() == idnum) {
return m;
}

View File

@@ -36,6 +36,7 @@
#include "utilities/accessFlags.hpp"
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
#include "classfile/classFileParserDCEVM.hpp"
#if INCLUDE_JFR
#include "jfr/support/jfrKlassExtension.hpp"
#endif
@@ -565,6 +566,7 @@ public:
bool find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
bool find_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
bool find_local_field_by_name(Symbol* name, fieldDescriptor* fd) const;
private:
inline static int quick_search(const Array<Method*>* methods, const Symbol* name);
@@ -878,9 +880,11 @@ public:
// subclass/subinterface checks
bool implements_interface(Klass* k) const;
bool implements_interface_any_version(Klass* k) const;
bool is_same_or_direct_interface(Klass* k) const;
// (DCEVM)
bool implements_interface_dcevm(Klass* k, Old2NewKlassMap* old_2_new_klass_map) const;
#ifdef ASSERT
// check whether this class or one of its superclasses was redefined
bool has_redefined_this_or_super() const;

View File

@@ -196,13 +196,14 @@ void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word
// The constructor is also used from CppVtableCloner,
// which doesn't zero out the memory before calling the constructor.
Klass::Klass(KlassKind kind) : _kind(kind),
_old_version(NULL),
_new_version(NULL),
_old_version(nullptr),
_new_version(nullptr),
_redefinition_flags(Klass::NoRedefinition),
_is_redefining(false),
_update_information(NULL),
_update_information(nullptr),
_is_copying_backwards(false),
_is_rolled_back(false),
_compat_check_field_offsets(nullptr),
_shared_class_path_index(-1) {
CDS_ONLY(_shared_class_flags = 0;)
CDS_JAVA_HEAP_ONLY(_archived_mirror_index = -1;)

View File

@@ -167,18 +167,18 @@ class Klass : public Metadata {
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
// Advanced class redefinition
// Enhanced class redefinition
// Old version (used in advanced class redefinition)
Klass* _old_version;
// New version (used in advanced class redefinition)
Klass* _new_version;
int _redefinition_flags; // Level of class redefinition
bool _is_redefining;
int* _update_information;
bool _is_copying_backwards; // Does the class need to copy fields backwards? => possibly overwrite itself?
bool _is_rolled_back; // true if class was rolled back in redefinition
// offsets of fields used in compatibility check
GrowableArray<int>* volatile _compat_check_field_offsets;
private:
// This is an index into FileMapHeader::_shared_path_table[], to
@@ -419,6 +419,13 @@ protected:
void set_copying_backwards(bool b) { _is_copying_backwards = b; }
bool is_rolled_back() { return _is_rolled_back; }
void set_rolled_back(bool b) { _is_rolled_back = b;}
GrowableArray<int>* compat_check_field_offsets() const { return Atomic::load_acquire(&_compat_check_field_offsets); }
GrowableArray<int>* set_compat_check_field_offsets(GrowableArray<int>* offsets) {
return Atomic::cmpxchg(&_compat_check_field_offsets, (GrowableArray<int>*) nullptr, offsets);
}
void clear_compat_check_field_offsets() {
_compat_check_field_offsets = nullptr;
}
protected: // internal accessors
void set_subklass(Klass* s);
@@ -431,7 +438,8 @@ protected:
ModifyClassSize = ModifyClass << 1, // The size of the class meta data changes.
ModifyInstances = ModifyClassSize << 1, // There are change to the instance format.
ModifyInstanceSize = ModifyInstances << 1, // The size of instances changes.
RemoveSuperType = ModifyInstanceSize << 1, // A super type of this class is removed.
RemoveInterface = ModifyInstanceSize << 1, // A super type of this class is removed.
RemoveSuperType = RemoveInterface << 1, // A super type of this class is removed.
MarkedAsAffected = RemoveSuperType << 1, // This class has been marked as an affected class.
PrimaryRedefine = MarkedAsAffected << 1 // This class is from primary redefinition set
};

View File

@@ -918,7 +918,7 @@ public:
void release_C_heap_structures();
Method* get_new_method() const {
InstanceKlass* holder = InstanceKlass::cast(method_holder()->newest_version());
InstanceKlass* holder = InstanceKlass::cast(method_holder()->active_version());
Method* new_method = holder->method_with_idnum(orig_method_idnum());
assert(new_method != nullptr, "method_with_idnum() should not be null");

View File

@@ -306,10 +306,12 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR
Handle class_loader (THREAD, JNIHandles::resolve(loaderRef));
Handle protection_domain;
ClassLoadInfo cl_info(protection_domain);
Klass* k = SystemDictionary::resolve_from_stream(&st, class_name,
Klass* k = SystemDictionary::resolve_from_stream(&st,
class_name,
class_loader,
cl_info,
NULL,
nullptr,
nullptr,
CHECK_NULL);
if (log_is_enabled(Debug, class, resolve)) {

View File

@@ -896,7 +896,8 @@ static jclass jvm_define_class_common(const char *name,
Klass* k = SystemDictionary::resolve_from_stream(&st, class_name,
class_loader,
cl_info,
NULL,
nullptr,
nullptr,
CHECK_NULL);
if (log_is_enabled(Debug, class, resolve)) {
@@ -984,7 +985,8 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name,
ik = SystemDictionary::resolve_from_stream(&st, class_name,
class_loader,
cl_info,
NULL,
nullptr,
nullptr,
CHECK_NULL);
if (log_is_enabled(Debug, class, resolve)) {
@@ -1001,7 +1003,8 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name,
ik = SystemDictionary::resolve_from_stream(&st, class_name,
class_loader,
cl_info,
NULL,
nullptr,
nullptr,
CHECK_NULL);
// The hidden class loader data has been artificially been kept alive to

View File

@@ -108,6 +108,7 @@ VM_EnhancedRedefineClasses::VM_EnhancedRedefineClasses(jint class_count, const j
VM_GC_Operation(Universe::heap()->total_collections(), GCCause::_heap_inspection, Universe::heap()->total_full_collections(), true) {
_new_classes = nullptr;
_affected_klasses = nullptr;
_removed_interfaces = nullptr;
_class_count = class_count;
_class_defs = class_defs;
_class_load_kind = class_load_kind;
@@ -128,7 +129,6 @@ static inline InstanceKlass* get_ik(jclass def) {
// - Start mark&sweep GC.
// - true if success, otherwise all chnages are rollbacked.
bool VM_EnhancedRedefineClasses::doit_prologue() {
if (_class_count == 0) {
_res = JVMTI_ERROR_NONE;
return false;
@@ -202,7 +202,36 @@ bool VM_EnhancedRedefineClasses::doit_prologue() {
// Closer for static fields - copy value from old class to the new class.
class FieldCopier : public FieldClosure {
public:
private:
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
public:
FieldCopier(VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces)
: _removed_interfaces(removed_interfaces) {}
bool is_compatible(oop fld_holder, int fld_offset, Symbol* sig_new) {
oop oop = fld_holder->obj_field(fld_offset);
if (oop != nullptr) {
Klass* k = oop->klass();
if (k->is_instance_klass() && k->is_redefining()) {
InstanceKlass *scan = InstanceKlass::cast(k);
while (scan != nullptr) {
if (sig_new->equals(scan->signature_name())) {
return true;
}
Array<InstanceKlass*>* local_interfaces = scan->local_interfaces();
for (int j = 0; j < local_interfaces->length(); j++) {
Klass* iface = local_interfaces->at(j);
if (sig_new->equals(iface->signature_name())) {
return true;
}
}
scan = (scan->super() != nullptr) ? InstanceKlass::cast(scan->super()) : nullptr;
}
}
}
return false;
}
void do_field(fieldDescriptor* fd) {
InstanceKlass* cur = InstanceKlass::cast(fd->field_holder());
oop cur_oop = cur->java_mirror();
@@ -211,19 +240,36 @@ class FieldCopier : public FieldClosure {
oop old_oop = old->java_mirror();
fieldDescriptor result;
bool found = old->find_local_field(fd->name(), fd->signature(), &result);
Symbol* sig_new = fd->signature();
bool found = old->find_local_field_by_name(fd->name(), &result);
if (found && result.is_static()) {
log_trace(redefine, class, obsolete, metadata)("Copying static field value for field %s old_offset=%d new_offset=%d",
fd->name()->as_C_string(), result.offset(), fd->offset());
memcpy(cur_oop->field_addr<HeapWord>(fd->offset()),
old_oop->field_addr<HeapWord>(result.offset()),
type2aelembytes(fd->field_type()));
Symbol* sig_old = result.signature();
bool compatible = false;
// Static fields may have references to java.lang.Class
if (fd->field_type() == T_OBJECT) {
oop oop = cur_oop->obj_field(fd->offset());
if (oop != nullptr && oop->is_instance() && InstanceKlass::cast(oop->klass())->is_mirror_instance_klass()) {
Klass* klass = java_lang_Class::as_Klass(oop);
if (sig_new == sig_old) {
if (_removed_interfaces != nullptr && _removed_interfaces->contains(sig_old) && fd->field_type() == T_OBJECT && result.field_type() == T_OBJECT) {
compatible = is_compatible(old_oop, result.offset(), sig_new);
} else {
compatible = true;
}
} else {
if (fd->field_type() == T_OBJECT && result.field_type() == T_OBJECT) {
compatible = is_compatible(old_oop, result.offset(), sig_new);
}
}
if (compatible) {
log_trace(redefine, class, obsolete, metadata)("Copying static field value for field %s old_offset=%d new_offset=%d",
fd->name()->as_C_string(), result.offset(), fd->offset());
memcpy(cur_oop->field_addr<HeapWord>(fd->offset()),
old_oop->field_addr<HeapWord>(result.offset()),
type2aelembytes(fd->field_type()));
// Static fields may have references to java.lang.Class
if (fd->field_type() == T_OBJECT) {
oop oop = cur_oop->obj_field(fd->offset());
if (oop != nullptr && oop->is_instance() && InstanceKlass::cast(oop->klass())->is_mirror_instance_klass()) {
Klass *klass = java_lang_Class::as_Klass(oop);
if (klass != nullptr && klass->is_instance_klass()) {
assert(oop == InstanceKlass::cast(klass)->java_mirror(), "just checking");
if (klass->new_version() != nullptr) {
@@ -233,10 +279,36 @@ class FieldCopier : public FieldClosure {
}
}
}
} else {
log_trace(redefine,class, obsolete, metadata)("Skipping incompatible static field %s, old_signature=%s, new_signature=%s",
fd->name()->as_C_string(), sig_old->as_C_string(), sig_new->as_C_string());
}
}
}
};
class FieldCompatibilityChecker : public FieldClosure {
private:
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
GrowableArray<int>* _compat_check_field_offsets;
public:
FieldCompatibilityChecker(VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces)
: _removed_interfaces(removed_interfaces), _compat_check_field_offsets(nullptr) {}
void do_field(fieldDescriptor* fd) {
Symbol *sig_new = fd->signature();
if (_removed_interfaces->contains(fd->signature())) {
if (_compat_check_field_offsets == nullptr) {
_compat_check_field_offsets = new (mtInternal) GrowableArray<int>(2, mtInternal);
}
_compat_check_field_offsets->append(fd->offset());
}
}
GrowableArray<int>* compat_check_field_offsets() {
return _compat_check_field_offsets;
}
};
// TODO: review...
void VM_EnhancedRedefineClasses::mark_as_scavengable(nmethod* nm) {
@@ -442,15 +514,23 @@ class ChangePointersOopClosure : public BasicOopIterateClosure {
// - otherwise set the _needs_instance_update flag, we need to do full GC
// and reshuffle object positions durring mark&sweep
class ChangePointersObjectClosure : public ObjectClosure {
private:
private:
OopIterateClosure *_closure;
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
DcevmSharedGC* _dcevm_shared_gc;
bool _needs_instance_update;
oop _tmp_obj;
size_t _tmp_obj_size;
public:
ChangePointersObjectClosure(OopIterateClosure *closure) : _closure(closure), _needs_instance_update(false), _tmp_obj(nullptr), _tmp_obj_size(0) {}
ChangePointersObjectClosure(OopIterateClosure *closure, VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces)
: _closure(closure), _removed_interfaces(removed_interfaces), _needs_instance_update(false), _tmp_obj(nullptr), _tmp_obj_size(0) {
_dcevm_shared_gc = new DcevmSharedGC();
}
~ChangePointersObjectClosure() {
delete _dcevm_shared_gc;
}
bool needs_instance_update() {
return _needs_instance_update;
@@ -465,6 +545,36 @@ public:
Copy::aligned_disjoint_words(cast_from_oop<HeapWord*>(o), cast_from_oop<HeapWord*>(_tmp_obj), size);
}
void do_compat_check_field_offsets(oop obj) {
// Non-redefined class may store fields of redefined types
// check field-level compatibility to avoid invalid accesses.
GrowableArray<int>* fields = obj->klass()->compat_check_field_offsets();
if (fields == nullptr) {
FieldCompatibilityChecker fld_compat_check(_removed_interfaces);
InstanceKlass::cast(obj->klass())->do_nonstatic_fields(&fld_compat_check);
fields = fld_compat_check.compat_check_field_offsets();
if (fields != nullptr) {
GrowableArray<int>* old = obj->klass()->set_compat_check_field_offsets(fields);
if (old != nullptr) {
delete fields;
fields = old;
}
} else {
fields = reinterpret_cast<GrowableArray<int>*>(-1);
obj->klass()->set_compat_check_field_offsets(fields);
}
}
if (reinterpret_cast<intptr_t>(fields) != -1) {
for (int i = 0; i < fields->length(); i++) {
int fld_offset = fields->at(i);
oop fld_val = obj->obj_field(fld_offset);
if (fld_val != nullptr && !_dcevm_shared_gc->is_compatible(obj, fld_offset, fld_val)) {
obj->obj_field_put(fld_offset, nullptr);
}
}
}
}
virtual void do_object(oop obj) {
if (obj->is_instance() && InstanceKlass::cast(obj->klass())->is_mirror_instance_klass()) {
// static fields may have references to old java.lang.Class instances, update them
@@ -473,6 +583,9 @@ public:
//instanceMirrorKlass::oop_fields_iterate(obj, _closure);
} else {
obj->oop_iterate(_closure);
if (_removed_interfaces != nullptr && obj->klass()->is_instance_klass() && obj->klass()->new_version() == nullptr) {
do_compat_check_field_offsets(obj);
}
}
if (obj->klass()->new_version() != nullptr) {
@@ -482,6 +595,7 @@ public:
if (obj->size() - obj->size_given_klass(new_klass) != 0) {
// We need an instance update => set back to old klass
_needs_instance_update = true;
_dcevm_shared_gc->update_fields_in_old(obj, new_klass->update_information());
} else {
// Either new size is bigger or gap is too small to be filled
oop src = obj;
@@ -492,7 +606,7 @@ public:
src->set_klass(obj->klass()->new_version());
// FIXME: instance updates...
//guarantee(false, "instance updates!");
DcevmSharedGC::update_fields(obj, src, new_klass->update_information());
_dcevm_shared_gc->update_fields(obj, src, new_klass->update_information(), true);
}
} else {
obj->set_klass(obj->klass()->new_version());
@@ -505,14 +619,15 @@ class ChangePointersObjectTask : public WorkerTask {
private:
ChangePointersOopClosure<StoreBarrier>* _cl;
ParallelObjectIterator* _poi;
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
bool _needs_instance_update;
public:
ChangePointersObjectTask(ChangePointersOopClosure<StoreBarrier>* cl, ParallelObjectIterator* poi) : WorkerTask("IterateObject Closure"),
_cl(cl), _poi(poi), _needs_instance_update(false) { }
ChangePointersObjectTask(ChangePointersOopClosure<StoreBarrier>* cl, ParallelObjectIterator* poi, VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces)
: WorkerTask("IterateObject Closure"), _cl(cl), _poi(poi), _removed_interfaces(removed_interfaces), _needs_instance_update(false) { }
virtual void work(uint worker_id) {
HandleMark hm(Thread::current()); // make sure any handles created are deleted
ChangePointersObjectClosure objectClosure(_cl);
ChangePointersObjectClosure objectClosure(_cl, _removed_interfaces);
_poi->object_iterate(&objectClosure, worker_id);
_needs_instance_update = _needs_instance_update || objectClosure.needs_instance_update();
}
@@ -521,6 +636,19 @@ public:
}
};
class ClearCompatCheckFields : public KlassClosure {
public:
ClearCompatCheckFields() {}
void do_klass(Klass* k) {
if (k->compat_check_field_offsets() != nullptr) {
if (reinterpret_cast<intptr_t>(k->compat_check_field_offsets()) != -1) {
delete k->compat_check_field_offsets();
}
k->clear_compat_check_field_offsets();
}
}
};
// Main transformation method - runs in VM thread.
// - for each scratch class call redefine_single_class
// - clear code cache (flush_dependent_code)
@@ -552,6 +680,7 @@ void VM_EnhancedRedefineClasses::doit() {
}
Universe::set_inside_redefinition(true);
DcevmSharedGC::create_static_instance();
// Mark methods seen on stack and everywhere else so old methods are not
// cleaned up if they're on the stack.
@@ -562,6 +691,15 @@ void VM_EnhancedRedefineClasses::doit() {
// before the stack walk again.
for (int i = 0; i < _new_classes->length(); i++) {
Klass *new_class = _new_classes->at(i);
// MagicAccessorImpl new_class is set in load_new_class_versions
if (new_class->old_version() != vmClasses::reflect_MagicAccessorImpl_klass() || new_class->old_version()->new_version() == nullptr) {
new_class->old_version()->set_new_version(new_class);
}
}
for (int i = 0; i < _new_classes->length(); i++) {
Klass* new_class = _new_classes->at(i);
redefine_single_class(current, _new_classes->at(i));
}
@@ -630,11 +768,11 @@ void VM_EnhancedRedefineClasses::doit() {
WorkerThreads* workers = Universe::heap()->safepoint_workers();
if (workers != nullptr && workers->active_workers() > 1) {
ParallelObjectIterator poi(workers->active_workers());
ChangePointersObjectTask objectTask(&oopClosure, &poi);
ChangePointersObjectTask objectTask(&oopClosure, &poi, _removed_interfaces);
workers->run_task(&objectTask);
needs_instance_update = objectTask.needs_instance_update();
} else {
ChangePointersObjectClosure objectClosure(&oopClosure);
ChangePointersObjectClosure objectClosure(&oopClosure, _removed_interfaces);
Universe::heap()->object_iterate(&objectClosure);
needs_instance_update = objectClosure.needs_instance_update();
}
@@ -670,7 +808,7 @@ void VM_EnhancedRedefineClasses::doit() {
// Initialize the new class! Special static initialization that does not execute the
// static constructor but copies static field values from the old class if name
// and signature of a static field match.
FieldCopier copier;
FieldCopier copier(_removed_interfaces);
cur->do_local_static_fields(&copier); // TODO (tw): What about internal static fields??
//java_lang_Class::set_klass(old->java_mirror(), cur); // FIXME-isd (from JDK8): is that correct?
//FIXME-isd (from JDK8): do we need this: ??? old->set_java_mirror(cur->java_mirror());
@@ -744,6 +882,12 @@ void VM_EnhancedRedefineClasses::doit() {
cur->clear_update_information();
}
// delete compat_check_fields
if (_removed_interfaces != nullptr) {
ClearCompatCheckFields compat_check_fields;
ClassLoaderDataGraph::classes_do(&compat_check_fields);
}
// TODO: explain...
LoaderConstraintTable::update_after_redefinition();
@@ -781,6 +925,7 @@ void VM_EnhancedRedefineClasses::doit() {
}
#endif
DcevmSharedGC::destroy_static_instance();
Universe::set_inside_redefinition(false);
_timer_vm_op_doit.stop();
@@ -807,8 +952,8 @@ void VM_EnhancedRedefineClasses::doit_epilogue() {
_new_classes = nullptr;
if (_affected_klasses != nullptr) {
delete _affected_klasses;
_affected_klasses = nullptr;
}
_affected_klasses = nullptr;
// Reset the_class_oop to null for error printing.
_the_class_oop = nullptr;
@@ -859,11 +1004,12 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
_affected_klasses = new (mtInternal) GrowableArray<Klass*>(_class_count, mtInternal);
_new_classes = new (mtInternal) GrowableArray<InstanceKlass*>(_class_count, mtInternal);
Old2NewKlassMap old_2_new_klass_map;
ResourceMark rm(THREAD);
// Retrieve an array of all classes that need to be redefined into _affected_klasses
jvmtiError err = find_sorted_affected_classes(true, nullptr, THREAD);
jvmtiError err = find_sorted_affected_classes(true, nullptr, &old_2_new_klass_map, THREAD);
if (err != JVMTI_ERROR_NONE) {
return err;
}
@@ -871,9 +1017,10 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
_max_redefinition_flags = Klass::NoRedefinition;
GrowableArray<Klass*>* prev_affected_klasses = new (mtInternal) GrowableArray<Klass*>(_class_count, mtInternal);
GrowableArray<int> klass_redefinition_flags(_class_count, mtInternal);
do {
err = load_new_class_versions_single_step(THREAD);
err = load_new_class_versions_single_step(&old_2_new_klass_map, &klass_redefinition_flags, THREAD);
if (err != JVMTI_ERROR_NONE) {
delete prev_affected_klasses;
return err;
@@ -886,7 +1033,7 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
_affected_klasses->clear();
}
err = find_sorted_affected_classes(false, prev_affected_klasses, THREAD);
err = find_sorted_affected_classes(false, prev_affected_klasses, &old_2_new_klass_map, THREAD);
if (err != JVMTI_ERROR_NONE) {
delete prev_affected_klasses;
return err;
@@ -896,12 +1043,21 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
delete _affected_klasses;
_affected_klasses = prev_affected_klasses;
// Calculate instance update information after all new classes are resolved
for (int i = 0; i < _new_classes->length(); i++) {
int redefinition_flags = klass_redefinition_flags.at(i);
if ((redefinition_flags & Klass::ModifyInstances) != 0) {
Klass *new_class = _new_classes->at(i);
calculate_instance_update_information(new_class);
}
}
// Link and verify new classes _after_ all classes have been updated in the system dictionary!
for (int i = 0; i < _affected_klasses->length(); i++) {
Klass* the_class = _affected_klasses->at(i);
if (the_class != nullptr) {
assert (the_class->new_version() != nullptr, "new version must be present");
InstanceKlass *new_class(InstanceKlass::cast(the_class->new_version()));
assert (old_2_new_klass_map.contains(the_class), "new version must be present");
InstanceKlass *new_class(InstanceKlass::cast(*old_2_new_klass_map.get(the_class)));
new_class->link_class(THREAD);
if (HAS_PENDING_EXCEPTION) {
Symbol *ex_name = PENDING_EXCEPTION->klass()->name();
@@ -918,7 +1074,8 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
return JVMTI_ERROR_NONE;
}
jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS) {
jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(Old2NewKlassMap* old_2_new_klass_map,
GrowableArray<int>* klass_redefinition_flags, TRAPS) {
// thread local state - used to transfer class_being_redefined object to SystemDictonery::resolve_from_stream
JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current());
@@ -933,10 +1090,16 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
HandleMark hm(THREAD);
InstanceKlass* the_class = InstanceKlass::cast(_affected_klasses->at(i));
if (the_class->new_version() != nullptr) {
if (old_2_new_klass_map->contains(the_class)) {
continue;
}
if (the_class->new_version() != nullptr) {
// the_class was redefined and now has a new version
log_trace(redefine, class, load)("Class redefinition detected: '%s' has a new version.", the_class->name()->as_C_string());
_affected_klasses->at_put(i, the_class);
}
Symbol* the_class_sym = the_class->name();
// Ensure class is linked before redefine
@@ -1014,6 +1177,7 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
the_class_loader,
cl_info,
the_class,
old_2_new_klass_map,
THREAD);
if (!HAS_PENDING_EXCEPTION) {
@@ -1045,6 +1209,7 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
the_class_loader,
cl_info,
the_class,
old_2_new_klass_map,
THREAD);
}
// Clear class_being_redefined just to be sure.
@@ -1083,9 +1248,17 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
the_class->clear_redefinition_flag(Klass::PrimaryRedefine);
InstanceKlass* new_class = k;
the_class->set_new_version(new_class);
old_2_new_klass_map->put(the_class, new_class);
_new_classes->append(new_class);
// If MagicAccessorImpl is being redefined, we must set new_version,
// because class loading may trigger Reflection::verify_class_access,
// which performs superclass checks. This can occur when a subclass
// of MagicAccessorImpl is being loaded as part of the same redefinition run.
if (the_class == vmClasses::reflect_MagicAccessorImpl_klass()) {
the_class->set_new_version(new_class);
}
if (the_class == vmClasses::Reference_klass()) {
// must set offset+count to skip field "referent". Look at InstanceRefKlass::update_nonstatic_oop_maps
OopMapBlock* old_map = the_class->start_of_nonstatic_oop_maps();
@@ -1102,7 +1275,7 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
if (not_changed) {
redefinition_flags = Klass::NoRedefinition;
} else {
redefinition_flags = calculate_redefinition_flags(new_class);
redefinition_flags = calculate_redefinition_flags(new_class, old_2_new_klass_map);
if (redefinition_flags >= Klass::RemoveSuperType) {
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED;
}
@@ -1120,9 +1293,7 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
_max_redefinition_flags = _max_redefinition_flags | redefinition_flags;
if ((redefinition_flags & Klass::ModifyInstances) != 0) {
calculate_instance_update_information(new_class);
}
klass_redefinition_flags->append(redefinition_flags);
if (the_class == vmClasses::Object_klass()) {
_object_klass_redefined = true;
@@ -1136,7 +1307,8 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(TRAPS
}
// Calculated the difference between new and old class (field change, method change, supertype change, ...).
int VM_EnhancedRedefineClasses::calculate_redefinition_flags(InstanceKlass* new_class) {
int VM_EnhancedRedefineClasses::calculate_redefinition_flags(InstanceKlass* new_class,
Old2NewKlassMap* old_2_new_klass_map) {
int result = Klass::NoRedefinition;
log_debug(redefine, class, load)("Comparing different class versions of class %s",new_class->name()->as_C_string());
@@ -1157,7 +1329,8 @@ int VM_EnhancedRedefineClasses::calculate_redefinition_flags(InstanceKlass* new_
// Super class changed
Klass* cur_klass = the_class->super();
while (cur_klass != nullptr) {
if (!new_class->is_subclass_of(cur_klass->newest_version())) {
Klass** new_cur_klass = old_2_new_klass_map->get(cur_klass);
if (!new_class->is_subclass_of(new_cur_klass != nullptr ? *new_cur_klass : cur_klass)) {
log_info(redefine, class, load)("removed super class %s", cur_klass->name()->as_C_string());
result = result | Klass::RemoveSuperType | Klass::ModifyInstances | Klass::ModifyClass;
}
@@ -1167,7 +1340,7 @@ int VM_EnhancedRedefineClasses::calculate_redefinition_flags(InstanceKlass* new_
cur_klass = new_class->super();
while (cur_klass != nullptr) {
if (!the_class->is_subclass_of(cur_klass->is_redefining() ? cur_klass->old_version() : cur_klass)) {
log_info(redefine, class, load)("added super class %s", cur_klass->name()->as_C_string());
log_debug(redefine, class, load)("added super class %s", cur_klass->name()->as_C_string());
result = result | Klass::ModifyClass | Klass::ModifyInstances;
}
cur_klass = cur_klass->super();
@@ -1180,18 +1353,23 @@ int VM_EnhancedRedefineClasses::calculate_redefinition_flags(InstanceKlass* new_
Array<InstanceKlass*>* old_interfaces = the_class->transitive_interfaces();
for (i = 0; i < old_interfaces->length(); i++) {
InstanceKlass* old_interface = InstanceKlass::cast(old_interfaces->at(i));
if (!new_class->implements_interface_any_version(old_interface)) {
result = result | Klass::RemoveSuperType | Klass::ModifyClass;
log_info(redefine, class, load)("removed interface %s", old_interface->name()->as_C_string());
if (!new_class->implements_interface_dcevm(old_interface, old_2_new_klass_map)) {
result = result | Klass::RemoveInterface | Klass::ModifyClass;
log_debug(redefine, class, load)("removed interface %s", old_interface->name()->as_C_string());
if (_removed_interfaces == nullptr) {
_removed_interfaces = new (mtInternal) SymbolSet();
}
Symbol* interf_sign_sym = SymbolTable::new_symbol(old_interface->signature_name());
_removed_interfaces->put(interf_sign_sym, true);
}
}
// Interfaces added?
Array<InstanceKlass*>* new_interfaces = new_class->transitive_interfaces();
for (i = 0; i<new_interfaces->length(); i++) {
if (!the_class->implements_interface_any_version(new_interfaces->at(i))) {
if (!the_class->implements_interface_dcevm(new_interfaces->at(i), old_2_new_klass_map)) {
result = result | Klass::ModifyClass;
log_info(redefine, class, load)("added interface %s", new_interfaces->at(i)->name()->as_C_string());
log_debug(redefine, class, load)("added interface %s", new_interfaces->at(i)->name()->as_C_string());
}
}
@@ -1467,7 +1645,7 @@ jvmtiError VM_EnhancedRedefineClasses::find_class_bytes(InstanceKlass* the_class
// Calculate difference between non static fields of old and new class and store the info into new class:
// instanceKlass->store_update_information
// instanceKlass->copy_backwards
// instanceKlass->copying_backwards
void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* new_version) {
class CalculateFieldUpdates : public FieldClosure {
@@ -1475,17 +1653,24 @@ void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* ne
private:
InstanceKlass* _old_ik;
GrowableArray<int> _update_info;
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
int _position;
bool _copy_backwards;
bool _copying_backwards;
bool _compat_check;
public:
bool does_copy_backwards() {
return _copy_backwards;
bool is_copying_backwards() {
return _copying_backwards;
}
CalculateFieldUpdates(InstanceKlass* old_ik) :
_old_ik(old_ik), _position(instanceOopDesc::base_offset_in_bytes()), _copy_backwards(false) {
bool is_compat_check() {
return _compat_check;
}
CalculateFieldUpdates(InstanceKlass* old_ik, VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces) :
_old_ik(old_ik), _removed_interfaces(removed_interfaces), _position(instanceOopDesc::base_offset_in_bytes()),
_copying_backwards(false), _compat_check() {
_update_info.append(_position);
_update_info.append(0);
}
@@ -1507,43 +1692,78 @@ void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* ne
assert(_position == fd->offset(), "must be correct offset!");
InstanceKlass* holder = fd->field_holder();
InstanceKlass* maybe_old_holder = holder->is_redefining() ? InstanceKlass::cast(holder->old_version()) : holder;
if (fd->index() < holder->java_fields_count()) {
fieldDescriptor old_fd;
if (_old_ik->find_field(fd->name(), fd->signature(), false, &old_fd) != nullptr) {
// Found field in the old class, copy
copy(old_fd.offset(), type2aelembytes(fd->field_type()));
if (old_fd.offset() < fd->offset()) {
_copy_backwards = true;
bool found = false;
if (_old_ik->find_field(fd->name(), fd->signature(), false, &old_fd) != nullptr) {
found = true;
} else {
if (maybe_old_holder->find_local_field_by_name(fd->name(), &old_fd) && !old_fd.is_static()) {
found = true;
}
}
if (found) {
// Found field in the old class, copy
Symbol *sig_new = fd->signature();
Symbol *sig_old = old_fd.signature();
int compat_flag;
if (sig_new == sig_old) {
if (_removed_interfaces != nullptr && _removed_interfaces->contains(sig_old) && fd->field_type() == T_OBJECT && old_fd.field_type() == T_OBJECT) {
compat_flag = 0;
_compat_check = true;
} else {
compat_flag = 1;
}
} else {
if (fd->field_type() == T_OBJECT && old_fd.field_type() == T_OBJECT) {
compat_flag = 0;
_compat_check = true;
} else {
compat_flag = -1;
}
}
// Transfer special flags
fd->set_is_field_modification_watched(old_fd.is_field_modification_watched());
fd->set_is_field_access_watched(old_fd.is_field_access_watched());
if (compat_flag != -1) {
copy(old_fd.offset(), type2aelembytes(fd->field_type()), (compat_flag == 0));
if (old_fd.offset() < fd->offset()) {
_copying_backwards = true;
}
// Transfer special flags
fd->set_is_field_modification_watched(old_fd.is_field_modification_watched());
fd->set_is_field_access_watched(old_fd.is_field_access_watched());
} else {
fill(type2aelembytes(fd->field_type()));
}
} else {
// New field, fill
fill(type2aelembytes(fd->field_type()));
}
} else {
FieldInfo internal_field = holder->field(fd->index());
InstanceKlass* maybe_old_klass = holder->is_redefining() ? InstanceKlass::cast(holder->old_version()) : holder;
int java_fields_count = maybe_old_klass->java_fields_count();
int java_fields_count = maybe_old_holder->java_fields_count();
int num_injected;
const InjectedField* const injected = JavaClasses::get_injected(maybe_old_klass->name(), &num_injected);
for (int i = java_fields_count; i < java_fields_count+num_injected; i++) {
FieldInfo maybe_old_field = maybe_old_klass->field(i);
const InjectedField *const injected = JavaClasses::get_injected(maybe_old_holder->name(), &num_injected);
for (int i = java_fields_count; i < java_fields_count + num_injected; i++) {
FieldInfo maybe_old_field = maybe_old_holder->field(i);
if (maybe_old_field.field_flags().is_injected() &&
internal_field.field_flags().is_injected() &&
maybe_old_field.lookup_symbol(maybe_old_field.name_index()) == internal_field.lookup_symbol(internal_field.name_index())) {
copy(maybe_old_field.offset(), type2aelembytes(Signature::basic_type(internal_field.signature_injected_dcevm())));
copy(maybe_old_field.offset(), type2aelembytes(Signature::basic_type(internal_field.signature_injected_dcevm())), false);
if (maybe_old_field.offset() < internal_field.offset()) {
_copy_backwards = true;
_copying_backwards = true;
}
break;
}
}
}
}
}
private:
void fill(int size) {
@@ -1555,19 +1775,24 @@ void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* ne
_position += size;
}
void copy(int offset, int size) {
int prev_end = -1;
if (_update_info.length() > 0 && _update_info.at(_update_info.length() - 1) > 0) {
prev_end = _update_info.at(_update_info.length() - 2) + _update_info.at(_update_info.length() - 1);
}
void copy(int offset, int size, bool needs_compat_check) {
if (!needs_compat_check && _update_info.length() >= 2) {
int last_size = _update_info.at(_update_info.length() - 2);
int last_offset = _update_info.at(_update_info.length() - 1);
if (prev_end == offset) {
(*_update_info.adr_at(_update_info.length() - 2)) += size;
} else {
_update_info.append(size);
_update_info.append(offset);
if (last_offset > 0 && (last_size & DcevmSharedGC::UpdateInfoCompatFlag) == 0) {
int last_len = last_size & DcevmSharedGC::UpdateInfoLengthMask;
int prev_end = last_offset + last_len;
if (prev_end == offset) {
(*_update_info.adr_at(_update_info.length() - 2)) += size;
_position += size;
return;
}
}
}
int tagged_size = needs_compat_check ? (size | DcevmSharedGC::UpdateInfoCompatFlag) : size;
_update_info.append(tagged_size);
_update_info.append(offset);
_position += size;
}
};
@@ -1576,15 +1801,16 @@ void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* ne
InstanceKlass* old_ik = InstanceKlass::cast(new_version->old_version());
//
CalculateFieldUpdates cl(old_ik);
CalculateFieldUpdates cl(old_ik, _removed_interfaces);
ik->do_nonstatic_fields_dcevm(&cl);
GrowableArray<int> result = cl.finish();
ik->store_update_information(result);
ik->set_copying_backwards(cl.does_copy_backwards());
ik->set_copying_backwards(cl.is_copying_backwards());
if (log_is_enabled(Trace, redefine, class, obsolete, metadata)) {
log_trace(redefine, class, obsolete, metadata)("Instance update information for %s:", new_version->name()->as_C_string());
if (cl.does_copy_backwards()) {
if (cl.is_copying_backwards()) {
log_trace(redefine, class, obsolete, metadata)("\tDoes copy backwards!");
}
for (int i=0; i<result.length(); i++) {
@@ -1749,21 +1975,24 @@ u8 VM_EnhancedRedefineClasses::next_id() {
}
// Clean method data for this class
void VM_EnhancedRedefineClasses::MethodDataCleaner::do_klass(Klass* k) {
if (k->is_instance_klass()) {
InstanceKlass *ik = InstanceKlass::cast(k);
// Clean MethodData of this class's methods so they don't refer to
// old methods that are no longer running.
Array<Method*>* methods = ik->methods();
int num_methods = methods->length();
for (int index = 0; index < num_methods; ++index) {
if (methods->at(index)->method_data() != nullptr) {
methods->at(index)->method_data()->clean_weak_method_links();
class MethodDataCleaner : public KlassClosure {
public:
MethodDataCleaner() {}
void do_klass(Klass* k) {
if (k->is_instance_klass()) {
InstanceKlass *ik = InstanceKlass::cast(k);
// Clean MethodData of this class's methods so they don't refer to
// old methods that are no longer running.
Array<Method*>* methods = ik->methods();
int num_methods = methods->length();
for (int index = 0; index < num_methods; ++index) {
if (methods->at(index)->method_data() != nullptr) {
methods->at(index)->method_data()->clean_weak_method_links();
}
}
}
}
}
};
void VM_EnhancedRedefineClasses::update_jmethod_ids(Thread *current) {
for (int j = 0; j < _matching_methods_length; ++j) {
@@ -2285,7 +2514,10 @@ class AffectedKlassClosure : public KlassClosure {
// Find all affected classes by current redefinition (either because of redefine, class hierarchy or interface change).
// Affected classes are stored in _affected_klasses and parent classes always precedes child class.
jvmtiError VM_EnhancedRedefineClasses::find_sorted_affected_classes(bool do_initial_mark, GrowableArray<Klass*>* prev_affected_klasses, TRAPS) {
jvmtiError VM_EnhancedRedefineClasses::find_sorted_affected_classes(bool do_initial_mark,
GrowableArray<Klass*>* prev_affected_klasses,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS) {
if (do_initial_mark) {
for (int i = 0; i < _class_count; i++) {
InstanceKlass* klass = get_ik(_class_defs[i].klass);
@@ -2315,7 +2547,7 @@ jvmtiError VM_EnhancedRedefineClasses::find_sorted_affected_classes(bool do_init
log_trace(redefine, class, load)("%d classes affected", _affected_klasses->length());
// Sort the affected klasses such that a supertype is always on a smaller array index than its subtype.
jvmtiError result = do_topological_class_sorting(THREAD);
jvmtiError result = do_topological_class_sorting(old_2_new_klass_map, THREAD);
if (log_is_enabled(Trace, redefine, class, load)) {
log_trace(redefine, class, load)("redefine order:");
@@ -2323,7 +2555,7 @@ jvmtiError VM_EnhancedRedefineClasses::find_sorted_affected_classes(bool do_init
log_trace(redefine, class, load)("%s", _affected_klasses->at(i)->name()->as_C_string());
}
}
return JVMTI_ERROR_NONE;
return result;
}
// Pairs of class dependencies (for topological sort)
@@ -2344,7 +2576,7 @@ static bool match_second(void* value, KlassPair elem) {
// Affected flag is cleared (clear_redefinition_flag(Klass::MarkedAsAffected))
// For each dependency create a KlassPair instance. Finally, affected classes (_affected_klasses) are sorted according to pairs.
// TODO - the class file is potentially parsed multiple times - introduce a cache?
jvmtiError VM_EnhancedRedefineClasses::do_topological_class_sorting(TRAPS) {
jvmtiError VM_EnhancedRedefineClasses::do_topological_class_sorting(Old2NewKlassMap* old_2_new_klass_map, TRAPS) {
ResourceMark mark(THREAD);
// Collect dependencies
@@ -2366,9 +2598,21 @@ jvmtiError VM_EnhancedRedefineClasses::do_topological_class_sorting(TRAPS) {
klass->class_loader_data(),
&cl_info,
ClassFileParser::INTERNAL, // publicity level
true,
old_2_new_klass_map,
THREAD);
if (HAS_PENDING_EXCEPTION) {
Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
if (message != nullptr) {
char* ex_msg = java_lang_String::as_utf8_string(message);
log_info(redefine, class, load, exceptions)("parse_class exception: '%s %s'", ex_name->as_C_string(), ex_msg);
} else {
log_info(redefine, class, load, exceptions)("parse_class exception: '%s'", ex_name->as_C_string());
}
return JVMTI_ERROR_INTERNAL;
}
const Klass* super_klass = parser.super_klass();
if (super_klass != nullptr && _affected_klasses->contains((Klass*) super_klass)) {
links.append(KlassPair(super_klass, klass));

View File

@@ -34,6 +34,7 @@
#include "oops/objArrayOop.hpp"
#include "gc/shared/gcVMOperations.hpp"
#include "../../../java.base/unix/native/include/jni_md.h"
#include "classfile/classFileParserDCEVM.hpp"
//
// Enhanced class redefiner.
@@ -46,7 +47,11 @@
// - doit() - main redefition, adjust existing objects on the heap, clear caches
// - doit_epilogue() - cleanup
class VM_EnhancedRedefineClasses: public VM_GC_Operation {
private:
public:
static unsigned int sym_hash (Symbol* const& s) { return (int)(uintptr_t)s; }
static bool sym_equals(Symbol* const& a, Symbol* const& b) { return a == b; }
typedef ResourceHashtable<Symbol*, char, 37, AnyObj::C_HEAP, mtInternal, &sym_hash, &sym_equals> SymbolSet;
private:
// These static fields are needed by ClassLoaderDataGraph::classes_do()
// facility and the AdjustCpoolCacheAndVtable helper:
static Array<Method*>* _old_methods;
@@ -70,7 +75,7 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
// RetransformClasses. Indicate which.
JvmtiClassLoadKind _class_load_kind;
GrowableArray<InstanceKlass*>* _new_classes;
GrowableArray<InstanceKlass*>* _new_classes;
jvmtiError _res;
// Set if any of the InstanceKlasses have entries in the ResolvedMethodTable
@@ -89,6 +94,8 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
int _max_redefinition_flags;
SymbolSet* _removed_interfaces;
// Performance measurement support. These timers do not cover all
// the work done for JVM/TI RedefineClasses() but they do cover
// the heavy lifting.
@@ -112,16 +119,19 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
//
// The result is sotred in _affected_klasses(old definitions) and _new_classes(new definitions) arrays.
jvmtiError load_new_class_versions(TRAPS);
jvmtiError load_new_class_versions_single_step(TRAPS);
jvmtiError load_new_class_versions_single_step(Old2NewKlassMap* old_2_new_klass_map, GrowableArray<int>* klass_redefinition_flags, TRAPS);
// Searches for all affected classes and performs a sorting such tha
// a supertype is always before a subtype.
jvmtiError find_sorted_affected_classes(bool do_initial_mark, GrowableArray<Klass*>* prev_affected_klasses, TRAPS);
jvmtiError find_sorted_affected_classes(bool do_initial_mark,
GrowableArray<Klass*>* prev_affected_klasses,
Old2NewKlassMap* old_2_new_klass_map,
TRAPS);
jvmtiError do_topological_class_sorting(TRAPS);
jvmtiError do_topological_class_sorting(Old2NewKlassMap* old_2_new_klass_map, TRAPS);
jvmtiError find_class_bytes(InstanceKlass* the_class, const unsigned char **class_bytes, jint *class_byte_count, jboolean *not_changed);
int calculate_redefinition_flags(InstanceKlass* new_class);
int calculate_redefinition_flags(InstanceKlass* new_class, Old2NewKlassMap* old_2_new_klass_map);
void calculate_instance_update_information(Klass* new_version);
void rollback();
@@ -149,7 +159,6 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
// and in all direct and indirect subclasses.
void increment_class_counter(Thread* current, InstanceKlass *ik);
void flush_dependent_code();
u8 next_id();
@@ -158,14 +167,6 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
static void dump_methods();
// Check that there are no old or obsolete methods
class CheckClass : public KlassClosure {
Thread* _thread;
public:
CheckClass(Thread* t) : _thread(t) {}
void do_klass(Klass* k);
};
// Unevolving classes may point to methods of the_class directly
// from their constant pool caches, itables, and/or vtables. We
// use the ClassLoaderDataGraph::classes_do() facility and this helper
@@ -176,13 +177,6 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
ClearCpoolCacheAndUnpatch(Thread* t) : _thread(t) {}
void do_klass(Klass* k);
};
// Clean MethodData out
class MethodDataCleaner : public KlassClosure {
public:
MethodDataCleaner() {}
void do_klass(Klass* k);
};
public:
VM_EnhancedRedefineClasses(jint class_count,
const jvmtiClassDefinition *class_defs,

View File

@@ -91,6 +91,8 @@
// FIXLATER: hook into JvmtiTrace
#define TraceJVMTICalls false
static volatile int _active_redefinitions = 0;
JvmtiEnv::JvmtiEnv(jint version) : JvmtiEnvBase(version) {
}
@@ -487,10 +489,14 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
if (AllowEnhancedClassRedefinition) {
// MutexLocker sd_mutex(EnhancedRedefineClasses_lock, Monitor::_no_safepoint_check_flag);
// Stop compilation to avoid compilator race condition (crashes) with advanced redefinition
Atomic::add(&_active_redefinitions, 1);
CompileBroker::stopCompilationBeforeEnhancedRedefinition();
VM_EnhancedRedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_retransform);
VMThread::execute(&op);
CompileBroker::releaseCompilationAfterEnhancedRedefinition();
Atomic::sub(&_active_redefinitions, 1);
if (_active_redefinitions == 0) {
CompileBroker::releaseCompilationAfterEnhancedRedefinition();
}
op_id = op.id();
error = (op.check_error());
} else {

View File

@@ -1400,7 +1400,7 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() {
the_class->name(),
the_class->class_loader_data(),
cl_info,
false,
nullptr,
THREAD);
// Clear class_being_redefined just to be sure.

View File

@@ -37,6 +37,7 @@ import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.spi.FileSystemProvider;
import java.util.Arrays;
import java.util.Objects;
import jdk.internal.access.JavaLangAccess;
@@ -718,23 +719,7 @@ class UnixPath implements Path {
@Override
public int compareTo(Path other) {
int len1 = path.length;
int len2 = ((UnixPath) other).path.length;
int n = Math.min(len1, len2);
byte v1[] = path;
byte v2[] = ((UnixPath) other).path;
int k = 0;
while (k < n) {
int c1 = v1[k] & 0xff;
int c2 = v2[k] & 0xff;
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
return Arrays.compareUnsigned(path, ((UnixPath) other).path);
}
@Override

View File

@@ -64,6 +64,9 @@ class WindowsPath implements Path {
// paths and has a long path prefix for all paths longer than MAX_PATH.
private volatile WeakReference<String> pathForWin32Calls;
// Used for fast string comparison.
private volatile WeakReference<byte[]> uppercasePath;
// offsets into name components (computed lazily)
private volatile Integer[] offsets;
@@ -791,23 +794,7 @@ class WindowsPath implements Path {
public int compareTo(Path obj) {
if (obj == null)
throw new NullPointerException();
String s1 = path;
String s2 = ((WindowsPath)obj).path;
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
return c1 - c2;
}
}
}
return n1 - n2;
return Arrays.compareUnsigned(getUppercasePath(), ((WindowsPath)obj).getUppercasePath());
}
@Override
@@ -917,6 +904,15 @@ class WindowsPath implements Path {
}
}
private byte[] getUppercasePath() {
byte[] result = uppercasePath != null ? uppercasePath.get() : null;
if (result == null) {
result = path.toUpperCase().getBytes();
uppercasePath = new WeakReference<>(result);
}
return result;
}
@Override
public URI toUri() {
return WindowsUriSupport.toUri(this);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,7 @@ import sun.java2d.MacOSFlags;
import sun.java2d.MacosxSurfaceManagerFactory;
import sun.java2d.SunGraphicsEnvironment;
import sun.java2d.SurfaceManagerFactory;
import sun.java2d.metal.MTLGraphicsConfig;
import sun.util.logging.PlatformLogger;
import com.jetbrains.exported.JBRApi;
@@ -159,7 +160,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
}
/* Populate the device table */
rebuildDevices();
initDevices();
if (LogDisplay.ENABLED) {
for (CGraphicsDevice gd : devices.values()) {
@@ -178,11 +179,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
return mtlShadersLib;
}
/**
* Updates the list of devices and notify listeners.
*/
private void rebuildDevices() {
initDevices();
private void doNotifyListeners() {
// Do not notify devices, this was already done in initDevices.
displayChanger.notifyListeners();
}
@@ -191,7 +188,7 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
* Called by the CoreGraphics Display Reconfiguration Callback.
*
* @param displayId CoreGraphics displayId
* @param removed true if displayId was removed, false otherwise.
* @param flags CGDisplayChangeSummaryFlags flags as integer
*/
void _displayReconfiguration(int displayId, int flags) {
// See CGDisplayChangeSummaryFlags
@@ -207,13 +204,35 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
// monitors are not added nor removed, but when the video card is
// switched to/from the discrete video card, so we should try to map the
// old to the new devices.
rebuildDevices();
initDevices();
if (log != null && log != LogDisplay.REMOVED) {
CGraphicsDevice gd = devices.get(displayId);
log.log(displayId, gd != null ? gd.getBounds() : "UNKNOWN", gd != null ? gd.getScaleFactor() : Double.NaN);
}
}
/**
* Called by the CoreGraphics Display Reconfiguration Callback (once all displays processed = finished)
*/
void _displayReconfigurationFinished() {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("CGraphicsEnvironment._displayReconfigurationFinished(): enter");
}
try {
doNotifyListeners();
} catch (Exception e) {
logger.severe("CGraphicsEnvironment._displayReconfigurationFinished: exception occurred: ", e);
} finally {
// notify the metal pipeline after processing listeners:
if (CGraphicsEnvironment.usingMetalPipeline()) {
MTLGraphicsConfig.displayReconfigurationDone();
}
}
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("_displayReconfigurationFinished(): exit");
}
}
@Override
@SuppressWarnings("removal")
protected void finalize() throws Throwable {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -79,6 +79,8 @@ public final class MTLGraphicsConfig extends CGraphicsConfig
private final Object disposerReferent = new Object();
private final int maxTextureSize;
public static native void displayReconfigurationDone();
private static native boolean isMetalFrameworkAvailable();
private static native long getMTLConfigInfo(int displayID, String mtlShadersLib);

View File

@@ -67,6 +67,7 @@ import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JTextArea;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.KeyStroke;
@@ -1096,4 +1097,23 @@ class CAccessibility implements PropertyChangeListener {
}
}, c, false);
}
private static Accessible getScrollBar(Accessible a, Component c, int orientation) {
if (a == null) return null;
return invokeAndWait(() -> {
Accessible sa = CAccessible.getSwingAccessible(a);
if (sa instanceof JScrollPane scrollPane) {
// NSAccessibilityOrientationVertical
if (orientation == 1) {
return scrollPane.getVerticalScrollBar();
}
// NSAccessibilityOrientationHorizontal
else if (orientation == 2) {
return scrollPane.getHorizontalScrollBar();
}
}
return null;
}, c);
}
}

View File

@@ -405,7 +405,8 @@ class CAccessible extends CFRetainedResource implements Accessible {
AccessibleRole thisRole = accessible.getAccessibleContext()
.getAccessibleRole();
if (thisRole == AccessibleRole.SLIDER ||
thisRole == AccessibleRole.PROGRESS_BAR) {
thisRole == AccessibleRole.PROGRESS_BAR ||
thisRole == AccessibleRole.SCROLL_BAR) {
execute(ptr -> valueChanged(ptr));
}
}

View File

@@ -244,6 +244,13 @@ public class CDataTransferer extends DataTransferer {
@Override
protected byte[] imageToPlatformBytes(Image image, long format) {
String formatString = getNativeForFormat(format);
byte[] result = CImage.getCreator().getPlatformImageBytesForFormat(image, formatString);
if (result != null) {
return result;
}
// fallback
return CImage.getCreator().getPlatformImageBytes(image);
}

View File

@@ -26,9 +26,12 @@
package sun.lwawt.macosx;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.geom.Dimension2D;
import java.awt.image.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.awt.image.MultiResolutionImage;
@@ -38,6 +41,8 @@ import sun.awt.image.MultiResolutionCachedImage;
import sun.awt.image.SunWritableRaster;
import javax.imageio.ImageIO;
public class CImage extends CFRetainedResource {
private static native long nativeCreateNSImageFromArray(int[] buffer, int w, int h);
private static native long nativeCreateNSImageFromBytes(byte[] buffer);
@@ -176,6 +181,41 @@ public class CImage extends CFRetainedResource {
return nativeGetPlatformImageBytes(buffer, image.getWidth(null), image.getHeight(null));
}
public byte[] getPlatformImageBytesForFormat(final Image image, final String format) {
if (format.equals("TIFF")) {
return getPlatformImageBytes(image);
}
BufferedImage bufferedImage;
if (image instanceof BufferedImage) {
bufferedImage = (BufferedImage) image;
} else {
int width = image.getWidth(null);
int height = image.getHeight(null);
if (width <= 0 || height <= 0) {
return null;
}
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
if (!ImageIO.write(bufferedImage, format, out)) {
return null;
}
} catch (IOException e) {
return null;
}
return out.toByteArray();
}
/**
* Translates a byte array which contains platform-specific image data in the given format into an Image.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1192,8 +1192,8 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
new GetPropertyAction(invokeLaterKey));
final int result;
if (invokeLaterArg == null) {
// default = 'enabled' to avoid any potential freeze (safe) until better solution:
result = INVOKE_LATER_ENABLED;
// default = 'false':
result = INVOKE_LATER_DISABLED;
} else {
switch (invokeLaterArg.toLowerCase()) {
default:
@@ -1215,28 +1215,9 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
return result;
}
@SuppressWarnings("removal")
private final static boolean INVOKE_LATER_USE_PWM = getInvokeLaterUsePWM();
private static boolean getInvokeLaterUsePWM() {
final String usePwmKey = "awt.mac.flushBuffers.pwm";
@SuppressWarnings("removal")
final String usePwmArg = AccessController.doPrivileged(
new GetPropertyAction(usePwmKey));
final boolean result;
if (usePwmArg == null) {
// default = 'false':
result = false;
} else {
result = "true".equalsIgnoreCase(usePwmArg);
logger.info("CPlatformWindow: property \"{0}={1}\", using usePWM={2}.",
usePwmKey, usePwmArg, result);
}
return result;
}
private final static long NANOS_PER_SEC = 1000000000L;
/* 10s period arround reference times (sleep/wake-up...)
* to ensure all displays are awaken properly */
private final static long NANOS_PER_SEC = 1000000000L;
private final static long STATE_CHANGE_PERIOD = 10L * NANOS_PER_SEC;
private final AtomicBoolean mirroringState = new AtomicBoolean(false);
@@ -1244,23 +1225,36 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
private final AtomicLong mirroringDisablingTime = new AtomicLong(0L);
// Specific class needed to get obvious stack traces:
private final class EmptyRunnable implements Runnable {
private final static class EmptyRunnable implements Runnable {
private final String identifier;
EmptyRunnable(final String identifier) {
this.identifier = identifier;
}
@Override
public void run() {
// Posting an empty to flush the EventQueue without blocking the main thread
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("CPlatformWindow.flushBuffers: run() invoked on {0}",
getIdentifier(target));
logger.fine("CPlatformWindow.flushBuffers: run() invoked on target: {0}", identifier);
}
}
};
private final EmptyRunnable emptyTask = new EmptyRunnable();
void flushBuffers() {
// Only 1 usage by deliverMoveResizeEvent():
// System-dependent appearance optimization.
// May be blocking so postpone this event processing:
// Test only to validate LWCToolkit self-defense against freezes:
final boolean checkLWCToolkitBlockingMainGuard = false;
if (!checkLWCToolkitBlockingMainGuard && LWCToolkit.isBlockingMainThread()) {
logger.fine("Blocked main thread, skip flushBuffers().");
return;
}
if (isVisible() && !nativeBounds.isEmpty() && !isFullScreenMode) {
// use the system property 'awt.mac.flushBuffers.invokeLater' to true/auto (default: auto)
// to avoid deadlocks caused by the LWCToolkit.invokeAndWait() call below:
@@ -1276,7 +1270,6 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
// JBR-5497: force using invokeLater() when computer returns from sleep or displayChanged()
// (mirroring case especially) to avoid deadlocks until solved definitely:
boolean mirroring = false;
if (peer != null) {
final GraphicsDevice device = peer.getGraphicsConfiguration().getDevice();
@@ -1326,39 +1319,30 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
useInvokeLater = true;
break;
}
if (!useInvokeLater && INVOKE_LATER_USE_PWM) {
// If the system property 'awt.mac.flushBuffers.pwm' is true,
// invokeLater is enforced during power transitions.
final boolean inTransition = LWCToolkit.isWithinPowerTransition();
if (inTransition) {
logger.fine("CPlatformWindow.flushBuffers[pwm]: inTransition = true");
useInvokeLater = true;
}
}
try {
final String identifier = logger.isLoggable(PlatformLogger.Level.FINE) ? getIdentifier(target) : null;
final EmptyRunnable emptyTask = new EmptyRunnable(identifier);
// check invokeAndWait: KO (operations require AWTLock and main thread)
// => use invokeLater as it is an empty event to force refresh ASAP
// => use invokeLater as it is an empty event to force refresh
if (useInvokeLater) {
LWCToolkit.invokeLater(emptyTask, target);
} else {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("CPlatformWindow.flushBuffers: enter " +
"LWCToolkit.invokeAndWait(emptyTask) on target = {0}",
getIdentifier(target));
}
/* Ensure >500ms = 666ms timeout to avoid any deadlock among
/* Ensure >3000ms = 3.666ms timeout to avoid any deadlock among
* appkit, EDT, Flusher & a11y threads, locks
* and various synchronization patterns... */
final double timeoutSeconds = 0.666; // seconds
final double timeoutSeconds = 3.666; // seconds
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("CPlatformWindow.flushBuffers: enter " +
"LWCToolkit.invokeAndWait(emptyTask) on target = {0}", identifier);
}
// FUCK: appKit is calling this method !
LWCToolkit.invokeAndWait(emptyTask, target, timeoutSeconds);
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("CPlatformWindow.flushBuffers: exit " +
"LWCToolkit.invokeAndWait(emptyTask) on target = {0}",
getIdentifier(target));
"LWCToolkit.invokeAndWait(emptyTask) on target = {0}", identifier);
}
}
} catch (InvocationTargetException ite) {
@@ -1411,6 +1395,10 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
/* native call by AWTWindow._deliverMoveResizeEvent() */
protected void deliverMoveResizeEvent(int x, int y, int width, int height,
boolean byUser) {
/* Test only to generate more appkit freezes */
final boolean bypassToHaveMoreFreezes = false;
AtomicBoolean ref = new AtomicBoolean();
execute(ptr -> {
ref.set(CWrapper.NSWindow.isZoomed(ptr));
@@ -1429,10 +1417,9 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
}
// System-dependent appearance optimization.
if ((byUser && !oldB.getSize().equals(nativeBounds.getSize()))
if (bypassToHaveMoreFreezes
|| (byUser && !oldB.getSize().equals(nativeBounds.getSize()))
|| isFullScreenAnimationOn) {
// May be blocking so postpone this event processing:
flushBuffers();
}
}

View File

@@ -766,7 +766,7 @@ public final class LWCToolkit extends LWToolkit {
public static <T> T invokeAndWait(final Callable<T> callable,
Component component) throws Exception {
return invokeAndWait(callable, component, -1);
return invokeAndWait(callable, component, 0);
}
public static <T> T invokeAndWait(final Callable<T> callable, Component component, int timeoutSeconds) throws Exception {
@@ -818,7 +818,7 @@ public final class LWCToolkit extends LWToolkit {
invokeAndWait(runnable, component, false, 0.0);
}
/* 25.01.25: keep public methods with (int timeoutSeconds) */
/* 25.04: keep public methods with (int timeoutSeconds) */
@Deprecated(since = "25")
public static void invokeAndWait(Runnable runnable, Component component, int timeoutSeconds)
throws InvocationTargetException
@@ -833,7 +833,7 @@ public final class LWCToolkit extends LWToolkit {
invokeAndWait(runnable, component, processEvents, timeout);
}
/* 25.01.25: added public methods with (double timeoutSeconds) to have timeouts between 0.0 and 1.0 */
/* 25.04: added public methods with (double timeoutSeconds) to have more precise timeouts */
public static void invokeAndWait(Runnable runnable, Component component, double timeoutSeconds)
throws InvocationTargetException
@@ -905,9 +905,9 @@ public final class LWCToolkit extends LWToolkit {
private static native boolean isBlockingEventDispatchThread();
static native String getThreadTraceContexts();
public static native boolean isBlockingMainThread();
static native boolean isWithinPowerTransition();
static native String getThreadTraceContexts();
public static void invokeLater(Runnable event, Component component)
throws InvocationTargetException {
@@ -1084,7 +1084,7 @@ public final class LWCToolkit extends LWToolkit {
static native long createAWTRunLoopMediator();
/**
* Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent
* by [JNFRunLoop performOnMainThreadWaiting] are processed.
* by [ThreadUtilities performOnMainThreadWaiting] are processed.
* @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator
* @param processEvents if true - dispatches event while in the nested loop. Used in DnD.
* Additional attention is needed when using this feature as we short-circuit normal event
@@ -1098,7 +1098,7 @@ public final class LWCToolkit extends LWToolkit {
}
/**
* Starts run-loop with the provided timeout. Use (<=0.0) for the infinite value.
* Starts run-loop with the provided timeout. Use (<= 0.0) for the infinite value.
*/
static boolean doAWTRunLoop(long mediator, boolean processEvents, double timeoutSeconds) {
if (log.isLoggable(PlatformLogger.Level.FINE)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@ static NSInteger architecture = -1;
/*
* Convert the mode string to the more convenient bits per pixel value
*/
int getBPPFromModeString(CFStringRef mode)
static int getBPPFromModeString(CFStringRef mode)
{
if ((CFStringCompare(mode, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
// This is a strange mode, where we using 10 bits per RGB component and pack it into 32 bits
@@ -57,11 +57,105 @@ int getBPPFromModeString(CFStringRef mode)
else if (CFStringCompare(mode, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
return 8;
}
return 0;
}
static BOOL isValidDisplayMode(CGDisplayModeRef mode) {
void dumpDisplayInfo(jint displayID)
{
// Returns a Boolean value indicating whether a display is active.
jint displayIsActive = CGDisplayIsActive(displayID);
// Returns a Boolean value indicating whether a display is always in a mirroring set.
jint displayIsalwaysInMirrorSet = CGDisplayIsAlwaysInMirrorSet(displayID);
// Returns a Boolean value indicating whether a display is sleeping (and is therefore not drawable).
jint displayIsAsleep = CGDisplayIsAsleep(displayID);
// Returns a Boolean value indicating whether a display is built-in, such as the internal display in portable systems.
jint displayIsBuiltin = CGDisplayIsBuiltin(displayID);
// Returns a Boolean value indicating whether a display is in a mirroring set.
jint displayIsInMirrorSet = CGDisplayIsInMirrorSet(displayID);
// Returns a Boolean value indicating whether a display is in a hardware mirroring set.
jint displayIsInHWMirrorSet = CGDisplayIsInHWMirrorSet(displayID);
// Returns a Boolean value indicating whether a display is the main display.
jint displayIsMain = CGDisplayIsMain(displayID);
// Returns a Boolean value indicating whether a display is connected or online.
jint displayIsOnline = CGDisplayIsOnline(displayID);
// Returns a Boolean value indicating whether a display is running in a stereo graphics mode.
jint displayIsStereo = CGDisplayIsStereo(displayID);
// For a secondary display in a mirroring set, returns the primary display.
CGDirectDisplayID displayMirrorsDisplay = CGDisplayMirrorsDisplay(displayID);
// Returns the primary display in a hardware mirroring set.
CGDirectDisplayID displayPrimaryDisplay = CGDisplayPrimaryDisplay(displayID);
// Returns the width and height of a display in millimeters.
CGSize size = CGDisplayScreenSize(displayID);
NSLog(@"CGDisplay[%d]{\n"
"displayIsActive=%d\n"
"displayIsalwaysInMirrorSet=%d\n"
"displayIsAsleep=%d\n"
"displayIsBuiltin=%d\n"
"displayIsInMirrorSet=%d\n"
"displayIsInHWMirrorSet=%d\n"
"displayIsMain=%d\n"
"displayIsOnline=%d\n"
"displayIsStereo=%d\n"
"displayMirrorsDisplay=%d\n"
"displayPrimaryDisplay=%d\n"
"displayScreenSizey=[%.1lf %.1lf]\n",
displayID,
displayIsActive,
displayIsalwaysInMirrorSet,
displayIsAsleep,
displayIsBuiltin,
displayIsInMirrorSet,
displayIsInHWMirrorSet,
displayIsMain,
displayIsOnline,
displayIsStereo,
displayMirrorsDisplay,
displayPrimaryDisplay,
size.width, size.height
);
// CGDisplayCopyDisplayMode can return NULL if displayID is invalid
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayID);
if (mode != NULL) {
// Getting Information About a Display Mode
jint h = -1, w = -1, bpp = -1;
jdouble refreshRate = 0.0;
// Returns the width of the specified display mode.
w = CGDisplayModeGetWidth(mode);
// Returns the height of the specified display mode.
h = CGDisplayModeGetHeight(mode);
// Returns the pixel encoding of the specified display mode.
// Deprecated
CFStringRef currentBPP = CGDisplayModeCopyPixelEncoding(mode);
bpp = getBPPFromModeString(currentBPP);
CFRelease(currentBPP);
// Returns the refresh rate of the specified display mode.
refreshRate = CGDisplayModeGetRefreshRate(mode);
NSLog(@"CGDisplayMode[%d]: w=%d, h=%d, bpp=%d, freq=%.2lf hz",
displayID, w, h, bpp, refreshRate);
CGDisplayModeRelease(mode);
}
}
BOOL isValidDisplayMode(CGDisplayModeRef mode) {
if (!CGDisplayModeIsUsableForDesktopGUI(mode)) {
return NO;
}
@@ -184,7 +278,7 @@ static jobject createJavaDisplayMode(CGDisplayModeRef mode, JNIEnv *env) {
jint h = DEFAULT_DEVICE_HEIGHT, w = DEFAULT_DEVICE_WIDTH, bpp = 0, refrate = 0;
JNI_COCOA_ENTER(env);
BOOL isDisplayModeDefault = NO;
if (mode) {
if (mode != NULL) {
CFStringRef currentBPP = CGDisplayModeCopyPixelEncoding(mode);
bpp = getBPPFromModeString(currentBPP);
CFRelease(currentBPP);
@@ -342,10 +436,9 @@ JNI_COCOA_ENTER(env);
configureDisplayLock = [[NSLock alloc] init];
});
// Avoid reentrance and ensure consistency between the best mode and ConfigureDisplay transaction:
[configureDisplayLock lock];
@try {
// Avoid reentrance and ensure consistency between the best mode and ConfigureDisplay transaction:
[configureDisplayLock lock];
if (TRACE_DISPLAY_CHANGE_CONF) {
NSLog(@"nativeSetDisplayMode: displayID: %d w:%d h:%d bpp: %d refrate:%d", displayID, w, h, bpp, refrate);
}
@@ -411,7 +504,9 @@ JNI_COCOA_ENTER(env);
// CGDisplayCopyDisplayMode can return NULL if displayID is invalid
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID);
ret = createJavaDisplayMode(currentMode, env);
CGDisplayModeRelease(currentMode);
if (currentMode != NULL) {
CGDisplayModeRelease(currentMode);
}
JNI_COCOA_EXIT(env);
return ret;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,10 @@
#define MAX_DISPLAYS 64
static const BOOL TRACE_DISPLAY_CALLBACKS = NO;
extern void dumpDisplayInfo(jint displayID);
/*
* Class: sun_awt_CGraphicsEnvironment
* Method: getDisplayIDs
@@ -109,25 +113,78 @@ Java_sun_awt_CGraphicsEnvironment_getMainDisplayID
* Post the display reconfiguration event.
*/
static void displaycb_handle
(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo)
(CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo)
{
if (flags == kCGDisplayBeginConfigurationFlag) return;
AWT_ASSERT_APPKIT_THREAD;
JNI_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:NO block:^() {
if (TRACE_DISPLAY_CALLBACKS) {
NSLog(@"CGraphicsEnv::displaycb_handle(displayId: %d, flags: %d, userInfo: %p)",
displayId, flags, userInfo);
}
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
jobject cgeRef = (jobject)userInfo;
/*
* RunLoop interactions with callbacks means several RunLoop iterations may be needed to run these callbacks
* within dispatch_queue (RunLoopBeforeSources -> RunLoopExit)
*/
const jobject cgeRef = (jobject)userInfo;
if (flags == kCGDisplayBeginConfigurationFlag) {
/*
* During the Reconfigure transaction consituted by
* [Begin(each displayID) ... -> Finished(each displayID) callbacks]
* run by RunLoop (__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__),
* the begin and finished loops are running callbacks for each displayID which can not modify the RunLoop state
* during the complete [Begin -> END] reconfigure transaction
* ie appkit thread can not wait ie LWCToolkit.invokeAndWait(task, target ...) is forbidden.
*/
// Avoid LWCToolkit.invokeAndWait() calls since first Begin(each displayID) callback:
[ThreadUtilities setBlockingMainThread:true];
return;
}
// Processing display changes (Finished called by _displayReconfigurationFinished):
// first register Main RunLoop callback to ensure blockingMainThread = false anyway:
if ([ThreadUtilities hasMainThreadRunLoopCallback:MAIN_CALLBACK_CGDISPLAY_RECONFIGURE] == NO) {
// avoid creating block if not needed:
[ThreadUtilities registerMainThreadRunLoopCallback:MAIN_CALLBACK_CGDISPLAY_RECONFIGURE
block:^()
{
@try {
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
if (graphicsEnv == NULL) return; // ref already GC'd
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
DECLARE_METHOD(jm_displayReconfigurationFinished,
jc_CGraphicsEnvironment, "_displayReconfigurationFinished", "()V");
(*env)->CallVoidMethod(env, graphicsEnv, jm_displayReconfigurationFinished);
(*env)->DeleteLocalRef(env, graphicsEnv);
CHECK_EXCEPTION();
} @finally {
// Allow LWCToolkit.invokeAndWait() once Finished callbacks:
[ThreadUtilities setBlockingMainThread:false];
}
}];
}
if (TRACE_DISPLAY_CALLBACKS) {
dumpDisplayInfo(displayId);
}
// braces to reduce variable scope
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
if (graphicsEnv == NULL) return; // ref already GC'd
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
DECLARE_METHOD(jm_displayReconfiguration,
jc_CGraphicsEnvironment, "_displayReconfiguration","(II)V");
(*env)->CallVoidMethod(env, graphicsEnv, jm_displayReconfiguration,
(jint) display, (jint) flags);
(jint) displayId, (jint) flags);
(*env)->DeleteLocalRef(env, graphicsEnv);
CHECK_EXCEPTION();
}];
}
JNI_COCOA_EXIT(env);
}
/*

View File

@@ -602,6 +602,12 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoopImpl
jboolean result = JNI_TRUE;
JNI_COCOA_ENTER(env);
/* defensive programming (should not happen) */
if ([ThreadUtilities blockingMainThread]) {
NSLog(@"LWCToolkit_doAWTRunLoopImpl: invalid state: blockingMainThread = YES !");
return JNI_FALSE;
}
AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
if (mediatorObject == nil) {
@@ -612,7 +618,7 @@ JNI_COCOA_ENTER(env);
* 2025.02: infinite timeout means possible deadlocks or freezes may happen.
* To ensure responsiveness, infinite is limited to a huge delay (~10s)
*/
if (timeoutSeconds < WAIT_TIMEOUT_LIMIT) {
if ((timeoutSeconds <= 0.0) || (timeoutSeconds > WAIT_TIMEOUT_LIMIT)) {
timeoutSeconds = WAIT_TIMEOUT_LIMIT;
}
@@ -696,6 +702,17 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isBlockingEventDispa
return ThreadUtilities.blockingEventDispatchThread;
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: isBlockingMainThread
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isBlockingMainThread
(JNIEnv *env, jclass clz)
{
return [ThreadUtilities blockingMainThread];
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: getThreadTraceContexts
@@ -716,19 +733,6 @@ JNI_COCOA_ENTER(env);
JNI_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: isWithinPowerTransition
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isWithinPowerTransition
(JNIEnv *env, jclass clz)
{
JNI_COCOA_ENTER(env);
return [ThreadUtilities isWithinPowerTransition:PWM_TRANSITION_PERIOD] ? JNI_TRUE : JNI_FALSE;
JNI_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: stopAWTRunLoop

View File

@@ -179,6 +179,26 @@ enum ShortcutID {
Shortcut_ToggleSpeakSelection = 230,
Shortcut_ToggleSpeakItemUnderPointer = 231,
Shortcut_ToggleTypingFeedback = 232,
Shortcut_MinimizeWindow = 233,
Shortcut_ZoomWindow = 235,
Shortcut_FillWindow = 237,
Shortcut_CenterWindow = 238,
Shortcut_RestoreWindow = 239,
Shortcut_TileLeftHalf = 240,
Shortcut_TileRightHalf = 241,
Shortcut_TileTopHalf = 242,
Shortcut_TileBottomHalf = 243,
Shortcut_TileTopLeftQuarter = 244,
Shortcut_TileTopRightQuarter = 245,
Shortcut_TileBottomLeftQuarter = 246,
Shortcut_TileBottomRightQuarter = 247,
Shortcut_ArrangeLeftRight = 248,
Shortcut_ArrangeRightLeft = 249,
Shortcut_ArrangeTopBottom = 250,
Shortcut_ArrangeBottomTop = 251,
Shortcut_ArrangeQuarters = 256,
Shortcut_FullScreenTileLeft = 257,
Shortcut_FullScreenTileRight = 258,
};
struct SymbolicHotKey {
@@ -204,67 +224,88 @@ struct SymbolicHotKey {
// Modifier mask using the NSEventModifierFlag* values for this shortcut
int modifiers;
// The first major version of macOS that has this shortcut or -1 if unknown.
int macOSVersion;
// The first version of macOS that has this shortcut or -1 if unknown.
int macOSVersionMajor;
int macOSVersionMinor;
};
static const struct SymbolicHotKey defaultSymbolicHotKeys[] = {
[Shortcut_FocusMenuBar] = { "FocusMenuBar", "Move focus to the menu bar", YES, 65535, 120, 0x00840000, -1 },
[Shortcut_FocusDock] = { "FocusDock", "Move focus to the Dock", YES, 65535, 99, 0x00840000, -1 },
[Shortcut_FocusActiveWindow] = { "FocusActiveWindow", "Move focus to active or next window", YES, 65535, 118, 0x00840000, -1 },
[Shortcut_FocusToolbar] = { "FocusToolbar", "Move focus to window toolbar", YES, 65535, 96, 0x00840000, -1 },
[Shortcut_FocusFloatingWindow] = { "FocusFloatingWindow", "Move focus to floating window", YES, 65535, 97, 0x00840000, -1 },
[Shortcut_ToggleKeyboardAccess] = { "ToggleKeyboardAccess", "Turn keyboard access on or off", YES, 65535, 122, 0x00840000, -1 },
[Shortcut_ChangeTabMode] = { "ChangeTabMode", "Change the way Tab moves focus", YES, 65535, 98, 0x00840000, -1 },
[Shortcut_ToggleZoom] = { "ToggleZoom", "Zoom: Turn zoom on or off", NO, 56, 28, 0x00180000, -1 },
[Shortcut_ZoomIn] = { "ZoomIn", "Zoom: Zoom in", NO, 61, 24, 0x00180000, -1 },
[Shortcut_ZoomOut] = { "ZoomOut", "Zoom: Zoom out", NO, 45, 27, 0x00180000, -1 },
[Shortcut_InvertColors] = { "InvertColors", "Invert colors", YES, 56, 28, 0x001c0000, -1 },
[Shortcut_ToggleZoomImageSmoothing] = { "ToggleZoomImageSmoothing", "Zoom: Turn image smoothing on or off", NO, 92, 42, 0x00180000, -1 },
[Shortcut_IncreaseContrast] = { "IncreaseContrast", "Increase contrast", NO, 46, 47, 0x001c0000, -1 },
[Shortcut_DecreaseContrast] = { "DecreaseContrast", "Decrease contrast", NO, 44, 43, 0x001c0000, -1 },
[Shortcut_FocusNextApplicationWindow] = { "FocusNextApplicationWindow", "Move focus to the next window in application", YES, 96, 50, 0x00100000, -1 },
[Shortcut_ScreenshotToFile] = { "ScreenshotToFile", "Save picture of screen as a file", YES, 51, 20, 0x00120000, -1 },
[Shortcut_ScreenshotToClipboard] = { "ScreenshotToClipboard", "Copy picture of screen to the clipboard", YES, 51, 20, 0x00160000, -1 },
[Shortcut_ScreenshotAreaToFile] = { "ScreenshotAreaToFile", "Save picture of selected area as a file", YES, 52, 21, 0x00120000, -1 },
[Shortcut_ScreenshotAreaToClipboard] = { "ScreenshotAreaToClipboard", "Copy picture of selected area to the clipboard", YES, 52, 21, 0x00160000, -1 },
[Shortcut_ShowAllWindows] = { "ShowAllWindows", "Mission Control", YES, 65535, 126, 0x00840000, -1 },
[Shortcut_ShowApplicationWindows] = { "ShowApplicationWindows", "Application windows", YES, 65535, 125, 0x00840000, -1 },
[Shortcut_ShowDesktop] = { "ShowDesktop", "Show desktop", YES, 65535, 103, 0x00800000, -1 },
[Shortcut_ToggleDockHiding] = { "ToggleDockHiding", "Turn Dock hiding on/off", YES, 100, 2, 0x00180000, -1 },
[Shortcut_DecreaseBrightness] = { "DecreaseBrightness", "Decrease display brightness", YES, 65535, 107, 0x00800000, -1 },
[Shortcut_IncreaseBrightness] = { "IncreaseBrightness", "Increase display brightness", YES, 65535, 113, 0x00800000, -1 },
[Shortcut_FocusStatusMenu] = { "FocusStatusMenu", "Move focus to the status menus", YES, 65535, 100, 0x00840000, -1 },
[Shortcut_ToggleVoiceOver] = { "ToggleVoiceOver", "Turn VoiceOver on or off", YES, 65535, 96, 0x00900000, -1 },
[Shortcut_SelectPreviousInputSource] = { "SelectPreviousInputSource", "Select the previous input source", YES, 32, 49, 0x00040000, -1 },
[Shortcut_SelectNextInputSource] = { "SelectNextInputSource", "Select next source in Input menu", YES, 32, 49, 0x000c0000, -1 },
[Shortcut_ShowSpotlight] = { "ShowSpotlight", "Show Spotlight Search", YES, 32, 49, 0x00100000, -1 },
[Shortcut_ShowFinderSearch] = { "ShowFinderSearch", "Show Finder search window", YES, 32, 49, 0x00180000, -1 },
[Shortcut_SwitchToDesktopLeft] = { "SwitchToDesktopLeft", "Move left a space", NO, 65535, 123, 0x00840000, -1 },
[Shortcut_SwitchToDesktopRight] = { "SwitchToDesktopRight", "Move right a space", NO, 65535, 124, 0x00840000, -1 },
[Shortcut_SwitchToDesktop1] = { "SwitchToDesktop1", "Switch to Desktop 1", NO, 65535, 18, 0x00040000, -1 },
[Shortcut_SwitchToDesktop2] = { "SwitchToDesktop2", "Switch to Desktop 2", NO, 65535, 19, 0x00040000, -1 },
[Shortcut_SwitchToDesktop3] = { "SwitchToDesktop3", "Switch to Desktop 3", NO, 65535, 20, 0x00040000, -1 },
[Shortcut_SwitchToDesktop4] = { "SwitchToDesktop4", "Switch to Desktop 4", NO, 65535, 21, 0x00040000, -1 },
[Shortcut_ShowContextualMenu] = { "ShowContextualMenu", "Show contextual menu", YES, 65535, 36, 0x00040000, 15 },
[Shortcut_ShowLaunchpad] = { "ShowLaunchpad", "Show Launchpad", NO, 65535, 65535, 0, -1 },
[Shortcut_ShowAccessibilityControls] = { "ShowAccessibilityControls", "Show Accessibility controls", YES, 65535, 96, 0x00980000, -1 },
[Shortcut_ShowNotificationCenter] = { "ShowNotificationCenter", "Show Notification Center", NO, 65535, 65535, 0, -1 },
[Shortcut_ToggleDoNotDisturb] = { "ToggleDoNotDisturb", "Turn Do Not Disturb on/off", YES, 65535, 65535, 0, -1 },
[Shortcut_ToggleZoomFocusFollowing] = { "ToggleZoomFocusFollowing", "Zoom: Turn focus following on or off", NO, 65535, 65535, 0, -1 },
[Shortcut_ScreenshotOptions] = { "ScreenshotOptions", "Screenshot and recording options", YES, 53, 23, 0x00120000, -1 },
[Shortcut_OpenQuickNote] = { "OpenQuickNote", "Quick note", YES, 113, 12, 0x00800000, -1 },
[Shortcut_ToggleStageManager] = { "ToggleStageManager", "Turn Stage Manager on/off", NO, 65535, 65535, 0, -1 },
[Shortcut_TogglePresenterOverlayLarge] = { "TogglePresenterOverlayLarge", "Turn Presenter Overlay (large) on or off", YES, 65535, 65535, 0, -1 },
[Shortcut_TogglePresenterOverlaySmall] = { "TogglePresenterOverlaySmall", "Turn Presenter Overlay (small) on or off", YES, 65535, 65535, 0, -1 },
[Shortcut_ToggleLiveSpeech] = { "ToggleLiveSpeech", "LiveSpeech: Turn Live Speech on or off", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleLiveSpeechVisibility] = { "ToggleLiveSpeechVisibility", "LiveSpeech: Toggle visibility", YES, 65535, 65535, 0, 14 },
[Shortcut_PauseOrResumeLiveSpeech] = { "PauseOrResumeLiveSpeech", "LiveSpeech: Pause or resume speech", YES, 65535, 65535, 0, 14 },
[Shortcut_CancelLiveSpeech] = { "CancelLiveSpeech", "LiveSpeech: Cancel speech", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleLiveSpeechPhrases] = { "ToggleLiveSpeechPhrases", "LiveSpeech: Hide or show phrases", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleSpeakSelection] = { "ToggleSpeakSelection", "Turn speak selection on or off", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleSpeakItemUnderPointer] = { "ToggleSpeakItemUnderPointer", "Turn speak item under the pointer on or off", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleTypingFeedback] = { "ToggleTypingFeedback", "Turn typing feedback on or off", YES, 65535, 65535, 0, 14 },
[Shortcut_FocusMenuBar] = { "FocusMenuBar", "Move focus to the menu bar", YES, 65535, 120, 0x00840000, -1, -1 },
[Shortcut_FocusDock] = { "FocusDock", "Move focus to the Dock", YES, 65535, 99, 0x00840000, -1, -1 },
[Shortcut_FocusActiveWindow] = { "FocusActiveWindow", "Move focus to active or next window", YES, 65535, 118, 0x00840000, -1, -1 },
[Shortcut_FocusToolbar] = { "FocusToolbar", "Move focus to window toolbar", YES, 65535, 96, 0x00840000, -1, -1 },
[Shortcut_FocusFloatingWindow] = { "FocusFloatingWindow", "Move focus to floating window", YES, 65535, 97, 0x00840000, -1, -1 },
[Shortcut_ToggleKeyboardAccess] = { "ToggleKeyboardAccess", "Turn keyboard access on or off", YES, 65535, 122, 0x00840000, -1, -1 },
[Shortcut_ChangeTabMode] = { "ChangeTabMode", "Change the way Tab moves focus", YES, 65535, 98, 0x00840000, -1, -1 },
[Shortcut_ToggleZoom] = { "ToggleZoom", "Zoom: Turn zoom on or off", NO, 56, 28, 0x00180000, -1, -1 },
[Shortcut_ZoomIn] = { "ZoomIn", "Zoom: Zoom in", NO, 61, 24, 0x00180000, -1, -1 },
[Shortcut_ZoomOut] = { "ZoomOut", "Zoom: Zoom out", NO, 45, 27, 0x00180000, -1, -1 },
[Shortcut_InvertColors] = { "InvertColors", "Invert colors", YES, 56, 28, 0x001c0000, -1, -1 },
[Shortcut_ToggleZoomImageSmoothing] = { "ToggleZoomImageSmoothing", "Zoom: Turn image smoothing on or off", NO, 92, 42, 0x00180000, -1, -1 },
[Shortcut_IncreaseContrast] = { "IncreaseContrast", "Increase contrast", NO, 46, 47, 0x001c0000, -1, -1 },
[Shortcut_DecreaseContrast] = { "DecreaseContrast", "Decrease contrast", NO, 44, 43, 0x001c0000, -1, -1 },
[Shortcut_FocusNextApplicationWindow] = { "FocusNextApplicationWindow", "Move focus to the next window in application", YES, 96, 50, 0x00100000, -1, -1 },
[Shortcut_ScreenshotToFile] = { "ScreenshotToFile", "Save picture of screen as a file", YES, 51, 20, 0x00120000, -1, -1 },
[Shortcut_ScreenshotToClipboard] = { "ScreenshotToClipboard", "Copy picture of screen to the clipboard", YES, 51, 20, 0x00160000, -1, -1 },
[Shortcut_ScreenshotAreaToFile] = { "ScreenshotAreaToFile", "Save picture of selected area as a file", YES, 52, 21, 0x00120000, -1, -1 },
[Shortcut_ScreenshotAreaToClipboard] = { "ScreenshotAreaToClipboard", "Copy picture of selected area to the clipboard", YES, 52, 21, 0x00160000, -1, -1 },
[Shortcut_ShowAllWindows] = { "ShowAllWindows", "Mission Control", YES, 65535, 126, 0x00840000, -1, -1 },
[Shortcut_ShowApplicationWindows] = { "ShowApplicationWindows", "Application windows", YES, 65535, 125, 0x00840000, -1, -1 },
[Shortcut_ShowDesktop] = { "ShowDesktop", "Show desktop", YES, 65535, 103, 0x00800000, -1, -1 },
[Shortcut_ToggleDockHiding] = { "ToggleDockHiding", "Turn Dock hiding on/off", YES, 100, 2, 0x00180000, -1, -1 },
[Shortcut_DecreaseBrightness] = { "DecreaseBrightness", "Decrease display brightness", YES, 65535, 107, 0x00800000, -1, -1 },
[Shortcut_IncreaseBrightness] = { "IncreaseBrightness", "Increase display brightness", YES, 65535, 113, 0x00800000, -1, -1 },
[Shortcut_FocusStatusMenu] = { "FocusStatusMenu", "Move focus to the status menus", YES, 65535, 100, 0x00840000, -1, -1 },
[Shortcut_ToggleVoiceOver] = { "ToggleVoiceOver", "Turn VoiceOver on or off", YES, 65535, 96, 0x00900000, -1, -1 },
[Shortcut_SelectPreviousInputSource] = { "SelectPreviousInputSource", "Select the previous input source", YES, 32, 49, 0x00040000, -1, -1 },
[Shortcut_SelectNextInputSource] = { "SelectNextInputSource", "Select next source in Input menu", YES, 32, 49, 0x000c0000, -1, -1 },
[Shortcut_ShowSpotlight] = { "ShowSpotlight", "Show Spotlight Search", YES, 32, 49, 0x00100000, -1, -1 },
[Shortcut_ShowFinderSearch] = { "ShowFinderSearch", "Show Finder search window", YES, 32, 49, 0x00180000, -1, -1 },
[Shortcut_SwitchToDesktopLeft] = { "SwitchToDesktopLeft", "Move left a space", NO, 65535, 123, 0x00840000, -1, -1 },
[Shortcut_SwitchToDesktopRight] = { "SwitchToDesktopRight", "Move right a space", NO, 65535, 124, 0x00840000, -1, -1 },
[Shortcut_SwitchToDesktop1] = { "SwitchToDesktop1", "Switch to Desktop 1", NO, 65535, 18, 0x00040000, -1, -1 },
[Shortcut_SwitchToDesktop2] = { "SwitchToDesktop2", "Switch to Desktop 2", NO, 65535, 19, 0x00040000, -1, -1 },
[Shortcut_SwitchToDesktop3] = { "SwitchToDesktop3", "Switch to Desktop 3", NO, 65535, 20, 0x00040000, -1, -1 },
[Shortcut_SwitchToDesktop4] = { "SwitchToDesktop4", "Switch to Desktop 4", NO, 65535, 21, 0x00040000, -1, -1 },
[Shortcut_ShowContextualMenu] = { "ShowContextualMenu", "Show contextual menu", YES, 65535, 36, 0x00040000, 15, 0 },
[Shortcut_ShowLaunchpad] = { "ShowLaunchpad", "Show Launchpad", NO, 65535, 65535, 0, -1, -1 },
[Shortcut_ShowAccessibilityControls] = { "ShowAccessibilityControls", "Show Accessibility controls", YES, 65535, 96, 0x00980000, -1, -1 },
[Shortcut_ShowNotificationCenter] = { "ShowNotificationCenter", "Show Notification Center", NO, 65535, 65535, 0, -1, -1 },
[Shortcut_ToggleDoNotDisturb] = { "ToggleDoNotDisturb", "Turn Do Not Disturb on/off", YES, 65535, 65535, 0, -1, -1 },
[Shortcut_ToggleZoomFocusFollowing] = { "ToggleZoomFocusFollowing", "Zoom: Turn focus following on or off", NO, 65535, 65535, 0, -1, -1 },
[Shortcut_ScreenshotOptions] = { "ScreenshotOptions", "Screenshot and recording options", YES, 53, 23, 0x00120000, -1, -1 },
[Shortcut_OpenQuickNote] = { "OpenQuickNote", "Quick note", YES, 113, 12, 0x00800000, -1, -1 },
[Shortcut_ToggleStageManager] = { "ToggleStageManager", "Turn Stage Manager on/off", NO, 65535, 65535, 0, -1, -1 },
[Shortcut_TogglePresenterOverlayLarge] = { "TogglePresenterOverlayLarge", "Turn Presenter Overlay (large) on or off", YES, 65535, 65535, 0, -1, -1 },
[Shortcut_TogglePresenterOverlaySmall] = { "TogglePresenterOverlaySmall", "Turn Presenter Overlay (small) on or off", YES, 65535, 65535, 0, -1, -1 },
[Shortcut_ToggleLiveSpeech] = { "ToggleLiveSpeech", "LiveSpeech: Turn Live Speech on or off", YES, 65535, 65535, 0, 14, 0 },
[Shortcut_ToggleLiveSpeechVisibility] = { "ToggleLiveSpeechVisibility", "LiveSpeech: Toggle visibility", YES, 65535, 65535, 0, 14, 0 },
[Shortcut_PauseOrResumeLiveSpeech] = { "PauseOrResumeLiveSpeech", "LiveSpeech: Pause or resume speech", YES, 65535, 65535, 0, 14, 0 },
[Shortcut_CancelLiveSpeech] = { "CancelLiveSpeech", "LiveSpeech: Cancel speech", YES, 65535, 65535, 0, 14, 0 },
[Shortcut_ToggleLiveSpeechPhrases] = { "ToggleLiveSpeechPhrases", "LiveSpeech: Hide or show phrases", YES, 65535, 65535, 0, 14, 0 },
[Shortcut_ToggleSpeakSelection] = { "ToggleSpeakSelection", "Turn speak selection on or off", YES, 65535, 65535, 0, 14, 0 },
[Shortcut_ToggleSpeakItemUnderPointer] = { "ToggleSpeakItemUnderPointer", "Turn speak item under the pointer on or off", YES, 65535, 65535, 0, 14, 0 },
[Shortcut_ToggleTypingFeedback] = { "ToggleTypingFeedback", "Turn typing feedback on or off", YES, 65535, 65535, 0, 14, 0 },
[Shortcut_MinimizeWindow] = { "MinimizeWindow", "Windows: Minimize", YES, 109, 46, 0x00100000, 15, 4 },
[Shortcut_ZoomWindow] = { "ZoomWindow", "Windows: Zoom", YES, 65535, 65535, 0, 15, 4 },
[Shortcut_FillWindow] = { "FillWindow", "Windows: Fill", YES, 102, 3, 0x00840000, 15, 4 },
[Shortcut_CenterWindow] = { "CenterWindow", "Windows: Center", YES, 99, 8, 0x00840000, 15, 4 },
[Shortcut_RestoreWindow] = { "RestoreWindow", "Windows: Return to Previous Size", YES, 114, 15, 0x00840000, 15, 4 },
[Shortcut_TileLeftHalf] = { "TileLeftHalf", "Windows: Tile Left Half", YES, 65535, 123, 0x00840000, 15, 4 },
[Shortcut_TileRightHalf] = { "TileRightHalf", "Windows: Tile Right Half", YES, 65535, 124, 0x00840000, 15, 4 },
[Shortcut_TileTopHalf] = { "TileTopHalf", "Windows: Tile Top Half", YES, 65535, 126, 0x00840000, 15, 4 },
[Shortcut_TileBottomHalf] = { "TileBottomHalf", "Windows: Tile Bottom Half", YES, 65535, 125, 0x00840000, 15, 4 },
[Shortcut_TileTopLeftQuarter] = { "TileTopLeftQuarter", "Windows: Tile Top-Left Quarter", YES, 65535, 65535, 0, 15, 4 },
[Shortcut_TileTopRightQuarter] = { "TileTopRightQuarter", "Windows: Tile Top-Right Quarter", YES, 65535, 65535, 0, 15, 4 },
[Shortcut_TileBottomLeftQuarter] = { "TileBottomLeftQuarter", "Windows: Tile Bottom-Left Quarter", YES, 65535, 65535, 0, 15, 4 },
[Shortcut_TileBottomRightQuarter] = { "TileBottomRightQuarter", "Windows: Tile Bottom-Right Quarter", YES, 65535, 65535, 0, 15, 4 },
[Shortcut_ArrangeLeftRight] = { "ArrangeLeftRight", "Windows: Arrange Left and Right", YES, 65535, 123, 0x00860000, 15, 4 },
[Shortcut_ArrangeRightLeft] = { "ArrangeRightLeft", "Windows: Arrange Right and Left", YES, 65535, 124, 0x00860000, 15, 4 },
[Shortcut_ArrangeTopBottom] = { "ArrangeTopBottom", "Windows: Arrange Top and Bottom", YES, 65535, 126, 0x00860000, 15, 4 },
[Shortcut_ArrangeBottomTop] = { "ArrangeBottomTop", "Windows: Arrange Bottom and Top", YES, 65535, 125, 0x00860000, 15, 4 },
[Shortcut_ArrangeQuarters] = { "ArrangeQuarters", "Windows: Arrange in Quarters", YES, 65535, 65535, 0, 15, 4 },
[Shortcut_FullScreenTileLeft] = { "FullScreenTileLeft", "Windows: Full-Screen Tile Left", YES, 65535, 65535, 0, 15, 4 },
[Shortcut_FullScreenTileRight] = { "FullScreenTileRight", "Windows: Full-Screen Tile Right", YES, 65535, 65535, 0, 15, 4 },
};
static const int numSymbolicHotkeys = sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]);
@@ -393,6 +434,11 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
int uid = [hkNumber intValue];
// Ignore hotkeys out of range, as well as 0, which is the "invalid value" for intValue
if (uid <= 0 || uid >= numSymbolicHotkeys) {
continue;
}
id hkDesc = hkObj[hkNumber];
if (![hkDesc isKindOfClass:[NSDictionary class]]) {
plog(LL_DEBUG, "hotkey descriptor '%s' isn't instance of NSDictionary (class=%s)", toCString(hkDesc),
@@ -477,8 +523,19 @@ static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymboli
for (int uid = 0; uid < numSymbolicHotkeys; ++uid) {
struct SymbolicHotKey* hotkey = &hotkeys[uid];
if (!hotkey->enabled) continue;
if (hotkey->macOSVersion > macOSVersion.majorVersion) continue;
if (!hotkey->enabled) {
continue;
}
if (hotkey->macOSVersionMajor > macOSVersion.majorVersion ||
(hotkey->macOSVersionMajor == macOSVersion.majorVersion && hotkey->macOSVersionMinor > macOSVersion.minorVersion)) {
continue;
}
if (hotkey->character == 0xFFFF && hotkey->key == 0xFFFF) {
continue;
}
char keyCharBuf[64];
const char *keyCharStr = keyCharBuf;
@@ -577,15 +634,6 @@ static bool ensureInitializedAndEnabled() {
return enabled;
}
// JBR-8422
const NSOperatingSystemVersion macOSVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
if (macOSVersion.majorVersion > 15 || (macOSVersion.majorVersion == 15 && macOSVersion.minorVersion >= 4)) {
state.initialized = true;
state.enabled = false;
pthread_mutex_unlock(&state.mutex);
return false;
}
state.initialized = true;
state.enabled = true;
[SystemHotkey subscribeToChanges];

View File

@@ -28,6 +28,9 @@
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID sjm_getScrollBar = NULL;
/*
* Implementation of the accessibility peer for the ScrollArea role
*/
@@ -57,10 +60,30 @@
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
// Firstly, try to get the scroll bar using getHorizontalScrollBar/getVerticalScrollBar methods of JScrollPane.
jobject scrollBar = NULL;
GET_CACCESSIBILITY_CLASS_RETURN(nil);
GET_STATIC_METHOD_RETURN(sjm_getScrollBar, sjc_CAccessibility, "getScrollBar",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)Ljavax/accessibility/Accessible;", nil);
scrollBar = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getScrollBar, fAccessible, fComponent, orientation);
CHECK_EXCEPTION();
if (scrollBar != NULL) {
CommonComponentAccessibility *axScrollBar = nil;
DECLARE_CLASS_RETURN(sjc_Accessible, "javax/accessibility/Accessible", nil);
if ((*env)->IsInstanceOf(env, scrollBar, sjc_Accessible)) {
axScrollBar = [CommonComponentAccessibility createWithAccessible:scrollBar withEnv:env withView:fView];
}
(*env)->DeleteLocalRef(env, scrollBar);
if (axScrollBar != nil) {
return axScrollBar;
}
}
// Otherwise, try to search for the scroll bar within the children.
NSArray *children = [CommonComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:YES];
if ([children count] <= 0) return nil;
// The scroll bars are in the children.
CommonComponentAccessibility *aElement;
NSEnumerator *enumerator = [children objectEnumerator];
while ((aElement = (CommonComponentAccessibility *)[enumerator nextObject])) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,15 @@
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
#define MTL_GPU_FAMILY_MAC_TXT_SIZE 16384
typedef enum {
MTLDCM_SYSTEM_UNDEFINED,
MTLDCM_SYSTEM_SLEEP,
MTLDCM_SYSTEM_WAKEUP,
MTLDCM_DISPLAY_SLEEP,
MTLDCM_DISPLAY_WAKEUP,
MTLDCM_DISPLAY_RECONFIGURE
} MTLContextStoreNotification;
/**
* The MTLCommandBufferWrapper class contains command buffer and
* associated resources that will be released in completion handler
@@ -110,13 +119,14 @@
+ (MTLContext*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(jlong)pDst;
+ (NSMutableDictionary*) contextStore;
+ (void) processContextStoreNotification:(MTLContextStoreNotification)notification;
+ (MTLContext*) createContextWithDeviceIfAbsent:(jint)displayID shadersLib:(NSString*)mtlShadersLib;
- (id)initWithDevice:(id<MTLDevice>)device shadersLib:(NSString*)mtlShadersLib;
- (void)dealloc;
- (NSArray<NSNumber*>*)getDisplayLinkDisplayIds;
- (void)handleDisplayLink:(BOOL)enabled displayID:(jint)displayID source:(const char*)src;
- (void)createDisplayLinkIfAbsent: (jint)displayID;
- (void)createDisplayLinkIfAbsent: (NSNumber*)displayID;
/**
* Resets the current clip state (disables both scissor and depth tests).

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,8 @@
// to avoid multiple start/stop displaylink operations. It speeds up
// scenarios with multiple subsequent updates.
#define KEEP_ALIVE_COUNT 4
#define CV_DISPLAYLINK_FAIL_DELAY 1.0
#define MAX_DISPLAYLINK_FAIL_COUNT 5
#define TO_MS(x) (1000.0 * (x))
#define TO_FPS(x) (1.0 / (x))
@@ -55,11 +57,12 @@
extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
extern BOOL isDisplaySyncEnabled();
extern BOOL MTLLayer_isExtraRedrawEnabled();
extern int getBPPFromModeString(CFStringRef mode);
extern void dumpDisplayInfo(jint displayID);
extern BOOL isValidDisplayMode(CGDisplayModeRef mode);
#define STATS_CVLINK 0
#define TRACE_PWM_NOTIF 0
#define TRACE_NOTIF 0
#define TRACE_CVLINK 0
#define TRACE_CVLINK_WARN 0
@@ -79,10 +82,6 @@ extern int getBPPFromModeString(CFStringRef mode);
} \
}
boolean_t mtlc_IsDisplayReallyActive(CGDirectDisplayID displayID) {
return CGDisplayIsActive(displayID) & !CGDisplayIsAsleep(displayID) && CGDisplayIsOnline(displayID);
}
/* 60 fps typically => exponential smoothing on 0.5s */
static const NSTimeInterval EXP_AVG_WEIGHT = (1.0 / 30.0);
static const NSTimeInterval EXP_INV_WEIGHT = (1.0 - EXP_AVG_WEIGHT);
@@ -101,15 +100,34 @@ typedef struct {
CVDisplayLinkRef displayLink;
MTLContext* mtlc;
jint redrawCount;
jint failCount;
jint avgDisplayLinkSamples;
CFTimeInterval lastRedrawTime;
CFTimeInterval lastDisplayLinkTime;
CFTimeInterval avgDisplayLinkTime;
CFTimeInterval lastStatTime;
} MTLDisplayLinkState;
/* debugging helper functions */
static const char* mtlContextStoreNotificationToStr(MTLContextStoreNotification notification) {
#undef CASE_MTL_OP
#define CASE_MTL_OP(X) \
case MTLDCM_##X: \
return #X;
switch (notification) {
CASE_MTL_OP(SYSTEM_SLEEP)
CASE_MTL_OP(SYSTEM_WAKEUP)
CASE_MTL_OP(DISPLAY_SLEEP)
CASE_MTL_OP(DISPLAY_WAKEUP)
CASE_MTL_OP(DISPLAY_RECONFIGURE)
default:
return "";
}
#undef CASE_MTL_OP
}
@implementation MTLCommandBufferWrapper {
id<MTLCommandBuffer> _commandBuffer;
NSMutableArray * _pooledTextures;
@@ -194,69 +212,42 @@ typedef struct {
extern void initSamplers(id<MTLDevice> device);
+ (void)mtlc_systemOrScreenWillSleep:(NSNotification*)notification {
if (TRACE_PWM_NOTIF) {
if (TRACE_NOTIF) {
NSLog(@"MTLContext_systemOrScreenWillSleep[%@]", [notification name]);
}
if (isDisplaySyncEnabled()) {
[ThreadUtilities performOnMainThreadNowOrLater:NO // critical
block:^(){
for (MTLContext *mtlc in [MTLContext.contextStore allValues]) {
const NSArray<NSNumber*> *displayIDs = [mtlc getDisplayLinkDisplayIds]; // old ids
if (TRACE_PWM_NOTIF) {
NSLog(@"MTLContext_systemOrScreenWillSleep: ctx=%p (%d displayLinks)",
mtlc, (int) displayIDs.count);
}
for (NSNumber* displayIDVal in displayIDs) {
const jint displayID = [displayIDVal intValue];
const BOOL active = mtlc_IsDisplayReallyActive(displayID);
if (TRACE_PWM_NOTIF) {
NSLog(@"MTLContext_systemOrScreenWillSleep: displayId=%d active=%d", displayID, active);
}
if (TRACE_DISPLAY) {
[MTLContext dumpDisplayInfo:displayID];
}
if ((notification.name == NSWorkspaceWillSleepNotification)|| !active) {
[mtlc destroyDisplayLink:displayID];
}
}
}
}];
MTLContextStoreNotification ctxNotif = MTLDCM_SYSTEM_UNDEFINED;
if (notification.name == NSWorkspaceWillSleepNotification) {
ctxNotif = MTLDCM_SYSTEM_SLEEP;
} else if (notification.name == NSWorkspaceWillSleepNotification) {
ctxNotif = MTLDCM_DISPLAY_SLEEP;
}
if (ctxNotif != MTLDCM_SYSTEM_UNDEFINED) {
[ThreadUtilities performOnMainThreadNowOrLater:NO // critical
block:^() {
[MTLContext processContextStoreNotification:ctxNotif];
}];
}
}
}
+ (void)mtlc_systemOrScreenDidWake:(NSNotification*)notification {
if (TRACE_PWM_NOTIF) {
if (TRACE_NOTIF) {
NSLog(@"MTLContext_systemOrScreenDidWake[%@]", [notification name]);
}
if (isDisplaySyncEnabled()) {
[ThreadUtilities performOnMainThreadNowOrLater:NO // critical
block:^(){
for (MTLContext *mtlc in [MTLContext.contextStore allValues]) {
const NSArray<NSNumber*>* displayIDs = [mtlc getDisplayLinkDisplayIds]; // old ids
if (TRACE_PWM_NOTIF) {
NSLog(@"MTLContext_systemOrScreenDidWake: ctx=%p (%d displayLinks)",
mtlc, (int)displayIDs.count);
}
for (NSNumber* displayIDVal in displayIDs) {
const jint displayID = [displayIDVal intValue];
const BOOL active = mtlc_IsDisplayReallyActive(displayID);
if (TRACE_PWM_NOTIF) {
NSLog(@"MTLContext_systemOrScreenDidWake: displayId=%d active=%d", displayID, active);
}
if (TRACE_DISPLAY) {
[MTLContext dumpDisplayInfo:displayID];
}
if (active) {
// (if needed will start a new display link thread):
[mtlc createDisplayLinkIfAbsent:displayID];
}
}
}
}];
MTLContextStoreNotification ctxNotif = MTLDCM_SYSTEM_UNDEFINED;
if (notification.name == NSWorkspaceDidWakeNotification) {
ctxNotif = MTLDCM_SYSTEM_WAKEUP;
} else if (notification.name == NSWorkspaceScreensDidWakeNotification) {
ctxNotif = MTLDCM_DISPLAY_WAKEUP;
}
if (ctxNotif != MTLDCM_SYSTEM_UNDEFINED) {
[ThreadUtilities performOnMainThreadNowOrLater:NO // critical
block:^() {
[MTLContext processContextStoreNotification:ctxNotif];
}];
}
}
}
@@ -265,15 +256,17 @@ extern void initSamplers(id<MTLDevice> device);
if (!notificationRegistered) {
notificationRegistered = true;
NSNotificationCenter *ctr = [[NSWorkspace sharedWorkspace] notificationCenter];
Class clz = [MTLContext class];
if (isDisplaySyncEnabled()) {
NSNotificationCenter *ctr = [[NSWorkspace sharedWorkspace] notificationCenter];
Class clz = [MTLContext class];
[ctr addObserver:clz selector:@selector(mtlc_systemOrScreenWillSleep:) name:NSWorkspaceWillSleepNotification object:nil];
[ctr addObserver:clz selector:@selector(mtlc_systemOrScreenDidWake:) name:NSWorkspaceDidWakeNotification object:nil];
[ctr addObserver:clz selector:@selector(mtlc_systemOrScreenWillSleep:) name:NSWorkspaceWillSleepNotification object:nil];
[ctr addObserver:clz selector:@selector(mtlc_systemOrScreenDidWake:) name:NSWorkspaceDidWakeNotification object:nil];
// NSWorkspaceScreensDidWakeNotification is first sent:
[ctr addObserver:clz selector:@selector(mtlc_systemOrScreenWillSleep:) name:NSWorkspaceScreensDidSleepNotification object:nil];
[ctr addObserver:clz selector:@selector(mtlc_systemOrScreenDidWake:) name:NSWorkspaceScreensDidWakeNotification object:nil];
// NSWorkspaceScreensDidWakeNotification is first sent:
[ctr addObserver:clz selector:@selector(mtlc_systemOrScreenWillSleep:) name:NSWorkspaceScreensDidSleepNotification object:nil];
[ctr addObserver:clz selector:@selector(mtlc_systemOrScreenDidWake:) name:NSWorkspaceScreensDidWakeNotification object:nil];
}
}
}
@@ -289,7 +282,82 @@ extern void initSamplers(id<MTLDevice> device);
return _contextStore;
}
+ (void) processContextStoreNotification:(MTLContextStoreNotification)notification {
AWT_ASSERT_APPKIT_THREAD;
if (isDisplaySyncEnabled()) {
const char* name = mtlContextStoreNotificationToStr(notification);
if (TRACE_NOTIF) {
NSLog(@"MTLContext_processContextStoreNotification[%s]: enter", name);
}
for (MTLContext *mtlc in [MTLContext.contextStore allValues]) {
const NSArray<NSNumber*>* displayIDs = [mtlc getDisplayLinkDisplayIds]; // old ids
if (TRACE_NOTIF) {
NSLog(@"MTLContext_processContextStoreNotification[%s]: ctx=%p (%d displayLinks)",
name, mtlc, (int)displayIDs.count);
}
for (NSNumber* displayIDVal in displayIDs) {
const jint displayID = [displayIDVal intValue];
// CGDisplayIsActive is not always reliable:
BOOL active = CGDisplayIsActive(displayID) ? YES : NO;
if (active) {
// Ensure mode is really valid:
// CGDisplayCopyDisplayMode can return NULL if displayID is invalid
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayID);
if (mode != NULL) {
active = isValidDisplayMode(mode);
CGDisplayModeRelease(mode);
}
}
if (TRACE_NOTIF) {
NSLog(@"MTLContext_processContextStoreNotification[%s]: displayId=%d active=%d",
name, displayID, active);
}
if (TRACE_DISPLAY) {
dumpDisplayInfo(displayID);
}
switch (notification) {
case MTLDCM_SYSTEM_SLEEP:
// kill all CVDisplayLinks:
[mtlc destroyDisplayLink:displayID];
break;
case MTLDCM_DISPLAY_SLEEP:
if (!active) {
// kill CVDisplayLinks for inactive displays:
[mtlc destroyDisplayLink:displayID];
}
break;
case MTLDCM_SYSTEM_WAKEUP:
case MTLDCM_DISPLAY_WAKEUP:
if (active) {
// (if needed will start a new display link thread):
[mtlc createDisplayLinkIfAbsent:@(displayID)];
}
break;
case MTLDCM_DISPLAY_RECONFIGURE:
if (active) {
// (if needed will start a new display link thread):
[mtlc createDisplayLinkIfAbsent:@(displayID)];
} else {
// kill CVDisplayLinks for inactive displays:
[mtlc destroyDisplayLink:displayID];
}
break;
default:
NSLog(@"Unsupported notification : %d", notification);
}
}
if (TRACE_NOTIF) {
NSLog(@"MTLContext_processContextStoreNotification[%s]: exit", name);
}
}
}
}
+ (MTLContext*) createContextWithDeviceIfAbsent:(jint)displayID shadersLib:(NSString*)mtlShadersLib {
AWT_ASSERT_APPKIT_THREAD;
// Initialization code here.
// note: the device reference is NS_RETURNS_RETAINED, should be released by the caller:
bool shouldReleaseDevice = true;
@@ -326,8 +394,7 @@ extern void initSamplers(id<MTLDevice> device);
[mtlc release];
J2dRlsTraceLn4(J2D_TRACE_INFO,
"MTLContext_createContextWithDeviceIfAbsent: new context(%p) for display=%d device=\"%s\" "
"retainCount=%d", mtlc, displayID, [mtlc.device.name UTF8String],
mtlc.retainCount);
"retainCount=%d", mtlc, displayID, [mtlc.device.name UTF8String], mtlc.retainCount);
}
} else {
if (![mtlc.shadersLib isEqualToString:mtlShadersLib]) {
@@ -340,18 +407,18 @@ extern void initSamplers(id<MTLDevice> device);
[mtlc retain];
J2dRlsTraceLn4(J2D_TRACE_INFO,
"MTLContext_createContextWithDeviceIfAbsent: reuse context(%p) for display=%d device=\"%s\" "
"retainCount=%d", mtlc, displayID, [mtlc.device.name UTF8String],
mtlc.retainCount);
"retainCount=%d", mtlc, displayID, [mtlc.device.name UTF8String], mtlc.retainCount);
}
if (shouldReleaseDevice) {
[device release];
}
// (will start a new display link thread if needed):
[mtlc createDisplayLinkIfAbsent:displayID];
[mtlc createDisplayLinkIfAbsent:@(displayID)];
return mtlc;
}
+ (void) releaseContext:(MTLContext*) mtlc {
AWT_ASSERT_APPKIT_THREAD;
id<NSCopying> deviceID = nil;
if (@available(macOS 10.13, *)) {
deviceID = @(mtlc.device.registryID);
@@ -377,6 +444,7 @@ extern void initSamplers(id<MTLDevice> device);
}
- (id)initWithDevice:(id<MTLDevice>)mtlDevice shadersLib:(NSString*)mtlShadersLib {
AWT_ASSERT_APPKIT_THREAD;
self = [super init];
if (self) {
device = mtlDevice;
@@ -424,126 +492,53 @@ extern void initSamplers(id<MTLDevice> device);
return self;
}
+ (void)dumpDisplayInfo: (jint)displayID {
// Returns a Boolean value indicating whether a display is active.
jint displayIsActive = CGDisplayIsActive(displayID);
// Returns a Boolean value indicating whether a display is always in a mirroring set.
jint displayIsalwaysInMirrorSet = CGDisplayIsAlwaysInMirrorSet(displayID);
// Returns a Boolean value indicating whether a display is sleeping (and is therefore not drawable).
jint displayIsAsleep = CGDisplayIsAsleep(displayID);
// Returns a Boolean value indicating whether a display is built-in, such as the internal display in portable systems.
jint displayIsBuiltin = CGDisplayIsBuiltin(displayID);
// Returns a Boolean value indicating whether a display is in a mirroring set.
jint displayIsInMirrorSet = CGDisplayIsInMirrorSet(displayID);
// Returns a Boolean value indicating whether a display is in a hardware mirroring set.
jint displayIsInHWMirrorSet = CGDisplayIsInHWMirrorSet(displayID);
// Returns a Boolean value indicating whether a display is the main display.
jint displayIsMain = CGDisplayIsMain(displayID);
// Returns a Boolean value indicating whether a display is connected or online.
jint displayIsOnline = CGDisplayIsOnline(displayID);
// Returns a Boolean value indicating whether a display is running in a stereo graphics mode.
jint displayIsStereo = CGDisplayIsStereo(displayID);
// For a secondary display in a mirroring set, returns the primary display.
CGDirectDisplayID displayMirrorsDisplay = CGDisplayMirrorsDisplay(displayID);
// Returns the primary display in a hardware mirroring set.
CGDirectDisplayID displayPrimaryDisplay = CGDisplayPrimaryDisplay(displayID);
// Returns the width and height of a display in millimeters.
CGSize size = CGDisplayScreenSize(displayID);
NSLog(@"CGDisplay[%d]{\n"
"displayIsActive=%d\n"
"displayIsalwaysInMirrorSet=%d\n"
"displayIsAsleep=%d\n"
"displayIsBuiltin=%d\n"
"displayIsInMirrorSet=%d\n"
"displayIsInHWMirrorSet=%d\n"
"displayIsMain=%d\n"
"displayIsOnline=%d\n"
"displayIsStereo=%d\n"
"displayMirrorsDisplay=%d\n"
"displayPrimaryDisplay=%d\n"
"displayScreenSizey=[%.1lf %.1lf]\n",
displayID,
displayIsActive,
displayIsalwaysInMirrorSet,
displayIsAsleep,
displayIsBuiltin,
displayIsInMirrorSet,
displayIsInHWMirrorSet,
displayIsMain,
displayIsOnline,
displayIsStereo,
displayMirrorsDisplay,
displayPrimaryDisplay,
size.width, size.height
);
// CGDisplayCopyDisplayMode can return NULL if displayID is invalid
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayID);
if (mode) {
// Getting Information About a Display Mode
jint h = -1, w = -1, bpp = -1;
jdouble refreshRate = 0.0;
// Returns the width of the specified display mode.
w = CGDisplayModeGetWidth(mode);
// Returns the height of the specified display mode.
h = CGDisplayModeGetHeight(mode);
// Returns the pixel encoding of the specified display mode.
// Deprecated
CFStringRef currentBPP = CGDisplayModeCopyPixelEncoding(mode);
bpp = getBPPFromModeString(currentBPP);
CFRelease(currentBPP);
// Returns the refresh rate of the specified display mode.
refreshRate = CGDisplayModeGetRefreshRate(mode);
NSLog(@"CGDisplayMode[%d]: w=%d, h=%d, bpp=%d, freq=%.2lf hz",
displayID, w, h, bpp, refreshRate);
CGDisplayModeRelease(mode);
}
}
- (NSArray<NSNumber*>*)getDisplayLinkDisplayIds {
return [_displayLinkStates allKeys];
}
- (void)createDisplayLinkIfAbsent: (jint)displayID {
if (isDisplaySyncEnabled()) {
MTLDisplayLinkState *dlState = [self getDisplayLinkState:displayID];
- (void)createDisplayLinkIfAbsent: (NSNumber*)displayID {
AWT_ASSERT_APPKIT_THREAD;
if (_displayLinkStates != nil) {
MTLDisplayLinkState *dlState = [self getDisplayLinkState:[displayID intValue]];
if ((dlState != nil) && (dlState->displayLink != nil)) {
return;
}
if (TRACE_DISPLAY) {
[MTLContext dumpDisplayInfo:displayID];
dumpDisplayInfo([displayID intValue]);
}
CVDisplayLinkRef _displayLink;
if (TRACE_CVLINK) {
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_createDisplayLinkIfAbsent: "
"ctx=%p displayID=%d", self, displayID);
"ctx=%p displayID=%d", self, [displayID intValue]);
}
CHECK_CVLINK("CreateWithCGDisplay", nil, &_displayLink,
CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink));
CVDisplayLinkCreateWithCGDisplay([displayID intValue], &_displayLink));
if (_displayLink == nil) {
J2dRlsTraceLn(J2D_TRACE_ERROR,
"MTLContext_createDisplayLinkIfAbsent: Failed to initialize CVDisplayLink.");
if (dlState == nil) {
dlState = malloc(sizeof(MTLDisplayLinkState));
dlState->displayID = [displayID intValue];
dlState->displayLink = nil;
dlState->failCount = 0;
_displayLinkStates[displayID] = [NSValue valueWithPointer:dlState];
}
if (dlState->failCount >= MAX_DISPLAYLINK_FAIL_COUNT) {
J2dTraceLn(J2D_TRACE_ERROR,
"MTLLayer.createDisplayLink --- unable to create CVDisplayLink.");
dlState->failCount = 0;
return;
}
dlState->failCount++;
[self performSelector:@selector(createDisplayLinkIfAbsent:)
withObject:displayID
afterDelay:CV_DISPLAYLINK_FAIL_DELAY];
} else {
J2dRlsTraceLn3(J2D_TRACE_INFO, "MTLContext_destroyDisplayLinkMTLContext_createDisplayLinkIfAbsent["
J2dRlsTraceLn3(J2D_TRACE_INFO, "MTLContext_createDisplayLinkIfAbsent["
"ctx=%p displayID=%d] displayLink=%p",
self, displayID, _displayLink);
bool isNewDisplayLink = false;
@@ -552,11 +547,12 @@ extern void initSamplers(id<MTLDevice> device);
isNewDisplayLink = true;
}
// update:
dlState->displayID = displayID;
dlState->displayID = [displayID intValue];
dlState->displayLink = _displayLink;
dlState->mtlc = self;
dlState->redrawCount = 0;
dlState->failCount = 0;
dlState->avgDisplayLinkSamples = 0;
dlState->lastRedrawTime = 0.0;
dlState->lastDisplayLinkTime = 0.0;
@@ -565,7 +561,7 @@ extern void initSamplers(id<MTLDevice> device);
if (isNewDisplayLink) {
// publish fully initialized object:
_displayLinkStates[@(displayID)] = [NSValue valueWithPointer:dlState];
_displayLinkStates[displayID] = [NSValue valueWithPointer:dlState];
}
CHECK_CVLINK("SetOutputCallback", nil, &_displayLink,
@@ -595,7 +591,8 @@ extern void initSamplers(id<MTLDevice> device);
}
- (void)destroyDisplayLink: (jint)displayID {
if (isDisplaySyncEnabled()) {
AWT_ASSERT_APPKIT_THREAD;
if (_displayLinkStates != nil) {
MTLDisplayLinkState *dlState = [self getDisplayLinkState:displayID];
if (dlState == nil) {
return;
@@ -620,17 +617,21 @@ extern void initSamplers(id<MTLDevice> device);
// Release display link thread:
CVDisplayLinkRelease(_displayLink);
dlState->displayLink = nil;
J2dRlsTraceLn2(J2D_TRACE_INFO, "MTLContext_destroyDisplayLink["
"ctx=%p displayID=%d] done",
self, displayID);
}
}
- (void)handleDisplayLink: (BOOL)enabled displayID:(jint)displayID source:(const char*)src {
AWT_ASSERT_APPKIT_THREAD;
MTLDisplayLinkState *dlState = [self getDisplayLinkState:displayID];
if (dlState == nil) {
return;
}
CVDisplayLinkRef _displayLink = dlState->displayLink;
if (_displayLink == nil) {
if (TRACE_CVLINK) {
if (TRACE_CVLINK_DEBUG) {
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_handleDisplayLink[%s]: "
"displayLink is nil (disabled).", src);
}
@@ -1023,7 +1024,6 @@ extern void initSamplers(id<MTLDevice> device);
- (void) redraw:(NSNumber*)displayIDNumber {
AWT_ASSERT_APPKIT_THREAD;
const CFTimeInterval now = CACurrentMediaTime();
const jint displayID = [displayIDNumber intValue];
MTLDisplayLinkState *dlState = [self getDisplayLinkState:displayID];
@@ -1034,6 +1034,7 @@ extern void initSamplers(id<MTLDevice> device);
* Avoid repeated invocations by UIKit Main Thread
* if blocked while many mtlDisplayLinkCallback() are dispatched
*/
const CFTimeInterval now = CACurrentMediaTime();
const CFTimeInterval elapsed = (dlState->lastRedrawTime != 0.0) ? (now - dlState->lastRedrawTime) : -1.0;
CFTimeInterval threshold = (dlState->avgDisplayLinkSamples >= 10) ?
@@ -1078,7 +1079,7 @@ extern void initSamplers(id<MTLDevice> device);
}
CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* nowTime, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) {
JNI_COCOA_ENTER(env);
JNI_COCOA_ENTER();
J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_mtlDisplayLinkCallback: ctx=%p", displayLinkContext);
MTLDisplayLinkState *dlState = (__bridge MTLDisplayLinkState*) displayLinkContext;
@@ -1110,25 +1111,18 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
}
}
const BOOL active = mtlc_IsDisplayReallyActive(displayID);
if (TRACE_CVLINK_DEBUG) {
NSLog(@"MTLContext_mtlDisplayLinkCallback: ctx=%p displayID=%d active=%d (display link = %p)",
mtlc, displayID, active, dlState->displayLink);
}
if (!active) {
if (TRACE_CVLINK) {
NSLog(@"MTLContext_mtlDisplayLinkCallback: displayId=%d active=%d "
"=> destroyDisplayLink", displayID, active);
/* defensive programming (should not happen) */
if ([ThreadUtilities blockingMainThread]) {
if (TRACE_CVLINK_WARN) {
NSLog(@"MTLContext_mtlDisplayLinkCallback: ctx=%p - invalid state: blockingMainThread = YES !",
displayLinkContext);
}
if (TRACE_DISPLAY) {
[MTLContext dumpDisplayInfo:displayID];
}
[mtlc destroyDisplayLink:displayID];
} else {
[ThreadUtilities performOnMainThread:@selector(redraw:) on:mtlc withObject:@(displayID)
waitUntilDone:NO useJavaModes:NO]; // critical
return kCVReturnError;
}
JNI_COCOA_EXIT(env);
[ThreadUtilities performOnMainThread:@selector(redraw:) on:mtlc withObject:@(displayID)
waitUntilDone:NO useJavaModes:NO]; // critical
JNI_COCOA_EXIT();
return kCVReturnSuccess;
}
@@ -1183,6 +1177,7 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
}
- (void)haltRedraw {
AWT_ASSERT_APPKIT_THREAD;
if (_displayLinkStates != nil) {
if (TRACE_CVLINK) {
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLContext_haltRedraw: ctx=%p", self);
@@ -1194,7 +1189,12 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
[_layers removeAllObjects];
}
if (_displayLinkStates.count > 0) {
for (NSNumber* displayIDVal in [self getDisplayLinkDisplayIds]) {
const NSArray<NSNumber*>* displayIDs = [self getDisplayLinkDisplayIds]; // old ids
if (TRACE_CVLINK) {
NSLog(@"MTLContext_haltRedraw: ctx=%p (%d displayLinks)",
self, (int) displayIDs.count);
}
for (NSNumber* displayIDVal in displayIDs) {
const jint displayID = [displayIDVal intValue];
[self destroyDisplayLink:displayID];

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -127,3 +127,14 @@ Java_sun_java2d_metal_MTLGraphicsConfig_nativeGetMaxTextureSize
return (jint)MTL_GPU_FAMILY_MAC_TXT_SIZE;
}
JNIEXPORT void JNICALL
Java_sun_java2d_metal_MTLGraphicsConfig_displayReconfigurationDone
(JNIEnv *env, jclass mtlgc)
{
JNI_COCOA_ENTER(env);
[MTLContext processContextStoreNotification:MTLDCM_DISPLAY_RECONFIGURE];
JNI_COCOA_EXIT(env);
}

View File

@@ -191,7 +191,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "[%.6lf] MTLLayer_blitTexture: skip drawable [skip blit] nextDrawableCount = %d",
CACurrentMediaTime(), self.nextDrawableCount);
}
[self startRedraw];
[self startRedrawIfNeeded];
return;
}
@@ -371,7 +371,7 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
}
- (void) blitCallback {
AWT_ASSERT_APPKIT_THREAD;
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_MTL_LAYER_CLASS();
DECLARE_METHOD(jm_drawInMTLContext, jc_JavaLayer, "drawInMTLContext", "()V");
@@ -395,10 +395,8 @@ BOOL MTLLayer_isExtraRedrawEnabled() {
- (void)startRedrawIfNeeded {
AWT_ASSERT_APPKIT_THREAD;
if (isDisplaySyncEnabled()) {
if (self.redrawCount == 0) {
[self.ctx startRedraw:self];
}
if (isDisplaySyncEnabled() && (self.redrawCount == 0)) {
[self.ctx startRedraw:self];
}
}

View File

@@ -121,8 +121,7 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo
{
__block jlong ret = 0L;
JNI_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:YES useJavaModes:NO // critical
block:^(){
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
@@ -351,8 +350,7 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_nativeGetMaxTextureSize
__block int max = 0;
[ThreadUtilities performOnMainThreadWaiting:YES useJavaModes:NO // critical
block:^(){
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
[sharedContext makeCurrentContext];
j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
[NSOpenGLContext clearCurrentContext];

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -176,8 +176,7 @@ JNI_COCOA_ENTER(env);
jobject javaLayer = (*env)->NewWeakGlobalRef(env, obj);
[ThreadUtilities performOnMainThreadWaiting:YES useJavaModes:NO // critical
block:^(){
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
AWT_ASSERT_APPKIT_THREAD;
layer = [[CGLLayer alloc] initWithJavaLayer: javaLayer];
}];
@@ -225,8 +224,7 @@ Java_sun_java2d_opengl_CGLLayer_nativeSetScale
// this method where we need to change native texture size and layer's scale
// in one call on appkit, otherwise we'll get window's contents blinking,
// during screen-2-screen moving.
[ThreadUtilities performOnMainThreadNowOrLater:NO // critical
block:^(){
[ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){
layer.contentsScale = scale;
}];
JNI_COCOA_EXIT(env);

View File

@@ -315,8 +315,7 @@ OGLSD_Flush(JNIEnv *env)
CGLSDOps *dstCGLOps = (CGLSDOps *)dstOps->privOps;
CGLLayer *layer = (CGLLayer*)dstCGLOps->layer;
if (layer != NULL) {
[ThreadUtilities performOnMainThreadWaiting:NO useJavaModes:NO // critical
block:^(){
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
AWT_ASSERT_APPKIT_THREAD;
[layer setNeedsDisplay];
}];

View File

@@ -127,25 +127,46 @@ do { \
#endif /* AWT_THREAD_ASSERTS */
// --------------------------------------------------------------------------
/* bit flag to coalesce CGDisplayReconfigureCallbacks */
#define MAIN_CALLBACK_CGDISPLAY_RECONFIGURE 1
@interface RunLoopCallbackQueue : NSObject
@property(readwrite, atomic) u_long coalesingflags;
@property(retain) NSMutableArray* queue;
+ (RunLoopCallbackQueue*) shared;
- (id) init;
- (void) dealloc;
- (BOOL)hasCallback:(u_long)bit;
- (BOOL)addCallback:(u_long)bit block:(void (^)())block;
- (void)processQueuedCallbacks;
@end
@interface ThreadTraceContext : NSObject <NSCopying>
@property (readwrite, atomic) BOOL sleep;
@property (readwrite, atomic) BOOL useJavaModes;
@property (readwrite, atomic) long actionId;
@property (readwrite, atomic) char* operation;
@property (readwrite, atomic) CFTimeInterval timestamp;
@property (readwrite, atomic, retain) NSString* threadName;
@property (readwrite, atomic, retain) NSString* caller;
@property (readwrite, atomic, retain) NSString* callStack;
/* autorelease in init and copy */
- (id)init;
- (void)reset;
- (void)updateThreadState:(BOOL)sleepValue;
@property (readwrite, atomic) BOOL sleep;
@property (readwrite, atomic) BOOL useJavaModes;
@property (readwrite, atomic) long actionId;
@property (readwrite, atomic) const char* operation;
@property (readwrite, atomic) CFTimeInterval timestamp;
@property (readwrite, atomic, retain) NSString* threadName;
@property (readwrite, atomic, retain) NSString* caller;
@property (readwrite, atomic, retain) NSString* callStack;
- (void)set:(long)pActionId operation:(char*)pOperation useJavaModes:(BOOL)pUseJavaModes
caller:(NSString *)pCaller callstack:(NSString *)pCallStack;
/* autorelease in init and copy */
- (id)init:(NSString*)threadName;
- (void)reset;
- (void)updateThreadState:(BOOL)sleepValue;
- (const char*)identifier;
- (void)set:(long)pActionId operation:(const char*)pOperation useJavaModes:(BOOL)pUseJavaModes
caller:(NSString *)pCaller callstack:(NSString *)pCallStack;
- (const char*)identifier;
@end
@@ -175,20 +196,24 @@ __attribute__((visibility("default")))
+ (NSString*)criticalRunLoopMode;
+ (NSString*)javaRunLoopMode;
+ (void)setBlockingMainThread:(BOOL)value;
+ (BOOL)blockingMainThread;
/* internal special RunLoop callbacks */
+ (void)registerMainThreadRunLoopCallback:(u_long)coalesingBit block:(void (^)())block;
/* native thread tracing */
+ (ThreadTraceContext*)getTraceContext;
+ (void)removeTraceContext;
+ (void)resetTraceContext;
+ (ThreadTraceContext*)recordTraceContext;
+ (ThreadTraceContext*)recordTraceContext:(NSString*)prefix;
+ (ThreadTraceContext*)recordTraceContext:(NSString*)prefix actionId:(long)actionId useJavaModes:(BOOL)useJavaModes operation:(char*) operation;
+ (ThreadTraceContext*)recordTraceContext:(NSString*)prefix actionId:(long)actionId useJavaModes:(BOOL)useJavaModes operation:(const char*)pOperation;
+ (void)dumpThreadTraceContext;
+ (void)dumpThreadTraceContext:(const char*)pOperation;
+ (NSString*)getThreadTraceContexts;
+ (void)registerForSystemAndScreenNotifications;
+ (BOOL)isWithinPowerTransition:(double)periodInSeconds;
@end
JNIEXPORT void OSXAPP_SetJavaVM(JavaVM *vm);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,8 +37,8 @@
return; \
}
#define RUN_BLOCK_IF_MAIN(block) \
RUN_BLOCK_IF([NSThread isMainThread], block)
/* See LWCToolkit.APPKIT_THREAD_NAME */
#define MAIN_THREAD_NAME "AppKit Thread"
/* Returns the MainThread latency threshold in milliseconds
* used to detect slow operations that may cause high latencies or delays.
@@ -62,7 +62,7 @@ int getMainThreadLatencyThreshold() {
}
static const char* toCString(id obj) {
return obj == nil ? "nil" : [NSString stringWithFormat:@"%@", obj].UTF8String;
return (obj == nil) ? "nil" : [NSString stringWithFormat:@"%@", obj].UTF8String;
}
// The following must be named "jvm", as there are extern references to it in AWT
@@ -78,47 +78,18 @@ static NSArray<NSString*> *allModesExceptJava = nil;
/* Traceability data */
static const BOOL forceTracing = NO;
static const BOOL enableTracing = NO || forceTracing;
static const BOOL enableTracingLog = YES && enableTracing;
static const BOOL enableCallStacks = YES && enableTracing;
static const BOOL enableRunLoopObserver = NO;
static const BOOL enableTracingLog = NO;
static const BOOL enableTracingNSLog = YES && enableTracingLog;
static const BOOL enableCallStacks = YES;
/* Traceability data */
static const BOOL TRACE_PWM = NO;
static const BOOL TRACE_PWM_EVENTS = NO;
static const BOOL TRACE_CLOCKS = NO;
static const uint64_t NANOS_PER_SEC = 1000000000ULL;
static const double SEC_PER_NANOS = 1e9;
static const int TRACE_BLOCKING_FLAGS = 0;
/* RunLoop traceability identifier generators */
static atomic_long runLoopId = 0L;
static atomic_long mainThreadActionId = 0L;
static atomic_uint_least64_t sleepTime = 0LL;
static atomic_uint_least64_t wakeUpTime = 0LL;
bool _getTime_nanos(clockid_t clock_id, atomic_uint_least64_t *nanotime) {
struct timespec tp;
// Use the given clock:
int status = clock_gettime(clock_id, &tp);
if (status != 0) {
return false;
}
*nanotime = tp.tv_sec * NANOS_PER_SEC + tp.tv_nsec;
return true;
}
bool _nanoUpTime(atomic_uint_least64_t *nanotime) {
// Use a monotonic clock (linearly increasing by each tick)
// but not counting the time while sleeping.
// NOTE:CLOCK_UPTIME_RAW seems counting more elapsed time
// arround sleep/wake-up cycle than CLOCK_PROCESS_CPUTIME_ID (adopted):
return _getTime_nanos(CLOCK_PROCESS_CPUTIME_ID, nanotime);
}
static inline void doLog(JNIEnv* env, const char *formatMsg, ...) {
if (forceTracing) {
if (enableTracingNSLog) {
va_list args;
va_start(args, formatMsg);
@@ -145,7 +116,7 @@ static inline void attachCurrentThread(void** env) {
if ([NSThread isMainThread]) {
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_4;
args.name = "AppKit Thread";
args.name = MAIN_THREAD_NAME;
args.group = appkitThreadGroup;
(*jvm)->AttachCurrentThreadAsDaemon(jvm, env, &args);
} else {
@@ -155,8 +126,9 @@ static inline void attachCurrentThread(void** env) {
@implementation ThreadUtilities
static BOOL _blockingEventDispatchThread = NO;
static long eventDispatchThreadPtr = (long)nil;
static BOOL _blockingEventDispatchThread = NO;
static BOOL _blockingMainThread = NO;
static BOOL isEventDispatchThread() {
return (long)[NSThread currentThread] == eventDispatchThreadPtr;
@@ -165,6 +137,9 @@ static BOOL isEventDispatchThread() {
// The [blockingEventDispatchThread] property is readonly, so we implement a private setter
static void setBlockingEventDispatchThread(BOOL value) {
assert([NSThread isMainThread]);
if ((TRACE_BLOCKING_FLAGS & 1) != 0) {
NSLog(@"setBlockingEventDispatchThread(%s)", value ? "YES" : "NO");
}
_blockingEventDispatchThread = value;
}
@@ -173,6 +148,18 @@ static void setBlockingEventDispatchThread(BOOL value) {
return _blockingEventDispatchThread;
}
+ (void)setBlockingMainThread:(BOOL)value {
assert([NSThread isMainThread]);
if ((TRACE_BLOCKING_FLAGS & 2) != 0) {
NSLog(@"setBlockingMainThread(%s)", value ? "YES" : "NO");
}
_blockingMainThread = value;
}
+ (BOOL)blockingMainThread {
return _blockingMainThread;
}
+ (void)initialize {
/* All the standard modes plus the Critical mode */
allModesExceptJava = [[NSArray alloc] initWithObjects:NSRunLoopCommonModes,
@@ -214,71 +201,41 @@ AWT_ASSERT_APPKIT_THREAD;
if (enableTracing) {
// Record thread stack now and return another copy (auto-released):
[ThreadUtilities recordTraceContext];
@try {
if (enableRunLoopObserver) {
CFRunLoopObserverRef logObserver = CFRunLoopObserverCreateWithHandler(
NULL, // CFAllocator
kCFRunLoopAllActivities, // CFOptionFlags
true, // repeats
NSIntegerMin, // order = max priority
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
if ([[NSThread currentThread] isMainThread]) {
char *activityName = NULL;
switch (activity) {
default:
break;
case kCFRunLoopEntry:
activityName = "RunLoopEntry";
/* Increment global main RunLoop id */
runLoopId++;
break;
case kCFRunLoopBeforeTimers:
activityName = "RunLoopBeforeTimers";
break;
case kCFRunLoopBeforeSources :
activityName = "RunLoopBeforeSources";
break;
case kCFRunLoopBeforeWaiting:
activityName = "RunLoopBeforeWaiting";
break;
case kCFRunLoopAfterWaiting:
activityName = "RunLoopAfterWaiting";
break;
case kCFRunLoopExit:
activityName = "RunLoopExit";
break;
case kCFRunLoopAllActivities:
activityName = "RunLoopAllActivities";
break;
}
if (activityName != NULL) {
NSLog(@"RunLoop[on %s][%lu]: processing %s on mode = '%@'",
NSThread.currentThread.name.UTF8String, runLoopId, activityName,
NSRunLoop.currentRunLoop.currentMode);
}
}
}
);
}
@try {
// Start callback queue:
[RunLoopCallbackQueue shared];
CFRunLoopRef runLoop = [[NSRunLoop mainRunLoop] getCFRunLoop];
CFRunLoopAddObserver(runLoop, logObserver, kCFRunLoopDefaultMode);
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(
NULL, // CFAllocator
kCFRunLoopAllActivities, // CFOptionFlags
true, // repeats
NSIntegerMin, // order (Highest priority = earliest)
^(CFRunLoopObserverRef observerRef, CFRunLoopActivity activity)
{
// Run any registered callback:
[[RunLoopCallbackQueue shared] processQueuedCallbacks];
}
);
// Register observer on the Main RunLoop for all modes (common, critical & java):
CFRunLoopRef mainRunLoop = [[NSRunLoop mainRunLoop] getCFRunLoop];
CFRunLoopAddObserver(mainRunLoop, observer, kCFRunLoopCommonModes);
CFStringRef criticalModeRef = (__bridge CFStringRef) CriticalRunLoopMode;
CFRunLoopAddObserver(runLoop, logObserver, criticalModeRef);
CFStringRef criticalModeRef = (__bridge CFStringRef) CriticalRunLoopMode;
CFRunLoopAddObserver(mainRunLoop, observer, criticalModeRef);
CFRelease(criticalModeRef);
CFStringRef javaModeRef = (__bridge CFStringRef) JavaRunLoopMode;
CFRunLoopAddObserver(runLoop, logObserver, javaModeRef);
CFStringRef javaModeRef = (__bridge CFStringRef) JavaRunLoopMode;
CFRunLoopAddObserver(mainRunLoop, observer, javaModeRef);
CFRelease(javaModeRef);
CFRelease(observer);
CFRelease(javaModeRef);
CFRelease(criticalModeRef);
CFRelease(logObserver);
}
} @finally {
} @finally {
if (enableTracing) {
// Finally reset Main thread context in context store:
[ThreadUtilities resetTraceContext];
}
}
[ThreadUtilities registerForSystemAndScreenNotifications];
}
/*
@@ -331,7 +288,7 @@ AWT_ASSERT_APPKIT_THREAD;
+ (void)performOnMainThreadNowOrLater:(BOOL)useJavaModes
block:(void (^)())block
{
RUN_BLOCK_IF_MAIN(block);
RUN_BLOCK_IF([NSThread isMainThread], block);
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block)
waitUntilDone:NO useJavaModes:useJavaModes];
@@ -353,7 +310,7 @@ AWT_ASSERT_APPKIT_THREAD;
useJavaModes:(BOOL)useJavaModes
block:(void (^)())block
{
RUN_BLOCK_IF_MAIN(block);
RUN_BLOCK_IF([NSThread isMainThread] && wait, block);
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block)
waitUntilDone:wait useJavaModes:useJavaModes];
@@ -434,7 +391,7 @@ AWT_ASSERT_APPKIT_THREAD;
waitUntilDone:(BOOL)wait
useJavaModes:(BOOL)useJavaModes
{
const BOOL invokeDirect = NSThread.isMainThread && wait;
const BOOL invokeDirect = [NSThread isMainThread] && wait;
const BOOL doWait = !invokeDirect && wait;
const BOOL blockingEDT = doWait && isEventDispatchThread();
@@ -551,6 +508,22 @@ AWT_ASSERT_APPKIT_THREAD;
return JavaRunLoopMode;
}
/* internal special RunLoop callbacks */
+ (BOOL)hasMainThreadRunLoopCallback:(u_long)coalesingBit {
return [[RunLoopCallbackQueue shared] hasCallback:coalesingBit];
}
+ (void)registerMainThreadRunLoopCallback:(u_long)coalesingBit block:(void (^)())block {
[[RunLoopCallbackQueue shared] addCallback:coalesingBit block:block];
}
/* native thread tracing */
+ (NSString*) getCurrentThreadName {
return ([NSThread isMainThread]) ? @MAIN_THREAD_NAME : [[NSThread currentThread] name];
}
+ (NSMutableDictionary*)threadContextStore {
static NSMutableDictionary<NSString*, ThreadTraceContext*>* _threadTraceContextPerName;
static dispatch_once_t oncePredicate;
@@ -562,14 +535,14 @@ AWT_ASSERT_APPKIT_THREAD;
}
+ (ThreadTraceContext*)getTraceContext {
const NSString* thName = [[NSThread currentThread] name];
NSString* thName = [ThreadUtilities getCurrentThreadName];
NSMutableDictionary* allContexts = [ThreadUtilities threadContextStore];
ThreadTraceContext* thCtx = allContexts[thName];
if (thCtx == nil) {
// Create the empty thread context (auto-released):
thCtx = [[[ThreadTraceContext alloc] init] autorelease];
thCtx = [[[ThreadTraceContext alloc] init:thName] autorelease];
allContexts[thName] = thCtx;
}
return thCtx;
@@ -579,7 +552,7 @@ AWT_ASSERT_APPKIT_THREAD;
* TODO: call when Threads are destroyed.
*/
+ (void)removeTraceContext {
const NSString* thName = [[NSThread currentThread] name];
const NSString* thName = [ThreadUtilities getCurrentThreadName];
[[ThreadUtilities threadContextStore] removeObjectForKey:thName];
}
@@ -595,10 +568,14 @@ AWT_ASSERT_APPKIT_THREAD;
return [ThreadUtilities recordTraceContext:prefix actionId:-1 useJavaModes:NO operation:""];
}
+ (ThreadTraceContext*)recordTraceContext:(NSString*) prefix operation:(const char*)pOperation {
return [ThreadUtilities recordTraceContext:prefix actionId:-1 useJavaModes:NO operation:pOperation];
}
+ (ThreadTraceContext*)recordTraceContext:(NSString*) prefix
actionId:(long) actionId
useJavaModes:(BOOL) useJavaModes
operation:(char*) operation
operation:(const char*)pOperation
{
ThreadTraceContext *thCtx = [ThreadUtilities getTraceContext];
@@ -606,18 +583,18 @@ AWT_ASSERT_APPKIT_THREAD;
NSString *caller = [ThreadUtilities getCaller:prefix];
NSString *callStack = (enableCallStacks) ? [ThreadUtilities getCallerStack:prefix] : nil;
// update recorded thread state:
[thCtx set:actionId operation:operation useJavaModes:useJavaModes caller:caller callstack:callStack];
[thCtx set:actionId operation:pOperation useJavaModes:useJavaModes caller:caller callstack:callStack];
// Record thread stack now and return another copy (auto-released):
return [[thCtx copy] autorelease];
}
+ (void)dumpThreadTraceContext {
+ (void)dumpThreadTraceContext:(const char*)pOperation {
if (enableTracingLog) {
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
// Record thread stack now and return another copy (auto-released):
ThreadTraceContext* thCtx = [ThreadUtilities recordTraceContext];
doLog(env, "dumpThreadTraceContext: %s", toCString([thCtx description]));
ThreadTraceContext* thCtx = [ThreadUtilities recordTraceContext:@"dumpThreadTraceContext" operation:pOperation];
doLog(env, "dumpThreadTraceContext: {\n%s\n}", toCString([thCtx description]));
}
}
@@ -649,163 +626,6 @@ AWT_ASSERT_APPKIT_THREAD;
[dump retain];
return dump;
}
+ (BOOL)isWithinPowerTransition:(double)periodInSeconds {
if (wakeUpTime != 0LL) {
// check last wake-up time:
if (_nowNearTime("wake-up", &wakeUpTime, (SEC_PER_NANOS * periodInSeconds))) {
return true;
}
// reset invalid time:
wakeUpTime = 0LL;
} else if (sleepTime != 0LL) {
// check last sleep time:
if (_nowNearTime("sleep", &sleepTime, (SEC_PER_NANOS * periodInSeconds))) {
return true;
}
// reset invalid time:
sleepTime = 0LL;
} else if (TRACE_PWM) {
NSLog(@"EAWT: isWithinPowerTransition: no times");
}
return false;
}
+ (void)_systemOrScreenWillSleep:(NSNotification*)notification {
atomic_uint_least64_t now;
if (_nanoUpTime(&now))
{
// keep most-recent wake-up time (system or display):
sleepTime = now;
if (TRACE_PWM_EVENTS) {
NSLog(@"EAWT: _systemOrScreenWillSleep[%@]: sleep time = %.5lf (%.5lf)",
[notification name], 1e-9 * sleepTime,
[NSProcessInfo processInfo].systemUptime);
}
// reset wake-up time (system or display):
wakeUpTime = 0LL;
if (TRACE_CLOCKS) {
dumpClocks();
}
}
}
+ (void)_systemOrScreenDidWake:(NSNotification*)notification {
atomic_uint_least64_t now;
if (_nanoUpTime(&now))
{
// keep most-recent wake-up time (system or display):
wakeUpTime = now;
if (TRACE_PWM_EVENTS) {
NSLog(@"EAWT: _systemOrScreenDidWake[%@]: wake-up time = %.5lf (%.5lf)",
[notification name], 1e-9 * wakeUpTime,
[NSProcessInfo processInfo].systemUptime);
}
// CHECK
if (sleepTime != 0LL) {
if (now > sleepTime) {
// check last sleep time:
now -= sleepTime; // delta in ns
if (TRACE_PWM_EVENTS) {
NSLog(@"EAWT: _systemOrScreenDidWake: SLEEP duration = %.5lf ms", 1e-6 * now);
}
}
}
if (TRACE_CLOCKS) {
dumpClocks();
}
}
}
bool _nowNearTime(const char* src, atomic_uint_least64_t *refTime, atomic_uint_least64_t periodNanos) {
if (*refTime != 0LL) {
atomic_uint_least64_t now;
if (_nanoUpTime(&now)) {
if (now < *refTime) {
// should not happen with monotonic clocks, but:
now = *refTime;
}
// check absolute delta in nanoseconds:
now -= *refTime;
if (TRACE_PWM) {
NSLog(@"EAWT: nowNearTime[%s]: delta time = %.5lf ms", src, 1e-6 * now);
}
return (now <= periodNanos);
}
}
return false;
}
void dumpClocks() {
if (TRACE_CLOCKS) {
logTime_nanos(CLOCK_REALTIME);
logTime_nanos(CLOCK_MONOTONIC);
logTime_nanos(CLOCK_MONOTONIC_RAW);
logTime_nanos(CLOCK_MONOTONIC_RAW_APPROX);
logTime_nanos(CLOCK_UPTIME_RAW);
logTime_nanos(CLOCK_UPTIME_RAW_APPROX);
logTime_nanos(CLOCK_PROCESS_CPUTIME_ID);
logTime_nanos(CLOCK_THREAD_CPUTIME_ID);
}
}
void logTime_nanos(clockid_t clock_id) {
if (TRACE_CLOCKS) {
atomic_uint_least64_t now;
if (_getTime_nanos(clock_id, &now)) {
const char *clock_name;
switch (clock_id) {
case CLOCK_REALTIME:
clock_name = "CLOCK_REALTIME";
break;
case CLOCK_MONOTONIC:
clock_name = "CLOCK_MONOTONIC";
break;
case CLOCK_MONOTONIC_RAW:
clock_name = "CLOCK_MONOTONIC_RAW";
break;
case CLOCK_MONOTONIC_RAW_APPROX:
clock_name = "CLOCK_MONOTONIC_RAW_APPROX";
break;
case CLOCK_UPTIME_RAW:
clock_name = "CLOCK_UPTIME_RAW";
break;
case CLOCK_UPTIME_RAW_APPROX:
clock_name = "CLOCK_UPTIME_RAW_APPROX";
break;
case CLOCK_PROCESS_CPUTIME_ID:
clock_name = "CLOCK_PROCESS_CPUTIME_ID";
break;
case CLOCK_THREAD_CPUTIME_ID:
clock_name = "CLOCK_THREAD_CPUTIME_ID";
break;
default:
clock_name = "unknown";
}
NSLog(@"EAWT: logTime_nanos[%27s] time: %.6lf s", clock_name, 1e-9 * now);
}
}
}
+ (void)registerForSystemAndScreenNotifications {
static BOOL notificationRegistered = false;
if (!notificationRegistered) {
notificationRegistered = true;
NSNotificationCenter *ctr = [[NSWorkspace sharedWorkspace] notificationCenter];
Class clz = [ThreadUtilities class];
[ctr addObserver:clz selector:@selector(_systemOrScreenWillSleep:) name:NSWorkspaceWillSleepNotification object:nil];
[ctr addObserver:clz selector:@selector(_systemOrScreenDidWake:) name:NSWorkspaceDidWakeNotification object:nil];
[ctr addObserver:clz selector:@selector(_systemOrScreenWillSleep:) name:NSWorkspaceScreensDidSleepNotification object:nil];
[ctr addObserver:clz selector:@selector(_systemOrScreenDidWake:) name:NSWorkspaceScreensDidWakeNotification object:nil];
}
}
@end
void OSXAPP_SetJavaVM(JavaVM *vm)
@@ -885,17 +705,91 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
}
}
/* Traceability data */
@implementation ThreadTraceContext {
/* RunLoop Callback Queue */
@implementation RunLoopCallbackQueue
+ (RunLoopCallbackQueue*) shared {
static RunLoopCallbackQueue* _runLoopCallbackQueue = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_runLoopCallbackQueue = [RunLoopCallbackQueue new];
});
return _runLoopCallbackQueue;
}
- (id) init {
self = [super init];
if (self) {
self.queue = [NSMutableArray arrayWithCapacity: 8];
[self reset];
}
return self;
}
- (void)dealloc {
[self reset];
self.queue = nil;
[super dealloc];
}
- (void)reset {
[self.queue removeAllObjects];
self.coalesingflags = 0;
}
- (BOOL)coalesingFlag:(u_long)bit {
return (self.coalesingflags & (1L << bit)) != 0;
}
- (void)setCoalesingFlag:(u_long)bit {
self.coalesingflags |= (1L << bit);
}
- (BOOL)hasCallback:(u_long)bit {
return (bit != 0) && [self coalesingFlag:bit];
}
- (BOOL)addCallback:(u_long)bit block:(void (^)())block {
if ([NSThread isMainThread] == NO) {
NSLog(@"addCallback should be called on main thread");
return NO;
}
// check coalesing flag:
if (bit != 0) {
if ([self coalesingFlag:bit]) {
// skip coalesing callback:
return NO;
}
[self setCoalesingFlag:bit];
}
[self.queue addObject:Block_copy(block)];
return YES;
}
- (void)processQueuedCallbacks {
const NSUInteger count = [self.queue count];
if (count != 0) {
for (NSUInteger i = 0; i < count; i++) {
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
// invoke callback:
[ThreadUtilities invokeBlockCopy:blockCopy];
}
// reset queue anyway:
[self reset];
}
}
@end
/* Traceability data */
@implementation ThreadTraceContext
@synthesize sleep, useJavaModes, actionId, operation, timestamp, caller, callStack;
- (id _Nonnull)init
{
- (id)init:(NSString*)threadName {
self = [super init];
if (self) {
self.threadName = [[NSThread currentThread] name];
self.threadName = threadName;
[self reset];
}
return self;
@@ -938,8 +832,12 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
self.sleep = sleepValue;
}
- (void)set:(long)pActionId operation:(char*) pOperation useJavaModes:(BOOL) pUseJavaModes
caller:(NSString*) pCaller callstack:(NSString*) pCallStack {
- (void) set:(long) pActionId
operation:(const char*) pOperation
useJavaModes:(BOOL) pUseJavaModes
caller:(NSString*) pCaller
callstack:(NSString*) pCallStack
{
[self updateThreadState:NO];
self.useJavaModes = pUseJavaModes;
self.actionId = pActionId;

View File

@@ -63,7 +63,7 @@ public class AWTThreading {
* or waits a notification from Toolkit. The method is re-entrant.
* <p>
* Currently only macOS is supported. The callable can wrap a native obj-c selector. The selector should be executed via
* [JNFRunLoop performOnMainThreadWaiting:YES ...] so that doAWTRunLoop on AppKit (which is run in [JNFRunLoop javaRunLoopMode]) accepts it.
* [ThreadUtilities performOnMainThreadWaiting:YES ...] so that doAWTRunLoop on AppKit (which is run in [ThreadUtilities javaRunLoopMode]) accepts it.
* The callable should not call any Java code that would normally be called on EDT.
* <p>
* A deadlock can happen when the callable triggers any blocking invocation from Toolkit to EDT, or when Toolkit already waits in
@@ -310,7 +310,7 @@ public class AWTThreading {
} else if (logger.isLoggable(PlatformLogger.Level.INFO)) {
StackTraceElement[] stack = throwable.getStackTrace();
logger.info(message + ". Originated at " + stack[stack.length - 1]);
} else {
} else if (TRACE_RUN_LOOP) {
logger.severe("AWTThreading.TrackedInvocationEvent.whenComplete: failure", ex);
logger.severe("AWTThreading.TrackedInvocationEvent.whenComplete: caller:", throwable);
}

View File

@@ -173,6 +173,10 @@ public abstract class SunDropTargetContextPeer implements DropTargetContextPeer,
return currentA;
}
protected int getDropAction() {
return currentDA;
}
/**
* get the Transferable associated with the drop
*/

View File

@@ -45,7 +45,7 @@ class VKBufImgOps extends BufferedBufImgOps {
/**
* This method is called from VKDrawImage.transformImage() only. It
* validates the provided BufferedImageOp to determine whether the op
* is one that can be accelerated by the MTL pipeline. If the operation
* is one that can be accelerated by the Vulkan pipeline. If the operation
* cannot be completed for any reason, this method returns false;
* otherwise, the given BufferedImage is rendered to the destination
* using the provided BufferedImageOp and this method returns true.
@@ -53,65 +53,66 @@ class VKBufImgOps extends BufferedBufImgOps {
static boolean renderImageWithOp(SunGraphics2D sg, BufferedImage img,
BufferedImageOp biop, int x, int y)
{
// Validate the provided BufferedImage (make sure it is one that
// is supported, and that its properties are acceleratable)
if (biop instanceof ConvolveOp) {
if (!isConvolveOpValid((ConvolveOp)biop)) {
return false;
}
} else if (biop instanceof RescaleOp) {
if (!isRescaleOpValid((RescaleOp)biop, img)) {
return false;
}
} else if (biop instanceof LookupOp) {
if (!isLookupOpValid((LookupOp)biop, img)) {
return false;
}
} else {
// No acceleration for other BufferedImageOps (yet)
return false;
}
SurfaceData dstData = sg.surfaceData;
if (!(dstData instanceof VKSurfaceData) ||
(sg.interpolationType == AffineTransformOp.TYPE_BICUBIC) ||
(sg.compositeState > SunGraphics2D.COMP_ALPHA))
{
return false;
}
SurfaceData srcData =
dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
CompositeType.SrcOver, null);
if (!(srcData instanceof VKSurfaceData)) {
// REMIND: this hack tries to ensure that we have a cached texture
srcData =
dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
CompositeType.SrcOver, null);
if (!(srcData instanceof VKSurfaceData)) {
return false;
}
}
// Verify that the source surface is actually a texture and
// that the operation is supported
VKSurfaceData vkSrc = (VKSurfaceData)srcData;
VKGraphicsConfig gc = vkSrc.getGraphicsConfig();
if (vkSrc.getType() != VKSurfaceData.TEXTURE || !gc.isCapPresent(CAPS_EXT_BIOP_SHADER))
{
return false;
}
int sw = img.getWidth();
int sh = img.getHeight();
VKBlitLoops.IsoBlit(srcData, dstData,
img, biop,
sg.composite, sg.getCompClip(),
sg.transform, sg.interpolationType,
0, 0, sw, sh,
x, y, x+sw, y+sh,
true);
return true;
// TODO No acceleration for image ops yet.
return false;
// // Validate the provided BufferedImage (make sure it is one that
// // is supported, and that its properties are acceleratable)
// if (biop instanceof ConvolveOp) {
// if (!isConvolveOpValid((ConvolveOp)biop)) {
// return false;
// }
// } else if (biop instanceof RescaleOp) {
// if (!isRescaleOpValid((RescaleOp)biop, img)) {
// return false;
// }
// } else if (biop instanceof LookupOp) {
// if (!isLookupOpValid((LookupOp)biop, img)) {
// return false;
// }
// } else {
// // No acceleration for other BufferedImageOps (yet)
// return false;
// }
//
// SurfaceData dstData = sg.surfaceData;
// if (!(dstData instanceof VKSurfaceData) ||
// (sg.interpolationType == AffineTransformOp.TYPE_BICUBIC) ||
// (sg.compositeState > SunGraphics2D.COMP_ALPHA))
// {
// return false;
// }
//
// SurfaceData srcData =
// dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
// CompositeType.SrcOver, null);
// if (!(srcData instanceof VKSurfaceData)) {
// // REMIND: this hack tries to ensure that we have a cached texture
// srcData =
// dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
// CompositeType.SrcOver, null);
// if (!(srcData instanceof VKSurfaceData)) {
// return false;
// }
// }
//
// // Verify that the source surface is actually a texture and
// // that the operation is supported
// VKSurfaceData vkSrc = (VKSurfaceData)srcData;
// VKGraphicsConfig gc = vkSrc.getGraphicsConfig();
// if (vkSrc.getType() != VKSurfaceData.TEXTURE || !gc.isCapPresent(CAPS_EXT_BIOP_SHADER))
// {
// return false;
// }
//
// int sw = img.getWidth();
// int sh = img.getHeight();
// VKBlitLoops.IsoBlit(srcData, dstData,
// img, biop,
// sg.composite, sg.getCompClip(),
// sg.transform, sg.interpolationType,
// 0, 0, sw, sh,
// x, y, x+sw, y+sh);
//
// return true;
}
}

View File

@@ -31,6 +31,8 @@ import sun.java2d.pipe.RenderQueue;
import sun.java2d.pipe.hw.ContextCapabilities;
import sun.util.logging.PlatformLogger;
import java.awt.BufferCapabilities;
import java.awt.ImageCapabilities;
import java.lang.annotation.Native;
/**
@@ -41,6 +43,8 @@ final class VKContext extends BufferedContext {
private static final PlatformLogger log =
PlatformLogger.getLogger("sun.java2d.vulkan.VKContext");
public static final VKContext INSTANCE = new VKContext(VKRenderQueue.getInstance());
public VKContext(RenderQueue rq) {
super(rq);
}
@@ -73,6 +77,26 @@ final class VKContext extends BufferedContext {
@Native
static final int CAPS_EXT_GRAD_SHADER = (FIRST_PRIVATE_CAP << 3);
public static final VKContextCaps CONTEXT_CAPS = new VKContextCaps(
CAPS_PS30 | CAPS_PS20 | CAPS_RT_TEXTURE_ALPHA |
CAPS_RT_TEXTURE_OPAQUE | CAPS_MULTITEXTURE | CAPS_TEXNONPOW2 |
CAPS_TEXNONSQUARE, null);
public static final ImageCapabilities IMAGE_CAPS = new ImageCapabilities(true) {
@Override
public boolean isTrueVolatile() {
return true;
}
};
public static final BufferCapabilities BUFFER_CAPS = new BufferCapabilities(IMAGE_CAPS, IMAGE_CAPS,
BufferCapabilities.FlipContents.COPIED) {
@Override
public boolean isMultiBufferAvailable() {
return true;
}
};
public VKContextCaps(int caps, String adapterId) {
super(caps, adapterId);
}

View File

@@ -50,13 +50,6 @@ public class VKDrawImage extends DrawImage {
// punt to the MediaLib-based transformImage() in the superclass if:
// - bicubic interpolation is specified
// - a background color is specified and will be used
// - the source surface is neither a texture nor render-to-texture
// surface, and a non-default interpolation hint is specified
// (we can only control the filtering for texture->surface
// copies)
// REMIND: we should tweak the sw->texture->surface
// transform case to handle filtering appropriately
// (see 4841762)...
// - an appropriate TransformBlit primitive could not be found
if (interpType != AffineTransformOp.TYPE_BICUBIC) {
SurfaceData dstData = sg.surfaceData;
@@ -66,12 +59,7 @@ public class VKDrawImage extends DrawImage {
sg.imageComp,
bgColor);
if (srcData != null &&
!isBgOperation(srcData, bgColor) &&
(srcData.getSurfaceType() == VKSurfaceData.VKTexture ||
srcData.getSurfaceType() == VKSurfaceData.VKSurfaceRTT ||
interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR))
{
if (srcData != null && !isBgOperation(srcData, bgColor)) {
SurfaceType srcType = srcData.getSurfaceType();
SurfaceType dstType = dstData.getSurfaceType();
TransformBlit blit = TransformBlit.getFromCache(srcType,

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.java2d.vulkan;
import sun.util.logging.PlatformLogger;
import java.awt.Toolkit;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class VKEnv {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.vulkan.VKInstance");
private static final class Options {
@SuppressWarnings("removal")
private static final boolean vulkan = "true".equalsIgnoreCase(AccessController.doPrivileged(
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan", "")));
@SuppressWarnings("removal")
private static final boolean accelsd = vulkan && "true".equalsIgnoreCase(AccessController.doPrivileged(
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.accelsd", "")));
@SuppressWarnings("removal")
private static final int deviceNumber = !vulkan ? 0 : AccessController.doPrivileged(
(PrivilegedAction<Integer>) () -> Integer.getInteger("sun.java2d.vulkan.deviceNumber", 0));
}
private static final int UNINITIALIZED = 0;
private static final int INITIALIZING = 1;
private static final int DISABLED = 2;
private static final int ENABLED = 3;
private static final int ACCELSD_BIT = 4;
private static final int PRESENT_BIT = 8;
private static int state = UNINITIALIZED;
private static VKGPU[] devices;
private static VKGPU defaultDevice;
private static native long initPlatform(long nativePtr);
private static native VKGPU[] initNative(long platformData);
public static synchronized void init(long nativePtr) {
if (state > INITIALIZING) return;
long platformData = nativePtr == 0 ? 0 : initPlatform(nativePtr);
int newState = DISABLED;
if (Options.vulkan) {
devices = initNative(platformData);
if (devices != null) {
newState = ENABLED;
if (Options.accelsd) newState |= ACCELSD_BIT;
defaultDevice = devices[Options.deviceNumber >= 0 && Options.deviceNumber < devices.length ?
Options.deviceNumber : 0];
// Check whether the presentation is supported.
for (VKGPU device : devices) {
if (device.hasCap(VKGPU.CAP_PRESENTABLE_BIT) &&
device.getPresentableGraphicsConfigs().findAny().isPresent()) {
newState |= PRESENT_BIT;
break;
}
}
VKBlitLoops.register();
VKMaskFill.register();
VKMaskBlit.register();
}
}
state = newState;
if (log.isLoggable(PlatformLogger.Level.FINE)) {
if (isVulkanEnabled()) {
log.fine("Vulkan rendering enabled: YES" +
"\n presentation enabled: " + (isPresentationEnabled() ? "YES" : "NO") +
"\n accelerated surface data enabled: " + (isSurfaceDataAccelerated() ? "YES" : "NO") +
"\n devices:" + Stream.of(devices).map(d -> (d == defaultDevice ?
"\n *" : "\n ") + d.getName()).collect(Collectors.joining()));
} else log.fine("Vulkan rendering enabled: NO");
}
}
private static void checkInit() {
if (state > INITIALIZING) return;
synchronized (VKEnv.class) {
if (state == UNINITIALIZED) {
// Try initializing the Toolkit first to give it a chance to init Vulkan with proper platform data.
state = INITIALIZING;
Toolkit.getDefaultToolkit();
}
// Still not initialized? Init without platform data.
if (state == INITIALIZING) init(0);
}
}
public static boolean isVulkanEnabled() {
checkInit();
return (state & ENABLED) == ENABLED;
}
public static boolean isPresentationEnabled() {
checkInit();
return (state & PRESENT_BIT) != 0;
}
public static boolean isSurfaceDataAccelerated() {
checkInit();
return (state & ACCELSD_BIT) != 0;
}
public static Stream<VKGPU> getDevices() {
checkInit();
final VKGPU first = defaultDevice;
return Stream.concat(Stream.of(first), Stream.of(devices).filter(d -> d != first));
}
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright 2025 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.java2d.vulkan;
import java.awt.GraphicsConfiguration;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.awt.image.BufImgSurfaceData;
import sun.awt.image.ByteComponentRaster;
import sun.awt.image.IntegerComponentRaster;
import sun.awt.image.SurfaceManager;
import sun.java2d.SurfaceData;
import sun.java2d.loops.SurfaceType;
/**
* Vulkan format description, which allows creation of compatible BufferedImages.
*/
public enum VKFormat {
// VK_FORMAT_B8G8R8A8_UNORM doesn't have a matching standard format in Java,
// but it can be aliased as TYPE_INT_ARGB on little-endian systems.
B8G8R8A8_UNORM(44,
LEOptimizations.ENABLED ? VKFormatModel.INT_ARGB_PRE : VKFormatModel.CUSTOM_4BYTE_BGRA_PRE,
LEOptimizations.ENABLED ? VKFormatModel.INT_RGB : VKFormatModel.CUSTOM_4BYTE_BGRx),
R8G8B8A8_UNORM(37, VKFormatModel.CUSTOM_4BYTE_RGBA_PRE, VKFormatModel.CUSTOM_4BYTE_RGBx),
A8B8G8R8_UNORM_PACK32(51, VKFormatModel.CUSTOM_INT_ABGR_PRE, VKFormatModel.INT_BGR);
private final int value;
private final SurfaceType surfaceType, translucentSurfaceType, opaqueSurfaceType;
private final VKFormatModel translucentModel, opaqueModel;
private final VKBufImgGraphicsConfig bufferedGraphicsConfig = new VKBufImgGraphicsConfig(this);
VKFormat(int value, VKFormatModel translucentModel, VKFormatModel opaqueModel) {
this.value = value;
this.surfaceType = VKSurfaceData.VKSurface.deriveSubType("Vulkan surface (" + name() + ")");
this.translucentSurfaceType = translucentModel == null ? null :
this.surfaceType.deriveSubType("Vulkan surface (" + name() + ", TRANSLUCENT)");
this.opaqueSurfaceType = this.surfaceType.deriveSubType("Vulkan surface (" + name() + ", OPAQUE)");
this.translucentModel = translucentModel;
this.opaqueModel = opaqueModel;
}
public int getValue(int transparency) {
final int FORMAT_OPAQUE_BIT = 0x80000000;
return transparency != Transparency.OPAQUE ? value : value | FORMAT_OPAQUE_BIT;
}
public SurfaceType getSurfaceType(int transparency) {
return switch (transparency) {
case 0 -> surfaceType; // Any transparency.
case Transparency.TRANSLUCENT, Transparency.BITMASK -> translucentSurfaceType;
case Transparency.OPAQUE -> opaqueSurfaceType;
default -> null;
};
}
public VKFormatModel getFormatModel(int transparency) {
return transparency != Transparency.OPAQUE ? translucentModel : opaqueModel;
}
public BufferedImage createCompatibleImage(int width, int height, int transparency) {
VKFormatModel formatModel = getFormatModel(transparency);
ColorModel colorModel = formatModel.getColorModel();
SampleModel sampleModel = formatModel.createSampleModel(width, height);
SurfaceType surfaceType = formatModel.getSurfaceType();
WritableRaster raster = Raster.createWritableRaster(sampleModel, null);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
VKBufImgSurfaceData surfaceData = new VKBufImgSurfaceData(bufferedGraphicsConfig, raster, image, surfaceType);
SurfaceManager.setManager(image, new VKBufImgSurfaceManager(image, surfaceData));
return image;
}
public boolean isTranslucencyCapable() {
return translucentModel != VKFormatModel.NONE;
}
/**
* Some Vulkan formats can be more efficiently aliased as built-in Java formats on little-endian systems.
*/
private interface LEOptimizations {
@SuppressWarnings("removal")
boolean ENABLED = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN &&
"true".equalsIgnoreCase(AccessController.doPrivileged((PrivilegedAction<String>) () ->
System.getProperty("sun.java2d.vulkan.leOptimizations", "true")));
}
private static class VKBufImgSurfaceManager extends SurfaceManager {
private final BufferedImage image;
private final VKBufImgSurfaceData sd;
private VKBufImgSurfaceManager(BufferedImage image, VKBufImgSurfaceData sd) {
this.image = image;
this.sd = sd;
}
public SurfaceData getPrimarySurfaceData() { return sd; }
public SurfaceData restoreContents() { return sd; }
}
private static class VKBufImgSurfaceData extends BufImgSurfaceData {
private final GraphicsConfiguration gc;
private VKBufImgSurfaceData(GraphicsConfiguration gc,
WritableRaster raster, BufferedImage image, SurfaceType surfaceType) {
super(raster.getDataBuffer(), image, surfaceType, 1, 1);
this.gc = gc;
Object array;
if (raster instanceof IntegerComponentRaster r) array = r.getDataStorage();
else if (raster instanceof ByteComponentRaster r) array = r.getDataStorage();
else throw new IllegalArgumentException("Unsupported raster type: " + raster.getClass().getCanonicalName());
int pixStr, scanStr;
if (raster.getSampleModel() instanceof PixelInterleavedSampleModel sm) {
pixStr = sm.getPixelStride();
scanStr = sm.getScanlineStride();
} else if (raster.getSampleModel() instanceof SinglePixelPackedSampleModel sm) {
pixStr = DataBuffer.getDataTypeSize(sm.getDataType()) / 8;
scanStr = sm.getScanlineStride() * pixStr;
} else throw new IllegalArgumentException("Unsupported sample model: " +
raster.getSampleModel().getClass().getCanonicalName());
initRaster(array, 0, 0, image.getWidth(), image.getHeight(), pixStr, scanStr, null);
initSolidLoops();
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return gc;
}
}
private static class VKBufImgGraphicsConfig extends VKOffscreenGraphicsConfig {
private VKBufImgGraphicsConfig(VKFormat format) {
super(null, format);
}
@Override
public VKGPU getGPU() {
throw new UnsupportedOperationException("No VKGPU associated with VKBufImgGraphicsConfig");
}
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright 2025 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.java2d.vulkan;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.SampleModel;
import sun.awt.image.PixelConverter;
import sun.java2d.loops.SurfaceType;
import static java.awt.image.DataBuffer.TYPE_BYTE;
import static java.awt.image.DataBuffer.TYPE_INT;
import static java.awt.Transparency.OPAQUE;
import static java.awt.Transparency.TRANSLUCENT;
/**
* Format model describes properties of the surface, necessary for the creation of compatible BufferedImages.
*/
public enum VKFormatModel {
NONE(BufferedImage.TYPE_CUSTOM, null, null, null, null),
INT_ARGB_PRE(BufferedImage.TYPE_INT_ARGB_PRE, SurfaceType.IntArgbPre, PixelConverter.ArgbPre.instance,
new DirectColorModel(sRGB(), 32, 0xff0000, 0xff00, 0xff, 0xff000000, true, TYPE_INT), null),
INT_RGB(BufferedImage.TYPE_INT_RGB, SurfaceType.IntRgb, PixelConverter.Xrgb.instance,
new DirectColorModel(sRGB(), 24, 0xff0000, 0xff00, 0xff, 0x00000000, false, TYPE_INT), null),
CUSTOM_4BYTE_BGRA_PRE(BufferedImage.TYPE_CUSTOM, SurfaceType.Any4Byte, PixelConverter.ArgbPre.instance,
new ComponentColorModel(sRGB(), true, true, TRANSLUCENT, TYPE_BYTE), sampleModel(TYPE_BYTE, 4, 2, 1, 0, 3)),
CUSTOM_4BYTE_BGRx(BufferedImage.TYPE_CUSTOM, SurfaceType.Any4Byte, PixelConverter.Xrgb.instance,
new ComponentColorModel(sRGB(), false, false, OPAQUE, TYPE_BYTE), sampleModel(TYPE_BYTE, 4, 2, 1, 0)),
CUSTOM_4BYTE_RGBA_PRE(BufferedImage.TYPE_CUSTOM, SurfaceType.Any4Byte, CustomPixelConverter.AbgrPre,
new ComponentColorModel(sRGB(), true, true, TRANSLUCENT, TYPE_BYTE), sampleModel(TYPE_BYTE, 4, 0, 1, 2, 3)),
CUSTOM_4BYTE_RGBx(BufferedImage.TYPE_CUSTOM, SurfaceType.Any4Byte, PixelConverter.Xbgr.instance,
new ComponentColorModel(sRGB(), false, false, OPAQUE, TYPE_BYTE), sampleModel(TYPE_BYTE, 4, 0, 1, 2)),
CUSTOM_INT_ABGR_PRE(BufferedImage.TYPE_CUSTOM, SurfaceType.AnyDcm, CustomPixelConverter.AbgrPre,
new DirectColorModel(sRGB(), 32, 0xff, 0xff00, 0xff0000, 0xff000000, true, TYPE_INT), null),
INT_BGR(BufferedImage.TYPE_INT_BGR, SurfaceType.IntBgr, PixelConverter.Xbgr.instance,
new DirectColorModel(sRGB(), 24, 0xff, 0xff00, 0xff0000, 0x00000000, false, TYPE_INT), null);
private final int type;
private final SurfaceType surfaceType;
private final ColorModel colorModel;
private final SampleModelFactory sampleModelFactory;
VKFormatModel(int type, SurfaceType surfaceType, PixelConverter pixelConverter,
ColorModel colorModel, SampleModelFactory sampleModelFactory) {
this.type = type;
this.surfaceType = surfaceType == null ? null : surfaceType.deriveSubType(
"Vulkan-compatible buffered surface (" + surfaceType.getDescriptor() + ")", pixelConverter);
this.colorModel = colorModel;
this.sampleModelFactory = sampleModelFactory == null && colorModel != null ?
this.colorModel::createCompatibleSampleModel : sampleModelFactory;
}
public SurfaceType getSurfaceType() {
return surfaceType;
}
public ColorModel getColorModel() {
return colorModel;
}
public SampleModel createSampleModel(int width, int height) {
return sampleModelFactory.createSampleModel(width, height);
}
@FunctionalInterface
interface SampleModelFactory {
SampleModel createSampleModel(int w, int h);
}
private static SampleModelFactory sampleModel(int dataType, int components, int... bandOffsets) {
return (w, h) -> new PixelInterleavedSampleModel(dataType, w, h, components, w*components, bandOffsets);
}
private static ColorSpace sRGB() {
return ColorSpace.getInstance(ColorSpace. CS_sRGB);
}
private static abstract class CustomPixelConverter extends PixelConverter {
private static final PixelConverter AbgrPre = new CustomPixelConverter(0xff000000) {
@Override
public int rgbToPixel(int rgb, ColorModel cm) {
int a = rgb >>> 24;
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = (rgb ) & 0xff;
int a2 = a + (a >> 7);
r = (r * a2) >> 8;
g = (g * a2) >> 8;
b = (b * a2) >> 8;
return ((a << 24) | (b << 16) | (g << 8) | (r));
}
@Override
public int pixelToRgb(int pixel, ColorModel cm) {
int a = pixel >>> 24;
int r = (pixel ) & 0xff;
int g = (pixel >> 8) & 0xff;
int b = (pixel >> 16) & 0xff;
if (a != 0) {
r = ((r << 8) - r) / a;
g = ((g << 8) - g) / a;
b = ((b << 8) - b) / a;
}
return ((a << 24) | (r << 16) | (g << 8) | (b));
}
};
private CustomPixelConverter(int alphaMask) { this.alphaMask = alphaMask; }
@Override
public abstract int rgbToPixel(int rgb, ColorModel cm);
@Override
public abstract int pixelToRgb(int pixel, ColorModel cm);
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright 2025 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.java2d.vulkan;
import sun.awt.image.SurfaceManager;
import java.awt.Transparency;
import java.lang.annotation.Native;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* VKDevice wrapper.
*/
public class VKGPU {
@Native public static final int CAP_PRESENTABLE_BIT = 0x80000000;
@Native public static final int CAP_LOGIC_OP_BIT = 0x40000000;
@Native public static final int CAP_SAMPLED_4BYTE_BIT = 0; // Considered always supported.
@Native public static final int CAP_SAMPLED_3BYTE_BIT = 1;
@Native public static final int CAP_SAMPLED_565_BIT = 2;
@Native public static final int CAP_SAMPLED_555_BIT = 4;
private boolean initialized;
private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache();
private final long nativeHandle;
private final String name;
private final Type type;
private final int caps;
private final List<VKGraphicsConfig> offscreenGraphicsConfigs, presentableGraphicsConfigs;
private static native void init(long nativeHandle);
private static native void reset(long nativeHandle);
/**
* Instantiated from native code, see createJavaDevices in VKInstance.c
* Fresh devices are created in uninitialized state. They can be queried for their properties
* but cannot be used for rendering until initialized via getNativeHandle().
*/
private VKGPU(long nativeHandle, String name, int type, int caps, int[] supportedFormats) {
this.nativeHandle = nativeHandle;
this.name = name;
this.type = Type.VALUES[type];
this.caps = caps;
offscreenGraphicsConfigs = new ArrayList<>();
presentableGraphicsConfigs = new ArrayList<>();
VKFormat[] allFormats = VKFormat.values();
for (int supportedFormat : supportedFormats) {
int formatValue = supportedFormat & ~CAP_PRESENTABLE_BIT;
for (VKFormat format : allFormats) {
if (formatValue == format.getValue(Transparency.TRANSLUCENT)) {
VKOffscreenGraphicsConfig gc = new VKOffscreenGraphicsConfig(this, format);
offscreenGraphicsConfigs.add(gc);
if ((supportedFormat & caps & CAP_PRESENTABLE_BIT) != 0) presentableGraphicsConfigs.add(gc);
break;
}
}
}
}
public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { return surfaceDataProxyCache; }
public String getName() { return name; }
public Type getType() { return type; }
public Stream<VKGraphicsConfig> getOffscreenGraphicsConfigs() {
return offscreenGraphicsConfigs.stream();
}
public Stream<VKGraphicsConfig> getPresentableGraphicsConfigs() {
return presentableGraphicsConfigs.stream();
}
public int getCaps() {
return caps;
}
public boolean hasCap(int cap) {
return (caps & cap) == cap;
}
/**
* Initialize the device and return its native handle.
*/
public synchronized long getNativeHandle() {
if (!initialized) {
try {
init(nativeHandle);
} catch (RuntimeException e) {
throw new RuntimeException("Failed to initialize Vulkan device: " + name, e);
}
initialized = true;
}
return nativeHandle;
}
@Override
public String toString() {
return name + " (" + type + ")";
}
public enum Type {
OTHER,
INTEGRATED_GPU,
DISCRETE_GPU,
VIRTUAL_GPU,
CPU;
private static final Type[] VALUES = values();
}
}

View File

@@ -26,9 +26,124 @@
package sun.java2d.vulkan;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.VolatileImage;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.SurfaceManager;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.Surface;
import sun.java2d.SurfaceManagerFactory;
import sun.java2d.pipe.BufferedContext;
import sun.java2d.pipe.hw.AccelGraphicsConfig;
import sun.java2d.pipe.hw.AccelTypedVolatileImage;
import sun.java2d.pipe.hw.ContextCapabilities;
public interface VKGraphicsConfig extends AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig {
boolean isCapPresent(int capsExtGradShader);
import java.awt.BufferCapabilities;
import java.awt.GraphicsConfiguration;
import java.awt.ImageCapabilities;
import static java.awt.Transparency.OPAQUE;
import static java.awt.Transparency.TRANSLUCENT;
import static sun.java2d.pipe.hw.AccelSurface.RT_TEXTURE;
import static sun.java2d.pipe.hw.AccelSurface.TEXTURE;
/**
* Base type for Vulkan graphics config.
* Despite it being an interface, it contains a (preferred) default implementation
* for most of the methods, including base methods of GraphicsConfiguration class.
*/
public interface VKGraphicsConfig extends AccelGraphicsConfig,
SurfaceManager.ProxiedGraphicsConfig {
default VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
Object context) {
return new VKVolatileSurfaceManager(image, context);
}
VKGraphicsConfig getOffscreenConfig();
default VKGPU getGPU() {
return getOffscreenConfig().getGPU();
}
default VKFormat getFormat() {
return getOffscreenConfig().getFormat();
}
default double getScale() {
return 1;
}
@Override
default SurfaceManager.ProxyCache getSurfaceDataProxyCache() {
return getGPU().getSurfaceDataProxyCache();
}
@Override
default BufferedContext getContext() {
return VKContext.INSTANCE;
}
/**
* Returns true if the provided capability bit is present for this config.
* See VKContext.java for a list of supported capabilities.
*/
default boolean isCapPresent(int cap) { // TODO refactor capability checks.
return ((getContextCapabilities().getCaps() & cap) != 0);
}
@Override
default ContextCapabilities getContextCapabilities() {
return VKContext.VKContextCaps.CONTEXT_CAPS;
}
@Override
default VolatileImage createCompatibleVolatileImage(int width, int height, int transparency, int type) {
if (type != RT_TEXTURE && type != TEXTURE) return null;
if (transparency != OPAQUE && (transparency != TRANSLUCENT || !isTranslucencyCapable())) return null;
SunVolatileImage vi =
new AccelTypedVolatileImage((GraphicsConfiguration) this, width, height, transparency, type);
Surface sd = vi.getDestSurface();
if (!(sd instanceof VKSurfaceData vsd) || vsd.getType() != type) {
vi.flush();
vi = null;
}
return vi;
}
default String descriptorString() {
return getFormat().name() + ", " + getGPU();
}
// Default implementation of GraphicsConfiguration methods.
// Those need to be explicitly overridden by subclasses using VKGraphicsConfig.super.
default BufferedImage createCompatibleImage(int width, int height) {
return createCompatibleImage(width, height, isTranslucencyCapable() ? TRANSLUCENT : OPAQUE);
}
default BufferedImage createCompatibleImage(int width, int height, int transparency) {
return getFormat().createCompatibleImage(width, height, transparency);
}
default ColorModel getColorModel() {
return getColorModel(isTranslucencyCapable() ? TRANSLUCENT : OPAQUE);
}
default ColorModel getColorModel(int transparency) {
return getFormat().getFormatModel(transparency).getColorModel();
}
default BufferCapabilities getBufferCapabilities() {
return VKContext.VKContextCaps.BUFFER_CAPS;
}
default ImageCapabilities getImageCapabilities() {
return VKContext.VKContextCaps.IMAGE_CAPS;
}
default boolean isTranslucencyCapable() {
return getFormat().isTranslucencyCapable();
}
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.java2d.vulkan;
import sun.util.logging.PlatformLogger;
import java.security.AccessController;
import java.security.PrivilegedAction;
public class VKInstance {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.vulkan.VKInstance");
private static Boolean initialized;
private static Boolean sdAccelerated;
private static native boolean initNative(long nativePtr, boolean verbose, int deviceNumber);
public static void init(long nativePtr) {
@SuppressWarnings("removal")
String vulkanOption = AccessController.doPrivileged(
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan", ""));
if ("true".equalsIgnoreCase(vulkanOption)) {
@SuppressWarnings("removal")
String deviceNumberOption = AccessController.doPrivileged(
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.deviceNumber", "0"));
int parsedDeviceNumber = 0;
try {
parsedDeviceNumber = Integer.parseInt(deviceNumberOption);
} catch (NumberFormatException e) {
log.warning("Invalid Vulkan device number:" + deviceNumberOption);
}
final int deviceNumber = parsedDeviceNumber;
final boolean verbose = "True".equals(vulkanOption);
System.loadLibrary("awt");
@SuppressWarnings("removal")
String sdOption = AccessController.doPrivileged(
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.accelsd", ""));
initialized = initNative(nativePtr, verbose, deviceNumber);
sdAccelerated = initialized && "true".equalsIgnoreCase(sdOption);
} else initialized = false;
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("Vulkan rendering enabled: " + (initialized ? "YES" : "NO"));
log.fine("Vulkan accelerated surface data enabled: " + (sdAccelerated ? "YES" : "NO"));
}
}
public static boolean isVulkanEnabled() {
if (initialized == null) throw new RuntimeException("Vulkan not initialized");
return initialized;
}
public static boolean isSurfaceDataAccelerated() {
if (initialized == null) throw new RuntimeException("Vulkan not initialized");
return sdAccelerated;
}
}

View File

@@ -25,26 +25,28 @@
package sun.java2d.vulkan;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.VolatileImage;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.BufferedContext;
/**
* SurfaceData object representing an off-screen buffer
*/
public class VKOffScreenSurfaceData extends VKSurfaceData {
private final Image offscreenImage;
private native void initOps(int width, int height);
public VKOffScreenSurfaceData(VKGraphicsConfig gc, Image image, ColorModel cm,
int type, int width, int height)
{
super(gc, cm, type, width, height);
private final Image offscreenImage;
private final int userWidth, userHeight; // In logical units.
private native void initOps(int format);
public VKOffScreenSurfaceData(Image image, VKFormat format, int transparency, int type, int width, int height) {
super(format, transparency, type);
this.userWidth = width;
this.userHeight = height;
offscreenImage = image;
initOps(width, height);
initOps(format.getValue(transparency));
}
@Override
@@ -52,11 +54,6 @@ public class VKOffScreenSurfaceData extends VKSurfaceData {
return restoreContents(offscreenImage);
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return null;
}
@Override
public long getNativeResource(int resType) {
return 0;
@@ -76,13 +73,13 @@ public class VKOffScreenSurfaceData extends VKSurfaceData {
}
@Override
public BufferedContext getContext() {
return getGraphicsConfig().getContext();
}
@Override
public boolean isOnScreen() {
return false;
protected int revalidate(VKGraphicsConfig gc) {
int result = super.revalidate(gc);
if (result != VolatileImage.IMAGE_INCOMPATIBLE) {
scale = gc.getScale();
width = (int) Math.ceil(scale * userWidth);
height = (int) Math.ceil(scale * userHeight);
}
return result;
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2025 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.java2d.vulkan;
import java.awt.BufferCapabilities;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.ImageCapabilities;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
public class VKOffscreenGraphicsConfig extends GraphicsConfiguration implements VKGraphicsConfig {
private final VKOffsecreenGraphicsDevice graphicsDevice = new VKOffsecreenGraphicsDevice(this);
private final VKGPU gpu;
private final VKFormat format;
VKOffscreenGraphicsConfig(VKGPU gpu, VKFormat format) {
this.gpu = gpu;
this.format = format;
}
@Override
public GraphicsDevice getDevice() {
return graphicsDevice;
}
@Override
public VKGraphicsConfig getOffscreenConfig() {
return this;
}
@Override
public VKGPU getGPU() {
return gpu;
}
@Override
public VKFormat getFormat() {
return format;
}
@Override
public AffineTransform getDefaultTransform() {
return new AffineTransform();
}
@Override
public AffineTransform getNormalizingTransform() {
return new AffineTransform();
}
@Override
public Rectangle getBounds() {
return new Rectangle(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
}
@Override
public BufferedImage createCompatibleImage(int width, int height) {
return VKGraphicsConfig.super.createCompatibleImage(width, height);
}
@Override
public BufferedImage createCompatibleImage(int width, int height, int transparency) {
return VKGraphicsConfig.super.createCompatibleImage(width, height, transparency);
}
@Override
public ColorModel getColorModel() {
return VKGraphicsConfig.super.getColorModel();
}
@Override
public ColorModel getColorModel(int transparency) {
return VKGraphicsConfig.super.getColorModel(transparency);
}
@Override
public BufferCapabilities getBufferCapabilities() {
return VKGraphicsConfig.super.getBufferCapabilities();
}
@Override
public ImageCapabilities getImageCapabilities() {
return VKGraphicsConfig.super.getImageCapabilities();
}
@Override
public boolean isTranslucencyCapable() {
return VKGraphicsConfig.super.isTranslucencyCapable();
}
@Override
public String toString() {
return "VKOffscreenGraphicsConfig[" + descriptorString() + "]";
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2025 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.java2d.vulkan;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
public class VKOffsecreenGraphicsDevice extends GraphicsDevice {
private final VKGraphicsConfig config;
VKOffsecreenGraphicsDevice(VKGraphicsConfig config) {
this.config = config;
}
@Override
public int getType() {
return GraphicsDevice.TYPE_IMAGE_BUFFER;
}
@Override
public String getIDstring() {
return "VKOffscreenGraphicsDevice";
}
@Override
public GraphicsConfiguration[] getConfigurations() {
return new GraphicsConfiguration[]{ getDefaultConfiguration() };
}
@Override
public GraphicsConfiguration getDefaultConfiguration() {
return (GraphicsConfiguration) config;
}
}

View File

@@ -31,19 +31,24 @@ import sun.awt.SunHints;
import sun.awt.image.PixelConverter;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.Blit;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.loops.SurfaceType;
import static sun.java2d.pipe.BufferedOpCodes.CONFIGURE_SURFACE;
import sun.java2d.pipe.BufferedContext;
import sun.java2d.pipe.ParallelogramPipe;
import sun.java2d.pipe.PixelToParallelogramConverter;
import sun.java2d.pipe.RenderBuffer;
import sun.java2d.pipe.TextPipe;
import sun.java2d.pipe.hw.AccelSurface;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.VolatileImage;
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_PS30;
@@ -51,40 +56,9 @@ import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_PS30;
public abstract class VKSurfaceData extends SurfaceData
implements AccelSurface {
/**
* Pixel formats
*/
public static final int PF_INT_ARGB = 0;
public static final int PF_INT_ARGB_PRE = 1;
public static final int PF_INT_RGB = 2;
public static final int PF_INT_RGBX = 3;
public static final int PF_INT_BGR = 4;
public static final int PF_INT_BGRX = 5;
public static final int PF_USHORT_565_RGB = 6;
public static final int PF_USHORT_555_RGB = 7;
public static final int PF_USHORT_555_RGBX = 8;
public static final int PF_BYTE_GRAY = 9;
public static final int PF_USHORT_GRAY = 10;
public static final int PF_3BYTE_BGR = 11;
/**
* SurfaceTypes
*/
private static final String DESC_VK_SURFACE = "VK Surface";
private static final String DESC_VK_SURFACE_RTT =
"VK Surface (render-to-texture)";
private static final String DESC_VK_TEXTURE = "VK Texture";
// We want non-premultiplied alpha to prevent precision loss, so use PixelConverter.Argb
// See also VKUtil_DecodeJavaColor.
static final SurfaceType VKSurface =
SurfaceType.Any.deriveSubType(DESC_VK_SURFACE,
PixelConverter.Argb.instance);
static final SurfaceType VKSurfaceRTT =
VKSurface.deriveSubType(DESC_VK_SURFACE_RTT);
static final SurfaceType VKTexture =
SurfaceType.Any.deriveSubType(DESC_VK_TEXTURE);
static final SurfaceType VKSurface = SurfaceType.Any.deriveSubType("VK Surface", PixelConverter.Argb.instance);
protected static VKRenderer vkRenderPipe;
protected static PixelToParallelogramConverter vkTxRenderPipe;
@@ -93,74 +67,59 @@ public abstract class VKSurfaceData extends SurfaceData
protected static VKDrawImage vkImagePipe;
static {
if (!GraphicsEnvironment.isHeadless()) {
VKRenderQueue rq = VKRenderQueue.getInstance();
vkImagePipe = new VKDrawImage();
vkTextPipe = new VKTextRenderer(rq);
vkRenderPipe = new VKRenderer(rq);
if (GraphicsPrimitive.tracingEnabled()) {
vkTextPipe = vkTextPipe.traceWrap();
//The wrapped vkRenderPipe will wrap the AA pipe as well...
vkAAPgramPipe = vkRenderPipe.traceWrap();
}
vkAAPgramPipe = vkRenderPipe.getAAParallelogramPipe();
vkTxRenderPipe =
new PixelToParallelogramConverter(vkRenderPipe, vkRenderPipe, 1.0, 0.25, true);
VKBlitLoops.register();
VKMaskFill.register();
VKMaskBlit.register();
VKRenderQueue rq = VKRenderQueue.getInstance();
vkImagePipe = new VKDrawImage();
vkTextPipe = new VKTextRenderer(rq);
vkRenderPipe = new VKRenderer(rq);
if (GraphicsPrimitive.tracingEnabled()) {
vkTextPipe = vkTextPipe.traceWrap();
//The wrapped vkRenderPipe will wrap the AA pipe as well...
vkAAPgramPipe = vkRenderPipe.traceWrap();
}
vkAAPgramPipe = vkRenderPipe.getAAParallelogramPipe();
vkTxRenderPipe = new PixelToParallelogramConverter(vkRenderPipe, vkRenderPipe, 1.0, 0.25, true);
}
// TODO Do we really want to have scale there? It is used by getDefaultScaleX/Y...
protected int scale;
private final VKFormat format;
protected VKGraphicsConfig gc;
protected double scale;
protected int width;
protected int height;
protected int type;
private VKGraphicsConfig graphicsConfig;
// these fields are set from the native code when the surface is
// initialized
private int nativeWidth;
private int nativeHeight;
private int type;
/**
* Returns the appropriate SurfaceType corresponding to the given Metal
* surface type constant (e.g. TEXTURE -> MTLTexture).
*/
private static SurfaceType getCustomSurfaceType(int vkType) {
switch (vkType) {
case TEXTURE:
return VKTexture;
case RT_TEXTURE:
return VKSurfaceRTT;
default:
return VKSurface;
}
}
protected VKSurfaceData(VKGraphicsConfig gc, ColorModel cm, int type, int width, int height)
{
super(getCustomSurfaceType(type), cm);
this.graphicsConfig = gc;
protected VKSurfaceData(VKFormat format, int transparency, int type) {
super(format.getSurfaceType(transparency), format.getFormatModel(transparency).getColorModel());
this.format = format;
this.type = type;
setBlitProxyCache(gc.getSurfaceDataProxyCache());
// TEXTURE shouldn't be scaled, it is used for managed BufferedImages.
scale = 1;
this.width = width * scale;
this.height = height * scale;
}
public VKFormat getFormat() {
return format;
}
@Override
public double getDefaultScaleX() {
return scale;
}
@Override
public double getDefaultScaleY() {
return scale;
}
/**
* Returns one of the surface type constants defined above.
*/
@Override
public final int getType() {
return type;
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return (GraphicsConfiguration) gc;
}
public void flush() {
invalidate();
VKRenderQueue rq = VKRenderQueue.getInstance();
@@ -178,28 +137,28 @@ public abstract class VKSurfaceData extends SurfaceData
}
}
public Raster getRaster(int x, int y, int w, int h) {
throw new InternalError("not implemented yet");
protected BufferedImage getSnapshot(int x, int y, int width, int height) {
BufferedImage image = getFormat().createCompatibleImage(width, height, getTransparency());
SurfaceData sd = SurfaceData.getPrimarySurfaceData(image);
Blit blit = Blit.getFromCache(getSurfaceType(), CompositeType.SrcNoEa, sd.getSurfaceType());
blit.Blit(this, sd, AlphaComposite.Src, null, x, y, 0, 0, width, height);
return image;
}
public Raster getRaster(int x, int y, int w, int h) {
return getSnapshot(x, y, w, h).getRaster().createTranslatedChild(x, y);
}
@Override
public Rectangle getNativeBounds() {
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
return new Rectangle(nativeWidth, nativeHeight);
} finally {
rq.unlock();
}
return new Rectangle(width, height);
}
public void validatePipe(SunGraphics2D sg2d) {
TextPipe textpipe;
boolean validated = false;
// MTLTextRenderer handles both AA and non-AA text, but
// VKTextRenderer handles both AA and non-AA text, but
// only works with the following modes:
// (Note: For LCD text we only enter this code path if
// canRenderLCDText() has already validated that the mode is
@@ -247,7 +206,7 @@ public abstract class VKSurfaceData extends SurfaceData
}
} else {
if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
if (graphicsConfig.isCapPresent(CAPS_PS30) &&
if (getGraphicsConfig().isCapPresent(CAPS_PS30) &&
(sg2d.imageComp == CompositeType.SrcOverNoEa ||
sg2d.imageComp == CompositeType.SrcOver))
{
@@ -300,18 +259,29 @@ public abstract class VKSurfaceData extends SurfaceData
sg2d.imagepipe = vkImagePipe;
}
// TODO this is only used for caps checks, refactor and remove this method
public VKGraphicsConfig getGraphicsConfig() {
return graphicsConfig;
return (VKGraphicsConfig) getDeviceConfiguration();
}
protected synchronized void configure() {
protected int revalidate(VKGraphicsConfig gc) {
if (gc.getFormat() != format) return VolatileImage.IMAGE_INCOMPATIBLE;
else if (this.gc == gc) return VolatileImage.IMAGE_OK;
// TODO proxy cache needs to be cleared for this surface data?
setBlitProxyCache(gc.getGPU().getSurfaceDataProxyCache());
this.gc = gc;
return VolatileImage.IMAGE_RESTORED;
}
protected void configure() {
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacityAndAlignment(20, 4);
rq.ensureCapacityAndAlignment(24, 4);
buf.putInt(CONFIGURE_SURFACE);
buf.putLong(getNativeOps());
buf.putLong(gc.getGPU().getNativeHandle());
buf.putInt(width);
buf.putInt(height);
@@ -321,5 +291,8 @@ public abstract class VKSurfaceData extends SurfaceData
}
}
public abstract boolean isOnScreen();
@Override
public BufferedContext getContext() {
return VKContext.INSTANCE;
}
}

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
* Copyright 2025 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,17 +28,17 @@ package sun.java2d.vulkan;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.hw.AccelSurface;
import java.awt.GraphicsConfiguration;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import sun.java2d.pipe.hw.AccelSurface;
import java.awt.image.VolatileImage;
public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
public class VKVolatileSurfaceManager extends VolatileSurfaceManager {
private final boolean accelerationEnabled;
public WLVKVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
public VKVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
super(vImg, context);
/*
@@ -48,7 +47,7 @@ public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
*/
int transparency = vImg.getTransparency();
accelerationEnabled = VKInstance.isSurfaceDataAccelerated() &&
accelerationEnabled = VKEnv.isSurfaceDataAccelerated() &&
transparency != Transparency.BITMASK;
}
@@ -62,25 +61,43 @@ public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
*/
protected SurfaceData initAcceleratedSurface() {
try {
WLVKGraphicsConfig gc =
(WLVKGraphicsConfig)vImg.getGraphicsConfig();
ColorModel cm = gc.getColorModel(vImg.getTransparency());
VKGraphicsConfig gc = (VKGraphicsConfig) vImg.getGraphicsConfig();
int type = vImg.getForcedAccelSurfaceType();
// if acceleration type is forced (type != UNDEFINED) then
// use the forced type, otherwise choose RT_TEXTURE
if (type == AccelSurface.UNDEFINED) {
type = AccelSurface.RT_TEXTURE;
}
return new VKOffScreenSurfaceData(
gc, vImg, cm, type, vImg.getWidth(), vImg.getHeight());
VKOffScreenSurfaceData sd = new VKOffScreenSurfaceData(vImg, gc.getFormat(), vImg.getTransparency(), type,
vImg.getWidth(), vImg.getHeight());
sd.revalidate(gc);
sd.configure();
return sd;
} catch (NullPointerException | OutOfMemoryError ignored) {
return null;
}
}
@Override
public int validate(GraphicsConfiguration gc) {
if (gc != null && sdAccel != null && isAccelerationEnabled() && isConfigValid(gc)) {
VKSurfaceData vksd = (VKSurfaceData) sdAccel;
switch (vksd.revalidate((VKGraphicsConfig) gc)) {
case VolatileImage.IMAGE_INCOMPATIBLE:
return VolatileImage.IMAGE_INCOMPATIBLE;
case VolatileImage.IMAGE_RESTORED:
vksd.setSurfaceLost(true);
vksd.configure();
}
}
return super.validate(gc);
}
@Override
protected boolean isConfigValid(GraphicsConfiguration gc) {
return ((gc == null) || (gc == vImg.getGraphicsConfig()));
// We consider configs with the same format compatible across Vulkan devices.
return gc == null || vImg.getGraphicsConfig() == null ||
((VKGraphicsConfig) gc).getFormat() == ((VKGraphicsConfig) vImg.getGraphicsConfig()).getFormat();
}
@Override

View File

@@ -0,0 +1,20 @@
#define ALPHA_TYPE_PRE_MULTIPLIED 0U
#define ALPHA_TYPE_STRAIGHT 1U
vec4 convertAlpha(vec4 color, uint inType, uint outType) {
if (inType == ALPHA_TYPE_STRAIGHT && outType == ALPHA_TYPE_PRE_MULTIPLIED) {
return vec4(color.rgb * color.a, color.a);
} else if (inType == ALPHA_TYPE_PRE_MULTIPLIED && outType == ALPHA_TYPE_STRAIGHT && color.a > 0.0) {
return vec4(color.rgb / color.a, color.a);
} else return color;
}
#ifdef ALPHA_TYPE_SPEC_INDEX
layout (constant_id = ALPHA_TYPE_SPEC_INDEX ) const uint const_InAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
layout (constant_id = ALPHA_TYPE_SPEC_INDEX+1) const uint const_OutAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
vec4 convertAlpha(vec4 color) {
return convertAlpha(color, const_InAlphaType, const_OutAlphaType);
}
#endif

View File

@@ -1,11 +1,13 @@
#version 450
#extension GL_GOOGLE_include_directive: require
#define ALPHA_TYPE_SPEC_INDEX 0
#include "alpha_type.glsl"
layout(binding = 0) uniform sampler2D u_TexSampler;
layout(set = 0, binding = 0) uniform texture2D u_Texture;
layout(set = 1, binding = 0) uniform sampler u_Sampler;
layout(location = 0) in vec2 in_TexCoord;
layout(location = 0) out vec4 out_Color;
void main() {
out_Color = texture(u_TexSampler, in_TexCoord);
// TODO: Temporary fix of unexpected transparency with blit operations
out_Color.a = 1.0;
out_Color = convertAlpha(texture(sampler2D(u_Texture, u_Sampler), in_TexCoord));
}

View File

@@ -1,7 +1,7 @@
#version 450
layout(push_constant) uniform PushConstants {
vec2 viewportNormalizer; // 2.0 / viewport
mat2x3 transform;
} push;
layout(location = 0) in vec2 in_Position;
@@ -9,6 +9,6 @@ layout(location = 1) in vec2 in_TexCoord;
layout(location = 0) out vec2 out_TexCoord;
void main() {
gl_Position = vec4(in_Position * push.viewportNormalizer - vec2(1.0), 0.0, 1.0);
gl_Position = vec4(vec3(in_Position, 1.0)*push.transform, 0.0, 1.0);
out_TexCoord = in_TexCoord;
}

View File

@@ -1,11 +1,11 @@
#version 450
layout(push_constant) uniform PushConstants {
vec2 viewportNormalizer; // 2.0 / viewport
mat2x3 transform;
} push;
layout(location = 0) in ivec2 in_Position;
void main() {
gl_Position = vec4(vec2(in_Position) * push.viewportNormalizer - vec2(1.0), 0.0, 1.0);
gl_Position = vec4(vec3(in_Position, 1)*push.transform, 0.0, 1.0);
}

View File

@@ -1,7 +1,7 @@
#version 450
layout(push_constant) uniform PushConstants {
vec2 viewportNormalizer; // 2.0 / viewport
mat2x3 transform;
} push;
layout(location = 0) in vec2 in_Position;
@@ -9,6 +9,6 @@ layout(location = 1) in vec4 in_Color;
layout(location = 0) out flat vec4 out_Color;
void main() {
gl_Position = vec4(in_Position * push.viewportNormalizer - vec2(1.0), 0.0, 1.0);
gl_Position = vec4(vec3(in_Position, 1)*push.transform, 0.0, 1.0);
out_Color = in_Color;
}

View File

@@ -10,7 +10,7 @@ layout(location = 1) in flat vec4 in_Color;
layout(location = 0) out vec4 out_Color;
void main() {
ivec2 maskPos = ivec2(gl_FragCoord.xy) - in_OriginOffsetAndScanline.xy;
ivec2 maskPos = ivec2(gl_FragCoord.xy - vec2(in_OriginOffsetAndScanline.xy));
int offset = in_OriginOffsetAndScanline.z;
int scanline = in_OriginOffsetAndScanline.w;
int maskIndex = offset + scanline * maskPos.y + min(scanline, maskPos.x);

View File

@@ -1,7 +1,7 @@
#version 450
layout(push_constant) uniform PushConstants {
vec2 viewportNormalizer; // 2.0 / viewport
mat2x3 transform;
} push;
layout(location = 0) in ivec4 in_PositionOffsetAndScanline;
@@ -14,7 +14,7 @@ layout(location = 0) out flat ivec4 out_OriginOffsetAndScanline;
layout(location = 1) out flat vec4 out_Color;
void main() {
gl_Position = vec4(vec2(in_PositionOffsetAndScanline.xy) * push.viewportNormalizer - vec2(1.0), 0.0, 1.0);
gl_Position = vec4(vec3(in_PositionOffsetAndScanline.xy, 1)*push.transform, 0.0, 1.0);
out_OriginOffsetAndScanline = in_PositionOffsetAndScanline;
out_Color = in_Color;
}

View File

@@ -432,22 +432,22 @@ bool CARR_hash_map_linear_probing_rehash(CARR_MAP_LAYOUT_ARGS, void** handle, CA
/**
* Find a value for the provided key.
* @param P map
* @param KEY key to find, can be a compound literal, like (int){0}
* @param ... key to find, can be a compound literal, like (int){0}
* @return pointer to the found value, or NULL
*/
#define MAP_FIND(P, KEY) \
CARR_MAP_VALUE_PTR((P), CARR_MAP_DISPATCH((P), find, (P), CARR_MAP_KEY_GUARD((P), &(KEY)), NULL, false))
#define MAP_FIND(P, ...) \
CARR_MAP_VALUE_PTR((P), CARR_MAP_DISPATCH((P), find, (P), CARR_MAP_KEY_GUARD((P), &(__VA_ARGS__)), NULL, false))
/**
* Find a value for the provided key, or insert a new one.
* Value is zeroed for newly inserted items.
* On allocation failure, C_ARRAY_UTIL_ALLOCATION_FAILED is called.
* @param P map
* @param KEY key to find, can be a compound literal, like (int){0}
* @param ... key to find, can be a compound literal, like (int){0}
* @return dereferenced pointer to the found value
*/
#define MAP_AT(P, KEY) (*(MAP_ENSURE_EXTRA_CAPACITY((P), 1), \
CARR_MAP_VALUE_PTR((P), CARR_MAP_DISPATCH((P), find, (P), CARR_MAP_KEY_GUARD((P), &(KEY)), NULL, true))))
#define MAP_AT(P, ...) (*(MAP_ENSURE_EXTRA_CAPACITY((P), 1), \
CARR_MAP_VALUE_PTR((P), CARR_MAP_DISPATCH((P), find, (P), CARR_MAP_KEY_GUARD((P), &(__VA_ARGS__)), NULL, true))))
/**
* Resolve provided key and find corresponding value.
@@ -474,10 +474,10 @@ bool CARR_hash_map_linear_probing_rehash(CARR_MAP_LAYOUT_ARGS, void** handle, CA
/**
* Remove the provided key, if one exists.
* @param P map
* @param KEY key to remove, can be a compound literal, like (int){0}
* @param ... key to remove, can be a compound literal, like (int){0}
* @return true if the key was removed
*/
#define MAP_REMOVE(P, KEY) CARR_MAP_DISPATCH((P), remove, (P), CARR_MAP_KEY_GUARD((P), &(KEY)))
#define MAP_REMOVE(P, ...) CARR_MAP_DISPATCH((P), remove, (P), CARR_MAP_KEY_GUARD((P), &(__VA_ARGS__)))
/**
* Ensure that map has enough capacity to insert COUNT more items without reallocation.

View File

@@ -26,8 +26,8 @@
#include <assert.h>
#include "VKUtil.h"
#include "VKBase.h"
#include "VKAllocator.h"
#include "VKEnv.h"
/**
* Block size is a minimum allocation size.
@@ -165,9 +165,11 @@ VKMemoryRequirements VKAllocator_ImageRequirements(VKAllocator* allocator, VkIma
return r;
}
void VKAllocator_PadToAlignment(VKMemoryRequirements* requirements) {
void VKAllocator_PadToAlignment(VKAllocator* allocator, VKMemoryRequirements* requirements) {
assert(allocator != NULL);
assert(requirements != NULL);
VkMemoryRequirements* t = &requirements->requirements.memoryRequirements;
if (t->alignment < allocator->device->nonCoherentAtomSize) t->alignment = allocator->device->nonCoherentAtomSize;
t->size = ((t->size + t->alignment - 1) / t->alignment) * t->alignment;
requirements->dedicatedRequirements.requiresDedicatedAllocation = VK_FALSE;
requirements->dedicatedRequirements.prefersDedicatedAllocation = VK_FALSE;
@@ -562,8 +564,7 @@ void VKAllocator_Invalidate(VKAllocator* allocator, VKMemory memory, VkDeviceSiz
}
VKAllocator* VKAllocator_Create(VKDevice* device) {
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
VKAllocator* allocator = (VKAllocator*) calloc(1, sizeof(VKAllocator));
VKAllocator* allocator = calloc(1, sizeof(VKAllocator));
allocator->device = device;
allocator->freePageIndex = NO_PAGE_INDEX;
for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
@@ -572,7 +573,7 @@ VKAllocator* VKAllocator_Create(VKDevice* device) {
.allocationLevelTracker = MIN_SHARED_PAGE_LEVEL * 2
};
}
ge->vkGetPhysicalDeviceMemoryProperties(device->physicalDevice, &allocator->memoryProperties);
VKEnv_GetInstance()->vkGetPhysicalDeviceMemoryProperties(device->physicalDevice, &allocator->memoryProperties);
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKAllocator_Create: allocator=%p", allocator);
return allocator;

Some files were not shown because too many files have changed in this diff Show More