mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-26 02:10:49 +01:00
Compare commits
216 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44f0cf40c8 | ||
|
|
e37c2450a8 | ||
|
|
78ef30a322 | ||
|
|
6afbc34d4b | ||
|
|
874d5698bc | ||
|
|
dd1afa581e | ||
|
|
cd5cad7154 | ||
|
|
8827281c82 | ||
|
|
3c8aa5a169 | ||
|
|
fe6d252047 | ||
|
|
08faf984f0 | ||
|
|
1c95b96ff8 | ||
|
|
f1ad521666 | ||
|
|
4a239d2c6e | ||
|
|
47f236f3cc | ||
|
|
7b21605ecb | ||
|
|
ccba9acd9d | ||
|
|
869f0ca11f | ||
|
|
133cf30195 | ||
|
|
210ed7aaba | ||
|
|
07ac32e2ad | ||
|
|
6fe6b416ce | ||
|
|
0c40b9514d | ||
|
|
70d0e98389 | ||
|
|
89049a7d65 | ||
|
|
90ec8da421 | ||
|
|
2348ef2e99 | ||
|
|
54960903b1 | ||
|
|
b95cee8fc2 | ||
|
|
4616ff7408 | ||
|
|
777e396408 | ||
|
|
830fd66a48 | ||
|
|
53e7e4501e | ||
|
|
42c0b92816 | ||
|
|
66b090fd94 | ||
|
|
2fefe69c1e | ||
|
|
67995ff0a6 | ||
|
|
63950e41f9 | ||
|
|
045a7e4e51 | ||
|
|
9e54ae6019 | ||
|
|
873bbbbf0a | ||
|
|
1f4d50ec68 | ||
|
|
2bb26da3aa | ||
|
|
c038d78960 | ||
|
|
0d5fd3a262 | ||
|
|
0834621763 | ||
|
|
94c7666b0a | ||
|
|
a375bb12df | ||
|
|
57b9a8440d | ||
|
|
744155766c | ||
|
|
a34e03679d | ||
|
|
b5d182dad5 | ||
|
|
b1d74cfd8c | ||
|
|
da445c6087 | ||
|
|
5f511645bc | ||
|
|
0520d877f5 | ||
|
|
434759c5d5 | ||
|
|
e12dcf3508 | ||
|
|
4cbbadb390 | ||
|
|
1f26cf71e0 | ||
|
|
a39bae17c1 | ||
|
|
f517898e25 | ||
|
|
f772c75686 | ||
|
|
ec809bd4a3 | ||
|
|
dd7bf16eed | ||
|
|
c33cf48fb2 | ||
|
|
006df66744 | ||
|
|
83c2dee7c1 | ||
|
|
abab9861e3 | ||
|
|
21a4d7d76b | ||
|
|
5a868021da | ||
|
|
e151c26d25 | ||
|
|
2c60b7a85f | ||
|
|
80c0fbb177 | ||
|
|
d43671d418 | ||
|
|
8b00cadfd6 | ||
|
|
26a5760faf | ||
|
|
c62472e069 | ||
|
|
ea2a58e624 | ||
|
|
c0330f4183 | ||
|
|
764e4346b9 | ||
|
|
e5eb7d9946 | ||
|
|
388db19279 | ||
|
|
8b7846203e | ||
|
|
8cc49bad44 | ||
|
|
f03cac9ff2 | ||
|
|
cec6f263c1 | ||
|
|
dda9d6103f | ||
|
|
2f028fbae7 | ||
|
|
bdcd1e4c39 | ||
|
|
61f48f0b88 | ||
|
|
c3549f6239 | ||
|
|
9e99c0fc8e | ||
|
|
92ffe365d4 | ||
|
|
c27dc3a873 | ||
|
|
84cd4fbe2c | ||
|
|
383df1a2dd | ||
|
|
b906579a1f | ||
|
|
3f9953eeae | ||
|
|
8518106781 | ||
|
|
2cbde99ea7 | ||
|
|
d3a0e27b1c | ||
|
|
b73293fa7d | ||
|
|
7adfbd2a3e | ||
|
|
3a78dc3d6c | ||
|
|
93f0cde18c | ||
|
|
40a8493648 | ||
|
|
9bc7cf2b20 | ||
|
|
844ab591b5 | ||
|
|
2c5b433600 | ||
|
|
defae8c96e | ||
|
|
23fccbe136 | ||
|
|
f474814232 | ||
|
|
59b6dfdde8 | ||
|
|
2a1af667e6 | ||
|
|
2abe325dbd | ||
|
|
245acdbd66 | ||
|
|
aa05977182 | ||
|
|
6896b97ab7 | ||
|
|
fc35634581 | ||
|
|
24e28003d8 | ||
|
|
d6ff7e4a23 | ||
|
|
0678564e9e | ||
|
|
0e9d1aaafb | ||
|
|
918e730302 | ||
|
|
e60627e900 | ||
|
|
f25d8f7df5 | ||
|
|
0c7cdb5121 | ||
|
|
eeb8db2b06 | ||
|
|
5cb988d7d8 | ||
|
|
e6a939f040 | ||
|
|
fbe021df82 | ||
|
|
e8cedf7581 | ||
|
|
8fccfdc808 | ||
|
|
6c495147ac | ||
|
|
1f07a1ec6b | ||
|
|
5d8c50a985 | ||
|
|
fe52188a97 | ||
|
|
08726c2c3b | ||
|
|
7795d493e3 | ||
|
|
f9d7d6ae62 | ||
|
|
e350e83d13 | ||
|
|
ea74152ba4 | ||
|
|
006d94e5f7 | ||
|
|
d50b30f24e | ||
|
|
7be6dc146a | ||
|
|
e7c634367b | ||
|
|
d414816fa5 | ||
|
|
32d8dcedeb | ||
|
|
ed921ac9c3 | ||
|
|
8d391838a7 | ||
|
|
4a55cc83e4 | ||
|
|
f13e11bcb2 | ||
|
|
2e460d1500 | ||
|
|
9b1554a5ba | ||
|
|
4ce3da1235 | ||
|
|
fcef03e4c3 | ||
|
|
3d24c9849d | ||
|
|
422e5ad03e | ||
|
|
5108814114 | ||
|
|
2b9241767d | ||
|
|
c530c6bb03 | ||
|
|
9c7a6ec32b | ||
|
|
a0dbcc2c77 | ||
|
|
c323f46b13 | ||
|
|
e684f81d59 | ||
|
|
dc64782afe | ||
|
|
d76f62ad91 | ||
|
|
8e68862875 | ||
|
|
3b0802826f | ||
|
|
19f57666be | ||
|
|
2ffcb1efcb | ||
|
|
d8de757534 | ||
|
|
1bc480c1c1 | ||
|
|
574c532ebf | ||
|
|
85d8121280 | ||
|
|
61892ddc7e | ||
|
|
a887872dbd | ||
|
|
32a25f06a1 | ||
|
|
3f9db3eaa8 | ||
|
|
9a4e1dcaf4 | ||
|
|
952b9b341d | ||
|
|
a45e79c5ec | ||
|
|
f317dace68 | ||
|
|
26cac65d4e | ||
|
|
5d72dff3c6 | ||
|
|
8ece167c80 | ||
|
|
e37d44133a | ||
|
|
447ba4c7af | ||
|
|
3fa9b47987 | ||
|
|
fe544d71ea | ||
|
|
20a9bdebb9 | ||
|
|
185f109e82 | ||
|
|
c1714e7623 | ||
|
|
37ea104c5b | ||
|
|
994da4e774 | ||
|
|
ec47c0e107 | ||
|
|
a2d956d526 | ||
|
|
42c74201c7 | ||
|
|
3dfdfc6671 | ||
|
|
f40ed464dc | ||
|
|
fef56b2194 | ||
|
|
56920ab04c | ||
|
|
c258b1edf1 | ||
|
|
1d9b2ca261 | ||
|
|
79dc605fd4 | ||
|
|
21976f7faa | ||
|
|
49e1ed04c6 | ||
|
|
9a1b44814b | ||
|
|
1d6bd0aaba | ||
|
|
c62bb40cf5 | ||
|
|
3bb65dd8fd | ||
|
|
44458e4210 | ||
|
|
0153a4826f | ||
|
|
3e575ebc93 | ||
|
|
72305df0b5 |
@@ -1 +1 @@
|
||||
1.0.0
|
||||
1.0.2
|
||||
|
||||
@@ -5,34 +5,33 @@
|
||||
# image creation reproducible.
|
||||
# NB: this also means there may be no security-related fixes there, need to
|
||||
# move the version to the next manually.
|
||||
FROM arm64v8/alpine:3.12
|
||||
FROM arm64v8/alpine:3.14
|
||||
|
||||
# Install the necessary build tools
|
||||
RUN apk --no-cache add --update \
|
||||
alsa-lib-dev=1.2.2-r0 \
|
||||
autoconf=2.69-r2 \
|
||||
bash=5.0.17-r0 \
|
||||
build-base=0.5-r2 \
|
||||
alsa-lib-dev=1.2.5-r2 \
|
||||
autoconf=2.71-r0 \
|
||||
bash=5.1.16-r0 \
|
||||
build-base=0.5-r3 \
|
||||
bzip2=1.0.8-r1 \
|
||||
cups-dev=2.3.3-r0 \
|
||||
file=5.38-r0 \
|
||||
fontconfig=2.13.1-r2 \
|
||||
fontconfig-dev=2.13.1-r2 \
|
||||
freetype-dev=2.10.4-r2 \
|
||||
git=2.26.3-r1 \
|
||||
grep=3.4-r0 \
|
||||
libx11-dev=1.6.12-r1 \
|
||||
cups-dev=2.3.3-r3 \
|
||||
file=5.40-r1 \
|
||||
fontconfig=2.13.1-r4 \
|
||||
fontconfig-dev=2.13.1-r4 \
|
||||
freetype-dev=2.10.4-r3 \
|
||||
git=2.32.7-r0 \
|
||||
grep=3.7-r0 \
|
||||
libx11-dev=1.7.3.1-r0 \
|
||||
libxext-dev=1.3.4-r0 \
|
||||
libxrandr-dev=1.5.2-r0 \
|
||||
libxrandr-dev=1.5.2-r1 \
|
||||
libxrender-dev=0.9.10-r3 \
|
||||
libxt-dev=1.2.0-r0 \
|
||||
libxt-dev=1.2.1-r0 \
|
||||
libxtst-dev=1.2.3-r3 \
|
||||
linux-headers=5.4.5-r1 \
|
||||
rsync=3.1.3-r3 \
|
||||
tar=1.32-r2 \
|
||||
wayland-dev=1.18.0-r4 \
|
||||
zip=3.0-r8
|
||||
|
||||
linux-headers=5.10.41-r0 \
|
||||
rsync=3.2.5-r0 \
|
||||
tar=1.34-r1 \
|
||||
wayland-dev=1.19.0-r0 \
|
||||
zip=3.0-r9
|
||||
|
||||
# Set up boot JDK for building
|
||||
COPY boot_jdk_musl_aarch64.tar.gz /jdk20/
|
||||
@@ -40,4 +39,5 @@ RUN cd /jdk20 && tar --strip-components=1 -xzf boot_jdk_musl_aarch64.tar.gz && r
|
||||
ENV BOOT_JDK=/jdk20
|
||||
|
||||
RUN git config --global user.email "teamcity@jetbrains.com" && \
|
||||
git config --global user.name "builduser"
|
||||
git config --global user.name "builduser" && \
|
||||
git config --global --add safe.directory '*'
|
||||
@@ -63,7 +63,7 @@ function create_image_bundle {
|
||||
__cds_opt=''
|
||||
|
||||
if is_musl; then libc_type_suffix='musl-' ; fi
|
||||
if [ "$__arch_name" == "$JBRSDK_BUNDLE" ]; then __cds_opt="--generate-cds-archive"; fi
|
||||
__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}aarch64-${fastdebug_infix}b${build_number}
|
||||
|
||||
@@ -71,7 +71,7 @@ function create_image_bundle {
|
||||
__cds_opt=''
|
||||
|
||||
if is_musl; then libc_type_suffix='musl-' ; fi
|
||||
if [ "$__arch_name" == "$JBRSDK_BUNDLE" ]; then __cds_opt="--generate-cds-archive"; fi
|
||||
__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}x64-${fastdebug_infix}b${build_number}
|
||||
|
||||
@@ -51,7 +51,7 @@ function create_image_bundle {
|
||||
__cds_opt=''
|
||||
|
||||
if is_musl; then libc_type_suffix='musl-' ; fi
|
||||
if [ "$__arch_name" == "$JBRSDK_BUNDLE" ]; then __cds_opt="--generate-cds-archive"; fi
|
||||
__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}
|
||||
|
||||
@@ -53,7 +53,7 @@ function create_image_bundle {
|
||||
|
||||
fastdebug_infix=''
|
||||
__cds_opt=''
|
||||
if [ "$__arch_name" == "$JBRSDK_BUNDLE" ]; then __cds_opt="--generate-cds-archive"; fi
|
||||
__cds_opt="--generate-cds-archive"
|
||||
|
||||
tmp=.bundle.$$.tmp
|
||||
mkdir "$tmp" || do_exit $?
|
||||
|
||||
@@ -54,7 +54,7 @@ function create_image_bundle {
|
||||
|
||||
fastdebug_infix=''
|
||||
__cds_opt=''
|
||||
if [ "$__arch_name" == "$JBRSDK_BUNDLE" ]; then __cds_opt="--generate-cds-archive"; fi
|
||||
__cds_opt="--generate-cds-archive"
|
||||
|
||||
[ "$bundle_type" == "fd" ] && [ "$__arch_name" == "$JBRSDK_BUNDLE" ] && __bundle_name=$__arch_name && fastdebug_infix="fastdebug-"
|
||||
__root_dir=${__bundle_name}-${JBSDK_VERSION}-windows-x64-${fastdebug_infix}b${build_number}
|
||||
|
||||
@@ -50,7 +50,7 @@ function create_image_bundle {
|
||||
|
||||
fastdebug_infix=''
|
||||
__cds_opt=''
|
||||
if [ "$__arch_name" == "$JBRSDK_BUNDLE" ]; then __cds_opt="--generate-cds-archive"; fi
|
||||
__cds_opt="--generate-cds-archive"
|
||||
|
||||
[ "$bundle_type" == "fd" ] && [ "$__arch_name" == "$JBRSDK_BUNDLE" ] && __bundle_name=$__arch_name && fastdebug_infix="fastdebug-"
|
||||
__root_dir=${__bundle_name}-${JBSDK_VERSION}-windows-x86-${fastdebug_infix}b${build_number}
|
||||
|
||||
@@ -62,6 +62,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \
|
||||
ProcessImpl_md.c_CFLAGS := $(VERSION_CFLAGS), \
|
||||
WARNINGS_AS_ERRORS_xlc := false, \
|
||||
DISABLED_WARNINGS_gcc_ProcessImpl_md.c := unused-result, \
|
||||
DISABLED_WARNINGS_clang_jni_util.c := format-nonliteral, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_macosx := -L$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/, \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2024, 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
|
||||
@@ -391,6 +391,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
common/awt/debug \
|
||||
common/awt/systemscale \
|
||||
common/font \
|
||||
common/java2d \
|
||||
common/java2d/wl \
|
||||
common/java2d/vulkan \
|
||||
common/wayland \
|
||||
@@ -1084,6 +1085,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
libawt_lwawt/java2d/metal \
|
||||
include \
|
||||
common/awt/debug \
|
||||
common/java2d \
|
||||
common/java2d/opengl \
|
||||
libosxapp \
|
||||
#
|
||||
|
||||
@@ -80,7 +80,11 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libTracePinnedThreads := jvm.lib
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libNewDirectByteBuffer := $(WIN_LIB_JAVA)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libGetXSpace := $(WIN_LIB_JAVA)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libFatalErrorTest := $(WIN_LIB_JAVA)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libLogEventTest := $(WIN_LIB_JAVA)
|
||||
else
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libFatalErrorTest := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libLogEventTest := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libNewDirectByteBuffer := -ljava
|
||||
|
||||
@@ -549,6 +549,15 @@ JNI_ENTRY(jint, jni_ThrowNew(JNIEnv *env, jclass clazz, const char *message))
|
||||
|
||||
InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)));
|
||||
Symbol* name = k->name();
|
||||
if (name->equals("java/lang/Exception$JB$$Assertion")) {
|
||||
// A special exception name to trigger a fatal error
|
||||
report_fatal(INTERNAL_ERROR, "<dummy>", 0, "%s", message);
|
||||
ShouldNotReachHere();
|
||||
return 0;
|
||||
} else if (name->equals("java/lang/Exception$JB$$Event")) {
|
||||
Events::log(THREAD, "%s", message);
|
||||
return 0;
|
||||
}
|
||||
Handle class_loader (THREAD, k->class_loader());
|
||||
Handle protection_domain (THREAD, k->protection_domain());
|
||||
THROW_MSG_LOADER_(name, (char *)message, class_loader, protection_domain, JNI_OK);
|
||||
|
||||
@@ -242,10 +242,10 @@ void VM_EnhancedRedefineClasses::mark_as_scavengable(nmethod* nm) {
|
||||
ScavengableNMethods::register_nmethod(nm);
|
||||
}
|
||||
|
||||
void VM_EnhancedRedefineClasses::unregister_nmethod_g1(nmethod* nm) {
|
||||
// It should work not only for G1 but also for another GCs, but this way is safer now
|
||||
Universe::heap()->unregister_nmethod(nm);
|
||||
}
|
||||
//void VM_EnhancedRedefineClasses::unregister_nmethod_g1(nmethod* nm) {
|
||||
// // It should work not only for G1 but also for another GCs, but this way is safer now
|
||||
// Universe::heap()->unregister_nmethod(nm);
|
||||
//}
|
||||
|
||||
void VM_EnhancedRedefineClasses::register_nmethod_g1(nmethod* nm) {
|
||||
// It should work not only for G1 but also for another GCs, but this way is safer now
|
||||
@@ -612,7 +612,8 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
if (UseG1GC) {
|
||||
// G1 holds references to nmethods in regions based on oops values. Since oops in nmethod can be changed in ChangePointers* closures
|
||||
// we unregister nmethods from G1 heap, then closures are processed (oops are changed) and finally we register nmethod to G1 again
|
||||
CodeCache::nmethods_do(unregister_nmethod_g1);
|
||||
// CodeCache::nmethods_do(unregister_nmethod_g1);
|
||||
G1CollectedHeap::heap()->bulk_unregister_nmethods();
|
||||
} else {
|
||||
#endif
|
||||
CodeCache::nmethods_do(mark_as_scavengable);
|
||||
|
||||
@@ -126,7 +126,7 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
|
||||
|
||||
void rollback();
|
||||
static void mark_as_scavengable(nmethod* nm);
|
||||
static void unregister_nmethod_g1(nmethod* nm);
|
||||
//static void unregister_nmethod_g1(nmethod* nm);
|
||||
static void register_nmethod_g1(nmethod* nm);
|
||||
static void unpatch_bytecode(Method* method);
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ class Proxy {
|
||||
interFace = target = null;
|
||||
flags = 0;
|
||||
}
|
||||
inverse = inverseProxy == null ? new Proxy(repository, inverseInfo, specialization, this, null, null) : inverseProxy;
|
||||
inverse = inverseProxy == null ? new Proxy(repository, inverseInfo, inverseSpecialization, this, null, null) : inverseProxy;
|
||||
if (inverse.getInterface() != null) directDependencies = Set.of(inverse);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,12 @@ class ProxyGenerator {
|
||||
accessContext.canAccess(info.targetLookup.lookupClass()) ? info.targetLookup.lookupClass() : Object.class;
|
||||
targetDescriptor = constructorTargetParameterType == null ? "" : constructorTargetParameterType.descriptorString();
|
||||
|
||||
proxyName = proxyGenLookup.lookupClass().getPackageName().replace('.', '/') + "/" + interFace.getSimpleName();
|
||||
// Even though generated proxy is hidden and therefore has no qualified name,
|
||||
// it can reference itself via internal name, which can lead to name collisions.
|
||||
// Let's consider specialized proxy for java/util/List - if we name proxy similarly,
|
||||
// methods calls to java/util/List will be treated by VM as calls to proxy class,
|
||||
// not standard library interface. Therefore we append $$$ to proxy name to avoid name collision.
|
||||
proxyName = proxyGenLookup.lookupClass().getPackageName().replace('.', '/') + "/" + interFace.getSimpleName() + "$$$";
|
||||
|
||||
originalProxyWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES) {
|
||||
@Override
|
||||
|
||||
@@ -122,4 +122,7 @@ public class Exception extends Throwable {
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
private static class JB$$Assertion {}
|
||||
private static class JB$$Event {}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,8 @@ public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
|
||||
lock.lock();
|
||||
try {
|
||||
q.offer(e);
|
||||
if (q.peek() == e) {
|
||||
E curPeek = q.peek();
|
||||
if (curPeek == e || curPeek.getDelay(TimeUnit.NANOSECONDS) <= 0L) {
|
||||
leader = null;
|
||||
available.signal();
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ import java.util.stream.StreamSupport;
|
||||
import jdk.internal.access.JavaUtilZipFileAccess;
|
||||
import jdk.internal.access.JavaUtilJarAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.util.OperatingSystem;
|
||||
import jdk.internal.perf.PerfCounter;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
@@ -112,7 +113,7 @@ public class ZipFile implements ZipConstants, Closeable {
|
||||
private final @Stable CleanableResource res;
|
||||
|
||||
private static final boolean USE_NIO_FOR_ZIP_FILE_ACCESS =
|
||||
Boolean.parseBoolean(System.getProperty("java.util.zip.use.nio.for.zip.file.access", "false"));
|
||||
Boolean.parseBoolean(GetPropertyAction.privilegedGetProperty("java.util.zip.use.nio.for.zip.file.access", "false"));
|
||||
|
||||
private static final int STORED = ZipEntry.STORED;
|
||||
private static final int DEFLATED = ZipEntry.DEFLATED;
|
||||
@@ -1571,7 +1572,7 @@ public class ZipFile implements ZipConstants, Closeable {
|
||||
private Source(Key key, boolean toDelete, ZipCoder zc) throws IOException {
|
||||
this.zc = zc;
|
||||
this.key = key;
|
||||
if (USE_NIO_FOR_ZIP_FILE_ACCESS) {
|
||||
if (USE_NIO_FOR_ZIP_FILE_ACCESS && VM.isBooted()) {
|
||||
Set<OpenOption> options;
|
||||
if (toDelete) {
|
||||
options = Set.of(StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE);
|
||||
|
||||
@@ -1306,3 +1306,54 @@ JNU_GetStaticFieldByName(JNIEnv *env,
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNU_Fatal(JNIEnv *env, const char *file, int line, const char *msg)
|
||||
{
|
||||
jclass cls = (*env)->FindClass(env, "java/lang/Exception$JB$$Assertion");
|
||||
if (cls != 0) {
|
||||
size_t len = strlen(msg) + strlen(file) + 64;
|
||||
char *real_msg = malloc(len);
|
||||
snprintf(real_msg, len, "%s (%s:%d)", msg, file, line);
|
||||
// Throwing an exception by this name will trigger JVM fatal error
|
||||
// with the given message
|
||||
(*env)->ThrowNew(env, cls, real_msg);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNU_LogEvent(JNIEnv *env, const char *file, int line, const char *fmt, ...)
|
||||
{
|
||||
jclass cls = (*env)->FindClass(env, "java/lang/Exception$JB$$Event");
|
||||
if (cls == 0) return;
|
||||
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
int len = vsnprintf(NULL, 0, fmt, args);
|
||||
va_end(args);
|
||||
if (len < 0) return;
|
||||
|
||||
int suffix_len = (int) strlen(file) + 64;
|
||||
len += suffix_len;
|
||||
char * real_msg = malloc(len);
|
||||
if (real_msg == NULL) return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(real_msg, len, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
char * suffix = malloc(suffix_len);
|
||||
if (suffix == NULL) {
|
||||
free(real_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(suffix, suffix_len, " (%s:%d)", file, line);
|
||||
strncat(real_msg, suffix, suffix_len);
|
||||
free(suffix);
|
||||
|
||||
// Throwing an exception by this name will result in Events::log() call
|
||||
(*env)->ThrowNew(env, cls, real_msg);
|
||||
free(real_msg);
|
||||
}
|
||||
@@ -237,6 +237,15 @@ JNU_GetStaticFieldByName(JNIEnv *env,
|
||||
const char *name,
|
||||
const char *sig);
|
||||
|
||||
/*
|
||||
* Crashes the JVM with Internal Error providing the message and
|
||||
* source location information in the fatal error log.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
JNU_Fatal(JNIEnv *env, const char *file, int line, const char *msg);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNU_LogEvent(JNIEnv *env, const char *file, int line, const char *fmt, ...);
|
||||
|
||||
/************************************************************************
|
||||
* Miscellaneous utilities used by the class libraries
|
||||
@@ -310,6 +319,23 @@ JNU_GetStaticFieldByName(JNIEnv *env,
|
||||
} while (0)
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Crashes the JVM with Internal Error providing the message and
|
||||
* source location information in the fatal error log iff
|
||||
* 'cond' is not true.
|
||||
*/
|
||||
#define JNU_RUNTIME_ASSERT(env, cond, msg) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
JNU_Fatal((env), __FILE__, __LINE__, (msg));\
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define JNU_LOG_EVENT(env, fmt, ...) \
|
||||
do { \
|
||||
JNU_LogEvent((env), __FILE__, __LINE__, (fmt), ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
/************************************************************************
|
||||
* Debugging utilities
|
||||
*/
|
||||
|
||||
@@ -26,111 +26,37 @@
|
||||
package sun.lwawt;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Point;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.awt.CachedCursorManager;
|
||||
|
||||
public abstract class LWCursorManager {
|
||||
public abstract class LWCursorManager extends CachedCursorManager {
|
||||
|
||||
/**
|
||||
* A flag to indicate if the update is scheduled, so we don't process it
|
||||
* twice.
|
||||
*/
|
||||
private final AtomicBoolean updatePending = new AtomicBoolean(false);
|
||||
|
||||
protected LWCursorManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cursor to correspond the component currently under mouse.
|
||||
*
|
||||
* This method should not be executed on the toolkit thread as it
|
||||
* calls to user code (e.g. Container.findComponentAt).
|
||||
*/
|
||||
public final void updateCursor() {
|
||||
updatePending.set(false);
|
||||
updateCursorImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules updating the cursor on the corresponding event dispatch
|
||||
* thread for the given window.
|
||||
*
|
||||
* This method is called on the toolkit thread as a result of a
|
||||
* native update cursor request (e.g. WM_SETCURSOR on Windows).
|
||||
*/
|
||||
public final void updateCursorLater(final LWWindowPeer window) {
|
||||
if (updatePending.compareAndSet(false, true)) {
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateCursor();
|
||||
}
|
||||
};
|
||||
SunToolkit.executeOnEventHandlerThread(window.getTarget(), r);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCursorImpl() {
|
||||
final Point cursorPos = getCursorPosition();
|
||||
final Component c = findComponent(cursorPos);
|
||||
final Cursor cursor;
|
||||
@Override
|
||||
protected Cursor getCursorByPosition(final Point cursorPos, Component c) {
|
||||
final Object peer = LWToolkit.targetToPeer(c);
|
||||
if (peer instanceof LWComponentPeer) {
|
||||
final LWComponentPeer<?, ?> lwpeer = (LWComponentPeer<?, ?>) peer;
|
||||
final Point p = lwpeer.getLocationOnScreen();
|
||||
cursor = lwpeer.getCursor(new Point(cursorPos.x - p.x,
|
||||
cursorPos.y - p.y));
|
||||
} else {
|
||||
cursor = (c != null) ? c.getCursor() : null;
|
||||
return lwpeer.getCursor(new Point(cursorPos.x - p.x,
|
||||
cursorPos.y - p.y));
|
||||
}
|
||||
setCursor(cursor);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first visible, enabled and showing component under cursor.
|
||||
* Returns null for modal blocked windows.
|
||||
*
|
||||
* @param cursorPos Current cursor position.
|
||||
* @return Component or null.
|
||||
*/
|
||||
private static final Component findComponent(final Point cursorPos) {
|
||||
@Override
|
||||
protected Component getComponentUnderCursor() {
|
||||
final LWComponentPeer<?, ?> peer = LWWindowPeer.getPeerUnderCursor();
|
||||
Component c = null;
|
||||
if (peer != null && peer.getWindowPeerOrSelf().getBlocker() == null) {
|
||||
c = peer.getTarget();
|
||||
if (c instanceof Container) {
|
||||
final Point p = peer.getLocationOnScreen();
|
||||
c = AWTAccessor.getContainerAccessor().findComponentAt(
|
||||
(Container) c, cursorPos.x - p.x, cursorPos.y - p.y, false);
|
||||
|
||||
}
|
||||
while (c != null) {
|
||||
final Object p = AWTAccessor.getComponentAccessor().getPeer(c);
|
||||
if (c.isVisible() && c.isEnabled() && p != null) {
|
||||
break;
|
||||
}
|
||||
c = c.getParent();
|
||||
}
|
||||
return peer.getTarget();
|
||||
}
|
||||
return c;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current cursor position.
|
||||
*/
|
||||
// TODO: make it public to reuse for MouseInfo
|
||||
protected abstract Point getCursorPosition();
|
||||
|
||||
/**
|
||||
* Sets a cursor. The cursor can be null if the mouse is not over a Java
|
||||
* window.
|
||||
* @param cursor the new {@code Cursor}.
|
||||
*/
|
||||
protected abstract void setCursor(Cursor cursor);
|
||||
@Override
|
||||
protected Point getLocationOnScreen(Component component) {
|
||||
return AWTAccessor.getComponentAccessor().getPeer(component).getLocationOnScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.MenuBar;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
@@ -59,12 +58,12 @@ import java.awt.peer.KeyboardFocusManagerPeer;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.AWTAccessor.ComponentAccessor;
|
||||
import sun.awt.AppContext;
|
||||
import sun.awt.CGraphicsDevice;
|
||||
import sun.awt.DisplayChangedListener;
|
||||
import sun.awt.ExtendedKeyCodes;
|
||||
@@ -159,6 +158,8 @@ public class LWWindowPeer
|
||||
*/
|
||||
private LWWindowPeer blocker;
|
||||
|
||||
Jbr7481MouseEnteredExitedFix jbr7481MouseEnteredExitedFix = null;
|
||||
|
||||
public LWWindowPeer(Window target, PlatformComponent platformComponent,
|
||||
PlatformWindow platformWindow, PeerType peerType)
|
||||
{
|
||||
@@ -782,7 +783,7 @@ public class LWWindowPeer
|
||||
|
||||
@Override
|
||||
public void notifyUpdateCursor() {
|
||||
getLWToolkit().getCursorManager().updateCursorLater(this);
|
||||
getLWToolkit().getCursorManager().updateCursorLater(this.getTarget());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -811,6 +812,18 @@ public class LWWindowPeer
|
||||
*/
|
||||
@Override
|
||||
public void notifyMouseEvent(int id, long when, int button,
|
||||
int x, int y, int absX, int absY,
|
||||
int modifiers, int clickCount, boolean popupTrigger,
|
||||
byte[] bdata) {
|
||||
if (Jbr7481MouseEnteredExitedFix.isEnabled) {
|
||||
mouseEnteredExitedBugWorkaround().apply(id, when, button, x, y, absX, absY, modifiers, clickCount, popupTrigger, bdata);
|
||||
}
|
||||
else {
|
||||
doNotifyMouseEvent(id, when, button, x, y, absX, absY, modifiers, clickCount, popupTrigger, bdata);
|
||||
}
|
||||
}
|
||||
|
||||
void doNotifyMouseEvent(int id, long when, int button,
|
||||
int x, int y, int absX, int absY,
|
||||
int modifiers, int clickCount, boolean popupTrigger,
|
||||
byte[] bdata)
|
||||
@@ -959,6 +972,13 @@ public class LWWindowPeer
|
||||
notifyUpdateCursor();
|
||||
}
|
||||
|
||||
private Jbr7481MouseEnteredExitedFix mouseEnteredExitedBugWorkaround() {
|
||||
if (jbr7481MouseEnteredExitedFix == null) {
|
||||
jbr7481MouseEnteredExitedFix = new Jbr7481MouseEnteredExitedFix(this);
|
||||
}
|
||||
return jbr7481MouseEnteredExitedFix;
|
||||
}
|
||||
|
||||
private void generateMouseEnterExitEventsForComponents(long when,
|
||||
int button, int x, int y, int screenX, int screenY,
|
||||
int modifiers, int clickCount, boolean popupTrigger,
|
||||
@@ -1043,7 +1063,7 @@ public class LWWindowPeer
|
||||
*/
|
||||
@Override
|
||||
public void notifyKeyEvent(int id, long when, int modifiers,
|
||||
int keyCode, char keyChar, int keyLocation)
|
||||
int keyCode, char keyChar, int keyLocation, Map<String, Object> properties)
|
||||
{
|
||||
LWKeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
|
||||
Component focusOwner = kfmPeer.getCurrentFocusOwner();
|
||||
@@ -1060,6 +1080,7 @@ public class LWWindowPeer
|
||||
AWTAccessor.getKeyEventAccessor().setExtendedKeyCode(keyEvent,
|
||||
(keyChar == KeyEvent.CHAR_UNDEFINED) ? keyCode
|
||||
: ExtendedKeyCodes.getExtendedKeyCodeForChar(keyChar));
|
||||
AWTAccessor.getKeyEventAccessor().setJBRExtraProperties(keyEvent, properties);
|
||||
postEvent(keyEvent);
|
||||
}
|
||||
|
||||
@@ -1504,4 +1525,122 @@ public class LWWindowPeer
|
||||
}
|
||||
return handle[0];
|
||||
}
|
||||
|
||||
static class Jbr7481MouseEnteredExitedFix {
|
||||
static final boolean isEnabled;
|
||||
|
||||
static {
|
||||
boolean isEnabledLocal = false;
|
||||
|
||||
try {
|
||||
isEnabledLocal = Boolean.parseBoolean(System.getProperty("awt.mac.enableMouseEnteredExitedWorkaround", "true"));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
isEnabled = isEnabledLocal;
|
||||
}
|
||||
|
||||
private final LWWindowPeer peer;
|
||||
long when;
|
||||
int x;
|
||||
int y;
|
||||
int absX;
|
||||
int absY;
|
||||
int modifiers;
|
||||
|
||||
Jbr7481MouseEnteredExitedFix(LWWindowPeer peer) {
|
||||
this.peer = peer;
|
||||
}
|
||||
|
||||
void apply(
|
||||
int id, long when, int button,
|
||||
int x, int y, int absX, int absY,
|
||||
int modifiers, int clickCount, boolean popupTrigger,
|
||||
byte[] bdata
|
||||
) {
|
||||
this.when = when;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.absX = absX;
|
||||
this.absY = absY;
|
||||
this.modifiers = modifiers;
|
||||
switch (id) {
|
||||
case MouseEvent.MOUSE_ENTERED -> {
|
||||
var currentPeerWorkaround = getCurrentPeerWorkaroundOrNull();
|
||||
// First, send a "mouse exited" to the current window, if any,
|
||||
// to maintain a sensible "exited, entered" order.
|
||||
if (currentPeerWorkaround != null && currentPeerWorkaround != this) {
|
||||
currentPeerWorkaround.sendMouseExited();
|
||||
}
|
||||
// Then forward the "mouse entered" to this window, regardless of whether it's already current.
|
||||
// Repeated "mouse entered" are allowed and may be even needed somewhere deep inside this call.
|
||||
peer.doNotifyMouseEvent(id, when, button, x, y, absX, absY, modifiers, clickCount, popupTrigger, bdata);
|
||||
}
|
||||
case MouseEvent.MOUSE_EXITED -> {
|
||||
var currentPeerWorkaround = getCurrentPeerWorkaroundOrNull();
|
||||
// An "exited" event often arrives too late. Such events may cause the current window to get lost.
|
||||
// And since we've already sent a "mouse exited" when entering the current window, we don't need another one.
|
||||
if (currentPeerWorkaround == this) {
|
||||
peer.doNotifyMouseEvent(id, when, button, x, y, absX, absY, modifiers, clickCount, popupTrigger, bdata);
|
||||
}
|
||||
}
|
||||
case MouseEvent.MOUSE_MOVED -> {
|
||||
var currentPeerWorkaround = getCurrentPeerWorkaroundOrNull();
|
||||
if (currentPeerWorkaround != this) {
|
||||
// Inconsistency detected: either the events arrived out of order or never did.
|
||||
// First, send an "exited" event to the current window, if any.
|
||||
if (currentPeerWorkaround != null) {
|
||||
currentPeerWorkaround.sendMouseExited();
|
||||
}
|
||||
// Next, send a fake "mouse entered" to the new window.
|
||||
sendMouseEntered();
|
||||
}
|
||||
peer.doNotifyMouseEvent(id, when, button, x, y, absX, absY, modifiers, clickCount, popupTrigger, bdata);
|
||||
}
|
||||
default -> {
|
||||
peer.doNotifyMouseEvent(id, when, button, x, y, absX, absY, modifiers, clickCount, popupTrigger, bdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Jbr7481MouseEnteredExitedFix getCurrentPeerWorkaroundOrNull() {
|
||||
var currentPeer = getCurrentWindowPeer();
|
||||
return currentPeer == null ? null : currentPeer.jbr7481MouseEnteredExitedFix;
|
||||
}
|
||||
|
||||
private static LWWindowPeer getCurrentWindowPeer() {
|
||||
return LWWindowPeer.getWindowUnderCursor();
|
||||
}
|
||||
|
||||
private void sendMouseEntered() {
|
||||
peer.doNotifyMouseEvent(
|
||||
MouseEvent.MOUSE_ENTERED, when, MouseEvent.NOBUTTON,
|
||||
x, y, absX, absY,
|
||||
modifiers, 0, false,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
private void sendMouseExited() {
|
||||
peer.doNotifyMouseEvent(
|
||||
MouseEvent.MOUSE_EXITED, when, MouseEvent.NOBUTTON,
|
||||
x, y, absX, absY,
|
||||
modifiers, 0, false,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Jbr7481MouseEnteredExitedFix{" +
|
||||
"peer=" + peer +
|
||||
", when=" + when +
|
||||
", x=" + x +
|
||||
", y=" + y +
|
||||
", absX=" + absX +
|
||||
", absY=" + absY +
|
||||
", modifiers=" + modifiers +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
package sun.lwawt;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.util.Map;
|
||||
|
||||
public interface PlatformEventNotifier {
|
||||
void notifyIconify(boolean iconify);
|
||||
@@ -61,5 +62,9 @@ public interface PlatformEventNotifier {
|
||||
* Called by the delegate when a key is pressed.
|
||||
*/
|
||||
void notifyKeyEvent(int id, long when, int modifiers,
|
||||
int keyCode, char keyChar, int keyLocation);
|
||||
int keyCode, char keyChar, int keyLocation, Map<String, Object> properties);
|
||||
|
||||
default void notifyKeyEvent(int id, long when, int modifiers, int keyCode, char keyChar, int keyLocation) {
|
||||
notifyKeyEvent(id, when, modifiers, keyCode, keyChar, keyLocation, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ final class CCursorManager extends LWCursorManager {
|
||||
private CCursorManager() { }
|
||||
|
||||
@Override
|
||||
protected Point getCursorPosition() {
|
||||
public Point getCursorPosition() {
|
||||
final Point2D nativePosition = nativeGetCursorPosition();
|
||||
return new Point((int)nativePosition.getX(), (int)nativePosition.getY());
|
||||
}
|
||||
@@ -67,6 +67,11 @@ final class CCursorManager extends LWCursorManager {
|
||||
return;
|
||||
}
|
||||
currentCursor = cursor;
|
||||
setCurrentCursor();
|
||||
}
|
||||
|
||||
void setCurrentCursor() {
|
||||
Cursor cursor = currentCursor;
|
||||
|
||||
if (cursor == null) {
|
||||
nativeSetBuiltInCursor(Cursor.DEFAULT_CURSOR, null);
|
||||
|
||||
@@ -35,6 +35,7 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -116,6 +117,11 @@ final class CPlatformResponder {
|
||||
|
||||
boolean jpopupTrigger = NSEvent.isPopupTrigger(jmodifiers);
|
||||
|
||||
if (jeventType == MouseEvent.MOUSE_ENTERED || jeventType == MouseEvent.MOUSE_EXITED) {
|
||||
// JBR-7484: AppKit resets the cursor we set previously on entered/exit events, so we re-set it.
|
||||
CCursorManager.getInstance().setCurrentCursor();
|
||||
}
|
||||
|
||||
eventNotifier.notifyMouseEvent(jeventType, System.currentTimeMillis(), jbuttonNumber,
|
||||
x, y, absX, absY, jmodifiers, jclickCount,
|
||||
jpopupTrigger, null);
|
||||
@@ -196,6 +202,9 @@ final class CPlatformResponder {
|
||||
int jkeyCode = KeyEvent.VK_UNDEFINED;
|
||||
int jkeyLocation = KeyEvent.KEY_LOCATION_UNKNOWN;
|
||||
boolean spaceKeyTyped = false;
|
||||
HashMap<String, Object> properties = new HashMap<>();
|
||||
|
||||
properties.put("RAW_KEYCODE", keyCode);
|
||||
|
||||
char testChar = KeyEvent.CHAR_UNDEFINED;
|
||||
|
||||
@@ -208,6 +217,11 @@ final class CPlatformResponder {
|
||||
jkeyCode = out[0];
|
||||
jkeyLocation = out[1];
|
||||
jeventType = out[2];
|
||||
properties.put("US_KEYCODE", jkeyCode);
|
||||
properties.put("DEAD_KEYCODE", KeyEvent.VK_UNDEFINED);
|
||||
properties.put("DEAD_KEYSTROKE", KeyEvent.VK_UNDEFINED);
|
||||
properties.put("IS_TYPED", false);
|
||||
properties.put("CHARACTERS", "");
|
||||
} else {
|
||||
if (chars != null && chars.length() > 0) {
|
||||
// `chars` might contain more than one character, so why are we using the last one?
|
||||
@@ -224,15 +238,23 @@ final class CPlatformResponder {
|
||||
}
|
||||
}
|
||||
|
||||
int[] in = new int[] {keyCode, KeyEventProcessing.useNationalLayouts ? 1 : 0, KeyEventProcessing.reportDeadKeysAsNormal ? 1 : 0};
|
||||
int[] out = new int[2]; // [jkeyCode, jkeyLocation]
|
||||
|
||||
int[] in = new int[] {keyCode, modifierFlags, KeyEventProcessing.useNationalLayouts ? 1 : 0, KeyEventProcessing.reportDeadKeysAsNormal ? 1 : 0};
|
||||
int[] out = new int[5]; // [jkeyCode, jkeyLocation, usKeyCode, deadKeyCode, deadKeyComboCode]
|
||||
NSEvent.nsToJavaKeyInfo(in, out);
|
||||
|
||||
jkeyCode = out[0];
|
||||
jkeyLocation = out[1];
|
||||
jeventType = isNpapiCallback ? NSEvent.npToJavaEventType(eventType) :
|
||||
NSEvent.nsToJavaEventType(eventType);
|
||||
|
||||
properties.put("US_KEYCODE", out[2]);
|
||||
properties.put("DEAD_KEYCODE", out[3]);
|
||||
if (chars != null && chars.isEmpty()) {
|
||||
properties.put("DEAD_KEYSTROKE", out[4]);
|
||||
} else {
|
||||
properties.put("DEAD_KEYSTROKE", KeyEvent.VK_UNDEFINED);
|
||||
}
|
||||
properties.put("CHARACTERS", actualChars == null ? "" : actualChars);
|
||||
}
|
||||
|
||||
char javaChar = (testChar == KeyEvent.CHAR_UNDEFINED) ? KeyEvent.CHAR_UNDEFINED :
|
||||
@@ -245,7 +267,7 @@ final class CPlatformResponder {
|
||||
lastKeyPressCode = jkeyCode;
|
||||
}
|
||||
eventNotifier.notifyKeyEvent(jeventType, when, jmodifiers,
|
||||
jkeyCode, javaChar, jkeyLocation);
|
||||
jkeyCode, javaChar, jkeyLocation, properties);
|
||||
|
||||
// That's the reaction on the PRESSED (not RELEASED) event as it comes to
|
||||
// appear in MacOSX.
|
||||
@@ -258,7 +280,6 @@ final class CPlatformResponder {
|
||||
// Either macOS didn't send us anything in insertText: to type,
|
||||
// or this event was not generated in AWTView.m. Let's fall back to using javaChar
|
||||
// since we still need to generate KEY_TYPED events, for instance for Ctrl+ combinations.
|
||||
// javaChar is guaranteed to be a valid character, since postsTyped is true.
|
||||
actualChars = String.valueOf(javaChar);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
|
||||
public final class CWarningWindow extends CPlatformWindow
|
||||
implements SecurityWarningWindow, PlatformEventNotifier {
|
||||
@@ -245,7 +246,7 @@ public final class CWarningWindow extends CPlatformWindow
|
||||
|
||||
@Override
|
||||
public void notifyKeyEvent(int id, long when, int modifiers, int keyCode,
|
||||
char keyChar, int keyLocation) {
|
||||
char keyChar, int keyLocation, Map<String, Object> properties) {
|
||||
}
|
||||
|
||||
protected int getInitialStyleBits() {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2024 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.lwawt.macosx;
|
||||
|
||||
import com.jetbrains.desktop.JBRKeyboard;
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JBRKeyboardMacOS extends JBRKeyboard {
|
||||
@Override
|
||||
public String getCurrentKeyboardLayout() {
|
||||
// ensure LWCToolkit is initialized
|
||||
LWCToolkit.getLWCToolkit();
|
||||
|
||||
return LWCToolkit.getKeyboardLayoutId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getEnabledKeyboardLayouts() {
|
||||
// ensure LWCToolkit is initialized
|
||||
LWCToolkit.getLWCToolkit();
|
||||
|
||||
return LWCToolkit.getKeyboardLayoutList(false);
|
||||
}
|
||||
}
|
||||
@@ -27,23 +27,28 @@ package sun.lwawt.macosx;
|
||||
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("TextInput")
|
||||
public class JBRTextInputMacOS {
|
||||
private EventListener listener;
|
||||
|
||||
JBRTextInputMacOS() {
|
||||
var desc = (CInputMethodDescriptor) LWCToolkit.getLWCToolkit().getInputMethodAdapterDescriptor();
|
||||
desc.textInputEventListener = new EventListener() {
|
||||
public void handleSelectTextRangeEvent(SelectTextRangeEvent event) {
|
||||
// This listener is called on the EDT
|
||||
synchronized (JBRTextInputMacOS.this) {
|
||||
if (listener != null) {
|
||||
listener.handleSelectTextRangeEvent(event);
|
||||
var toolkit = Toolkit.getDefaultToolkit();
|
||||
if (toolkit instanceof LWCToolkit) {
|
||||
var desc = (CInputMethodDescriptor) ((LWCToolkit) toolkit).getInputMethodAdapterDescriptor();
|
||||
desc.textInputEventListener = new EventListener() {
|
||||
public void handleSelectTextRangeEvent(SelectTextRangeEvent event) {
|
||||
// This listener is called on the EDT
|
||||
synchronized (JBRTextInputMacOS.this) {
|
||||
if (listener != null) {
|
||||
listener.handleSelectTextRangeEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@JBRApi.Provides("TextInput.SelectTextRangeEvent")
|
||||
|
||||
@@ -45,6 +45,6 @@ struct KeyCodeTranslationResult {
|
||||
};
|
||||
|
||||
TISInputSourceRef GetCurrentUnderlyingLayout(BOOL useNationalLayouts);
|
||||
struct KeyCodeTranslationResult TranslateKeyCodeUsingLayout(TISInputSourceRef layout, unsigned short keyCode);
|
||||
struct KeyCodeTranslationResult TranslateKeyCodeUsingLayout(TISInputSourceRef layout, unsigned short keyCode, unsigned mods);
|
||||
|
||||
#endif /* __AWTEVENT_H */
|
||||
|
||||
@@ -505,7 +505,7 @@ TISInputSourceRef GetCurrentUnderlyingLayout(BOOL useNationalLayouts) {
|
||||
return underlyingLayout;
|
||||
}
|
||||
|
||||
struct KeyCodeTranslationResult TranslateKeyCodeUsingLayout(TISInputSourceRef layout, unsigned short keyCode)
|
||||
struct KeyCodeTranslationResult TranslateKeyCodeUsingLayout(TISInputSourceRef layout, unsigned short keyCode, unsigned mods)
|
||||
{
|
||||
struct KeyCodeTranslationResult result = {
|
||||
.character = (unichar)0,
|
||||
@@ -548,7 +548,6 @@ struct KeyCodeTranslationResult TranslateKeyCodeUsingLayout(TISInputSourceRef la
|
||||
return result;
|
||||
}
|
||||
|
||||
UInt32 modifierKeyState = 0;
|
||||
UInt32 deadKeyState = 0;
|
||||
const UniCharCount maxStringLength = 255;
|
||||
UniCharCount actualStringLength = 0;
|
||||
@@ -556,7 +555,7 @@ struct KeyCodeTranslationResult TranslateKeyCodeUsingLayout(TISInputSourceRef la
|
||||
|
||||
// get the deadKeyState
|
||||
OSStatus status = UCKeyTranslate(keyboardLayout,
|
||||
keyCode, kUCKeyActionDown, modifierKeyState,
|
||||
keyCode, kUCKeyActionDown, mods,
|
||||
LMGetKbdType(), 0,
|
||||
&deadKeyState,
|
||||
maxStringLength,
|
||||
@@ -589,7 +588,7 @@ struct KeyCodeTranslationResult TranslateKeyCodeUsingLayout(TISInputSourceRef la
|
||||
|
||||
// Extract the dead key non-combining character
|
||||
status = UCKeyTranslate(keyboardLayout,
|
||||
keyCode, kUCKeyActionDown, modifierKeyState,
|
||||
keyCode, kUCKeyActionDown, mods,
|
||||
LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask,
|
||||
&deadKeyState,
|
||||
maxStringLength,
|
||||
@@ -609,14 +608,50 @@ struct KeyCodeTranslationResult TranslateKeyCodeUsingLayout(TISInputSourceRef la
|
||||
return result;
|
||||
}
|
||||
|
||||
static jint CharacterToDeadKeyCode(unichar ch) {
|
||||
for (const struct CharToVKEntry *map = charToDeadVKTable; map->c != 0; ++map) {
|
||||
if (ch == map->c) {
|
||||
return map->javaKey;
|
||||
}
|
||||
}
|
||||
|
||||
// No builtin VK_DEAD_ constant for this dead key,
|
||||
// nothing better to do than to fall back to the extended key code.
|
||||
// This can happen on the following ascii-capable key layouts on the base layer:
|
||||
// - Apache (com.apple.keylayout.Apache)
|
||||
// - Chickasaw (com.apple.keylayout.Chickasaw)
|
||||
// - Choctaw (com.apple.keylayout.Choctaw)
|
||||
// - Navajo (com.apple.keylayout.Navajo)
|
||||
// - Vietnamese (com.apple.keylayout.Vietnamese)
|
||||
// Vietnamese layout is unique among these in that the "dead key" is actually a self-containing symbol,
|
||||
// that can be modified by an accent typed after it. In essence, it's like a dead key in reverse:
|
||||
// the user should first type the letter and only then the necessary accent.
|
||||
// This way the key code would be what the user expects.
|
||||
|
||||
return 0x1000000 + ch;
|
||||
}
|
||||
|
||||
struct JavaKeyTranslationResult {
|
||||
jint keyCode;
|
||||
jint keyLocation;
|
||||
|
||||
jint usKeyCode; // this is always the key position on the QWERTY keyboard
|
||||
|
||||
// if the base key is dead, then it's the corresponding dead key code, otherwise it's VK_UNDEFINED
|
||||
jint deadKeyCode;
|
||||
|
||||
// if the key combo is dead, then it's the corresponding dead key code, otherwise it's VK_UNDEFINED
|
||||
jint deadKeyComboCode;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the function that uses the table above to take incoming
|
||||
* NSEvent keyCodes and translate to the Java virtual key code.
|
||||
*/
|
||||
static void
|
||||
NsCharToJavaVirtualKeyCode(unsigned short key, const BOOL useNationalLayouts,
|
||||
NsCharToJavaVirtualKeyCode(unsigned short key, unsigned mods, const BOOL useNationalLayouts,
|
||||
const BOOL reportDeadKeysAsNormal,
|
||||
jint *keyCode, jint *keyLocation)
|
||||
struct JavaKeyTranslationResult* result)
|
||||
{
|
||||
// This is going to be a lengthy explanation about what it is that we need to achieve in this function.
|
||||
// It took me quite a while to figure out myself, so hopefully it will be useful to others as well.
|
||||
@@ -699,47 +734,45 @@ NsCharToJavaVirtualKeyCode(unsigned short key, const BOOL useNationalLayouts,
|
||||
// Need to take into account that the same virtual key code may correspond to
|
||||
// different keys depending on the physical layout.
|
||||
|
||||
// memset the result to zero
|
||||
*result = (struct JavaKeyTranslationResult){0};
|
||||
|
||||
const struct KeyTableEntry* usKey = GetKeyTableEntryForKeyCode(key);
|
||||
|
||||
// Determine the underlying layout.
|
||||
// If underlyingLayout is nil then fall back to using the usKey.
|
||||
|
||||
TISInputSourceRef underlyingLayout = GetCurrentUnderlyingLayout(useNationalLayouts);
|
||||
TISInputSourceRef activeLayout = useNationalLayouts ? GetCurrentUnderlyingLayout(NO) : underlyingLayout;
|
||||
|
||||
// Default to returning the US key data.
|
||||
*keyCode = usKey->javaKeyCode;
|
||||
*keyLocation = usKey->javaKeyLocation;
|
||||
result->keyCode = result->usKeyCode = usKey->javaKeyCode;
|
||||
result->keyLocation = usKey->javaKeyLocation;
|
||||
result->deadKeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
|
||||
result->deadKeyComboCode = java_awt_event_KeyEvent_VK_UNDEFINED;
|
||||
|
||||
if (underlyingLayout == nil || !usKey->variesBetweenLayouts) {
|
||||
if (underlyingLayout == nil || activeLayout == nil || !usKey->variesBetweenLayouts) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Translate the key + modifiers using the current key layout
|
||||
struct KeyCodeTranslationResult translatedKeyCombo = TranslateKeyCodeUsingLayout(activeLayout, key, (mods >> 16) & 0xFF);
|
||||
|
||||
// If the key + modifiers produces a dead key, report it
|
||||
if (translatedKeyCombo.isDead) {
|
||||
result->deadKeyComboCode = CharacterToDeadKeyCode(translatedKeyCombo.character);
|
||||
}
|
||||
|
||||
// Translate the key using the underlying key layout.
|
||||
struct KeyCodeTranslationResult translatedKey = TranslateKeyCodeUsingLayout(underlyingLayout, key);
|
||||
struct KeyCodeTranslationResult translatedKey = TranslateKeyCodeUsingLayout(underlyingLayout, key, 0);
|
||||
|
||||
// Test whether this key is dead.
|
||||
if (translatedKey.isDead && !reportDeadKeysAsNormal) {
|
||||
for (const struct CharToVKEntry *map = charToDeadVKTable; map->c != 0; ++map) {
|
||||
if (translatedKey.character == map->c) {
|
||||
*keyCode = map->javaKey;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (translatedKey.isDead) {
|
||||
result->deadKeyCode = CharacterToDeadKeyCode(translatedKey.character);
|
||||
}
|
||||
|
||||
// No builtin VK_DEAD_ constant for this dead key,
|
||||
// nothing better to do than to fall back to the extended key code.
|
||||
// This can happen on the following ascii-capable key layouts:
|
||||
// - Apache (com.apple.keylayout.Apache)
|
||||
// - Chickasaw (com.apple.keylayout.Chickasaw)
|
||||
// - Choctaw (com.apple.keylayout.Choctaw)
|
||||
// - Navajo (com.apple.keylayout.Navajo)
|
||||
// - Vietnamese (com.apple.keylayout.Vietnamese)
|
||||
// Vietnamese layout is unique among these in that the "dead key" is actually a self-containing symbol,
|
||||
// that can be modified by an accent typed after it. In essence, it's like a dead key in reverse:
|
||||
// the user should first type the letter and only then the necessary accent.
|
||||
// This way the key code would be what the user expects.
|
||||
|
||||
*keyCode = 0x1000000 + translatedKey.character;
|
||||
if (!reportDeadKeysAsNormal && result->deadKeyCode) {
|
||||
result->keyCode = result->deadKeyCode;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -755,21 +788,21 @@ NsCharToJavaVirtualKeyCode(unsigned short key, const BOOL useNationalLayouts,
|
||||
|
||||
for (const struct CharToVKEntry *map = extraCharToVKTable; map->c != 0; ++map) {
|
||||
if (map->c == ch) {
|
||||
*keyCode = map->javaKey;
|
||||
result->keyCode = map->javaKey;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch >= 'a' && ch <= 'z') {
|
||||
// key is a basic latin letter
|
||||
*keyCode = java_awt_event_KeyEvent_VK_A + ch - 'a';
|
||||
result->keyCode = java_awt_event_KeyEvent_VK_A + ch - 'a';
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
// key is a digit
|
||||
// numpad digits are already handled, since they don't vary between layouts
|
||||
*keyCode = java_awt_event_KeyEvent_VK_0 + ch - '0';
|
||||
result->keyCode = java_awt_event_KeyEvent_VK_0 + ch - '0';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -782,7 +815,7 @@ NsCharToJavaVirtualKeyCode(unsigned short key, const BOOL useNationalLayouts,
|
||||
// Apart from letters, this is the case for characters like the Section Sign (U+00A7)
|
||||
// on the French keyboard (key ANSI_6) or Pound Sign (U+00A3) on the Italian – QZERTY keyboard (key ANSI_8).
|
||||
|
||||
*keyCode = 0x01000000 + ch;
|
||||
result->keyCode = 0x01000000 + ch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,20 +998,24 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
// in = [keyCode, useNationalLayouts]
|
||||
jshort keyCode = (jshort)data[0];
|
||||
BOOL useNationalLayouts = (data[1] != 0);
|
||||
BOOL reportDeadKeysAsNormal = (data[2] != 0);
|
||||
unsigned mods = ((unsigned*)data)[1];
|
||||
BOOL useNationalLayouts = (data[2] != 0);
|
||||
BOOL reportDeadKeysAsNormal = (data[3] != 0);
|
||||
|
||||
jint jkeyCode = java_awt_event_KeyEvent_VK_UNDEFINED;
|
||||
jint jkeyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN;
|
||||
struct JavaKeyTranslationResult result = {0};
|
||||
|
||||
NsCharToJavaVirtualKeyCode((unsigned short)keyCode,
|
||||
mods,
|
||||
useNationalLayouts,
|
||||
reportDeadKeysAsNormal,
|
||||
&jkeyCode, &jkeyLocation);
|
||||
&result);
|
||||
|
||||
// out = [jkeyCode, jkeyLocation];
|
||||
(*env)->SetIntArrayRegion(env, outData, 0, 1, &jkeyCode);
|
||||
(*env)->SetIntArrayRegion(env, outData, 1, 1, &jkeyLocation);
|
||||
// out = [jkeyCode, jkeyLocation, usKeyCode, deadKeyCode, deadKeyComboCode];
|
||||
(*env)->SetIntArrayRegion(env, outData, 0, 1, &result.keyCode);
|
||||
(*env)->SetIntArrayRegion(env, outData, 1, 1, &result.keyLocation);
|
||||
(*env)->SetIntArrayRegion(env, outData, 2, 1, &result.usKeyCode);
|
||||
(*env)->SetIntArrayRegion(env, outData, 3, 1, &result.deadKeyCode);
|
||||
(*env)->SetIntArrayRegion(env, outData, 4, 1, &result.deadKeyComboCode);
|
||||
|
||||
(*env)->ReleaseIntArrayElements(env, inData, data, 0);
|
||||
|
||||
|
||||
@@ -49,8 +49,7 @@
|
||||
NSString* actualCharacters;
|
||||
|
||||
BOOL fEnablePressAndHold;
|
||||
BOOL fInPressAndHold;
|
||||
BOOL fPAHNeedsToSelect;
|
||||
BOOL fIsPressAndHold;
|
||||
|
||||
id cglLayer; // is a sublayer of view.layer
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, i
|
||||
lastCtrlCombo = 0;
|
||||
|
||||
fEnablePressAndHold = shouldUsePressAndHold();
|
||||
fInPressAndHold = NO;
|
||||
|
||||
mouseIsOver = NO;
|
||||
[self resetTrackingArea];
|
||||
@@ -372,8 +371,11 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
#ifdef LOG_KEY_EVENTS
|
||||
debugPrintNSEvent(event, "keyDown");
|
||||
#endif
|
||||
// Check for willBeHandledByComplexInputMethod here, because interpretKeyEvents might invalidate that field
|
||||
fIsPressAndHold = fEnablePressAndHold && [event willBeHandledByComplexInputMethod] && fInputMethodLOCKABLE;
|
||||
|
||||
fProcessingKeystroke = YES;
|
||||
fKeyEventsNeeded = YES;
|
||||
fKeyEventsNeeded = !fIsPressAndHold;
|
||||
|
||||
NSString *eventCharacters = [event characters];
|
||||
unsigned mods = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||
@@ -389,36 +391,39 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
}
|
||||
|
||||
if (fEnablePressAndHold && [event willBeHandledByComplexInputMethod] &&
|
||||
fInputMethodLOCKABLE)
|
||||
if (fIsPressAndHold)
|
||||
{
|
||||
BOOL skipProcessingCancelKeys = YES;
|
||||
fIsPressAndHold = NO;
|
||||
BOOL skipProcessingCancelKeys = NO;
|
||||
fProcessingKeystroke = NO;
|
||||
if (!fInPressAndHold) {
|
||||
fInPressAndHold = YES;
|
||||
} else {
|
||||
// Abandon input to reset IM and unblock input after canceling
|
||||
// input accented symbols
|
||||
// Abandon input to reset IM and unblock input after canceling
|
||||
// input accented symbols
|
||||
|
||||
switch([event keyCode]) {
|
||||
case kVK_ForwardDelete:
|
||||
case kVK_Delete:
|
||||
skipProcessingCancelKeys = NO;
|
||||
case kVK_Return:
|
||||
case kVK_Escape:
|
||||
case kVK_PageUp:
|
||||
case kVK_PageDown:
|
||||
case kVK_DownArrow:
|
||||
case kVK_UpArrow:
|
||||
case kVK_Home:
|
||||
case kVK_End:
|
||||
// Abandon input to reset IM and unblock input after
|
||||
// canceling input accented symbols
|
||||
[self abandonInput:nil];
|
||||
break;
|
||||
}
|
||||
switch([event keyCode]) {
|
||||
case kVK_Return:
|
||||
case kVK_Escape:
|
||||
case kVK_PageUp:
|
||||
case kVK_PageDown:
|
||||
case kVK_DownArrow:
|
||||
case kVK_UpArrow:
|
||||
case kVK_Home:
|
||||
case kVK_End:
|
||||
skipProcessingCancelKeys = YES;
|
||||
|
||||
case kVK_ForwardDelete:
|
||||
case kVK_Delete:
|
||||
// Abandon input to reset IM and unblock input after
|
||||
// canceling input accented symbols
|
||||
#ifdef LOG_KEY_EVENTS
|
||||
fprintf(stderr, "[AWTView.m] Abandoning input in the keyDown event\n");
|
||||
#endif
|
||||
[self abandonInput:nil];
|
||||
break;
|
||||
}
|
||||
if (skipProcessingCancelKeys) {
|
||||
#ifdef LOG_KEY_EVENTS
|
||||
fprintf(stderr, "[AWTView.m] Skipping the keyDown event: isPressAndHold && skipProcessingCancelKeys\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -428,6 +433,14 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
if ((![self hasMarkedText] && fKeyEventsNeeded) || isDeadKey) {
|
||||
[self deliverJavaKeyEventHelper: event];
|
||||
}
|
||||
#ifdef LOG_KEY_EVENTS
|
||||
else {
|
||||
fprintf(stderr, "[AWTView.m] Skipping the keyDown event: ([self hasMarkedText] || !fKeyEventsNeeded) && !isDeadKey\n");
|
||||
fprintf(stderr, "[AWTView.m] hasMarkedText: %s\n", [self hasMarkedText] ? "YES" : "NO");
|
||||
fprintf(stderr, "[AWTView.m] fKeyEventsNeeded: %s\n", fKeyEventsNeeded ? "YES" : "NO");
|
||||
fprintf(stderr, "[AWTView.m] isDeadKey: %s\n", isDeadKey ? "YES" : "NO");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (actualCharacters != nil) {
|
||||
[actualCharacters release];
|
||||
@@ -456,7 +469,7 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
debugPrintNSEvent(event, "performKeyEquivalent");
|
||||
#endif
|
||||
// if IM is active key events should be ignored
|
||||
if (![self hasMarkedText] && !fInPressAndHold) {
|
||||
if (![self hasMarkedText] && !fIsPressAndHold && ![event willBeHandledByComplexInputMethod]) {
|
||||
[self deliverJavaKeyEventHelper: event];
|
||||
}
|
||||
|
||||
@@ -503,7 +516,7 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
// for layouts that have the backtick as a dead key. Unfortunately, some (but notably not all) of these layouts
|
||||
// consider Cmd+Dead Grave to also be a dead key, which means that event.characters will be an empty string.
|
||||
// Explicitly translating the key code with a proper underlying key layout fixes this.
|
||||
struct KeyCodeTranslationResult translationResult = TranslateKeyCodeUsingLayout(GetCurrentUnderlyingLayout(YES), [event keyCode]);
|
||||
struct KeyCodeTranslationResult translationResult = TranslateKeyCodeUsingLayout(GetCurrentUnderlyingLayout(YES), [event keyCode], 0);
|
||||
if (translationResult.isSuccess && translationResult.character) {
|
||||
return isSystemShortcut_NextWindowInApplication(deviceIndependentModifierFlagsMask, [event keyCode], [NSString stringWithCharacters:&translationResult.character length:1]) ? YES : NO;
|
||||
}
|
||||
@@ -627,6 +640,9 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
static NSEvent* sLastKeyEvent = nil;
|
||||
if (event == sLastKeyEvent) {
|
||||
// The event is repeatedly delivered by keyDown: after performKeyEquivalent:
|
||||
#ifdef LOG_KEY_EVENTS
|
||||
fprintf(stderr, "[AWTView.m] deliverJavaKeyEventHelper: ignoring duplicate events\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
[sLastKeyEvent release];
|
||||
@@ -1174,9 +1190,6 @@ static jclass jc_CInputMethod = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert happens at the end of PAH
|
||||
fInPressAndHold = NO;
|
||||
|
||||
// insertText gets called when the user commits text generated from an input method. It also gets
|
||||
// called during ordinary input as well. We only need to send an input method event when we have marked
|
||||
// text, or 'text in progress'. We also need to send the event if we get an insert text out of the blue!
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 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
|
||||
@@ -25,50 +26,31 @@
|
||||
|
||||
#ifndef MTLTexturePool_h_Included
|
||||
#define MTLTexturePool_h_Included
|
||||
#include <time.h>
|
||||
#import "MTLUtils.h"
|
||||
|
||||
@class MTLPoolCell;
|
||||
|
||||
@interface MTLTexturePoolItem : NSObject
|
||||
@property (readwrite, retain) id<MTLTexture> texture;
|
||||
@property (readwrite) bool isBusy;
|
||||
@property (readwrite) time_t lastUsed;
|
||||
@property (readwrite) bool isMultiSample;
|
||||
@property (readwrite, assign) MTLTexturePoolItem* prev;
|
||||
@property (readwrite, retain) MTLTexturePoolItem* next;
|
||||
@property (readwrite, assign) MTLPoolCell* cell;
|
||||
|
||||
- (id) initWithTexture:(id<MTLTexture>)tex cell:(MTLPoolCell*)cell;
|
||||
@end
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
@interface MTLPooledTextureHandle : NSObject
|
||||
@property (readonly, assign) id<MTLTexture> texture;
|
||||
@property (readonly) MTLRegion rect;
|
||||
- (void) releaseTexture;
|
||||
@property (readonly, assign) id<MTLTexture> texture;
|
||||
@property (readonly) NSUInteger reqWidth;
|
||||
@property (readonly) NSUInteger reqHeight;
|
||||
|
||||
// used by MTLCommandBufferWrapper.onComplete() to release used textures:
|
||||
- (void) releaseTexture;
|
||||
@end
|
||||
|
||||
// NOTE: owns all MTLTexture objects
|
||||
@interface MTLTexturePool : NSObject
|
||||
@property (readwrite, retain) id<MTLDevice> device;
|
||||
@property (readwrite, retain) id<MTLDevice> device;
|
||||
@property (readwrite) uint64_t memoryAllocated;
|
||||
@property (readwrite) uint64_t totalMemoryAllocated;
|
||||
@property (readwrite) uint32_t allocatedCount;
|
||||
@property (readwrite) uint32_t totalAllocatedCount;
|
||||
@property (readwrite) uint64_t cacheHits;
|
||||
@property (readwrite) uint64_t totalHits;
|
||||
|
||||
- (id) initWithDevice:(id<MTLDevice>)device;
|
||||
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format;
|
||||
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format
|
||||
isMultiSample:(bool)isMultiSample;
|
||||
@end
|
||||
- (id) initWithDevice:(id<MTLDevice>)device;
|
||||
|
||||
@interface MTLPoolCell : NSObject
|
||||
@property (readwrite, retain) MTLTexturePoolItem* available;
|
||||
@property (readwrite, assign) MTLTexturePoolItem* availableTail;
|
||||
@property (readwrite, retain) MTLTexturePoolItem* occupied;
|
||||
- (MTLTexturePoolItem *)createItem:(id<MTLDevice>)dev
|
||||
width:(int)width
|
||||
height:(int)height
|
||||
format:(MTLPixelFormat)format
|
||||
isMultiSample:(bool)isMultiSample;
|
||||
- (NSUInteger)cleanIfBefore:(time_t)lastUsedTimeToRemove;
|
||||
- (void)releaseItem:(MTLTexturePoolItem *)item;
|
||||
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format;
|
||||
@end
|
||||
|
||||
#endif /* MTLTexturePool_h_Included */
|
||||
|
||||
@@ -0,0 +1,823 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#include "time.h"
|
||||
|
||||
#import "AccelTexturePool.h"
|
||||
#import "MTLTexturePool.h"
|
||||
#import "Trace.h"
|
||||
|
||||
#define USE_ACCEL_TEXTURE_POOL 0
|
||||
|
||||
#define TRACE_LOCK 0
|
||||
#define TRACE_TEX 0
|
||||
|
||||
|
||||
/* lock API */
|
||||
ATexturePoolLockPrivPtr* MTLTexturePoolLock_initImpl(void) {
|
||||
NSLock* l = [[[NSLock alloc] init] autorelease];
|
||||
[l retain];
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLTexturePoolLock_initImpl: lock=%p", l);
|
||||
return l;
|
||||
}
|
||||
|
||||
void MTLTexturePoolLock_DisposeImpl(ATexturePoolLockPrivPtr *lock) {
|
||||
NSLock* l = (NSLock*)lock;
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLTexturePoolLock_DisposeImpl: lock=%p", l);
|
||||
[l release];
|
||||
}
|
||||
|
||||
void MTLTexturePoolLock_lockImpl(ATexturePoolLockPrivPtr *lock) {
|
||||
NSLock* l = (NSLock*)lock;
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLTexturePoolLock_lockImpl: lock=%p", l);
|
||||
[l lock];
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLTexturePoolLock_lockImpl: lock=%p - locked", l);
|
||||
}
|
||||
|
||||
void MTLTexturePoolLock_unlockImpl(ATexturePoolLockPrivPtr *lock) {
|
||||
NSLock* l = (NSLock*)lock;
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLTexturePoolLock_unlockImpl: lock=%p", l);
|
||||
[l unlock];
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLTexturePoolLock_unlockImpl: lock=%p - unlocked", l);
|
||||
}
|
||||
|
||||
|
||||
/* Texture allocate/free API */
|
||||
static id<MTLTexture> MTLTexturePool_createTexture(id<MTLDevice> device,
|
||||
int width,
|
||||
int height,
|
||||
long format)
|
||||
{
|
||||
MTLTextureDescriptor *textureDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:(MTLPixelFormat)format
|
||||
width:(NSUInteger) width
|
||||
height:(NSUInteger) height
|
||||
mipmapped:NO];
|
||||
// By default:
|
||||
// usage = MTLTextureUsageShaderRead
|
||||
// storage = MTLStorageModeManaged
|
||||
textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
|
||||
// Use auto-release => MTLTexturePoolItem.dealloc to free texture !
|
||||
id <MTLTexture> texture = (id <MTLTexture>) [[device newTextureWithDescriptor:textureDescriptor] autorelease];
|
||||
[texture retain];
|
||||
|
||||
if (TRACE_TEX) J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "MTLTexturePool_createTexture: created texture: tex=%p, w=%d h=%d, pf=%d",
|
||||
texture, [texture width], [texture height], [texture pixelFormat]);
|
||||
return texture;
|
||||
}
|
||||
|
||||
static int MTLTexturePool_bytesPerPixel(long format) {
|
||||
switch ((MTLPixelFormat)format) {
|
||||
case MTLPixelFormatBGRA8Unorm:
|
||||
return 4;
|
||||
case MTLPixelFormatA8Unorm:
|
||||
return 1;
|
||||
default:
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "MTLTexturePool_bytesPerPixel: format=%d not supported (4 bytes by default)", format);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void MTLTexturePool_freeTexture(id<MTLDevice> device, id<MTLTexture> texture) {
|
||||
if (TRACE_TEX) J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "MTLTexturePool_freeTexture: free texture: tex=%p, w=%d h=%d, pf=%d",
|
||||
texture, [texture width], [texture height], [texture pixelFormat]);
|
||||
[texture release];
|
||||
}
|
||||
|
||||
/*
|
||||
* Former but updated MTLTexturePool implementation
|
||||
*/
|
||||
|
||||
#define USE_MAX_GPU_DEVICE_MEM 1
|
||||
#define MAX_GPU_DEVICE_MEM (512 * UNIT_MB)
|
||||
#define SCREEN_MEMORY_SIZE_5K (5120 * 4096 * 4) // ~ 84 mb
|
||||
|
||||
#define MAX_POOL_ITEM_LIFETIME_SEC 30
|
||||
|
||||
// 32 pixel
|
||||
#define CELL_WIDTH_BITS 5
|
||||
#define CELL_HEIGHT_BITS 5
|
||||
|
||||
#define CELL_WIDTH_MASK ((1 << CELL_WIDTH_BITS) - 1)
|
||||
#define CELL_HEIGHT_MASK ((1 << CELL_HEIGHT_BITS) - 1)
|
||||
|
||||
#define USE_CEIL_SIZE 1
|
||||
|
||||
#define FORCE_GC 1
|
||||
// force gc (prune old textures):
|
||||
#define FORCE_GC_INTERVAL_SEC (MAX_POOL_ITEM_LIFETIME_SEC * 10)
|
||||
|
||||
// force young gc every 15 seconds (prune only not reused textures):
|
||||
#define YOUNG_GC_INTERVAL_SEC 15
|
||||
#define YOUNG_GC_LIFETIME_SEC (FORCE_GC_INTERVAL_SEC * 2)
|
||||
|
||||
#define TRACE_GC 1
|
||||
#define TRACE_GC_ALIVE 0
|
||||
|
||||
#define TRACE_MEM_API 0
|
||||
#define TRACE_USE_API 0
|
||||
#define TRACE_REUSE 0
|
||||
|
||||
#define INIT_TEST 0
|
||||
#define INIT_TEST_STEP 1
|
||||
#define INIT_TEST_MAX 1024
|
||||
|
||||
/* private definitions */
|
||||
@class MTLPoolCell;
|
||||
|
||||
@interface MTLTexturePoolItem : NSObject
|
||||
@property (readwrite, assign) id<MTLTexture> texture;
|
||||
@property (readwrite, assign) MTLPoolCell* cell;
|
||||
@property (readwrite, assign) MTLTexturePoolItem* prev;
|
||||
@property (readwrite, retain) MTLTexturePoolItem* next;
|
||||
@property (readwrite) time_t lastUsed;
|
||||
@property (readwrite) int width;
|
||||
@property (readwrite) int height;
|
||||
@property (readwrite) MTLPixelFormat format;
|
||||
@property (readwrite) int reuseCount;
|
||||
@property (readwrite) bool isBusy;
|
||||
@end
|
||||
|
||||
@interface MTLPoolCell : NSObject
|
||||
@property (readwrite, retain) MTLTexturePoolItem* available;
|
||||
@property (readwrite, assign) MTLTexturePoolItem* availableTail;
|
||||
@property (readwrite, retain) MTLTexturePoolItem* occupied;
|
||||
@end
|
||||
|
||||
@implementation MTLTexturePoolItem
|
||||
|
||||
@synthesize texture, lastUsed, next, cell, width, height, format, reuseCount, isBusy;
|
||||
|
||||
- (id) initWithTexture:(id<MTLTexture>)tex
|
||||
cell:(MTLPoolCell*)c
|
||||
width:(int)w
|
||||
height:(int)h
|
||||
format:(MTLPixelFormat)f
|
||||
{
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
self.texture = tex;
|
||||
self.cell = c;
|
||||
self.next = nil;
|
||||
self.prev = nil;
|
||||
self.lastUsed = 0;
|
||||
self.width = w;
|
||||
self.height = h;
|
||||
self.format = f;
|
||||
self.reuseCount = 0;
|
||||
self.isBusy = NO;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLTexturePoolItem_initWithTexture: item = %p", self);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn2(J2D_TRACE_INFO, "MTLTexturePoolItem_dealloc: item = %p - reuse: %4d", self, self.reuseCount);
|
||||
|
||||
// use texture (native API) to release allocated texture:
|
||||
MTLTexturePool_freeTexture(nil, self.texture);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) releaseItem {
|
||||
if (!isBusy) {
|
||||
return;
|
||||
}
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLTexturePoolItem_releaseItem: item = %p", self);
|
||||
|
||||
if (self.cell != nil) {
|
||||
[self.cell releaseCellItem:self];
|
||||
} else {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "MTLTexturePoolItem_releaseItem: item = %p (detached)", self);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
/* MTLPooledTextureHandle API */
|
||||
@implementation MTLPooledTextureHandle
|
||||
{
|
||||
id<MTLTexture> _texture;
|
||||
MTLTexturePoolItem * _poolItem;
|
||||
ATexturePoolHandle* _texHandle;
|
||||
NSUInteger _reqWidth;
|
||||
NSUInteger _reqHeight;
|
||||
}
|
||||
@synthesize texture = _texture, reqWidth = _reqWidth, reqHeight = _reqHeight;
|
||||
|
||||
- (id) initWithPoolItem:(id<MTLTexture>)texture poolItem:(MTLTexturePoolItem *)poolItem reqWidth:(NSUInteger)w reqHeight:(NSUInteger)h {
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
_texture = texture;
|
||||
_poolItem = poolItem;
|
||||
_texHandle = nil;
|
||||
|
||||
_reqWidth = w;
|
||||
_reqHeight = h;
|
||||
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPooledTextureHandle_initWithPoolItem: handle = %p", self);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initWithTextureHandle:(ATexturePoolHandle*)texHandle {
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
_texture = ATexturePoolHandle_GetTexture(texHandle);
|
||||
_poolItem = nil;
|
||||
_texHandle = texHandle;
|
||||
|
||||
_reqWidth = ATexturePoolHandle_GetRequestedWidth(texHandle);
|
||||
_reqHeight = ATexturePoolHandle_GetRequestedHeight(texHandle);
|
||||
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPooledTextureHandle_initWithTextureHandle: handle = %p", self);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) releaseTexture {
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPooledTextureHandle_ReleaseTexture: handle = %p", self);
|
||||
if (_texHandle != nil) {
|
||||
ATexturePoolHandle_ReleaseTexture(_texHandle);
|
||||
}
|
||||
if (_poolItem != nil) {
|
||||
[_poolItem releaseItem];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation MTLPoolCell {
|
||||
MTLTexturePool* _pool;
|
||||
NSLock* _lock;
|
||||
}
|
||||
@synthesize available, availableTail, occupied;
|
||||
|
||||
- (instancetype) init:(MTLTexturePool*)pool {
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
self.available = nil;
|
||||
self.availableTail = nil;
|
||||
self.occupied = nil;
|
||||
_pool = pool;
|
||||
_lock = [[NSLock alloc] init];
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPoolCell_init: cell = %p", self);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) removeAllItems {
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn(J2D_TRACE_INFO, "MTLPoolCell_removeAllItems");
|
||||
|
||||
MTLTexturePoolItem *cur = self.available;
|
||||
MTLTexturePoolItem *next = nil;
|
||||
while (cur != nil) {
|
||||
next = cur.next;
|
||||
self.available = cur;
|
||||
cur = next;
|
||||
}
|
||||
cur = self.occupied;
|
||||
next = nil;
|
||||
while (cur != nil) {
|
||||
next = cur.next;
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "MTLPoolCell_removeAllItems: occupied item = %p (detached)", cur);
|
||||
// Do not dispose (may leak) until MTLTexturePoolItem_releaseItem() is called by handle:
|
||||
// mark item as detached:
|
||||
cur.cell = nil;
|
||||
cur = next;
|
||||
self.occupied = cur;
|
||||
}
|
||||
self.availableTail = nil;
|
||||
}
|
||||
|
||||
- (void) removeAvailableItem:(MTLTexturePoolItem*)item {
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPoolCell_removeAvailableItem: item = %p", item);
|
||||
[item retain];
|
||||
if (item.prev == nil) {
|
||||
self.available = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = nil;
|
||||
item.next = nil;
|
||||
} else {
|
||||
self.availableTail = item.prev;
|
||||
}
|
||||
} else {
|
||||
item.prev.next = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = item.prev;
|
||||
item.next = nil;
|
||||
} else {
|
||||
self.availableTail = item.prev;
|
||||
}
|
||||
}
|
||||
[item release];
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPoolCell_dealloc: cell = %p", self);
|
||||
[_lock lock];
|
||||
@try {
|
||||
[self removeAllItems];
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
[_lock release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) occupyItem:(MTLTexturePoolItem *)item {
|
||||
if (item.isBusy) {
|
||||
return;
|
||||
}
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPoolCell_occupyItem: item = %p", item);
|
||||
[item retain];
|
||||
if (item.prev == nil) {
|
||||
self.available = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = nil;
|
||||
} else {
|
||||
self.availableTail = item.prev;
|
||||
}
|
||||
} else {
|
||||
item.prev.next = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = item.prev;
|
||||
} else {
|
||||
self.availableTail = item.prev;
|
||||
}
|
||||
item.prev = nil;
|
||||
}
|
||||
if (occupied) {
|
||||
occupied.prev = item;
|
||||
}
|
||||
item.next = occupied;
|
||||
self.occupied = item;
|
||||
item.isBusy = YES;
|
||||
[item release];
|
||||
}
|
||||
|
||||
- (void) releaseCellItem:(MTLTexturePoolItem *)item {
|
||||
if (!item.isBusy) return;
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPoolCell_releaseCellItem: item = %p", item);
|
||||
[_lock lock];
|
||||
@try {
|
||||
[item retain];
|
||||
if (item.prev == nil) {
|
||||
self.occupied = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = nil;
|
||||
}
|
||||
} else {
|
||||
item.prev.next = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = item.prev;
|
||||
}
|
||||
item.prev = nil;
|
||||
}
|
||||
if (self.available) {
|
||||
self.available.prev = item;
|
||||
} else {
|
||||
self.availableTail = item;
|
||||
}
|
||||
item.next = self.available;
|
||||
self.available = item;
|
||||
item.isBusy = NO;
|
||||
[item release];
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) addOccupiedItem:(MTLTexturePoolItem *)item {
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPoolCell_addOccupiedItem: item = %p", item);
|
||||
[_lock lock];
|
||||
@try {
|
||||
_pool.allocatedCount++;
|
||||
_pool.totalAllocatedCount++;
|
||||
|
||||
if (self.occupied) {
|
||||
self.occupied.prev = item;
|
||||
}
|
||||
item.next = self.occupied;
|
||||
self.occupied = item;
|
||||
item.isBusy = YES;
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) cleanIfBefore:(time_t)lastUsedTimeToRemove {
|
||||
[_lock lock];
|
||||
@try {
|
||||
MTLTexturePoolItem *cur = availableTail;
|
||||
while (cur != nil) {
|
||||
MTLTexturePoolItem *prev = cur.prev;
|
||||
if ((cur.reuseCount == 0) || (lastUsedTimeToRemove <= 0) || (cur.lastUsed < lastUsedTimeToRemove)) {
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "MTLPoolCell_cleanIfBefore: remove pool item: tex=%p, w=%d h=%d, elapsed=%d",
|
||||
cur.texture, cur.width, cur.height,
|
||||
time(NULL) - cur.lastUsed);
|
||||
|
||||
const int requestedBytes = cur.width * cur.height * MTLTexturePool_bytesPerPixel(cur.format);
|
||||
// cur is nil after removeAvailableItem:
|
||||
[self removeAvailableItem:cur];
|
||||
_pool.allocatedCount--;
|
||||
_pool.memoryAllocated -= requestedBytes;
|
||||
} else {
|
||||
if (TRACE_MEM_API || TRACE_GC_ALIVE) J2dRlsTraceLn2(J2D_TRACE_INFO, "MTLPoolCell_cleanIfBefore: item = %p - ALIVE - reuse: %4d -> 0",
|
||||
cur, cur.reuseCount);
|
||||
// clear reuse count anyway:
|
||||
cur.reuseCount = 0;
|
||||
}
|
||||
cur = prev;
|
||||
}
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (MTLTexturePoolItem *) occupyCellItem:(int)width height:(int)height format:(MTLPixelFormat)format {
|
||||
int minDeltaArea = -1;
|
||||
const int requestedPixels = width*height;
|
||||
MTLTexturePoolItem *minDeltaTpi = nil;
|
||||
[_lock lock];
|
||||
@try {
|
||||
for (MTLTexturePoolItem *cur = available; cur != nil; cur = cur.next) {
|
||||
// TODO: use swizzle when formats are not equal:
|
||||
if (cur.format != format) {
|
||||
continue;
|
||||
}
|
||||
if (cur.width < width || cur.height < height) {
|
||||
continue;
|
||||
}
|
||||
const int deltaArea = (const int) (cur.width * cur.height - requestedPixels);
|
||||
if (minDeltaArea < 0 || deltaArea < minDeltaArea) {
|
||||
minDeltaArea = deltaArea;
|
||||
minDeltaTpi = cur;
|
||||
if (deltaArea == 0) {
|
||||
// found exact match in current cell
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minDeltaTpi) {
|
||||
[self occupyItem:minDeltaTpi];
|
||||
}
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLPoolCell_occupyCellItem: item = %p", minDeltaTpi);
|
||||
return minDeltaTpi;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
/* MTLTexturePool API */
|
||||
@implementation MTLTexturePool {
|
||||
void ** _cells;
|
||||
int _poolCellWidth;
|
||||
int _poolCellHeight;
|
||||
uint64_t _maxPoolMemory;
|
||||
uint64_t _memoryAllocated;
|
||||
uint64_t _memoryTotalAllocated;
|
||||
time_t _lastYoungGC;
|
||||
time_t _lastFullGC;
|
||||
time_t _lastGC;
|
||||
ATexturePool* _accelTexturePool;
|
||||
bool _enableGC;
|
||||
}
|
||||
|
||||
@synthesize device, allocatedCount, totalAllocatedCount,
|
||||
memoryAllocated = _memoryAllocated,
|
||||
totalMemoryAllocated = _memoryTotalAllocated;
|
||||
|
||||
- (void) autoTest:(MTLPixelFormat)format {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "MTLTexturePool_autoTest: step = %d", INIT_TEST_STEP);
|
||||
|
||||
_enableGC = false;
|
||||
|
||||
for (int w = 1; w <= INIT_TEST_MAX; w += INIT_TEST_STEP) {
|
||||
for (int h = 1; h <= INIT_TEST_MAX; h += INIT_TEST_STEP) {
|
||||
/* use auto-release pool to free memory as early as possible */
|
||||
@autoreleasepool {
|
||||
MTLPooledTextureHandle *texHandle = [self getTexture:w height:h format:format];
|
||||
id<MTLTexture> texture = texHandle.texture;
|
||||
if (texture == nil) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLTexturePool_autoTest: w= %d h= %d => texture is NULL !", w, h);
|
||||
} else {
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn3(J2D_TRACE_VERBOSE, "MTLTexturePool_autoTest: w=%d h=%d => tex=%p",
|
||||
w, h, texture);
|
||||
}
|
||||
[texHandle releaseTexture];
|
||||
}
|
||||
}
|
||||
}
|
||||
J2dRlsTraceLn2(J2D_TRACE_INFO, "MTLTexturePool_autoTest: before GC: total allocated memory = %lld Mb (total allocs: %d)",
|
||||
_memoryTotalAllocated / UNIT_MB, self.totalAllocatedCount);
|
||||
|
||||
_enableGC = true;
|
||||
|
||||
[self cleanIfNecessary:FORCE_GC_INTERVAL_SEC];
|
||||
|
||||
J2dRlsTraceLn2(J2D_TRACE_INFO, "MTLTexturePool_autoTest: after GC: total allocated memory = %lld Mb (total allocs: %d)",
|
||||
_memoryTotalAllocated / UNIT_MB, self.totalAllocatedCount);
|
||||
}
|
||||
|
||||
- (id) initWithDevice:(id<MTLDevice>)dev {
|
||||
// recommendedMaxWorkingSetSize typically greatly exceeds SCREEN_MEMORY_SIZE_5K constant.
|
||||
// It usually corresponds to the VRAM available to the graphics card
|
||||
uint64_t maxDeviceMemory = dev.recommendedMaxWorkingSetSize;
|
||||
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
#if (USE_ACCEL_TEXTURE_POOL == 1)
|
||||
ATexturePoolLockWrapper *lockWrapper = ATexturePoolLockWrapper_init(&MTLTexturePoolLock_initImpl,
|
||||
&MTLTexturePoolLock_DisposeImpl,
|
||||
&MTLTexturePoolLock_lockImpl,
|
||||
&MTLTexturePoolLock_unlockImpl);
|
||||
|
||||
_accelTexturePool = ATexturePool_initWithDevice(dev,
|
||||
(jlong)maxDeviceMemory,
|
||||
&MTLTexturePool_createTexture,
|
||||
&MTLTexturePool_freeTexture,
|
||||
&MTLTexturePool_bytesPerPixel,
|
||||
lockWrapper,
|
||||
MTLPixelFormatBGRA8Unorm);
|
||||
#endif
|
||||
self.device = dev;
|
||||
|
||||
// use (5K) 5120-by-2880 resolution:
|
||||
_poolCellWidth = 5120 >> CELL_WIDTH_BITS;
|
||||
_poolCellHeight = 2880 >> CELL_HEIGHT_BITS;
|
||||
|
||||
const int cellsCount = _poolCellWidth * _poolCellHeight;
|
||||
_cells = (void **)malloc(cellsCount * sizeof(void*));
|
||||
CHECK_NULL_LOG_RETURN(_cells, NULL, "MTLTexturePool_initWithDevice: could not allocate cells");
|
||||
memset(_cells, 0, cellsCount * sizeof(void*));
|
||||
|
||||
_maxPoolMemory = maxDeviceMemory / 2;
|
||||
// Set maximum to handle at least 5K screen size
|
||||
if (_maxPoolMemory < SCREEN_MEMORY_SIZE_5K) {
|
||||
_maxPoolMemory = SCREEN_MEMORY_SIZE_5K;
|
||||
} else if (USE_MAX_GPU_DEVICE_MEM && (_maxPoolMemory > MAX_GPU_DEVICE_MEM)) {
|
||||
_maxPoolMemory = MAX_GPU_DEVICE_MEM;
|
||||
}
|
||||
|
||||
self.allocatedCount = 0;
|
||||
self.totalAllocatedCount = 0;
|
||||
|
||||
_memoryAllocated = 0;
|
||||
_memoryTotalAllocated = 0;
|
||||
|
||||
_enableGC = true;
|
||||
_lastGC = time(NULL);
|
||||
_lastYoungGC = _lastGC;
|
||||
_lastFullGC = _lastGC;
|
||||
|
||||
self.cacheHits = 0;
|
||||
self.totalHits = 0;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn2(J2D_TRACE_INFO, "MTLTexturePool_initWithDevice: pool = %p - maxPoolMemory = %lld", self, _maxPoolMemory);
|
||||
|
||||
if (INIT_TEST) {
|
||||
static bool INIT_TEST_START = true;
|
||||
if (INIT_TEST_START) {
|
||||
INIT_TEST_START = false;
|
||||
[self autoTest:MTLPixelFormatBGRA8Unorm];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
#if (USE_ACCEL_TEXTURE_POOL == 1)
|
||||
ATexturePoolLockWrapper_Dispose(ATexturePool_getLockWrapper(_accelTexturePool));
|
||||
ATexturePool_Dispose(_accelTexturePool);
|
||||
#endif
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLTexturePool_dealloc: pool = %p", self);
|
||||
|
||||
for (int c = 0; c < _poolCellWidth * _poolCellHeight; ++c) {
|
||||
MTLPoolCell *cell = _cells[c];
|
||||
if (cell != NULL) {
|
||||
[cell release];
|
||||
}
|
||||
}
|
||||
free(_cells);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) cleanIfNecessary:(int)lastUsedTimeThreshold {
|
||||
time_t lastUsedTimeToRemove =
|
||||
lastUsedTimeThreshold > 0 ?
|
||||
time(NULL) - lastUsedTimeThreshold :
|
||||
lastUsedTimeThreshold;
|
||||
|
||||
if (TRACE_MEM_API || TRACE_GC) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLTexturePool_cleanIfNecessary: before GC: allocated memory = %lld Kb (allocs: %d)",
|
||||
_memoryAllocated / UNIT_KB, self.allocatedCount);
|
||||
}
|
||||
|
||||
for (int cy = 0; cy < _poolCellHeight; ++cy) {
|
||||
for (int cx = 0; cx < _poolCellWidth; ++cx) {
|
||||
MTLPoolCell *cell = _cells[cy * _poolCellWidth + cx];
|
||||
if (cell != NULL) {
|
||||
[cell cleanIfBefore:lastUsedTimeToRemove];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TRACE_MEM_API || TRACE_GC) {
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "MTLTexturePool_cleanIfNecessary: after GC: allocated memory = %lld Kb (allocs: %d) - hits = %lld (%.3lf %% cached)",
|
||||
_memoryAllocated / UNIT_KB, self.allocatedCount,
|
||||
self.totalHits, (self.totalHits != 0) ? (100.0 * self.cacheHits) / self.totalHits : 0.0);
|
||||
// reset hits:
|
||||
self.cacheHits = 0;
|
||||
self.totalHits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: called from RQ-thread (on blit operations)
|
||||
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format {
|
||||
#if (USE_ACCEL_TEXTURE_POOL == 1)
|
||||
ATexturePoolHandle* texHandle = ATexturePool_getTexture(_accelTexturePool, width, height, format);
|
||||
CHECK_NULL_RETURN(texHandle, NULL);
|
||||
return [[[MTLPooledTextureHandle alloc] initWithTextureHandle:texHandle] autorelease];
|
||||
#else
|
||||
const int reqWidth = width;
|
||||
const int reqHeight = height;
|
||||
|
||||
int cellX0 = width >> CELL_WIDTH_BITS;
|
||||
int cellY0 = height >> CELL_HEIGHT_BITS;
|
||||
|
||||
if (USE_CEIL_SIZE) {
|
||||
// use upper cell size to maximize cache hits:
|
||||
const int remX0 = width & CELL_WIDTH_MASK;
|
||||
const int remY0 = height & CELL_HEIGHT_MASK;
|
||||
|
||||
if (remX0 != 0) {
|
||||
cellX0++;
|
||||
}
|
||||
if (remY0 != 0) {
|
||||
cellY0++;
|
||||
}
|
||||
// adjust width / height to cell upper boundaries:
|
||||
width = (cellX0) << CELL_WIDTH_BITS;
|
||||
height = (cellY0) << CELL_HEIGHT_BITS;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "MTLTexturePool_getTexture: fixed tex size: (%d %d) => (%d %d)",
|
||||
reqWidth, reqHeight, width, height);
|
||||
}
|
||||
|
||||
// 1. clean pool if necessary
|
||||
const int requestedPixels = width * height;
|
||||
const int requestedBytes = requestedPixels * MTLTexturePool_bytesPerPixel(format);
|
||||
const uint64_t neededMemoryAllocated = _memoryAllocated + requestedBytes;
|
||||
|
||||
if (neededMemoryAllocated > _maxPoolMemory) {
|
||||
// release all free textures
|
||||
[self cleanIfNecessary:0];
|
||||
} else {
|
||||
time_t now = time(NULL);
|
||||
// ensure 1s at least:
|
||||
if ((now - _lastGC) > 0) {
|
||||
_lastGC = now;
|
||||
if (neededMemoryAllocated > _maxPoolMemory / 2) {
|
||||
// release only old free textures
|
||||
[self cleanIfNecessary:MAX_POOL_ITEM_LIFETIME_SEC];
|
||||
} else if (FORCE_GC && _enableGC) {
|
||||
if ((now - _lastFullGC) > FORCE_GC_INTERVAL_SEC) {
|
||||
_lastFullGC = now;
|
||||
_lastYoungGC = now;
|
||||
// release only old free textures since last full-gc
|
||||
[self cleanIfNecessary:FORCE_GC_INTERVAL_SEC];
|
||||
} else if ((now - _lastYoungGC) > YOUNG_GC_INTERVAL_SEC) {
|
||||
_lastYoungGC = now;
|
||||
// release only not reused and old textures
|
||||
[self cleanIfNecessary:YOUNG_GC_LIFETIME_SEC];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. find free item
|
||||
const int cellX1 = cellX0 + 1;
|
||||
const int cellY1 = cellY0 + 1;
|
||||
|
||||
// Note: this code (test + resizing) is not thread-safe:
|
||||
if (cellX1 > _poolCellWidth || cellY1 > _poolCellHeight) {
|
||||
const int newCellWidth = cellX1 <= _poolCellWidth ? _poolCellWidth : cellX1;
|
||||
const int newCellHeight = cellY1 <= _poolCellHeight ? _poolCellHeight : cellY1;
|
||||
const int newCellsCount = newCellWidth * newCellHeight;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLTexturePool_getTexture: resize: %d -> %d",
|
||||
_poolCellWidth * _poolCellHeight, newCellsCount);
|
||||
|
||||
void **newcells = malloc(newCellsCount * sizeof(void*));
|
||||
CHECK_NULL_LOG_RETURN(newcells, NULL, "MTLTexturePool_getTexture: could not allocate newCells");
|
||||
|
||||
const size_t strideBytes = _poolCellWidth * sizeof(void*);
|
||||
for (int cy = 0; cy < _poolCellHeight; ++cy) {
|
||||
void **dst = newcells + cy * newCellWidth;
|
||||
void **src = _cells + cy * _poolCellWidth;
|
||||
memcpy(dst, src, strideBytes);
|
||||
if (newCellWidth > _poolCellWidth)
|
||||
memset(dst + _poolCellWidth, 0, (newCellWidth - _poolCellWidth) * sizeof(void*));
|
||||
}
|
||||
if (newCellHeight > _poolCellHeight) {
|
||||
void **dst = newcells + _poolCellHeight * newCellWidth;
|
||||
memset(dst, 0, (newCellHeight - _poolCellHeight) * newCellWidth * sizeof(void*));
|
||||
}
|
||||
free(_cells);
|
||||
_cells = newcells;
|
||||
_poolCellWidth = newCellWidth;
|
||||
_poolCellHeight = newCellHeight;
|
||||
}
|
||||
|
||||
MTLTexturePoolItem *minDeltaTpi = nil;
|
||||
int minDeltaArea = -1;
|
||||
for (int cy = cellY0; cy < cellY1; ++cy) {
|
||||
for (int cx = cellX0; cx < cellX1; ++cx) {
|
||||
MTLPoolCell * cell = _cells[cy * _poolCellWidth + cx];
|
||||
if (cell != NULL) {
|
||||
MTLTexturePoolItem* tpi = [cell occupyCellItem:width height:height format:format];
|
||||
if (!tpi) {
|
||||
continue;
|
||||
}
|
||||
const int deltaArea = (const int) (tpi.width * tpi.height - requestedPixels);
|
||||
if (minDeltaArea < 0 || deltaArea < minDeltaArea) {
|
||||
minDeltaArea = deltaArea;
|
||||
minDeltaTpi = tpi;
|
||||
if (deltaArea == 0) {
|
||||
// found exact match in current cell
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minDeltaTpi != nil) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (minDeltaTpi == NULL) {
|
||||
MTLPoolCell* cell = _cells[cellY0 * _poolCellWidth + cellX0];
|
||||
if (cell == NULL) {
|
||||
cell = [[MTLPoolCell alloc] init:self];
|
||||
_cells[cellY0 * _poolCellWidth + cellX0] = cell;
|
||||
}
|
||||
// use device to allocate NEW texture:
|
||||
id <MTLTexture> tex = MTLTexturePool_createTexture(device, width, height, format);
|
||||
|
||||
minDeltaTpi = [[[MTLTexturePoolItem alloc] initWithTexture:tex cell:cell
|
||||
width:width height:height format:format] autorelease];
|
||||
[cell addOccupiedItem: minDeltaTpi];
|
||||
|
||||
_memoryAllocated += requestedBytes;
|
||||
_memoryTotalAllocated += requestedBytes;
|
||||
|
||||
J2dTraceLn6(J2D_TRACE_VERBOSE, "MTLTexturePool_getTexture: created pool item: tex=%p, w=%d h=%d, pf=%d | allocated memory = %lld Kb (allocs: %d)",
|
||||
minDeltaTpi.texture, width, height, format, _memoryAllocated / UNIT_KB, allocatedCount);
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn6(J2D_TRACE_VERBOSE, "MTLTexturePool_getTexture: created pool item: tex=%p, w=%d h=%d, pf=%d | allocated memory = %lld Kb (allocs: %d)",
|
||||
minDeltaTpi.texture, width, height, format, _memoryAllocated / UNIT_KB, allocatedCount);
|
||||
} else {
|
||||
self.cacheHits++;
|
||||
minDeltaTpi.reuseCount++;
|
||||
if (TRACE_REUSE) {
|
||||
J2dRlsTraceLn5(J2D_TRACE_VERBOSE, "MTLTexturePool_getTexture: reused pool item: tex=%p, w=%d h=%d, pf=%d - reuse=%d",
|
||||
minDeltaTpi.texture, width, height, format, minDeltaTpi.reuseCount);
|
||||
}
|
||||
}
|
||||
self.totalHits++;
|
||||
minDeltaTpi.lastUsed = time(NULL);
|
||||
return [[[MTLPooledTextureHandle alloc] initWithPoolItem:minDeltaTpi.texture
|
||||
poolItem:minDeltaTpi reqWidth:reqWidth reqHeight:reqHeight] autorelease];
|
||||
#endif
|
||||
}
|
||||
@end
|
||||
@@ -1,455 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, 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. 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.
|
||||
*/
|
||||
|
||||
#import "MTLTexturePool.h"
|
||||
#import "Trace.h"
|
||||
|
||||
#define SCREEN_MEMORY_SIZE_5K (5120*4096*4) //~84 mb
|
||||
#define MAX_POOL_ITEM_LIFETIME_SEC 30
|
||||
|
||||
#define CELL_WIDTH_BITS 5 // ~ 32 pixel
|
||||
#define CELL_HEIGHT_BITS 5 // ~ 32 pixel
|
||||
|
||||
@implementation MTLTexturePoolItem
|
||||
|
||||
@synthesize texture, isBusy, lastUsed, isMultiSample, next, cell;
|
||||
|
||||
- (id) initWithTexture:(id<MTLTexture>)tex cell:(MTLPoolCell*)c{
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
self.texture = tex;
|
||||
isBusy = NO;
|
||||
self.next = nil;
|
||||
self.prev = nil;
|
||||
self.cell = c;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
[texture release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTLPooledTextureHandle
|
||||
{
|
||||
MTLRegion _rect;
|
||||
id<MTLTexture> _texture;
|
||||
MTLTexturePoolItem * _poolItem;
|
||||
}
|
||||
@synthesize texture = _texture, rect = _rect;
|
||||
|
||||
- (id) initWithPoolItem:(id<MTLTexture>)texture rect:(MTLRegion)rectangle poolItem:(MTLTexturePoolItem *)poolItem {
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
_rect = rectangle;
|
||||
_texture = texture;
|
||||
_poolItem = poolItem;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) releaseTexture {
|
||||
[_poolItem.cell releaseItem:_poolItem];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTLPoolCell {
|
||||
NSLock* _lock;
|
||||
}
|
||||
@synthesize available, availableTail, occupied;
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.available = nil;
|
||||
self.availableTail = nil;
|
||||
self.occupied = nil;
|
||||
_lock = [[NSLock alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)occupyItem:(MTLTexturePoolItem *)item {
|
||||
if (item.isBusy) return;
|
||||
[item retain];
|
||||
if (item.prev == nil) {
|
||||
self.available = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = nil;
|
||||
} else {
|
||||
self.availableTail = item.prev;
|
||||
}
|
||||
} else {
|
||||
item.prev.next = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = item.prev;
|
||||
} else {
|
||||
self.availableTail = item.prev;
|
||||
}
|
||||
item.prev = nil;
|
||||
}
|
||||
if (occupied) occupied.prev = item;
|
||||
item.next = occupied;
|
||||
self.occupied = item;
|
||||
[item release];
|
||||
item.isBusy = YES;
|
||||
}
|
||||
|
||||
- (void)releaseItem:(MTLTexturePoolItem *)item {
|
||||
[_lock lock];
|
||||
@try {
|
||||
if (!item.isBusy) return;
|
||||
[item retain];
|
||||
if (item.prev == nil) {
|
||||
self.occupied = item.next;
|
||||
if (item.next) item.next.prev = nil;
|
||||
} else {
|
||||
item.prev.next = item.next;
|
||||
if (item.next) item.next.prev = item.prev;
|
||||
item.prev = nil;
|
||||
}
|
||||
if (self.available) {
|
||||
self.available.prev = item;
|
||||
} else {
|
||||
self.availableTail = item;
|
||||
}
|
||||
item.next = self.available;
|
||||
self.available = item;
|
||||
item.isBusy = NO;
|
||||
[item release];
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addOccupiedItem:(MTLTexturePoolItem *)item {
|
||||
if (self.occupied) self.occupied.prev = item;
|
||||
item.next = self.occupied;
|
||||
item.isBusy = YES;
|
||||
self.occupied = item;
|
||||
}
|
||||
|
||||
- (void)removeAvailableItem:(MTLTexturePoolItem*)item {
|
||||
[item retain];
|
||||
if (item.prev == nil) {
|
||||
self.available = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = nil;
|
||||
item.next = nil;
|
||||
} else {
|
||||
self.availableTail = item.prev;
|
||||
}
|
||||
} else {
|
||||
item.prev.next = item.next;
|
||||
if (item.next) {
|
||||
item.next.prev = item.prev;
|
||||
item.next = nil;
|
||||
} else {
|
||||
self.availableTail = item.prev;
|
||||
}
|
||||
}
|
||||
[item release];
|
||||
}
|
||||
|
||||
- (void)removeAllItems {
|
||||
MTLTexturePoolItem *cur = self.available;
|
||||
while (cur != nil) {
|
||||
cur = cur.next;
|
||||
self.available = cur;
|
||||
}
|
||||
cur = self.occupied;
|
||||
while (cur != nil) {
|
||||
cur = cur.next;
|
||||
self.occupied = cur;
|
||||
}
|
||||
self.availableTail = nil;
|
||||
}
|
||||
|
||||
- (MTLTexturePoolItem *)createItem:(id<MTLDevice>)dev
|
||||
width:(int)width
|
||||
height:(int)height
|
||||
format:(MTLPixelFormat)format
|
||||
isMultiSample:(bool)isMultiSample
|
||||
{
|
||||
MTLTextureDescriptor *textureDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
|
||||
width:(NSUInteger) width
|
||||
height:(NSUInteger) height
|
||||
mipmapped:NO];
|
||||
textureDescriptor.usage = MTLTextureUsageRenderTarget |
|
||||
MTLTextureUsageShaderRead;
|
||||
if (isMultiSample) {
|
||||
textureDescriptor.textureType = MTLTextureType2DMultisample;
|
||||
textureDescriptor.sampleCount = MTLAASampleCount;
|
||||
textureDescriptor.storageMode = MTLStorageModePrivate;
|
||||
}
|
||||
|
||||
id <MTLTexture> tex = (id <MTLTexture>) [[dev newTextureWithDescriptor:textureDescriptor] autorelease];
|
||||
MTLTexturePoolItem* item = [[[MTLTexturePoolItem alloc] initWithTexture:tex cell:self] autorelease];
|
||||
item.isMultiSample = isMultiSample;
|
||||
[_lock lock];
|
||||
@try {
|
||||
[self addOccupiedItem:item];
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
- (NSUInteger)cleanIfBefore:(time_t)lastUsedTimeToRemove {
|
||||
NSUInteger deallocMem = 0;
|
||||
[_lock lock];
|
||||
MTLTexturePoolItem *cur = availableTail;
|
||||
@try {
|
||||
while (cur != nil) {
|
||||
MTLTexturePoolItem *prev = cur.prev;
|
||||
if (lastUsedTimeToRemove <= 0 ||
|
||||
cur.lastUsed < lastUsedTimeToRemove) {
|
||||
#ifdef DEBUG
|
||||
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE,
|
||||
"MTLTexturePool: remove pool item: tex=%p, w=%d h=%d, elapsed=%d",
|
||||
cur.texture, cur.texture.width, cur.texture.height,
|
||||
time(NULL) - cur.lastUsed);
|
||||
#endif //DEBUG
|
||||
deallocMem += cur.texture.width * cur.texture.height * 4;
|
||||
[self removeAvailableItem:cur];
|
||||
} else {
|
||||
if (lastUsedTimeToRemove > 0) break;
|
||||
}
|
||||
cur = prev;
|
||||
}
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
return deallocMem;
|
||||
}
|
||||
|
||||
- (MTLTexturePoolItem *)occupyItem:(int)width height:(int)height format:(MTLPixelFormat)format
|
||||
isMultiSample:(bool)isMultiSample {
|
||||
int minDeltaArea = -1;
|
||||
const int requestedPixels = width*height;
|
||||
MTLTexturePoolItem *minDeltaTpi = nil;
|
||||
[_lock lock];
|
||||
@try {
|
||||
for (MTLTexturePoolItem *cur = available; cur != nil; cur = cur.next) {
|
||||
if (cur.texture.pixelFormat != format
|
||||
|| cur.isMultiSample != isMultiSample) { // TODO: use swizzle when formats are not equal
|
||||
continue;
|
||||
}
|
||||
if (cur.texture.width < width || cur.texture.height < height) {
|
||||
continue;
|
||||
}
|
||||
const int deltaArea = (const int) (cur.texture.width * cur.texture.height - requestedPixels);
|
||||
if (minDeltaArea < 0 || deltaArea < minDeltaArea) {
|
||||
minDeltaArea = deltaArea;
|
||||
minDeltaTpi = cur;
|
||||
if (deltaArea == 0) {
|
||||
// found exact match in current cell
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minDeltaTpi) {
|
||||
[self occupyItem:minDeltaTpi];
|
||||
}
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
return minDeltaTpi;
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
[_lock lock];
|
||||
@try {
|
||||
[self removeAllItems];
|
||||
} @finally {
|
||||
[_lock unlock];
|
||||
}
|
||||
[_lock release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTLTexturePool {
|
||||
int _memoryTotalAllocated;
|
||||
|
||||
void ** _cells;
|
||||
int _poolCellWidth;
|
||||
int _poolCellHeight;
|
||||
uint64_t _maxPoolMemory;
|
||||
}
|
||||
|
||||
@synthesize device;
|
||||
|
||||
- (id) initWithDevice:(id<MTLDevice>)dev {
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
_memoryTotalAllocated = 0;
|
||||
_poolCellWidth = 10;
|
||||
_poolCellHeight = 10;
|
||||
const int cellsCount = _poolCellWidth * _poolCellHeight;
|
||||
_cells = (void **)malloc(cellsCount * sizeof(void*));
|
||||
memset(_cells, 0, cellsCount * sizeof(void*));
|
||||
self.device = dev;
|
||||
|
||||
// recommendedMaxWorkingSetSize typically greatly exceeds SCREEN_MEMORY_SIZE_5K constant.
|
||||
// It usually corresponds to the VRAM available to the graphics card
|
||||
_maxPoolMemory = self.device.recommendedMaxWorkingSetSize/2;
|
||||
|
||||
// Set maximum to handle at least 5K screen size
|
||||
if (_maxPoolMemory < SCREEN_MEMORY_SIZE_5K) {
|
||||
_maxPoolMemory = SCREEN_MEMORY_SIZE_5K;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
for (int c = 0; c < _poolCellWidth * _poolCellHeight; ++c) {
|
||||
MTLPoolCell * cell = _cells[c];
|
||||
if (cell != NULL) {
|
||||
[cell release];
|
||||
}
|
||||
}
|
||||
free(_cells);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// NOTE: called from RQ-thread (on blit operations)
|
||||
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format {
|
||||
return [self getTexture:width height:height format:format isMultiSample:NO];
|
||||
}
|
||||
|
||||
// NOTE: called from RQ-thread (on blit operations)
|
||||
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format
|
||||
isMultiSample:(bool)isMultiSample {
|
||||
// 1. clean pool if necessary
|
||||
const int requestedPixels = width*height;
|
||||
const int requestedBytes = requestedPixels*4;
|
||||
if (_memoryTotalAllocated + requestedBytes > _maxPoolMemory) {
|
||||
[self cleanIfNecessary:0]; // release all free textures
|
||||
} else if (_memoryTotalAllocated + requestedBytes > _maxPoolMemory/2) {
|
||||
[self cleanIfNecessary:MAX_POOL_ITEM_LIFETIME_SEC]; // release only old free textures
|
||||
}
|
||||
|
||||
// 2. find free item
|
||||
const int cellX0 = width >> CELL_WIDTH_BITS;
|
||||
const int cellY0 = height >> CELL_HEIGHT_BITS;
|
||||
const int cellX1 = cellX0 + 1;
|
||||
const int cellY1 = cellY0 + 1;
|
||||
if (cellX1 > _poolCellWidth || cellY1 > _poolCellHeight) {
|
||||
const int newCellWidth = cellX1 <= _poolCellWidth ? _poolCellWidth : cellX1;
|
||||
const int newCellHeight = cellY1 <= _poolCellHeight ? _poolCellHeight : cellY1;
|
||||
const int newCellsCount = newCellWidth*newCellHeight;
|
||||
#ifdef DEBUG
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE, "MTLTexturePool: resize: %d -> %d", _poolCellWidth * _poolCellHeight, newCellsCount);
|
||||
#endif
|
||||
void ** newcells = malloc(newCellsCount*sizeof(void*));
|
||||
const int strideBytes = _poolCellWidth * sizeof(void*);
|
||||
for (int cy = 0; cy < _poolCellHeight; ++cy) {
|
||||
void ** dst = newcells + cy*newCellWidth;
|
||||
void ** src = _cells + cy * _poolCellWidth;
|
||||
memcpy(dst, src, strideBytes);
|
||||
if (newCellWidth > _poolCellWidth)
|
||||
memset(dst + _poolCellWidth, 0, (newCellWidth - _poolCellWidth) * sizeof(void*));
|
||||
}
|
||||
if (newCellHeight > _poolCellHeight) {
|
||||
void ** dst = newcells + _poolCellHeight * newCellWidth;
|
||||
memset(dst, 0, (newCellHeight - _poolCellHeight) * newCellWidth * sizeof(void*));
|
||||
}
|
||||
free(_cells);
|
||||
_cells = newcells;
|
||||
_poolCellWidth = newCellWidth;
|
||||
_poolCellHeight = newCellHeight;
|
||||
}
|
||||
|
||||
MTLTexturePoolItem * minDeltaTpi = nil;
|
||||
int minDeltaArea = -1;
|
||||
for (int cy = cellY0; cy < cellY1; ++cy) {
|
||||
for (int cx = cellX0; cx < cellX1; ++cx) {
|
||||
MTLPoolCell * cell = _cells[cy * _poolCellWidth + cx];
|
||||
if (cell != NULL) {
|
||||
MTLTexturePoolItem* tpi = [cell occupyItem:width height:height
|
||||
format:format isMultiSample:isMultiSample];
|
||||
if (!tpi) continue;
|
||||
const int deltaArea = (const int) (tpi.texture.width * tpi.texture.height - requestedPixels);
|
||||
if (minDeltaArea < 0 || deltaArea < minDeltaArea) {
|
||||
minDeltaArea = deltaArea;
|
||||
minDeltaTpi = tpi;
|
||||
if (deltaArea == 0) {
|
||||
// found exact match in current cell
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minDeltaTpi != nil) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (minDeltaTpi == NULL) {
|
||||
MTLPoolCell* cell = _cells[cellY0 * _poolCellWidth + cellX0];
|
||||
if (cell == NULL) {
|
||||
cell = [[MTLPoolCell alloc] init];
|
||||
_cells[cellY0 * _poolCellWidth + cellX0] = cell;
|
||||
}
|
||||
minDeltaTpi = [cell createItem:device width:width height:height format:format isMultiSample:isMultiSample];
|
||||
_memoryTotalAllocated += requestedBytes;
|
||||
J2dTraceLn5(J2D_TRACE_VERBOSE, "MTLTexturePool: created pool item: tex=%p, w=%d h=%d, pf=%d | total memory = %d Kb", minDeltaTpi.texture, width, height, format, _memoryTotalAllocated/1024);
|
||||
}
|
||||
|
||||
minDeltaTpi.isBusy = YES;
|
||||
minDeltaTpi.lastUsed = time(NULL);
|
||||
return [[[MTLPooledTextureHandle alloc] initWithPoolItem:minDeltaTpi.texture
|
||||
rect:MTLRegionMake2D(0, 0,
|
||||
minDeltaTpi.texture.width,
|
||||
minDeltaTpi.texture.height)
|
||||
poolItem:minDeltaTpi] autorelease];
|
||||
}
|
||||
|
||||
- (void) cleanIfNecessary:(int)lastUsedTimeThreshold {
|
||||
time_t lastUsedTimeToRemove =
|
||||
lastUsedTimeThreshold > 0 ?
|
||||
time(NULL) - lastUsedTimeThreshold :
|
||||
lastUsedTimeThreshold;
|
||||
for (int cy = 0; cy < _poolCellHeight; ++cy) {
|
||||
for (int cx = 0; cx < _poolCellWidth; ++cx) {
|
||||
MTLPoolCell * cell = _cells[cy * _poolCellWidth + cx];
|
||||
if (cell != NULL) {
|
||||
_memoryTotalAllocated -= [cell cleanIfBefore:lastUsedTimeToRemove];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2024 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 com.jetbrains.desktop;
|
||||
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.event.KeyEventProcessing;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation for platform-agnostic parts of JBR keyboard API
|
||||
*/
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("Keyboard")
|
||||
public class JBRKeyboard {
|
||||
/** (Integer) Java key code as if the keyboard was a US QWERTY one */
|
||||
public static final String US_KEYCODE = "US_KEYCODE";
|
||||
|
||||
/** (Integer) VK_DEAD_* keycode for the base key, or VK_UNDEFINED if the base key is not dead */
|
||||
public static final String DEAD_KEYCODE = "DEAD_KEYCODE";
|
||||
|
||||
/** (Integer) VK_DEAD_* keycode for the key with modifiers, or VK_UNDEFINED if the key with modifiers is not dead */
|
||||
public static final String DEAD_KEYSTROKE = "DEAD_KEYSTROKE";
|
||||
|
||||
/** (String) The characters that this specific event has generated as a sequence of KEY_TYPED events */
|
||||
public static final String CHARACTERS = "CHARACTERS";
|
||||
|
||||
/** (Integer) Raw platform-dependent keycode for the specific key on the keyboard */
|
||||
public static final String RAW_KEYCODE = "RAW_KEYCODE";
|
||||
|
||||
private static JBRKeyboard create() {
|
||||
try {
|
||||
var implMacOS = Class.forName("sun.lwawt.macosx.JBRKeyboardMacOS");
|
||||
var instance = implMacOS.getDeclaredConstructor().newInstance();
|
||||
return (JBRKeyboard)instance;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return new JBRKeyboard();
|
||||
} catch (InvocationTargetException | IllegalAccessException | InstantiationException | NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object getKeyEventProperty(KeyEvent event, String name) {
|
||||
Map<String, Object> properties = AWTAccessor.getKeyEventAccessor().getJBRExtraProperties(event);
|
||||
return (properties == null) ? null : properties.get(name);
|
||||
}
|
||||
|
||||
public int getKeyEventUSKeyCode(KeyEvent event) {
|
||||
if (event.getID() == KeyEvent.KEY_PRESSED || event.getID() == KeyEvent.KEY_RELEASED) {
|
||||
var prop = getKeyEventProperty(event, US_KEYCODE);
|
||||
if (!(prop instanceof Integer)) {
|
||||
throw new UnsupportedOperationException("US_KEYCODE property is invalid");
|
||||
}
|
||||
return (Integer)prop;
|
||||
} else {
|
||||
throw new IllegalArgumentException("event is not KEY_PRESSED or KEY_RELEASED");
|
||||
}
|
||||
}
|
||||
|
||||
public int getKeyEventDeadKeyCode(KeyEvent event) {
|
||||
if (event.getID() == KeyEvent.KEY_PRESSED || event.getID() == KeyEvent.KEY_RELEASED) {
|
||||
var prop = getKeyEventProperty(event, DEAD_KEYCODE);
|
||||
if (!(prop instanceof Integer)) {
|
||||
throw new UnsupportedOperationException("DEAD_KEYCODE property is invalid");
|
||||
}
|
||||
return (Integer)prop;
|
||||
} else {
|
||||
throw new IllegalArgumentException("event is not KEY_PRESSED or KEY_RELEASED");
|
||||
}
|
||||
}
|
||||
|
||||
public int getKeyEventDeadKeyStroke(KeyEvent event) {
|
||||
if (event.getID() == KeyEvent.KEY_PRESSED || event.getID() == KeyEvent.KEY_RELEASED) {
|
||||
var prop = getKeyEventProperty(event, DEAD_KEYSTROKE);
|
||||
if (!(prop instanceof Integer)) {
|
||||
throw new UnsupportedOperationException("DEAD_KEYSTROKE property is invalid");
|
||||
}
|
||||
return (Integer)prop;
|
||||
} else {
|
||||
throw new IllegalArgumentException("event is not KEY_PRESSED or KEY_RELEASED");
|
||||
}
|
||||
}
|
||||
|
||||
public String getKeyEventCharacters(KeyEvent event) {
|
||||
if (event.getID() == KeyEvent.KEY_RELEASED) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (event.getID() == KeyEvent.KEY_TYPED) {
|
||||
return String.valueOf(event.getKeyChar());
|
||||
}
|
||||
|
||||
if (event.getID() == KeyEvent.KEY_PRESSED) {
|
||||
var prop = getKeyEventProperty(event, CHARACTERS);
|
||||
if (!(prop instanceof String)) {
|
||||
throw new UnsupportedOperationException("CHARACTERS property is invalid");
|
||||
}
|
||||
return (String)prop;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("event with unknown ID");
|
||||
}
|
||||
|
||||
public String getCurrentKeyboardLayout() {
|
||||
throw new UnsupportedOperationException("getCurrentKeyboardLayout() not implemented for this platform");
|
||||
}
|
||||
|
||||
public List<String> getEnabledKeyboardLayouts() {
|
||||
throw new UnsupportedOperationException("getEnabledKeyboardLayouts() not implemented for this platform");
|
||||
}
|
||||
|
||||
public void setReportNationalKeyCodes(boolean value) {
|
||||
EventQueue.invokeLater(() -> {
|
||||
KeyEventProcessing.useNationalLayouts = value;
|
||||
});
|
||||
}
|
||||
|
||||
void setConvertDeadKeyCodesToNormal(boolean value) {
|
||||
EventQueue.invokeLater(() -> {
|
||||
KeyEventProcessing.reportDeadKeysAsNormal = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4876,6 +4876,9 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
eventLog.finest("{0}", e);
|
||||
}
|
||||
|
||||
if (id == MouseEvent.MOUSE_ENTERED && getToolkit() instanceof SunToolkit toolkit) {
|
||||
toolkit.updateLastMouseEventComponent(this);
|
||||
}
|
||||
/*
|
||||
* 0. Set timestamp and modifiers of current event.
|
||||
*/
|
||||
@@ -7157,6 +7160,12 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
setGlobalPermanentFocusOwner(null);
|
||||
}
|
||||
|
||||
if (getToolkit() instanceof SunToolkit toolkit) {
|
||||
if (toolkit.getLastMouseEventComponent() == this) {
|
||||
toolkit.updateLastMouseEventComponent(null);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (getTreeLock()) {
|
||||
if (isFocusOwner() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) {
|
||||
transferFocus(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, 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
|
||||
@@ -23,7 +23,6 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.awt;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -38,7 +37,6 @@ import sun.font.FontManager;
|
||||
import sun.font.FontManagerFactory;
|
||||
import sun.java2d.HeadlessGraphicsEnvironment;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.awt.Toolkit;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serial;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
|
||||
@@ -1182,6 +1184,9 @@ public non-sealed class KeyEvent extends InputEvent {
|
||||
private transient long scancode = 0; // for MS Windows only
|
||||
private transient long extendedKeyCode = 0;
|
||||
|
||||
// JBR-specific additional options
|
||||
private transient Map<String, Object> jbrExtraProperties;
|
||||
|
||||
/**
|
||||
* Use serialVersionUID from JDK 1.1 for interoperability.
|
||||
*/
|
||||
@@ -1219,6 +1224,16 @@ public non-sealed class KeyEvent extends InputEvent {
|
||||
public boolean isProxyActive(KeyEvent ev) {
|
||||
return ev.isProxyActive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getJBRExtraProperties(KeyEvent ev) {
|
||||
return ev.jbrExtraProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJBRExtraProperties(KeyEvent ev, Map<String, Object> properties) {
|
||||
ev.jbrExtraProperties = properties;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.security.AccessControlContext;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Vector;
|
||||
import java.util.function.BooleanSupplier;
|
||||
@@ -745,6 +746,16 @@ public final class AWTAccessor {
|
||||
* Gets isProxyActive field for KeyEvent
|
||||
*/
|
||||
boolean isProxyActive(KeyEvent ev);
|
||||
|
||||
/**
|
||||
* Returns the JBR-specific property map
|
||||
*/
|
||||
Map<String, Object> getJBRExtraProperties(KeyEvent ev);
|
||||
|
||||
/**
|
||||
* Overwrites the JBR-specific property map
|
||||
*/
|
||||
void setJBRExtraProperties(KeyEvent ev, Map<String, Object> properties);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
131
src/java.desktop/share/classes/sun/awt/CachedCursorManager.java
Normal file
131
src/java.desktop/share/classes/sun/awt/CachedCursorManager.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 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.awt;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Point;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public abstract class CachedCursorManager {
|
||||
|
||||
/**
|
||||
* A flag to indicate if the update is scheduled, so we don't process it
|
||||
* twice.
|
||||
*/
|
||||
private final AtomicBoolean updatePending = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Sets the cursor to correspond the component currently under mouse.
|
||||
*
|
||||
* This method should not be executed on the toolkit thread as it
|
||||
* calls to user code (e.g. Container.findComponentAt).
|
||||
*/
|
||||
public final void updateCursor() {
|
||||
updatePending.set(false);
|
||||
updateCursorImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules updating the cursor on the corresponding event dispatch
|
||||
* thread for the given window.
|
||||
*
|
||||
* This method is called on the toolkit thread as a result of a
|
||||
* native update cursor request (e.g. WM_SETCURSOR on Windows).
|
||||
*/
|
||||
public final void updateCursorLater(final Component window) {
|
||||
if (updatePending.compareAndSet(false, true)) {
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateCursor();
|
||||
}
|
||||
};
|
||||
SunToolkit.executeOnEventHandlerThread(window, r);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Cursor getCursorByPosition(final Point cursorPos, Component c);
|
||||
|
||||
private void updateCursorImpl() {
|
||||
final Point cursorPos = getCursorPosition();
|
||||
final Component c = findComponent(cursorPos);
|
||||
Cursor cursor = getCursorByPosition(cursorPos, c);
|
||||
|
||||
if (cursor == null) {
|
||||
cursor = (c != null) ? c.getCursor() : null;
|
||||
}
|
||||
|
||||
if (cursor != null) {
|
||||
setCursor(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Component getComponentUnderCursor();
|
||||
protected abstract Point getLocationOnScreen(Component component);
|
||||
|
||||
/**
|
||||
* Returns the first visible, enabled and showing component under cursor.
|
||||
* Returns null for modal blocked windows.
|
||||
*
|
||||
* @param cursorPos Current cursor position.
|
||||
* @return Component or null.
|
||||
*/
|
||||
protected Component findComponent(final Point cursorPos) {
|
||||
Component component = getComponentUnderCursor();
|
||||
if (component != null) {
|
||||
if (component instanceof Container && component.isShowing()) {
|
||||
final Point p = getLocationOnScreen(component);
|
||||
component = AWTAccessor.getContainerAccessor().findComponentAt(
|
||||
(Container) component, cursorPos.x - p.x, cursorPos.y - p.y, false);
|
||||
|
||||
}
|
||||
while (component != null) {
|
||||
final Object p = AWTAccessor.getComponentAccessor().getPeer(component);
|
||||
if (component.isVisible() && component.isEnabled() && p != null) {
|
||||
break;
|
||||
}
|
||||
component = component.getParent();
|
||||
}
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current cursor position.
|
||||
*/
|
||||
public abstract Point getCursorPosition();
|
||||
|
||||
/**
|
||||
* Sets a cursor. The cursor can be null if the mouse is not over a Java
|
||||
* window.
|
||||
* @param cursor the new {@code Cursor}.
|
||||
*/
|
||||
protected abstract void setCursor(Cursor cursor);
|
||||
}
|
||||
@@ -236,6 +236,17 @@ public abstract class SunToolkit extends Toolkit
|
||||
AccessController.doPrivileged(new GetBooleanAction("awt.lock.fair")));
|
||||
private static final Condition AWT_LOCK_COND = AWT_LOCK.newCondition();
|
||||
|
||||
/*
|
||||
* A component where the last mouse event came to. Used by cursor manager to
|
||||
* find the component under cursor. Currently, uses only on Windows
|
||||
*/
|
||||
public void updateLastMouseEventComponent(Component component) {
|
||||
}
|
||||
|
||||
public Component getLastMouseEventComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public interface AwtLockListener {
|
||||
void afterAwtLocked();
|
||||
void beforeAwtUnlocked();
|
||||
|
||||
@@ -10,14 +10,14 @@ public class KeyEventProcessing {
|
||||
// "com.jetbrains.use.old.keyevent.processing"
|
||||
public final static String useNationalLayoutsOption = "com.sun.awt.use.national.layouts";
|
||||
@Native
|
||||
public final static boolean useNationalLayouts = "true".equals(
|
||||
public static volatile boolean useNationalLayouts = "true".equals(
|
||||
System.getProperty(useNationalLayoutsOption,
|
||||
FontUtilities.isMacOSX ? "true" : "false"));
|
||||
|
||||
// Report dead keys (such as VK_DEAD_GRAVE) as normal keys (such as VK_BACK_QUOTE)
|
||||
public final static String reportDeadKeysAsNormalOption = "com.sun.awt.reportDeadKeysAsNormal";
|
||||
@Native
|
||||
public final static boolean reportDeadKeysAsNormal = "true".equals(
|
||||
public static boolean reportDeadKeysAsNormal = "true".equals(
|
||||
System.getProperty(reportDeadKeysAsNormalOption,
|
||||
FontUtilities.isMacOSX ? "true" : "false"));
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ public final class BufferedOpCodes {
|
||||
@Native public static final int INVALIDATE_CONTEXT = 75;
|
||||
@Native public static final int SYNC = 76;
|
||||
@Native public static final int RESTORE_DEVICES = 77;
|
||||
@Native public static final int CONFIGURE_SURFACE = 78;
|
||||
|
||||
// multibuffering ops
|
||||
@Native public static final int SWAP_BUFFERS = 80;
|
||||
|
||||
@@ -110,9 +110,9 @@ public abstract class VKSurfaceData extends SurfaceData
|
||||
}
|
||||
}
|
||||
|
||||
protected final int scale;
|
||||
protected final int width;
|
||||
protected final int height;
|
||||
protected int 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
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in flat vec4 fragColor;
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = fragColor;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec4 fragColor;
|
||||
} pushConstants;
|
||||
|
||||
const vec2 positions[4] = vec2[4](
|
||||
vec2(-1.0, -1.0),
|
||||
vec2( 1.0, -1.0),
|
||||
vec2(-1.0, 1.0),
|
||||
vec2( 1.0, 1.0)
|
||||
);
|
||||
|
||||
layout(location = 0) out flat vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
fragColor = pushConstants.fragColor;
|
||||
}
|
||||
829
src/java.desktop/share/native/common/java2d/AccelTexturePool.c
Normal file
829
src/java.desktop/share/native/common/java2d/AccelTexturePool.c
Normal file
@@ -0,0 +1,829 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "AccelTexturePool.h"
|
||||
#include "jni.h"
|
||||
#include "Trace.h"
|
||||
|
||||
|
||||
#define USE_MAX_GPU_DEVICE_MEM 1
|
||||
#define MAX_GPU_DEVICE_MEM (512 * UNIT_MB)
|
||||
#define SCREEN_MEMORY_SIZE_5K (5120 * 4096 * 4) // ~ 84 mb
|
||||
|
||||
#define MAX_POOL_ITEM_LIFETIME_SEC 30
|
||||
|
||||
// 32 pixel
|
||||
#define CELL_WIDTH_BITS 5
|
||||
#define CELL_HEIGHT_BITS 5
|
||||
|
||||
#define CELL_WIDTH_MASK ((1 << CELL_WIDTH_BITS) - 1)
|
||||
#define CELL_HEIGHT_MASK ((1 << CELL_HEIGHT_BITS) - 1)
|
||||
|
||||
#define USE_CEIL_SIZE 1
|
||||
|
||||
#define FORCE_GC 1
|
||||
// force gc (prune old textures):
|
||||
#define FORCE_GC_INTERVAL_SEC (MAX_POOL_ITEM_LIFETIME_SEC * 10)
|
||||
|
||||
// force young gc every 5 seconds (prune only not reused textures):
|
||||
#define YOUNG_GC_INTERVAL_SEC 15
|
||||
#define YOUNG_GC_LIFETIME_SEC (FORCE_GC_INTERVAL_SEC * 2)
|
||||
|
||||
#define TRACE_GC 1
|
||||
#define TRACE_GC_ALIVE 0
|
||||
|
||||
#define TRACE_MEM_API 0
|
||||
#define TRACE_USE_API 0
|
||||
#define TRACE_REUSE 0
|
||||
|
||||
#define INIT_TEST 1
|
||||
#define INIT_TEST_STEP 1
|
||||
#define INIT_TEST_MAX 1024
|
||||
|
||||
#define LOCK_WRAPPER(cell) ((cell)->pool->lockWrapper)
|
||||
#define LOCK_WRAPPER_LOCK(cell) (LOCK_WRAPPER(cell)->lockFunc((cell)->lock))
|
||||
#define LOCK_WRAPPER_UNLOCK(cell) (LOCK_WRAPPER(cell)->unlockFunc((cell)->lock))
|
||||
|
||||
|
||||
/* Private definitions */
|
||||
struct ATexturePoolLockWrapper_ {
|
||||
ATexturePoolLock_init *initFunc;
|
||||
ATexturePoolLock_dispose *disposeFunc;
|
||||
ATexturePoolLock_lock *lockFunc;
|
||||
ATexturePoolLock_unlock *unlockFunc;
|
||||
};
|
||||
|
||||
struct ATexturePoolItem_ {
|
||||
ATexturePool_freeTexture *freeTextureFunc;
|
||||
ADevicePrivPtr *device;
|
||||
ATexturePrivPtr *texture;
|
||||
ATexturePoolCell *cell;
|
||||
ATexturePoolItem *prev;
|
||||
ATexturePoolItem *next;
|
||||
time_t lastUsed;
|
||||
jint width;
|
||||
jint height;
|
||||
jlong format;
|
||||
jint reuseCount;
|
||||
jboolean isBusy;
|
||||
};
|
||||
|
||||
struct ATexturePoolCell_ {
|
||||
ATexturePool *pool;
|
||||
ATexturePoolLockPrivPtr *lock;
|
||||
ATexturePoolItem *available;
|
||||
ATexturePoolItem *availableTail;
|
||||
ATexturePoolItem *occupied;
|
||||
};
|
||||
|
||||
static void ATexturePoolCell_releaseItem(ATexturePoolCell *cell, ATexturePoolItem *item);
|
||||
|
||||
struct ATexturePoolHandle_ {
|
||||
ATexturePrivPtr *texture;
|
||||
ATexturePoolItem *_poolItem;
|
||||
jint reqWidth;
|
||||
jint reqHeight;
|
||||
};
|
||||
|
||||
// NOTE: owns all texture objects
|
||||
struct ATexturePool_ {
|
||||
ATexturePool_createTexture *createTextureFunc;
|
||||
ATexturePool_freeTexture *freeTextureFunc;
|
||||
ATexturePool_bytesPerPixel *bytesPerPixelFunc;
|
||||
ATexturePoolLockWrapper *lockWrapper;
|
||||
ADevicePrivPtr *device;
|
||||
ATexturePoolCell **_cells;
|
||||
jint poolCellWidth;
|
||||
jint poolCellHeight;
|
||||
jlong maxPoolMemory;
|
||||
jlong memoryAllocated;
|
||||
jlong totalMemoryAllocated;
|
||||
jlong allocatedCount;
|
||||
jlong totalAllocatedCount;
|
||||
jlong cacheHits;
|
||||
jlong totalHits;
|
||||
time_t lastGC;
|
||||
time_t lastYoungGC;
|
||||
time_t lastFullGC;
|
||||
jboolean enableGC;
|
||||
};
|
||||
|
||||
|
||||
/* ATexturePoolLockWrapper API */
|
||||
ATexturePoolLockWrapper* ATexturePoolLockWrapper_init(ATexturePoolLock_init *initFunc,
|
||||
ATexturePoolLock_dispose *disposeFunc,
|
||||
ATexturePoolLock_lock *lockFunc,
|
||||
ATexturePoolLock_unlock *unlockFunc)
|
||||
{
|
||||
CHECK_NULL_LOG_RETURN(initFunc, NULL, "ATexturePoolLockWrapper_init: initFunc function is null !");
|
||||
CHECK_NULL_LOG_RETURN(disposeFunc, NULL, "ATexturePoolLockWrapper_init: disposeFunc function is null !");
|
||||
CHECK_NULL_LOG_RETURN(lockFunc, NULL, "ATexturePoolLockWrapper_init: lockFunc function is null !");
|
||||
CHECK_NULL_LOG_RETURN(unlockFunc, NULL, "ATexturePoolLockWrapper_init: unlockFunc function is null !");
|
||||
|
||||
ATexturePoolLockWrapper *lockWrapper = (ATexturePoolLockWrapper*)malloc(sizeof(ATexturePoolLockWrapper));
|
||||
CHECK_NULL_LOG_RETURN(lockWrapper, NULL, "ATexturePoolLockWrapper_init: could not allocate ATexturePoolLockWrapper");
|
||||
|
||||
lockWrapper->initFunc = initFunc;
|
||||
lockWrapper->disposeFunc = disposeFunc;
|
||||
lockWrapper->lockFunc = lockFunc;
|
||||
lockWrapper->unlockFunc = unlockFunc;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolLockWrapper_init: lockWrapper = %p", lockWrapper);
|
||||
return lockWrapper;
|
||||
}
|
||||
|
||||
void ATexturePoolLockWrapper_Dispose(ATexturePoolLockWrapper *lockWrapper) {
|
||||
CHECK_NULL(lockWrapper);
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolLockWrapper_Dispose: lockWrapper = %p", lockWrapper);
|
||||
|
||||
free(lockWrapper);
|
||||
}
|
||||
|
||||
|
||||
/* ATexturePoolItem API */
|
||||
static ATexturePoolItem* ATexturePoolItem_initWithTexture(ATexturePool_freeTexture *freeTextureFunc,
|
||||
ADevicePrivPtr *device,
|
||||
ATexturePrivPtr *texture,
|
||||
ATexturePoolCell *cell,
|
||||
jint width,
|
||||
jint height,
|
||||
jlong format)
|
||||
{
|
||||
CHECK_NULL_LOG_RETURN(freeTextureFunc, NULL, "ATexturePoolItem_initWithTexture: freeTextureFunc function is null !");
|
||||
CHECK_NULL_RETURN(texture, NULL);
|
||||
CHECK_NULL_RETURN(cell, NULL);
|
||||
|
||||
ATexturePoolItem *item = (ATexturePoolItem*)malloc(sizeof(ATexturePoolItem));
|
||||
CHECK_NULL_LOG_RETURN(item, NULL, "ATexturePoolItem_initWithTexture: could not allocate ATexturePoolItem");
|
||||
|
||||
item->freeTextureFunc = freeTextureFunc;
|
||||
item->device = device;
|
||||
item->texture = texture;
|
||||
item->cell = cell;
|
||||
item->prev = NULL;
|
||||
item->next = NULL;
|
||||
item->lastUsed = 0;
|
||||
item->width = width;
|
||||
item->height = height;
|
||||
item->format = format;
|
||||
item->reuseCount = 0;
|
||||
item->isBusy = JNI_FALSE;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolItem_initWithTexture: item = %p", item);
|
||||
return item;
|
||||
}
|
||||
|
||||
static void ATexturePoolItem_Dispose(ATexturePoolItem *item) {
|
||||
CHECK_NULL(item);
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn2(J2D_TRACE_INFO, "ATexturePoolItem_Dispose: item = %p - reuse: %4d", item, item->reuseCount);
|
||||
|
||||
// use texture (native API) to release allocated texture:
|
||||
item->freeTextureFunc(item->device, item->texture);
|
||||
free(item);
|
||||
}
|
||||
|
||||
/* Callback from metal pipeline => multi-thread (cell lock) */
|
||||
static void ATexturePoolItem_ReleaseItem(ATexturePoolItem *item) {
|
||||
CHECK_NULL(item);
|
||||
if (!item->isBusy) {
|
||||
return;
|
||||
}
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolItem_ReleaseItem: item = %p", item);
|
||||
|
||||
if IS_NOT_NULL(item->cell) {
|
||||
ATexturePoolCell_releaseItem(item->cell, item);
|
||||
} else {
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolItem_ReleaseItem: item = %p (detached)", item);
|
||||
// item marked as detached:
|
||||
ATexturePoolItem_Dispose(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ATexturePoolCell API */
|
||||
static ATexturePoolCell* ATexturePoolCell_init(ATexturePool *pool) {
|
||||
CHECK_NULL_RETURN(pool, NULL);
|
||||
|
||||
ATexturePoolCell *cell = (ATexturePoolCell*)malloc(sizeof(ATexturePoolCell));
|
||||
CHECK_NULL_LOG_RETURN(cell, NULL, "ATexturePoolCell_init: could not allocate ATexturePoolCell");
|
||||
|
||||
cell->pool = pool;
|
||||
|
||||
ATexturePoolLockPrivPtr* lock = LOCK_WRAPPER(cell)->initFunc();
|
||||
CHECK_NULL_LOG_RETURN(lock, NULL, "ATexturePoolCell_init: could not allocate ATexturePoolLockPrivPtr");
|
||||
|
||||
cell->lock = lock;
|
||||
cell->available = NULL;
|
||||
cell->availableTail = NULL;
|
||||
cell->occupied = NULL;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolCell_init: cell = %p", cell);
|
||||
return cell;
|
||||
}
|
||||
|
||||
static void ATexturePoolCell_removeAllItems(ATexturePoolCell *cell) {
|
||||
CHECK_NULL(cell);
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn(J2D_TRACE_INFO, "ATexturePoolCell_removeAllItems");
|
||||
|
||||
ATexturePoolItem *cur = cell->available;
|
||||
ATexturePoolItem *next = NULL;
|
||||
while IS_NOT_NULL(cur) {
|
||||
next = cur->next;
|
||||
ATexturePoolItem_Dispose(cur);
|
||||
cur = next;
|
||||
}
|
||||
cell->available = NULL;
|
||||
|
||||
cur = cell->occupied;
|
||||
next = NULL;
|
||||
while IS_NOT_NULL(cur) {
|
||||
next = cur->next;
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolCell_removeAllItems: occupied item = %p", cur);
|
||||
// Do not dispose (may leak) until ATexturePoolItem_Release() is called by handle:
|
||||
// mark item as detached:
|
||||
cur->cell = NULL;
|
||||
cur = next;
|
||||
}
|
||||
cell->occupied = NULL;
|
||||
cell->availableTail = NULL;
|
||||
}
|
||||
|
||||
static void ATexturePoolCell_removeAvailableItem(ATexturePoolCell *cell, ATexturePoolItem *item) {
|
||||
CHECK_NULL(cell);
|
||||
CHECK_NULL(item);
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolCell_removeAvailableItem: item = %p", item);
|
||||
|
||||
if IS_NULL(item->prev) {
|
||||
cell->available = item->next;
|
||||
if IS_NOT_NULL(item->next) {
|
||||
item->next->prev = NULL;
|
||||
item->next = NULL;
|
||||
} else {
|
||||
cell->availableTail = item->prev;
|
||||
}
|
||||
} else {
|
||||
item->prev->next = item->next;
|
||||
if IS_NOT_NULL(item->next) {
|
||||
item->next->prev = item->prev;
|
||||
item->next = NULL;
|
||||
} else {
|
||||
cell->availableTail = item->prev;
|
||||
}
|
||||
}
|
||||
ATexturePoolItem_Dispose(item);
|
||||
}
|
||||
|
||||
static void ATexturePoolCell_Dispose(ATexturePoolCell *cell) {
|
||||
CHECK_NULL(cell);
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolCell_Dispose: cell = %p", cell);
|
||||
|
||||
LOCK_WRAPPER_LOCK(cell);
|
||||
{
|
||||
ATexturePoolCell_removeAllItems(cell);
|
||||
}
|
||||
LOCK_WRAPPER_UNLOCK(cell);
|
||||
|
||||
LOCK_WRAPPER(cell)->disposeFunc(cell->lock);
|
||||
free(cell);
|
||||
}
|
||||
|
||||
/* RQ thread from metal pipeline (cell locked) */
|
||||
static void ATexturePoolCell_occupyItem(ATexturePoolCell *cell, ATexturePoolItem *item) {
|
||||
CHECK_NULL(cell);
|
||||
CHECK_NULL(item);
|
||||
if (item->isBusy) {
|
||||
return;
|
||||
}
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolCell_occupyItem: item = %p", item);
|
||||
|
||||
if IS_NULL(item->prev) {
|
||||
cell->available = item->next;
|
||||
if IS_NOT_NULL(item->next) {
|
||||
item->next->prev = NULL;
|
||||
} else {
|
||||
cell->availableTail = item->prev;
|
||||
}
|
||||
} else {
|
||||
item->prev->next = item->next;
|
||||
if IS_NOT_NULL(item->next) {
|
||||
item->next->prev = item->prev;
|
||||
} else {
|
||||
cell->availableTail = item->prev;
|
||||
}
|
||||
item->prev = NULL;
|
||||
}
|
||||
if (cell->occupied) {
|
||||
cell->occupied->prev = item;
|
||||
}
|
||||
item->next = cell->occupied;
|
||||
cell->occupied = item;
|
||||
item->isBusy = JNI_TRUE;
|
||||
}
|
||||
|
||||
/* Callback from native java2D pipeline => multi-thread (cell lock) */
|
||||
static void ATexturePoolCell_releaseItem(ATexturePoolCell *cell, ATexturePoolItem *item) {
|
||||
CHECK_NULL(cell);
|
||||
CHECK_NULL(item);
|
||||
if (!item->isBusy) {
|
||||
return;
|
||||
}
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolCell_releaseItem: item = %p", item);
|
||||
|
||||
LOCK_WRAPPER_LOCK(cell);
|
||||
{
|
||||
if IS_NULL(item->prev) {
|
||||
cell->occupied = item->next;
|
||||
if IS_NOT_NULL(item->next) {
|
||||
item->next->prev = NULL;
|
||||
}
|
||||
} else {
|
||||
item->prev->next = item->next;
|
||||
if IS_NOT_NULL(item->next) {
|
||||
item->next->prev = item->prev;
|
||||
}
|
||||
item->prev = NULL;
|
||||
}
|
||||
if IS_NOT_NULL(cell->available) {
|
||||
cell->available->prev = item;
|
||||
} else {
|
||||
cell->availableTail = item;
|
||||
}
|
||||
item->next = cell->available;
|
||||
cell->available = item;
|
||||
item->isBusy = JNI_FALSE;
|
||||
}
|
||||
LOCK_WRAPPER_UNLOCK(cell);
|
||||
}
|
||||
|
||||
static void ATexturePoolCell_addOccupiedItem(ATexturePoolCell *cell, ATexturePoolItem *item) {
|
||||
CHECK_NULL(cell);
|
||||
CHECK_NULL(item);
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolCell_addOccupiedItem: item = %p", item);
|
||||
|
||||
LOCK_WRAPPER_LOCK(cell);
|
||||
{
|
||||
cell->pool->allocatedCount++;
|
||||
cell->pool->totalAllocatedCount++;
|
||||
|
||||
if IS_NOT_NULL(cell->occupied) {
|
||||
cell->occupied->prev = item;
|
||||
}
|
||||
item->next = cell->occupied;
|
||||
cell->occupied = item;
|
||||
item->isBusy = JNI_TRUE;
|
||||
}
|
||||
LOCK_WRAPPER_UNLOCK(cell);
|
||||
}
|
||||
|
||||
static void ATexturePoolCell_cleanIfBefore(ATexturePoolCell *cell, time_t lastUsedTimeToRemove) {
|
||||
CHECK_NULL(cell);
|
||||
LOCK_WRAPPER_LOCK(cell);
|
||||
{
|
||||
ATexturePoolItem *cur = cell->availableTail;
|
||||
while IS_NOT_NULL(cur) {
|
||||
ATexturePoolItem *prev = cur->prev;
|
||||
if ((cur->reuseCount == 0) || (lastUsedTimeToRemove <= 0) || (cur->lastUsed < lastUsedTimeToRemove)) {
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "ATexturePoolCell_cleanIfBefore: remove pool item: tex=%p, w=%d h=%d, elapsed=%d",
|
||||
cur->texture, cur->width, cur->height,
|
||||
time(NULL) - cur->lastUsed);
|
||||
|
||||
const int requestedBytes = cur->width * cur->height * cell->pool->bytesPerPixelFunc(cur->format);
|
||||
// cur is NULL after removeAvailableItem:
|
||||
ATexturePoolCell_removeAvailableItem(cell, cur);
|
||||
cell->pool->allocatedCount--;
|
||||
cell->pool->memoryAllocated -= requestedBytes;
|
||||
} else {
|
||||
if (TRACE_MEM_API || TRACE_GC_ALIVE) J2dRlsTraceLn2(J2D_TRACE_INFO, "ATexturePoolCell_cleanIfBefore: item = %p - ALIVE - reuse: %4d -> 0",
|
||||
cur, cur->reuseCount);
|
||||
// clear reuse count anyway:
|
||||
cur->reuseCount = 0;
|
||||
}
|
||||
cur = prev;
|
||||
}
|
||||
}
|
||||
LOCK_WRAPPER_UNLOCK(cell);
|
||||
}
|
||||
|
||||
/* RQ thread from metal pipeline <=> multi-thread callbacks (cell lock) */
|
||||
static ATexturePoolItem* ATexturePoolCell_occupyCellItem(ATexturePoolCell *cell,
|
||||
jint width,
|
||||
jint height,
|
||||
jlong format)
|
||||
{
|
||||
CHECK_NULL_RETURN(cell, NULL);
|
||||
int minDeltaArea = -1;
|
||||
const int requestedPixels = width * height;
|
||||
ATexturePoolItem *minDeltaTpi = NULL;
|
||||
LOCK_WRAPPER_LOCK(cell);
|
||||
{
|
||||
for (ATexturePoolItem *cur = cell->available; IS_NOT_NULL(cur); cur = cur->next) {
|
||||
// TODO: use swizzle when formats are not equal
|
||||
if (cur->format != format) {
|
||||
continue;
|
||||
}
|
||||
if (cur->width < width || cur->height < height) {
|
||||
continue;
|
||||
}
|
||||
const int deltaArea = (const int) (cur->width * cur->height - requestedPixels);
|
||||
if ((minDeltaArea < 0) || (deltaArea < minDeltaArea)) {
|
||||
minDeltaArea = deltaArea;
|
||||
minDeltaTpi = cur;
|
||||
if (deltaArea == 0) {
|
||||
// found exact match in current cell
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if IS_NOT_NULL(minDeltaTpi) {
|
||||
ATexturePoolCell_occupyItem(cell, minDeltaTpi);
|
||||
}
|
||||
}
|
||||
LOCK_WRAPPER_UNLOCK(cell);
|
||||
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolCell_occupyCellItem: item = %p", minDeltaTpi);
|
||||
return minDeltaTpi;
|
||||
}
|
||||
|
||||
|
||||
/* ATexturePoolHandle API */
|
||||
static ATexturePoolHandle* ATexturePoolHandle_initWithPoolItem(ATexturePoolItem *item, jint reqWidth, jint reqHeight) {
|
||||
CHECK_NULL_RETURN(item, NULL);
|
||||
ATexturePoolHandle *handle = (ATexturePoolHandle*)malloc(sizeof(ATexturePoolHandle));
|
||||
CHECK_NULL_LOG_RETURN(handle, NULL, "ATexturePoolHandle_initWithPoolItem: could not allocate ATexturePoolHandle");
|
||||
|
||||
handle->texture = item->texture;
|
||||
handle->_poolItem = item;
|
||||
|
||||
handle->reqWidth = reqWidth;
|
||||
handle->reqHeight = reqHeight;
|
||||
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolHandle_initWithPoolItem: handle = %p", handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/* Callback from metal pipeline => multi-thread (cell lock) */
|
||||
void ATexturePoolHandle_ReleaseTexture(ATexturePoolHandle *handle) {
|
||||
CHECK_NULL(handle);
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolHandle_ReleaseTexture: handle = %p", handle);
|
||||
|
||||
ATexturePoolItem_ReleaseItem(handle->_poolItem);
|
||||
free(handle);
|
||||
}
|
||||
|
||||
ATexturePrivPtr* ATexturePoolHandle_GetTexture(ATexturePoolHandle *handle) {
|
||||
CHECK_NULL_RETURN(handle, NULL);
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolHandle_GetTexture: handle = %p", handle);
|
||||
return handle->texture;
|
||||
}
|
||||
|
||||
jint ATexturePoolHandle_GetRequestedWidth(ATexturePoolHandle *handle) {
|
||||
CHECK_NULL_RETURN(handle, 0);
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolHandle_GetRequestedWidth: handle = %p", handle);
|
||||
return handle->reqWidth;
|
||||
}
|
||||
|
||||
jint ATexturePoolHandle_GetRequestedHeight(ATexturePoolHandle *handle) {
|
||||
CHECK_NULL_RETURN(handle, 0);
|
||||
if (TRACE_USE_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePoolHandle_GetRequestedHeight: handle = %p", handle);
|
||||
return handle->reqHeight;
|
||||
}
|
||||
|
||||
|
||||
/* ATexturePool API */
|
||||
static void ATexturePool_cleanIfNecessary(ATexturePool *pool, int lastUsedTimeThreshold);
|
||||
|
||||
static void ATexturePool_autoTest(ATexturePool *pool, jlong format) {
|
||||
CHECK_NULL(pool);
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "ATexturePool_autoTest: step = %d", INIT_TEST_STEP);
|
||||
|
||||
pool->enableGC = JNI_FALSE;
|
||||
|
||||
for (int w = 1; w <= INIT_TEST_MAX; w += INIT_TEST_STEP) {
|
||||
for (int h = 1; h <= INIT_TEST_MAX; h += INIT_TEST_STEP) {
|
||||
/* use auto-release pool to free memory as early as possible */
|
||||
|
||||
ATexturePoolHandle *texHandle = ATexturePool_getTexture(pool, w, h, format);
|
||||
ATexturePrivPtr *texture = ATexturePoolHandle_GetTexture(texHandle);
|
||||
|
||||
if IS_NULL(texture) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "ATexturePool_autoTest: w= %d h= %d => texture is NULL !", w, h);
|
||||
} else {
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn3(J2D_TRACE_VERBOSE, "ATexturePool_autoTest: w=%d h=%d => tex=%p",
|
||||
w, h, texture);
|
||||
}
|
||||
ATexturePoolHandle_ReleaseTexture(texHandle);
|
||||
}
|
||||
}
|
||||
J2dRlsTraceLn2(J2D_TRACE_INFO, "ATexturePool_autoTest: before GC: total allocated memory = %lld Mb (total allocs: %d)",
|
||||
pool->totalMemoryAllocated / UNIT_MB, pool->totalAllocatedCount);
|
||||
|
||||
pool->enableGC = JNI_TRUE;
|
||||
|
||||
ATexturePool_cleanIfNecessary(pool, FORCE_GC_INTERVAL_SEC);
|
||||
|
||||
J2dRlsTraceLn2(J2D_TRACE_INFO, "ATexturePool_autoTest: after GC: total allocated memory = %lld Mb (total allocs: %d)",
|
||||
pool->totalMemoryAllocated / UNIT_MB, pool->totalAllocatedCount);
|
||||
}
|
||||
|
||||
ATexturePool* ATexturePool_initWithDevice(ADevicePrivPtr *device,
|
||||
jlong maxDeviceMemory,
|
||||
ATexturePool_createTexture *createTextureFunc,
|
||||
ATexturePool_freeTexture *freeTextureFunc,
|
||||
ATexturePool_bytesPerPixel *bytesPerPixelFunc,
|
||||
ATexturePoolLockWrapper *lockWrapper,
|
||||
jlong autoTestFormat)
|
||||
{
|
||||
CHECK_NULL_LOG_RETURN(device, NULL, "ATexturePool_initWithDevice: device is null !");
|
||||
CHECK_NULL_LOG_RETURN(createTextureFunc, NULL, "ATexturePool_initWithDevice: createTextureFunc function is null !");
|
||||
CHECK_NULL_LOG_RETURN(freeTextureFunc, NULL, "ATexturePool_initWithDevice: freeTextureFunc function is null !");
|
||||
CHECK_NULL_LOG_RETURN(bytesPerPixelFunc, NULL, "ATexturePool_initWithDevice: bytesPerPixelFunc function is null !");
|
||||
CHECK_NULL_LOG_RETURN(lockWrapper, NULL, "ATexturePool_initWithDevice: lockWrapper is null !");
|
||||
|
||||
ATexturePool *pool = (ATexturePool*)malloc(sizeof(ATexturePool));
|
||||
CHECK_NULL_LOG_RETURN(pool, NULL, "ATexturePool_initWithDevice: could not allocate ATexturePool");
|
||||
|
||||
pool->createTextureFunc = createTextureFunc;
|
||||
pool->freeTextureFunc = freeTextureFunc;
|
||||
pool->bytesPerPixelFunc = bytesPerPixelFunc;
|
||||
pool->lockWrapper = lockWrapper;
|
||||
pool->device = device;
|
||||
|
||||
// use (5K) 5120-by-2880 resolution:
|
||||
pool->poolCellWidth = 5120 >> CELL_WIDTH_BITS;
|
||||
pool->poolCellHeight = 2880 >> CELL_HEIGHT_BITS;
|
||||
|
||||
const int cellsCount = pool->poolCellWidth * pool->poolCellHeight;
|
||||
pool->_cells = (ATexturePoolCell**)malloc(cellsCount * sizeof(void*));
|
||||
CHECK_NULL_LOG_RETURN(pool->_cells, NULL, "ATexturePool_initWithDevice: could not allocate cells");
|
||||
memset(pool->_cells, 0, cellsCount * sizeof(void*));
|
||||
|
||||
pool->maxPoolMemory = maxDeviceMemory / 2;
|
||||
// Set maximum to handle at least 5K screen size
|
||||
if (pool->maxPoolMemory < SCREEN_MEMORY_SIZE_5K) {
|
||||
pool->maxPoolMemory = SCREEN_MEMORY_SIZE_5K;
|
||||
} else if (USE_MAX_GPU_DEVICE_MEM && (pool->maxPoolMemory > MAX_GPU_DEVICE_MEM)) {
|
||||
pool->maxPoolMemory = MAX_GPU_DEVICE_MEM;
|
||||
}
|
||||
|
||||
pool->allocatedCount = 0L;
|
||||
pool->totalAllocatedCount = 0L;
|
||||
|
||||
pool->memoryAllocated = 0L;
|
||||
pool->totalMemoryAllocated = 0L;
|
||||
|
||||
pool->enableGC = JNI_TRUE;
|
||||
pool->lastGC = time(NULL);
|
||||
pool->lastYoungGC = pool->lastGC;
|
||||
pool->lastFullGC = pool->lastGC;
|
||||
|
||||
pool->cacheHits = 0L;
|
||||
pool->totalHits = 0L;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePool_initWithDevice: pool = %p", pool);
|
||||
|
||||
if (INIT_TEST) {
|
||||
static jboolean INIT_TEST_START = JNI_TRUE;
|
||||
if (INIT_TEST_START) {
|
||||
INIT_TEST_START = JNI_FALSE;
|
||||
ATexturePool_autoTest(pool, autoTestFormat);
|
||||
}
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
void ATexturePool_Dispose(ATexturePool *pool) {
|
||||
CHECK_NULL(pool);
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePool_Dispose: pool = %p", pool);
|
||||
|
||||
const int cellsCount = pool->poolCellWidth * pool->poolCellHeight;
|
||||
for (int c = 0; c < cellsCount; ++c) {
|
||||
ATexturePoolCell *cell = pool->_cells[c];
|
||||
if IS_NOT_NULL(cell) {
|
||||
ATexturePoolCell_Dispose(cell);
|
||||
}
|
||||
}
|
||||
free(pool->_cells);
|
||||
free(pool);
|
||||
}
|
||||
|
||||
ATexturePoolLockWrapper* ATexturePool_getLockWrapper(ATexturePool *pool) {
|
||||
CHECK_NULL_RETURN(pool, NULL);
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn1(J2D_TRACE_INFO, "ATexturePool_getLockWrapper: pool = %p", pool);
|
||||
return pool->lockWrapper;
|
||||
}
|
||||
|
||||
static void ATexturePool_cleanIfNecessary(ATexturePool *pool, int lastUsedTimeThreshold) {
|
||||
CHECK_NULL(pool);
|
||||
time_t lastUsedTimeToRemove =
|
||||
lastUsedTimeThreshold > 0 ?
|
||||
time(NULL) - lastUsedTimeThreshold :
|
||||
lastUsedTimeThreshold;
|
||||
|
||||
if (TRACE_MEM_API || TRACE_GC) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "ATexturePool_cleanIfNecessary: before GC: allocated memory = %lld Kb (allocs: %d)",
|
||||
pool->memoryAllocated / UNIT_KB, pool->allocatedCount);
|
||||
}
|
||||
|
||||
for (int cy = 0; cy < pool->poolCellHeight; ++cy) {
|
||||
for (int cx = 0; cx < pool->poolCellWidth; ++cx) {
|
||||
ATexturePoolCell *cell = pool->_cells[cy * pool->poolCellWidth + cx];
|
||||
if IS_NOT_NULL(cell) {
|
||||
ATexturePoolCell_cleanIfBefore(cell, lastUsedTimeToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TRACE_MEM_API || TRACE_GC) {
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "ATexturePool_cleanIfNecessary: after GC: allocated memory = %lld Kb (allocs: %d) - hits = %lld (%.3lf %% cached)",
|
||||
pool->memoryAllocated / UNIT_KB, pool->allocatedCount,
|
||||
pool->totalHits, (pool->totalHits != 0L) ? (100.0 * pool->cacheHits) / pool->totalHits : 0.0);
|
||||
// reset hits:
|
||||
pool->cacheHits = 0L;
|
||||
pool->totalHits = 0L;
|
||||
}
|
||||
}
|
||||
|
||||
ATexturePoolHandle* ATexturePool_getTexture(ATexturePool* pool,
|
||||
jint width,
|
||||
jint height,
|
||||
jlong format)
|
||||
{
|
||||
CHECK_NULL_RETURN(pool, NULL);
|
||||
|
||||
const int reqWidth = width;
|
||||
const int reqHeight = height;
|
||||
|
||||
int cellX0 = width >> CELL_WIDTH_BITS;
|
||||
int cellY0 = height >> CELL_HEIGHT_BITS;
|
||||
|
||||
if (USE_CEIL_SIZE) {
|
||||
// use upper cell size to maximize cache hits:
|
||||
const int remX0 = width & CELL_WIDTH_MASK;
|
||||
const int remY0 = height & CELL_HEIGHT_MASK;
|
||||
|
||||
if (remX0 != 0) {
|
||||
cellX0++;
|
||||
}
|
||||
if (remY0 != 0) {
|
||||
cellY0++;
|
||||
}
|
||||
// adjust width / height to cell upper boundaries:
|
||||
width = (cellX0) << CELL_WIDTH_BITS;
|
||||
height = (cellY0) << CELL_HEIGHT_BITS;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "ATexturePool_getTexture: fixed tex size: (%d %d) => (%d %d)",
|
||||
reqWidth, reqHeight, width, height);
|
||||
}
|
||||
|
||||
// 1. clean pool if necessary
|
||||
const int requestedPixels = width * height;
|
||||
const int requestedBytes = requestedPixels * pool->bytesPerPixelFunc(format);
|
||||
const jlong neededMemoryAllocated = pool->memoryAllocated + requestedBytes;
|
||||
|
||||
if (neededMemoryAllocated > pool->maxPoolMemory) {
|
||||
// release all free textures
|
||||
ATexturePool_cleanIfNecessary(pool, 0);
|
||||
} else {
|
||||
time_t now = time(NULL);
|
||||
// ensure 1s at least:
|
||||
if ((now - pool->lastGC) > 0) {
|
||||
pool->lastGC = now;
|
||||
if (neededMemoryAllocated > pool->maxPoolMemory / 2) {
|
||||
// release only old free textures
|
||||
ATexturePool_cleanIfNecessary(pool, MAX_POOL_ITEM_LIFETIME_SEC);
|
||||
} else if (FORCE_GC && pool->enableGC) {
|
||||
if ((now - pool->lastFullGC) > FORCE_GC_INTERVAL_SEC) {
|
||||
pool->lastFullGC = now;
|
||||
pool->lastYoungGC = now;
|
||||
// release only old free textures since last full-gc
|
||||
ATexturePool_cleanIfNecessary(pool, FORCE_GC_INTERVAL_SEC);
|
||||
} else if ((now - pool->lastYoungGC) > YOUNG_GC_INTERVAL_SEC) {
|
||||
pool->lastYoungGC = now;
|
||||
// release only not reused and old textures
|
||||
ATexturePool_cleanIfNecessary(pool, YOUNG_GC_LIFETIME_SEC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. find free item
|
||||
const int cellX1 = cellX0 + 1;
|
||||
const int cellY1 = cellY0 + 1;
|
||||
|
||||
// Note: this code (test + resizing) is not thread-safe:
|
||||
if (cellX1 > pool->poolCellWidth || cellY1 > pool->poolCellHeight) {
|
||||
const int newCellWidth = cellX1 <= pool->poolCellWidth ? pool->poolCellWidth : cellX1;
|
||||
const int newCellHeight = cellY1 <= pool->poolCellHeight ? pool->poolCellHeight : cellY1;
|
||||
const int newCellsCount = newCellWidth*newCellHeight;
|
||||
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "ATexturePool_getTexture: resize: %d -> %d",
|
||||
pool->poolCellWidth * pool->poolCellHeight, newCellsCount);
|
||||
|
||||
ATexturePoolCell **newCells = (ATexturePoolCell **)malloc(newCellsCount * sizeof(void*));
|
||||
CHECK_NULL_LOG_RETURN(newCells, NULL, "ATexturePool_getTexture: could not allocate newCells");
|
||||
|
||||
const size_t strideBytes = pool->poolCellWidth * sizeof(void*);
|
||||
for (int cy = 0; cy < pool->poolCellHeight; ++cy) {
|
||||
ATexturePoolCell **dst = newCells + cy * newCellWidth;
|
||||
ATexturePoolCell **src = pool->_cells + cy * pool->poolCellWidth;
|
||||
memcpy(dst, src, strideBytes);
|
||||
if (newCellWidth > pool->poolCellWidth)
|
||||
memset(dst + pool->poolCellWidth, 0, (newCellWidth - pool->poolCellWidth) * sizeof(void*));
|
||||
}
|
||||
if (newCellHeight > pool->poolCellHeight) {
|
||||
ATexturePoolCell **dst = newCells + pool->poolCellHeight * newCellWidth;
|
||||
memset(dst, 0, (newCellHeight - pool->poolCellHeight) * newCellWidth * sizeof(void*));
|
||||
}
|
||||
free(pool->_cells);
|
||||
pool->_cells = newCells;
|
||||
pool->poolCellWidth = newCellWidth;
|
||||
pool->poolCellHeight = newCellHeight;
|
||||
}
|
||||
|
||||
ATexturePoolItem *minDeltaTpi = NULL;
|
||||
int minDeltaArea = -1;
|
||||
for (int cy = cellY0; cy < cellY1; ++cy) {
|
||||
for (int cx = cellX0; cx < cellX1; ++cx) {
|
||||
ATexturePoolCell* cell = pool->_cells[cy * pool->poolCellWidth + cx];
|
||||
if IS_NOT_NULL(cell) {
|
||||
ATexturePoolItem *tpi = ATexturePoolCell_occupyCellItem(cell, width, height, format);
|
||||
if IS_NULL(tpi) {
|
||||
continue;
|
||||
}
|
||||
const int deltaArea = (const int) (tpi->width * tpi->height - requestedPixels);
|
||||
if (minDeltaArea < 0 || deltaArea < minDeltaArea) {
|
||||
minDeltaArea = deltaArea;
|
||||
minDeltaTpi = tpi;
|
||||
if (deltaArea == 0) {
|
||||
// found exact match in current cell
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if IS_NOT_NULL(minDeltaTpi) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if IS_NULL(minDeltaTpi) {
|
||||
ATexturePoolCell* cell = pool->_cells[cellY0 * pool->poolCellWidth + cellX0];
|
||||
if IS_NULL(cell) {
|
||||
cell = ATexturePoolCell_init(pool);
|
||||
CHECK_NULL_RETURN(cell, NULL);
|
||||
pool->_cells[cellY0 * pool->poolCellWidth + cellX0] = cell;
|
||||
}
|
||||
// use device to allocate NEW texture:
|
||||
ATexturePrivPtr* tex = pool->createTextureFunc(pool->device, width, height, format);
|
||||
CHECK_NULL_LOG_RETURN(tex, NULL, "ATexturePool_getTexture: createTextureFunc failed to allocate texture !");
|
||||
|
||||
minDeltaTpi = ATexturePoolItem_initWithTexture(pool->freeTextureFunc, pool->device, tex, cell,
|
||||
width, height, format);
|
||||
ATexturePoolCell_addOccupiedItem(cell, minDeltaTpi);
|
||||
|
||||
pool->memoryAllocated += requestedBytes;
|
||||
pool->totalMemoryAllocated += requestedBytes;
|
||||
|
||||
J2dTraceLn6(J2D_TRACE_VERBOSE, "ATexturePool_getTexture: created pool item: tex=%p, w=%d h=%d, pf=%d | allocated memory = %lld Kb (allocs: %d)",
|
||||
minDeltaTpi->texture, width, height, format, pool->memoryAllocated / UNIT_KB, pool->allocatedCount)
|
||||
if (TRACE_MEM_API) J2dRlsTraceLn6(J2D_TRACE_VERBOSE, "ATexturePool_getTexture: created pool item: tex=%p, w=%d h=%d, pf=%d | allocated memory = %lld Kb (allocs: %d)",
|
||||
minDeltaTpi->texture, width, height, format, pool->memoryAllocated / UNIT_KB, pool->allocatedCount)
|
||||
} else {
|
||||
pool->cacheHits++;
|
||||
minDeltaTpi->reuseCount++;
|
||||
if (TRACE_REUSE) {
|
||||
J2dRlsTraceLn5(J2D_TRACE_VERBOSE, "ATexturePool_getTexture: reused pool item: tex=%p, w=%d h=%d, pf=%d - reuse: %4d",
|
||||
minDeltaTpi->texture, width, height, format, minDeltaTpi->reuseCount)
|
||||
}
|
||||
}
|
||||
pool->totalHits++;
|
||||
minDeltaTpi->lastUsed = time(NULL);
|
||||
return ATexturePoolHandle_initWithPoolItem(minDeltaTpi, reqWidth, reqHeight);
|
||||
}
|
||||
139
src/java.desktop/share/native/common/java2d/AccelTexturePool.h
Normal file
139
src/java.desktop/share/native/common/java2d/AccelTexturePool.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef AccelTexturePool_h_Included
|
||||
#define AccelTexturePool_h_Included
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
|
||||
#define UNIT_KB 1024
|
||||
#define UNIT_MB (UNIT_KB * UNIT_KB)
|
||||
|
||||
|
||||
/* useful macros (from jni_utils.h) */
|
||||
#define IS_NULL(obj) ((obj) == NULL)
|
||||
#define IS_NOT_NULL(obj) ((obj) != NULL)
|
||||
|
||||
#define CHECK_NULL(x) \
|
||||
do { \
|
||||
if ((x) == NULL) { \
|
||||
return; \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
#define CHECK_NULL_RETURN(x, y) \
|
||||
do { \
|
||||
if ((x) == NULL) { \
|
||||
return (y); \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
#define CHECK_NULL_LOG_RETURN(x, y, msg) \
|
||||
do { \
|
||||
if IS_NULL(x) { \
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, (msg)); \
|
||||
return (y); \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
|
||||
/* Generic native-specific device (platform specific) */
|
||||
typedef void ADevicePrivPtr;
|
||||
/* Generic native-specific texture (platform specific) */
|
||||
typedef void ATexturePrivPtr;
|
||||
|
||||
|
||||
/* Texture allocate/free API */
|
||||
typedef ATexturePrivPtr* (ATexturePool_createTexture)(ADevicePrivPtr *device,
|
||||
int width,
|
||||
int height,
|
||||
long format);
|
||||
|
||||
typedef void (ATexturePool_freeTexture)(ADevicePrivPtr *device,
|
||||
ATexturePrivPtr *texture);
|
||||
|
||||
typedef int (ATexturePool_bytesPerPixel)(long format);
|
||||
|
||||
|
||||
/* lock API */
|
||||
/* Generic native-specific lock (platform specific) */
|
||||
typedef void ATexturePoolLockPrivPtr;
|
||||
|
||||
typedef ATexturePoolLockPrivPtr* (ATexturePoolLock_init)(void);
|
||||
|
||||
typedef void (ATexturePoolLock_dispose) (ATexturePoolLockPrivPtr *lock);
|
||||
|
||||
typedef void (ATexturePoolLock_lock) (ATexturePoolLockPrivPtr *lock);
|
||||
|
||||
typedef void (ATexturePoolLock_unlock) (ATexturePoolLockPrivPtr *lock);
|
||||
|
||||
|
||||
/* forward-definitions (private) */
|
||||
typedef struct ATexturePoolLockWrapper_ ATexturePoolLockWrapper;
|
||||
typedef struct ATexturePoolItem_ ATexturePoolItem;
|
||||
typedef struct ATexturePoolHandle_ ATexturePoolHandle;
|
||||
typedef struct ATexturePoolCell_ ATexturePoolCell;
|
||||
typedef struct ATexturePool_ ATexturePool;
|
||||
|
||||
|
||||
/* ATexturePoolLockWrapper API */
|
||||
ATexturePoolLockWrapper* ATexturePoolLockWrapper_init(ATexturePoolLock_init *initFunc,
|
||||
ATexturePoolLock_dispose *disposeFunc,
|
||||
ATexturePoolLock_lock *lockFunc,
|
||||
ATexturePoolLock_unlock *unlockFunc);
|
||||
|
||||
void ATexturePoolLockWrapper_Dispose(ATexturePoolLockWrapper *lockWrapper);
|
||||
|
||||
|
||||
/* ATexturePoolHandle API */
|
||||
void ATexturePoolHandle_ReleaseTexture(ATexturePoolHandle *handle);
|
||||
|
||||
ATexturePrivPtr* ATexturePoolHandle_GetTexture(ATexturePoolHandle *handle);
|
||||
|
||||
jint ATexturePoolHandle_GetRequestedWidth(ATexturePoolHandle *handle);
|
||||
jint ATexturePoolHandle_GetRequestedHeight(ATexturePoolHandle *handle);
|
||||
|
||||
|
||||
/* ATexturePool API */
|
||||
ATexturePool* ATexturePool_initWithDevice(ADevicePrivPtr *device,
|
||||
jlong maxDeviceMemory,
|
||||
ATexturePool_createTexture *createTextureFunc,
|
||||
ATexturePool_freeTexture *freeTextureFunc,
|
||||
ATexturePool_bytesPerPixel *bytesPerPixelFunc,
|
||||
ATexturePoolLockWrapper *lockWrapper,
|
||||
jlong autoTestFormat);
|
||||
|
||||
void ATexturePool_Dispose(ATexturePool *pool);
|
||||
|
||||
ATexturePoolLockWrapper* ATexturePool_getLockWrapper(ATexturePool *pool);
|
||||
|
||||
ATexturePoolHandle* ATexturePool_getTexture(ATexturePool *pool,
|
||||
jint width,
|
||||
jint height,
|
||||
jlong format);
|
||||
|
||||
#endif /* AccelTexturePool_h_Included */
|
||||
@@ -8,25 +8,48 @@ void* CARR_array_alloc(size_t elem_size, size_t capacity) {
|
||||
if (pvec == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
pvec->elem_size = elem_size;
|
||||
pvec->size = 0;
|
||||
pvec->capacity = capacity;
|
||||
return pvec->data;
|
||||
}
|
||||
|
||||
void* CARR_array_realloc(CARR_array_t* vec, size_t new_capacity) {
|
||||
void* CARR_array_realloc(CARR_array_t* vec, size_t elem_size, size_t new_capacity) {
|
||||
if (vec->capacity == new_capacity) {
|
||||
return vec->data;
|
||||
}
|
||||
CARR_array_t* new_vec =
|
||||
(CARR_array_t*)((char*)CARR_array_alloc(vec->elem_size, new_capacity) - offsetof(CARR_array_t, data));
|
||||
(CARR_array_t*)((char*)CARR_array_alloc(elem_size, new_capacity) - offsetof(CARR_array_t, data));
|
||||
if (new_vec == NULL) {
|
||||
return NULL;
|
||||
return vec == NULL ? NULL : vec->data;
|
||||
}
|
||||
new_vec->capacity = new_capacity;
|
||||
new_vec->size = MIN(vec->size, new_capacity);
|
||||
new_vec->elem_size = vec->elem_size;
|
||||
memcpy(new_vec->data, vec->data, new_vec->size*new_vec->elem_size);
|
||||
memcpy(new_vec->data, vec->data, new_vec->size*elem_size);
|
||||
free(vec);
|
||||
return new_vec->data;
|
||||
}
|
||||
|
||||
void* CARR_ring_buffer_realloc(CARR_ring_buffer_t* buf, size_t elem_size, size_t new_capacity) {
|
||||
if (buf != NULL && buf->capacity == new_capacity) {
|
||||
return buf->data;
|
||||
}
|
||||
CARR_ring_buffer_t* new_buf =
|
||||
(CARR_ring_buffer_t*) malloc(elem_size * new_capacity + offsetof(CARR_ring_buffer_t, data));
|
||||
if (new_buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
new_buf->head = new_buf->tail = 0;
|
||||
new_buf->capacity = new_capacity;
|
||||
if (buf != NULL) {
|
||||
if (buf->tail > buf->head) {
|
||||
new_buf->tail = buf->tail - buf->head;
|
||||
memcpy(new_buf->data, buf->data + buf->head*elem_size, new_buf->tail*elem_size);
|
||||
} else if (buf->tail < buf->head) {
|
||||
new_buf->tail = buf->capacity + buf->tail - buf->head;
|
||||
memcpy(new_buf->data, buf->data + buf->head*elem_size, (buf->capacity-buf->head)*elem_size);
|
||||
memcpy(new_buf->data + (new_buf->tail-buf->tail)*elem_size, buf->data, buf->tail*elem_size);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
return new_buf->data;
|
||||
}
|
||||
|
||||
@@ -1,48 +1,63 @@
|
||||
#ifndef C_ARRAY_UTIL_H
|
||||
#define C_ARRAY_UTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define ARRAY_CAPACITY_MULT 2
|
||||
// C_ARRAY_UTIL_ALLOCATION_FAILED is called when allocation fails.
|
||||
// Default implementation calls abort().
|
||||
// Functions that can call C_ARRAY_UTIL_ALLOCATION_FAILED explicitly state
|
||||
// this in the documentation. Functions with *_TRY_* return NULL on failure.
|
||||
#ifndef C_ARRAY_UTIL_ALLOCATION_FAILED
|
||||
#include <stdlib.h>
|
||||
#define C_ARRAY_UTIL_ALLOCATION_FAILED() abort()
|
||||
#endif
|
||||
|
||||
#define ARRAY_CAPACITY_GROW(C) (((C) * 3 + 1) / 2) // 1.5 multiplier
|
||||
#define ARRAY_DEFAULT_CAPACITY 10
|
||||
typedef struct {
|
||||
size_t elem_size;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
char data[];
|
||||
} CARR_array_t;
|
||||
|
||||
void* CARR_array_alloc(size_t elem_size, size_t capacity);
|
||||
void* CARR_array_realloc(CARR_array_t* vec, size_t new_capacity);
|
||||
void* CARR_array_realloc(CARR_array_t* vec, size_t elem_size, size_t new_capacity);
|
||||
|
||||
typedef struct {
|
||||
size_t head;
|
||||
size_t tail;
|
||||
size_t capacity;
|
||||
char data[];
|
||||
} CARR_ring_buffer_t;
|
||||
|
||||
void* CARR_ring_buffer_realloc(CARR_ring_buffer_t* buf, size_t elem_size, size_t new_capacity);
|
||||
|
||||
/**
|
||||
* Allocate array
|
||||
* Allocate array. Returns NULL on allocation failure.
|
||||
* @param T type of elements
|
||||
* @param CAPACITY capacity of the array
|
||||
*/
|
||||
#define ARRAY_ALLOC(T, CAPACITY) (T*)CARR_array_alloc(sizeof(T), CAPACITY)
|
||||
|
||||
|
||||
#define ARRAY_T(P) (CARR_array_t *)((char*)P - offsetof(CARR_array_t, data))
|
||||
#define ARRAY_T(P) ((CARR_array_t *)((P) == NULL ? NULL : (char*)(P) - offsetof(CARR_array_t, data)))
|
||||
|
||||
/**
|
||||
* @param P pointer to the first data element of the array
|
||||
* @return size of the array
|
||||
*/
|
||||
#define ARRAY_SIZE(P) (ARRAY_T(P))->size
|
||||
#define ARRAY_SIZE(P) ((P) == NULL ? (size_t) 0 : (ARRAY_T(P))->size)
|
||||
|
||||
/**
|
||||
* @param P pointer to the first data element of the array
|
||||
* @return capacity of the array
|
||||
*/
|
||||
#define ARRAY_CAPACITY(P) (ARRAY_T(P))->capacity
|
||||
#define ARRAY_CAPACITY(P) ((P) == NULL ? (size_t) 0 : (ARRAY_T(P))->capacity)
|
||||
|
||||
/**
|
||||
* @param P pointer to the first data element of the array
|
||||
* @return last element in the array
|
||||
*/
|
||||
#define ARRAY_LAST(P) (P[(ARRAY_T(P))->size - 1])
|
||||
#define ARRAY_LAST(P) ((P)[ARRAY_SIZE(P) - 1])
|
||||
|
||||
/**
|
||||
* Deallocate the vector
|
||||
@@ -56,7 +71,7 @@ void* CARR_array_realloc(CARR_array_t* vec, size_t new_capacity);
|
||||
* @param F function to apply
|
||||
*/
|
||||
#define ARRAY_APPLY(P, F) do { \
|
||||
for (uint32_t _i = 0; _i < ARRAY_SIZE(P); _i++) F(&(P[_i])); \
|
||||
for (size_t _i = 0; _i < ARRAY_SIZE(P); _i++) F(&((P)[_i])); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
@@ -65,7 +80,7 @@ void* CARR_array_realloc(CARR_array_t* vec, size_t new_capacity);
|
||||
* @param F function to apply
|
||||
*/
|
||||
#define ARRAY_APPLY_LEADING(P, F, ...) do { \
|
||||
for (uint32_t _i = 0; _i < ARRAY_SIZE(P); _i++) F(&(P[_i]), __VA_ARGS__); \
|
||||
for (size_t _i = 0; _i < ARRAY_SIZE(P); _i++) F(&((P)[_i]), __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
@@ -74,29 +89,148 @@ void* CARR_array_realloc(CARR_array_t* vec, size_t new_capacity);
|
||||
* @param F function to apply
|
||||
*/
|
||||
#define ARRAY_APPLY_TRAILING(P, F, ...) do { \
|
||||
for (uint32_t _i = 0; _i < ARRAY_SIZE(P); _i++) F(__VA_ARGS__, &(P[_i])); \
|
||||
for (size_t _i = 0; _i < ARRAY_SIZE(P); _i++) F(__VA_ARGS__, &((P)[_i])); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Shrink capacity of the array to its size
|
||||
* @param PP pointer to the pointer to the first data element of the array
|
||||
* Ensure array capacity. Implicitly initializes when array is NULL.
|
||||
* On allocation failure, array is unchanged.
|
||||
* @param P pointer to the first data element of the array
|
||||
* @param CAPACITY required capacity of the array
|
||||
*/
|
||||
#define ARRAY_SHRINK_TO_FIT(PP) do { \
|
||||
*PP = CARR_array_realloc(ARRAY_T(*PP), ARRAY_SIZE(*PP)); \
|
||||
#define ARRAY_TRY_ENSURE_CAPACITY(P, CAPACITY) do { \
|
||||
if ((P) == NULL) { \
|
||||
if ((CAPACITY) > 0) (P) = CARR_array_alloc(sizeof((P)[0]), CAPACITY); \
|
||||
} else if (ARRAY_CAPACITY(P) < (CAPACITY)) { \
|
||||
(P) = CARR_array_realloc(ARRAY_T(P), sizeof((P)[0]), CAPACITY); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Add element to the end of the array
|
||||
* @param PP pointer to the pointer to the first data element of the array
|
||||
* Ensure array capacity. Implicitly initializes when array is NULL.
|
||||
* On allocation failure, C_ARRAY_UTIL_ALLOCATION_FAILED is called.
|
||||
* @param P pointer to the first data element of the array
|
||||
* @param CAPACITY required capacity of the array
|
||||
*/
|
||||
#define ARRAY_PUSH_BACK(PP, D) do { \
|
||||
if (ARRAY_SIZE(*PP) >= ARRAY_CAPACITY(*PP)) { \
|
||||
*PP = CARR_array_realloc(ARRAY_T(*PP), ARRAY_SIZE(*PP)*ARRAY_CAPACITY_MULT);\
|
||||
} \
|
||||
*(*PP + ARRAY_SIZE(*PP)) = (D); \
|
||||
ARRAY_SIZE(*PP)++; \
|
||||
#define ARRAY_ENSURE_CAPACITY(P, CAPACITY) do { \
|
||||
ARRAY_TRY_ENSURE_CAPACITY(P, CAPACITY); \
|
||||
if (ARRAY_CAPACITY(P) < (CAPACITY)) C_ARRAY_UTIL_ALLOCATION_FAILED(); \
|
||||
} while(0)
|
||||
|
||||
#define SARRAY_COUNT_OF(STATIC_ARRAY) (sizeof(STATIC_ARRAY)/sizeof(STATIC_ARRAY[0]))
|
||||
/**
|
||||
* Shrink capacity of the array to its size.
|
||||
* On allocation failure, array is unchanged.
|
||||
* @param P pointer to the first data element of the array
|
||||
*/
|
||||
#define ARRAY_SHRINK_TO_FIT(P) do { \
|
||||
if ((P) != NULL) { \
|
||||
(P) = CARR_array_realloc(ARRAY_T(P), sizeof((P)[0]), ARRAY_SIZE(P)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ARRAY_RESIZE_IMPL(P, SIZE, ...) do { \
|
||||
if ((P) != NULL || (SIZE) > 0) { \
|
||||
ARRAY_ENSURE_CAPACITY(P, SIZE); \
|
||||
if ((P) != NULL && (ARRAY_T(P))->capacity >= (SIZE)) { \
|
||||
(ARRAY_T(P))->size = (SIZE); \
|
||||
} __VA_ARGS__ \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Resize an array. Implicitly initializes when array is NULL.
|
||||
* On allocation failure, array is unchanged.
|
||||
* @param P pointer to the first data element of the array
|
||||
* @param SIZE required size of the array
|
||||
*/
|
||||
#define ARRAY_TRY_RESIZE(P, SIZE) ARRAY_RESIZE_IMPL(P, SIZE, )
|
||||
|
||||
/**
|
||||
* Resize an array. Implicitly initializes when array is NULL.
|
||||
* On allocation failure, C_ARRAY_UTIL_ALLOCATION_FAILED is called.
|
||||
* @param P pointer to the first data element of the array
|
||||
* @param SIZE required size of the array
|
||||
*/
|
||||
#define ARRAY_RESIZE(P, SIZE) ARRAY_RESIZE_IMPL(P, SIZE, else if ((SIZE) > 0) C_ARRAY_UTIL_ALLOCATION_FAILED();)
|
||||
|
||||
/**
|
||||
* Add element to the end of the array. Implicitly initializes when array is NULL.
|
||||
* On allocation failure, C_ARRAY_UTIL_ALLOCATION_FAILED is called.
|
||||
* @param P pointer to the first data element of the array
|
||||
*/
|
||||
#define ARRAY_PUSH_BACK(P, ...) do { \
|
||||
if ((P) == NULL) { \
|
||||
(P) = CARR_array_alloc(sizeof((P)[0]), ARRAY_DEFAULT_CAPACITY); \
|
||||
} else if (ARRAY_SIZE(P) >= ARRAY_CAPACITY(P)) { \
|
||||
(P) = CARR_array_realloc(ARRAY_T(P), sizeof((P)[0]), ARRAY_CAPACITY_GROW(ARRAY_SIZE(P))); \
|
||||
} \
|
||||
if (ARRAY_SIZE(P) >= ARRAY_CAPACITY(P)) C_ARRAY_UTIL_ALLOCATION_FAILED(); \
|
||||
*((P) + ARRAY_SIZE(P)) = (__VA_ARGS__); \
|
||||
(ARRAY_T(P))->size++; \
|
||||
} while(0)
|
||||
|
||||
#define SARRAY_COUNT_OF(STATIC_ARRAY) (sizeof(STATIC_ARRAY)/sizeof((STATIC_ARRAY)[0]))
|
||||
|
||||
#define RING_BUFFER_T(P) ((CARR_ring_buffer_t *)((P) == NULL ? NULL : (char*)(P) - offsetof(CARR_ring_buffer_t, data)))
|
||||
|
||||
/**
|
||||
* @param P pointer to the first data element of the ring buffer
|
||||
* @return size of the ring buffer
|
||||
*/
|
||||
#define RING_BUFFER_SIZE(P) ((P) == NULL ? (size_t) 0 : \
|
||||
(RING_BUFFER_T(P)->capacity + RING_BUFFER_T(P)->tail - RING_BUFFER_T(P)->head) % RING_BUFFER_T(P)->capacity)
|
||||
|
||||
/**
|
||||
* @param P pointer to the first data element of the ring buffer
|
||||
* @return capacity of the ring buffer
|
||||
*/
|
||||
#define RING_BUFFER_CAPACITY(P) ((P) == NULL ? (size_t) 0 : RING_BUFFER_T(P)->capacity)
|
||||
|
||||
/**
|
||||
* Add element to the end of the ring buffer. Implicitly initializes when buffer is NULL.
|
||||
* On allocation failure, C_ARRAY_UTIL_ALLOCATION_FAILED is called.
|
||||
* @param P pointer to the first data element of the buffer
|
||||
*/
|
||||
#define RING_BUFFER_PUSH(P, ...) RING_BUFFER_PUSH_CUSTOM(P, (P)[tail] = (__VA_ARGS__);)
|
||||
#define RING_BUFFER_PUSH_CUSTOM(P, ...) do { \
|
||||
size_t head, tail, new_tail; \
|
||||
if ((P) == NULL) { \
|
||||
(P) = CARR_ring_buffer_realloc(NULL, sizeof((P)[0]), ARRAY_DEFAULT_CAPACITY); \
|
||||
if ((P) == NULL) C_ARRAY_UTIL_ALLOCATION_FAILED(); \
|
||||
head = tail = 0; \
|
||||
new_tail = 1; \
|
||||
} else { \
|
||||
head = RING_BUFFER_T(P)->head; \
|
||||
tail = RING_BUFFER_T(P)->tail; \
|
||||
new_tail = (tail + 1) % RING_BUFFER_T(P)->capacity; \
|
||||
if (new_tail == head) { \
|
||||
(P) = CARR_ring_buffer_realloc(RING_BUFFER_T(P), sizeof(P[0]), ARRAY_CAPACITY_GROW(RING_BUFFER_T(P)->capacity)); \
|
||||
if ((P) == NULL) C_ARRAY_UTIL_ALLOCATION_FAILED(); \
|
||||
head = 0; \
|
||||
tail = RING_BUFFER_T(P)->tail; \
|
||||
new_tail = RING_BUFFER_T(P)->tail + 1; \
|
||||
} \
|
||||
} \
|
||||
__VA_ARGS__ \
|
||||
RING_BUFFER_T(P)->tail = new_tail; \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Get pointer to the first element of the ring buffer.
|
||||
* @param P pointer to the first data element of the buffer
|
||||
*/
|
||||
#define RING_BUFFER_PEEK(P) ((P) == NULL || RING_BUFFER_T(P)->head == RING_BUFFER_T(P)->tail ? NULL : &(P)[RING_BUFFER_T(P)->head])
|
||||
|
||||
/**
|
||||
* Move beginning of the ring buffer forward (remove first element).
|
||||
* @param P pointer to the first data element of the buffer
|
||||
*/
|
||||
#define RING_BUFFER_POP(P) RING_BUFFER_T(P)->head = (RING_BUFFER_T(P)->head + 1) % RING_BUFFER_T(P)->capacity
|
||||
|
||||
/**
|
||||
* Deallocate the ring buffer
|
||||
* @param P pointer to the first data element of the buffer
|
||||
*/
|
||||
#define RING_BUFFER_FREE(P) free(RING_BUFFER_T(P))
|
||||
|
||||
#endif // CARRAYUTILS_H
|
||||
|
||||
@@ -24,43 +24,25 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <Trace.h>
|
||||
#include "jlong_md.h"
|
||||
#include "jvm_md.h"
|
||||
#include "jni_util.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKVertex.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "CArrayUtil.h"
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKTexturePool.h"
|
||||
|
||||
#define VULKAN_DLL JNI_LIB_NAME("vulkan")
|
||||
#define VULKAN_1_DLL VERSIONED_JNI_LIB_NAME("vulkan", "1")
|
||||
static const uint32_t REQUIRED_VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 2, 0);
|
||||
|
||||
|
||||
#define MAX_ENABLED_LAYERS 5
|
||||
#define MAX_ENABLED_EXTENSIONS 5
|
||||
#define VALIDATION_LAYER_NAME "VK_LAYER_KHRONOS_validation"
|
||||
#define COUNT_OF(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
static jboolean verbose;
|
||||
static VKGraphicsEnvironment* geInstance = NULL;
|
||||
static void* pVulkanLib = NULL;
|
||||
#define INCLUDE_BYTECODE
|
||||
#define SHADER_ENTRY(NAME, TYPE) static uint32_t NAME ## _ ## TYPE ## _data[] = {
|
||||
#define BYTECODE_END };
|
||||
#include "vulkan/shader_list.h"
|
||||
#undef INCLUDE_BYTECODE
|
||||
#undef SHADER_ENTRY
|
||||
#undef BYTECODE_END
|
||||
|
||||
#define GET_VK_PROC_RET_FALSE_IF_ERR(GETPROCADDR, STRUCT, HANDLE, NAME) do { \
|
||||
STRUCT->NAME = (PFN_ ## NAME) GETPROCADDR(HANDLE, #NAME); \
|
||||
if (STRUCT->NAME == NULL) { \
|
||||
#define GET_VK_PROC_RET_FALSE_IF_ERR(GETPROCADDR, STRUCT, HANDLE, NAME) do { \
|
||||
(STRUCT)->NAME = (PFN_ ## NAME) GETPROCADDR(HANDLE, #NAME); \
|
||||
if ((STRUCT)->NAME == NULL) { \
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Required api is not supported. " #NAME " is missing.") \
|
||||
return JNI_FALSE; \
|
||||
} \
|
||||
@@ -72,20 +54,17 @@ static void vulkanLibClose() {
|
||||
ARRAY_FREE(geInstance->physicalDevices);
|
||||
if (geInstance->devices != NULL) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(geInstance->devices); i++) {
|
||||
if (geInstance->devices[i].enabledExtensions != NULL) {
|
||||
free(geInstance->devices[i].enabledExtensions);
|
||||
}
|
||||
if (geInstance->devices[i].enabledLayers != NULL) {
|
||||
free(geInstance->devices[i].enabledLayers);
|
||||
}
|
||||
if (geInstance->devices[i].name != NULL) {
|
||||
free(geInstance->devices[i].name);
|
||||
}
|
||||
if (geInstance->devices[i].vkDestroyDevice != NULL && geInstance->devices[i].device != NULL) {
|
||||
geInstance->devices[i].vkDestroyDevice(geInstance->devices[i].device, NULL);
|
||||
VKDevice* device = &geInstance->devices[i];
|
||||
VKRenderer_Destroy(device->renderer);
|
||||
VKTexturePool_Dispose(device->texturePool);
|
||||
ARRAY_FREE(device->enabledExtensions);
|
||||
ARRAY_FREE(device->enabledLayers);
|
||||
free(device->name);
|
||||
if (device->vkDestroyDevice != NULL && device->handle != NULL) {
|
||||
device->vkDestroyDevice(device->handle, NULL);
|
||||
}
|
||||
}
|
||||
free(geInstance->devices);
|
||||
ARRAY_FREE(geInstance->devices);
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
@@ -113,7 +92,7 @@ static PFN_vkGetInstanceProcAddr vulkanLibOpen() {
|
||||
pVulkanLib = dlopen(VULKAN_1_DLL, RTLD_NOW);
|
||||
}
|
||||
if (pVulkanLib == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Failed to load %s", VULKAN_DLL)
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Vulkan: Failed to load %s", VULKAN_DLL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -121,7 +100,7 @@ static PFN_vkGetInstanceProcAddr vulkanLibOpen() {
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) dlsym(pVulkanLib, "vkGetInstanceProcAddr");
|
||||
if (vkGetInstanceProcAddr == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR,
|
||||
"Failed to get proc address of vkGetInstanceProcAddr from %s", VULKAN_DLL)
|
||||
"Vulkan: Failed to get proc address of vkGetInstanceProcAddr from %s", VULKAN_DLL)
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
@@ -163,7 +142,7 @@ static VkBool32 debugCallback(
|
||||
J2dRlsTraceLn(level, pCallbackData->pMessage);
|
||||
|
||||
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
// raise(SIGABRT); TODO uncomment when all validation errors are fixed.
|
||||
VK_FATAL_ERROR("Unhandled Vulkan validation error");
|
||||
}
|
||||
return VK_FALSE;
|
||||
}
|
||||
@@ -181,10 +160,7 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
|
||||
uint32_t apiVersion = 0;
|
||||
|
||||
if (geInstance->vkEnumerateInstanceVersion(&apiVersion) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: unable to enumerate Vulkan instance version")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceVersion(&apiVersion)) return JNI_FALSE;
|
||||
|
||||
J2dRlsTraceLn3(J2D_TRACE_INFO, "Vulkan: Available (%d.%d.%d)",
|
||||
VK_API_VERSION_MAJOR(apiVersion),
|
||||
@@ -201,30 +177,14 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
|
||||
uint32_t extensionsCount;
|
||||
// Get the number of extensions and layers
|
||||
if (geInstance->vkEnumerateInstanceExtensionProperties(NULL, &extensionsCount, NULL) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: vkEnumerateInstanceExtensionProperties fails")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceExtensionProperties(NULL, &extensionsCount, NULL)) return JNI_FALSE;
|
||||
VkExtensionProperties extensions[extensionsCount];
|
||||
if (geInstance->vkEnumerateInstanceExtensionProperties(NULL, &extensionsCount, extensions) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: vkEnumerateInstanceExtensionProperties fails")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceExtensionProperties(NULL, &extensionsCount, extensions)) return JNI_FALSE;
|
||||
|
||||
uint32_t layersCount;
|
||||
if (geInstance->vkEnumerateInstanceLayerProperties(&layersCount, NULL) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: vkEnumerateInstanceLayerProperties fails")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceLayerProperties(&layersCount, NULL)) return JNI_FALSE;
|
||||
VkLayerProperties layers[layersCount];
|
||||
if (geInstance->vkEnumerateInstanceLayerProperties(&layersCount, layers) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: vkEnumerateInstanceLayerProperties fails")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceLayerProperties(&layersCount, layers)) return JNI_FALSE;
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " Supported instance layers:")
|
||||
for (uint32_t i = 0; i < layersCount; i++) {
|
||||
@@ -236,13 +196,13 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " %s", (char *) extensions[i].extensionName)
|
||||
}
|
||||
|
||||
pchar* enabledLayers = ARRAY_ALLOC(pchar, MAX_ENABLED_LAYERS);
|
||||
pchar* enabledExtensions = ARRAY_ALLOC(pchar, MAX_ENABLED_EXTENSIONS);
|
||||
pchar* enabledLayers = NULL;
|
||||
pchar* enabledExtensions = NULL;
|
||||
void *pNext = NULL;
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
ARRAY_PUSH_BACK(&enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||
ARRAY_PUSH_BACK(enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
ARRAY_PUSH_BACK(&enabledExtensions, VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
ARRAY_PUSH_BACK(enabledExtensions, VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
|
||||
// Check required layers & extensions.
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(enabledExtensions); i++) {
|
||||
@@ -273,7 +233,7 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
|
||||
VkValidationFeaturesEXT features = {};
|
||||
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
|
||||
features.enabledValidationFeatureCount = COUNT_OF(enables);
|
||||
features.enabledValidationFeatureCount = SARRAY_COUNT_OF(enables);
|
||||
features.pEnabledValidationFeatures = enables;
|
||||
|
||||
// Includes the validation features into the instance creation process
|
||||
@@ -295,8 +255,8 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
}
|
||||
|
||||
if (foundDebugLayer && foundDebugExt) {
|
||||
ARRAY_PUSH_BACK(&enabledLayers, VALIDATION_LAYER_NAME);
|
||||
ARRAY_PUSH_BACK(&enabledExtensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
ARRAY_PUSH_BACK(enabledLayers, VALIDATION_LAYER_NAME);
|
||||
ARRAY_PUSH_BACK(enabledExtensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
pNext = &features;
|
||||
} else {
|
||||
J2dRlsTraceLn2(J2D_TRACE_WARNING, "Vulkan: %s and %s are not supported",
|
||||
@@ -324,14 +284,12 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
.ppEnabledExtensionNames = (const char *const *) enabledExtensions
|
||||
};
|
||||
|
||||
if (geInstance->vkCreateInstance(&instanceCreateInfo, NULL, &geInstance->vkInstance) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Failed to create Vulkan instance")
|
||||
VK_IF_ERROR(geInstance->vkCreateInstance(&instanceCreateInfo, NULL, &geInstance->vkInstance)) {
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
return JNI_FALSE;
|
||||
} else {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "Vulkan: Instance Created")
|
||||
}
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "Vulkan: Instance Created")
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
|
||||
@@ -351,6 +309,7 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
INSTANCE_PROC(vkEnumerateDeviceLayerProperties);
|
||||
INSTANCE_PROC(vkEnumerateDeviceExtensionProperties);
|
||||
INSTANCE_PROC(vkCreateDevice);
|
||||
INSTANCE_PROC(vkDestroySurfaceKHR);
|
||||
INSTANCE_PROC(vkGetDeviceProcAddr);
|
||||
|
||||
// Create debug messenger
|
||||
@@ -359,6 +318,7 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
INSTANCE_PROC(vkDestroyDebugUtilsMessengerEXT);
|
||||
if (pNext) {
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||
.flags = 0,
|
||||
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
@@ -369,10 +329,8 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||
.pfnUserCallback = &debugCallback
|
||||
};
|
||||
if (geInstance->vkCreateDebugUtilsMessengerEXT(geInstance->vkInstance, &debugUtilsMessengerCreateInfo,
|
||||
NULL, &geInstance->debugMessenger) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_WARNING, "Vulkan: Failed to create debug messenger")
|
||||
}
|
||||
VK_IF_ERROR(geInstance->vkCreateDebugUtilsMessengerEXT(geInstance->vkInstance, &debugUtilsMessengerCreateInfo,
|
||||
NULL, &geInstance->debugMessenger)) {}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -382,13 +340,8 @@ static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstan
|
||||
|
||||
static jboolean VK_FindDevices() {
|
||||
uint32_t physicalDevicesCount;
|
||||
if (geInstance->vkEnumeratePhysicalDevices(geInstance->vkInstance,
|
||||
&physicalDevicesCount,
|
||||
NULL) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: vkEnumeratePhysicalDevices fails")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VK_IF_ERROR(geInstance->vkEnumeratePhysicalDevices(geInstance->vkInstance,
|
||||
&physicalDevicesCount, NULL)) return JNI_FALSE;
|
||||
|
||||
if (physicalDevicesCount == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Failed to find GPUs with Vulkan support")
|
||||
@@ -397,26 +350,12 @@ static jboolean VK_FindDevices() {
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "Vulkan: Found %d physical devices:", physicalDevicesCount)
|
||||
}
|
||||
|
||||
geInstance->physicalDevices = ARRAY_ALLOC(VkPhysicalDevice, physicalDevicesCount);
|
||||
if (geInstance->physicalDevices == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkPhysicalDevice")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
ARRAY_RESIZE(geInstance->physicalDevices, physicalDevicesCount);
|
||||
|
||||
if (geInstance->vkEnumeratePhysicalDevices(
|
||||
geInstance->vkInstance,
|
||||
&physicalDevicesCount,
|
||||
geInstance->physicalDevices) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: vkEnumeratePhysicalDevices fails")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VK_IF_ERROR(geInstance->vkEnumeratePhysicalDevices(geInstance->vkInstance, &physicalDevicesCount,
|
||||
geInstance->physicalDevices)) return JNI_FALSE;
|
||||
|
||||
geInstance->devices = ARRAY_ALLOC(VKLogicalDevice, physicalDevicesCount);
|
||||
if (geInstance->devices == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VKLogicalDevice")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
ARRAY_ENSURE_CAPACITY(geInstance->devices, physicalDevicesCount);
|
||||
|
||||
for (uint32_t i = 0; i < physicalDevicesCount; i++) {
|
||||
VkPhysicalDeviceVulkan12Features device12Features = {
|
||||
@@ -454,14 +393,7 @@ static jboolean VK_FindDevices() {
|
||||
uint32_t queueFamilyCount = 0;
|
||||
geInstance->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
geInstance->physicalDevices[i], &queueFamilyCount, NULL);
|
||||
|
||||
VkQueueFamilyProperties *queueFamilies = (VkQueueFamilyProperties*)calloc(queueFamilyCount,
|
||||
sizeof(VkQueueFamilyProperties));
|
||||
if (queueFamilies == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkQueueFamilyProperties")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
|
||||
geInstance->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
geInstance->physicalDevices[i], &queueFamilyCount, queueFamilies);
|
||||
int64_t queueFamily = -1;
|
||||
@@ -494,37 +426,28 @@ static jboolean VK_FindDevices() {
|
||||
queueFamily = j;
|
||||
}
|
||||
}
|
||||
free(queueFamilies);
|
||||
if (queueFamily == -1) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, " --------------------- Suitable queue not found, skipped")
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t layerCount;
|
||||
geInstance->vkEnumerateDeviceLayerProperties(geInstance->physicalDevices[i], &layerCount, NULL);
|
||||
VkLayerProperties *layers = (VkLayerProperties *) calloc(layerCount, sizeof(VkLayerProperties));
|
||||
if (layers == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkLayerProperties")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
geInstance->vkEnumerateDeviceLayerProperties(geInstance->physicalDevices[i], &layerCount, layers);
|
||||
VK_IF_ERROR(geInstance->vkEnumerateDeviceLayerProperties(geInstance->physicalDevices[i],
|
||||
&layerCount, NULL)) continue;
|
||||
VkLayerProperties layers[layerCount];
|
||||
VK_IF_ERROR(geInstance->vkEnumerateDeviceLayerProperties(geInstance->physicalDevices[i],
|
||||
&layerCount, layers)) continue;
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " Supported device layers:")
|
||||
for (uint32_t j = 0; j < layerCount; j++) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " %s", (char *) layers[j].layerName)
|
||||
}
|
||||
|
||||
uint32_t extensionCount;
|
||||
geInstance->vkEnumerateDeviceExtensionProperties(geInstance->physicalDevices[i], NULL, &extensionCount, NULL);
|
||||
VkExtensionProperties *extensions = (VkExtensionProperties *) calloc(
|
||||
extensionCount, sizeof(VkExtensionProperties));
|
||||
if (extensions == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkExtensionProperties")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
geInstance->vkEnumerateDeviceExtensionProperties(
|
||||
geInstance->physicalDevices[i], NULL, &extensionCount, extensions);
|
||||
VK_IF_ERROR(geInstance->vkEnumerateDeviceExtensionProperties(geInstance->physicalDevices[i],
|
||||
NULL, &extensionCount, NULL)) continue;
|
||||
VkExtensionProperties extensions[extensionCount];
|
||||
VK_IF_ERROR(geInstance->vkEnumerateDeviceExtensionProperties(geInstance->physicalDevices[i],
|
||||
NULL, &extensionCount, extensions)) continue;
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " Supported device extensions:")
|
||||
VkBool32 hasSwapChain = VK_FALSE;
|
||||
for (uint32_t j = 0; j < extensionCount; j++) {
|
||||
@@ -532,31 +455,18 @@ static jboolean VK_FindDevices() {
|
||||
hasSwapChain = hasSwapChain ||
|
||||
strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, extensions[j].extensionName) == 0;
|
||||
}
|
||||
free(extensions);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " Found:")
|
||||
if (hasSwapChain) {
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " VK_KHR_SWAPCHAIN_EXTENSION_NAME")
|
||||
}
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "Vulkan: Found device extensions:")
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " " VK_KHR_SWAPCHAIN_EXTENSION_NAME " = %s", hasSwapChain ? "true" : "false")
|
||||
|
||||
if (!hasSwapChain) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO,
|
||||
" --------------------- Required VK_KHR_SWAPCHAIN_EXTENSION_NAME not found, skipped")
|
||||
" --------------------- Required " VK_KHR_SWAPCHAIN_EXTENSION_NAME " not found, skipped")
|
||||
continue;
|
||||
}
|
||||
|
||||
pchar* deviceEnabledLayers = ARRAY_ALLOC(pchar, MAX_ENABLED_LAYERS);
|
||||
if (deviceEnabledLayers == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot allocate deviceEnabledLayers array")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
pchar* deviceEnabledExtensions = ARRAY_ALLOC(pchar, MAX_ENABLED_EXTENSIONS);
|
||||
if (deviceEnabledExtensions == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot allocate deviceEnabledExtensions array")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ARRAY_PUSH_BACK(&deviceEnabledExtensions, VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
pchar* deviceEnabledLayers = NULL;
|
||||
pchar* deviceEnabledExtensions = NULL;
|
||||
ARRAY_PUSH_BACK(deviceEnabledExtensions, VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
|
||||
// Validation layer
|
||||
#ifdef DEBUG
|
||||
@@ -564,7 +474,7 @@ static jboolean VK_FindDevices() {
|
||||
for (uint32_t j = 0; j < layerCount; j++) {
|
||||
if (strcmp(VALIDATION_LAYER_NAME, layers[j].layerName) == 0) {
|
||||
validationLayerNotSupported = 0;
|
||||
ARRAY_PUSH_BACK(&deviceEnabledLayers, VALIDATION_LAYER_NAME);
|
||||
ARRAY_PUSH_BACK(deviceEnabledLayers, VALIDATION_LAYER_NAME);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -572,32 +482,31 @@ static jboolean VK_FindDevices() {
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, " %s device layer is not supported", VALIDATION_LAYER_NAME)
|
||||
}
|
||||
#endif
|
||||
free(layers);
|
||||
char* deviceName = strdup(deviceProperties2.properties.deviceName);
|
||||
if (deviceName == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot duplicate deviceName")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ARRAY_PUSH_BACK(&geInstance->devices,
|
||||
((VKLogicalDevice) {
|
||||
ARRAY_PUSH_BACK(geInstance->devices,
|
||||
((VKDevice) {
|
||||
.name = deviceName,
|
||||
.device = VK_NULL_HANDLE,
|
||||
.handle = VK_NULL_HANDLE,
|
||||
.physicalDevice = geInstance->physicalDevices[i],
|
||||
.queueFamily = queueFamily,
|
||||
.enabledLayers = deviceEnabledLayers,
|
||||
.enabledExtensions = deviceEnabledExtensions,
|
||||
.enabledExtensions = deviceEnabledExtensions
|
||||
}));
|
||||
}
|
||||
if (ARRAY_SIZE(geInstance->devices) == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "No compatible device found")
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: No compatible device found")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static jboolean VK_InitLogicalDevice(VKLogicalDevice* logicalDevice) {
|
||||
if (logicalDevice->device != VK_NULL_HANDLE) {
|
||||
static jboolean VK_InitDevice(VKDevice* device) {
|
||||
if (device->handle != VK_NULL_HANDLE) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
if (geInstance == NULL) {
|
||||
@@ -606,7 +515,7 @@ static jboolean VK_InitLogicalDevice(VKLogicalDevice* logicalDevice) {
|
||||
}
|
||||
if (verbose) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(geInstance->devices); i++) {
|
||||
fprintf(stderr, " %c%d: %s\n", &geInstance->devices[i] == logicalDevice ? '*' : ' ',
|
||||
fprintf(stderr, " %c%d: %s\n", &geInstance->devices[i] == device ? '*' : ' ',
|
||||
i, geInstance->devices[i].name);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
@@ -615,48 +524,58 @@ static jboolean VK_InitLogicalDevice(VKLogicalDevice* logicalDevice) {
|
||||
float queuePriority = 1.0f;
|
||||
VkDeviceQueueCreateInfo queueCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.queueFamilyIndex = logicalDevice->queueFamily, // obtained separately
|
||||
.queueFamilyIndex = device->queueFamily, // obtained separately
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority
|
||||
};
|
||||
|
||||
VkPhysicalDeviceFeatures features10 = { .logicOp = VK_TRUE };
|
||||
VkPhysicalDeviceVulkan12Features features12 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
.timelineSemaphore = VK_TRUE
|
||||
};
|
||||
void *pNext = &features12;
|
||||
|
||||
VkDeviceCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.pNext = pNext,
|
||||
.flags = 0,
|
||||
.queueCreateInfoCount = 1,
|
||||
.pQueueCreateInfos = &queueCreateInfo,
|
||||
.enabledLayerCount = ARRAY_SIZE(logicalDevice->enabledLayers),
|
||||
.ppEnabledLayerNames = (const char *const *) logicalDevice->enabledLayers,
|
||||
.enabledExtensionCount = ARRAY_SIZE(logicalDevice->enabledExtensions),
|
||||
.ppEnabledExtensionNames = (const char *const *) logicalDevice->enabledExtensions,
|
||||
.enabledLayerCount = ARRAY_SIZE(device->enabledLayers),
|
||||
.ppEnabledLayerNames = (const char *const *) device->enabledLayers,
|
||||
.enabledExtensionCount = ARRAY_SIZE(device->enabledExtensions),
|
||||
.ppEnabledExtensionNames = (const char *const *) device->enabledExtensions,
|
||||
.pEnabledFeatures = &features10
|
||||
};
|
||||
|
||||
if (geInstance->vkCreateDevice(logicalDevice->physicalDevice, &createInfo, NULL, &logicalDevice->device) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Cannot create device:\n %s", logicalDevice->name)
|
||||
vulkanLibClose();
|
||||
VK_IF_ERROR(geInstance->vkCreateDevice(device->physicalDevice, &createInfo, NULL, &device->handle)) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Vulkan: Cannot create device: %s", device->name)
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VkDevice device = logicalDevice->device;
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "Logical device (%s) created", logicalDevice->name)
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "Vulkan: Device created (%s)", device->name)
|
||||
|
||||
#define DEVICE_PROC(NAME) GET_VK_PROC_RET_FALSE_IF_ERR(geInstance->vkGetDeviceProcAddr, logicalDevice, device, NAME)
|
||||
#define DEVICE_PROC(NAME) GET_VK_PROC_RET_FALSE_IF_ERR(geInstance->vkGetDeviceProcAddr, device, device->handle, NAME)
|
||||
DEVICE_PROC(vkDestroyDevice);
|
||||
DEVICE_PROC(vkCreateShaderModule);
|
||||
DEVICE_PROC(vkCreatePipelineLayout);
|
||||
DEVICE_PROC(vkCreateGraphicsPipelines);
|
||||
DEVICE_PROC(vkDestroyShaderModule);
|
||||
DEVICE_PROC(vkCreatePipelineLayout);
|
||||
DEVICE_PROC(vkDestroyPipelineLayout);
|
||||
DEVICE_PROC(vkCreateGraphicsPipelines);
|
||||
DEVICE_PROC(vkDestroyPipeline);
|
||||
DEVICE_PROC(vkCreateSwapchainKHR);
|
||||
DEVICE_PROC(vkDestroySwapchainKHR);
|
||||
DEVICE_PROC(vkGetSwapchainImagesKHR);
|
||||
DEVICE_PROC(vkCreateImageView);
|
||||
DEVICE_PROC(vkCreateFramebuffer);
|
||||
DEVICE_PROC(vkCreateCommandPool);
|
||||
DEVICE_PROC(vkDestroyCommandPool);
|
||||
DEVICE_PROC(vkAllocateCommandBuffers);
|
||||
DEVICE_PROC(vkFreeCommandBuffers);
|
||||
DEVICE_PROC(vkCreateSemaphore);
|
||||
DEVICE_PROC(vkDestroySemaphore);
|
||||
DEVICE_PROC(vkWaitSemaphores);
|
||||
DEVICE_PROC(vkGetSemaphoreCounterValue);
|
||||
DEVICE_PROC(vkCreateFence);
|
||||
DEVICE_PROC(vkGetDeviceQueue);
|
||||
DEVICE_PROC(vkWaitForFences);
|
||||
@@ -666,7 +585,11 @@ static jboolean VK_InitLogicalDevice(VKLogicalDevice* logicalDevice) {
|
||||
DEVICE_PROC(vkQueueSubmit);
|
||||
DEVICE_PROC(vkQueuePresentKHR);
|
||||
DEVICE_PROC(vkBeginCommandBuffer);
|
||||
DEVICE_PROC(vkCmdBlitImage);
|
||||
DEVICE_PROC(vkCmdPipelineBarrier);
|
||||
DEVICE_PROC(vkCmdBeginRenderPass);
|
||||
DEVICE_PROC(vkCmdExecuteCommands);
|
||||
DEVICE_PROC(vkCmdClearAttachments);
|
||||
DEVICE_PROC(vkCmdBindPipeline);
|
||||
DEVICE_PROC(vkCmdSetViewport);
|
||||
DEVICE_PROC(vkCmdSetScissor);
|
||||
@@ -675,9 +598,11 @@ static jboolean VK_InitLogicalDevice(VKLogicalDevice* logicalDevice) {
|
||||
DEVICE_PROC(vkEndCommandBuffer);
|
||||
DEVICE_PROC(vkCreateImage);
|
||||
DEVICE_PROC(vkCreateSampler);
|
||||
DEVICE_PROC(vkDestroySampler);
|
||||
DEVICE_PROC(vkAllocateMemory);
|
||||
DEVICE_PROC(vkBindImageMemory);
|
||||
DEVICE_PROC(vkCreateDescriptorSetLayout);
|
||||
DEVICE_PROC(vkDestroyDescriptorSetLayout);
|
||||
DEVICE_PROC(vkUpdateDescriptorSets);
|
||||
DEVICE_PROC(vkCreateDescriptorPool);
|
||||
DEVICE_PROC(vkAllocateDescriptorSets);
|
||||
@@ -690,6 +615,7 @@ static jboolean VK_InitLogicalDevice(VKLogicalDevice* logicalDevice) {
|
||||
DEVICE_PROC(vkUnmapMemory);
|
||||
DEVICE_PROC(vkCmdBindVertexBuffers);
|
||||
DEVICE_PROC(vkCreateRenderPass);
|
||||
DEVICE_PROC(vkDestroyRenderPass);
|
||||
DEVICE_PROC(vkDestroyBuffer);
|
||||
DEVICE_PROC(vkFreeMemory);
|
||||
DEVICE_PROC(vkDestroyImageView);
|
||||
@@ -698,67 +624,28 @@ static jboolean VK_InitLogicalDevice(VKLogicalDevice* logicalDevice) {
|
||||
DEVICE_PROC(vkFlushMappedMemoryRanges);
|
||||
DEVICE_PROC(vkCmdPushConstants);
|
||||
|
||||
// Create command pool
|
||||
VkCommandPoolCreateInfo poolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
.queueFamilyIndex = logicalDevice->queueFamily
|
||||
};
|
||||
if (logicalDevice->vkCreateCommandPool(device, &poolInfo, NULL, &logicalDevice->commandPool) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to create command pool!")
|
||||
device->vkGetDeviceQueue(device->handle, device->queueFamily, 0, &device->queue);
|
||||
if (device->queue == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "Vulkan: Failed to get device queue");
|
||||
VK_UNHANDLED_ERROR();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// Create command buffer
|
||||
VkCommandBufferAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = logicalDevice->commandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1
|
||||
};
|
||||
|
||||
if (logicalDevice->vkAllocateCommandBuffers(device, &allocInfo, &logicalDevice->commandBuffer) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to allocate command buffers!");
|
||||
device->renderer = VKRenderer_Create(device);
|
||||
if (!device->renderer) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot create renderer")
|
||||
VK_UNHANDLED_ERROR();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// Create semaphores
|
||||
VkSemaphoreCreateInfo semaphoreInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
|
||||
};
|
||||
|
||||
VkFenceCreateInfo fenceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT
|
||||
};
|
||||
|
||||
if (logicalDevice->vkCreateSemaphore(device, &semaphoreInfo, NULL, &logicalDevice->imageAvailableSemaphore) != VK_SUCCESS ||
|
||||
logicalDevice->vkCreateSemaphore(device, &semaphoreInfo, NULL, &logicalDevice->renderFinishedSemaphore) != VK_SUCCESS ||
|
||||
logicalDevice->vkCreateFence(device, &fenceInfo, NULL, &logicalDevice->inFlightFence) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to create semaphores!");
|
||||
device->texturePool = VKTexturePool_InitWithDevice(device);
|
||||
if (!device->texturePool) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot create texture pool")
|
||||
VK_UNHANDLED_ERROR();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
logicalDevice->vkGetDeviceQueue(device, logicalDevice->queueFamily, 0, &logicalDevice->queue);
|
||||
if (logicalDevice->queue == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to get device queue!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
VKTxVertex* vertices = ARRAY_ALLOC(VKTxVertex, 4);
|
||||
ARRAY_PUSH_BACK(&vertices, ((VKTxVertex){-1.0f, -1.0f, 0.0f, 0.0f}));
|
||||
ARRAY_PUSH_BACK(&vertices, ((VKTxVertex){1.0f, -1.0f, 1.0f, 0.0f}));
|
||||
ARRAY_PUSH_BACK(&vertices, ((VKTxVertex){-1.0f, 1.0f, 0.0f, 1.0f}));
|
||||
ARRAY_PUSH_BACK(&vertices, ((VKTxVertex){1.0f, 1.0f, 1.0f, 1.0f}));
|
||||
logicalDevice->blitVertexBuffer = ARRAY_TO_VERTEX_BUF(logicalDevice, vertices);
|
||||
if (!logicalDevice->blitVertexBuffer) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot create vertex buffer")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
ARRAY_FREE(vertices);
|
||||
|
||||
geInstance->currentDevice = logicalDevice;
|
||||
geInstance->currentDevice = device;
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
@@ -800,14 +687,11 @@ Java_sun_java2d_vulkan_VKInstance_initNative(JNIEnv *env, jclass wlge, jlong nat
|
||||
if (requestedDevice < 0 || (uint32_t)requestedDevice >= ARRAY_SIZE(geInstance->devices)) {
|
||||
requestedDevice = 0;
|
||||
}
|
||||
if (!VK_InitLogicalDevice(&geInstance->devices[requestedDevice])) {
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (!VK_CreateLogicalDeviceRenderers(geInstance->currentDevice)) {
|
||||
if (!VK_InitDevice(&geInstance->devices[requestedDevice])) {
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,38 +27,40 @@
|
||||
#ifndef VKBase_h_Included
|
||||
#define VKBase_h_Included
|
||||
#include "VKTypes.h"
|
||||
#include "VKTexturePool.h"
|
||||
|
||||
struct VKLogicalDevice {
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
VKRenderer* fillTexturePoly;
|
||||
VKRenderer* fillColorPoly;
|
||||
VKRenderer* fillMaxColorPoly;
|
||||
char* name;
|
||||
uint32_t queueFamily;
|
||||
pchar* enabledLayers;
|
||||
pchar* enabledExtensions;
|
||||
VkCommandPool commandPool;
|
||||
VkCommandBuffer commandBuffer;
|
||||
VkSemaphore imageAvailableSemaphore;
|
||||
VkSemaphore renderFinishedSemaphore;
|
||||
VkFence inFlightFence;
|
||||
VkQueue queue;
|
||||
VkSampler textureSampler;
|
||||
VKBuffer* blitVertexBuffer;
|
||||
struct VKDevice {
|
||||
VkDevice handle;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
char* name;
|
||||
uint32_t queueFamily;
|
||||
pchar* enabledLayers;
|
||||
pchar* enabledExtensions;
|
||||
VkQueue queue;
|
||||
|
||||
VKRenderer* renderer;
|
||||
VKTexturePool* texturePool;
|
||||
|
||||
PFN_vkDestroyDevice vkDestroyDevice;
|
||||
PFN_vkCreateShaderModule vkCreateShaderModule;
|
||||
PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
|
||||
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
|
||||
PFN_vkDestroyShaderModule vkDestroyShaderModule;
|
||||
PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
|
||||
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
|
||||
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
|
||||
PFN_vkDestroyPipeline vkDestroyPipeline;
|
||||
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
|
||||
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
|
||||
PFN_vkCreateImageView vkCreateImageView;
|
||||
PFN_vkCreateFramebuffer vkCreateFramebuffer;
|
||||
PFN_vkCreateCommandPool vkCreateCommandPool;
|
||||
PFN_vkDestroyCommandPool vkDestroyCommandPool;
|
||||
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
|
||||
PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
|
||||
PFN_vkCreateSemaphore vkCreateSemaphore;
|
||||
PFN_vkDestroySemaphore vkDestroySemaphore;
|
||||
PFN_vkWaitSemaphores vkWaitSemaphores;
|
||||
PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue;
|
||||
PFN_vkCreateFence vkCreateFence;
|
||||
PFN_vkGetDeviceQueue vkGetDeviceQueue;
|
||||
PFN_vkWaitForFences vkWaitForFences;
|
||||
@@ -68,7 +70,11 @@ struct VKLogicalDevice {
|
||||
PFN_vkQueueSubmit vkQueueSubmit;
|
||||
PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||
PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
|
||||
PFN_vkCmdBlitImage vkCmdBlitImage;
|
||||
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
|
||||
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
|
||||
PFN_vkCmdExecuteCommands vkCmdExecuteCommands;
|
||||
PFN_vkCmdClearAttachments vkCmdClearAttachments;
|
||||
PFN_vkCmdBindPipeline vkCmdBindPipeline;
|
||||
PFN_vkCmdSetViewport vkCmdSetViewport;
|
||||
PFN_vkCmdSetScissor vkCmdSetScissor;
|
||||
@@ -77,9 +83,11 @@ struct VKLogicalDevice {
|
||||
PFN_vkEndCommandBuffer vkEndCommandBuffer;
|
||||
PFN_vkCreateImage vkCreateImage;
|
||||
PFN_vkCreateSampler vkCreateSampler;
|
||||
PFN_vkDestroySampler vkDestroySampler;
|
||||
PFN_vkAllocateMemory vkAllocateMemory;
|
||||
PFN_vkBindImageMemory vkBindImageMemory;
|
||||
PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
|
||||
PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
|
||||
PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
|
||||
PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
|
||||
PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
|
||||
@@ -92,6 +100,7 @@ struct VKLogicalDevice {
|
||||
PFN_vkUnmapMemory vkUnmapMemory;
|
||||
PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
|
||||
PFN_vkCreateRenderPass vkCreateRenderPass;
|
||||
PFN_vkDestroyRenderPass vkDestroyRenderPass;
|
||||
PFN_vkDestroyBuffer vkDestroyBuffer;
|
||||
PFN_vkFreeMemory vkFreeMemory;
|
||||
PFN_vkDestroyImageView vkDestroyImageView;
|
||||
@@ -101,12 +110,11 @@ struct VKLogicalDevice {
|
||||
PFN_vkCmdPushConstants vkCmdPushConstants;
|
||||
};
|
||||
|
||||
|
||||
struct VKGraphicsEnvironment {
|
||||
VkInstance vkInstance;
|
||||
VkPhysicalDevice* physicalDevices;
|
||||
VKLogicalDevice* devices;
|
||||
VKLogicalDevice* currentDevice;
|
||||
VkInstance vkInstance;
|
||||
VkPhysicalDevice* physicalDevices;
|
||||
VKDevice* devices;
|
||||
VKDevice* currentDevice;
|
||||
|
||||
#if defined(DEBUG)
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
@@ -138,6 +146,7 @@ struct VKGraphicsEnvironment {
|
||||
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
|
||||
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
|
||||
PFN_vkCreateDevice vkCreateDevice;
|
||||
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
|
||||
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <Trace.h>
|
||||
#include "CArrayUtil.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKBuffer.h"
|
||||
|
||||
@@ -46,10 +45,11 @@ VkResult VKBuffer_FindMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeF
|
||||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
VKBuffer* VKBuffer_Create(VKLogicalDevice* logicalDevice, VkDeviceSize size,
|
||||
VKBuffer* VKBuffer_Create(VKDevice* device, VkDeviceSize size,
|
||||
VkBufferUsageFlags usage, VkMemoryPropertyFlags properties)
|
||||
{
|
||||
VKBuffer* buffer = malloc(sizeof (VKBuffer));
|
||||
VKBuffer* buffer = calloc(1, sizeof(VKBuffer));
|
||||
VK_RUNTIME_ASSERT(buffer);
|
||||
|
||||
VkBufferCreateInfo bufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
@@ -58,23 +58,22 @@ VKBuffer* VKBuffer_Create(VKLogicalDevice* logicalDevice, VkDeviceSize size,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
|
||||
if (logicalDevice->vkCreateBuffer(logicalDevice->device, &bufferInfo, NULL, &buffer->buffer) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to allocate descriptor sets!")
|
||||
VK_IF_ERROR(device->vkCreateBuffer(device->handle, &bufferInfo, NULL, &buffer->buffer)) {
|
||||
VKBuffer_free(device, buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer->size = size;
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
logicalDevice->vkGetBufferMemoryRequirements(logicalDevice->device, buffer->buffer, &memRequirements);
|
||||
device->vkGetBufferMemoryRequirements(device->handle, buffer->buffer, &memRequirements);
|
||||
|
||||
uint32_t memoryType;
|
||||
|
||||
if (VKBuffer_FindMemoryType(logicalDevice->physicalDevice,
|
||||
memRequirements.memoryTypeBits,
|
||||
properties, &memoryType) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to find memory!")
|
||||
VK_IF_ERROR(VKBuffer_FindMemoryType(device->physicalDevice,
|
||||
memRequirements.memoryTypeBits,
|
||||
properties, &memoryType)) {
|
||||
VKBuffer_free(device, buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -84,28 +83,28 @@ VKBuffer* VKBuffer_Create(VKLogicalDevice* logicalDevice, VkDeviceSize size,
|
||||
.memoryTypeIndex = memoryType
|
||||
};
|
||||
|
||||
if (logicalDevice->vkAllocateMemory(logicalDevice->device, &allocInfo, NULL, &buffer->memory) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to allocate buffer memory!");
|
||||
VK_IF_ERROR(device->vkAllocateMemory(device->handle, &allocInfo, NULL, &buffer->memory)) {
|
||||
VKBuffer_free(device, buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (logicalDevice->vkBindBufferMemory(logicalDevice->device, buffer->buffer, buffer->memory, 0) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to bind buffer memory!");
|
||||
VK_IF_ERROR(device->vkBindBufferMemory(device->handle, buffer->buffer, buffer->memory, 0)) {
|
||||
VKBuffer_free(device, buffer);
|
||||
return NULL;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
VKBuffer* VKBuffer_CreateFromData(VKLogicalDevice* logicalDevice, void* vertices, VkDeviceSize bufferSize)
|
||||
VKBuffer* VKBuffer_CreateFromData(VKDevice* device, void* vertices, VkDeviceSize bufferSize)
|
||||
{
|
||||
VKBuffer* buffer = VKBuffer_Create(logicalDevice, bufferSize,
|
||||
VKBuffer* buffer = VKBuffer_Create(device, bufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
void* data;
|
||||
if (logicalDevice->vkMapMemory(logicalDevice->device, buffer->memory, 0, bufferSize, 0, &data) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to map memory!");
|
||||
VK_IF_ERROR(device->vkMapMemory(device->handle, buffer->memory, 0, VK_WHOLE_SIZE, 0, &data)) {
|
||||
VKBuffer_free(device, buffer);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(data, vertices, bufferSize);
|
||||
@@ -119,23 +118,23 @@ VKBuffer* VKBuffer_CreateFromData(VKLogicalDevice* logicalDevice, void* vertices
|
||||
};
|
||||
|
||||
|
||||
if (logicalDevice->vkFlushMappedMemoryRanges(logicalDevice->device, 1, &memoryRange) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to flush memory!");
|
||||
VK_IF_ERROR(device->vkFlushMappedMemoryRanges(device->handle, 1, &memoryRange)) {
|
||||
VKBuffer_free(device, buffer);
|
||||
return NULL;
|
||||
}
|
||||
logicalDevice->vkUnmapMemory(logicalDevice->device, buffer->memory);
|
||||
device->vkUnmapMemory(device->handle, buffer->memory);
|
||||
buffer->size = bufferSize;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void VKBuffer_free(VKLogicalDevice* logicalDevice, VKBuffer* buffer) {
|
||||
void VKBuffer_free(VKDevice* device, VKBuffer* buffer) {
|
||||
if (buffer != NULL) {
|
||||
if (buffer->buffer != VK_NULL_HANDLE) {
|
||||
logicalDevice->vkDestroyBuffer(logicalDevice->device, buffer->buffer, NULL);
|
||||
device->vkDestroyBuffer(device->handle, buffer->buffer, NULL);
|
||||
}
|
||||
if (buffer->memory != VK_NULL_HANDLE) {
|
||||
logicalDevice->vkFreeMemory(logicalDevice->device, buffer->memory, NULL);
|
||||
device->vkFreeMemory(device->handle, buffer->memory, NULL);
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ struct VKBuffer {
|
||||
VkResult VKBuffer_FindMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter,
|
||||
VkMemoryPropertyFlags properties, uint32_t* pMemoryType);
|
||||
|
||||
VKBuffer* VKBuffer_Create(VKLogicalDevice* logicalDevice, VkDeviceSize size,
|
||||
VKBuffer* VKBuffer_Create(VKDevice* device, VkDeviceSize size,
|
||||
VkBufferUsageFlags usage, VkMemoryPropertyFlags properties);
|
||||
|
||||
VKBuffer* VKBuffer_CreateFromData(VKLogicalDevice* logicalDevice, void* vertices, VkDeviceSize bufferSize);
|
||||
VKBuffer* VKBuffer_CreateFromData(VKDevice* device, void* vertices, VkDeviceSize bufferSize);
|
||||
|
||||
void VKBuffer_free(VKLogicalDevice* logicalDevice, VKBuffer* buffer);
|
||||
void VKBuffer_free(VKDevice* device, VKBuffer* buffer);
|
||||
|
||||
#endif // VKBuffer_h_Included
|
||||
|
||||
@@ -24,14 +24,13 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <Trace.h>
|
||||
#include "CArrayUtil.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKBuffer.h"
|
||||
#include "VKImage.h"
|
||||
|
||||
|
||||
VkBool32 VKImage_CreateView(VKLogicalDevice* logicalDevice, VKImage* image) {
|
||||
VkBool32 VKImage_CreateView(VKDevice* device, VKImage* image) {
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = image->image,
|
||||
@@ -44,49 +43,19 @@ VkBool32 VKImage_CreateView(VKLogicalDevice* logicalDevice, VKImage* image) {
|
||||
.subresourceRange.layerCount = 1,
|
||||
};
|
||||
|
||||
if (logicalDevice->vkCreateImageView(logicalDevice->device, &viewInfo, NULL, &image->view) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot surface image view\n");
|
||||
VK_IF_ERROR(device->vkCreateImageView(device->handle, &viewInfo, NULL, &image->view)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
VkBool32 VKImage_CreateFramebuffer(VKLogicalDevice* logicalDevice, VKImage *image, VkRenderPass renderPass) {
|
||||
VkImageView attachments[] = {
|
||||
image->view
|
||||
};
|
||||
|
||||
VkFramebufferCreateInfo framebufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.renderPass = renderPass,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = attachments,
|
||||
.width = image->extent.width,
|
||||
.height = image->extent.height,
|
||||
.layers = 1
|
||||
};
|
||||
|
||||
if (logicalDevice->vkCreateFramebuffer(logicalDevice->device, &framebufferInfo, NULL,
|
||||
&image->framebuffer) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to create framebuffer!")
|
||||
return VK_FALSE;
|
||||
}
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
VKImage* VKImage_Create(VKLogicalDevice* logicalDevice,
|
||||
uint32_t width, uint32_t height,
|
||||
VKImage* VKImage_Create(VKDevice* device, uint32_t width, uint32_t height,
|
||||
VkFormat format, VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties)
|
||||
{
|
||||
VKImage* image = malloc(sizeof (VKImage));
|
||||
|
||||
if (!image) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot allocate data for image")
|
||||
return NULL;
|
||||
}
|
||||
VKImage* image = calloc(1, sizeof(VKImage));
|
||||
VK_RUNTIME_ASSERT(image);
|
||||
|
||||
image->format = format;
|
||||
image->extent = (VkExtent2D) {width, height};
|
||||
@@ -107,22 +76,20 @@ VKImage* VKImage_Create(VKLogicalDevice* logicalDevice,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
|
||||
if (logicalDevice->vkCreateImage(logicalDevice->device, &imageInfo, NULL, &image->image) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot create surface image")
|
||||
VKImage_free(logicalDevice, image);
|
||||
VK_IF_ERROR(device->vkCreateImage(device->handle, &imageInfo, NULL, &image->image)) {
|
||||
VKImage_free(device, image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
logicalDevice->vkGetImageMemoryRequirements(logicalDevice->device, image->image, &memRequirements);
|
||||
device->vkGetImageMemoryRequirements(device->handle, image->image, &memRequirements);
|
||||
|
||||
uint32_t memoryType;
|
||||
if (VKBuffer_FindMemoryType(logicalDevice->physicalDevice,
|
||||
VK_IF_ERROR(VKBuffer_FindMemoryType(device->physicalDevice,
|
||||
memRequirements.memoryTypeBits,
|
||||
properties, &memoryType) != VK_SUCCESS)
|
||||
properties, &memoryType))
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Failed to find memory")
|
||||
VKImage_free(logicalDevice, image);
|
||||
VKImage_free(device, image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -132,92 +99,41 @@ VKImage* VKImage_Create(VKLogicalDevice* logicalDevice,
|
||||
.memoryTypeIndex = memoryType
|
||||
};
|
||||
|
||||
if (logicalDevice->vkAllocateMemory(logicalDevice->device, &allocInfo, NULL, &image->memory) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Failed to allocate image memory");
|
||||
VKImage_free(logicalDevice, image);
|
||||
VK_IF_ERROR(device->vkAllocateMemory(device->handle, &allocInfo, NULL, &image->memory)) {
|
||||
VKImage_free(device, image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
logicalDevice->vkBindImageMemory(logicalDevice->device, image->image, image->memory, 0);
|
||||
VK_IF_ERROR(device->vkBindImageMemory(device->handle, image->image, image->memory, 0)) {
|
||||
VKImage_free(device, image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!VKImage_CreateView(logicalDevice, image)) {
|
||||
VKImage_free(logicalDevice, image);
|
||||
if (!VKImage_CreateView(device, image)) {
|
||||
VKImage_free(device, image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
VKImage* VKImage_CreateImageArrayFromSwapChain(VKLogicalDevice* logicalDevice,
|
||||
VkSwapchainKHR swapchainKhr, VkRenderPass renderPass,
|
||||
VkFormat format, VkExtent2D extent)
|
||||
{
|
||||
uint32_t swapChainImagesCount;
|
||||
if (logicalDevice->vkGetSwapchainImagesKHR(logicalDevice->device, swapchainKhr, &swapChainImagesCount,
|
||||
NULL) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot get swapchain images\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (swapChainImagesCount == 0) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "No swapchain images found\n");
|
||||
return NULL;
|
||||
}
|
||||
VkImage swapChainImages[swapChainImagesCount];
|
||||
|
||||
if (logicalDevice->vkGetSwapchainImagesKHR(logicalDevice->device, swapchainKhr, &swapChainImagesCount,
|
||||
swapChainImages) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot get swapchain images\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VKImage* images = ARRAY_ALLOC(VKImage, swapChainImagesCount);
|
||||
for (uint32_t i = 0; i < swapChainImagesCount; i++) {
|
||||
ARRAY_PUSH_BACK(&images, ((VKImage){
|
||||
.image = swapChainImages[i],
|
||||
.memory = VK_NULL_HANDLE,
|
||||
.format = format,
|
||||
.extent = extent,
|
||||
.noImageDealloc = VK_TRUE
|
||||
}));
|
||||
|
||||
if (!VKImage_CreateView(logicalDevice, &ARRAY_LAST(images))) {
|
||||
ARRAY_APPLY_TRAILING(images, VKImage_dealloc, logicalDevice);
|
||||
ARRAY_FREE(images);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!VKImage_CreateFramebuffer(logicalDevice, &ARRAY_LAST(images), renderPass)) {
|
||||
ARRAY_APPLY_TRAILING(images, VKImage_dealloc, logicalDevice);
|
||||
ARRAY_FREE(images);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
void VKImage_dealloc(VKLogicalDevice* logicalDevice, VKImage* image) {
|
||||
void VKImage_free(VKDevice* device, VKImage* image) {
|
||||
if (!image) return;
|
||||
|
||||
if (image->framebuffer != VK_NULL_HANDLE) {
|
||||
logicalDevice->vkDestroyFramebuffer(logicalDevice->device, image->framebuffer, NULL);
|
||||
}
|
||||
|
||||
if (image->view != VK_NULL_HANDLE) {
|
||||
logicalDevice->vkDestroyImageView(logicalDevice->device, image->view, NULL);
|
||||
device->vkDestroyImageView(device->handle, image->view, NULL);
|
||||
image->view = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (image->memory != VK_NULL_HANDLE) {
|
||||
logicalDevice->vkFreeMemory(logicalDevice->device, image->memory, NULL);
|
||||
device->vkFreeMemory(device->handle, image->memory, NULL);
|
||||
image->memory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (image->image != VK_NULL_HANDLE && !image->noImageDealloc) {
|
||||
logicalDevice->vkDestroyImage(logicalDevice->device, image->image, NULL);
|
||||
if (image->image != VK_NULL_HANDLE) {
|
||||
device->vkDestroyImage(device->handle, image->image, NULL);
|
||||
image->image = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void VKImage_free(VKLogicalDevice* logicalDevice, VKImage* image) {
|
||||
VKImage_dealloc(logicalDevice, image);
|
||||
free(image);
|
||||
}
|
||||
@@ -32,28 +32,15 @@
|
||||
struct VKImage {
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
VkFramebuffer framebuffer;
|
||||
VkImageView view;
|
||||
VkFormat format;
|
||||
VkExtent2D extent;
|
||||
VkBool32 noImageDealloc;
|
||||
};
|
||||
|
||||
VKImage* VKImage_Create(VKLogicalDevice* logicalDevice,
|
||||
uint32_t width, uint32_t height,
|
||||
VKImage* VKImage_Create(VKDevice* device, uint32_t width, uint32_t height,
|
||||
VkFormat format, VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties);
|
||||
|
||||
VKImage* VKImage_CreateImageArrayFromSwapChain(VKLogicalDevice* logicalDevice,
|
||||
VkSwapchainKHR swapchainKhr,
|
||||
VkRenderPass renderPass,
|
||||
VkFormat format,
|
||||
VkExtent2D extent);
|
||||
|
||||
VkBool32 VKImage_CreateFramebuffer(VKLogicalDevice* logicalDevice,
|
||||
VKImage *image, VkRenderPass renderPass);
|
||||
|
||||
void VKImage_free(VKLogicalDevice* logicalDevice, VKImage* image);
|
||||
void VKImage_dealloc(VKLogicalDevice* logicalDevice, VKImage* image);
|
||||
void VKImage_free(VKDevice* device, VKImage* image);
|
||||
#endif // VKImage_h_Included
|
||||
|
||||
433
src/java.desktop/share/native/common/java2d/vulkan/VKPipelines.c
Normal file
433
src/java.desktop/share/native/common/java2d/vulkan/VKPipelines.c
Normal file
@@ -0,0 +1,433 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKPipelines.h"
|
||||
|
||||
#define INCLUDE_BYTECODE
|
||||
#define SHADER_ENTRY(NAME, TYPE) static uint32_t NAME ## _ ## TYPE ## _data[] = {
|
||||
#define BYTECODE_END };
|
||||
#include "vulkan/shader_list.h"
|
||||
#undef INCLUDE_BYTECODE
|
||||
#undef SHADER_ENTRY
|
||||
#undef BYTECODE_END
|
||||
|
||||
struct VKPipelineSet {
|
||||
VkPipeline pipelines[PIPELINE_COUNT];
|
||||
};
|
||||
|
||||
struct VKShaders {
|
||||
# define SHADER_ENTRY(NAME, TYPE) VkPipelineShaderStageCreateInfo NAME ## _ ## TYPE;
|
||||
# include "vulkan/shader_list.h"
|
||||
# undef SHADER_ENTRY
|
||||
};
|
||||
|
||||
static void VKPipelines_DestroyShaders(VKDevice* device, VKShaders* shaders) {
|
||||
assert(device != NULL);
|
||||
if (shaders == NULL) return;
|
||||
# define SHADER_ENTRY(NAME, TYPE) if (shaders->NAME##_##TYPE.module != VK_NULL_HANDLE) \
|
||||
device->vkDestroyShaderModule(device->handle, shaders->NAME##_##TYPE.module, NULL);
|
||||
# include "vulkan/shader_list.h"
|
||||
# undef SHADER_ENTRY
|
||||
free(shaders);
|
||||
}
|
||||
|
||||
static VKShaders* VKPipelines_CreateShaders(VKDevice* device) {
|
||||
assert(device != NULL);
|
||||
const VkShaderStageFlagBits vert = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
const VkShaderStageFlagBits frag = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VKShaders* shaders = (VKShaders*) calloc(1, sizeof(VKShaders));
|
||||
VK_RUNTIME_ASSERT(shaders);
|
||||
VkShaderModuleCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
||||
# define SHADER_ENTRY(NAME, TYPE) \
|
||||
shaders->NAME ## _ ## TYPE = (VkPipelineShaderStageCreateInfo) { \
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, \
|
||||
.stage = (TYPE), \
|
||||
.pName = "main" \
|
||||
}; \
|
||||
createInfo.codeSize = sizeof(NAME ## _ ## TYPE ## _data); \
|
||||
createInfo.pCode = NAME ## _ ## TYPE ## _data; \
|
||||
VK_IF_ERROR(device->vkCreateShaderModule(device->handle, \
|
||||
&createInfo, NULL, &shaders->NAME##_##TYPE.module)) { \
|
||||
VKPipelines_DestroyShaders(device, shaders); \
|
||||
return NULL; \
|
||||
}
|
||||
# include "vulkan/shader_list.h"
|
||||
# undef SHADER_ENTRY
|
||||
return shaders;
|
||||
}
|
||||
|
||||
#define MAKE_INPUT_STATE(TYPE, ...) \
|
||||
static const VkVertexInputAttributeDescription attributes[] = { __VA_ARGS__ }; \
|
||||
static const VkVertexInputBindingDescription binding = { \
|
||||
.binding = 0, \
|
||||
.stride = sizeof(TYPE), \
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX \
|
||||
}; \
|
||||
static const VkPipelineVertexInputStateCreateInfo inputState = { \
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, \
|
||||
.vertexBindingDescriptionCount = 1, \
|
||||
.pVertexBindingDescriptions = &binding, \
|
||||
.vertexAttributeDescriptionCount = SARRAY_COUNT_OF(attributes), \
|
||||
.pVertexAttributeDescriptions = attributes \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
VkGraphicsPipelineCreateInfo createInfo;
|
||||
VkPipelineMultisampleStateCreateInfo multisampleState;
|
||||
VkPipelineColorBlendStateCreateInfo colorBlendState;
|
||||
VkPipelineDynamicStateCreateInfo dynamicState;
|
||||
VkDynamicState dynamicStates[2];
|
||||
} PipelineCreateState;
|
||||
|
||||
typedef struct {
|
||||
VkPipelineShaderStageCreateInfo createInfos[2]; // vert + frag
|
||||
} ShaderStages;
|
||||
|
||||
/**
|
||||
* Init default pipeline state. Some members are left uninitialized:
|
||||
* - pStages (but stageCount is set to 2)
|
||||
* - pVertexInputState
|
||||
* - pInputAssemblyState
|
||||
* - colorBlendState.pAttachments (but attachmentCount is set to 1)
|
||||
* - createInfo.layout
|
||||
* - createInfo.renderPass
|
||||
* - renderingCreateInfo.pColorAttachmentFormats (but colorAttachmentCount is set to 1)
|
||||
*/
|
||||
static void VKPipelines_InitPipelineCreateState(PipelineCreateState* state) {
|
||||
static const VkViewport viewport = {};
|
||||
static const VkRect2D scissor = {};
|
||||
static const VkPipelineViewportStateCreateInfo viewportState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1,
|
||||
.pViewports = &viewport,
|
||||
.scissorCount = 1,
|
||||
.pScissors = &scissor
|
||||
};
|
||||
static const VkPipelineRasterizationStateCreateInfo rasterizationState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.lineWidth = 1.0f
|
||||
};
|
||||
state->multisampleState = (VkPipelineMultisampleStateCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
|
||||
};
|
||||
state->colorBlendState = (VkPipelineColorBlendStateCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_XOR,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = NULL,
|
||||
};
|
||||
state->dynamicState = (VkPipelineDynamicStateCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = state->dynamicStates
|
||||
};
|
||||
state->dynamicStates[0] = VK_DYNAMIC_STATE_VIEWPORT;
|
||||
state->dynamicStates[1] = VK_DYNAMIC_STATE_SCISSOR;
|
||||
state->createInfo = (VkGraphicsPipelineCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.stageCount = 2,
|
||||
.pViewportState = &viewportState,
|
||||
.pRasterizationState = &rasterizationState,
|
||||
.pMultisampleState = &state->multisampleState,
|
||||
.pColorBlendState = &state->colorBlendState,
|
||||
.pDynamicState = &state->dynamicState,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = -1
|
||||
};
|
||||
}
|
||||
|
||||
static const VkPipelineInputAssemblyStateCreateInfo INPUT_ASSEMBLY_STATE_TRIANGLE_STRIP = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
|
||||
};
|
||||
static const VkPipelineInputAssemblyStateCreateInfo INPUT_ASSEMBLY_STATE_TRIANGLE_LIST = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
|
||||
};
|
||||
static const VkPipelineInputAssemblyStateCreateInfo INPUT_ASSEMBLY_STATE_LINE_LIST = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST
|
||||
};
|
||||
|
||||
const VkPipelineColorBlendAttachmentState BLEND_STATE = {
|
||||
.blendEnable = VK_FALSE,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
|
||||
};
|
||||
|
||||
static void VKPipelines_DestroyPipelineSet(VKDevice* device, VKPipelineSet* set) {
|
||||
if (set == NULL) return;
|
||||
for (uint32_t i = 0; i < PIPELINE_COUNT; i++) {
|
||||
device->vkDestroyPipeline(device->handle, set->pipelines[i], NULL);
|
||||
}
|
||||
free(set);
|
||||
}
|
||||
|
||||
static VKPipelineSet* VKPipelines_CreatePipelineSet(VKRenderPassContext* renderPassContext) {
|
||||
assert(renderPassContext != NULL && renderPassContext->pipelineContext != NULL);
|
||||
VKPipelineContext* pipelineContext = renderPassContext->pipelineContext;
|
||||
|
||||
VKPipelineSet* set = calloc(1, sizeof(VKPipelineSet));
|
||||
VK_RUNTIME_ASSERT(set);
|
||||
VKDevice* device = pipelineContext->device;
|
||||
VKShaders* shaders = pipelineContext->shaders;
|
||||
|
||||
// Setup default pipeline parameters.
|
||||
PipelineCreateState base;
|
||||
VKPipelines_InitPipelineCreateState(&base);
|
||||
base.createInfo.layout = pipelineContext->pipelineLayout;
|
||||
base.createInfo.renderPass = renderPassContext->renderPass;
|
||||
base.colorBlendState.pAttachments = &BLEND_STATE;
|
||||
assert(base.dynamicState.dynamicStateCount <= SARRAY_COUNT_OF(base.dynamicStates));
|
||||
|
||||
ShaderStages stages[PIPELINE_COUNT];
|
||||
VkGraphicsPipelineCreateInfo createInfos[PIPELINE_COUNT];
|
||||
for (uint32_t i = 0; i < PIPELINE_COUNT; i++) {
|
||||
createInfos[i] = base.createInfo;
|
||||
createInfos[i].pStages = stages[i].createInfos;
|
||||
}
|
||||
|
||||
static const VkVertexInputAttributeDescription positionAttribute = {
|
||||
.location = 0,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = 0
|
||||
};
|
||||
static const VkVertexInputAttributeDescription texcoordAttribute = {
|
||||
.location = 1,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = sizeof(float) * 2
|
||||
};
|
||||
|
||||
{ // Setup plain color pipelines.
|
||||
MAKE_INPUT_STATE(VKVertex, positionAttribute);
|
||||
createInfos[PIPELINE_DRAW_COLOR].pVertexInputState = createInfos[PIPELINE_FILL_COLOR].pVertexInputState = &inputState;
|
||||
createInfos[PIPELINE_FILL_COLOR].pInputAssemblyState = &INPUT_ASSEMBLY_STATE_TRIANGLE_LIST;
|
||||
createInfos[PIPELINE_DRAW_COLOR].pInputAssemblyState = &INPUT_ASSEMBLY_STATE_LINE_LIST;
|
||||
stages[PIPELINE_DRAW_COLOR] = stages[PIPELINE_FILL_COLOR] = (ShaderStages) {{ shaders->color_vert, shaders->color_frag }};
|
||||
}
|
||||
|
||||
{ // Setup texture pipeline.
|
||||
MAKE_INPUT_STATE(VKTxVertex, positionAttribute, texcoordAttribute);
|
||||
createInfos[PIPELINE_BLIT].pVertexInputState = &inputState;
|
||||
createInfos[PIPELINE_BLIT].pInputAssemblyState = &INPUT_ASSEMBLY_STATE_TRIANGLE_STRIP;
|
||||
createInfos[PIPELINE_BLIT].layout = pipelineContext->texturePipelineLayout;
|
||||
stages[PIPELINE_BLIT] = (ShaderStages) {{ shaders->blit_vert, shaders->blit_frag }};
|
||||
}
|
||||
|
||||
// Create pipelines.
|
||||
// TODO pipeline cache
|
||||
VK_IF_ERROR(device->vkCreateGraphicsPipelines(device->handle, VK_NULL_HANDLE, PIPELINE_COUNT,
|
||||
createInfos, NULL, set->pipelines)) VK_UNHANDLED_ERROR();
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "VKPipelines_CreatePipelineSet");
|
||||
return set;
|
||||
}
|
||||
|
||||
static VkResult VKPipelines_InitRenderPass(VKDevice* device, VKRenderPassContext* renderPassContext) {
|
||||
VkAttachmentDescription colorAttachment = {
|
||||
.format = renderPassContext->format,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
};
|
||||
VkAttachmentReference colorReference = {
|
||||
.attachment = 0,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
};
|
||||
VkSubpassDescription subpassDescription = {
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.colorAttachmentCount = 1,
|
||||
.pColorAttachments = &colorReference
|
||||
};
|
||||
// TODO this is probably not needed?
|
||||
// // Subpass dependencies for layout transitions
|
||||
// VkSubpassDependency dependency = {
|
||||
// .srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
// .dstSubpass = 0,
|
||||
// .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
// .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
// .srcAccessMask = 0,
|
||||
// .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
// };
|
||||
VkRenderPassCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &colorAttachment,
|
||||
.subpassCount = 1,
|
||||
.pSubpasses = &subpassDescription,
|
||||
.dependencyCount = 0,
|
||||
.pDependencies = NULL
|
||||
};
|
||||
return device->vkCreateRenderPass(device->handle, &createInfo, NULL, &renderPassContext->renderPass);
|
||||
}
|
||||
|
||||
static void VKPipelines_DestroyRenderPassContext(VKRenderPassContext* renderPassContext) {
|
||||
if (renderPassContext == NULL) return;
|
||||
VKDevice* device = renderPassContext->pipelineContext->device;
|
||||
assert(device != NULL);
|
||||
VKPipelines_DestroyPipelineSet(device, renderPassContext->pipelineSet);
|
||||
device->vkDestroyRenderPass(device->handle, renderPassContext->renderPass, NULL);
|
||||
free(renderPassContext);
|
||||
}
|
||||
|
||||
static VKRenderPassContext* VKPipelines_CreateRenderPassContext(VKPipelineContext* pipelineContext, VkFormat format) {
|
||||
assert(pipelineContext != NULL && pipelineContext->device != NULL);
|
||||
VKRenderPassContext* renderPassContext = calloc(1, sizeof(VKRenderPassContext));
|
||||
VK_RUNTIME_ASSERT(renderPassContext);
|
||||
renderPassContext->pipelineContext = pipelineContext;
|
||||
renderPassContext->format = format;
|
||||
|
||||
VK_IF_ERROR(VKPipelines_InitRenderPass(pipelineContext->device, renderPassContext)) {
|
||||
VKPipelines_DestroyRenderPassContext(renderPassContext);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return renderPassContext;
|
||||
}
|
||||
|
||||
static VkResult VKPipelines_InitPipelineLayouts(VKDevice* device, VKPipelineContext* pipelines) {
|
||||
assert(device != NULL && pipelines != NULL);
|
||||
VkResult result;
|
||||
|
||||
// We want all our pipelines to have same push constant range to ensure common state is compatible between pipelines.
|
||||
VkPushConstantRange pushConstantRange = {
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0,
|
||||
.size = sizeof(float) * 4
|
||||
};
|
||||
VkPipelineLayoutCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 0,
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &pushConstantRange
|
||||
};
|
||||
result = device->vkCreatePipelineLayout(device->handle, &createInfo, NULL, &pipelines->pipelineLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
VkDescriptorSetLayoutBinding textureLayoutBinding = {
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.pImmutableSamplers = NULL
|
||||
};
|
||||
VkDescriptorSetLayoutCreateInfo textureDescriptorSetLayoutCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = 1,
|
||||
.pBindings = &textureLayoutBinding
|
||||
};
|
||||
result = device->vkCreateDescriptorSetLayout(device->handle, &textureDescriptorSetLayoutCreateInfo, NULL, &pipelines->textureDescriptorSetLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &pipelines->textureDescriptorSetLayout;
|
||||
result = device->vkCreatePipelineLayout(device->handle, &createInfo, NULL, &pipelines->texturePipelineLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKPipelineContext* VKPipelines_CreateContext(VKDevice* device) {
|
||||
assert(device != NULL);
|
||||
VKPipelineContext* pipelineContext = (VKPipelineContext*) calloc(1, sizeof(VKPipelineContext));
|
||||
VK_RUNTIME_ASSERT(pipelineContext);
|
||||
pipelineContext->device = device;
|
||||
|
||||
pipelineContext->shaders = VKPipelines_CreateShaders(device);
|
||||
if (pipelineContext->shaders == NULL) {
|
||||
VKPipelines_DestroyContext(pipelineContext);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VK_IF_ERROR(VKPipelines_InitPipelineLayouts(device, pipelineContext)) {
|
||||
VKPipelines_DestroyContext(pipelineContext);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create sampler.
|
||||
VkSamplerCreateInfo samplerCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.magFilter = VK_FILTER_LINEAR,
|
||||
.minFilter = VK_FILTER_LINEAR,
|
||||
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT
|
||||
};
|
||||
VK_IF_ERROR(device->vkCreateSampler(device->handle, &samplerCreateInfo, NULL, &pipelineContext->linearRepeatSampler)) {
|
||||
VKPipelines_DestroyContext(pipelineContext);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pipelineContext;
|
||||
}
|
||||
|
||||
void VKPipelines_DestroyContext(VKPipelineContext* pipelineContext) {
|
||||
if (pipelineContext == NULL) return;
|
||||
VKDevice* device = pipelineContext->device;
|
||||
assert(device != NULL);
|
||||
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(pipelineContext->renderPassContexts); i++) {
|
||||
VKPipelines_DestroyRenderPassContext(pipelineContext->renderPassContexts[i]);
|
||||
}
|
||||
ARRAY_FREE(pipelineContext->renderPassContexts);
|
||||
|
||||
VKPipelines_DestroyShaders(device, pipelineContext->shaders);
|
||||
device->vkDestroySampler(device->handle, pipelineContext->linearRepeatSampler, NULL);
|
||||
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->pipelineLayout, NULL);
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->texturePipelineLayout, NULL);
|
||||
device->vkDestroyDescriptorSetLayout(device->handle, pipelineContext->textureDescriptorSetLayout, NULL);
|
||||
|
||||
free(pipelineContext);
|
||||
}
|
||||
|
||||
VKRenderPassContext* VKPipelines_GetRenderPassContext(VKPipelineContext* pipelineContext, VkFormat format) {
|
||||
assert(pipelineContext != NULL && pipelineContext->device != NULL);
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(pipelineContext->renderPassContexts); i++) {
|
||||
if (pipelineContext->renderPassContexts[i]->format == format) return pipelineContext->renderPassContexts[i];
|
||||
}
|
||||
// Not found, create.
|
||||
VKRenderPassContext* renderPassContext = VKPipelines_CreateRenderPassContext(pipelineContext, format);
|
||||
ARRAY_PUSH_BACK(pipelineContext->renderPassContexts, renderPassContext);
|
||||
return renderPassContext;
|
||||
}
|
||||
|
||||
VkPipeline VKPipelines_GetPipeline(VKRenderPassContext* renderPassContext, VKPipeline pipeline) {
|
||||
if (renderPassContext->pipelineSet == NULL) {
|
||||
renderPassContext->pipelineSet = VKPipelines_CreatePipelineSet(renderPassContext);
|
||||
}
|
||||
return renderPassContext->pipelineSet->pipelines[pipeline];
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
#ifndef VKPipelines_h_Included
|
||||
#define VKPipelines_h_Included
|
||||
|
||||
#include "VKTypes.h"
|
||||
|
||||
typedef struct VKShaders VKShaders;
|
||||
typedef struct VKPipelineSet VKPipelineSet;
|
||||
|
||||
/**
|
||||
* All pipeline types, use these to index into VKPipelineSet.pipelines.
|
||||
*/
|
||||
typedef enum {
|
||||
PIPELINE_FILL_COLOR = 0,
|
||||
PIPELINE_DRAW_COLOR = 1,
|
||||
PIPELINE_BLIT = 2,
|
||||
PIPELINE_COUNT = 3
|
||||
} VKPipeline;
|
||||
|
||||
/**
|
||||
* Global pipeline context.
|
||||
*/
|
||||
struct VKPipelineContext {
|
||||
VKDevice* device;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkPipelineLayout texturePipelineLayout;
|
||||
VkDescriptorSetLayout textureDescriptorSetLayout;
|
||||
|
||||
VkSampler linearRepeatSampler;
|
||||
|
||||
VKShaders* shaders;
|
||||
VKRenderPassContext** renderPassContexts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Per-format context.
|
||||
*/
|
||||
struct VKRenderPassContext {
|
||||
VKPipelineContext* pipelineContext;
|
||||
VkFormat format;
|
||||
VkRenderPass renderPass;
|
||||
VKPipelineSet* pipelineSet; // TODO we will need a real hash map for this in the future.
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float x, y;
|
||||
} VKVertex;
|
||||
|
||||
typedef struct {
|
||||
float px, py;
|
||||
float u, v;
|
||||
} VKTxVertex;
|
||||
|
||||
VKPipelineContext* VKPipelines_CreateContext(VKDevice* device);
|
||||
void VKPipelines_DestroyContext(VKPipelineContext* pipelines);
|
||||
|
||||
VKRenderPassContext* VKPipelines_GetRenderPassContext(VKPipelineContext* pipelineContext, VkFormat format);
|
||||
VkPipeline VKPipelines_GetPipeline(VKRenderPassContext* renderPassContext, VKPipeline pipeline);
|
||||
|
||||
#endif //VKPipelines_h_Included
|
||||
@@ -32,10 +32,38 @@
|
||||
#include "sun_java2d_vulkan_VKBlitLoops.h"
|
||||
#include "Trace.h"
|
||||
#include "jlong.h"
|
||||
#include "VKRenderQueue.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKVertex.h"
|
||||
#include "VKUtil.h"
|
||||
|
||||
/*
|
||||
* The following macros are used to pick values (of the specified type) off
|
||||
* the queue.
|
||||
*/
|
||||
#define NEXT_VAL(buf, type) (((type *)((buf) = ((unsigned char*)(buf)) + sizeof(type)))[-1])
|
||||
#define NEXT_BYTE(buf) NEXT_VAL(buf, unsigned char)
|
||||
#define NEXT_INT(buf) NEXT_VAL(buf, jint)
|
||||
#define NEXT_FLOAT(buf) NEXT_VAL(buf, jfloat)
|
||||
#define NEXT_BOOLEAN(buf) (jboolean)NEXT_INT(buf)
|
||||
#define NEXT_LONG(buf) NEXT_VAL(buf, jlong)
|
||||
#define NEXT_DOUBLE(buf) NEXT_VAL(buf, jdouble)
|
||||
#define NEXT_SURFACE(buf) ((VKSDOps*) (SurfaceDataOps*) jlong_to_ptr(NEXT_LONG(buf)))
|
||||
|
||||
/*
|
||||
* Increments a pointer (buf) by the given number of bytes.
|
||||
*/
|
||||
#define SKIP_BYTES(buf, numbytes) (buf) = ((unsigned char*)(buf)) + (numbytes)
|
||||
|
||||
/*
|
||||
* Extracts a value at the given offset from the provided packed value.
|
||||
*/
|
||||
#define EXTRACT_VAL(packedval, offset, mask) \
|
||||
(((packedval) >> (offset)) & (mask))
|
||||
#define EXTRACT_BYTE(packedval, offset) \
|
||||
(unsigned char)EXTRACT_VAL(packedval, offset, 0xff)
|
||||
#define EXTRACT_BOOLEAN(packedval, offset) \
|
||||
(jboolean)EXTRACT_VAL(packedval, offset, 0x1)
|
||||
|
||||
#define BYTES_PER_POLY_POINT \
|
||||
sun_java2d_pipe_BufferedRenderPipe_BYTES_PER_POLY_POINT
|
||||
@@ -63,19 +91,16 @@
|
||||
#define OFFSET_XFORM sun_java2d_vulkan_VKBlitLoops_OFFSET_XFORM
|
||||
#define OFFSET_ISOBLIT sun_java2d_vulkan_VKBlitLoops_OFFSET_ISOBLIT
|
||||
|
||||
static VKSDOps *dstOps = NULL;
|
||||
|
||||
static VKLogicalDevice* currentDevice;
|
||||
|
||||
// TODO move this property to special drawing context structure
|
||||
static int color = -1;
|
||||
// Rendering context is only accessed from VKRenderQueue_flushBuffer,
|
||||
// which is only called from queue flusher thread, no need for synchronization.
|
||||
static VKRenderingContext context = {};
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
(JNIEnv *env, jobject oglrq, jlong buf, jint limit)
|
||||
{
|
||||
unsigned char *b, *end;
|
||||
|
||||
J2dTraceLn1(J2D_TRACE_INFO,
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: limit=%d", limit);
|
||||
|
||||
b = (unsigned char *)jlong_to_ptr(buf);
|
||||
@@ -160,6 +185,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn8(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DRAW_PARALLELOGRAM(%f, %f, %f, %f, %f, %f, %f, %f)",
|
||||
x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12);
|
||||
VKRenderer_RenderParallelogram(&context, PIPELINE_DRAW_COLOR, x11, y11, dx21, dy21, dx12, dy12);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
|
||||
@@ -187,7 +213,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint h = NEXT_INT(b);
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_RECT(%d, %d, %d, %d)", x, y, w, h);
|
||||
VKRenderer_FillRect(currentDevice, x, y, w, h);
|
||||
VKRenderer_FillRect(&context, x, y, w, h);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
|
||||
@@ -195,7 +221,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint count = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_SPANS");
|
||||
VKRenderer_FillSpans(currentDevice, color, dstOps, count, (jint *)b);
|
||||
VKRenderer_FillSpans(&context, count, (jint *)b);
|
||||
SKIP_BYTES(b, count * BYTES_PER_SPAN);
|
||||
}
|
||||
break;
|
||||
@@ -210,7 +236,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn6(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_PARALLELOGRAM(%f, %f, %f, %f, %f, %f)",
|
||||
x11, y11, dx21, dy21, dx12, dy12);
|
||||
VKRenderer_FillParallelogram(currentDevice, color, dstOps, x11, y11, dx21, dy21, dx12, dy12);
|
||||
VKRenderer_RenderParallelogram(&context, PIPELINE_FILL_COLOR, x11, y11, dx21, dy21, dx12, dy12);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
|
||||
@@ -423,24 +449,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_SURFACES");
|
||||
dstOps = (VKSDOps *) jlong_to_ptr(dst);
|
||||
|
||||
if (dstOps != NULL) {
|
||||
currentDevice = dstOps->device;
|
||||
if (dstOps->drawableType == VKSD_WINDOW && dstOps->bgColorUpdated) {
|
||||
VKWinSDOps *winDstOps = (VKWinSDOps *)dstOps;
|
||||
|
||||
currentDevice->vkWaitForFences(currentDevice->device, 1, ¤tDevice->inFlightFence, VK_TRUE, UINT64_MAX);
|
||||
currentDevice->vkResetFences(currentDevice->device, 1, ¤tDevice->inFlightFence);
|
||||
|
||||
currentDevice->vkResetCommandBuffer(currentDevice->commandBuffer, 0);
|
||||
|
||||
VKRenderer_BeginRendering(currentDevice);
|
||||
|
||||
VKRenderer_ColorRenderMaxRect(currentDevice, winDstOps->vksdOps.image, winDstOps->vksdOps.bgColor);
|
||||
VKRenderer_EndRendering(currentDevice, VK_FALSE, VK_FALSE);
|
||||
}
|
||||
}
|
||||
context.surface = dst;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
|
||||
@@ -448,7 +457,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_SCRATCH_SURFACE");
|
||||
dstOps = NULL;
|
||||
context.surface = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
|
||||
@@ -470,14 +479,14 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DISPOSE_CONFIG")
|
||||
dstOps = NULL;
|
||||
context.surface = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: INVALIDATE_CONTEXT");
|
||||
dstOps = NULL;
|
||||
context.surface = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SYNC:
|
||||
@@ -487,6 +496,17 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
}
|
||||
break;
|
||||
|
||||
case sun_java2d_pipe_BufferedOpCodes_CONFIGURE_SURFACE:
|
||||
{
|
||||
VKSDOps* surface = NEXT_SURFACE(b);
|
||||
jint width = NEXT_INT(b);
|
||||
jint height = NEXT_INT(b);
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: CONFIGURE_SURFACE %dx%d", width, height);
|
||||
VKRenderer_ConfigureSurface(surface, (VkExtent2D) {width, height});
|
||||
}
|
||||
break;
|
||||
|
||||
// multibuffering ops
|
||||
case sun_java2d_pipe_BufferedOpCodes_SWAP_BUFFERS:
|
||||
{
|
||||
@@ -496,6 +516,16 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
}
|
||||
break;
|
||||
|
||||
case sun_java2d_pipe_BufferedOpCodes_FLUSH_BUFFER:
|
||||
{
|
||||
VKSDOps* surface = NEXT_SURFACE(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FLUSH_BUFFER");
|
||||
|
||||
VKRenderer_FlushSurface(surface);
|
||||
}
|
||||
break;
|
||||
|
||||
// special no-op (mainly used for achieving 8-byte alignment)
|
||||
case sun_java2d_pipe_BufferedOpCodes_NOOP:
|
||||
{
|
||||
@@ -513,10 +543,11 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
|
||||
{
|
||||
jint pixel = NEXT_INT(b);
|
||||
color = pixel;
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_COLOR %d", pixel);
|
||||
jint javaColor = NEXT_INT(b);
|
||||
context.color = VKUtil_DecodeJavaColor(javaColor);
|
||||
J2dRlsTraceLn5(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_COLOR 0x%08x, linear_rgba={%.3f, %.3f, %.3f, %.3f}",
|
||||
javaColor, context.color.r, context.color.g, context.color.b, context.color.a);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
|
||||
@@ -649,43 +680,10 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
}
|
||||
}
|
||||
|
||||
if (dstOps != NULL && dstOps->drawableType == VKSD_WINDOW && currentDevice != NULL) {
|
||||
VKWinSDOps *winDstOps = (VKWinSDOps *)dstOps;
|
||||
|
||||
currentDevice->vkWaitForFences(currentDevice->device, 1, ¤tDevice->inFlightFence, VK_TRUE, UINT64_MAX);
|
||||
currentDevice->vkResetFences(currentDevice->device, 1, ¤tDevice->inFlightFence);
|
||||
|
||||
uint32_t imageIndex;
|
||||
currentDevice->vkAcquireNextImageKHR(currentDevice->device, winDstOps->swapchainKhr, UINT64_MAX,
|
||||
currentDevice->imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
|
||||
|
||||
currentDevice->vkResetCommandBuffer(currentDevice->commandBuffer, 0);
|
||||
|
||||
VKRenderer_BeginRendering(currentDevice);
|
||||
|
||||
VKRenderer_TextureRender(
|
||||
currentDevice,
|
||||
&winDstOps->swapChainImages[imageIndex],
|
||||
winDstOps->vksdOps.image,
|
||||
currentDevice->blitVertexBuffer->buffer, 4
|
||||
);
|
||||
|
||||
VKRenderer_EndRendering(currentDevice, VK_TRUE, VK_TRUE);
|
||||
|
||||
VkSemaphore signalSemaphores[] = {currentDevice->renderFinishedSemaphore};
|
||||
|
||||
VkSwapchainKHR swapChains[] = {winDstOps->swapchainKhr};
|
||||
VkPresentInfoKHR presentInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = signalSemaphores,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = swapChains,
|
||||
.pImageIndices = &imageIndex
|
||||
};
|
||||
|
||||
currentDevice->vkQueuePresentKHR(currentDevice->queue, &presentInfo);
|
||||
|
||||
// Flush all pending GPU work
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(ge->devices); i++) {
|
||||
VKRenderer_Flush(ge->devices[i].renderer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +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.
|
||||
*/
|
||||
|
||||
#ifndef VKRenderQueue_h_Included
|
||||
#define VKRenderQueue_h_Included
|
||||
|
||||
/*
|
||||
* The following macros are used to pick values (of the specified type) off
|
||||
* the queue.
|
||||
*/
|
||||
#define NEXT_VAL(buf, type) (((type *)((buf) += sizeof(type)))[-1])
|
||||
#define NEXT_BYTE(buf) NEXT_VAL(buf, unsigned char)
|
||||
#define NEXT_INT(buf) NEXT_VAL(buf, jint)
|
||||
#define NEXT_FLOAT(buf) NEXT_VAL(buf, jfloat)
|
||||
#define NEXT_BOOLEAN(buf) (jboolean)NEXT_INT(buf)
|
||||
#define NEXT_LONG(buf) NEXT_VAL(buf, jlong)
|
||||
#define NEXT_DOUBLE(buf) NEXT_VAL(buf, jdouble)
|
||||
#define NEXT_SURFACE(buf) ((VKSDOps*) (SurfaceDataOps*) jlong_to_ptr(NEXT_LONG(buf)))
|
||||
|
||||
/*
|
||||
* Increments a pointer (buf) by the given number of bytes.
|
||||
*/
|
||||
#define SKIP_BYTES(buf, numbytes) (buf) = ((unsigned char*)buf) + (numbytes)
|
||||
|
||||
/*
|
||||
* Extracts a value at the given offset from the provided packed value.
|
||||
*/
|
||||
#define EXTRACT_VAL(packedval, offset, mask) \
|
||||
(((packedval) >> (offset)) & (mask))
|
||||
#define EXTRACT_BYTE(packedval, offset) \
|
||||
(unsigned char)EXTRACT_VAL(packedval, offset, 0xff)
|
||||
#define EXTRACT_BOOLEAN(packedval, offset) \
|
||||
(jboolean)EXTRACT_VAL(packedval, offset, 0x1)
|
||||
|
||||
/*
|
||||
* The following macros allow the caller to return (or continue) if the
|
||||
* provided value is NULL. (The strange else clause is included below to
|
||||
* allow for a trailing ';' after RETURN/CONTINUE_IF_NULL() invocations.)
|
||||
*/
|
||||
#define ACT_IF_NULL(ACTION, value) \
|
||||
if ((value) == NULL) { \
|
||||
J2dTraceLn1(J2D_TRACE_ERROR, \
|
||||
"%s is null", #value); \
|
||||
ACTION; \
|
||||
} else do { } while (0)
|
||||
#define RETURN_IF_NULL(value) ACT_IF_NULL(return, value)
|
||||
#define CONTINUE_IF_NULL(value) ACT_IF_NULL(continue, value)
|
||||
|
||||
#endif /* VKRenderQueue_h_Included */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,41 +27,58 @@
|
||||
#ifndef VKRenderer_h_Included
|
||||
#define VKRenderer_h_Included
|
||||
|
||||
#include "j2d_md.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKBuffer.h"
|
||||
#include "VKImage.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKTypes.h"
|
||||
#include "VKPipelines.h"
|
||||
|
||||
struct VKRenderer {
|
||||
VkRenderPass renderPass;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
VkDescriptorPool descriptorPool;
|
||||
VkDescriptorSet descriptorSets;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkPipeline graphicsPipeline;
|
||||
struct VKRenderingContext {
|
||||
VKSDOps* surface;
|
||||
Color color;
|
||||
};
|
||||
|
||||
VKRenderer* VKRenderer_CreateFillTexturePoly(VKLogicalDevice* logicalDevice);
|
||||
VKRenderer* VKRenderer_Create(VKDevice* device);
|
||||
|
||||
VKRenderer* VKRenderer_CreateFillColorPoly(VKLogicalDevice* logicalDevice);
|
||||
void VKRenderer_Destroy(VKRenderer* renderer);
|
||||
|
||||
VKRenderer* VKRenderer_CreateFillMaxColorPoly(VKLogicalDevice* logicalDevice);
|
||||
/**
|
||||
* Wait for all rendering commands to complete.
|
||||
*/
|
||||
void VKRenderer_Sync(VKRenderer* renderer);
|
||||
|
||||
/**
|
||||
* Submit pending command buffer, completed render passes & presentation requests.
|
||||
*/
|
||||
void VKRenderer_Flush(VKRenderer* renderer);
|
||||
|
||||
/**
|
||||
* Cancel render pass of the surface, release all associated resources and deallocate render pass.
|
||||
*/
|
||||
void VKRenderer_ReleaseRenderPass(VKSDOps* surface);
|
||||
|
||||
/**
|
||||
* Flush pending render pass and queue surface for presentation (if applicable).
|
||||
*/
|
||||
void VKRenderer_FlushSurface(VKSDOps* surface);
|
||||
|
||||
/**
|
||||
* Request size for the surface. It has no effect, if it is already of the same size.
|
||||
* Actual resize will be performed later, before starting a new frame.
|
||||
*/
|
||||
void VKRenderer_ConfigureSurface(VKSDOps* surface, VkExtent2D extent);
|
||||
|
||||
// Blit ops.
|
||||
|
||||
void VKRenderer_TextureRender(VKRenderingContext* context,
|
||||
VKImage *destImage, VKImage *srcImage,
|
||||
VkBuffer vertexBuffer, uint32_t vertexNum);
|
||||
|
||||
void VKRenderer_BeginRendering(VKLogicalDevice* logicalDevice);
|
||||
void VKRenderer_EndRendering(VKLogicalDevice* logicalDevice, VkBool32 notifyRenderFinish, VkBool32 waitForDisplayImage);
|
||||
void VKRenderer_TextureRender(VKLogicalDevice* logicalDevice, VKImage *destImage, VKImage *srcImage, VkBuffer vertexBuffer, uint32_t vertexNum);
|
||||
void VKRenderer_ColorRender(VKLogicalDevice* logicalDevice, VKImage *destImage, uint32_t rgba, VkBuffer vertexBuffer, uint32_t vertexNum);
|
||||
void VKRenderer_ColorRenderMaxRect(VKLogicalDevice* logicalDevice, VKImage *destImage, uint32_t rgba);
|
||||
// fill ops
|
||||
void VKRenderer_FillRect(VKLogicalDevice* logicalDevice, jint x, jint y, jint w, jint h);
|
||||
void VKRenderer_FillParallelogram(VKLogicalDevice* logicalDevice,
|
||||
jint color, VKSDOps *dstOps,
|
||||
jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12);
|
||||
void VKRenderer_FillSpans(VKLogicalDevice* logicalDevice, jint color, VKSDOps *dstOps, jint spanCount, jint *spans);
|
||||
void VKRenderer_FillRect(VKRenderingContext* context, jint x, jint y, jint w, jint h);
|
||||
|
||||
jboolean VK_CreateLogicalDeviceRenderers(VKLogicalDevice* logicalDevice);
|
||||
void VKRenderer_RenderParallelogram(VKRenderingContext* context, VKPipeline pipeline,
|
||||
jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12);
|
||||
|
||||
void VKRenderer_FillSpans(VKRenderingContext* context, jint spanCount, jint *spans);
|
||||
|
||||
#endif //VKRenderer_h_Included
|
||||
|
||||
@@ -26,103 +26,191 @@
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include "jlong.h"
|
||||
#include "SurfaceData.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKImage.h"
|
||||
#include "VKRenderer.h"
|
||||
#include <Trace.h>
|
||||
|
||||
void VKSD_InitImageSurface(VKLogicalDevice* logicalDevice, VKSDOps *vksdo) {
|
||||
if (vksdo->image != VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Release VKSDOps resources & reset to initial state.
|
||||
*/
|
||||
static void VKSD_ResetImageSurface(VKSDOps* vksdo) {
|
||||
if (vksdo == NULL) return;
|
||||
|
||||
vksdo->device = logicalDevice;
|
||||
vksdo->image = VKImage_Create(logicalDevice, vksdo->width, vksdo->height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
if (!vksdo->image)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot create image\n");
|
||||
return;
|
||||
}
|
||||
// ReleaseRenderPass also waits while the surface resources are being used by device.
|
||||
VKRenderer_ReleaseRenderPass(vksdo);
|
||||
|
||||
if (!VKImage_CreateFramebuffer(logicalDevice, vksdo->image, logicalDevice->fillTexturePoly->renderPass)) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot create framebuffer for window surface")
|
||||
return;
|
||||
if (vksdo->device != NULL && vksdo->image != NULL) {
|
||||
VKImage_free(vksdo->device, vksdo->image);
|
||||
vksdo->image = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void VKSD_InitWindowSurface(VKLogicalDevice* logicalDevice, VKWinSDOps *vkwinsdo) {
|
||||
void VKSD_ResetSurface(VKSDOps* vksdo) {
|
||||
VKSD_ResetImageSurface(vksdo);
|
||||
|
||||
// Release VKWinSDOps resources, if applicable.
|
||||
if (vksdo->drawableType == VKSD_WINDOW) {
|
||||
VKWinSDOps* vkwinsdo = (VKWinSDOps*) vksdo;
|
||||
ARRAY_FREE(vkwinsdo->swapchainImages);
|
||||
vkwinsdo->swapchainImages = NULL;
|
||||
if (vkwinsdo->vksdOps.device != NULL && vkwinsdo->swapchain != VK_NULL_HANDLE) {
|
||||
vkwinsdo->vksdOps.device->vkDestroySwapchainKHR(vkwinsdo->vksdOps.device->handle, vkwinsdo->swapchain, NULL);
|
||||
}
|
||||
if (vkwinsdo->surface != VK_NULL_HANDLE) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
if (ge != NULL) ge->vkDestroySurfaceKHR(ge->vkInstance, vkwinsdo->surface, NULL);
|
||||
}
|
||||
vkwinsdo->swapchain = VK_NULL_HANDLE;
|
||||
vkwinsdo->surface = VK_NULL_HANDLE;
|
||||
vkwinsdo->swapchainDevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VkBool32 VKSD_ConfigureImageSurface(VKSDOps* vksdo) {
|
||||
// Initialize the device. currentDevice can be changed on the fly, and we must reconfigure surfaces accordingly.
|
||||
VKDevice* device = VKGE_graphics_environment()->currentDevice;
|
||||
if (device != vksdo->device) {
|
||||
VKSD_ResetImageSurface(vksdo);
|
||||
vksdo->device = device;
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_ConfigureImageSurface(%p): device updated", vksdo);
|
||||
}
|
||||
// Initialize image.
|
||||
if (vksdo->requestedExtent.width > 0 && vksdo->requestedExtent.height > 0 && (vksdo->image == NULL ||
|
||||
vksdo->requestedExtent.width != vksdo->image->extent.width ||
|
||||
vksdo->requestedExtent.height != vksdo->image->extent.height)) {
|
||||
// VK_FORMAT_B8G8R8A8_UNORM is the most widely-supported format for our use.
|
||||
VKImage* image = VKImage_Create(device, vksdo->requestedExtent.width, vksdo->requestedExtent.height,
|
||||
VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
if (image == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "VKSD_ConfigureImageSurface(%p): cannot create image", vksdo);
|
||||
VK_UNHANDLED_ERROR();
|
||||
}
|
||||
VKSD_ResetImageSurface(vksdo);
|
||||
vksdo->image = image;
|
||||
J2dRlsTraceLn3(J2D_TRACE_INFO, "VKSD_ConfigureImageSurface(%p): image updated %dx%d", vksdo, image->extent.width, image->extent.height);
|
||||
}
|
||||
return vksdo->image != NULL;
|
||||
}
|
||||
|
||||
VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
// Check that image is ready.
|
||||
if (vkwinsdo->vksdOps.image == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_WARNING, "VKSD_ConfigureWindowSurface(%p): image is not ready", vkwinsdo);
|
||||
return VK_FALSE;
|
||||
}
|
||||
// Check for changes.
|
||||
if (vkwinsdo->swapchain != VK_NULL_HANDLE && vkwinsdo->swapchainDevice == vkwinsdo->vksdOps.device &&
|
||||
vkwinsdo->swapchainExtent.width == vkwinsdo->vksdOps.image->extent.width &&
|
||||
vkwinsdo->swapchainExtent.height == vkwinsdo->vksdOps.image->extent.height) return VK_TRUE;
|
||||
// Check that surface is ready.
|
||||
if (vkwinsdo->surface == VK_NULL_HANDLE) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_WARNING, "VKSD_ConfigureWindowSurface(%p): surface is not ready", vkwinsdo);
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VkPhysicalDevice physicalDevice = logicalDevice->physicalDevice;
|
||||
VKDevice* device = vkwinsdo->vksdOps.device;
|
||||
VkPhysicalDevice physicalDevice = device->physicalDevice;
|
||||
|
||||
if (vkwinsdo->swapchainKhr == VK_NULL_HANDLE) {
|
||||
ge->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, vkwinsdo->surface, &vkwinsdo->capabilitiesKhr);
|
||||
ge->vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, vkwinsdo->surface, &vkwinsdo->formatsKhrCount, NULL);
|
||||
if (vkwinsdo->formatsKhrCount == 0) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "No formats for swapchain found\n");
|
||||
return;
|
||||
}
|
||||
vkwinsdo->formatsKhr = calloc(vkwinsdo->formatsKhrCount, sizeof(VkSurfaceFormatKHR));
|
||||
ge->vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, vkwinsdo->surface, &vkwinsdo->formatsKhrCount,
|
||||
vkwinsdo->formatsKhr);
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, vkwinsdo->surface, &capabilities)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
ge->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface,
|
||||
&vkwinsdo->presentModeKhrCount, NULL);
|
||||
uint32_t formatCount;
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, vkwinsdo->surface, &formatCount, NULL)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
VkSurfaceFormatKHR formats[formatCount];
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, vkwinsdo->surface, &formatCount, formats)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
if (vkwinsdo->presentModeKhrCount == 0) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "No present modes found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vkwinsdo->presentModesKhr = calloc(vkwinsdo->presentModeKhrCount, sizeof(VkPresentModeKHR));
|
||||
ge->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface, &vkwinsdo->presentModeKhrCount,
|
||||
vkwinsdo->presentModesKhr);
|
||||
|
||||
VkExtent2D extent = {
|
||||
(uint32_t) (vkwinsdo->vksdOps.width),
|
||||
(uint32_t) (vkwinsdo->vksdOps.height)
|
||||
};
|
||||
|
||||
uint32_t imageCount = vkwinsdo->capabilitiesKhr.minImageCount + 1;
|
||||
if (vkwinsdo->capabilitiesKhr.maxImageCount > 0 && imageCount > vkwinsdo->capabilitiesKhr.maxImageCount) {
|
||||
imageCount = vkwinsdo->capabilitiesKhr.maxImageCount;
|
||||
}
|
||||
VkSwapchainCreateInfoKHR createInfoKhr = {
|
||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
.surface = vkwinsdo->surface,
|
||||
.minImageCount = imageCount,
|
||||
.imageFormat = vkwinsdo->formatsKhr[0].format,
|
||||
.imageColorSpace = vkwinsdo->formatsKhr[0].colorSpace,
|
||||
.imageExtent = extent,
|
||||
.imageArrayLayers = 1,
|
||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = NULL,
|
||||
.preTransform = vkwinsdo->capabilitiesKhr.currentTransform,
|
||||
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
.presentMode = VK_PRESENT_MODE_FIFO_KHR,
|
||||
.clipped = VK_TRUE
|
||||
};
|
||||
|
||||
if (logicalDevice->vkCreateSwapchainKHR(logicalDevice->device, &createInfoKhr, NULL, &vkwinsdo->swapchainKhr) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot create swapchain\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vkwinsdo->swapChainImages = VKImage_CreateImageArrayFromSwapChain(
|
||||
logicalDevice, vkwinsdo->swapchainKhr,
|
||||
logicalDevice->fillTexturePoly->renderPass,
|
||||
vkwinsdo->formatsKhr[0].format, extent);
|
||||
|
||||
if (!vkwinsdo->swapChainImages) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot get swapchain images");
|
||||
return;
|
||||
VkSurfaceFormatKHR* format = NULL;
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_ConfigureWindowSurface(%p): available swapchain formats:", vkwinsdo);
|
||||
for (uint32_t i = 0; i < formatCount; i++) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_INFO, " format=%d, colorSpace=%d", formats[i].format, formats[i].colorSpace);
|
||||
// We draw with sRGB colors (see VKUtil_DecodeJavaColor()), so we don't want Vulkan to do color space
|
||||
// conversions when drawing to surface. We use *_UNORM formats, so that colors are written "as is".
|
||||
// With VK_COLOR_SPACE_SRGB_NONLINEAR_KHR these colors will be interpreted by presentation engine as sRGB.
|
||||
if (formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR && (
|
||||
formats[i].format == VK_FORMAT_A8B8G8R8_UNORM_PACK32 ||
|
||||
formats[i].format == VK_FORMAT_B8G8R8A8_UNORM ||
|
||||
formats[i].format == VK_FORMAT_R8G8B8A8_UNORM ||
|
||||
formats[i].format == VK_FORMAT_B8G8R8_UNORM ||
|
||||
formats[i].format == VK_FORMAT_R8G8B8_UNORM
|
||||
)) {
|
||||
format = &formats[i];
|
||||
}
|
||||
}
|
||||
if (format == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "VKSD_ConfigureWindowSurface(%p): no suitable format found", vkwinsdo);
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
// TODO inspect and choose present mode
|
||||
uint32_t presentModeCount;
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface, &presentModeCount, NULL)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
VkPresentModeKHR presentModes[presentModeCount];
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface, &presentModeCount, presentModes)) {
|
||||
VK_UNHANDLED_ERROR();
|
||||
}
|
||||
|
||||
uint32_t imageCount = capabilities.minImageCount + 1;
|
||||
if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) {
|
||||
imageCount = capabilities.maxImageCount;
|
||||
}
|
||||
|
||||
VkSwapchainKHR swapchain;
|
||||
VkSwapchainCreateInfoKHR createInfoKhr = {
|
||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
.surface = vkwinsdo->surface,
|
||||
.minImageCount = imageCount,
|
||||
.imageFormat = format->format,
|
||||
.imageColorSpace = format->colorSpace,
|
||||
.imageExtent = vkwinsdo->vksdOps.image->extent, // TODO consider capabilities.currentExtent, capabilities.minImageExtent and capabilities.maxImageExtent
|
||||
.imageArrayLayers = 1,
|
||||
.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = NULL,
|
||||
.preTransform = capabilities.currentTransform,
|
||||
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
.presentMode = VK_PRESENT_MODE_FIFO_KHR, // TODO need more flexibility
|
||||
.clipped = VK_TRUE,
|
||||
.oldSwapchain = vkwinsdo->swapchain
|
||||
};
|
||||
|
||||
VK_IF_ERROR(device->vkCreateSwapchainKHR(device->handle, &createInfoKhr, NULL, &swapchain)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_ConfigureWindowSurface(%p): swapchain created", vkwinsdo);
|
||||
|
||||
if (vkwinsdo->swapchain != VK_NULL_HANDLE) {
|
||||
// Destroy old swapchain.
|
||||
// TODO is it possible that old swapchain is still being presented, can we destroy it right now?
|
||||
device->vkDestroySwapchainKHR(device->handle, vkwinsdo->swapchain, NULL);
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_ConfigureWindowSurface(%p): old swapchain destroyed", vkwinsdo);
|
||||
}
|
||||
vkwinsdo->swapchain = swapchain;
|
||||
vkwinsdo->swapchainDevice = device;
|
||||
vkwinsdo->swapchainExtent = vkwinsdo->vksdOps.image->extent;
|
||||
|
||||
uint32_t swapchainImageCount;
|
||||
VK_IF_ERROR(device->vkGetSwapchainImagesKHR(device->handle, vkwinsdo->swapchain, &swapchainImageCount, NULL)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
ARRAY_RESIZE(vkwinsdo->swapchainImages, swapchainImageCount);
|
||||
VK_IF_ERROR(device->vkGetSwapchainImagesKHR(device->handle, vkwinsdo->swapchain,
|
||||
&swapchainImageCount, vkwinsdo->swapchainImages)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
|
||||
@@ -27,15 +27,15 @@
|
||||
#ifndef VKSurfaceData_h_Included
|
||||
#define VKSurfaceData_h_Included
|
||||
|
||||
#include <pthread.h>
|
||||
#include "jni.h"
|
||||
#include "SurfaceData.h"
|
||||
#include "sun_java2d_pipe_hw_AccelSurface.h"
|
||||
#include "VKTypes.h"
|
||||
#include "VKRenderer.h"
|
||||
|
||||
/**
|
||||
* These are shorthand names for the surface type constants defined in
|
||||
* VKSurfaceData.java.
|
||||
* TODO which constants?
|
||||
*/
|
||||
#define VKSD_UNDEFINED sun_java2d_pipe_hw_AccelSurface_UNDEFINED
|
||||
#define VKSD_WINDOW sun_java2d_pipe_hw_AccelSurface_WINDOW
|
||||
@@ -44,59 +44,46 @@
|
||||
* The VKSDOps structure describes a native Vulkan surface and contains all
|
||||
* information pertaining to the native surface.
|
||||
*/
|
||||
typedef struct {
|
||||
SurfaceDataOps sdOps;
|
||||
jint drawableType;
|
||||
pthread_mutex_t mutex;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t scale; // TODO Is it needed there at all?
|
||||
uint32_t bgColor;
|
||||
VkBool32 bgColorUpdated;
|
||||
VKLogicalDevice* device;
|
||||
VKImage* image;
|
||||
// We track any access and write access separately, as read-read access does not need synchronization.
|
||||
VkPipelineStageFlagBits lastStage;
|
||||
VkPipelineStageFlagBits lastWriteStage;
|
||||
VkAccessFlagBits lastAccess;
|
||||
VkAccessFlagBits lastWriteAccess;
|
||||
} VKSDOps;
|
||||
struct VKSDOps {
|
||||
SurfaceDataOps sdOps;
|
||||
jint drawableType;
|
||||
VKDevice* device;
|
||||
VKImage* image;
|
||||
|
||||
Color background;
|
||||
VkExtent2D requestedExtent;
|
||||
|
||||
VKRenderPass* renderPass;
|
||||
};
|
||||
|
||||
/**
|
||||
* The VKWinSDOps structure describes a native Vulkan surface connected with a window.
|
||||
* Some information about the more important/different fields:
|
||||
*
|
||||
* void *privOps;
|
||||
* Pointer to native-specific SurfaceData info, such as the
|
||||
* native Drawable handle and GraphicsConfig data.
|
||||
*/
|
||||
typedef struct {
|
||||
VKSDOps vksdOps;
|
||||
void *privOps;
|
||||
VkSurfaceKHR surface;
|
||||
VkSurfaceCapabilitiesKHR capabilitiesKhr;
|
||||
VkSurfaceFormatKHR* formatsKhr;
|
||||
uint32_t formatsKhrCount;
|
||||
VkPresentModeKHR* presentModesKhr;
|
||||
uint32_t presentModeKhrCount;
|
||||
VkSwapchainKHR swapchainKhr;
|
||||
VKImage* swapChainImages;
|
||||
} VKWinSDOps;
|
||||
struct VKWinSDOps {
|
||||
VKSDOps vksdOps;
|
||||
VkSurfaceKHR surface;
|
||||
VkSwapchainKHR swapchain;
|
||||
VkImage* swapchainImages;
|
||||
VKDevice* swapchainDevice;
|
||||
VkExtent2D swapchainExtent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exported methods.
|
||||
* Release all resources of the surface, resetting it to initial state.
|
||||
* This function must also be used to initialize newly allocated surfaces.
|
||||
* VKSDOps.drawableType must be properly set before calling this function.
|
||||
*/
|
||||
jint VKSD_Lock(JNIEnv *env,
|
||||
SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo,
|
||||
jint lockflags);
|
||||
void VKSD_GetRasInfo(JNIEnv *env,
|
||||
SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo);
|
||||
void VKSD_Unlock(JNIEnv *env,
|
||||
SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo);
|
||||
void VKSD_Dispose(JNIEnv *env, SurfaceDataOps *ops);
|
||||
void VKSD_Delete(JNIEnv *env, VKSDOps *oglsdo);
|
||||
void VKSD_ResetSurface(VKSDOps* vksdo);
|
||||
|
||||
void VKSD_InitImageSurface(VKLogicalDevice* logicalDevice, VKSDOps *vksdo);
|
||||
void VKSD_InitWindowSurface(VKLogicalDevice* logicalDevice, VKWinSDOps *vkwinsdo);
|
||||
/**
|
||||
* Configure image surface. This [re]initializes the device and surface image.
|
||||
*/
|
||||
VkBool32 VKSD_ConfigureImageSurface(VKSDOps* vksdo);
|
||||
|
||||
/**
|
||||
* Configure window surface. This [re]initializes the swapchain.
|
||||
* VKSD_ConfigureImageSurface must have been called before.
|
||||
*/
|
||||
VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo);
|
||||
|
||||
#endif /* VKSurfaceData_h_Included */
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "VKImage.h"
|
||||
#include "VKTexturePool.h"
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "Trace.h"
|
||||
|
||||
|
||||
#define TRACE_LOCK 0
|
||||
#define TRACE_TEX 0
|
||||
|
||||
|
||||
/* lock API */
|
||||
ATexturePoolLockPrivPtr* VKTexturePoolLock_initImpl(void) {
|
||||
pthread_mutex_t *l = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
|
||||
CHECK_NULL_LOG_RETURN(l, NULL, "VKTexturePoolLock_initImpl: could not allocate pthread_mutex_t");
|
||||
|
||||
int status = pthread_mutex_init(l, NULL);
|
||||
if (status != 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKTexturePoolLock_initImpl: lock=%p", l);
|
||||
return (ATexturePoolLockPrivPtr*)l;
|
||||
}
|
||||
|
||||
void VKTexturePoolLock_DisposeImpl(ATexturePoolLockPrivPtr *lock) {
|
||||
pthread_mutex_t* l = (pthread_mutex_t*)lock;
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKTexturePoolLock_DisposeImpl: lock=%p", l);
|
||||
pthread_mutex_destroy(l);
|
||||
free(l);
|
||||
}
|
||||
|
||||
void VKTexturePoolLock_lockImpl(ATexturePoolLockPrivPtr *lock) {
|
||||
pthread_mutex_t* l = (pthread_mutex_t*)lock;
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKTexturePoolLock_lockImpl: lock=%p", l);
|
||||
pthread_mutex_lock(l);
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKTexturePoolLock_lockImpl: lock=%p - locked", l);
|
||||
}
|
||||
|
||||
void VKTexturePoolLock_unlockImpl(ATexturePoolLockPrivPtr *lock) {
|
||||
pthread_mutex_t* l = (pthread_mutex_t*)lock;
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKTexturePoolLock_unlockImpl: lock=%p", l);
|
||||
pthread_mutex_unlock(l);
|
||||
if (TRACE_LOCK) J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKTexturePoolLock_unlockImpl: lock=%p - unlocked", l);
|
||||
}
|
||||
|
||||
|
||||
/* Texture allocate/free API */
|
||||
static ATexturePrivPtr* VKTexturePool_createTexture(ADevicePrivPtr *device,
|
||||
int width,
|
||||
int height,
|
||||
long format)
|
||||
{
|
||||
CHECK_NULL_RETURN(device, NULL);
|
||||
VKImage* texture = VKImage_Create((VKDevice*)device, width, height,
|
||||
(VkFormat)format,
|
||||
VK_IMAGE_TILING_LINEAR,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||
if IS_NULL(texture) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "VKTexturePool_createTexture: Cannot create VKImage");
|
||||
return NULL;
|
||||
}
|
||||
// usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
// storage = MTLStorageModeManaged
|
||||
|
||||
if (TRACE_TEX) J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "VKTexturePool_createTexture: created texture: tex=%p, w=%d h=%d, pf=%d",
|
||||
texture, width, height, format);
|
||||
return texture;
|
||||
}
|
||||
|
||||
static int VKTexturePool_bytesPerPixel(long format) {
|
||||
switch ((VkFormat)format) {
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
return 4;
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
return 1;
|
||||
default:
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "VKTexturePool_bytesPerPixel: format=%d not supported (4 bytes by default)", format);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void VKTexturePool_freeTexture(ADevicePrivPtr *device, ATexturePrivPtr *texture) {
|
||||
CHECK_NULL(device);
|
||||
CHECK_NULL(texture);
|
||||
VKImage* tex = (VKImage*)texture;
|
||||
if (TRACE_TEX) J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "VKTexturePool_freeTexture: free texture: tex=%p, w=%d h=%d, pf=%d",
|
||||
tex, tex->extent.width, tex->extent.height, tex->format);
|
||||
|
||||
VKImage_free((VKDevice*)device, tex);
|
||||
}
|
||||
|
||||
/* VKTexturePoolHandle API */
|
||||
void VKTexturePoolHandle_ReleaseTexture(VKTexturePoolHandle *handle) {
|
||||
ATexturePoolHandle_ReleaseTexture(handle);
|
||||
}
|
||||
|
||||
ATexturePrivPtr* VKTexturePoolHandle_GetTexture(VKTexturePoolHandle *handle) {
|
||||
return ATexturePoolHandle_GetTexture(handle);
|
||||
}
|
||||
|
||||
jint VKTexturePoolHandle_GetRequestedWidth(VKTexturePoolHandle *handle) {
|
||||
return ATexturePoolHandle_GetRequestedWidth(handle);
|
||||
}
|
||||
|
||||
jint VKTexturePoolHandle_GetRequestedHeight(VKTexturePoolHandle *handle) {
|
||||
return ATexturePoolHandle_GetRequestedHeight(handle);
|
||||
}
|
||||
|
||||
|
||||
/* VKTexturePool API */
|
||||
VKTexturePool* VKTexturePool_InitWithDevice(VKDevice *device) {
|
||||
CHECK_NULL_RETURN(device, NULL);
|
||||
// TODO: get vulkan device memory information (1gb fixed here):
|
||||
uint64_t maxDeviceMemory = 1024 * UNIT_MB;
|
||||
|
||||
ATexturePoolLockWrapper *lockWrapper = ATexturePoolLockWrapper_init(&VKTexturePoolLock_initImpl,
|
||||
&VKTexturePoolLock_DisposeImpl,
|
||||
&VKTexturePoolLock_lockImpl,
|
||||
&VKTexturePoolLock_unlockImpl);
|
||||
|
||||
return ATexturePool_initWithDevice(device,
|
||||
(jlong)maxDeviceMemory,
|
||||
&VKTexturePool_createTexture,
|
||||
&VKTexturePool_freeTexture,
|
||||
&VKTexturePool_bytesPerPixel,
|
||||
lockWrapper,
|
||||
VK_FORMAT_R8G8B8A8_UNORM);
|
||||
}
|
||||
|
||||
void VKTexturePool_Dispose(VKTexturePool *pool) {
|
||||
ATexturePoolLockWrapper_Dispose(ATexturePool_getLockWrapper(pool));
|
||||
ATexturePool_Dispose(pool);
|
||||
}
|
||||
|
||||
ATexturePoolLockWrapper* VKTexturePool_GetLockWrapper(VKTexturePool *pool) {
|
||||
return ATexturePool_getLockWrapper(pool);
|
||||
}
|
||||
|
||||
VKTexturePoolHandle* VKTexturePool_GetTexture(VKTexturePool *pool,
|
||||
jint width,
|
||||
jint height,
|
||||
jlong format)
|
||||
{
|
||||
return ATexturePool_getTexture(pool, width, height, format);
|
||||
}
|
||||
@@ -24,40 +24,36 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef VKVertex_h_Included
|
||||
#define VKVertex_h_Included
|
||||
#ifndef VKTexturePool_h_Included
|
||||
#define VKTexturePool_h_Included
|
||||
|
||||
#include "VKTypes.h"
|
||||
|
||||
#define RGBA_TO_L4(c) \
|
||||
(((c) >> 16) & (0xFF))/255.0f, \
|
||||
(((c) >> 8) & 0xFF)/255.0f, \
|
||||
((c) & 0xFF)/255.0f, \
|
||||
(((c) >> 24) & 0xFF)/255.0f
|
||||
|
||||
#define ARRAY_TO_VERTEX_BUF(logicalDevice, vertices) \
|
||||
VKBuffer_CreateFromData(logicalDevice, vertices, ARRAY_SIZE(vertices)*sizeof (vertices[0]))
|
||||
|
||||
typedef struct {
|
||||
VkVertexInputAttributeDescription *attributeDescriptions;
|
||||
uint32_t attributeDescriptionCount;
|
||||
VkVertexInputBindingDescription* bindingDescriptions;
|
||||
uint32_t bindingDescriptionCount;
|
||||
} VKVertexDescr;
|
||||
|
||||
typedef struct {
|
||||
float px, py;
|
||||
float u, v;
|
||||
} VKTxVertex;
|
||||
|
||||
typedef struct {
|
||||
float px, py;
|
||||
} VKVertex;
|
||||
#include "AccelTexturePool.h"
|
||||
#include "jni.h"
|
||||
|
||||
|
||||
VKVertexDescr VKVertex_GetTxVertexDescr();
|
||||
VKVertexDescr VKVertex_GetVertexDescr();
|
||||
/* VKTexturePoolHandle API */
|
||||
typedef ATexturePoolHandle VKTexturePoolHandle;
|
||||
|
||||
void VKTexturePoolHandle_ReleaseTexture(VKTexturePoolHandle *handle);
|
||||
|
||||
ATexturePrivPtr* VKTexturePoolHandle_GetTexture(VKTexturePoolHandle *handle);
|
||||
|
||||
jint VKTexturePoolHandle_GetRequestedWidth(VKTexturePoolHandle *handle);
|
||||
jint VKTexturePoolHandle_GetRequestedHeight(VKTexturePoolHandle *handle);
|
||||
|
||||
|
||||
/* VKTexturePool API */
|
||||
typedef ATexturePool VKTexturePool;
|
||||
|
||||
#endif //VKVertex_h_Included
|
||||
VKTexturePool* VKTexturePool_InitWithDevice(VKDevice *device) ;
|
||||
|
||||
void VKTexturePool_Dispose(VKTexturePool *pool);
|
||||
|
||||
ATexturePoolLockWrapper* VKTexturePool_GetLockWrapper(VKTexturePool *pool);
|
||||
|
||||
VKTexturePoolHandle* VKTexturePool_GetTexture(VKTexturePool *pool,
|
||||
jint width,
|
||||
jint height,
|
||||
jlong format);
|
||||
|
||||
#endif /* VKTexturePool_h_Included */
|
||||
@@ -25,14 +25,29 @@
|
||||
#define VKTypes_h_Included
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#define STRUCT(NAME) typedef struct NAME NAME
|
||||
/**
|
||||
* Floating-point RGBA color with sRGB encoding.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
float r, g, b, a;
|
||||
};
|
||||
VkClearValue vkClearValue;
|
||||
} Color;
|
||||
|
||||
typedef struct VKGraphicsEnvironment VKGraphicsEnvironment;
|
||||
typedef struct VKDevice VKDevice;
|
||||
typedef struct VKRenderer VKRenderer;
|
||||
typedef struct VKRenderPass VKRenderPass;
|
||||
typedef struct VKRenderingContext VKRenderingContext;
|
||||
typedef struct VKPipelineContext VKPipelineContext;
|
||||
typedef struct VKRenderPassContext VKRenderPassContext;
|
||||
typedef struct VKShaders VKShaders;
|
||||
typedef struct VKBuffer VKBuffer;
|
||||
typedef struct VKImage VKImage;
|
||||
typedef struct VKSDOps VKSDOps;
|
||||
typedef struct VKWinSDOps VKWinSDOps;
|
||||
|
||||
typedef char* pchar;
|
||||
|
||||
STRUCT(VKGraphicsEnvironment);
|
||||
STRUCT(VKLogicalDevice);
|
||||
STRUCT(VKRenderer);
|
||||
STRUCT(VKBuffer);
|
||||
STRUCT(VKImage);
|
||||
|
||||
#endif //VKTypes_h_Included
|
||||
|
||||
98
src/java.desktop/share/native/common/java2d/vulkan/VKUtil.c
Normal file
98
src/java.desktop/share/native/common/java2d/vulkan/VKUtil.c
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
#include "VKUtil.h"
|
||||
|
||||
Color VKUtil_DecodeJavaColor(uint32_t srgb) {
|
||||
// Just map [0, 255] integer colors onto [0, 1] floating-point range, it remains in sRGB color space.
|
||||
// sRGB gamma correction remains unsupported.
|
||||
static const float NormTable256[256] = {
|
||||
#define NORM1(N) ((float)(N) / 255.0F)
|
||||
#define NORM8(N) NORM1(N),NORM1(N+1),NORM1(N+2),NORM1(N+3),NORM1(N+4),NORM1(N+5),NORM1(N+6),NORM1(N+7)
|
||||
#define NORM64(N) NORM8(N),NORM8(N+8),NORM8(N+16),NORM8(N+24),NORM8(N+32),NORM8(N+40),NORM8(N+48),NORM8(N+56)
|
||||
NORM64(0),NORM64(64),NORM64(128),NORM64(192)
|
||||
};
|
||||
Color c = {
|
||||
.r = NormTable256[(srgb >> 16) & 0xFF],
|
||||
.g = NormTable256[(srgb >> 8) & 0xFF],
|
||||
.b = NormTable256[ srgb & 0xFF],
|
||||
.a = NormTable256[(srgb >> 24) & 0xFF]
|
||||
};
|
||||
return c;
|
||||
}
|
||||
|
||||
void VKUtil_LogResultError(const char* string, VkResult result) {
|
||||
const char* r;
|
||||
switch (result) {
|
||||
#define RESULT(T) case T: r = #T; break
|
||||
RESULT(VK_SUCCESS);
|
||||
RESULT(VK_NOT_READY);
|
||||
RESULT(VK_TIMEOUT);
|
||||
RESULT(VK_EVENT_SET);
|
||||
RESULT(VK_EVENT_RESET);
|
||||
RESULT(VK_INCOMPLETE);
|
||||
RESULT(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
RESULT(VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
||||
RESULT(VK_ERROR_INITIALIZATION_FAILED);
|
||||
RESULT(VK_ERROR_DEVICE_LOST);
|
||||
RESULT(VK_ERROR_MEMORY_MAP_FAILED);
|
||||
RESULT(VK_ERROR_LAYER_NOT_PRESENT);
|
||||
RESULT(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||
RESULT(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||
RESULT(VK_ERROR_INCOMPATIBLE_DRIVER);
|
||||
RESULT(VK_ERROR_TOO_MANY_OBJECTS);
|
||||
RESULT(VK_ERROR_FORMAT_NOT_SUPPORTED);
|
||||
RESULT(VK_ERROR_FRAGMENTED_POOL);
|
||||
RESULT(VK_ERROR_UNKNOWN);
|
||||
RESULT(VK_ERROR_OUT_OF_POOL_MEMORY);
|
||||
RESULT(VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
||||
RESULT(VK_ERROR_FRAGMENTATION);
|
||||
RESULT(VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS);
|
||||
RESULT(VK_PIPELINE_COMPILE_REQUIRED);
|
||||
RESULT(VK_ERROR_SURFACE_LOST_KHR);
|
||||
RESULT(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
|
||||
RESULT(VK_SUBOPTIMAL_KHR);
|
||||
RESULT(VK_ERROR_OUT_OF_DATE_KHR);
|
||||
RESULT(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
|
||||
RESULT(VK_ERROR_VALIDATION_FAILED_EXT);
|
||||
RESULT(VK_ERROR_INVALID_SHADER_NV);
|
||||
RESULT(VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR);
|
||||
RESULT(VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR);
|
||||
RESULT(VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR);
|
||||
RESULT(VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR);
|
||||
RESULT(VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR);
|
||||
RESULT(VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR);
|
||||
RESULT(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
|
||||
RESULT(VK_ERROR_NOT_PERMITTED_KHR);
|
||||
RESULT(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
|
||||
RESULT(VK_THREAD_IDLE_KHR);
|
||||
RESULT(VK_THREAD_DONE_KHR);
|
||||
RESULT(VK_OPERATION_DEFERRED_KHR);
|
||||
RESULT(VK_OPERATION_NOT_DEFERRED_KHR);
|
||||
RESULT(VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR);
|
||||
RESULT(VK_ERROR_COMPRESSION_EXHAUSTED_EXT);
|
||||
RESULT(VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT);
|
||||
default: r = "<UNKNOWN>"; break;
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, string, r)
|
||||
}
|
||||
70
src/java.desktop/share/native/common/java2d/vulkan/VKUtil.h
Normal file
70
src/java.desktop/share/native/common/java2d/vulkan/VKUtil.h
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
#ifndef VKUtil_h_Included
|
||||
#define VKUtil_h_Included
|
||||
#include <stdlib.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <Trace.h>
|
||||
#include "awt.h"
|
||||
#include "jni_util.h"
|
||||
#include "VKTypes.h"
|
||||
|
||||
#define C_ARRAY_UTIL_ALLOCATION_FAILED() VK_FATAL_ERROR("CArrayUtil allocation failed")
|
||||
#include "CArrayUtil.h"
|
||||
|
||||
// Useful logging & result checking macros
|
||||
void VKUtil_LogResultError(const char* string, VkResult result);
|
||||
inline VkBool32 VKUtil_CheckError(VkResult result, const char* errorMessage) {
|
||||
if (result != VK_SUCCESS) {
|
||||
VKUtil_LogResultError(errorMessage, result);
|
||||
return VK_TRUE;
|
||||
} else return VK_FALSE;
|
||||
}
|
||||
// Hack for converting __LINE__ to string taken from here: https://stackoverflow.com/a/19343239
|
||||
#define TO_STRING_HACK(T) #T
|
||||
#define TO_STRING(T) TO_STRING_HACK(T)
|
||||
#define LOCATION __FILE__ ": " TO_STRING(__LINE__)
|
||||
|
||||
#define VK_IF_ERROR(EXPR) if (VKUtil_CheckError(EXPR, #EXPR " == %s\n at " LOCATION))
|
||||
|
||||
#define VK_FATAL_ERROR(MESSAGE) do { \
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, MESSAGE "\n at " LOCATION); \
|
||||
JNIEnv* env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_2); \
|
||||
if (env != NULL) JNU_RUNTIME_ASSERT(env, 0, (MESSAGE)); \
|
||||
else abort(); \
|
||||
} while(0)
|
||||
#define VK_UNHANDLED_ERROR() VK_FATAL_ERROR("Unhandled Vulkan error")
|
||||
#define VK_RUNTIME_ASSERT(...) if (!(__VA_ARGS__)) VK_FATAL_ERROR("Vulkan assertion failed: " #__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Vulkan expects linear colors.
|
||||
* However Java2D expects legacy behavior, as if colors were blended in sRGB color space.
|
||||
* Therefore this function just remaps color components from [0, 255] to [0, 1] range,
|
||||
* they still represent sRGB color.
|
||||
* This is also accounted for in VKSD_ConfigureWindowSurface, so that Vulkan doesn't do any
|
||||
* color space conversions on its own, as the colors we are drawing are already in sRGB.
|
||||
*/
|
||||
Color VKUtil_DecodeJavaColor(uint32_t color);
|
||||
|
||||
#endif //VKUtil_h_Included
|
||||
@@ -1,91 +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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <string.h>
|
||||
#include "CArrayUtil.h"
|
||||
#include "VKVertex.h"
|
||||
|
||||
VKVertexDescr VKVertex_GetTxVertexDescr() {
|
||||
static VkVertexInputBindingDescription bindingDescriptions[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.stride = sizeof(VKTxVertex),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
||||
}
|
||||
};
|
||||
|
||||
static VkVertexInputAttributeDescription attributeDescriptions [] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(VKTxVertex, px)
|
||||
},
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 1,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(VKTxVertex, u)
|
||||
}
|
||||
};
|
||||
|
||||
return (VKVertexDescr) {
|
||||
.attributeDescriptions = attributeDescriptions,
|
||||
.attributeDescriptionCount = SARRAY_COUNT_OF(attributeDescriptions),
|
||||
.bindingDescriptions = bindingDescriptions,
|
||||
.bindingDescriptionCount = SARRAY_COUNT_OF(bindingDescriptions)
|
||||
};
|
||||
}
|
||||
|
||||
VKVertexDescr VKVertex_GetVertexDescr() {
|
||||
static VkVertexInputBindingDescription bindingDescriptions[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.stride = sizeof(VKVertex),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
||||
}
|
||||
};
|
||||
|
||||
static VkVertexInputAttributeDescription attributeDescriptions [] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(VKVertex, px)
|
||||
}
|
||||
};
|
||||
|
||||
return (VKVertexDescr) {
|
||||
.attributeDescriptions = attributeDescriptions,
|
||||
.attributeDescriptionCount = SARRAY_COUNT_OF(attributeDescriptions),
|
||||
.bindingDescriptions = bindingDescriptions,
|
||||
.bindingDescriptionCount = SARRAY_COUNT_OF(bindingDescriptions)
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,135 +0,0 @@
|
||||
#ifndef VULKAN_MEMORY_ALLOCATOR_HPP
|
||||
#define VULKAN_MEMORY_ALLOCATOR_HPP
|
||||
|
||||
#if !defined(AMD_VULKAN_MEMORY_ALLOCATOR_H)
|
||||
#include <vk_mem_alloc.h>
|
||||
#endif
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#if !defined(VMA_HPP_NAMESPACE)
|
||||
#define VMA_HPP_NAMESPACE vma
|
||||
#endif
|
||||
|
||||
#define VMA_HPP_NAMESPACE_STRING VULKAN_HPP_STRINGIFY(VMA_HPP_NAMESPACE)
|
||||
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
struct Dispatcher {}; // VMA uses function pointers from VmaAllocator instead
|
||||
class Allocator;
|
||||
|
||||
template<class T>
|
||||
VULKAN_HPP_NAMESPACE::UniqueHandle<T, Dispatcher> createUniqueHandle(const T& t) VULKAN_HPP_NOEXCEPT {
|
||||
return VULKAN_HPP_NAMESPACE::UniqueHandle<T, Dispatcher>(t);
|
||||
}
|
||||
template<class T, class O>
|
||||
VULKAN_HPP_NAMESPACE::UniqueHandle<T, Dispatcher> createUniqueHandle(const T& t, const O* o) VULKAN_HPP_NOEXCEPT {
|
||||
return VULKAN_HPP_NAMESPACE::UniqueHandle<T, Dispatcher>(t, o);
|
||||
}
|
||||
template<class F, class S, class O>
|
||||
std::pair<VULKAN_HPP_NAMESPACE::UniqueHandle<F, Dispatcher>, VULKAN_HPP_NAMESPACE::UniqueHandle<S, Dispatcher>>
|
||||
createUniqueHandle(const std::pair<F, S>& t, const O* o) VULKAN_HPP_NOEXCEPT {
|
||||
return {
|
||||
VULKAN_HPP_NAMESPACE::UniqueHandle<F, Dispatcher>(t.first, o),
|
||||
VULKAN_HPP_NAMESPACE::UniqueHandle<S, Dispatcher>(t.second, o)
|
||||
};
|
||||
}
|
||||
|
||||
template<class T, class UniqueVectorAllocator, class VectorAllocator, class O>
|
||||
std::vector<VULKAN_HPP_NAMESPACE::UniqueHandle<T, Dispatcher>, UniqueVectorAllocator>
|
||||
createUniqueHandleVector(const std::vector<T, VectorAllocator>& vector, const O* o,
|
||||
const UniqueVectorAllocator& vectorAllocator) VULKAN_HPP_NOEXCEPT {
|
||||
std::vector<VULKAN_HPP_NAMESPACE::UniqueHandle<T, Dispatcher>, UniqueVectorAllocator> result(vectorAllocator);
|
||||
result.reserve(vector.size());
|
||||
for (const T& t : vector) result.emplace_back(t, o);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, class Owner> class Deleter {
|
||||
const Owner* owner;
|
||||
public:
|
||||
Deleter() = default;
|
||||
Deleter(const Owner* owner) VULKAN_HPP_NOEXCEPT : owner(owner) {}
|
||||
protected:
|
||||
void destroy(const T& t) VULKAN_HPP_NOEXCEPT; // Implemented manually for each handle type
|
||||
};
|
||||
template<class T> class Deleter<T, void> {
|
||||
protected:
|
||||
void destroy(const T& t) VULKAN_HPP_NOEXCEPT { t.destroy(); }
|
||||
};
|
||||
}
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> struct UniqueHandleTraits<Buffer, VMA_HPP_NAMESPACE::Dispatcher> {
|
||||
using deleter = VMA_HPP_NAMESPACE::Deleter<Buffer, VMA_HPP_NAMESPACE::Allocator>;
|
||||
};
|
||||
template<> struct UniqueHandleTraits<Image, VMA_HPP_NAMESPACE::Dispatcher> {
|
||||
using deleter = VMA_HPP_NAMESPACE::Deleter<Image, VMA_HPP_NAMESPACE::Allocator>;
|
||||
};
|
||||
}
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
using UniqueBuffer = VULKAN_HPP_NAMESPACE::UniqueHandle<VULKAN_HPP_NAMESPACE::Buffer, Dispatcher>;
|
||||
using UniqueImage = VULKAN_HPP_NAMESPACE::UniqueHandle<VULKAN_HPP_NAMESPACE::Image, Dispatcher>;
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "vk_mem_alloc_enums.hpp"
|
||||
#include "vk_mem_alloc_handles.hpp"
|
||||
#include "vk_mem_alloc_structs.hpp"
|
||||
#include "vk_mem_alloc_funcs.hpp"
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
# define VMA_HPP_DESTROY_IMPL(NAME) \
|
||||
template<> VULKAN_HPP_INLINE void VULKAN_HPP_NAMESPACE::UniqueHandleTraits<NAME, Dispatcher>::deleter::destroy(const NAME& t) VULKAN_HPP_NOEXCEPT
|
||||
|
||||
VMA_HPP_DESTROY_IMPL(VULKAN_HPP_NAMESPACE::Buffer) { owner->destroyBuffer(t, nullptr); }
|
||||
VMA_HPP_DESTROY_IMPL(VULKAN_HPP_NAMESPACE::Image) { owner->destroyImage(t, nullptr); }
|
||||
VMA_HPP_DESTROY_IMPL(Pool) { owner->destroyPool(t); }
|
||||
VMA_HPP_DESTROY_IMPL(Allocation) { owner->freeMemory(t); }
|
||||
VMA_HPP_DESTROY_IMPL(VirtualAllocation) { owner->virtualFree(t); }
|
||||
|
||||
# undef VMA_HPP_DESTROY_IMPL
|
||||
#endif
|
||||
|
||||
template<class InstanceDispatcher, class DeviceDispatcher>
|
||||
VULKAN_HPP_CONSTEXPR VulkanFunctions functionsFromDispatcher(InstanceDispatcher const * instance,
|
||||
DeviceDispatcher const * device) VULKAN_HPP_NOEXCEPT {
|
||||
return VulkanFunctions {
|
||||
instance->vkGetInstanceProcAddr,
|
||||
instance->vkGetDeviceProcAddr,
|
||||
instance->vkGetPhysicalDeviceProperties,
|
||||
instance->vkGetPhysicalDeviceMemoryProperties,
|
||||
device->vkAllocateMemory,
|
||||
device->vkFreeMemory,
|
||||
device->vkMapMemory,
|
||||
device->vkUnmapMemory,
|
||||
device->vkFlushMappedMemoryRanges,
|
||||
device->vkInvalidateMappedMemoryRanges,
|
||||
device->vkBindBufferMemory,
|
||||
device->vkBindImageMemory,
|
||||
device->vkGetBufferMemoryRequirements,
|
||||
device->vkGetImageMemoryRequirements,
|
||||
device->vkCreateBuffer,
|
||||
device->vkDestroyBuffer,
|
||||
device->vkCreateImage,
|
||||
device->vkDestroyImage,
|
||||
device->vkCmdCopyBuffer,
|
||||
device->vkGetBufferMemoryRequirements2KHR ? device->vkGetBufferMemoryRequirements2KHR : device->vkGetBufferMemoryRequirements2,
|
||||
device->vkGetImageMemoryRequirements2KHR ? device->vkGetImageMemoryRequirements2KHR : device->vkGetImageMemoryRequirements2,
|
||||
device->vkBindBufferMemory2KHR ? device->vkBindBufferMemory2KHR : device->vkBindBufferMemory2,
|
||||
device->vkBindImageMemory2KHR ? device->vkBindImageMemory2KHR : device->vkBindImageMemory2,
|
||||
instance->vkGetPhysicalDeviceMemoryProperties2KHR ? instance->vkGetPhysicalDeviceMemoryProperties2KHR : instance->vkGetPhysicalDeviceMemoryProperties2,
|
||||
device->vkGetDeviceBufferMemoryRequirements,
|
||||
device->vkGetDeviceImageMemoryRequirements
|
||||
};
|
||||
}
|
||||
|
||||
template<class Dispatch = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
|
||||
VULKAN_HPP_CONSTEXPR VulkanFunctions functionsFromDispatcher(Dispatch const & dispatch
|
||||
VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT) VULKAN_HPP_NOEXCEPT {
|
||||
return functionsFromDispatcher(&dispatch, &dispatch);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,478 +0,0 @@
|
||||
#ifndef VULKAN_MEMORY_ALLOCATOR_ENUMS_HPP
|
||||
#define VULKAN_MEMORY_ALLOCATOR_ENUMS_HPP
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
enum class AllocatorCreateFlagBits : VmaAllocatorCreateFlags {
|
||||
eExternallySynchronized = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT,
|
||||
eKhrDedicatedAllocation = VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT,
|
||||
eKhrBindMemory2 = VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT,
|
||||
eExtMemoryBudget = VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT,
|
||||
eAmdDeviceCoherentMemory = VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT,
|
||||
eBufferDeviceAddress = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT,
|
||||
eExtMemoryPriority = VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT
|
||||
};
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(AllocatorCreateFlagBits value) {
|
||||
if (value == AllocatorCreateFlagBits::eExternallySynchronized) return "ExternallySynchronized";
|
||||
if (value == AllocatorCreateFlagBits::eKhrDedicatedAllocation) return "KhrDedicatedAllocation";
|
||||
if (value == AllocatorCreateFlagBits::eKhrBindMemory2) return "KhrBindMemory2";
|
||||
if (value == AllocatorCreateFlagBits::eExtMemoryBudget) return "ExtMemoryBudget";
|
||||
if (value == AllocatorCreateFlagBits::eAmdDeviceCoherentMemory) return "AmdDeviceCoherentMemory";
|
||||
if (value == AllocatorCreateFlagBits::eBufferDeviceAddress) return "BufferDeviceAddress";
|
||||
if (value == AllocatorCreateFlagBits::eExtMemoryPriority) return "ExtMemoryPriority";
|
||||
return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString(static_cast<uint32_t>(value)) + " )";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> struct FlagTraits<VMA_HPP_NAMESPACE::AllocatorCreateFlagBits> {
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR bool isBitmask = true;
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR Flags<VMA_HPP_NAMESPACE::AllocatorCreateFlagBits> allFlags =
|
||||
VMA_HPP_NAMESPACE::AllocatorCreateFlagBits::eExternallySynchronized
|
||||
| VMA_HPP_NAMESPACE::AllocatorCreateFlagBits::eKhrDedicatedAllocation
|
||||
| VMA_HPP_NAMESPACE::AllocatorCreateFlagBits::eKhrBindMemory2
|
||||
| VMA_HPP_NAMESPACE::AllocatorCreateFlagBits::eExtMemoryBudget
|
||||
| VMA_HPP_NAMESPACE::AllocatorCreateFlagBits::eAmdDeviceCoherentMemory
|
||||
| VMA_HPP_NAMESPACE::AllocatorCreateFlagBits::eBufferDeviceAddress
|
||||
| VMA_HPP_NAMESPACE::AllocatorCreateFlagBits::eExtMemoryPriority;
|
||||
};
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
using AllocatorCreateFlags = VULKAN_HPP_NAMESPACE::Flags<AllocatorCreateFlagBits>;
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR AllocatorCreateFlags operator|(AllocatorCreateFlagBits bit0, AllocatorCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return AllocatorCreateFlags(bit0) | bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR AllocatorCreateFlags operator&(AllocatorCreateFlagBits bit0, AllocatorCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return AllocatorCreateFlags(bit0) & bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR AllocatorCreateFlags operator^(AllocatorCreateFlagBits bit0, AllocatorCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return AllocatorCreateFlags(bit0) ^ bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR AllocatorCreateFlags operator~(AllocatorCreateFlagBits bits) VULKAN_HPP_NOEXCEPT {
|
||||
return ~(AllocatorCreateFlags(bits));
|
||||
}
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(AllocatorCreateFlags value) {
|
||||
if (!value) return "{}";
|
||||
std::string result;
|
||||
if (value & AllocatorCreateFlagBits::eExternallySynchronized) result += "ExternallySynchronized | ";
|
||||
if (value & AllocatorCreateFlagBits::eKhrDedicatedAllocation) result += "KhrDedicatedAllocation | ";
|
||||
if (value & AllocatorCreateFlagBits::eKhrBindMemory2) result += "KhrBindMemory2 | ";
|
||||
if (value & AllocatorCreateFlagBits::eExtMemoryBudget) result += "ExtMemoryBudget | ";
|
||||
if (value & AllocatorCreateFlagBits::eAmdDeviceCoherentMemory) result += "AmdDeviceCoherentMemory | ";
|
||||
if (value & AllocatorCreateFlagBits::eBufferDeviceAddress) result += "BufferDeviceAddress | ";
|
||||
if (value & AllocatorCreateFlagBits::eExtMemoryPriority) result += "ExtMemoryPriority | ";
|
||||
return "{ " + result.substr( 0, result.size() - 3 ) + " }";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
enum class MemoryUsage {
|
||||
eUnknown = VMA_MEMORY_USAGE_UNKNOWN,
|
||||
eGpuOnly = VMA_MEMORY_USAGE_GPU_ONLY,
|
||||
eCpuOnly = VMA_MEMORY_USAGE_CPU_ONLY,
|
||||
eCpuToGpu = VMA_MEMORY_USAGE_CPU_TO_GPU,
|
||||
eGpuToCpu = VMA_MEMORY_USAGE_GPU_TO_CPU,
|
||||
eCpuCopy = VMA_MEMORY_USAGE_CPU_COPY,
|
||||
eGpuLazilyAllocated = VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED,
|
||||
eAuto = VMA_MEMORY_USAGE_AUTO,
|
||||
eAutoPreferDevice = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
|
||||
eAutoPreferHost = VMA_MEMORY_USAGE_AUTO_PREFER_HOST
|
||||
};
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(MemoryUsage value) {
|
||||
if (value == MemoryUsage::eUnknown) return "Unknown";
|
||||
if (value == MemoryUsage::eGpuOnly) return "GpuOnly";
|
||||
if (value == MemoryUsage::eCpuOnly) return "CpuOnly";
|
||||
if (value == MemoryUsage::eCpuToGpu) return "CpuToGpu";
|
||||
if (value == MemoryUsage::eGpuToCpu) return "GpuToCpu";
|
||||
if (value == MemoryUsage::eCpuCopy) return "CpuCopy";
|
||||
if (value == MemoryUsage::eGpuLazilyAllocated) return "GpuLazilyAllocated";
|
||||
if (value == MemoryUsage::eAuto) return "Auto";
|
||||
if (value == MemoryUsage::eAutoPreferDevice) return "AutoPreferDevice";
|
||||
if (value == MemoryUsage::eAutoPreferHost) return "AutoPreferHost";
|
||||
return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString(static_cast<uint32_t>(value)) + " )";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
enum class AllocationCreateFlagBits : VmaAllocationCreateFlags {
|
||||
eDedicatedMemory = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||
eNeverAllocate = VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT,
|
||||
eMapped = VMA_ALLOCATION_CREATE_MAPPED_BIT,
|
||||
eUserDataCopyString = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT,
|
||||
eUpperAddress = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT,
|
||||
eDontBind = VMA_ALLOCATION_CREATE_DONT_BIND_BIT,
|
||||
eWithinBudget = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
|
||||
eCanAlias = VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT,
|
||||
eHostAccessSequentialWrite = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||
eHostAccessRandom = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
|
||||
eHostAccessAllowTransferInstead = VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT,
|
||||
eStrategyMinMemory = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT,
|
||||
eStrategyMinTime = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT,
|
||||
eStrategyMinOffset = VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT,
|
||||
eStrategyBestFit = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT,
|
||||
eStrategyFirstFit = VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT
|
||||
};
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(AllocationCreateFlagBits value) {
|
||||
if (value == AllocationCreateFlagBits::eDedicatedMemory) return "DedicatedMemory";
|
||||
if (value == AllocationCreateFlagBits::eNeverAllocate) return "NeverAllocate";
|
||||
if (value == AllocationCreateFlagBits::eMapped) return "Mapped";
|
||||
if (value == AllocationCreateFlagBits::eUserDataCopyString) return "UserDataCopyString";
|
||||
if (value == AllocationCreateFlagBits::eUpperAddress) return "UpperAddress";
|
||||
if (value == AllocationCreateFlagBits::eDontBind) return "DontBind";
|
||||
if (value == AllocationCreateFlagBits::eWithinBudget) return "WithinBudget";
|
||||
if (value == AllocationCreateFlagBits::eCanAlias) return "CanAlias";
|
||||
if (value == AllocationCreateFlagBits::eHostAccessSequentialWrite) return "HostAccessSequentialWrite";
|
||||
if (value == AllocationCreateFlagBits::eHostAccessRandom) return "HostAccessRandom";
|
||||
if (value == AllocationCreateFlagBits::eHostAccessAllowTransferInstead) return "HostAccessAllowTransferInstead";
|
||||
if (value == AllocationCreateFlagBits::eStrategyMinMemory) return "StrategyMinMemory";
|
||||
if (value == AllocationCreateFlagBits::eStrategyMinTime) return "StrategyMinTime";
|
||||
if (value == AllocationCreateFlagBits::eStrategyMinOffset) return "StrategyMinOffset";
|
||||
if (value == AllocationCreateFlagBits::eStrategyBestFit) return "StrategyBestFit";
|
||||
if (value == AllocationCreateFlagBits::eStrategyFirstFit) return "StrategyFirstFit";
|
||||
return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString(static_cast<uint32_t>(value)) + " )";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> struct FlagTraits<VMA_HPP_NAMESPACE::AllocationCreateFlagBits> {
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR bool isBitmask = true;
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR Flags<VMA_HPP_NAMESPACE::AllocationCreateFlagBits> allFlags =
|
||||
VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eDedicatedMemory
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eNeverAllocate
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eMapped
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eUserDataCopyString
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eUpperAddress
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eDontBind
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eWithinBudget
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eCanAlias
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eHostAccessSequentialWrite
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eHostAccessRandom
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eHostAccessAllowTransferInstead
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eStrategyMinMemory
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eStrategyMinTime
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eStrategyMinOffset
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eStrategyBestFit
|
||||
| VMA_HPP_NAMESPACE::AllocationCreateFlagBits::eStrategyFirstFit;
|
||||
};
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
using AllocationCreateFlags = VULKAN_HPP_NAMESPACE::Flags<AllocationCreateFlagBits>;
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR AllocationCreateFlags operator|(AllocationCreateFlagBits bit0, AllocationCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return AllocationCreateFlags(bit0) | bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR AllocationCreateFlags operator&(AllocationCreateFlagBits bit0, AllocationCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return AllocationCreateFlags(bit0) & bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR AllocationCreateFlags operator^(AllocationCreateFlagBits bit0, AllocationCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return AllocationCreateFlags(bit0) ^ bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR AllocationCreateFlags operator~(AllocationCreateFlagBits bits) VULKAN_HPP_NOEXCEPT {
|
||||
return ~(AllocationCreateFlags(bits));
|
||||
}
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(AllocationCreateFlags value) {
|
||||
if (!value) return "{}";
|
||||
std::string result;
|
||||
if (value & AllocationCreateFlagBits::eDedicatedMemory) result += "DedicatedMemory | ";
|
||||
if (value & AllocationCreateFlagBits::eNeverAllocate) result += "NeverAllocate | ";
|
||||
if (value & AllocationCreateFlagBits::eMapped) result += "Mapped | ";
|
||||
if (value & AllocationCreateFlagBits::eUserDataCopyString) result += "UserDataCopyString | ";
|
||||
if (value & AllocationCreateFlagBits::eUpperAddress) result += "UpperAddress | ";
|
||||
if (value & AllocationCreateFlagBits::eDontBind) result += "DontBind | ";
|
||||
if (value & AllocationCreateFlagBits::eWithinBudget) result += "WithinBudget | ";
|
||||
if (value & AllocationCreateFlagBits::eCanAlias) result += "CanAlias | ";
|
||||
if (value & AllocationCreateFlagBits::eHostAccessSequentialWrite) result += "HostAccessSequentialWrite | ";
|
||||
if (value & AllocationCreateFlagBits::eHostAccessRandom) result += "HostAccessRandom | ";
|
||||
if (value & AllocationCreateFlagBits::eHostAccessAllowTransferInstead) result += "HostAccessAllowTransferInstead | ";
|
||||
if (value & AllocationCreateFlagBits::eStrategyMinMemory) result += "StrategyMinMemory | ";
|
||||
if (value & AllocationCreateFlagBits::eStrategyMinTime) result += "StrategyMinTime | ";
|
||||
if (value & AllocationCreateFlagBits::eStrategyMinOffset) result += "StrategyMinOffset | ";
|
||||
if (value & AllocationCreateFlagBits::eStrategyBestFit) result += "StrategyBestFit | ";
|
||||
if (value & AllocationCreateFlagBits::eStrategyFirstFit) result += "StrategyFirstFit | ";
|
||||
return "{ " + result.substr( 0, result.size() - 3 ) + " }";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
enum class PoolCreateFlagBits : VmaPoolCreateFlags {
|
||||
eIgnoreBufferImageGranularity = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT,
|
||||
eLinearAlgorithm = VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT
|
||||
};
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(PoolCreateFlagBits value) {
|
||||
if (value == PoolCreateFlagBits::eIgnoreBufferImageGranularity) return "IgnoreBufferImageGranularity";
|
||||
if (value == PoolCreateFlagBits::eLinearAlgorithm) return "LinearAlgorithm";
|
||||
return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString(static_cast<uint32_t>(value)) + " )";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> struct FlagTraits<VMA_HPP_NAMESPACE::PoolCreateFlagBits> {
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR bool isBitmask = true;
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR Flags<VMA_HPP_NAMESPACE::PoolCreateFlagBits> allFlags =
|
||||
VMA_HPP_NAMESPACE::PoolCreateFlagBits::eIgnoreBufferImageGranularity
|
||||
| VMA_HPP_NAMESPACE::PoolCreateFlagBits::eLinearAlgorithm;
|
||||
};
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
using PoolCreateFlags = VULKAN_HPP_NAMESPACE::Flags<PoolCreateFlagBits>;
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR PoolCreateFlags operator|(PoolCreateFlagBits bit0, PoolCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return PoolCreateFlags(bit0) | bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR PoolCreateFlags operator&(PoolCreateFlagBits bit0, PoolCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return PoolCreateFlags(bit0) & bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR PoolCreateFlags operator^(PoolCreateFlagBits bit0, PoolCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return PoolCreateFlags(bit0) ^ bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR PoolCreateFlags operator~(PoolCreateFlagBits bits) VULKAN_HPP_NOEXCEPT {
|
||||
return ~(PoolCreateFlags(bits));
|
||||
}
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(PoolCreateFlags value) {
|
||||
if (!value) return "{}";
|
||||
std::string result;
|
||||
if (value & PoolCreateFlagBits::eIgnoreBufferImageGranularity) result += "IgnoreBufferImageGranularity | ";
|
||||
if (value & PoolCreateFlagBits::eLinearAlgorithm) result += "LinearAlgorithm | ";
|
||||
return "{ " + result.substr( 0, result.size() - 3 ) + " }";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
enum class DefragmentationFlagBits : VmaDefragmentationFlags {
|
||||
eFlagAlgorithmFast = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT,
|
||||
eFlagAlgorithmBalanced = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT,
|
||||
eFlagAlgorithmFull = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT,
|
||||
eFlagAlgorithmExtensive = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT
|
||||
};
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(DefragmentationFlagBits value) {
|
||||
if (value == DefragmentationFlagBits::eFlagAlgorithmFast) return "FlagAlgorithmFast";
|
||||
if (value == DefragmentationFlagBits::eFlagAlgorithmBalanced) return "FlagAlgorithmBalanced";
|
||||
if (value == DefragmentationFlagBits::eFlagAlgorithmFull) return "FlagAlgorithmFull";
|
||||
if (value == DefragmentationFlagBits::eFlagAlgorithmExtensive) return "FlagAlgorithmExtensive";
|
||||
return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString(static_cast<uint32_t>(value)) + " )";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> struct FlagTraits<VMA_HPP_NAMESPACE::DefragmentationFlagBits> {
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR bool isBitmask = true;
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR Flags<VMA_HPP_NAMESPACE::DefragmentationFlagBits> allFlags =
|
||||
VMA_HPP_NAMESPACE::DefragmentationFlagBits::eFlagAlgorithmFast
|
||||
| VMA_HPP_NAMESPACE::DefragmentationFlagBits::eFlagAlgorithmBalanced
|
||||
| VMA_HPP_NAMESPACE::DefragmentationFlagBits::eFlagAlgorithmFull
|
||||
| VMA_HPP_NAMESPACE::DefragmentationFlagBits::eFlagAlgorithmExtensive;
|
||||
};
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
using DefragmentationFlags = VULKAN_HPP_NAMESPACE::Flags<DefragmentationFlagBits>;
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR DefragmentationFlags operator|(DefragmentationFlagBits bit0, DefragmentationFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return DefragmentationFlags(bit0) | bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR DefragmentationFlags operator&(DefragmentationFlagBits bit0, DefragmentationFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return DefragmentationFlags(bit0) & bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR DefragmentationFlags operator^(DefragmentationFlagBits bit0, DefragmentationFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return DefragmentationFlags(bit0) ^ bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR DefragmentationFlags operator~(DefragmentationFlagBits bits) VULKAN_HPP_NOEXCEPT {
|
||||
return ~(DefragmentationFlags(bits));
|
||||
}
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(DefragmentationFlags value) {
|
||||
if (!value) return "{}";
|
||||
std::string result;
|
||||
if (value & DefragmentationFlagBits::eFlagAlgorithmFast) result += "FlagAlgorithmFast | ";
|
||||
if (value & DefragmentationFlagBits::eFlagAlgorithmBalanced) result += "FlagAlgorithmBalanced | ";
|
||||
if (value & DefragmentationFlagBits::eFlagAlgorithmFull) result += "FlagAlgorithmFull | ";
|
||||
if (value & DefragmentationFlagBits::eFlagAlgorithmExtensive) result += "FlagAlgorithmExtensive | ";
|
||||
return "{ " + result.substr( 0, result.size() - 3 ) + " }";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
enum class DefragmentationMoveOperation {
|
||||
eCopy = VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY,
|
||||
eIgnore = VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE,
|
||||
eDestroy = VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY
|
||||
};
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(DefragmentationMoveOperation value) {
|
||||
if (value == DefragmentationMoveOperation::eCopy) return "Copy";
|
||||
if (value == DefragmentationMoveOperation::eIgnore) return "Ignore";
|
||||
if (value == DefragmentationMoveOperation::eDestroy) return "Destroy";
|
||||
return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString(static_cast<uint32_t>(value)) + " )";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
enum class VirtualBlockCreateFlagBits : VmaVirtualBlockCreateFlags {
|
||||
eLinearAlgorithm = VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT
|
||||
};
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(VirtualBlockCreateFlagBits value) {
|
||||
if (value == VirtualBlockCreateFlagBits::eLinearAlgorithm) return "LinearAlgorithm";
|
||||
return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString(static_cast<uint32_t>(value)) + " )";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> struct FlagTraits<VMA_HPP_NAMESPACE::VirtualBlockCreateFlagBits> {
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR bool isBitmask = true;
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR Flags<VMA_HPP_NAMESPACE::VirtualBlockCreateFlagBits> allFlags =
|
||||
VMA_HPP_NAMESPACE::VirtualBlockCreateFlagBits::eLinearAlgorithm;
|
||||
};
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
using VirtualBlockCreateFlags = VULKAN_HPP_NAMESPACE::Flags<VirtualBlockCreateFlagBits>;
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR VirtualBlockCreateFlags operator|(VirtualBlockCreateFlagBits bit0, VirtualBlockCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return VirtualBlockCreateFlags(bit0) | bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR VirtualBlockCreateFlags operator&(VirtualBlockCreateFlagBits bit0, VirtualBlockCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return VirtualBlockCreateFlags(bit0) & bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR VirtualBlockCreateFlags operator^(VirtualBlockCreateFlagBits bit0, VirtualBlockCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return VirtualBlockCreateFlags(bit0) ^ bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR VirtualBlockCreateFlags operator~(VirtualBlockCreateFlagBits bits) VULKAN_HPP_NOEXCEPT {
|
||||
return ~(VirtualBlockCreateFlags(bits));
|
||||
}
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(VirtualBlockCreateFlags value) {
|
||||
if (!value) return "{}";
|
||||
std::string result;
|
||||
if (value & VirtualBlockCreateFlagBits::eLinearAlgorithm) result += "LinearAlgorithm | ";
|
||||
return "{ " + result.substr( 0, result.size() - 3 ) + " }";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
enum class VirtualAllocationCreateFlagBits : VmaVirtualAllocationCreateFlags {
|
||||
eUpperAddress = VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT,
|
||||
eStrategyMinMemory = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT,
|
||||
eStrategyMinTime = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT,
|
||||
eStrategyMinOffset = VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT
|
||||
};
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(VirtualAllocationCreateFlagBits value) {
|
||||
if (value == VirtualAllocationCreateFlagBits::eUpperAddress) return "UpperAddress";
|
||||
if (value == VirtualAllocationCreateFlagBits::eStrategyMinMemory) return "StrategyMinMemory";
|
||||
if (value == VirtualAllocationCreateFlagBits::eStrategyMinTime) return "StrategyMinTime";
|
||||
if (value == VirtualAllocationCreateFlagBits::eStrategyMinOffset) return "StrategyMinOffset";
|
||||
return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString(static_cast<uint32_t>(value)) + " )";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> struct FlagTraits<VMA_HPP_NAMESPACE::VirtualAllocationCreateFlagBits> {
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR bool isBitmask = true;
|
||||
static VULKAN_HPP_CONST_OR_CONSTEXPR Flags<VMA_HPP_NAMESPACE::VirtualAllocationCreateFlagBits> allFlags =
|
||||
VMA_HPP_NAMESPACE::VirtualAllocationCreateFlagBits::eUpperAddress
|
||||
| VMA_HPP_NAMESPACE::VirtualAllocationCreateFlagBits::eStrategyMinMemory
|
||||
| VMA_HPP_NAMESPACE::VirtualAllocationCreateFlagBits::eStrategyMinTime
|
||||
| VMA_HPP_NAMESPACE::VirtualAllocationCreateFlagBits::eStrategyMinOffset;
|
||||
};
|
||||
}
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
using VirtualAllocationCreateFlags = VULKAN_HPP_NAMESPACE::Flags<VirtualAllocationCreateFlagBits>;
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR VirtualAllocationCreateFlags operator|(VirtualAllocationCreateFlagBits bit0, VirtualAllocationCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return VirtualAllocationCreateFlags(bit0) | bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR VirtualAllocationCreateFlags operator&(VirtualAllocationCreateFlagBits bit0, VirtualAllocationCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return VirtualAllocationCreateFlags(bit0) & bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR VirtualAllocationCreateFlags operator^(VirtualAllocationCreateFlagBits bit0, VirtualAllocationCreateFlagBits bit1) VULKAN_HPP_NOEXCEPT {
|
||||
return VirtualAllocationCreateFlags(bit0) ^ bit1;
|
||||
}
|
||||
|
||||
VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR VirtualAllocationCreateFlags operator~(VirtualAllocationCreateFlagBits bits) VULKAN_HPP_NOEXCEPT {
|
||||
return ~(VirtualAllocationCreateFlags(bits));
|
||||
}
|
||||
|
||||
# if !defined( VULKAN_HPP_NO_TO_STRING )
|
||||
VULKAN_HPP_INLINE std::string to_string(VirtualAllocationCreateFlags value) {
|
||||
if (!value) return "{}";
|
||||
std::string result;
|
||||
if (value & VirtualAllocationCreateFlagBits::eUpperAddress) result += "UpperAddress | ";
|
||||
if (value & VirtualAllocationCreateFlagBits::eStrategyMinMemory) result += "StrategyMinMemory | ";
|
||||
if (value & VirtualAllocationCreateFlagBits::eStrategyMinTime) result += "StrategyMinTime | ";
|
||||
if (value & VirtualAllocationCreateFlagBits::eStrategyMinOffset) result += "StrategyMinOffset | ";
|
||||
return "{ " + result.substr( 0, result.size() - 3 ) + " }";
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,935 +0,0 @@
|
||||
#ifndef VULKAN_MEMORY_ALLOCATOR_HANDLES_HPP
|
||||
#define VULKAN_MEMORY_ALLOCATOR_HANDLES_HPP
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
struct DeviceMemoryCallbacks;
|
||||
struct VulkanFunctions;
|
||||
struct AllocatorCreateInfo;
|
||||
struct AllocatorInfo;
|
||||
struct Statistics;
|
||||
struct DetailedStatistics;
|
||||
struct TotalStatistics;
|
||||
struct Budget;
|
||||
struct AllocationCreateInfo;
|
||||
struct PoolCreateInfo;
|
||||
struct AllocationInfo;
|
||||
struct DefragmentationInfo;
|
||||
struct DefragmentationMove;
|
||||
struct DefragmentationPassMoveInfo;
|
||||
struct DefragmentationStats;
|
||||
struct VirtualBlockCreateInfo;
|
||||
struct VirtualAllocationCreateInfo;
|
||||
struct VirtualAllocationInfo;
|
||||
|
||||
class Allocator;
|
||||
class Pool;
|
||||
class Allocation;
|
||||
class DefragmentationContext;
|
||||
class VirtualAllocation;
|
||||
class VirtualBlock;
|
||||
}
|
||||
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
class Pool {
|
||||
public:
|
||||
using CType = VmaPool;
|
||||
using NativeType = VmaPool;
|
||||
public:
|
||||
VULKAN_HPP_CONSTEXPR Pool() = default;
|
||||
VULKAN_HPP_CONSTEXPR Pool(std::nullptr_t) VULKAN_HPP_NOEXCEPT {}
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT Pool(VmaPool pool) VULKAN_HPP_NOEXCEPT : m_pool(pool) {}
|
||||
|
||||
#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)
|
||||
Pool& operator=(VmaPool pool) VULKAN_HPP_NOEXCEPT {
|
||||
m_pool = pool;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
Pool& operator=(std::nullptr_t) VULKAN_HPP_NOEXCEPT {
|
||||
m_pool = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined( VULKAN_HPP_HAS_SPACESHIP_OPERATOR )
|
||||
auto operator<=>(Pool const &) const = default;
|
||||
#else
|
||||
bool operator==(Pool const & rhs) const VULKAN_HPP_NOEXCEPT {
|
||||
return m_pool == rhs.m_pool;
|
||||
}
|
||||
#endif
|
||||
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT operator VmaPool() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_pool;
|
||||
}
|
||||
|
||||
explicit operator bool() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_pool != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
bool operator!() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_pool == VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
private:
|
||||
VmaPool m_pool = {};
|
||||
};
|
||||
VULKAN_HPP_STATIC_ASSERT(sizeof(Pool) == sizeof(VmaPool),
|
||||
"handle and wrapper have different size!");
|
||||
}
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> class UniqueHandleTraits<VMA_HPP_NAMESPACE::Pool, VMA_HPP_NAMESPACE::Dispatcher> {
|
||||
public:
|
||||
using deleter = VMA_HPP_NAMESPACE::Deleter<VMA_HPP_NAMESPACE::Pool, VMA_HPP_NAMESPACE::Allocator>;
|
||||
};
|
||||
}
|
||||
namespace VMA_HPP_NAMESPACE { using UniquePool = VULKAN_HPP_NAMESPACE::UniqueHandle<Pool, Dispatcher>; }
|
||||
#endif
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
class Allocation {
|
||||
public:
|
||||
using CType = VmaAllocation;
|
||||
using NativeType = VmaAllocation;
|
||||
public:
|
||||
VULKAN_HPP_CONSTEXPR Allocation() = default;
|
||||
VULKAN_HPP_CONSTEXPR Allocation(std::nullptr_t) VULKAN_HPP_NOEXCEPT {}
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT Allocation(VmaAllocation allocation) VULKAN_HPP_NOEXCEPT : m_allocation(allocation) {}
|
||||
|
||||
#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)
|
||||
Allocation& operator=(VmaAllocation allocation) VULKAN_HPP_NOEXCEPT {
|
||||
m_allocation = allocation;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
Allocation& operator=(std::nullptr_t) VULKAN_HPP_NOEXCEPT {
|
||||
m_allocation = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined( VULKAN_HPP_HAS_SPACESHIP_OPERATOR )
|
||||
auto operator<=>(Allocation const &) const = default;
|
||||
#else
|
||||
bool operator==(Allocation const & rhs) const VULKAN_HPP_NOEXCEPT {
|
||||
return m_allocation == rhs.m_allocation;
|
||||
}
|
||||
#endif
|
||||
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT operator VmaAllocation() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_allocation;
|
||||
}
|
||||
|
||||
explicit operator bool() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_allocation != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
bool operator!() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_allocation == VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
private:
|
||||
VmaAllocation m_allocation = {};
|
||||
};
|
||||
VULKAN_HPP_STATIC_ASSERT(sizeof(Allocation) == sizeof(VmaAllocation),
|
||||
"handle and wrapper have different size!");
|
||||
}
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> class UniqueHandleTraits<VMA_HPP_NAMESPACE::Allocation, VMA_HPP_NAMESPACE::Dispatcher> {
|
||||
public:
|
||||
using deleter = VMA_HPP_NAMESPACE::Deleter<VMA_HPP_NAMESPACE::Allocation, VMA_HPP_NAMESPACE::Allocator>;
|
||||
};
|
||||
}
|
||||
namespace VMA_HPP_NAMESPACE { using UniqueAllocation = VULKAN_HPP_NAMESPACE::UniqueHandle<Allocation, Dispatcher>; }
|
||||
#endif
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
class DefragmentationContext {
|
||||
public:
|
||||
using CType = VmaDefragmentationContext;
|
||||
using NativeType = VmaDefragmentationContext;
|
||||
public:
|
||||
VULKAN_HPP_CONSTEXPR DefragmentationContext() = default;
|
||||
VULKAN_HPP_CONSTEXPR DefragmentationContext(std::nullptr_t) VULKAN_HPP_NOEXCEPT {}
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT DefragmentationContext(VmaDefragmentationContext defragmentationContext) VULKAN_HPP_NOEXCEPT : m_defragmentationContext(defragmentationContext) {}
|
||||
|
||||
#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)
|
||||
DefragmentationContext& operator=(VmaDefragmentationContext defragmentationContext) VULKAN_HPP_NOEXCEPT {
|
||||
m_defragmentationContext = defragmentationContext;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
DefragmentationContext& operator=(std::nullptr_t) VULKAN_HPP_NOEXCEPT {
|
||||
m_defragmentationContext = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined( VULKAN_HPP_HAS_SPACESHIP_OPERATOR )
|
||||
auto operator<=>(DefragmentationContext const &) const = default;
|
||||
#else
|
||||
bool operator==(DefragmentationContext const & rhs) const VULKAN_HPP_NOEXCEPT {
|
||||
return m_defragmentationContext == rhs.m_defragmentationContext;
|
||||
}
|
||||
#endif
|
||||
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT operator VmaDefragmentationContext() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_defragmentationContext;
|
||||
}
|
||||
|
||||
explicit operator bool() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_defragmentationContext != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
bool operator!() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_defragmentationContext == VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
private:
|
||||
VmaDefragmentationContext m_defragmentationContext = {};
|
||||
};
|
||||
VULKAN_HPP_STATIC_ASSERT(sizeof(DefragmentationContext) == sizeof(VmaDefragmentationContext),
|
||||
"handle and wrapper have different size!");
|
||||
}
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> class UniqueHandleTraits<VMA_HPP_NAMESPACE::DefragmentationContext, VMA_HPP_NAMESPACE::Dispatcher> {
|
||||
public:
|
||||
using deleter = VMA_HPP_NAMESPACE::Deleter<VMA_HPP_NAMESPACE::DefragmentationContext, void>;
|
||||
};
|
||||
}
|
||||
namespace VMA_HPP_NAMESPACE { using UniqueDefragmentationContext = VULKAN_HPP_NAMESPACE::UniqueHandle<DefragmentationContext, Dispatcher>; }
|
||||
#endif
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
class Allocator {
|
||||
public:
|
||||
using CType = VmaAllocator;
|
||||
using NativeType = VmaAllocator;
|
||||
public:
|
||||
VULKAN_HPP_CONSTEXPR Allocator() = default;
|
||||
VULKAN_HPP_CONSTEXPR Allocator(std::nullptr_t) VULKAN_HPP_NOEXCEPT {}
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT Allocator(VmaAllocator allocator) VULKAN_HPP_NOEXCEPT : m_allocator(allocator) {}
|
||||
|
||||
#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)
|
||||
Allocator& operator=(VmaAllocator allocator) VULKAN_HPP_NOEXCEPT {
|
||||
m_allocator = allocator;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
Allocator& operator=(std::nullptr_t) VULKAN_HPP_NOEXCEPT {
|
||||
m_allocator = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined( VULKAN_HPP_HAS_SPACESHIP_OPERATOR )
|
||||
auto operator<=>(Allocator const &) const = default;
|
||||
#else
|
||||
bool operator==(Allocator const & rhs) const VULKAN_HPP_NOEXCEPT {
|
||||
return m_allocator == rhs.m_allocator;
|
||||
}
|
||||
#endif
|
||||
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT operator VmaAllocator() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_allocator;
|
||||
}
|
||||
|
||||
explicit operator bool() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_allocator != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
bool operator!() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_allocator == VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void destroy() const;
|
||||
#else
|
||||
void destroy() const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS AllocatorInfo getAllocatorInfo() const;
|
||||
#endif
|
||||
void getAllocatorInfo(AllocatorInfo* allocatorInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS const VULKAN_HPP_NAMESPACE::PhysicalDeviceProperties* getPhysicalDeviceProperties() const;
|
||||
#endif
|
||||
void getPhysicalDeviceProperties(const VULKAN_HPP_NAMESPACE::PhysicalDeviceProperties** physicalDeviceProperties) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS const VULKAN_HPP_NAMESPACE::PhysicalDeviceMemoryProperties* getMemoryProperties() const;
|
||||
#endif
|
||||
void getMemoryProperties(const VULKAN_HPP_NAMESPACE::PhysicalDeviceMemoryProperties** physicalDeviceMemoryProperties) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS VULKAN_HPP_NAMESPACE::MemoryPropertyFlags getMemoryTypeProperties(uint32_t memoryTypeIndex) const;
|
||||
#endif
|
||||
void getMemoryTypeProperties(uint32_t memoryTypeIndex,
|
||||
VULKAN_HPP_NAMESPACE::MemoryPropertyFlags* flags) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void setCurrentFrameIndex(uint32_t frameIndex) const;
|
||||
#else
|
||||
void setCurrentFrameIndex(uint32_t frameIndex) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS TotalStatistics calculateStatistics() const;
|
||||
#endif
|
||||
void calculateStatistics(TotalStatistics* stats) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
template<typename VectorAllocator = std::allocator<Budget>,
|
||||
typename B = VectorAllocator,
|
||||
typename std::enable_if<std::is_same<typename B::value_type, Budget>::value, int>::type = 0>
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS std::vector<Budget, VectorAllocator> getHeapBudgets(VectorAllocator& vectorAllocator) const;
|
||||
|
||||
template<typename VectorAllocator = std::allocator<Budget>>
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS std::vector<Budget, VectorAllocator> getHeapBudgets() const;
|
||||
#endif
|
||||
void getHeapBudgets(Budget* budgets) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<uint32_t>::type findMemoryTypeIndex(uint32_t memoryTypeBits,
|
||||
const AllocationCreateInfo& allocationCreateInfo) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result findMemoryTypeIndex(uint32_t memoryTypeBits,
|
||||
const AllocationCreateInfo* allocationCreateInfo,
|
||||
uint32_t* memoryTypeIndex) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<uint32_t>::type findMemoryTypeIndexForBufferInfo(const VULKAN_HPP_NAMESPACE::BufferCreateInfo& bufferCreateInfo,
|
||||
const AllocationCreateInfo& allocationCreateInfo) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result findMemoryTypeIndexForBufferInfo(const VULKAN_HPP_NAMESPACE::BufferCreateInfo* bufferCreateInfo,
|
||||
const AllocationCreateInfo* allocationCreateInfo,
|
||||
uint32_t* memoryTypeIndex) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<uint32_t>::type findMemoryTypeIndexForImageInfo(const VULKAN_HPP_NAMESPACE::ImageCreateInfo& imageCreateInfo,
|
||||
const AllocationCreateInfo& allocationCreateInfo) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result findMemoryTypeIndexForImageInfo(const VULKAN_HPP_NAMESPACE::ImageCreateInfo* imageCreateInfo,
|
||||
const AllocationCreateInfo* allocationCreateInfo,
|
||||
uint32_t* memoryTypeIndex) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<Pool>::type createPool(const PoolCreateInfo& createInfo) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<UniquePool>::type createPoolUnique(const PoolCreateInfo& createInfo) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result createPool(const PoolCreateInfo* createInfo,
|
||||
Pool* pool) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void destroyPool(Pool pool) const;
|
||||
#else
|
||||
void destroyPool(Pool pool) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS Statistics getPoolStatistics(Pool pool) const;
|
||||
#endif
|
||||
void getPoolStatistics(Pool pool,
|
||||
Statistics* poolStats) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS DetailedStatistics calculatePoolStatistics(Pool pool) const;
|
||||
#endif
|
||||
void calculatePoolStatistics(Pool pool,
|
||||
DetailedStatistics* poolStats) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type checkPoolCorruption(Pool pool) const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result checkPoolCorruption(Pool pool) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS const char* getPoolName(Pool pool) const;
|
||||
#endif
|
||||
void getPoolName(Pool pool,
|
||||
const char** name) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void setPoolName(Pool pool,
|
||||
const char* name) const;
|
||||
#else
|
||||
void setPoolName(Pool pool,
|
||||
const char* name) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<Allocation>::type allocateMemory(const VULKAN_HPP_NAMESPACE::MemoryRequirements& vkMemoryRequirements,
|
||||
const AllocationCreateInfo& createInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<UniqueAllocation>::type allocateMemoryUnique(const VULKAN_HPP_NAMESPACE::MemoryRequirements& vkMemoryRequirements,
|
||||
const AllocationCreateInfo& createInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result allocateMemory(const VULKAN_HPP_NAMESPACE::MemoryRequirements* vkMemoryRequirements,
|
||||
const AllocationCreateInfo* createInfo,
|
||||
Allocation* allocation,
|
||||
AllocationInfo* allocationInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
template<typename VectorAllocator = std::allocator<Allocation>,
|
||||
typename B = VectorAllocator,
|
||||
typename std::enable_if<std::is_same<typename B::value_type, Allocation>::value, int>::type = 0>
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::vector<Allocation, VectorAllocator>>::type allocateMemoryPages(VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::MemoryRequirements> vkMemoryRequirements,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxy<const AllocationCreateInfo> createInfo,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries<AllocationInfo> allocationInfo,
|
||||
VectorAllocator& vectorAllocator) const;
|
||||
|
||||
template<typename VectorAllocator = std::allocator<Allocation>>
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::vector<Allocation, VectorAllocator>>::type allocateMemoryPages(VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::MemoryRequirements> vkMemoryRequirements,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxy<const AllocationCreateInfo> createInfo,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
template<typename VectorAllocator = std::allocator<UniqueAllocation>,
|
||||
typename B = VectorAllocator,
|
||||
typename std::enable_if<std::is_same<typename B::value_type, UniqueAllocation>::value, int>::type = 0>
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::vector<UniqueAllocation, VectorAllocator>>::type allocateMemoryPagesUnique(VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::MemoryRequirements> vkMemoryRequirements,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxy<const AllocationCreateInfo> createInfo,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries<AllocationInfo> allocationInfo,
|
||||
VectorAllocator& vectorAllocator) const;
|
||||
|
||||
template<typename VectorAllocator = std::allocator<UniqueAllocation>>
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::vector<UniqueAllocation, VectorAllocator>>::type allocateMemoryPagesUnique(VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::MemoryRequirements> vkMemoryRequirements,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxy<const AllocationCreateInfo> createInfo,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result allocateMemoryPages(const VULKAN_HPP_NAMESPACE::MemoryRequirements* vkMemoryRequirements,
|
||||
const AllocationCreateInfo* createInfo,
|
||||
size_t allocationCount,
|
||||
Allocation* allocations,
|
||||
AllocationInfo* allocationInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<Allocation>::type allocateMemoryForBuffer(VULKAN_HPP_NAMESPACE::Buffer buffer,
|
||||
const AllocationCreateInfo& createInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<UniqueAllocation>::type allocateMemoryForBufferUnique(VULKAN_HPP_NAMESPACE::Buffer buffer,
|
||||
const AllocationCreateInfo& createInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result allocateMemoryForBuffer(VULKAN_HPP_NAMESPACE::Buffer buffer,
|
||||
const AllocationCreateInfo* createInfo,
|
||||
Allocation* allocation,
|
||||
AllocationInfo* allocationInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<Allocation>::type allocateMemoryForImage(VULKAN_HPP_NAMESPACE::Image image,
|
||||
const AllocationCreateInfo& createInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<UniqueAllocation>::type allocateMemoryForImageUnique(VULKAN_HPP_NAMESPACE::Image image,
|
||||
const AllocationCreateInfo& createInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result allocateMemoryForImage(VULKAN_HPP_NAMESPACE::Image image,
|
||||
const AllocationCreateInfo* createInfo,
|
||||
Allocation* allocation,
|
||||
AllocationInfo* allocationInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void freeMemory(Allocation allocation) const;
|
||||
#else
|
||||
void freeMemory(Allocation allocation) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void freeMemoryPages(VULKAN_HPP_NAMESPACE::ArrayProxy<const Allocation> allocations) const;
|
||||
#endif
|
||||
void freeMemoryPages(size_t allocationCount,
|
||||
const Allocation* allocations) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS AllocationInfo getAllocationInfo(Allocation allocation) const;
|
||||
#endif
|
||||
void getAllocationInfo(Allocation allocation,
|
||||
AllocationInfo* allocationInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void setAllocationUserData(Allocation allocation,
|
||||
void* userData) const;
|
||||
#else
|
||||
void setAllocationUserData(Allocation allocation,
|
||||
void* userData) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void setAllocationName(Allocation allocation,
|
||||
const char* name) const;
|
||||
#else
|
||||
void setAllocationName(Allocation allocation,
|
||||
const char* name) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS VULKAN_HPP_NAMESPACE::MemoryPropertyFlags getAllocationMemoryProperties(Allocation allocation) const;
|
||||
#endif
|
||||
void getAllocationMemoryProperties(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::MemoryPropertyFlags* flags) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<void*>::type mapMemory(Allocation allocation) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result mapMemory(Allocation allocation,
|
||||
void** data) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void unmapMemory(Allocation allocation) const;
|
||||
#else
|
||||
void unmapMemory(Allocation allocation) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type flushAllocation(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize offset,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize size) const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result flushAllocation(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize offset,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize size) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type invalidateAllocation(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize offset,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize size) const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result invalidateAllocation(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize offset,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize size) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type flushAllocations(VULKAN_HPP_NAMESPACE::ArrayProxy<const Allocation> allocations,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::DeviceSize> offsets,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::DeviceSize> sizes) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result flushAllocations(uint32_t allocationCount,
|
||||
const Allocation* allocations,
|
||||
const VULKAN_HPP_NAMESPACE::DeviceSize* offsets,
|
||||
const VULKAN_HPP_NAMESPACE::DeviceSize* sizes) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type invalidateAllocations(VULKAN_HPP_NAMESPACE::ArrayProxy<const Allocation> allocations,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::DeviceSize> offsets,
|
||||
VULKAN_HPP_NAMESPACE::ArrayProxy<const VULKAN_HPP_NAMESPACE::DeviceSize> sizes) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result invalidateAllocations(uint32_t allocationCount,
|
||||
const Allocation* allocations,
|
||||
const VULKAN_HPP_NAMESPACE::DeviceSize* offsets,
|
||||
const VULKAN_HPP_NAMESPACE::DeviceSize* sizes) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type checkCorruption(uint32_t memoryTypeBits) const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result checkCorruption(uint32_t memoryTypeBits) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<DefragmentationContext>::type beginDefragmentation(const DefragmentationInfo& info) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result beginDefragmentation(const DefragmentationInfo* info,
|
||||
DefragmentationContext* context) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void endDefragmentation(DefragmentationContext context,
|
||||
VULKAN_HPP_NAMESPACE::Optional<DefragmentationStats> stats = nullptr) const;
|
||||
#endif
|
||||
void endDefragmentation(DefragmentationContext context,
|
||||
DefragmentationStats* stats) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<DefragmentationPassMoveInfo>::type beginDefragmentationPass(DefragmentationContext context) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result beginDefragmentationPass(DefragmentationContext context,
|
||||
DefragmentationPassMoveInfo* passInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<DefragmentationPassMoveInfo>::type endDefragmentationPass(DefragmentationContext context) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result endDefragmentationPass(DefragmentationContext context,
|
||||
DefragmentationPassMoveInfo* passInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type bindBufferMemory(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::Buffer buffer) const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result bindBufferMemory(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::Buffer buffer) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type bindBufferMemory2(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize allocationLocalOffset,
|
||||
VULKAN_HPP_NAMESPACE::Buffer buffer,
|
||||
const void* next) const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result bindBufferMemory2(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize allocationLocalOffset,
|
||||
VULKAN_HPP_NAMESPACE::Buffer buffer,
|
||||
const void* next) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type bindImageMemory(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::Image image) const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result bindImageMemory(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::Image image) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
typename VULKAN_HPP_NAMESPACE::ResultValueType<void>::type bindImageMemory2(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize allocationLocalOffset,
|
||||
VULKAN_HPP_NAMESPACE::Image image,
|
||||
const void* next) const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result bindImageMemory2(Allocation allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize allocationLocalOffset,
|
||||
VULKAN_HPP_NAMESPACE::Image image,
|
||||
const void* next) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::pair<VULKAN_HPP_NAMESPACE::Buffer, Allocation>>::type createBuffer(const VULKAN_HPP_NAMESPACE::BufferCreateInfo& bufferCreateInfo,
|
||||
const AllocationCreateInfo& allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::pair<UniqueBuffer, UniqueAllocation>>::type createBufferUnique(const VULKAN_HPP_NAMESPACE::BufferCreateInfo& bufferCreateInfo,
|
||||
const AllocationCreateInfo& allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result createBuffer(const VULKAN_HPP_NAMESPACE::BufferCreateInfo* bufferCreateInfo,
|
||||
const AllocationCreateInfo* allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::Buffer* buffer,
|
||||
Allocation* allocation,
|
||||
AllocationInfo* allocationInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::pair<VULKAN_HPP_NAMESPACE::Buffer, Allocation>>::type createBufferWithAlignment(const VULKAN_HPP_NAMESPACE::BufferCreateInfo& bufferCreateInfo,
|
||||
const AllocationCreateInfo& allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize minAlignment,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::pair<UniqueBuffer, UniqueAllocation>>::type createBufferWithAlignmentUnique(const VULKAN_HPP_NAMESPACE::BufferCreateInfo& bufferCreateInfo,
|
||||
const AllocationCreateInfo& allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize minAlignment,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result createBufferWithAlignment(const VULKAN_HPP_NAMESPACE::BufferCreateInfo* bufferCreateInfo,
|
||||
const AllocationCreateInfo* allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize minAlignment,
|
||||
VULKAN_HPP_NAMESPACE::Buffer* buffer,
|
||||
Allocation* allocation,
|
||||
AllocationInfo* allocationInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<VULKAN_HPP_NAMESPACE::Buffer>::type createAliasingBuffer(Allocation allocation,
|
||||
const VULKAN_HPP_NAMESPACE::BufferCreateInfo& bufferCreateInfo) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result createAliasingBuffer(Allocation allocation,
|
||||
const VULKAN_HPP_NAMESPACE::BufferCreateInfo* bufferCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::Buffer* buffer) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void destroyBuffer(VULKAN_HPP_NAMESPACE::Buffer buffer,
|
||||
Allocation allocation) const;
|
||||
#else
|
||||
void destroyBuffer(VULKAN_HPP_NAMESPACE::Buffer buffer,
|
||||
Allocation allocation) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::pair<VULKAN_HPP_NAMESPACE::Image, Allocation>>::type createImage(const VULKAN_HPP_NAMESPACE::ImageCreateInfo& imageCreateInfo,
|
||||
const AllocationCreateInfo& allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<std::pair<UniqueImage, UniqueAllocation>>::type createImageUnique(const VULKAN_HPP_NAMESPACE::ImageCreateInfo& imageCreateInfo,
|
||||
const AllocationCreateInfo& allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<AllocationInfo> allocationInfo = nullptr) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result createImage(const VULKAN_HPP_NAMESPACE::ImageCreateInfo* imageCreateInfo,
|
||||
const AllocationCreateInfo* allocationCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::Image* image,
|
||||
Allocation* allocation,
|
||||
AllocationInfo* allocationInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<VULKAN_HPP_NAMESPACE::Image>::type createAliasingImage(Allocation allocation,
|
||||
const VULKAN_HPP_NAMESPACE::ImageCreateInfo& imageCreateInfo) const;
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result createAliasingImage(Allocation allocation,
|
||||
const VULKAN_HPP_NAMESPACE::ImageCreateInfo* imageCreateInfo,
|
||||
VULKAN_HPP_NAMESPACE::Image* image) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void destroyImage(VULKAN_HPP_NAMESPACE::Image image,
|
||||
Allocation allocation) const;
|
||||
#else
|
||||
void destroyImage(VULKAN_HPP_NAMESPACE::Image image,
|
||||
Allocation allocation) const;
|
||||
#endif
|
||||
|
||||
#if VMA_STATS_STRING_ENABLED
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS char* buildStatsString(VULKAN_HPP_NAMESPACE::Bool32 detailedMap) const;
|
||||
#endif
|
||||
void buildStatsString(char** statsString,
|
||||
VULKAN_HPP_NAMESPACE::Bool32 detailedMap) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void freeStatsString(char* statsString) const;
|
||||
#else
|
||||
void freeStatsString(char* statsString) const;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
private:
|
||||
VmaAllocator m_allocator = {};
|
||||
};
|
||||
VULKAN_HPP_STATIC_ASSERT(sizeof(Allocator) == sizeof(VmaAllocator),
|
||||
"handle and wrapper have different size!");
|
||||
}
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> class UniqueHandleTraits<VMA_HPP_NAMESPACE::Allocator, VMA_HPP_NAMESPACE::Dispatcher> {
|
||||
public:
|
||||
using deleter = VMA_HPP_NAMESPACE::Deleter<VMA_HPP_NAMESPACE::Allocator, void>;
|
||||
};
|
||||
}
|
||||
namespace VMA_HPP_NAMESPACE { using UniqueAllocator = VULKAN_HPP_NAMESPACE::UniqueHandle<Allocator, Dispatcher>; }
|
||||
#endif
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
class VirtualAllocation {
|
||||
public:
|
||||
using CType = VmaVirtualAllocation;
|
||||
using NativeType = VmaVirtualAllocation;
|
||||
public:
|
||||
VULKAN_HPP_CONSTEXPR VirtualAllocation() = default;
|
||||
VULKAN_HPP_CONSTEXPR VirtualAllocation(std::nullptr_t) VULKAN_HPP_NOEXCEPT {}
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT VirtualAllocation(VmaVirtualAllocation virtualAllocation) VULKAN_HPP_NOEXCEPT : m_virtualAllocation(virtualAllocation) {}
|
||||
|
||||
#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)
|
||||
VirtualAllocation& operator=(VmaVirtualAllocation virtualAllocation) VULKAN_HPP_NOEXCEPT {
|
||||
m_virtualAllocation = virtualAllocation;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
VirtualAllocation& operator=(std::nullptr_t) VULKAN_HPP_NOEXCEPT {
|
||||
m_virtualAllocation = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined( VULKAN_HPP_HAS_SPACESHIP_OPERATOR )
|
||||
auto operator<=>(VirtualAllocation const &) const = default;
|
||||
#else
|
||||
bool operator==(VirtualAllocation const & rhs) const VULKAN_HPP_NOEXCEPT {
|
||||
return m_virtualAllocation == rhs.m_virtualAllocation;
|
||||
}
|
||||
#endif
|
||||
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT operator VmaVirtualAllocation() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_virtualAllocation;
|
||||
}
|
||||
|
||||
explicit operator bool() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_virtualAllocation != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
bool operator!() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_virtualAllocation == VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
private:
|
||||
VmaVirtualAllocation m_virtualAllocation = {};
|
||||
};
|
||||
VULKAN_HPP_STATIC_ASSERT(sizeof(VirtualAllocation) == sizeof(VmaVirtualAllocation),
|
||||
"handle and wrapper have different size!");
|
||||
}
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> class UniqueHandleTraits<VMA_HPP_NAMESPACE::VirtualAllocation, VMA_HPP_NAMESPACE::Dispatcher> {
|
||||
public:
|
||||
using deleter = VMA_HPP_NAMESPACE::Deleter<VMA_HPP_NAMESPACE::VirtualAllocation, VMA_HPP_NAMESPACE::VirtualBlock>;
|
||||
};
|
||||
}
|
||||
namespace VMA_HPP_NAMESPACE { using UniqueVirtualAllocation = VULKAN_HPP_NAMESPACE::UniqueHandle<VirtualAllocation, Dispatcher>; }
|
||||
#endif
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
class VirtualBlock {
|
||||
public:
|
||||
using CType = VmaVirtualBlock;
|
||||
using NativeType = VmaVirtualBlock;
|
||||
public:
|
||||
VULKAN_HPP_CONSTEXPR VirtualBlock() = default;
|
||||
VULKAN_HPP_CONSTEXPR VirtualBlock(std::nullptr_t) VULKAN_HPP_NOEXCEPT {}
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT VirtualBlock(VmaVirtualBlock virtualBlock) VULKAN_HPP_NOEXCEPT : m_virtualBlock(virtualBlock) {}
|
||||
|
||||
#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)
|
||||
VirtualBlock& operator=(VmaVirtualBlock virtualBlock) VULKAN_HPP_NOEXCEPT {
|
||||
m_virtualBlock = virtualBlock;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
VirtualBlock& operator=(std::nullptr_t) VULKAN_HPP_NOEXCEPT {
|
||||
m_virtualBlock = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined( VULKAN_HPP_HAS_SPACESHIP_OPERATOR )
|
||||
auto operator<=>(VirtualBlock const &) const = default;
|
||||
#else
|
||||
bool operator==(VirtualBlock const & rhs) const VULKAN_HPP_NOEXCEPT {
|
||||
return m_virtualBlock == rhs.m_virtualBlock;
|
||||
}
|
||||
#endif
|
||||
|
||||
VULKAN_HPP_TYPESAFE_EXPLICIT operator VmaVirtualBlock() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_virtualBlock;
|
||||
}
|
||||
|
||||
explicit operator bool() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_virtualBlock != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
bool operator!() const VULKAN_HPP_NOEXCEPT {
|
||||
return m_virtualBlock == VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void destroy() const;
|
||||
#else
|
||||
void destroy() const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS VULKAN_HPP_NAMESPACE::Bool32 isVirtualBlockEmpty() const;
|
||||
#else
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Bool32 isVirtualBlockEmpty() const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS VirtualAllocationInfo getVirtualAllocationInfo(VirtualAllocation allocation) const;
|
||||
#endif
|
||||
void getVirtualAllocationInfo(VirtualAllocation allocation,
|
||||
VirtualAllocationInfo* virtualAllocInfo) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<VirtualAllocation>::type virtualAllocate(const VirtualAllocationCreateInfo& createInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<VULKAN_HPP_NAMESPACE::DeviceSize> offset = nullptr) const;
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<UniqueVirtualAllocation>::type virtualAllocateUnique(const VirtualAllocationCreateInfo& createInfo,
|
||||
VULKAN_HPP_NAMESPACE::Optional<VULKAN_HPP_NAMESPACE::DeviceSize> offset = nullptr) const;
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result virtualAllocate(const VirtualAllocationCreateInfo* createInfo,
|
||||
VirtualAllocation* allocation,
|
||||
VULKAN_HPP_NAMESPACE::DeviceSize* offset) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void virtualFree(VirtualAllocation allocation) const;
|
||||
#else
|
||||
void virtualFree(VirtualAllocation allocation) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void clearVirtualBlock() const;
|
||||
#else
|
||||
void clearVirtualBlock() const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void setVirtualAllocationUserData(VirtualAllocation allocation,
|
||||
void* userData) const;
|
||||
#else
|
||||
void setVirtualAllocationUserData(VirtualAllocation allocation,
|
||||
void* userData) const;
|
||||
#endif
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS Statistics getVirtualBlockStatistics() const;
|
||||
#endif
|
||||
void getVirtualBlockStatistics(Statistics* stats) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS DetailedStatistics calculateVirtualBlockStatistics() const;
|
||||
#endif
|
||||
void calculateVirtualBlockStatistics(DetailedStatistics* stats) const;
|
||||
|
||||
#if VMA_STATS_STRING_ENABLED
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS char* buildVirtualBlockStatsString(VULKAN_HPP_NAMESPACE::Bool32 detailedMap) const;
|
||||
#endif
|
||||
void buildVirtualBlockStatsString(char** statsString,
|
||||
VULKAN_HPP_NAMESPACE::Bool32 detailedMap) const;
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
void freeVirtualBlockStatsString(char* statsString) const;
|
||||
#else
|
||||
void freeVirtualBlockStatsString(char* statsString) const;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
private:
|
||||
VmaVirtualBlock m_virtualBlock = {};
|
||||
};
|
||||
VULKAN_HPP_STATIC_ASSERT(sizeof(VirtualBlock) == sizeof(VmaVirtualBlock),
|
||||
"handle and wrapper have different size!");
|
||||
}
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
namespace VULKAN_HPP_NAMESPACE {
|
||||
template<> class UniqueHandleTraits<VMA_HPP_NAMESPACE::VirtualBlock, VMA_HPP_NAMESPACE::Dispatcher> {
|
||||
public:
|
||||
using deleter = VMA_HPP_NAMESPACE::Deleter<VMA_HPP_NAMESPACE::VirtualBlock, void>;
|
||||
};
|
||||
}
|
||||
namespace VMA_HPP_NAMESPACE { using UniqueVirtualBlock = VULKAN_HPP_NAMESPACE::UniqueHandle<VirtualBlock, Dispatcher>; }
|
||||
#endif
|
||||
|
||||
namespace VMA_HPP_NAMESPACE {
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<Allocator>::type createAllocator(const AllocatorCreateInfo& createInfo);
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<UniqueAllocator>::type createAllocatorUnique(const AllocatorCreateInfo& createInfo);
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result createAllocator(const AllocatorCreateInfo* createInfo,
|
||||
Allocator* allocator);
|
||||
|
||||
#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<VirtualBlock>::type createVirtualBlock(const VirtualBlockCreateInfo& createInfo);
|
||||
#ifndef VULKAN_HPP_NO_SMART_HANDLE
|
||||
VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS typename VULKAN_HPP_NAMESPACE::ResultValueType<UniqueVirtualBlock>::type createVirtualBlockUnique(const VirtualBlockCreateInfo& createInfo);
|
||||
#endif
|
||||
#endif
|
||||
VULKAN_HPP_NODISCARD VULKAN_HPP_NAMESPACE::Result createVirtualBlock(const VirtualBlockCreateInfo* createInfo,
|
||||
VirtualBlock* virtualBlock);
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -634,6 +634,7 @@ public final class X11GraphicsDevice extends GraphicsDevice
|
||||
if (x11gd.isScaleFactorDefault.get() || !uiScaleEnabled) {
|
||||
x11gd.scale = (int)Math.round(xftDpiScale * (uiScaleEnabled ? GDK_SCALE_MULTIPLIER : 1));
|
||||
x11gd.isScaleFactorDefault.set(false);
|
||||
x11gd.bounds = x11gd.getBoundsImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||
* Copyright (c) 2022-2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022-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
|
||||
@@ -73,7 +73,6 @@ import java.awt.image.ColorModel;
|
||||
import java.awt.image.VolatileImage;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.ContainerPeer;
|
||||
import java.awt.peer.KeyboardFocusManagerPeer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
@@ -86,7 +85,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
// mapping of AWT cursor types to X cursor names
|
||||
// multiple variants can be specified, that will be tried in order
|
||||
private static final String[][] CURSOR_NAMES = {
|
||||
{"default", "arrow"}, // DEFAULT_CURSOR
|
||||
{"default", "arrow", "left_ptr", "left_arrow"}, // DEFAULT_CURSOR
|
||||
{"crosshair"}, // CROSSHAIR_CURSOR
|
||||
{"text", "xterm"}, // TEXT_CURSOR
|
||||
{"wait", "watch"}, // WAIT_CURSOR
|
||||
@@ -101,7 +100,6 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
{"hand"}, // HAND_CURSOR
|
||||
{"move"}, // MOVE_CURSOR
|
||||
};
|
||||
private static final int WHEEL_SCROLL_AMOUNT = 3;
|
||||
|
||||
private static final int MINIMUM_WIDTH = 1;
|
||||
private static final int MINIMUM_HEIGHT = 1;
|
||||
@@ -121,10 +119,10 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
boolean visible = false;
|
||||
|
||||
private final Object dataLock = new Object();
|
||||
int width; // in native pixels, protected by dataLock
|
||||
int height; // in native pixels, protected by dataLock
|
||||
int wlBufferScale; // protected by dataLock
|
||||
boolean sizeIsBeingConfigured = false; // protected by dataLock
|
||||
int displayScale; // protected by dataLock
|
||||
double effectiveScale; // protected by dataLock
|
||||
private final WLSize wlSize = new WLSize();
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
@@ -137,32 +135,32 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
this.target = target;
|
||||
this.background = target.getBackground();
|
||||
Dimension size = constrainSize(target.getBounds().getSize());
|
||||
width = size.width;
|
||||
height = size.height;
|
||||
final WLGraphicsConfig config = (WLGraphicsConfig)target.getGraphicsConfiguration();
|
||||
wlBufferScale = config.getWlScale();
|
||||
displayScale = config.getDisplayScale();
|
||||
effectiveScale = config.getEffectiveScale();
|
||||
wlSize.deriveFromJavaSize(size.width, size.height);
|
||||
surfaceData = config.createSurfaceData(this);
|
||||
nativePtr = nativeCreateFrame();
|
||||
paintArea = new WLRepaintArea();
|
||||
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("WLComponentPeer: target=" + target + " with size=" + width + "x" + height);
|
||||
log.fine("WLComponentPeer: target=" + target + " with size=" + wlSize);
|
||||
}
|
||||
// TODO
|
||||
// setup parent window for target
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
int getDisplayScale() {
|
||||
synchronized (dataLock) {
|
||||
return width;
|
||||
return displayScale;
|
||||
}
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return wlSize.getJavaWidth();
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
synchronized (dataLock) {
|
||||
return height;
|
||||
}
|
||||
return wlSize.getJavaHeight();
|
||||
}
|
||||
|
||||
public Color getBackground() {
|
||||
@@ -272,14 +270,42 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
private static Window getToplevelFor(Component component) {
|
||||
Container container = component instanceof Container c ? c : component.getParent();
|
||||
for(Container p = container; p != null; p = p.getParent()) {
|
||||
if (p instanceof Window) {
|
||||
return (Window)p;
|
||||
if (p instanceof Window window && !isWlPopup(window)) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Point getRelativeLocation(Component c, Window toplevel) {
|
||||
Objects.requireNonNull(c);
|
||||
|
||||
if (toplevel == null) {
|
||||
return c.getLocation();
|
||||
}
|
||||
|
||||
int x = 0, y = 0;
|
||||
while (c != null) {
|
||||
if (c instanceof Window window) {
|
||||
// The location of non-popup windows has no relevance since
|
||||
// there are no absolute coordinates in Wayland.
|
||||
// The popup windows position, on the other hand, is set relative to their
|
||||
// parent toplevel.
|
||||
if (isWlPopup(window)) {
|
||||
x += c.getX();
|
||||
y += c.getY();
|
||||
}
|
||||
break;
|
||||
}
|
||||
x += c.getX();
|
||||
y += c.getY();
|
||||
c = c.getParent();
|
||||
}
|
||||
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
protected void wlSetVisible(boolean v) {
|
||||
synchronized (getStateLock()) {
|
||||
if (this.visible == v) return;
|
||||
@@ -305,9 +331,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
final Window toplevel = getToplevelFor(popupParent);
|
||||
// We need to provide popup "parent" location relative to
|
||||
// the surface it is painted upon:
|
||||
final Point toplevelLocation = toplevel == null
|
||||
? new Point(popupParent.getX(), popupParent.getY())
|
||||
: SwingUtilities.convertPoint(popupParent, 0, 0, toplevel);
|
||||
final Point toplevelLocation = getRelativeLocation(popupParent, toplevel);
|
||||
final int parentX = javaUnitsToSurfaceUnits(toplevelLocation.x);
|
||||
final int parentY = javaUnitsToSurfaceUnits(toplevelLocation.y);
|
||||
|
||||
@@ -324,7 +348,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
popupLog.fine("\toffset from anchor: " + offsetFromParent);
|
||||
}
|
||||
|
||||
nativeCreateWLPopup(nativePtr, getParentNativePtr(target),
|
||||
nativeCreateWLPopup(nativePtr, getNativePtrFor(toplevel),
|
||||
thisWidth, thisHeight,
|
||||
parentX + offsetX, parentY + offsetY);
|
||||
} else {
|
||||
@@ -374,53 +398,34 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
|
||||
void updateSurfaceData() {
|
||||
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
|
||||
getBufferWidth(), getBufferHeight(), getBufferScale());
|
||||
getBufferWidth(), getBufferHeight(), getDisplayScale());
|
||||
}
|
||||
|
||||
public void updateSurfaceSize() {
|
||||
assert SunToolkit.isAWTLockHeldByCurrentThread();
|
||||
// Note: must be called after a buffer of proper size has been attached to the surface,
|
||||
// but the surface has not yet been committed. Otherwise, the sizes may get out of sync,
|
||||
// but the surface has not yet been committed. Otherwise, the sizes will get out of sync,
|
||||
// which may result in visual artifacts.
|
||||
|
||||
int thisWidth = javaUnitsToSurfaceUnits(getWidth());
|
||||
int thisHeight = javaUnitsToSurfaceUnits(getHeight());
|
||||
Rectangle nativeVisibleBounds = getVisibleBounds();
|
||||
nativeVisibleBounds.x = javaUnitsToSurfaceUnits(nativeVisibleBounds.x);
|
||||
nativeVisibleBounds.y = javaUnitsToSurfaceUnits(nativeVisibleBounds.y);
|
||||
nativeVisibleBounds.width = javaUnitsToSurfaceUnits(nativeVisibleBounds.width);
|
||||
nativeVisibleBounds.height = javaUnitsToSurfaceUnits(nativeVisibleBounds.height);
|
||||
|
||||
Dimension nativeMinSize = constrainSize(getMinimumSize());
|
||||
nativeMinSize.width = javaUnitsToSurfaceUnits(nativeMinSize.width);
|
||||
nativeMinSize.height = javaUnitsToSurfaceUnits(nativeMinSize.height);
|
||||
|
||||
int surfaceWidth = wlSize.getSurfaceWidth();
|
||||
int surfaceHeight = wlSize.getSurfaceHeight();
|
||||
Dimension surfaceMinSize = javaUnitsToSurfaceUnits(constrainSize(getMinimumSize()));
|
||||
Dimension maxSize = target.isMaximumSizeSet() ? target.getMaximumSize() : null;
|
||||
Dimension nativeMaxSize = maxSize != null ? constrainSize(maxSize) : null;
|
||||
if (nativeMaxSize != null) {
|
||||
nativeMaxSize.width = javaUnitsToSurfaceUnits(nativeMaxSize.width);
|
||||
nativeMaxSize.height = javaUnitsToSurfaceUnits(nativeMaxSize.height);
|
||||
}
|
||||
Dimension surfaceMaxSize = maxSize != null ? javaUnitsToSurfaceUnits(constrainSize(maxSize)) : null;
|
||||
|
||||
nativeSetSurfaceSize(nativePtr, thisWidth, thisHeight);
|
||||
nativeSetSurfaceSize(nativePtr, surfaceWidth, surfaceHeight);
|
||||
if (!surfaceData.getColorModel().hasAlpha()) {
|
||||
nativeSetOpaqueRegion(nativePtr,
|
||||
nativeVisibleBounds.x, nativeVisibleBounds.y,
|
||||
nativeVisibleBounds.width, nativeVisibleBounds.height);
|
||||
nativeSetOpaqueRegion(nativePtr, 0, 0, surfaceWidth, surfaceHeight);
|
||||
}
|
||||
|
||||
nativeSetWindowGeometry(nativePtr,
|
||||
nativeVisibleBounds.x, nativeVisibleBounds.y,
|
||||
nativeVisibleBounds.width, nativeVisibleBounds.height);
|
||||
nativeSetMinimumSize(nativePtr, nativeMinSize.width, nativeMinSize.height);
|
||||
if (nativeMaxSize != null) {
|
||||
nativeSetMaximumSize(nativePtr, nativeMaxSize.width, nativeMaxSize.height);
|
||||
nativeSetWindowGeometry(nativePtr, 0, 0, surfaceWidth, surfaceHeight);
|
||||
nativeSetMinimumSize(nativePtr, surfaceMinSize.width, surfaceMinSize.height);
|
||||
if (surfaceMaxSize != null) {
|
||||
nativeSetMaximumSize(nativePtr, surfaceMaxSize.width, surfaceMaxSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
void configureWLSurface() {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("%s is configured to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), getBufferScale()));
|
||||
log.fine(String.format("%s is configured to %dx%d pixels", this, getBufferWidth(), getBufferHeight()));
|
||||
}
|
||||
updateSurfaceData();
|
||||
}
|
||||
@@ -484,7 +489,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
public void commitToServer() {
|
||||
performLocked(() -> {
|
||||
if (getWLSurface(nativePtr) != 0) {
|
||||
surfaceData.flush();
|
||||
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).commit();
|
||||
}
|
||||
});
|
||||
Toolkit.getDefaultToolkit().sync();
|
||||
@@ -530,8 +535,8 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
if (sizeChanged) {
|
||||
setSizeTo(newSize.width, newSize.height);
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("%s is resizing its buffer to %dx%d with %dx scale",
|
||||
this, getBufferWidth(), getBufferHeight(), getBufferScale()));
|
||||
log.fine(String.format("%s is resizing its buffer to %dx%d pixels",
|
||||
this, getBufferWidth(), getBufferHeight()));
|
||||
}
|
||||
updateSurfaceData();
|
||||
layout();
|
||||
@@ -542,11 +547,28 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
postPaintEvent();
|
||||
}
|
||||
|
||||
boolean isSizeBeingConfigured() {
|
||||
synchronized (dataLock) {
|
||||
return sizeIsBeingConfigured;
|
||||
}
|
||||
}
|
||||
|
||||
private void setSizeIsBeingConfigured(boolean value) {
|
||||
synchronized (dataLock) {
|
||||
sizeIsBeingConfigured = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void setSizeTo(int newWidth, int newHeight) {
|
||||
Dimension newSize = constrainSize(newWidth, newHeight);
|
||||
synchronized (dataLock) {
|
||||
this.width = newSize.width;
|
||||
this.height = newSize.height;
|
||||
if (isSizeBeingConfigured() && wlSize.hasPixelSizeSet()) {
|
||||
// Must be careful not to override the size of the Wayland surface because
|
||||
// some implementations (Weston) react badly when the size of the surface
|
||||
// mismatches the configured size. We can't always precisely derive the surface
|
||||
// size from the Java (client) size because of scaling rounding errors.
|
||||
wlSize.setJavaSize(newSize.width, newSize.height);
|
||||
} else {
|
||||
wlSize.deriveFromJavaSize(newSize.width, newSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,9 +579,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
final Window toplevel = getToplevelFor(popupParent);
|
||||
// We need to provide popup "parent" location relative to
|
||||
// the surface it is painted upon:
|
||||
final Point toplevelLocation = toplevel == null
|
||||
? new Point(popupParent.getX(), popupParent.getY())
|
||||
: SwingUtilities.convertPoint(popupParent, 0, 0, toplevel);
|
||||
final Point toplevelLocation = getRelativeLocation(popupParent, toplevel);
|
||||
final int parentX = javaUnitsToSurfaceUnits(toplevelLocation.x);
|
||||
final int parentY = javaUnitsToSurfaceUnits(toplevelLocation.y);
|
||||
int newXNative = javaUnitsToSurfaceUnits(newX);
|
||||
@@ -577,34 +597,12 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
} );
|
||||
}
|
||||
|
||||
public Rectangle getVisibleBounds() {
|
||||
synchronized(dataLock) {
|
||||
return new Rectangle(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the scale ratio of Wayland's backing buffer in pixel units
|
||||
* to surface units. Wayland events are generated in surface units, while
|
||||
* painting should be performed in pixel units.
|
||||
* The ratio is enforced with nativeSetSurfaceSize().
|
||||
*/
|
||||
int getBufferScale() {
|
||||
synchronized(dataLock) {
|
||||
return wlBufferScale;
|
||||
}
|
||||
}
|
||||
|
||||
public int getBufferWidth() {
|
||||
synchronized (dataLock) {
|
||||
return (int)(width * effectiveScale);
|
||||
}
|
||||
return wlSize.getPixelWidth();
|
||||
}
|
||||
|
||||
public int getBufferHeight() {
|
||||
synchronized (dataLock) {
|
||||
return (int)(height * effectiveScale);
|
||||
}
|
||||
return wlSize.getPixelHeight();
|
||||
}
|
||||
|
||||
public Rectangle getBufferBounds() {
|
||||
@@ -857,7 +855,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
WLComponentPeer peer = inputState.getPeer();
|
||||
if (peer == null) return;
|
||||
Cursor cursor = peer.getCursor(inputState.getPointerX(), inputState.getPointerY());
|
||||
setCursor(cursor, getGraphicsDevice() != null ? getGraphicsDevice().getWlScale() : 1);
|
||||
setCursor(cursor, getGraphicsDevice() != null ? getGraphicsDevice().getDisplayScale() : 1);
|
||||
}
|
||||
|
||||
Cursor getCursor(int x, int y) {
|
||||
@@ -968,16 +966,17 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
|
||||
@Override
|
||||
public boolean updateGraphicsData(GraphicsConfiguration gc) {
|
||||
final int newWlScale = ((WLGraphicsConfig)gc).getWlScale();
|
||||
final int newScale = ((WLGraphicsConfig)gc).getDisplayScale();
|
||||
|
||||
WLGraphicsDevice gd = ((WLGraphicsConfig) gc).getDevice();
|
||||
gd.addWindow(this);
|
||||
synchronized (dataLock) {
|
||||
if (newWlScale != wlBufferScale) {
|
||||
wlBufferScale = newWlScale;
|
||||
if (newScale != displayScale) {
|
||||
displayScale = newScale;
|
||||
effectiveScale = ((WLGraphicsConfig)gc).getEffectiveScale();
|
||||
wlSize.updateWithNewScale();
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("%s is updating buffer to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), wlBufferScale));
|
||||
log.fine(String.format("%s is updating buffer to %dx%d pixels", this, getBufferWidth(), getBufferHeight()));
|
||||
}
|
||||
updateSurfaceData();
|
||||
postPaintEvent();
|
||||
@@ -1064,16 +1063,18 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
private native void nativeShowWindowMenu(long ptr, int x, int y);
|
||||
private native void nativeActivate(long ptr);
|
||||
|
||||
static long getParentNativePtr(Component target) {
|
||||
Component parent = target.getParent();
|
||||
if (parent == null) return 0;
|
||||
|
||||
static long getNativePtrFor(Component component) {
|
||||
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
ComponentPeer peer = acc.getPeer(parent);
|
||||
ComponentPeer peer = acc.getPeer(component);
|
||||
|
||||
return ((WLComponentPeer)peer).nativePtr;
|
||||
}
|
||||
|
||||
static long getParentNativePtr(Component target) {
|
||||
Component parent = target.getParent();
|
||||
return parent == null ? 0 : getNativePtrFor(parent);
|
||||
}
|
||||
|
||||
private final Object state_lock = new Object();
|
||||
/**
|
||||
* This lock object is used to protect instance data from concurrent access
|
||||
@@ -1152,19 +1153,128 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
}
|
||||
|
||||
if (e.hasAxisEvent() && e.getIsAxis0Valid()) {
|
||||
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
|
||||
MouseEvent.MOUSE_WHEEL,
|
||||
timestamp,
|
||||
newInputState.getModifiers(),
|
||||
x, y,
|
||||
xAbsolute, yAbsolute,
|
||||
1,
|
||||
isPopupTrigger,
|
||||
MouseWheelEvent.WHEEL_UNIT_SCROLL,
|
||||
1,
|
||||
Integer.signum(e.getAxis0Value()) * WHEEL_SCROLL_AMOUNT);
|
||||
postMouseEvent(mouseEvent);
|
||||
if (e.hasAxisEvent()) {
|
||||
convertPointerEventToMWEParameters(e, xAxisWheelRoundRotationsAccumulator, yAxisWheelRoundRotationsAccumulator, mweConversionInfo);
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("{0} -> {1}", e, mweConversionInfo);
|
||||
}
|
||||
|
||||
// macOS's and Windows' AWT implement the following logic, so do we:
|
||||
// Shift + a vertical scroll means a horizontal scroll.
|
||||
// AWT/Swing components are also aware of it.
|
||||
|
||||
final boolean isShiftPressed = (newInputState.getModifiers() & KeyEvent.SHIFT_DOWN_MASK) != 0;
|
||||
|
||||
// These values decide whether a horizontal scrolling MouseWheelEvent will be created and posted
|
||||
final int horizontalMWEScrollAmount;
|
||||
final double horizontalMWEPreciseRotations;
|
||||
final int horizontalMWERoundRotations;
|
||||
|
||||
// These values decide whether a vertical scrolling MouseWheelEvent will be created and posted
|
||||
final int verticalMWEScrollAmount;
|
||||
final double verticalMWEPreciseRotations;
|
||||
final int verticalMWERoundRotations;
|
||||
|
||||
if (isShiftPressed) {
|
||||
// Pressing Shift makes only a horizontal scrolling MouseWheelEvent possible
|
||||
verticalMWEScrollAmount = 0;
|
||||
verticalMWEPreciseRotations = 0;
|
||||
verticalMWERoundRotations = 0;
|
||||
|
||||
// Now we're deciding values of which axis will be used to generate a horizontal MouseWheelEvent
|
||||
|
||||
if (mweConversionInfo.xAxisDirectionSign == mweConversionInfo.yAxisDirectionSign) {
|
||||
// The scrolling directions don't contradict each other.
|
||||
// Let's pick the more influencing axis.
|
||||
|
||||
final var xAxisUnitsToScroll = mweConversionInfo.xAxisMWEScrollAmount * (
|
||||
Math.abs(mweConversionInfo.xAxisMWEPreciseRotations) > Math.abs(mweConversionInfo.xAxisMWERoundRotations)
|
||||
? mweConversionInfo.xAxisMWEPreciseRotations
|
||||
: mweConversionInfo.xAxisMWERoundRotations );
|
||||
|
||||
final var yAxisUnitsToScroll = mweConversionInfo.yAxisMWEScrollAmount * (
|
||||
Math.abs(mweConversionInfo.yAxisMWEPreciseRotations) > Math.abs(mweConversionInfo.yAxisMWERoundRotations)
|
||||
? mweConversionInfo.yAxisMWEPreciseRotations
|
||||
: mweConversionInfo.yAxisMWERoundRotations );
|
||||
|
||||
if (xAxisUnitsToScroll > yAxisUnitsToScroll) {
|
||||
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
|
||||
} else {
|
||||
horizontalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
|
||||
}
|
||||
} else if (mweConversionInfo.yAxisMWERoundRotations != 0 || mweConversionInfo.yAxisMWEPreciseRotations != 0) {
|
||||
// The scrolling directions contradict.
|
||||
// I think consistently choosing the Y axis values (unless they're zero) provides the most expected UI behavior here.
|
||||
|
||||
horizontalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
|
||||
} else {
|
||||
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
|
||||
}
|
||||
} else {
|
||||
// Shift is not pressed, so both horizontal and vertical MouseWheelEvent s are possible.
|
||||
|
||||
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
|
||||
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
|
||||
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
|
||||
|
||||
verticalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
|
||||
verticalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
|
||||
verticalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
|
||||
}
|
||||
|
||||
if (e.xAxisHasStopEvent()) {
|
||||
xAxisWheelRoundRotationsAccumulator.reset();
|
||||
}
|
||||
if (e.yAxisHasStopEvent()) {
|
||||
yAxisWheelRoundRotationsAccumulator.reset();
|
||||
}
|
||||
|
||||
if (verticalMWERoundRotations != 0 || verticalMWEPreciseRotations != 0) {
|
||||
assert(verticalMWEScrollAmount > 0);
|
||||
|
||||
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
|
||||
MouseEvent.MOUSE_WHEEL,
|
||||
timestamp,
|
||||
// Making sure the event will cause scrolling along the vertical axis
|
||||
newInputState.getModifiers() & ~KeyEvent.SHIFT_DOWN_MASK,
|
||||
x, y,
|
||||
xAbsolute, yAbsolute,
|
||||
1,
|
||||
isPopupTrigger,
|
||||
MouseWheelEvent.WHEEL_UNIT_SCROLL,
|
||||
verticalMWEScrollAmount,
|
||||
verticalMWERoundRotations,
|
||||
verticalMWEPreciseRotations);
|
||||
postMouseEvent(mouseEvent);
|
||||
}
|
||||
|
||||
if (horizontalMWERoundRotations != 0 || horizontalMWEPreciseRotations != 0) {
|
||||
assert(horizontalMWEScrollAmount > 0);
|
||||
|
||||
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
|
||||
MouseEvent.MOUSE_WHEEL,
|
||||
timestamp,
|
||||
// Making sure the event will cause scrolling along the horizontal axis
|
||||
newInputState.getModifiers() | KeyEvent.SHIFT_DOWN_MASK,
|
||||
x, y,
|
||||
xAbsolute, yAbsolute,
|
||||
1,
|
||||
isPopupTrigger,
|
||||
MouseWheelEvent.WHEEL_UNIT_SCROLL,
|
||||
horizontalMWEScrollAmount,
|
||||
horizontalMWERoundRotations,
|
||||
horizontalMWEPreciseRotations);
|
||||
postMouseEvent(mouseEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.hasMotionEvent()) {
|
||||
@@ -1195,6 +1305,166 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates fractional parts of wheel rotation steps until their absolute sum represents one or more full step(s).
|
||||
* This allows implementing smoother scrolling, e.g., the sequence of wl_pointer::axis events with values
|
||||
* [0.2, 0.1, 0.4, 0.4] can be accumulated into 1.1=0.2+0.1+0.4+0.4, making it possible to
|
||||
* generate a MouseWheelEvent with wheelRotation=1
|
||||
* (instead of 4 tries to generate a MouseWheelEvent with wheelRotation=0 due to double->int conversion)
|
||||
*/
|
||||
private static final class MouseWheelRoundRotationsAccumulator {
|
||||
/**
|
||||
* This method is intended to accumulate fractional numbers of wheel rotations.
|
||||
*
|
||||
* @param fractionalRotations - fractional number of wheel rotations (usually got from a {@code wl_pointer::axis} event)
|
||||
* @return The number of wheel round rotations accumulated
|
||||
* @see #accumulateSteps120Rotations
|
||||
*/
|
||||
public int accumulateFractionalRotations(double fractionalRotations) {
|
||||
// The code assumes that the target component ({@link WLComponentPeer#target}) never changes.
|
||||
// If it did, all the accumulating fields would have to be reset each time the target changed.
|
||||
|
||||
accumulatedFractionalRotations += fractionalRotations;
|
||||
final int result = (int)accumulatedFractionalRotations;
|
||||
accumulatedFractionalRotations -= result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is intended to accumulate 1/120 fractions of a rotation step.
|
||||
*
|
||||
* @param steps120Rotations - a number of 1/120 parts of a wheel step (so that, e.g.,
|
||||
* 30 means one quarter of a step,
|
||||
* 240 means two steps,
|
||||
* -240 means two steps in the negative direction,
|
||||
* 540 means 4.5 steps).
|
||||
* Usually got from a {@code wl_pointer::axis_discrete}/{@code axis_value120} event.
|
||||
* @return The number of wheel round rotations accumulated
|
||||
* @see #accumulateFractionalRotations
|
||||
*/
|
||||
public int accumulateSteps120Rotations(int steps120Rotations) {
|
||||
// The code assumes that the target component ({@link WLComponentPeer#target}) never changes.
|
||||
// If it did, all the accumulating fields would have to be reset each time the target changed.
|
||||
|
||||
accumulatedSteps120Rotations += steps120Rotations;
|
||||
final int result = accumulatedSteps120Rotations / 120;
|
||||
accumulatedSteps120Rotations %= 120;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
accumulatedFractionalRotations = 0;
|
||||
accumulatedSteps120Rotations = 0;
|
||||
}
|
||||
|
||||
|
||||
private double accumulatedFractionalRotations = 0;
|
||||
private int accumulatedSteps120Rotations = 0;
|
||||
}
|
||||
private final MouseWheelRoundRotationsAccumulator xAxisWheelRoundRotationsAccumulator = new MouseWheelRoundRotationsAccumulator();
|
||||
private final MouseWheelRoundRotationsAccumulator yAxisWheelRoundRotationsAccumulator = new MouseWheelRoundRotationsAccumulator();
|
||||
|
||||
private static final class PointerEventToMWEConversionInfo {
|
||||
public double xAxisVector = 0;
|
||||
public int xAxisSteps120 = 0;
|
||||
public int xAxisDirectionSign = 0;
|
||||
public double xAxisMWEPreciseRotations = 0;
|
||||
public int xAxisMWERoundRotations = 0;
|
||||
public int xAxisMWEScrollAmount = 0;
|
||||
|
||||
public double yAxisVector = 0;
|
||||
public int yAxisSteps120 = 0;
|
||||
public int yAxisDirectionSign = 0;
|
||||
public double yAxisMWEPreciseRotations = 0;
|
||||
public int yAxisMWERoundRotations = 0;
|
||||
public int yAxisMWEScrollAmount = 0;
|
||||
|
||||
private final StringBuilder toStringBuf = new StringBuilder(1024);
|
||||
@Override
|
||||
public String toString() {
|
||||
toStringBuf.setLength(0);
|
||||
|
||||
toStringBuf.append("PointerEventToMWEConversionInfo[")
|
||||
.append("xAxisVector=" ).append(xAxisVector ).append(", ")
|
||||
.append("xAxisSteps120=" ).append(xAxisSteps120 ).append(", ")
|
||||
.append("xAxisDirectionSign=" ).append(xAxisDirectionSign ).append(", ")
|
||||
.append("xAxisMWEPreciseRotations=").append(xAxisMWEPreciseRotations).append(", ")
|
||||
.append("xAxisMWERoundRotations=" ).append(xAxisMWERoundRotations ).append(", ")
|
||||
.append("xAxisMWEScrollAmount=" ).append(xAxisMWEScrollAmount ).append(", ")
|
||||
|
||||
.append("yAxisVector=" ).append(yAxisVector ).append(", ")
|
||||
.append("yAxisSteps120=" ).append(yAxisSteps120 ).append(", ")
|
||||
.append("yAxisDirectionSign=" ).append(yAxisDirectionSign ).append(", ")
|
||||
.append("yAxisMWEPreciseRotations=").append(yAxisMWEPreciseRotations).append(", ")
|
||||
.append("yAxisMWERoundRotations=" ).append(yAxisMWERoundRotations ).append(", ")
|
||||
.append("yAxisMWEScrollAmount=" ).append(yAxisMWEScrollAmount )
|
||||
.append(']');
|
||||
|
||||
return toStringBuf.toString();
|
||||
}
|
||||
}
|
||||
private final PointerEventToMWEConversionInfo mweConversionInfo = new PointerEventToMWEConversionInfo();
|
||||
|
||||
private static void convertPointerEventToMWEParameters(
|
||||
WLPointerEvent dispatchingEvent,
|
||||
MouseWheelRoundRotationsAccumulator xAxisWheelRoundRotationsAccumulator,
|
||||
MouseWheelRoundRotationsAccumulator yAxisWheelRoundRotationsAccumulator,
|
||||
PointerEventToMWEConversionInfo mweConversionInfo) {
|
||||
// WLPointerEvent -> MouseWheelEvent conversion constants.
|
||||
// Please keep in mind that they're all related, so that changing one may require adjusting the others
|
||||
// (or altering this conversion routine).
|
||||
|
||||
// XToolkit uses 3 units per a wheel step, so do we here to preserve the user experience
|
||||
final int STEPS120_MWE_SCROLL_AMOUNT = 3;
|
||||
// For touchpad scrolling, it's worth being able to scroll the minimum possible number of units (i.e. 1)
|
||||
final int VECTOR_MWE_SCROLL_AMOUNT = 1;
|
||||
// 0.28 has experimentally been found as providing a good balance between
|
||||
// wheel scrolling sensitivity and touchpad scrolling sensitivity
|
||||
final double VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR = 0.28;
|
||||
|
||||
mweConversionInfo.xAxisVector = dispatchingEvent.xAxisHasVectorValue() ? dispatchingEvent.getXAxisVectorValue() : 0;
|
||||
mweConversionInfo.xAxisSteps120 = dispatchingEvent.xAxisHasSteps120Value() ? dispatchingEvent.getXAxisSteps120Value() : 0;
|
||||
|
||||
// Converting the X axis Wayland values to MouseWheelEvent parameters.
|
||||
|
||||
// wl_pointer::axis_discrete/axis_value120 are preferred over wl_pointer::axis because
|
||||
// they're closer to MouseWheelEvent by their nature.
|
||||
if (mweConversionInfo.xAxisSteps120 != 0) {
|
||||
mweConversionInfo.xAxisDirectionSign = Integer.signum(mweConversionInfo.xAxisSteps120);
|
||||
mweConversionInfo.xAxisMWEPreciseRotations = mweConversionInfo.xAxisSteps120 / 120d;
|
||||
mweConversionInfo.xAxisMWERoundRotations = xAxisWheelRoundRotationsAccumulator.accumulateSteps120Rotations(mweConversionInfo.xAxisSteps120);
|
||||
// It would be probably better to calculate the scrollAmount taking the xAxisVector value into
|
||||
// consideration, so that the wheel scrolling speed could be adjusted via some system settings.
|
||||
// However, neither Gnome nor KDE currently provide such a setting, making it difficult to test
|
||||
// how well such an approach would work. So leaving it as is for now.
|
||||
mweConversionInfo.xAxisMWEScrollAmount = STEPS120_MWE_SCROLL_AMOUNT;
|
||||
} else {
|
||||
mweConversionInfo.xAxisDirectionSign = (int)Math.signum(mweConversionInfo.xAxisVector);
|
||||
mweConversionInfo.xAxisMWEPreciseRotations = mweConversionInfo.xAxisVector * VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR;
|
||||
mweConversionInfo.xAxisMWERoundRotations = xAxisWheelRoundRotationsAccumulator.accumulateFractionalRotations(mweConversionInfo.xAxisMWEPreciseRotations);
|
||||
mweConversionInfo.xAxisMWEScrollAmount = VECTOR_MWE_SCROLL_AMOUNT;
|
||||
}
|
||||
|
||||
mweConversionInfo.yAxisVector = dispatchingEvent.yAxisHasVectorValue() ? dispatchingEvent.getYAxisVectorValue() : 0;
|
||||
mweConversionInfo.yAxisSteps120 = dispatchingEvent.yAxisHasSteps120Value() ? dispatchingEvent.getYAxisSteps120Value() : 0;
|
||||
|
||||
// Converting the Y axis Wayland values to MouseWheelEvent parameters.
|
||||
// (Currently, the routine is exactly like for X axis)
|
||||
|
||||
if (mweConversionInfo.yAxisSteps120 != 0) {
|
||||
mweConversionInfo.yAxisDirectionSign = Integer.signum(mweConversionInfo.yAxisSteps120);
|
||||
mweConversionInfo.yAxisMWEPreciseRotations = mweConversionInfo.yAxisSteps120 / 120d;
|
||||
mweConversionInfo.yAxisMWERoundRotations = yAxisWheelRoundRotationsAccumulator.accumulateSteps120Rotations(mweConversionInfo.yAxisSteps120);
|
||||
mweConversionInfo.yAxisMWEScrollAmount = STEPS120_MWE_SCROLL_AMOUNT;
|
||||
} else {
|
||||
mweConversionInfo.yAxisDirectionSign = (int)Math.signum(mweConversionInfo.yAxisVector);
|
||||
mweConversionInfo.yAxisMWEPreciseRotations = mweConversionInfo.yAxisVector * VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR;
|
||||
mweConversionInfo.yAxisMWERoundRotations = yAxisWheelRoundRotationsAccumulator.accumulateFractionalRotations(mweConversionInfo.yAxisMWEPreciseRotations);
|
||||
mweConversionInfo.yAxisMWEScrollAmount = VECTOR_MWE_SCROLL_AMOUNT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void startDrag() {
|
||||
performLocked(() -> nativeStartDrag(nativePtr));
|
||||
}
|
||||
@@ -1212,7 +1482,7 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
return value;
|
||||
} else {
|
||||
synchronized (dataLock) {
|
||||
return (int)(value * wlBufferScale / effectiveScale);
|
||||
return (int)(value * displayScale / effectiveScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1226,38 +1496,45 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
return value;
|
||||
} else {
|
||||
synchronized (dataLock) {
|
||||
return (int)(value * effectiveScale / wlBufferScale);
|
||||
return (int)(value * effectiveScale / displayScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void notifyConfigured(int newXNative, int newYNative, int newWidthNative, int newHeightNative, boolean active, boolean maximized) {
|
||||
int newWidth = surfaceUnitsToJavaUnits(newWidthNative);
|
||||
int newHeight = surfaceUnitsToJavaUnits(newHeightNative);
|
||||
final long wlSurfacePtr = getWLSurface(nativePtr);
|
||||
if (!surfaceAssigned) {
|
||||
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).assignSurface(wlSurfacePtr);
|
||||
surfaceAssigned = true;
|
||||
}
|
||||
Dimension javaUnitsToSurfaceUnits(Dimension d) {
|
||||
return new Dimension(javaUnitsToSurfaceUnits(d.width), javaUnitsToSurfaceUnits(d.height));
|
||||
}
|
||||
|
||||
void notifyConfigured(int newSurfaceX, int newSurfaceY, int newSurfaceWidth, int newSurfaceHeight, boolean active, boolean maximized) {
|
||||
// NB: The width and height, as well as X and Y arguments specify the size and the location
|
||||
// of the window in surface-local coordinates.
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("%s configured to %dx%d", this, newWidth, newHeight));
|
||||
log.fine(String.format("%s configured to %dx%d surface units", this, newSurfaceWidth, newSurfaceHeight));
|
||||
}
|
||||
|
||||
boolean isWlPopup = targetIsWlPopup();
|
||||
|
||||
if (isWlPopup) { // Only popups provide (relative) location
|
||||
int newX = surfaceUnitsToJavaUnits(newXNative);
|
||||
int newY = surfaceUnitsToJavaUnits(newYNative);
|
||||
int newX = surfaceUnitsToJavaUnits(newSurfaceX);
|
||||
int newY = surfaceUnitsToJavaUnits(newSurfaceY);
|
||||
setLocationTo(newX, newY);
|
||||
}
|
||||
|
||||
if (newWidth != 0 && newHeight != 0) performUnlocked(() -> target.setSize(newWidth, newHeight));
|
||||
// From xdg-shell.xml: "If the width or height arguments are zero,
|
||||
// it means the client should decide its own window dimension".
|
||||
boolean clientDecidesDimension = newSurfaceWidth == 0 || newSurfaceHeight == 0;
|
||||
if (!clientDecidesDimension) {
|
||||
changeSizeToConfigured(newSurfaceWidth, newSurfaceHeight);
|
||||
}
|
||||
|
||||
if (newWidth == 0 || newHeight == 0 || isWlPopup) {
|
||||
// From xdg-shell.xml: "If the width or height arguments are zero,
|
||||
// it means the client should decide its own window dimension".
|
||||
if (!surfaceAssigned) {
|
||||
long wlSurfacePtr = getWLSurface(nativePtr);
|
||||
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).assignSurface(wlSurfacePtr);
|
||||
surfaceAssigned = true;
|
||||
}
|
||||
|
||||
// In case this is the first configure after setVisible(true), we
|
||||
if (clientDecidesDimension || isWlPopup) {
|
||||
// In case this is the first 'configure' after setVisible(true), we
|
||||
// need to post the initial paint event for the window to appear on
|
||||
// the screen. In the other case, this paint event is posted
|
||||
// by setBounds() eventually called from target.setSize() above.
|
||||
@@ -1269,6 +1546,22 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
}
|
||||
|
||||
private void changeSizeToConfigured(int newSurfaceWidth, int newSurfaceHeight) {
|
||||
wlSize.deriveFromSurfaceSize(newSurfaceWidth, newSurfaceHeight);
|
||||
int newWidth = wlSize.getJavaWidth();
|
||||
int newHeight = wlSize.getJavaHeight();
|
||||
try {
|
||||
// Must not confuse the size given by the server with the size set by the user.
|
||||
// The former originates from the surface size in surface-local coordinates,
|
||||
// while the latter is set in the client (Java) units. These are not always
|
||||
// precisely convertible.
|
||||
setSizeIsBeingConfigured(true);
|
||||
performUnlocked(() -> target.setSize(newWidth, newHeight));
|
||||
} finally {
|
||||
setSizeIsBeingConfigured(false);
|
||||
}
|
||||
}
|
||||
|
||||
void notifyEnteredOutput(int wlOutputID) {
|
||||
// NB: May also be called from native code whenever the corresponding wl_surface enters a new output
|
||||
synchronized (devices) {
|
||||
@@ -1322,8 +1615,8 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
// Wayland's output and are removed as soon as we have left.
|
||||
synchronized (devices) {
|
||||
for (WLGraphicsDevice gd : devices) {
|
||||
if (gd.getWlScale() > scale) {
|
||||
scale = gd.getWlScale();
|
||||
if (gd.getDisplayScale() > scale) {
|
||||
scale = gd.getDisplayScale();
|
||||
theDevice = gd;
|
||||
}
|
||||
}
|
||||
@@ -1361,7 +1654,6 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
|
||||
private Dimension constrainSize(int width, int height) {
|
||||
Dimension maxBounds = getMaxBufferBounds();
|
||||
return new Dimension(
|
||||
@@ -1443,4 +1735,109 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private class WLSize {
|
||||
/**
|
||||
* Represents the full size of the component in "client" units as returned by Component.getSize().
|
||||
*/
|
||||
private final Dimension javaSize = new Dimension(); // in the client (Java) space, protected by dataLock
|
||||
|
||||
/**
|
||||
* Represents the full size of the component in screen pixels.
|
||||
* The SurfaceData associated with this component takes its size from this value.
|
||||
*/
|
||||
private final Dimension pixelSize = new Dimension(); // in pixels, protected by dataLock
|
||||
|
||||
/**
|
||||
* Represents the full size of the component in "surface-local" units;
|
||||
* these are the units that Wayland uses in most of its API.
|
||||
* Unless the debug scale is used (WLGraphicsEnvironment.isDebugScaleEnabled()), it is identical
|
||||
* to javaSize.
|
||||
*/
|
||||
private final Dimension surfaceSize = new Dimension(); // in surface units, protected by dataLock
|
||||
|
||||
void deriveFromJavaSize(int width, int height) {
|
||||
synchronized (dataLock) {
|
||||
javaSize.width = width;
|
||||
javaSize.height = height;
|
||||
pixelSize.width = (int) (width * effectiveScale);
|
||||
pixelSize.height = (int) (height * effectiveScale);
|
||||
surfaceSize.width = javaUnitsToSurfaceUnits(width);
|
||||
surfaceSize.height = javaUnitsToSurfaceUnits(height);
|
||||
}
|
||||
}
|
||||
|
||||
void deriveFromSurfaceSize(int width, int height) {
|
||||
synchronized (dataLock) {
|
||||
javaSize.width = surfaceUnitsToJavaUnits(width);
|
||||
javaSize.height = surfaceUnitsToJavaUnits(height);
|
||||
pixelSize.width = width * displayScale;
|
||||
pixelSize.height = height * displayScale;
|
||||
surfaceSize.width = width;
|
||||
surfaceSize.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
void updateWithNewScale() {
|
||||
synchronized (dataLock) {
|
||||
pixelSize.width = (int)(javaSize.width * effectiveScale);
|
||||
pixelSize.height = (int)(javaSize.height * effectiveScale);
|
||||
surfaceSize.width = javaUnitsToSurfaceUnits(javaSize.width);
|
||||
surfaceSize.height = javaUnitsToSurfaceUnits(javaSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasPixelSizeSet() {
|
||||
synchronized (dataLock) {
|
||||
return pixelSize.width > 0 && pixelSize.height > 0;
|
||||
}
|
||||
}
|
||||
|
||||
void setJavaSize(int width, int height) {
|
||||
synchronized (dataLock) {
|
||||
javaSize.width = width;
|
||||
javaSize.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
int getPixelWidth() {
|
||||
synchronized (dataLock) {
|
||||
return pixelSize.width;
|
||||
}
|
||||
}
|
||||
|
||||
int getPixelHeight() {
|
||||
synchronized (dataLock) {
|
||||
return pixelSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
int getJavaWidth() {
|
||||
synchronized (dataLock) {
|
||||
return javaSize.width;
|
||||
}
|
||||
}
|
||||
|
||||
int getJavaHeight() {
|
||||
synchronized (dataLock) {
|
||||
return javaSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
int getSurfaceWidth() {
|
||||
synchronized (dataLock) {
|
||||
return surfaceSize.width;
|
||||
}
|
||||
}
|
||||
|
||||
int getSurfaceHeight() {
|
||||
synchronized (dataLock) {
|
||||
return surfaceSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "WLSize[client=" + javaSize + ", pixel=" + pixelSize + ", surface=" + surfaceSize + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,18 +110,11 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
}
|
||||
|
||||
@Override
|
||||
void notifyConfigured(int newX, int newY, int newWidthNative, int newHeightNative, boolean active, boolean maximized) {
|
||||
super.notifyConfigured(newX, newY, newWidthNative, newHeightNative, active, maximized);
|
||||
void notifyConfigured(int newSurfaceX, int newSurfaceY, int newSurfaceWidth, int newSurfaceHeight, boolean active, boolean maximized) {
|
||||
super.notifyConfigured(newSurfaceX, newSurfaceY, newSurfaceWidth, newSurfaceHeight, active, maximized);
|
||||
decoration.setActive(active);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getVisibleBounds() {
|
||||
// TODO: modify if our decorations ever acquire special effects that
|
||||
// do not count into "visible bounds" of the window
|
||||
return super.getVisibleBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBounds(int newX, int newY, int newWidth, int newHeight, int op) {
|
||||
super.setBounds(newX, newY, newWidth, newHeight, op);
|
||||
|
||||
@@ -130,6 +130,20 @@ public class WLFramePeer extends WLDecoratedPeer implements FramePeer {
|
||||
public void setMaximizedBounds(Rectangle bounds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBounds(int newX, int newY, int newWidth, int newHeight, int op) {
|
||||
boolean isMaximized = (getState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH;
|
||||
if (isMaximized && !isSizeBeingConfigured()) {
|
||||
// Some Wayland implementations (Weston) react badly when the size of a maximized
|
||||
// surface differs from the size suggested by Wayland through the "configure" event.
|
||||
// Changing the location of a maximized window does not make sense also, even if it were
|
||||
// possible in Wayland.
|
||||
return;
|
||||
}
|
||||
|
||||
super.setBounds(newX, newY, newWidth, newHeight, op);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoundsPrivate(int x, int y, int width, int height) {
|
||||
throw new UnsupportedOperationException();
|
||||
@@ -151,21 +165,22 @@ public class WLFramePeer extends WLDecoratedPeer implements FramePeer {
|
||||
}
|
||||
|
||||
@Override
|
||||
void notifyConfigured(int newXNative, int newYNative, int newWidthNative, int newHeightNative, boolean active, boolean maximized) {
|
||||
void notifyConfigured(int newSurfaceX, int newSurfaceY, int newSurfaceWidth, int newSurfaceHeight, boolean active, boolean maximized) {
|
||||
int widthBefore = getWidth();
|
||||
int heightBefore = getHeight();
|
||||
|
||||
super.notifyConfigured(newXNative, newYNative, newWidthNative, newHeightNative, active, maximized);
|
||||
super.notifyConfigured(newSurfaceX, newSurfaceY, newSurfaceWidth, newSurfaceHeight, active, maximized);
|
||||
|
||||
synchronized (getStateLock()) {
|
||||
int oldState = state;
|
||||
state = maximized ? Frame.MAXIMIZED_BOTH : Frame.NORMAL;
|
||||
AWTAccessor.getFrameAccessor().setExtendedState(getFrame(), state);
|
||||
if (state != oldState) {
|
||||
boolean clientDecidesDimension = newSurfaceWidth == 0 || newSurfaceHeight == 0;
|
||||
if (maximized) {
|
||||
widthBeforeMaximized = widthBefore;
|
||||
heightBeforeMaximized = heightBefore;
|
||||
} else if (newWidthNative == 0 && newHeightNative == 0 && widthBeforeMaximized > 0 && heightBeforeMaximized > 0) {
|
||||
} else if (clientDecidesDimension && widthBeforeMaximized > 0 && heightBeforeMaximized > 0) {
|
||||
performUnlocked(() -> target.setSize(widthBeforeMaximized, heightBeforeMaximized));
|
||||
}
|
||||
WLToolkit.postEvent(new WindowEvent(getFrame(), WindowEvent.WINDOW_STATE_CHANGED, oldState, state));
|
||||
|
||||
@@ -39,19 +39,19 @@ public abstract class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
private final WLGraphicsDevice device;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final int wlScale; // as reported by Wayland
|
||||
private final int displayScale; // as reported by Wayland
|
||||
private final double effectiveScale; // as enforced by Java
|
||||
|
||||
protected WLGraphicsConfig(WLGraphicsDevice device, int width, int height, int wlScale) {
|
||||
protected WLGraphicsConfig(WLGraphicsDevice device, int width, int height, int displayScale) {
|
||||
this.device = device;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.wlScale = wlScale;
|
||||
this.effectiveScale = WLGraphicsEnvironment.effectiveScaleFrom(wlScale);
|
||||
this.displayScale = displayScale;
|
||||
this.effectiveScale = WLGraphicsEnvironment.effectiveScaleFrom(displayScale);
|
||||
}
|
||||
|
||||
boolean differsFrom(int width, int height, int scale) {
|
||||
return width != this.width || height != this.height || scale != this.wlScale;
|
||||
return width != this.width || height != this.height || scale != this.displayScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,8 +91,8 @@ public abstract class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
/**
|
||||
* Returns the preferred Wayland buffer scale for this display configuration.
|
||||
*/
|
||||
public int getWlScale() {
|
||||
return wlScale;
|
||||
public int getDisplayScale() {
|
||||
return displayScale;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,6 +108,6 @@ public abstract class WLGraphicsConfig extends GraphicsConfiguration {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%dx%d %dx scale", width, height, wlScale);
|
||||
return String.format("%dx%d %dx scale", width, height, displayScale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
this.x = similarDevice.x;
|
||||
this.y = similarDevice.y;
|
||||
|
||||
int newScale = similarDevice.getWlScale();
|
||||
int newScale = similarDevice.getDisplayScale();
|
||||
Rectangle newBounds = similarDevice.defaultConfig.getBounds();
|
||||
updateConfiguration(similarDevice.name, newBounds.width, newBounds.height, newScale);
|
||||
}
|
||||
@@ -208,8 +208,8 @@ public class WLGraphicsDevice extends GraphicsDevice {
|
||||
return defaultConfig;
|
||||
}
|
||||
|
||||
int getWlScale() {
|
||||
return defaultConfig.getWlScale();
|
||||
int getDisplayScale() {
|
||||
return defaultConfig.getDisplayScale();
|
||||
}
|
||||
|
||||
int getResolution() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||
* Copyright (c) 2022-2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022-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
|
||||
@@ -46,7 +46,6 @@ class WLPointerEvent {
|
||||
private boolean has_leave_event;
|
||||
private boolean has_motion_event;
|
||||
private boolean has_button_event;
|
||||
private boolean has_axis_event;
|
||||
|
||||
private long surface; /// 'struct wl_surface *' this event appertains to
|
||||
private long serial;
|
||||
@@ -58,8 +57,19 @@ class WLPointerEvent {
|
||||
private int buttonCode; // pointer button code corresponding to PointerButtonCodes.linuxCode
|
||||
private boolean isButtonPressed; // true if button was pressed, false if released
|
||||
|
||||
private boolean axis_0_valid; // is vertical scroll included in this event?
|
||||
private int axis_0_value; // "length of vector in surface-local coordinate space" (source: wayland.xml)
|
||||
private boolean xAxis_hasVectorValue; // whether xAxis_vectorValue is valid
|
||||
private boolean xAxis_hasStopEvent; // whether wl_pointer::axis_stop event has been received for this axis
|
||||
private boolean xAxis_hasSteps120Value; // whether xAxis_steps120Value is valid
|
||||
private double xAxis_vectorValue; // "length of vector in surface-local coordinate space" (source: wayland.xml)
|
||||
private int xAxis_steps120Value; // "high-resolution wheel scroll information, with each multiple of 120
|
||||
// representing one logical scroll step (a wheel detent)" (source: wayland.xml)
|
||||
|
||||
private boolean yAxis_hasVectorValue; // whether yAxis_vectorValue is valid
|
||||
private boolean yAxis_hasStopEvent; // whether wl_pointer::axis_stop event has been received for this axis
|
||||
private boolean yAxis_hasSteps120Value; // whether yAxis_steps120Value is valid
|
||||
private double yAxis_vectorValue; // "length of vector in surface-local coordinate space" (source: wayland.xml)
|
||||
private int yAxis_steps120Value; // "high-resolution wheel scroll information, with each multiple of 120
|
||||
// representing one logical scroll step (a wheel detent)" (source: wayland.xml)
|
||||
|
||||
private WLPointerEvent() {}
|
||||
|
||||
@@ -175,7 +185,7 @@ class WLPointerEvent {
|
||||
}
|
||||
|
||||
public boolean hasAxisEvent() {
|
||||
return has_axis_event;
|
||||
return xAxisHasEvents() || yAxisHasEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,14 +251,60 @@ class WLPointerEvent {
|
||||
return isButtonPressed;
|
||||
}
|
||||
|
||||
public boolean getIsAxis0Valid() {
|
||||
assert hasAxisEvent();
|
||||
return axis_0_valid;
|
||||
public boolean xAxisHasEvents() {
|
||||
return xAxisHasVectorValue() ||
|
||||
xAxisHasStopEvent() ||
|
||||
xAxisHasSteps120Value();
|
||||
}
|
||||
|
||||
public int getAxis0Value() {
|
||||
assert hasAxisEvent();
|
||||
return axis_0_value;
|
||||
public boolean xAxisHasVectorValue() {
|
||||
return xAxis_hasVectorValue;
|
||||
}
|
||||
|
||||
public boolean xAxisHasStopEvent() {
|
||||
return xAxis_hasStopEvent;
|
||||
}
|
||||
|
||||
public boolean xAxisHasSteps120Value() {
|
||||
return xAxis_hasSteps120Value;
|
||||
}
|
||||
|
||||
public double getXAxisVectorValue() {
|
||||
assert xAxisHasVectorValue();
|
||||
return xAxis_vectorValue;
|
||||
}
|
||||
|
||||
public int getXAxisSteps120Value() {
|
||||
assert xAxisHasSteps120Value();
|
||||
return xAxis_steps120Value;
|
||||
}
|
||||
|
||||
public boolean yAxisHasEvents() {
|
||||
return yAxisHasVectorValue() ||
|
||||
yAxisHasStopEvent() ||
|
||||
yAxisHasSteps120Value();
|
||||
}
|
||||
|
||||
public boolean yAxisHasVectorValue() {
|
||||
return yAxis_hasVectorValue;
|
||||
}
|
||||
|
||||
public boolean yAxisHasStopEvent() {
|
||||
return yAxis_hasStopEvent;
|
||||
}
|
||||
|
||||
public boolean yAxisHasSteps120Value() {
|
||||
return yAxis_hasSteps120Value;
|
||||
}
|
||||
|
||||
public double getYAxisVectorValue() {
|
||||
assert yAxisHasVectorValue();
|
||||
return yAxis_vectorValue;
|
||||
}
|
||||
|
||||
public int getYAxisSteps120Value() {
|
||||
assert yAxisHasSteps120Value();
|
||||
return yAxis_steps120Value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -283,9 +339,32 @@ class WLPointerEvent {
|
||||
}
|
||||
|
||||
if (hasAxisEvent()) {
|
||||
builder.append("axis");
|
||||
if (axis_0_valid) {
|
||||
builder.append("vertical-scroll: ").append(axis_0_value).append(" ");
|
||||
builder.append(" axis");
|
||||
if (yAxisHasEvents()) {
|
||||
builder.append(" vertical-scroll:");
|
||||
|
||||
if (yAxisHasVectorValue()) {
|
||||
builder.append(" ").append(getYAxisVectorValue());
|
||||
}
|
||||
if (yAxisHasSteps120Value()) {
|
||||
builder.append(" ").append(getYAxisSteps120Value()).append("/120 steps");
|
||||
}
|
||||
if (yAxisHasStopEvent()) {
|
||||
builder.append(" stop");
|
||||
}
|
||||
}
|
||||
if (xAxisHasEvents()) {
|
||||
builder.append(" horizontal-scroll:");
|
||||
|
||||
if (xAxisHasVectorValue()) {
|
||||
builder.append(" ").append(getXAxisVectorValue());
|
||||
}
|
||||
if (xAxisHasSteps120Value()) {
|
||||
builder.append(" ").append(getXAxisSteps120Value()).append("/120 steps");
|
||||
}
|
||||
if (xAxisHasStopEvent()) {
|
||||
builder.append(" stop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,25 +32,26 @@ import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.ColorModel;
|
||||
import sun.awt.wl.WLComponentPeer;
|
||||
import sun.awt.wl.WLGraphicsConfig;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.loops.SurfaceType;
|
||||
import sun.java2d.pipe.BufferedContext;
|
||||
import sun.java2d.pipe.RenderBuffer;
|
||||
import sun.java2d.wl.WLSurfaceDataExt;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_BUFFER;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.CONFIGURE_SURFACE;
|
||||
|
||||
public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurfaceDataExt {
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.vulkan.WLVKSurfaceData");
|
||||
|
||||
protected WLComponentPeer peer;
|
||||
protected WLVKGraphicsConfig graphicsConfig;
|
||||
|
||||
@Override
|
||||
public native void assignSurface(long surfacePtr);
|
||||
@Override
|
||||
public native void revalidate(int width, int height, int scale);
|
||||
private native void initOps(int backgroundRGB);
|
||||
|
||||
private native void assignWlSurface(long surfacePtr);
|
||||
|
||||
protected native void initOps(int width, int height, int scale, int backgroundRGB);
|
||||
protected WLVKSurfaceData(WLComponentPeer peer, WLVKGraphicsConfig gc,
|
||||
SurfaceType sType, ColorModel cm, int type)
|
||||
{
|
||||
@@ -60,8 +61,53 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
|
||||
final int backgroundRGB = peer.getBackground() != null
|
||||
? peer.getBackground().getRGB()
|
||||
: 0;
|
||||
int scale = ((WLGraphicsConfig)peer.getGraphicsConfiguration()).getWlScale();
|
||||
initOps(peer.getBufferWidth(), peer.getBufferHeight(), scale, backgroundRGB);
|
||||
initOps(backgroundRGB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assignSurface(long surfacePtr) {
|
||||
assignWlSurface(surfacePtr);
|
||||
if (surfacePtr != 0) configure();
|
||||
}
|
||||
@Override
|
||||
public void revalidate(int width, int height, int scale) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.scale = scale;
|
||||
configure();
|
||||
}
|
||||
|
||||
private synchronized void configure() {
|
||||
VKRenderQueue rq = VKRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
RenderBuffer buf = rq.getBuffer();
|
||||
rq.ensureCapacityAndAlignment(20, 4);
|
||||
buf.putInt(CONFIGURE_SURFACE);
|
||||
buf.putLong(getNativeOps());
|
||||
buf.putInt(width / scale); // TODO This is incorrect, but we'll deal with this later, we probably need to do something on Wayland side for app-controlled scaling
|
||||
buf.putInt(height / scale); // TODO This is incorrect, but we'll deal with this later, we probably need to do something on Wayland side for app-controlled scaling
|
||||
|
||||
rq.flushNow();
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void commit() {
|
||||
VKRenderQueue rq = VKRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
RenderBuffer buf = rq.getBuffer();
|
||||
rq.ensureCapacityAndAlignment(12, 4);
|
||||
buf.putInt(FLUSH_BUFFER);
|
||||
buf.putLong(getNativeOps());
|
||||
|
||||
rq.flushNow();
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,10 +156,8 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
|
||||
}
|
||||
|
||||
public Rectangle getBounds() {
|
||||
Rectangle r = peer.getVisibleBounds();
|
||||
Rectangle r = peer.getBufferBounds();
|
||||
r.x = r.y = 0;
|
||||
r.width = (int) Math.ceil(r.width * scale);
|
||||
r.height = (int) Math.ceil(r.height * scale);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
|
||||
public native void revalidate(int width, int height, int scale);
|
||||
|
||||
@Override
|
||||
public native void flush();
|
||||
public native void commit();
|
||||
|
||||
public int getRGBPixelAt(int x, int y) {
|
||||
int pixel = pixelAt(x, y);
|
||||
|
||||
@@ -1,7 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 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.wl;
|
||||
|
||||
public interface WLSurfaceDataExt {
|
||||
|
||||
void assignSurface(long surfacePtr);
|
||||
void revalidate(int width, int height, int scale);
|
||||
void commit();
|
||||
}
|
||||
|
||||
@@ -24,115 +24,50 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "jni.h"
|
||||
#include <jni_util.h>
|
||||
#include <Trace.h>
|
||||
#include <SurfaceData.h>
|
||||
#include "VKBase.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "WLVKSurfaceData.h"
|
||||
|
||||
extern struct wl_display *wl_display;
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_initOps
|
||||
(JNIEnv *env, jobject vksd, jint width, jint height, jint scale, jint backgroundRGB) {
|
||||
#ifndef HEADLESS
|
||||
J2dTrace3(J2D_TRACE_INFO, "Create WLVKSurfaceData with size %d x %d and scale %d\n", width, height, scale);
|
||||
VKWinSDOps *vkwinsdo = (VKWinSDOps *)SurfaceData_InitOps(env, vksd, sizeof(VKWinSDOps));
|
||||
vkwinsdo->vksdOps.drawableType = VKSD_WINDOW;
|
||||
|
||||
if (vkwinsdo == NULL) {
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_initOps(JNIEnv *env, jobject vksd, jint backgroundRGB) {
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "WLVKSurfaceData_initOps(%p)", vksd);
|
||||
VKWinSDOps* sd = (VKWinSDOps*)SurfaceData_InitOps(env, vksd, sizeof(VKWinSDOps));
|
||||
if (sd == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
WLVKSDOps *wlvksdo = (WLVKSDOps *)malloc(sizeof(WLVKSDOps));
|
||||
|
||||
if (wlvksdo == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "creating native WLVK ops");
|
||||
return;
|
||||
}
|
||||
|
||||
vkwinsdo->privOps = wlvksdo;
|
||||
wlvksdo->wl_surface = NULL;
|
||||
width /= scale; // TODO This is incorrect, but we'll deal with this later, we probably need to do something on Wayland side for app-controlled scaling
|
||||
height /= scale; // TODO This is incorrect, but we'll deal with this later, we probably need to do something on Wayland side for app-controlled scaling
|
||||
vkwinsdo->vksdOps.width = width;
|
||||
vkwinsdo->vksdOps.height = height;
|
||||
vkwinsdo->vksdOps.scale = scale;
|
||||
vkwinsdo->vksdOps.bgColor = backgroundRGB;
|
||||
vkwinsdo->vksdOps.bgColorUpdated = VK_TRUE;
|
||||
#endif /* !HEADLESS */
|
||||
sd->vksdOps.drawableType = VKSD_WINDOW;
|
||||
sd->vksdOps.background = VKUtil_DecodeJavaColor(backgroundRGB);
|
||||
VKSD_ResetSurface(&sd->vksdOps);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_vulkan_WLVKSurfaceData_assignSurface(JNIEnv *env, jobject wsd, jlong wlSurfacePtr)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
VKWinSDOps* vkwinsdo = (VKWinSDOps *)SurfaceData_GetOps(env, wsd);
|
||||
if (vkwinsdo == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "WLVKSurfaceData_assignSurface: VKSDOps is NULL");
|
||||
return;
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_assignWlSurface(JNIEnv *env, jobject vksd, jlong wlSurfacePtr) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_INFO, "WLVKSurfaceData_assignWlSurface(%p): wl_surface=%p", (void*)vksd, wlSurfacePtr);
|
||||
VKWinSDOps* sd = (VKWinSDOps*)SurfaceData_GetOps(env, vksd);
|
||||
if (sd == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "WLVKSurfaceData_assignWlSurface(%p): VKWinSDOps is NULL", vksd);
|
||||
VK_UNHANDLED_ERROR();
|
||||
}
|
||||
WLVKSDOps* wlvksdo = (WLVKSDOps *)vkwinsdo->privOps;
|
||||
if (wlvksdo == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "WLVKSurfaceData_assignSurface: WLVKSDOps is NULL");
|
||||
return;
|
||||
|
||||
if (sd->surface != VK_NULL_HANDLE) {
|
||||
VKSD_ResetSurface(&sd->vksdOps);
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "WLVKSurfaceData_assignWlSurface(%p): surface reset", vksd);
|
||||
}
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = ge->currentDevice;
|
||||
wlvksdo->wl_surface = (struct wl_surface*)jlong_to_ptr(wlSurfacePtr);
|
||||
|
||||
if (vkwinsdo->surface == VK_NULL_HANDLE) {
|
||||
VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {};
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.display = wl_display;
|
||||
surfaceCreateInfo.surface = wlvksdo->wl_surface;
|
||||
struct wl_surface* wl_surface = (struct wl_surface*)jlong_to_ptr(wlSurfacePtr);
|
||||
|
||||
if (ge->vkCreateWaylandSurfaceKHR(ge->vkInstance,
|
||||
&surfaceCreateInfo,
|
||||
NULL,
|
||||
&vkwinsdo->surface) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "WLVKSurfaceData_assignSurface: WLVKSDOps is NULL");
|
||||
return;
|
||||
if (wl_surface != NULL) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
|
||||
.display = ge->waylandDisplay,
|
||||
.surface = wl_surface
|
||||
};
|
||||
VK_IF_ERROR(ge->vkCreateWaylandSurfaceKHR(ge->vkInstance, &surfaceCreateInfo, NULL, &sd->surface)) {
|
||||
VK_UNHANDLED_ERROR();
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "WLVKSurfaceData_assignWlSurface(%p): surface created", vksd);
|
||||
// Swapchain will be created later after CONFIGURE_SURFACE.
|
||||
}
|
||||
|
||||
VKSD_InitImageSurface(logicalDevice, &vkwinsdo->vksdOps);
|
||||
VKSD_InitWindowSurface(logicalDevice, vkwinsdo);
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "WLVKSurfaceData_assignSurface: Created WaylandSurfaceKHR");
|
||||
|
||||
J2dTraceLn2(J2D_TRACE_INFO, "WLVKSurfaceData_assignSurface wl_surface(%p) wl_display(%p)", wlvksdo->wl_surface, wl_display);
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_vulkan_WLVKSurfaceData_flush(JNIEnv *env, jobject wsd)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
J2dTrace(J2D_TRACE_INFO, "WLVKSurfaceData_flush\n");
|
||||
// TODO?
|
||||
#endif /* !HEADLESS */
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_vulkan_WLVKSurfaceData_revalidate(JNIEnv *env, jobject wsd,
|
||||
jint width, jint height, jint scale)
|
||||
{
|
||||
width /= scale; // TODO This is incorrect, but we'll deal with this later, we probably need to do something on Wayland side for app-controlled scaling
|
||||
height /= scale; // TODO This is incorrect, but we'll deal with this later, we probably need to do something on Wayland side for app-controlled scaling
|
||||
#ifndef HEADLESS
|
||||
VKSDOps* vksdo = (VKSDOps*)SurfaceData_GetOps(env, wsd);
|
||||
if (vksdo == NULL) {
|
||||
return;
|
||||
}
|
||||
J2dTrace3(J2D_TRACE_INFO, "WLVKSurfaceData_revalidate to size %d x %d and scale %d\n", width, height, scale);
|
||||
vksdo->width = width;
|
||||
vksdo->height = height;
|
||||
vksdo->scale = scale;
|
||||
#endif /* !HEADLESS */
|
||||
}
|
||||
|
||||
@@ -149,12 +149,13 @@ DamageList_Add(DamageList* list, jint x, jint y, jint width, jint height)
|
||||
static DamageList*
|
||||
DamageList_AddList(DamageList* list, DamageList* add)
|
||||
{
|
||||
assert(list != add);
|
||||
if (add != NULL) {
|
||||
assert(list != add);
|
||||
|
||||
for (DamageList* l = add; l != NULL; l = l->next) {
|
||||
list = DamageList_Add(list, l->x, l->y, l->width, l->height);
|
||||
for (DamageList *l = add; l != NULL; l = l->next) {
|
||||
list = DamageList_Add(list, l->x, l->y, l->width, l->height);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -928,6 +929,27 @@ DrawBufferResize(WLSurfaceBufferManager * manager)
|
||||
}
|
||||
}
|
||||
|
||||
static void ResetBuffers(WLSurfaceBufferManager * manager) {
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
|
||||
// Make sure the draw buffer is not copied from and re-set before drawn upon again
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
manager->bufferForDraw.resizePending = true;
|
||||
MUTEX_UNLOCK(manager->drawLock);
|
||||
|
||||
// All the damage refers to a surface that doesn't exist anymore; clean the lists
|
||||
// in case these buffers will be re-used for a new surface
|
||||
for (WLSurfaceBuffer* buffer = manager->buffersFree; buffer != NULL; buffer = buffer->next) {
|
||||
DamageList_FreeAll(buffer->damageList);
|
||||
buffer->damageList = NULL;
|
||||
}
|
||||
|
||||
for (WLSurfaceBuffer* buffer = manager->buffersInUse; buffer != NULL; buffer = buffer->next) {
|
||||
DamageList_FreeAll(buffer->damageList);
|
||||
buffer->damageList = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
HaveEnoughMemoryForWindow(jint width, jint height)
|
||||
{
|
||||
@@ -1014,6 +1036,8 @@ WLSBM_SurfaceAssign(WLSurfaceBufferManager * manager, struct wl_surface* wl_surf
|
||||
// will not commit anything new for a while, in which case the surface
|
||||
// may never get associated with a buffer and the window will never appear.
|
||||
TrySendShowBufferToWayland(manager, true);
|
||||
} else {
|
||||
ResetBuffers(manager);
|
||||
}
|
||||
} else {
|
||||
assert(manager->wlSurface == wl_surface);
|
||||
|
||||
@@ -111,10 +111,10 @@ Java_sun_java2d_wl_WLSMSurfaceData_assignSurface(JNIEnv *env, jobject wsd,
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_wl_WLSMSurfaceData_flush(JNIEnv *env, jobject wsd)
|
||||
Java_sun_java2d_wl_WLSMSurfaceData_commit(JNIEnv *env, jobject wsd)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
J2dTrace(J2D_TRACE_INFO, "WLSMSurfaceData_flush\n");
|
||||
J2dTrace(J2D_TRACE_INFO, "WLSMSurfaceData_commit\n");
|
||||
WLSDOps *wsdo = (WLSDOps*)SurfaceData_GetOps(env, wsd);
|
||||
if (wsdo == NULL) {
|
||||
return;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <jni.h>
|
||||
#include <jni_util.h>
|
||||
#include <Trace.h>
|
||||
#include <assert.h>
|
||||
#include <gtk-shell1-client-protocol.h>
|
||||
@@ -544,6 +545,7 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWLPopup
|
||||
assert(parentFrame);
|
||||
struct xdg_positioner *xdg_positioner = newPositioner(width, height, offsetX, offsetY);
|
||||
CHECK_NULL(xdg_positioner);
|
||||
JNU_RUNTIME_ASSERT(env, parentFrame->toplevel, "Popup's parent surface must be a toplevel");
|
||||
frame->xdg_popup = xdg_surface_get_popup(frame->xdg_surface, parentFrame->xdg_surface, xdg_positioner);
|
||||
CHECK_NULL(frame->xdg_popup);
|
||||
xdg_popup_add_listener(frame->xdg_popup, &xdg_popup_listener, frame);
|
||||
|
||||
@@ -1091,7 +1091,7 @@ convertKeysymToJavaCode(xkb_keysym_t keysym, int *javaKeyCode, int *javaKeyLocat
|
||||
// since this doesn't deal with lowercase/uppercase characters.
|
||||
// It later needs to be passed to KeyEvent.getExtendedKeyCodeForChar().
|
||||
// This is done in WLToolkit.java
|
||||
*javaKeyCode = 0x1000000 + codepoint;
|
||||
*javaKeyCode = (int)(0x1000000 + codepoint);
|
||||
}
|
||||
|
||||
if (javaKeyLocation) {
|
||||
@@ -1102,12 +1102,13 @@ convertKeysymToJavaCode(xkb_keysym_t keysym, int *javaKeyCode, int *javaKeyLocat
|
||||
|
||||
// Posts one UTF-16 code unit as a KEY_TYPED event
|
||||
static void
|
||||
postKeyTypedJavaChar(uint16_t javaChar) {
|
||||
postKeyTypedJavaChar(long timestamp, uint16_t javaChar) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "postKeyTypedJavaChar(0x%04x)\n", (int) javaChar);
|
||||
#endif
|
||||
|
||||
struct WLKeyEvent event = {
|
||||
.timestamp = timestamp,
|
||||
.id = java_awt_event_KeyEvent_KEY_TYPED,
|
||||
.keyCode = java_awt_event_KeyEvent_VK_UNDEFINED,
|
||||
.keyLocation = java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN,
|
||||
@@ -1121,7 +1122,7 @@ postKeyTypedJavaChar(uint16_t javaChar) {
|
||||
|
||||
// Posts one Unicode code point as KEY_TYPED events
|
||||
static void
|
||||
postKeyTypedCodepoint(uint32_t codePoint) {
|
||||
postKeyTypedCodepoint(long timestamp, uint32_t codePoint) {
|
||||
if (codePoint >= 0x10000) {
|
||||
// break the codepoint into surrogates
|
||||
|
||||
@@ -1130,16 +1131,16 @@ postKeyTypedCodepoint(uint32_t codePoint) {
|
||||
uint16_t highSurrogate = (uint16_t) (0xD800 + ((codePoint >> 10) & 0x3ff));
|
||||
uint16_t lowSurrogate = (uint16_t) (0xDC00 + (codePoint & 0x3ff));
|
||||
|
||||
postKeyTypedJavaChar(highSurrogate);
|
||||
postKeyTypedJavaChar(lowSurrogate);
|
||||
postKeyTypedJavaChar(timestamp, highSurrogate);
|
||||
postKeyTypedJavaChar(timestamp, lowSurrogate);
|
||||
} else {
|
||||
postKeyTypedJavaChar((uint16_t) codePoint);
|
||||
postKeyTypedJavaChar(timestamp, (uint16_t) codePoint);
|
||||
}
|
||||
}
|
||||
|
||||
// Posts a UTF-8 encoded string as KEY_TYPED events
|
||||
static void
|
||||
postKeyTypedEvents(const char *string) {
|
||||
postKeyTypedEvents(long timestamp, const char *string) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "postKeyTypedEvents(b\"");
|
||||
for (const char *c = string; *c; ++c) {
|
||||
@@ -1175,13 +1176,13 @@ postKeyTypedEvents(const char *string) {
|
||||
// a single codepoint in range U+0000 to U+007F
|
||||
remaining = 0;
|
||||
curCodePoint = 0;
|
||||
postKeyTypedCodepoint(*ptr & 0x7f);
|
||||
postKeyTypedCodepoint(timestamp, *ptr & 0x7f);
|
||||
} else if ((*ptr & 0xc0) == 0x80) {
|
||||
// continuation byte
|
||||
curCodePoint = (curCodePoint << 6u) | (uint32_t) (*ptr & 0x3f);
|
||||
--remaining;
|
||||
if (remaining == 0) {
|
||||
postKeyTypedCodepoint(curCodePoint);
|
||||
postKeyTypedCodepoint(timestamp, curCodePoint);
|
||||
curCodePoint = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -1202,35 +1203,35 @@ getJavaKeyCharForKeycode(xkb_keycode_t xkbKeycode) {
|
||||
|
||||
// Posts an XKB keysym as KEY_TYPED events, without consulting the current compose state.
|
||||
static void
|
||||
handleKeyTypeNoCompose(xkb_keycode_t xkbKeycode) {
|
||||
handleKeyTypeNoCompose(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
int bufSize = xkb.state_key_get_utf8(keyboard.state, xkbKeycode, NULL, 0) + 1;
|
||||
char buf[bufSize];
|
||||
xkb.state_key_get_utf8(keyboard.state, xkbKeycode, buf, bufSize);
|
||||
postKeyTypedEvents(buf);
|
||||
postKeyTypedEvents(timestamp, buf);
|
||||
}
|
||||
|
||||
// Handles generating KEY_TYPED events for an XKB keysym, translating it using the active compose state
|
||||
static void
|
||||
handleKeyType(xkb_keycode_t xkbKeycode) {
|
||||
handleKeyType(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
xkb_keysym_t keysym = xkb.state_key_get_one_sym(keyboard.state, xkbKeycode);
|
||||
|
||||
if (!keyboard.composeState ||
|
||||
(xkb.compose_state_feed(keyboard.composeState, keysym) == XKB_COMPOSE_FEED_IGNORED)) {
|
||||
handleKeyTypeNoCompose(xkbKeycode);
|
||||
handleKeyTypeNoCompose(timestamp, xkbKeycode);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (xkb.compose_state_get_status(keyboard.composeState)) {
|
||||
case XKB_COMPOSE_NOTHING:
|
||||
xkb.compose_state_reset(keyboard.composeState);
|
||||
handleKeyTypeNoCompose(xkbKeycode);
|
||||
handleKeyTypeNoCompose(timestamp, xkbKeycode);
|
||||
break;
|
||||
case XKB_COMPOSE_COMPOSING:
|
||||
break;
|
||||
case XKB_COMPOSE_COMPOSED: {
|
||||
char buf[MAX_COMPOSE_UTF8_LENGTH];
|
||||
xkb.compose_state_get_utf8(keyboard.composeState, buf, sizeof buf);
|
||||
postKeyTypedEvents(buf);
|
||||
postKeyTypedEvents(timestamp, buf);
|
||||
xkb.compose_state_reset(keyboard.composeState);
|
||||
break;
|
||||
}
|
||||
@@ -1292,7 +1293,7 @@ handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
.id = isPressed ? java_awt_event_KeyEvent_KEY_PRESSED : java_awt_event_KeyEvent_KEY_RELEASED,
|
||||
.keyCode = javaKeyCode,
|
||||
.keyLocation = javaKeyLocation,
|
||||
.rawCode = keycode,
|
||||
.rawCode = (int)xkbKeycode,
|
||||
.extendedKeyCode = javaExtendedKeyCode,
|
||||
.keyChar = getJavaKeyCharForKeycode(xkbKeycode),
|
||||
};
|
||||
@@ -1300,7 +1301,7 @@ handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
wlPostKeyEvent(&event);
|
||||
|
||||
if (isPressed) {
|
||||
handleKeyType(xkbKeycode);
|
||||
handleKeyType(timestamp, xkbKeycode);
|
||||
|
||||
if (!isRepeat && xkb.keymap_key_repeats(keyboard.keymap, xkbKeycode)) {
|
||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, startRepeatMID, timestamp, keycode);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||
* Copyright (c) 2022-2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022-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
|
||||
@@ -59,6 +59,8 @@
|
||||
#include "sun_awt_wl_WLRobotPeer.h"
|
||||
#endif
|
||||
|
||||
#define CHECK_WL_INTERFACE(var, name) if (!(var)) { JNU_ThrowByName(env, "java/awt/AWTError", "Can't bind to the " name " interface"); }
|
||||
|
||||
extern JavaVM *jvm;
|
||||
|
||||
struct wl_display *wl_display = NULL;
|
||||
@@ -66,19 +68,19 @@ struct wl_shm *wl_shm = NULL;
|
||||
struct wl_compositor *wl_compositor = NULL;
|
||||
struct xdg_wm_base *xdg_wm_base = NULL;
|
||||
struct wp_viewporter *wp_viewporter = NULL;
|
||||
struct xdg_activation_v1 *xdg_activation_v1 = NULL;
|
||||
struct xdg_activation_v1 *xdg_activation_v1 = NULL; // optional, check for NULL before use
|
||||
struct gtk_shell1* gtk_shell1 = NULL;
|
||||
struct wl_seat *wl_seat = NULL;
|
||||
|
||||
struct wl_keyboard *wl_keyboard;
|
||||
struct wl_pointer *wl_pointer;
|
||||
struct wl_keyboard *wl_keyboard; // optional, check for NULL before use
|
||||
struct wl_pointer *wl_pointer; // optional, check for NULL before use
|
||||
|
||||
#define MAX_CURSOR_SCALE 100
|
||||
struct wl_cursor_theme *cursor_themes[MAX_CURSOR_SCALE] = {NULL};
|
||||
|
||||
struct wl_surface *wl_surface_in_focus = NULL;
|
||||
struct wl_data_device_manager *wl_ddm = NULL;
|
||||
struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm = NULL;
|
||||
struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm = NULL; // optional, check for NULL before use
|
||||
|
||||
uint32_t last_mouse_pressed_serial = 0;
|
||||
uint32_t last_pointer_enter_serial = 0;
|
||||
@@ -102,7 +104,6 @@ static jfieldID hasEnterEventFID;
|
||||
static jfieldID hasLeaveEventFID;
|
||||
static jfieldID hasMotionEventFID;
|
||||
static jfieldID hasButtonEventFID;
|
||||
static jfieldID hasAxisEventFID;
|
||||
static jfieldID serialFID;
|
||||
static jfieldID surfaceFID;
|
||||
static jfieldID timestampFID;
|
||||
@@ -110,8 +111,16 @@ static jfieldID surfaceXFID;
|
||||
static jfieldID surfaceYFID;
|
||||
static jfieldID buttonCodeFID;
|
||||
static jfieldID isButtonPressedFID;
|
||||
static jfieldID axis_0_validFID;
|
||||
static jfieldID axis_0_valueFID;
|
||||
static jfieldID xAxis_hasVectorValueFID;
|
||||
static jfieldID xAxis_hasStopEventFID;
|
||||
static jfieldID xAxis_hasSteps120ValueFID;
|
||||
static jfieldID xAxis_vectorValueFID;
|
||||
static jfieldID xAxis_steps120ValueFID;
|
||||
static jfieldID yAxis_hasVectorValueFID;
|
||||
static jfieldID yAxis_hasStopEventFID;
|
||||
static jfieldID yAxis_hasSteps120ValueFID;
|
||||
static jfieldID yAxis_vectorValueFID;
|
||||
static jfieldID yAxis_steps120ValueFID;
|
||||
|
||||
static jmethodID dispatchKeyboardKeyEventMID;
|
||||
static jmethodID dispatchKeyboardModifiersEventMID;
|
||||
@@ -141,10 +150,7 @@ struct pointer_event_cumulative {
|
||||
bool has_leave_event : 1;
|
||||
bool has_motion_event : 1;
|
||||
bool has_button_event : 1;
|
||||
bool has_axis_event : 1;
|
||||
bool has_axis_source_event : 1;
|
||||
bool has_axis_stop_event : 1;
|
||||
bool has_axis_discrete_event : 1;
|
||||
|
||||
uint32_t time;
|
||||
uint32_t serial;
|
||||
@@ -157,9 +163,19 @@ struct pointer_event_cumulative {
|
||||
uint32_t state;
|
||||
|
||||
struct {
|
||||
bool valid;
|
||||
wl_fixed_t value;
|
||||
int32_t discrete;
|
||||
// wl_pointer::axis
|
||||
bool has_vector_value : 1;
|
||||
// wl_pointer::axis_stop
|
||||
bool has_stop_event : 1;
|
||||
// wl_pointer::axis_discrete or wl_pointer::axis_value120
|
||||
bool has_steps120_value : 1;
|
||||
|
||||
// wl_pointer::axis
|
||||
wl_fixed_t vector_value;
|
||||
|
||||
// wl_pointer::axis_discrete or wl_pointer::axis_value120
|
||||
// In the former case, the value is multiplied by 120 for compatibility with wl_pointer::axis_value120
|
||||
int32_t steps120_value;
|
||||
} axes[2];
|
||||
uint32_t axis_source;
|
||||
};
|
||||
@@ -219,10 +235,9 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
||||
{
|
||||
assert(axis < sizeof(pointer_event.axes)/sizeof(pointer_event.axes[0]));
|
||||
|
||||
pointer_event.has_axis_event = true;
|
||||
pointer_event.time = time;
|
||||
pointer_event.axes[axis].valid = true;
|
||||
pointer_event.axes[axis].value = value;
|
||||
pointer_event.axes[axis].has_vector_value = true;
|
||||
pointer_event.time = time;
|
||||
pointer_event.axes[axis].vector_value = value;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -239,18 +254,35 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
||||
{
|
||||
assert(axis < sizeof(pointer_event.axes)/sizeof(pointer_event.axes[0]));
|
||||
|
||||
pointer_event.has_axis_stop_event = true;
|
||||
pointer_event.time = time;
|
||||
pointer_event.axes[axis].valid = true;
|
||||
pointer_event.axes[axis].has_stop_event = true;
|
||||
pointer_event.time = time;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t axis, int32_t discrete)
|
||||
{
|
||||
pointer_event.has_axis_discrete_event = true;
|
||||
pointer_event.axes[axis].valid = true;
|
||||
pointer_event.axes[axis].discrete = discrete;
|
||||
assert(axis < sizeof(pointer_event.axes)/sizeof(pointer_event.axes[0]));
|
||||
|
||||
// wl_pointer::axis_discrete event is deprecated with wl_pointer version 8 - this event is not sent to clients
|
||||
// supporting version 8 or later.
|
||||
// It's just an additional check to work around possible bugs in compositors when they send both
|
||||
// wl_pointer::axis_discrete and wl_pointer::axis_value120 events within the same frame.
|
||||
// In this case wl_pointer::axis_value120 would be preferred.
|
||||
if (!pointer_event.axes[axis].has_steps120_value) {
|
||||
pointer_event.axes[axis].has_steps120_value = true;
|
||||
pointer_event.axes[axis].steps120_value = discrete * 120;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wl_pointer_axis_value120(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t axis, int32_t value120)
|
||||
{
|
||||
assert(axis < sizeof(pointer_event.axes)/sizeof(pointer_event.axes[0]));
|
||||
|
||||
pointer_event.axes[axis].has_steps120_value = true;
|
||||
pointer_event.axes[axis].steps120_value = value120;
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -266,7 +298,6 @@ fillJavaPointerEvent(JNIEnv* env, jobject pointerEventRef)
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasLeaveEventFID, pointer_event.has_leave_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasMotionEventFID, pointer_event.has_motion_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasButtonEventFID, pointer_event.has_button_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, hasAxisEventFID, pointer_event.has_axis_event);
|
||||
|
||||
(*env)->SetLongField(env, pointerEventRef, surfaceFID, (long)pointer_event.surface);
|
||||
(*env)->SetLongField(env, pointerEventRef, serialFID, pointer_event.serial);
|
||||
@@ -279,8 +310,17 @@ fillJavaPointerEvent(JNIEnv* env, jobject pointerEventRef)
|
||||
(*env)->SetBooleanField(env, pointerEventRef, isButtonPressedFID,
|
||||
(pointer_event.state == WL_POINTER_BUTTON_STATE_PRESSED));
|
||||
|
||||
(*env)->SetBooleanField(env, pointerEventRef, axis_0_validFID, pointer_event.axes[0].valid);
|
||||
(*env)->SetIntField(env, pointerEventRef, axis_0_valueFID, wl_fixed_to_int(pointer_event.axes[0].value));
|
||||
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasVectorValueFID, pointer_event.axes[1].has_vector_value);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasStopEventFID, pointer_event.axes[1].has_stop_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasSteps120ValueFID, pointer_event.axes[1].has_steps120_value);
|
||||
(*env)->SetDoubleField (env, pointerEventRef, xAxis_vectorValueFID, wl_fixed_to_double(pointer_event.axes[1].vector_value));
|
||||
(*env)->SetIntField (env, pointerEventRef, xAxis_steps120ValueFID, pointer_event.axes[1].steps120_value);
|
||||
|
||||
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasVectorValueFID, pointer_event.axes[0].has_vector_value);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasStopEventFID, pointer_event.axes[0].has_stop_event);
|
||||
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasSteps120ValueFID, pointer_event.axes[0].has_steps120_value);
|
||||
(*env)->SetDoubleField (env, pointerEventRef, yAxis_vectorValueFID, wl_fixed_to_double(pointer_event.axes[0].vector_value));
|
||||
(*env)->SetIntField (env, pointerEventRef, yAxis_steps120ValueFID, pointer_event.axes[0].steps120_value);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -313,7 +353,9 @@ static const struct wl_pointer_listener wl_pointer_listener = {
|
||||
.frame = wl_pointer_frame,
|
||||
.axis_source = wl_pointer_axis_source,
|
||||
.axis_stop = wl_pointer_axis_stop,
|
||||
.axis_discrete = wl_pointer_axis_discrete
|
||||
.axis_discrete = wl_pointer_axis_discrete/*,
|
||||
This is only supported if the libwayland-client supports version 8 of the wl_pointer interface
|
||||
.axis_value120 = wl_pointer_axis_value120*/
|
||||
};
|
||||
|
||||
|
||||
@@ -439,7 +481,9 @@ wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
|
||||
|
||||
if (has_pointer && wl_pointer == NULL) {
|
||||
wl_pointer = wl_seat_get_pointer(wl_seat);
|
||||
wl_pointer_add_listener(wl_pointer, &wl_pointer_listener, NULL);
|
||||
if (wl_pointer != NULL) {
|
||||
wl_pointer_add_listener(wl_pointer, &wl_pointer_listener, NULL);
|
||||
}
|
||||
} else if (!has_pointer && wl_pointer != NULL) {
|
||||
wl_pointer_release(wl_pointer);
|
||||
wl_pointer = NULL;
|
||||
@@ -447,7 +491,9 @@ wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
|
||||
|
||||
if (has_keyboard && wl_keyboard == NULL) {
|
||||
wl_keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
wl_keyboard_add_listener(wl_keyboard, &wl_keyboard_listener, NULL);
|
||||
if (wl_keyboard != NULL) {
|
||||
wl_keyboard_add_listener(wl_keyboard, &wl_keyboard_listener, NULL);
|
||||
}
|
||||
} else if (!has_keyboard && wl_keyboard != NULL) {
|
||||
wl_keyboard_release(wl_keyboard);
|
||||
wl_keyboard = NULL;
|
||||
@@ -624,8 +670,6 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(hasButtonEventFID = (*env)->GetFieldID(env, pointerEventClass, "has_button_event", "Z"),
|
||||
JNI_FALSE);
|
||||
CHECK_NULL_RETURN(hasAxisEventFID = (*env)->GetFieldID(env, pointerEventClass, "has_axis_event", "Z"),
|
||||
JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(serialFID = (*env)->GetFieldID(env, pointerEventClass, "serial", "J"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(surfaceFID = (*env)->GetFieldID(env, pointerEventClass, "surface", "J"), JNI_FALSE);
|
||||
@@ -634,8 +678,18 @@ initJavaRefs(JNIEnv *env, jclass clazz)
|
||||
CHECK_NULL_RETURN(surfaceYFID = (*env)->GetFieldID(env, pointerEventClass, "surface_y", "I"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(buttonCodeFID = (*env)->GetFieldID(env, pointerEventClass, "buttonCode", "I"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(isButtonPressedFID = (*env)->GetFieldID(env, pointerEventClass, "isButtonPressed", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(axis_0_validFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_valid", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(axis_0_valueFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_value", "I"), JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(xAxis_hasVectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasVectorValue", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(xAxis_hasStopEventFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasStopEvent", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(xAxis_hasSteps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasSteps120Value", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(xAxis_vectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_vectorValue", "D"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(xAxis_steps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_steps120Value", "I"), JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(yAxis_hasVectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasVectorValue", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(yAxis_hasStopEventFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasStopEvent", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(yAxis_hasSteps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasSteps120Value", "Z"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(yAxis_vectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_vectorValue", "D"), JNI_FALSE);
|
||||
CHECK_NULL_RETURN(yAxis_steps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_steps120Value", "I"), JNI_FALSE);
|
||||
|
||||
CHECK_NULL_RETURN(dispatchKeyboardEnterEventMID = (*env)->GetStaticMethodID(env, tkClass,
|
||||
"dispatchKeyboardEnterEvent",
|
||||
@@ -737,6 +791,19 @@ finalizeInit(JNIEnv *env) {
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
checkInterfacesPresent(JNIEnv *env)
|
||||
{
|
||||
// Check that all non-optional interfaces have been bound to and throw an appropriate error otherwise
|
||||
CHECK_WL_INTERFACE(wl_shm, "wl_shm");
|
||||
CHECK_WL_INTERFACE(wl_seat, "wl_seat");
|
||||
CHECK_WL_INTERFACE(wl_display, "wl_display");
|
||||
CHECK_WL_INTERFACE(wl_compositor, "wl_compositor");
|
||||
CHECK_WL_INTERFACE(xdg_wm_base, "xdg_wm_base");
|
||||
CHECK_WL_INTERFACE(wp_viewporter, "wp_viewporter");
|
||||
CHECK_WL_INTERFACE(wl_ddm, "wl_data_device_manager");
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_awt_wl_WLDisplay_connect(JNIEnv *env, jobject obj)
|
||||
{
|
||||
@@ -771,6 +838,8 @@ Java_sun_awt_wl_WLToolkit_initIDs(JNIEnv *env, jclass clazz, jlong displayPtr)
|
||||
J2dTrace1(J2D_TRACE_INFO, "WLToolkit: Connection to display(%p) established\n", wl_display);
|
||||
|
||||
finalizeInit(env);
|
||||
|
||||
checkInterfacesPresent(env);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
||||
@@ -52,16 +52,16 @@ struct gtk_shell1;
|
||||
|
||||
extern struct wl_seat *wl_seat;
|
||||
extern struct wl_display *wl_display;
|
||||
extern struct wl_pointer *wl_pointer;
|
||||
extern struct wl_pointer *wl_pointer; // optional, check for NULL before use
|
||||
extern struct wl_compositor *wl_compositor;
|
||||
extern struct xdg_wm_base *xdg_wm_base;
|
||||
extern struct wp_viewporter *wp_viewporter;
|
||||
extern struct xdg_activation_v1 *xdg_activation_v1;
|
||||
extern struct xdg_activation_v1 *xdg_activation_v1; // optional, check for NULL before use
|
||||
extern struct gtk_shell1* gtk_shell1; // optional, check for NULL before use
|
||||
|
||||
extern struct wl_cursor_theme *wl_cursor_theme;
|
||||
extern struct wl_data_device_manager *wl_ddm;
|
||||
extern struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm;
|
||||
extern struct zwp_primary_selection_device_manager_v1 *zwp_selection_dm; // optional, check for NULL before use
|
||||
|
||||
extern struct wl_surface *wl_surface_in_focus;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2024, 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
|
||||
@@ -28,20 +28,41 @@ package sun.awt;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Toolkit;
|
||||
|
||||
import sun.awt.windows.WToolkit;
|
||||
|
||||
public class PlatformGraphicsInfo {
|
||||
|
||||
private static final boolean hasDisplays;
|
||||
|
||||
static {
|
||||
loadAWTLibrary();
|
||||
hasDisplays = hasDisplays0();
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static void loadAWTLibrary() {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("awt");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static native boolean hasDisplays0();
|
||||
|
||||
public static GraphicsEnvironment createGE() {
|
||||
return new Win32GraphicsEnvironment();
|
||||
}
|
||||
|
||||
public static Toolkit createToolkit() {
|
||||
return new sun.awt.windows.WToolkit();
|
||||
return new WToolkit();
|
||||
}
|
||||
|
||||
public static boolean getDefaultHeadlessProperty() {
|
||||
// On Windows, we assume we can always create headful apps.
|
||||
// Here is where we can add code that would actually check.
|
||||
return false;
|
||||
// If we don't find usable displays, we run headless.
|
||||
return !hasDisplays;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, 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
|
||||
@@ -66,7 +66,8 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
WToolkit.loadLibraries();
|
||||
// setup flags before initializing native layer
|
||||
WindowsFlags.initFlags();
|
||||
initDisplayWrapper();
|
||||
|
||||
initDisplay();
|
||||
|
||||
// Install correct surface manager factory.
|
||||
SurfaceManagerFactory.setInstance(new WindowsSurfaceManagerFactory());
|
||||
@@ -88,21 +89,12 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes native components of the graphics environment. This
|
||||
* Initializes native components of the graphics environment. This
|
||||
* includes everything from the native GraphicsDevice elements to
|
||||
* the DirectX rendering layer.
|
||||
*/
|
||||
private static native void initDisplay();
|
||||
|
||||
private static boolean displayInitialized; // = false;
|
||||
public static void initDisplayWrapper() {
|
||||
if (!displayInitialized) {
|
||||
displayInitialized = true;
|
||||
if (!isUIScaleEnabled()) setProcessDPIAwareness(PROCESS_SYSTEM_DPI_AWARE);
|
||||
initDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
public Win32GraphicsEnvironment() {
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.awt.BufferCapabilities;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
@@ -73,6 +74,8 @@ import sun.java2d.opengl.OGLSurfaceData;
|
||||
import sun.java2d.pipe.Region;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import static sun.awt.windows.WToolkit.getWToolkit;
|
||||
|
||||
public abstract class WComponentPeer extends WObjectPeer
|
||||
implements ComponentPeer, DropTargetPeer
|
||||
{
|
||||
@@ -129,6 +132,10 @@ public abstract class WComponentPeer extends WObjectPeer
|
||||
@Override
|
||||
public native Point getLocationOnScreen();
|
||||
|
||||
Cursor getCursor(final Point p) {
|
||||
return getTarget() instanceof Component ? ((Component)getTarget()).getCursor() : null;
|
||||
}
|
||||
|
||||
/* New 1.1 API */
|
||||
@Override
|
||||
public void setVisible(boolean b) {
|
||||
@@ -705,9 +712,10 @@ public abstract class WComponentPeer extends WObjectPeer
|
||||
_setFont(f);
|
||||
}
|
||||
synchronized native void _setFont(Font f);
|
||||
|
||||
@Override
|
||||
public void updateCursorImmediately() {
|
||||
WGlobalCursorManager.getCursorManager().updateCursorImmediately();
|
||||
WGlobalCursorManager.getInstance().updateCursor();
|
||||
}
|
||||
|
||||
// TODO: consider moving it to KeyboardFocusManagerPeerImpl
|
||||
|
||||
@@ -25,37 +25,68 @@
|
||||
|
||||
package sun.awt.windows;
|
||||
|
||||
import java.awt.*;
|
||||
import sun.awt.GlobalCursorManager;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Point;
|
||||
|
||||
final class WGlobalCursorManager extends GlobalCursorManager {
|
||||
private static WGlobalCursorManager manager;
|
||||
import sun.awt.CachedCursorManager;
|
||||
|
||||
public static GlobalCursorManager getCursorManager() {
|
||||
if (manager == null) {
|
||||
manager = new WGlobalCursorManager();
|
||||
import static sun.awt.windows.WToolkit.getWToolkit;
|
||||
|
||||
final class WGlobalCursorManager extends CachedCursorManager {
|
||||
private Component lastMouseEventComponent;
|
||||
|
||||
private WGlobalCursorManager() {
|
||||
}
|
||||
|
||||
public void setMouseEventComponent(Component component) {
|
||||
lastMouseEventComponent = component;
|
||||
}
|
||||
|
||||
public Component getMouseEventComponent() {
|
||||
return lastMouseEventComponent;
|
||||
}
|
||||
|
||||
private static final WGlobalCursorManager theInstance = new WGlobalCursorManager();
|
||||
public static WGlobalCursorManager getInstance() {
|
||||
return theInstance;
|
||||
}
|
||||
|
||||
private native void getCursorPos(Point p);
|
||||
private native void setCursor(Cursor cursor, boolean u);
|
||||
@Override
|
||||
protected native Point getLocationOnScreen(Component component);
|
||||
|
||||
@Override
|
||||
protected Cursor getCursorByPosition(Point cursorPos, Component c) {
|
||||
final Object peer = WToolkit.targetToPeer(c);
|
||||
if (peer instanceof WComponentPeer && c.isShowing()) {
|
||||
final WComponentPeer wpeer = (WComponentPeer) peer;
|
||||
final Point p = getLocationOnScreen((Component) wpeer.getTarget());
|
||||
return wpeer.getCursor(new Point(cursorPos.x - p.x,
|
||||
cursorPos.y - p.y));
|
||||
}
|
||||
return manager;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called in response to a native mouse enter or native mouse
|
||||
* button released message. Should not be called during a mouse drag.
|
||||
*/
|
||||
public static void nativeUpdateCursor(Component heavy) {
|
||||
WGlobalCursorManager.getCursorManager().updateCursorLater(heavy);
|
||||
public static void nativeUpdateCursor(Component component) {
|
||||
getInstance().updateCursorLater(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected native void setCursor(Component comp, Cursor cursor, boolean u);
|
||||
protected Component getComponentUnderCursor() {
|
||||
return lastMouseEventComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected native void getCursorPos(Point p);
|
||||
/*
|
||||
* two native methods to call corresponding methods in Container and
|
||||
* Component
|
||||
*/
|
||||
public Point getCursorPosition() {
|
||||
Point cursorPos = new Point();
|
||||
getCursorPos(cursorPos);
|
||||
return cursorPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected native Component findHeavyweightUnderCursor(boolean useCache);
|
||||
@Override
|
||||
protected native Point getLocationOnScreen(Component com);
|
||||
protected void setCursor(Cursor cursor) {
|
||||
setCursor(cursor, true);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user