mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-23 00:40:50 +01:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10839395fa | ||
|
|
1939def8e5 | ||
|
|
9bffde9d6e | ||
|
|
3f91b5c418 | ||
|
|
86c050e988 | ||
|
|
340680d3b2 | ||
|
|
0d64fee1c6 | ||
|
|
3dc09c7888 | ||
|
|
d8ece060f6 | ||
|
|
0aa17e5e25 | ||
|
|
c28643392f | ||
|
|
c430c1e0b7 | ||
|
|
c5dbd5d1a3 | ||
|
|
c1394c1688 | ||
|
|
3f05010c31 | ||
|
|
ca6a54d1ff | ||
|
|
8afe214424 | ||
|
|
17ef8fd65e | ||
|
|
3647144b39 | ||
|
|
1e3fb0289d | ||
|
|
56bd776f20 | ||
|
|
036ef4917f | ||
|
|
2c287a5f36 | ||
|
|
d8c179cf77 | ||
|
|
469130b7ec | ||
|
|
535416746d | ||
|
|
9d011d23df | ||
|
|
3399c59635 | ||
|
|
4bd4fcabf8 | ||
|
|
01df339ac6 | ||
|
|
6dfa6444b1 | ||
|
|
69866f39d9 | ||
|
|
13d8c351a2 | ||
|
|
2324820a9b | ||
|
|
96b270b25f | ||
|
|
d133624956 | ||
|
|
9bd0b744be | ||
|
|
0d099c3d27 | ||
|
|
ebaf3f9293 | ||
|
|
a79bb6107a | ||
|
|
0e564fd8b4 |
55
make/autoconf/lib-dbus.m4
Normal file
55
make/autoconf/lib-dbus.m4
Normal file
@@ -0,0 +1,55 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
################################################################################
|
||||
# Check if a potential dbus library match is correct and usable
|
||||
################################################################################
|
||||
AC_DEFUN_ONCE([LIB_SETUP_DBUS],
|
||||
[
|
||||
AC_ARG_WITH(dbus-includes, [AS_HELP_STRING([--with-dbus-includes],
|
||||
[specify include directories for the dbus files as list separated by space])])
|
||||
|
||||
if test "x$NEEDS_LIB_DBUS" = xfalse; then
|
||||
DBUS_CFLAGS=
|
||||
DBUS_FOUND=false
|
||||
else
|
||||
if test "x${with_dbus_includes}" != x; then
|
||||
DBUS_FOUND=true
|
||||
DBUS_CFLAGS=""
|
||||
for include in $with_dbus_includes; do
|
||||
DBUS_CFLAGS="${DBUS_CFLAGS}-I${include} "
|
||||
done
|
||||
else
|
||||
PKG_CHECK_MODULES(DBUS, dbus-1, [DBUS_FOUND=true], [
|
||||
DBUS_FOUND=false
|
||||
AC_MSG_NOTICE([Can't find dbus-1 library. This library is needed to use some features. You can install dbus-1 library or specify include directories manually by giving --with-dbus-includes option.])
|
||||
])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(DBUS_CFLAGS)
|
||||
AC_SUBST(DBUS_FOUND)
|
||||
])
|
||||
@@ -106,9 +106,6 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
AC_ARG_WITH(vulkan-include, [AS_HELP_STRING([--with-vulkan-include],
|
||||
[specify directory for the vulkan include files ({with-vulkan-include}/vulkan/vulkan.h)])])
|
||||
|
||||
AC_ARG_WITH(vulkan-hpp, [AS_HELP_STRING([--with-vulkan-hpp],
|
||||
[specify directory for the vulkan-hpp include files ({with-vulkan-hpp}/vulkan/vulkan_raii.hpp)])])
|
||||
|
||||
AC_ARG_WITH(vulkan-shader-compiler, [AS_HELP_STRING([--with-vulkan-shader-compiler],
|
||||
[specify which shader compiler to use: glslc/glslangValidator])])
|
||||
|
||||
@@ -139,27 +136,11 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Can't find 'vulkan/vulkan.h' under '${with_vulkan_include}'])
|
||||
fi
|
||||
AC_MSG_CHECKING([for vulkan_raii.hpp])
|
||||
if test "x${with_vulkan_hpp}" != x; then
|
||||
VULKAN_FLAGS="-I${with_vulkan_hpp} ${VULKAN_FLAGS}"
|
||||
VULKAN_HPP_DIR=${with_vulkan_hpp}
|
||||
else
|
||||
VULKAN_HPP_DIR=${with_vulkan_include}
|
||||
fi
|
||||
if test -s "$VULKAN_HPP_DIR/vulkan/vulkan_raii.hpp"; then
|
||||
VULKAN_FOUND=yes
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
VULKAN_FOUND=no
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Can't find 'vulkan/vulkan_raii.hpp' under '$VULKAN_HPP_DIR'])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_LANG_PUSH([C++])
|
||||
if test "x$VULKAN_FOUND" = xno; then
|
||||
# Check vulkan sdk location
|
||||
AC_CHECK_HEADERS([$VULKAN_SDK/include/vulkan/vulkan.h $VULKAN_SDK/include/vulkan/vulkan_raii.hpp],
|
||||
AC_CHECK_HEADERS([$VULKAN_SDK/include/vulkan/vulkan.h],
|
||||
[ VULKAN_FOUND=yes
|
||||
VULKAN_FLAGS="-DVK_USE_PLATFORM_WAYLAND_KHR -I${VULKAN_SDK}/include -DVULKAN_ENABLED"
|
||||
],
|
||||
@@ -169,14 +150,13 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
|
||||
if test "x$VULKAN_FOUND" = xno; then
|
||||
# Check default /usr/include location
|
||||
AC_CHECK_HEADERS([vulkan/vulkan.h vulkan/vulkan_raii.hpp],
|
||||
AC_CHECK_HEADERS([vulkan/vulkan.h],
|
||||
[ VULKAN_FOUND=yes
|
||||
VULKAN_FLAGS="-DVK_USE_PLATFORM_WAYLAND_KHR -DVULKAN_ENABLED"
|
||||
],
|
||||
[ VULKAN_FOUND=no; break ]
|
||||
)
|
||||
fi
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
if test "x$VULKAN_FOUND" = xno; then
|
||||
HELP_MSG_MISSING_DEPENDENCY([vulkan])
|
||||
|
||||
@@ -37,7 +37,7 @@ m4_include([lib-fontconfig.m4])
|
||||
m4_include([lib-speechd.m4])
|
||||
m4_include([lib-nvdacontrollerclient.m4])
|
||||
m4_include([lib-wayland.m4])
|
||||
|
||||
m4_include([lib-dbus.m4])
|
||||
m4_include([lib-tests.m4])
|
||||
|
||||
################################################################################
|
||||
@@ -90,11 +90,13 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES],
|
||||
NEEDS_LIB_FREETYPE=true
|
||||
fi
|
||||
|
||||
# Check if alsa is needed
|
||||
# Check if alsa and dbus is needed
|
||||
if test "x$OPENJDK_TARGET_OS" = xlinux; then
|
||||
NEEDS_LIB_ALSA=true
|
||||
NEEDS_LIB_DBUS=true
|
||||
else
|
||||
NEEDS_LIB_ALSA=false
|
||||
NEEDS_LIB_DBUS=false
|
||||
fi
|
||||
|
||||
# Check if ffi is needed
|
||||
@@ -152,7 +154,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
|
||||
LIB_SETUP_SPEECHD
|
||||
LIB_SETUP_NVDACONTROLLERCLIENT
|
||||
LIB_SETUP_WAYLAND
|
||||
|
||||
LIB_SETUP_DBUS
|
||||
LIB_TESTS_SETUP_GTEST
|
||||
|
||||
BASIC_JDKLIB_LIBS=""
|
||||
|
||||
@@ -467,6 +467,10 @@ UBSAN_LDFLAGS:=@UBSAN_LDFLAGS@
|
||||
X_CFLAGS:=@X_CFLAGS@
|
||||
X_LIBS:=@X_LIBS@
|
||||
|
||||
# Necessary additional compiler flags to compile dbus
|
||||
DBUS_CFLAGS := @DBUS_CFLAGS@
|
||||
DBUS_FOUND := @DBUS_FOUND@
|
||||
|
||||
# Linux speechd a11y announcer
|
||||
A11Y_SPEECHD_ANNOUNCING_ENABLED:=@A11Y_SPEECHD_ANNOUNCING_ENABLED@
|
||||
SPEECHD_CFLAGS:=@SPEECHD_CFLAGS@
|
||||
|
||||
@@ -78,6 +78,10 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
#
|
||||
endif
|
||||
|
||||
ifeq ($(DBUS_FOUND), false)
|
||||
LIBAWT_EXFILES += dbus_interface.c dbus_interface.h
|
||||
endif
|
||||
|
||||
ifeq ($(call isTargetOs, linux macosx aix), true)
|
||||
LIBAWT_EXFILES += awt_Font.c CUPSfuncs.c fontpath.c X11Color.c
|
||||
endif
|
||||
@@ -111,6 +115,10 @@ LIBAWT_CFLAGS += -D__MEDIALIB_OLD_NAMES -D__USE_J2D_NAMES $(X_CFLAGS)
|
||||
|
||||
LIBAWT_CFLAGS += -DMLIB_NO_LIBSUNMATH
|
||||
|
||||
ifeq ($(DBUS_FOUND), true)
|
||||
LIBAWT_CFLAGS += -DDBUS_FOUND
|
||||
endif
|
||||
|
||||
ifeq ($(call isTargetOs, windows), true)
|
||||
LIBAWT_CFLAGS += -EHsc -DUNICODE -D_UNICODE
|
||||
ifeq ($(call isTargetCpuBits, 64), true)
|
||||
@@ -162,7 +170,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
|
||||
EXCLUDES := $(LIBAWT_EXCLUDES), \
|
||||
EXCLUDE_FILES := $(LIBAWT_EXFILES), \
|
||||
OPTIMIZATION := HIGHEST, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS), \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS) $(DBUS_CFLAGS), \
|
||||
EXTRA_HEADER_DIRS := $(LIBAWT_EXTRA_HEADER_DIRS), \
|
||||
DISABLED_WARNINGS_gcc_awt_LoadLibrary.c := unused-result, \
|
||||
DISABLED_WARNINGS_gcc_debug_mem.c := format-nonliteral, \
|
||||
@@ -313,7 +321,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
EXTRA_HEADER_DIRS := $(LIBAWT_XAWT_EXTRA_HEADER_DIRS), \
|
||||
EXCLUDES := $(LIBAWT_XAWT_EXCLUDES), \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) $(DBUS_CFLAGS) \
|
||||
$(X_CFLAGS), \
|
||||
WARNINGS_AS_ERRORS_xlc := false, \
|
||||
DISABLED_WARNINGS_gcc := int-to-pointer-cast, \
|
||||
@@ -571,7 +579,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
EXCLUDES := $(LIBAWT_HEADLESS_EXCLUDES), \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
$(LIBAWT_HEADLESS_CFLAGS), \
|
||||
$(LIBAWT_HEADLESS_CFLAGS) $(DBUS_CFLAGS), \
|
||||
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
|
||||
EXTRA_HEADER_DIRS := $(LIBAWT_HEADLESS_EXTRA_HEADER_DIRS), \
|
||||
DISABLED_WARNINGS_gcc_X11Renderer.c := unused-function, \
|
||||
@@ -663,8 +671,10 @@ else
|
||||
# noexcept-type required for GCC 7 builds. Not required for GCC 8+.
|
||||
# expansion-to-defined required for GCC 9 builds. Not required for GCC 10+.
|
||||
# maybe-uninitialized required for GCC 8 builds. Not required for GCC 9+.
|
||||
# calloc-transposed-args required for GCC 14 builds. (fixed upstream in Harfbuzz 032c931e1c0cfb20f18e5acb8ba005775242bd92)
|
||||
HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := class-memaccess noexcept-type \
|
||||
expansion-to-defined dangling-reference maybe-uninitialized
|
||||
expansion-to-defined dangling-reference maybe-uninitialized \
|
||||
calloc-transposed-args
|
||||
HARFBUZZ_DISABLED_WARNINGS_clang := missing-field-initializers range-loop-analysis
|
||||
HARFBUZZ_DISABLED_WARNINGS_microsoft := 4267 4244
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ ZActivatedArray<T>::ZActivatedArray(bool locked)
|
||||
_array() {}
|
||||
|
||||
template <typename T>
|
||||
ZActivatedArray<T>::~ZActivatedArray<T>() {
|
||||
ZActivatedArray<T>::~ZActivatedArray() {
|
||||
FreeHeap(_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ template <class T, MEMFLAGS F> class ChunkedList : public CHeapObj<F> {
|
||||
}
|
||||
|
||||
public:
|
||||
ChunkedList<T, F>() : _top(_values), _next_used(nullptr), _next_free(nullptr) {}
|
||||
ChunkedList() : _top(_values), _next_used(nullptr), _next_free(nullptr) {}
|
||||
|
||||
bool is_full() const {
|
||||
return _top == end();
|
||||
|
||||
@@ -99,7 +99,7 @@ template <class T> class EventLogBase : public EventLog {
|
||||
EventRecord<T>* _records;
|
||||
|
||||
public:
|
||||
EventLogBase<T>(const char* name, const char* handle, int length = LogEventsBufferEntries):
|
||||
EventLogBase(const char* name, const char* handle, int length = LogEventsBufferEntries):
|
||||
_mutex(Mutex::event, name),
|
||||
_name(name),
|
||||
_handle(handle),
|
||||
|
||||
@@ -118,7 +118,7 @@ class GrowableArrayView : public GrowableArrayBase {
|
||||
protected:
|
||||
E* _data; // data array
|
||||
|
||||
GrowableArrayView<E>(E* data, int capacity, int initial_len) :
|
||||
GrowableArrayView(E* data, int capacity, int initial_len) :
|
||||
GrowableArrayBase(capacity, initial_len), _data(data) {}
|
||||
|
||||
~GrowableArrayView() {}
|
||||
@@ -126,7 +126,7 @@ protected:
|
||||
public:
|
||||
const static GrowableArrayView EMPTY;
|
||||
|
||||
bool operator==(const GrowableArrayView<E>& rhs) const {
|
||||
bool operator==(const GrowableArrayView& rhs) const {
|
||||
if (_len != rhs._len)
|
||||
return false;
|
||||
for (int i = 0; i < _len; i++) {
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const GrowableArrayView<E>& rhs) const {
|
||||
bool operator!=(const GrowableArrayView& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ template <typename E>
|
||||
class GrowableArrayFromArray : public GrowableArrayView<E> {
|
||||
public:
|
||||
|
||||
GrowableArrayFromArray<E>(E* data, int len) :
|
||||
GrowableArrayFromArray(E* data, int len) :
|
||||
GrowableArrayView<E>(data, len, len) {}
|
||||
};
|
||||
|
||||
@@ -480,7 +480,7 @@ public:
|
||||
return this->at(location);
|
||||
}
|
||||
|
||||
void swap(GrowableArrayWithAllocator<E, Derived>* other) {
|
||||
void swap(GrowableArrayWithAllocator* other) {
|
||||
::swap(this->_data, other->_data);
|
||||
::swap(this->_len, other->_len);
|
||||
::swap(this->_capacity, other->_capacity);
|
||||
@@ -682,8 +682,8 @@ public:
|
||||
// See: init_checks.
|
||||
|
||||
template <typename E>
|
||||
class GrowableArray : public GrowableArrayWithAllocator<E, GrowableArray<E> > {
|
||||
friend class GrowableArrayWithAllocator<E, GrowableArray<E> >;
|
||||
class GrowableArray : public GrowableArrayWithAllocator<E, GrowableArray<E>> {
|
||||
friend class GrowableArrayWithAllocator<E, GrowableArray>;
|
||||
friend class GrowableArrayTest;
|
||||
|
||||
static E* allocate(int max) {
|
||||
@@ -731,7 +731,7 @@ public:
|
||||
GrowableArray() : GrowableArray(2 /* initial_capacity */) {}
|
||||
|
||||
explicit GrowableArray(int initial_capacity) :
|
||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||
GrowableArrayWithAllocator<E, GrowableArray>(
|
||||
allocate(initial_capacity),
|
||||
initial_capacity),
|
||||
_metadata() {
|
||||
@@ -739,7 +739,7 @@ public:
|
||||
}
|
||||
|
||||
GrowableArray(int initial_capacity, MEMFLAGS memflags) :
|
||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||
GrowableArrayWithAllocator<E, GrowableArray>(
|
||||
allocate(initial_capacity, memflags),
|
||||
initial_capacity),
|
||||
_metadata(memflags) {
|
||||
@@ -747,7 +747,7 @@ public:
|
||||
}
|
||||
|
||||
GrowableArray(int initial_capacity, int initial_len, const E& filler) :
|
||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||
GrowableArrayWithAllocator<E, GrowableArray>(
|
||||
allocate(initial_capacity),
|
||||
initial_capacity, initial_len, filler),
|
||||
_metadata() {
|
||||
@@ -755,7 +755,7 @@ public:
|
||||
}
|
||||
|
||||
GrowableArray(int initial_capacity, int initial_len, const E& filler, MEMFLAGS memflags) :
|
||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||
GrowableArrayWithAllocator<E, GrowableArray>(
|
||||
allocate(initial_capacity, memflags),
|
||||
initial_capacity, initial_len, filler),
|
||||
_metadata(memflags) {
|
||||
@@ -763,7 +763,7 @@ public:
|
||||
}
|
||||
|
||||
GrowableArray(Arena* arena, int initial_capacity, int initial_len, const E& filler) :
|
||||
GrowableArrayWithAllocator<E, GrowableArray<E> >(
|
||||
GrowableArrayWithAllocator<E, GrowableArray>(
|
||||
allocate(initial_capacity, arena),
|
||||
initial_capacity, initial_len, filler),
|
||||
_metadata(arena) {
|
||||
@@ -847,15 +847,15 @@ class GrowableArrayIterator : public StackObj {
|
||||
|
||||
public:
|
||||
GrowableArrayIterator() : _array(nullptr), _position(0) { }
|
||||
GrowableArrayIterator<E>& operator++() { ++_position; return *this; }
|
||||
E operator*() { return _array->at(_position); }
|
||||
GrowableArrayIterator& operator++() { ++_position; return *this; }
|
||||
E operator*() { return _array->at(_position); }
|
||||
|
||||
bool operator==(const GrowableArrayIterator<E>& rhs) {
|
||||
bool operator==(const GrowableArrayIterator& rhs) {
|
||||
assert(_array == rhs._array, "iterator belongs to different array");
|
||||
return _position == rhs._position;
|
||||
}
|
||||
|
||||
bool operator!=(const GrowableArrayIterator<E>& rhs) {
|
||||
bool operator!=(const GrowableArrayIterator& rhs) {
|
||||
assert(_array == rhs._array, "iterator belongs to different array");
|
||||
return _position != rhs._position;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ template <class E> class LinkedListNode : public AnyObj {
|
||||
template <class E> class LinkedList : public AnyObj {
|
||||
protected:
|
||||
LinkedListNode<E>* _head;
|
||||
NONCOPYABLE(LinkedList<E>);
|
||||
NONCOPYABLE(LinkedList);
|
||||
|
||||
public:
|
||||
LinkedList() : _head(nullptr) { }
|
||||
|
||||
@@ -194,6 +194,8 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
if ((m = s.await(e, ns, this, // spin if (nearly) empty
|
||||
p == null || p.waiter == null)) == e)
|
||||
unspliceLifo(s); // cancelled
|
||||
else if (m != null)
|
||||
s.selfLinkItem();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
101
src/java.desktop/linux/native/libawt/awt/dbus_interface.c
Normal file
101
src/java.desktop/linux/native/libawt/awt/dbus_interface.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 "dbus_interface.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "jvm_md.h"
|
||||
|
||||
#define DBUS_LIB JNI_LIB_NAME("dbus-1")
|
||||
#define DBUS_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("dbus-1", "3")
|
||||
|
||||
static bool isCurrentVersionSupported(DBusApi* dBusApi) {
|
||||
int major = 0, minor = 0, micro = 0;
|
||||
dBusApi->dbus_get_version(&major, &minor, µ);
|
||||
return major == 1;
|
||||
}
|
||||
|
||||
static bool DBusApi_init(DBusApi* dBusApi, void *libhandle) {
|
||||
dBusApi->dbus_get_version = dlsym(libhandle, "dbus_get_version");
|
||||
if (dBusApi->dbus_get_version == NULL || !isCurrentVersionSupported(dBusApi)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dBusApi->dbus_error_init = dlsym(libhandle, "dbus_error_init");
|
||||
dBusApi->dbus_bus_get = dlsym(libhandle, "dbus_bus_get");
|
||||
dBusApi->dbus_error_is_set = dlsym(libhandle, "dbus_error_is_set");
|
||||
dBusApi->dbus_bus_request_name = dlsym(libhandle, "dbus_bus_request_name");
|
||||
dBusApi->dbus_connection_flush = dlsym(libhandle, "dbus_connection_flush");
|
||||
dBusApi->dbus_message_new_method_call = dlsym(libhandle, "dbus_message_new_method_call");
|
||||
dBusApi->dbus_message_set_destination = dlsym(libhandle, "dbus_message_set_destination");
|
||||
dBusApi->dbus_message_iter_init_append = dlsym(libhandle, "dbus_message_iter_init_append");
|
||||
dBusApi->dbus_message_iter_append_basic = dlsym(libhandle, "dbus_message_iter_append_basic");
|
||||
dBusApi->dbus_connection_send_with_reply_and_block = dlsym(libhandle, "dbus_connection_send_with_reply_and_block");
|
||||
dBusApi->dbus_message_iter_init = dlsym(libhandle, "dbus_message_iter_init");
|
||||
dBusApi->dbus_message_iter_get_arg_type = dlsym(libhandle, "dbus_message_iter_get_arg_type");
|
||||
dBusApi->dbus_message_iter_get_basic = dlsym(libhandle, "dbus_message_iter_get_basic");
|
||||
dBusApi->dbus_message_iter_recurse = dlsym(libhandle, "dbus_message_iter_recurse");
|
||||
dBusApi->dbus_message_iter_next = dlsym(libhandle, "dbus_message_iter_next");
|
||||
dBusApi->dbus_message_unref = dlsym(libhandle, "dbus_message_unref");
|
||||
dBusApi->dbus_error_free = dlsym(libhandle, "dbus_error_free");
|
||||
|
||||
return dBusApi->dbus_error_init != NULL && dBusApi->dbus_bus_get != NULL && dBusApi->dbus_error_is_set != NULL &&
|
||||
dBusApi->dbus_bus_request_name != NULL && dBusApi->dbus_connection_flush != NULL &&
|
||||
dBusApi->dbus_message_set_destination != NULL && dBusApi->dbus_message_iter_init_append != NULL &&
|
||||
dBusApi->dbus_message_iter_append_basic != NULL && dBusApi->dbus_connection_send_with_reply_and_block != NULL &&
|
||||
dBusApi->dbus_message_iter_init != NULL && dBusApi->dbus_message_iter_get_arg_type != NULL &&
|
||||
dBusApi->dbus_message_iter_get_basic != NULL && dBusApi->dbus_message_iter_recurse != NULL &&
|
||||
dBusApi->dbus_message_iter_next != NULL && dBusApi->dbus_message_unref != NULL &&
|
||||
dBusApi->dbus_message_new_method_call != NULL && dBusApi->dbus_error_free != NULL;
|
||||
}
|
||||
|
||||
DBusApi* DBusApi_setupDBus(void *libhandle) {
|
||||
DBusApi *dBusApi = (DBusApi*)malloc(sizeof(DBusApi));
|
||||
if (dBusApi == NULL || !DBusApi_init(dBusApi, libhandle)) {
|
||||
free(dBusApi);
|
||||
dBusApi = NULL;
|
||||
}
|
||||
|
||||
return dBusApi;
|
||||
}
|
||||
|
||||
DBusApi* DBusApi_setupDBusDefault() {
|
||||
void *dbus_libhandle = dlopen(DBUS_LIB, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (dbus_libhandle == NULL) {
|
||||
dbus_libhandle = dlopen(DBUS_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (dbus_libhandle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return DBusApi_setupDBus(dbus_libhandle);
|
||||
}
|
||||
76
src/java.desktop/linux/native/libawt/awt/dbus_interface.h
Normal file
76
src/java.desktop/linux/native/libawt/awt/dbus_interface.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 JETBRAINSRUNTIME_DBUS_INTERFACE_H
|
||||
#define JETBRAINSRUNTIME_DBUS_INTERFACE_H
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
typedef struct DBusApi {
|
||||
void (*dbus_get_version)(int *major_version_p, int *minor_version_p, int *micro_version_p);
|
||||
|
||||
void (*dbus_error_init)(DBusError *error);
|
||||
|
||||
DBusConnection *(*dbus_bus_get)(DBusBusType type, DBusError *error);
|
||||
|
||||
dbus_bool_t (*dbus_error_is_set)(const DBusError *error);
|
||||
|
||||
void (*dbus_error_free)(DBusError *error);
|
||||
|
||||
int (*dbus_bus_request_name)(DBusConnection *connection, const char *name, unsigned int flags, DBusError *error);
|
||||
|
||||
void (*dbus_connection_flush)(DBusConnection *connection);
|
||||
|
||||
DBusMessage* (*dbus_message_new_method_call)(const char *bus_name, const char *path,
|
||||
const char *iface, const char *method);
|
||||
|
||||
dbus_bool_t (*dbus_message_set_destination)(DBusMessage *message, const char *destination);
|
||||
|
||||
void (*dbus_message_iter_init_append)(DBusMessage *message, DBusMessageIter *iter);
|
||||
|
||||
dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter *iter, int type, const void *value);
|
||||
|
||||
DBusMessage *(*dbus_connection_send_with_reply_and_block)(DBusConnection *connection, DBusMessage *message,
|
||||
int timeout_milliseconds, DBusError *error);
|
||||
|
||||
dbus_bool_t (*dbus_message_iter_init)(DBusMessage *message, DBusMessageIter *iter);
|
||||
|
||||
int (*dbus_message_iter_get_arg_type)(DBusMessageIter *iter);
|
||||
|
||||
void (*dbus_message_iter_get_basic)(DBusMessageIter *iter, void *value);
|
||||
|
||||
void (*dbus_message_iter_recurse)(DBusMessageIter *iter, DBusMessageIter *sub);
|
||||
|
||||
dbus_bool_t (*dbus_message_iter_next)(DBusMessageIter *iter);
|
||||
|
||||
void (*dbus_message_unref)(DBusMessage *message);
|
||||
} DBusApi;
|
||||
|
||||
DBusApi* DBusApi_setupDBus(void *libhandle);
|
||||
DBusApi* DBusApi_setupDBusDefault();
|
||||
|
||||
#endif //JETBRAINSRUNTIME_DBUS_INTERFACE_H
|
||||
265
src/java.desktop/linux/native/libawt/awt/system_properties.c
Normal file
265
src/java.desktop/linux/native/libawt/awt/system_properties.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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 "system_properties.h"
|
||||
|
||||
#ifdef DBUS_FOUND
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define UNKNOWN_RESULT -1
|
||||
#define SETTING_INTERFACE "org.freedesktop.portal.Settings"
|
||||
#define SETTING_INTERFACE_METHOD "Read"
|
||||
#define DESKTOP_DESTINATION "org.freedesktop.portal.Desktop"
|
||||
#define DESKTOP_PATH "/org/freedesktop/portal/desktop"
|
||||
#define REPLY_TIMEOUT 150
|
||||
|
||||
static DBusConnection *connection = NULL;
|
||||
static JNIEnv *env = NULL;
|
||||
static DBusApi *dBus = NULL;
|
||||
static DBusMessage *msg_freedesktop_appearance = NULL;
|
||||
static DBusMessage *msg_gnome_desktop = NULL;
|
||||
static bool initialized = false;
|
||||
static bool logEnabled = true;
|
||||
extern JavaVM *jvm;
|
||||
|
||||
static void printError(const char* fmt, ...) {
|
||||
if (!logEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
char* buf = (char*)malloc(1024);
|
||||
|
||||
if (env && buf) {
|
||||
va_list vargs;
|
||||
va_start(vargs, fmt);
|
||||
vsnprintf(buf, 1024, fmt, vargs);
|
||||
jstring text = JNU_NewStringPlatform(env, buf);
|
||||
free(buf);
|
||||
va_end(vargs);
|
||||
|
||||
jboolean ignoreException;
|
||||
JNU_CallStaticMethodByName(env, &ignoreException, "sun/awt/UNIXToolkit", "printError",
|
||||
"(Ljava/lang/String;)V", text);
|
||||
}
|
||||
}
|
||||
|
||||
static bool dbusCheckError(DBusError *err, const char *msg) {
|
||||
bool is_error_set = dBus->dbus_error_is_set(err);
|
||||
if (is_error_set) {
|
||||
printError("DBus error: %s. %s\n", msg, err->message);
|
||||
dBus->dbus_error_free(err);
|
||||
}
|
||||
return is_error_set;
|
||||
}
|
||||
|
||||
// current implementation of object decomposition supports only
|
||||
// primitive types (including a recursive type wrapper)
|
||||
static bool decomposeDBusReply(void *val, DBusMessageIter *iter, int demand_type) {
|
||||
int cur_type = dBus->dbus_message_iter_get_arg_type(iter);
|
||||
switch (cur_type)
|
||||
{
|
||||
case DBUS_TYPE_INT16:
|
||||
case DBUS_TYPE_UINT16:
|
||||
case DBUS_TYPE_INT32:
|
||||
case DBUS_TYPE_UINT32:
|
||||
case DBUS_TYPE_INT64:
|
||||
case DBUS_TYPE_UINT64:
|
||||
case DBUS_TYPE_STRING:
|
||||
{
|
||||
if (cur_type != demand_type) {
|
||||
return false;
|
||||
}
|
||||
dBus->dbus_message_iter_get_basic(iter, val);
|
||||
return true;
|
||||
}
|
||||
case DBUS_TYPE_VARIANT:
|
||||
{
|
||||
DBusMessageIter unwrap_iter;
|
||||
dBus->dbus_message_iter_recurse(iter, &unwrap_iter);
|
||||
bool res = decomposeDBusReply(val, &unwrap_iter, demand_type);
|
||||
// current implementation doesn't support types with multiple fields
|
||||
if (dBus->dbus_message_iter_next(iter)) {
|
||||
return false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
case DBUS_TYPE_INVALID:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *createDBusMessage(const char *messages[], int message_count) {
|
||||
DBusMessage *msg = NULL;
|
||||
DBusMessageIter msg_iter;
|
||||
|
||||
if ((msg = dBus->dbus_message_new_method_call(NULL, DESKTOP_PATH, SETTING_INTERFACE, SETTING_INTERFACE_METHOD)) == NULL) {
|
||||
printError("DBus error: cannot allocate message\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!dBus->dbus_message_set_destination(msg, DESKTOP_DESTINATION)) {
|
||||
printError("DBus error: cannot set destination\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
dBus->dbus_message_iter_init_append(msg, &msg_iter);
|
||||
|
||||
for (int i = 0; i < message_count; i++) {
|
||||
if (!dBus->dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &messages[i])) {
|
||||
printError("DBus error: cannot append to message\n");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
cleanup:
|
||||
if (msg) {
|
||||
dBus->dbus_message_unref(msg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool sendDBusMessageWithReply(DBusMessage *msg, void *val, int demand_type) {
|
||||
DBusError error;
|
||||
DBusMessage *msg_reply = NULL;
|
||||
DBusMessageIter msg_iter;
|
||||
bool res = false;
|
||||
|
||||
dBus->dbus_error_init(&error);
|
||||
if ((msg_reply = dBus->dbus_connection_send_with_reply_and_block(connection, msg, REPLY_TIMEOUT, &error)) == NULL) {
|
||||
printError("DBus error: cannot get msg_reply or sent message. %s\n", dBus->dbus_error_is_set(&error) ? error.message : "");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!dBus->dbus_message_iter_init(msg_reply, &msg_iter)) {
|
||||
printError("DBus error: cannot process message\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
res = decomposeDBusReply(val, &msg_iter, demand_type);
|
||||
cleanup:
|
||||
if (msg_reply) {
|
||||
dBus->dbus_message_unref(msg_reply);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_sun_awt_UNIXToolkit_isSystemDarkColorScheme() {
|
||||
static int use_freedesktop_appearance = -1;
|
||||
if (!initialized) {
|
||||
return UNKNOWN_RESULT;
|
||||
}
|
||||
|
||||
if (use_freedesktop_appearance == -1) {
|
||||
unsigned int res = 0;
|
||||
logEnabled = false;
|
||||
use_freedesktop_appearance =
|
||||
sendDBusMessageWithReply(msg_freedesktop_appearance, &res, DBUS_TYPE_UINT32);
|
||||
logEnabled = true;
|
||||
}
|
||||
|
||||
if (use_freedesktop_appearance) {
|
||||
unsigned int res = 0;
|
||||
if (!sendDBusMessageWithReply(msg_freedesktop_appearance, &res, DBUS_TYPE_UINT32)) {
|
||||
return UNKNOWN_RESULT;
|
||||
}
|
||||
/* From org.freedesktop.portal color-scheme specs:
|
||||
* 0: No preference, 1: Prefer dark appearance, 2: Prefer light appearance
|
||||
*/
|
||||
return res == 1;
|
||||
} else {
|
||||
char *res = NULL;
|
||||
if (!sendDBusMessageWithReply(msg_gnome_desktop, &res, DBUS_TYPE_STRING)) {
|
||||
return UNKNOWN_RESULT;
|
||||
}
|
||||
return (res != NULL) ? strstr(res, "dark") != NULL : UNKNOWN_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
jboolean SystemProperties_setup(DBusApi *dBus_, JNIEnv *env_) {
|
||||
env = env_;
|
||||
dBus = dBus_;
|
||||
DBusError err;
|
||||
int ret;
|
||||
|
||||
dBus->dbus_error_init(&err);
|
||||
if ((connection = dBus->dbus_bus_get(DBUS_BUS_SESSION, &err)) == NULL) {
|
||||
printError("DBus error: connection is Null\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (dbusCheckError(&err, "connection error")) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ret = dBus->dbus_bus_request_name(connection, "dbus.JBR.server", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
|
||||
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER && ret != DBUS_REQUEST_NAME_REPLY_IN_QUEUE) {
|
||||
printError("DBus error: Failed to acquire service name \n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (dbusCheckError(&err, "error request 'dbus.JBR.server' name on the bus")) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
dBus->dbus_connection_flush(connection);
|
||||
|
||||
const char *freedesktop_appearance_messages[] = {"org.freedesktop.appearance", "color-scheme"};
|
||||
const char *gnome_desktop_messages[] = {"org.gnome.desktop.interface", "gtk-theme"};
|
||||
msg_freedesktop_appearance = createDBusMessage(freedesktop_appearance_messages, 2);
|
||||
msg_gnome_desktop = createDBusMessage(gnome_desktop_messages, 2);
|
||||
if (msg_freedesktop_appearance == NULL || msg_gnome_desktop == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_sun_awt_UNIXToolkit_dbusInit() {
|
||||
DBusApi *dBus = DBusApi_setupDBusDefault();
|
||||
if (dBus) {
|
||||
return SystemProperties_setup(dBus, env);
|
||||
}
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
JNIEXPORT jint JNICALL Java_sun_awt_UNIXToolkit_isSystemDarkColorScheme() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_sun_awt_UNIXToolkit_dbusInit() {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -24,19 +25,20 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef VKPipeline_h_Included
|
||||
#define VKPipeline_h_Included
|
||||
#ifndef JETBRAINSRUNTIME_SYSTEM_PROPERTIES_H
|
||||
#define JETBRAINSRUNTIME_SYSTEM_PROPERTIES_H
|
||||
|
||||
#include "VKShader.h"
|
||||
#include <stdbool.h>
|
||||
#include <jni.h>
|
||||
#include <jni_util.h>
|
||||
|
||||
struct VKPipelines {
|
||||
VKShaders shaders;
|
||||
// TODO we need a pool of pipelines and (optionally) render passes for different formats.
|
||||
vk::raii::RenderPass renderPass = nullptr; // Render pass is only needed if dynamic rendering is off.
|
||||
vk::raii::PipelineLayout testLayout = nullptr;
|
||||
vk::raii::Pipeline test = nullptr;
|
||||
#ifdef DBUS_FOUND
|
||||
|
||||
void init(const vk::raii::Device& device, bool dynamicRendering);
|
||||
};
|
||||
#include "dbus_interface.h"
|
||||
|
||||
#endif //VKPipeline_h_Included
|
||||
jboolean SystemProperties_setup(DBusApi *dBus_, JNIEnv *env_);
|
||||
void SystemProperties_pullEvent(void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif //JETBRAINSRUNTIME_SYSTEM_PROPERTIES_H
|
||||
@@ -218,7 +218,7 @@ MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
jdk_message = (MidiMessage*) calloc(sizeof(MidiMessage), 1);
|
||||
jdk_message = (MidiMessage*) calloc(1, sizeof(MidiMessage));
|
||||
if (!jdk_message) {
|
||||
ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n");
|
||||
return NULL;
|
||||
|
||||
@@ -383,7 +383,7 @@ INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex,
|
||||
|
||||
TRACE0("> openMidiDevice()\n");
|
||||
|
||||
(*handle) = (MidiDeviceHandle*) calloc(sizeof(MidiDeviceHandle), 1);
|
||||
(*handle) = (MidiDeviceHandle*) calloc(1, sizeof(MidiDeviceHandle));
|
||||
if (!(*handle)) {
|
||||
ERROR0("ERROR: openDevice: out of memory\n");
|
||||
return MIDI_OUT_OF_MEMORY;
|
||||
|
||||
@@ -159,6 +159,12 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
/* Populate the device table */
|
||||
rebuildDevices();
|
||||
|
||||
if (LogDisplay.ENABLED) {
|
||||
for (CGraphicsDevice gd : devices.values()) {
|
||||
LogDisplay.ADDED.log(gd.getDisplayID(), gd.getBounds(), gd.getScaleFactor());
|
||||
}
|
||||
}
|
||||
|
||||
/* Register our display reconfiguration listener */
|
||||
displayReconfigContext = registerDisplayReconfiguration();
|
||||
if (displayReconfigContext == 0L) {
|
||||
@@ -185,13 +191,25 @@ public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
* @param displayId CoreGraphics displayId
|
||||
* @param removed true if displayId was removed, false otherwise.
|
||||
*/
|
||||
void _displayReconfiguration(int displayId, boolean removed) {
|
||||
void _displayReconfiguration(int displayId, int flags) {
|
||||
// See CGDisplayChangeSummaryFlags
|
||||
LogDisplay log = !LogDisplay.ENABLED ? null :
|
||||
(flags & (1 << 4)) != 0 ? LogDisplay.ADDED :
|
||||
(flags & (1 << 5)) != 0 ? LogDisplay.REMOVED : LogDisplay.CHANGED;
|
||||
if (log == LogDisplay.REMOVED) {
|
||||
CGraphicsDevice gd = devices.get(displayId);
|
||||
log.log(displayId, gd != null ? gd.getBounds() : "UNKNOWN", gd != null ? gd.getScaleFactor() : Double.NaN);
|
||||
}
|
||||
// we ignore the passed parameters and check removed devices ourself
|
||||
// Note that it is possible that this callback is called when the
|
||||
// monitors are not added nor removed, but when the video card is
|
||||
// switched to/from the discrete video card, so we should try to map the
|
||||
// old to the new devices.
|
||||
rebuildDevices();
|
||||
if (log != null && log != LogDisplay.REMOVED) {
|
||||
CGraphicsDevice gd = devices.get(displayId);
|
||||
log.log(displayId, gd != null ? gd.getBounds() : "UNKNOWN", gd != null ? gd.getScaleFactor() : Double.NaN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -515,25 +515,23 @@ public class CInputMethod extends InputMethodAdapter {
|
||||
fCurrentText.addAttribute(TextAttribute.INPUT_METHOD_HIGHLIGHT, theHighlight, begin, end);
|
||||
}
|
||||
|
||||
/* Called from JNI to select the previously typed glyph during press and hold */
|
||||
private void selectPreviousGlyph() {
|
||||
if (fIMContext == null || fAwtFocussedComponent == null) return; // ???
|
||||
private void selectRange(int selectionStart, int length) {
|
||||
if (fIMContext == null || fAwtFocussedComponent == null) {
|
||||
return;
|
||||
}
|
||||
final int selectionEnd = selectionStart + length;
|
||||
try {
|
||||
LWCToolkit.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
final int offset = fIMContext.getInsertPositionOffset();
|
||||
if (offset < 1) return; // ???
|
||||
|
||||
if (fAwtFocussedComponent instanceof JTextComponent) {
|
||||
((JTextComponent) fAwtFocussedComponent).select(offset - 1, offset);
|
||||
((JTextComponent) fAwtFocussedComponent).select(selectionStart, selectionEnd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fAwtFocussedComponent instanceof TextComponent) {
|
||||
((TextComponent) fAwtFocussedComponent).select(offset - 1, offset);
|
||||
((TextComponent) fAwtFocussedComponent).select(selectionStart, selectionEnd);
|
||||
return;
|
||||
}
|
||||
// TODO: Ideally we want to disable press-and-hold in this case
|
||||
}
|
||||
}, fAwtFocussedComponent);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -60,7 +60,6 @@ static unichar lastCtrlCombo;
|
||||
|
||||
// Uncomment this line to see fprintfs of each InputMethod API being called on this View
|
||||
//#define IM_DEBUG TRUE
|
||||
//#define EXTRA_DEBUG
|
||||
//#define LOG_KEY_EVENTS
|
||||
|
||||
static BOOL shouldUsePressAndHold() {
|
||||
@@ -95,7 +94,6 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, i
|
||||
|
||||
fEnablePressAndHold = shouldUsePressAndHold();
|
||||
fInPressAndHold = NO;
|
||||
fPAHNeedsToSelect = NO;
|
||||
|
||||
mouseIsOver = NO;
|
||||
[self resetTrackingArea];
|
||||
@@ -365,6 +363,8 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
fprintf(stderr, "\tmodifierFlags: 0x%08x\n", (unsigned)[event modifierFlags]);
|
||||
TISInputSourceRef is = TISCopyCurrentKeyboardLayoutInputSource();
|
||||
fprintf(stderr, "\tTISCopyCurrentKeyboardLayoutInputSource: %s\n", is == nil ? "(nil)" : [(NSString*) TISGetInputSourceProperty(is, kTISPropertyInputSourceID) UTF8String]);
|
||||
fprintf(stderr, "\twillBeHandledByComplexInputMethod: %s\n", [event willBeHandledByComplexInputMethod] ? "true" : "false");
|
||||
CFRelease(is);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -376,6 +376,7 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
fKeyEventsNeeded = YES;
|
||||
|
||||
NSString *eventCharacters = [event characters];
|
||||
unsigned mods = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||
|
||||
if (([event modifierFlags] & NSControlKeyMask) && [eventCharacters length] == 1) {
|
||||
lastCtrlCombo = [eventCharacters characterAtIndex:0];
|
||||
@@ -395,7 +396,6 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
|
||||
fProcessingKeystroke = NO;
|
||||
if (!fInPressAndHold) {
|
||||
fInPressAndHold = YES;
|
||||
fPAHNeedsToSelect = YES;
|
||||
} else {
|
||||
// Abandon input to reset IM and unblock input after canceling
|
||||
// input accented symbols
|
||||
@@ -1157,7 +1157,9 @@ static jclass jc_CInputMethod = NULL;
|
||||
- (void) insertText:(id)aString replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
#ifdef IM_DEBUG
|
||||
fprintf(stderr, "AWTView InputMethod Selector Called : [insertText]: %s\n", [aString UTF8String]);
|
||||
fprintf(stderr,
|
||||
"AWTView InputMethod Selector Called : [insertText]: %s, replacementRange: location=%lu, length=%lu\n",
|
||||
[aString UTF8String], replacementRange.location, replacementRange.length);
|
||||
#endif // IM_DEBUG
|
||||
|
||||
NSMutableString * useString = [self parseString:aString];
|
||||
@@ -1195,12 +1197,12 @@ static jclass jc_CInputMethod = NULL;
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
GET_CIM_CLASS();
|
||||
// We need to select the previous glyph so that it is overwritten.
|
||||
if (fPAHNeedsToSelect) {
|
||||
DECLARE_METHOD(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V");
|
||||
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_selectPreviousGlyph);
|
||||
|
||||
if (replacementRange.length > 0) {
|
||||
DECLARE_METHOD(jm_selectRange, jc_CInputMethod, "selectRange", "(II)V");
|
||||
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_selectRange, replacementRange.location,
|
||||
replacementRange.length);
|
||||
CHECK_EXCEPTION();
|
||||
fPAHNeedsToSelect = NO;
|
||||
}
|
||||
|
||||
if (usingComplexIM) {
|
||||
@@ -1217,7 +1219,6 @@ static jclass jc_CInputMethod = NULL;
|
||||
actualCharacters = [useString copy];
|
||||
fKeyEventsNeeded = YES;
|
||||
}
|
||||
fPAHNeedsToSelect = NO;
|
||||
|
||||
// Abandon input to reset IM and unblock input after entering accented
|
||||
// symbols
|
||||
@@ -1256,7 +1257,9 @@ static jclass jc_CInputMethod = NULL;
|
||||
NSAttributedString *attrString = (isAttributedString ? (NSAttributedString *)aString : nil);
|
||||
NSString *incomingString = (isAttributedString ? [aString string] : aString);
|
||||
#ifdef IM_DEBUG
|
||||
fprintf(stderr, "AWTView InputMethod Selector Called : [setMarkedText] \"%s\", loc=%lu, length=%lu\n", [incomingString UTF8String], (unsigned long)selectionRange.location, (unsigned long)selectionRange.length);
|
||||
fprintf(stderr, "AWTView InputMethod Selector Called :[setMarkedText] \"%s\","
|
||||
"selectionRange(%lu, %lu), replacementRange(%lu, %lu)\n", [incomingString UTF8String],
|
||||
selectionRange.location, selectionRange.length, replacementRange.location, replacementRange.length);
|
||||
#endif // IM_DEBUG
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
GET_CIM_CLASS();
|
||||
@@ -1264,6 +1267,14 @@ static jclass jc_CInputMethod = NULL;
|
||||
DECLARE_METHOD(jm_addAttribute, jc_CInputMethod, "addAttribute", "(ZZII)V");
|
||||
DECLARE_METHOD(jm_dispatchText, jc_CInputMethod, "dispatchText", "(IIZ)V");
|
||||
|
||||
if (replacementRange.length > 0) {
|
||||
DECLARE_METHOD(jm_selectRange, jc_CInputMethod, "selectRange", "(II)V");
|
||||
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_selectRange, replacementRange.location,
|
||||
replacementRange.length);
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
|
||||
// NSInputContext already did the analysis of the TSM event and created attributes indicating
|
||||
// the underlining and color that should be done to the string. We need to look at the underline
|
||||
// style and color to determine what kind of Java highlighting needs to be done.
|
||||
@@ -1299,14 +1310,6 @@ static jclass jc_CInputMethod = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_METHOD(jm_selectPreviousGlyph, jc_CInputMethod, "selectPreviousGlyph", "()V");
|
||||
// We need to select the previous glyph so that it is overwritten.
|
||||
if (fPAHNeedsToSelect) {
|
||||
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_selectPreviousGlyph);
|
||||
CHECK_EXCEPTION();
|
||||
fPAHNeedsToSelect = NO;
|
||||
}
|
||||
|
||||
(*env)->CallVoidMethod(env, fInputMethodLOCKABLE, jm_dispatchText,
|
||||
selectionRange.location, selectionRange.length, JNI_FALSE);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
@@ -122,9 +122,9 @@ static void displaycb_handle
|
||||
if (graphicsEnv == NULL) return; // ref already GC'd
|
||||
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
|
||||
DECLARE_METHOD(jm_displayReconfiguration,
|
||||
jc_CGraphicsEnvironment, "_displayReconfiguration","(IZ)V");
|
||||
jc_CGraphicsEnvironment, "_displayReconfiguration","(II)V");
|
||||
(*env)->CallVoidMethod(env, graphicsEnv, jm_displayReconfiguration,
|
||||
(jint) display, (jboolean) flags & kCGDisplayRemoveFlag);
|
||||
(jint) display, (jint) flags);
|
||||
(*env)->DeleteLocalRef(env, graphicsEnv);
|
||||
CHECK_EXCEPTION();
|
||||
}];
|
||||
|
||||
@@ -660,19 +660,17 @@ MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
int ry = ginfo->subpixelResolutionY;
|
||||
ADJUST_SUBPIXEL_GLYPH_POSITION(glyphx, rx);
|
||||
ADJUST_SUBPIXEL_GLYPH_POSITION(glyphy, ry);
|
||||
int subx = 0, suby = 0;
|
||||
// see DrawGlyphList.c FLOOR_ASSIGN & getSubpixelGlyphImage
|
||||
if (glyphx >= 0.0f && glyphy >= 0.0f) {
|
||||
x = (int) glyphx;
|
||||
y = (int) glyphy;
|
||||
subx = ((int) (glyphx * (float) rx)) % rx;
|
||||
suby = ((int) (glyphy * (float) ry)) % ry;
|
||||
float fx = floor(glyphx);
|
||||
float fy = floor(glyphy);
|
||||
x = (int) fx;
|
||||
y = (int) fy;
|
||||
int subimage;
|
||||
if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
|
||||
subimage = 0;
|
||||
} else {
|
||||
float fx = floor(glyphx), fy = floor(glyphy);
|
||||
x = (int) fx;
|
||||
y = (int) fy;
|
||||
subx = (int) ((glyphx - fx) * (float) rx);
|
||||
suby = (int) ((glyphy - fy) * (float) ry);
|
||||
int subx = (int) ((glyphx - fx) * (float) rx);
|
||||
int suby = (int) ((glyphy - fy) * (float) ry);
|
||||
subimage = subx + suby * rx;
|
||||
}
|
||||
|
||||
if (ginfo->image == NULL) {
|
||||
@@ -684,12 +682,6 @@ MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
J2dTraceLn1(J2D_TRACE_INFO, "rowBytes = %d", ginfo->rowBytes);
|
||||
if (ginfo->format == sun_font_StrikeCache_PIXEL_FORMAT_GREYSCALE) {
|
||||
// grayscale or monochrome glyph data
|
||||
int subimage;
|
||||
if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
|
||||
subimage = 0;
|
||||
} else {
|
||||
subimage = subx + suby * rx;
|
||||
}
|
||||
if (ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
|
||||
ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)
|
||||
{
|
||||
|
||||
@@ -410,6 +410,7 @@ public class Window extends Container implements Accessible {
|
||||
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.Window");
|
||||
private static final PlatformLogger focusRequestLog = PlatformLogger.getLogger("jb.focus.requests");
|
||||
private static final PlatformLogger perfLog = PlatformLogger.getLogger("awt.window.counters");
|
||||
|
||||
private static final boolean locationByPlatformProp;
|
||||
|
||||
@@ -4459,6 +4460,10 @@ public class Window extends Container implements Accessible {
|
||||
}
|
||||
|
||||
static {
|
||||
@SuppressWarnings("removal")
|
||||
String counters = AccessController.doPrivileged(
|
||||
new GetPropertyAction("awt.window.counters"));
|
||||
|
||||
AWTAccessor.setWindowAccessor(new AWTAccessor.WindowAccessor() {
|
||||
public void updateWindow(Window window) {
|
||||
window.updateWindow();
|
||||
@@ -4503,6 +4508,92 @@ public class Window extends Container implements Accessible {
|
||||
public Window[] getOwnedWindows(Window w) {
|
||||
return w.getOwnedWindows_NoClientCode();
|
||||
}
|
||||
|
||||
public boolean countersEnabled(Window w) {
|
||||
// May want to selectively enable or disable counters per window
|
||||
return counters != null;
|
||||
}
|
||||
|
||||
public void bumpCounter(Window w, String counterName) {
|
||||
Objects.requireNonNull(w);
|
||||
Objects.requireNonNull(counterName);
|
||||
|
||||
PerfCounter newCounter;
|
||||
long curTimeNanos = System.nanoTime();
|
||||
synchronized (w.perfCounters) {
|
||||
newCounter = w.perfCounters.compute(counterName, (k, v) ->
|
||||
v == null
|
||||
? new PerfCounter(curTimeNanos, 1L)
|
||||
: new PerfCounter(curTimeNanos, v.value + 1));
|
||||
}
|
||||
PerfCounter prevCounter;
|
||||
synchronized (w.perfCountersPrev) {
|
||||
prevCounter = w.perfCountersPrev.putIfAbsent(counterName, newCounter);
|
||||
}
|
||||
if (prevCounter != null) {
|
||||
long nanosInSecond = java.util.concurrent.TimeUnit.SECONDS.toNanos(1);
|
||||
long timeDeltaNanos = curTimeNanos - prevCounter.updateTimeNanos;
|
||||
if (timeDeltaNanos > nanosInSecond) {
|
||||
long valPerSecond = (long) ((double) (newCounter.value - prevCounter.value)
|
||||
* nanosInSecond / timeDeltaNanos);
|
||||
boolean traceAllCounters = Objects.equals(counters, "")
|
||||
|| Objects.equals(counters, "stdout")
|
||||
|| Objects.equals(counters, "stderr");
|
||||
boolean traceEnabled = traceAllCounters || (counters != null && counters.contains(counterName));
|
||||
if (traceEnabled) {
|
||||
if (counters.contains("stderr")) {
|
||||
System.err.println(counterName + " per second: " + valPerSecond);
|
||||
} else {
|
||||
System.out.println(counterName + " per second: " + valPerSecond);
|
||||
}
|
||||
}
|
||||
if (perfLog.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
perfLog.fine(counterName + " per second: " + valPerSecond);
|
||||
}
|
||||
synchronized (w.perfCountersPrev) {
|
||||
w.perfCountersPrev.put(counterName, newCounter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long getCounter(Window w, String counterName) {
|
||||
Objects.requireNonNull(w);
|
||||
Objects.requireNonNull(counterName);
|
||||
|
||||
synchronized (w.perfCounters) {
|
||||
PerfCounter counter = w.perfCounters.get(counterName);
|
||||
return counter != null ? counter.value : -1L;
|
||||
}
|
||||
}
|
||||
|
||||
public long getCounterPerSecond(Window w, String counterName) {
|
||||
Objects.requireNonNull(w);
|
||||
Objects.requireNonNull(counterName);
|
||||
|
||||
PerfCounter newCounter;
|
||||
PerfCounter prevCounter;
|
||||
|
||||
synchronized (w.perfCounters) {
|
||||
newCounter = w.perfCounters.get(counterName);
|
||||
}
|
||||
|
||||
synchronized (w.perfCountersPrev) {
|
||||
prevCounter = w.perfCountersPrev.get(counterName);
|
||||
}
|
||||
|
||||
if (newCounter != null && prevCounter != null) {
|
||||
long timeDeltaNanos = newCounter.updateTimeNanos - prevCounter.updateTimeNanos;
|
||||
// Note that this time delta will usually be above one second.
|
||||
if (timeDeltaNanos > 0) {
|
||||
long nanosInSecond = java.util.concurrent.TimeUnit.SECONDS.toNanos(1);
|
||||
long valPerSecond = (long) ((double) (newCounter.value - prevCounter.value)
|
||||
* nanosInSecond / timeDeltaNanos);
|
||||
return valPerSecond;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}); // WindowAccessor
|
||||
} // static
|
||||
|
||||
@@ -4510,6 +4601,11 @@ public class Window extends Container implements Accessible {
|
||||
@Override
|
||||
void updateZOrder() {}
|
||||
|
||||
private record PerfCounter(Long updateTimeNanos, Long value) {}
|
||||
|
||||
private transient final Map<String, PerfCounter> perfCounters = new HashMap<>(4);
|
||||
private transient final Map<String, PerfCounter> perfCountersPrev = new HashMap<>(4);
|
||||
|
||||
} // class Window
|
||||
|
||||
|
||||
|
||||
@@ -4996,9 +4996,15 @@ public class JTree extends JComponent implements Scrollable, Accessible
|
||||
if (treeModel != null) {
|
||||
index = treeModel.getIndexOfChild(objParent, obj);
|
||||
}
|
||||
accessibleParent = new AccessibleJTreeNode(tree,
|
||||
parentPath,
|
||||
null);
|
||||
// If the root is not visible and the parent is the root,
|
||||
// don't create an accessible node for it.
|
||||
if (!isRootVisible() && parentPath.getParentPath() == null) {
|
||||
accessibleParent = tree;
|
||||
} else {
|
||||
accessibleParent = new AccessibleJTreeNode(tree,
|
||||
parentPath,
|
||||
null);
|
||||
}
|
||||
this.setAccessibleParent(accessibleParent);
|
||||
} else if (treeModel != null) {
|
||||
accessibleParent = tree; // we're the top!
|
||||
|
||||
@@ -49,6 +49,8 @@ import sun.security.action.GetPropertyAction;
|
||||
|
||||
import com.sun.java.swing.SwingUtilities3;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.pipe.Region;
|
||||
import sun.swing.SwingAccessor;
|
||||
@@ -811,7 +813,14 @@ public class RepaintManager
|
||||
|
||||
for (Window window : windows) {
|
||||
AWTAccessor.getWindowAccessor().updateWindow(window);
|
||||
AWTAccessor.getWindowAccessor().bumpCounter(window, "swing.RepaintManager.updateWindows");
|
||||
}
|
||||
} else {
|
||||
dirtyComponents.keySet().stream()
|
||||
.map(c -> c instanceof Window w ? w : SwingUtilities.getWindowAncestor(c))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(w -> AWTAccessor.getWindowAccessor()
|
||||
.bumpCounter(w, "swing.RepaintManager.updateWindows"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -346,6 +346,11 @@ public final class AWTAccessor {
|
||||
* window currently owns.
|
||||
*/
|
||||
Window[] getOwnedWindows(Window w);
|
||||
|
||||
boolean countersEnabled(Window w);
|
||||
void bumpCounter(Window w, String counterName);
|
||||
long getCounter(Window w, String counterName);
|
||||
long getCounterPerSecond(Window w, String counterName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,6 +53,7 @@ import sun.font.FontManagerFactory;
|
||||
import sun.font.FontManagerForSGE;
|
||||
import sun.font.FontUtilities;
|
||||
import sun.java2d.pipe.Region;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
@@ -88,6 +89,21 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
|
||||
debugScale = uiScaleEnabled ? getScaleFactor("sun.java2d.uiScale") : -1;
|
||||
}
|
||||
|
||||
protected enum LogDisplay {
|
||||
ADDED,
|
||||
REMOVED,
|
||||
CHANGED;
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
public static final boolean ENABLED = AccessController.doPrivileged(new GetBooleanAction("sun.java2d.logDisplays"));
|
||||
|
||||
public void log(int id, Object bounds, double scale) {
|
||||
if (!ENABLED) return;
|
||||
System.out.println("DISPLAY " + this + ": #" + id +
|
||||
", " + bounds + ", scale=" + scale);
|
||||
}
|
||||
}
|
||||
|
||||
protected GraphicsDevice[] screens;
|
||||
|
||||
private static boolean isWindows_8_1_orUpper() {
|
||||
|
||||
9
src/java.desktop/share/glsl/vulkan/blit.frag
Normal file
9
src/java.desktop/share/glsl/vulkan/blit.frag
Normal file
@@ -0,0 +1,9 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0) uniform sampler2D texSampler;
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = texture(texSampler, fragTexCoord);
|
||||
}
|
||||
10
src/java.desktop/share/glsl/vulkan/blit.vert
Normal file
10
src/java.desktop/share/glsl/vulkan/blit.vert
Normal file
@@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec2 texPosition;
|
||||
layout(location = 0) out vec2 fragTexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(inPosition, 0.0, 1.0);
|
||||
fragTexCoord = texPosition;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec4 inColor;
|
||||
layout(location = 0) in flat vec4 fragColor;
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = inColor;
|
||||
outColor = fragColor;
|
||||
}
|
||||
10
src/java.desktop/share/glsl/vulkan/color.vert
Normal file
10
src/java.desktop/share/glsl/vulkan/color.vert
Normal file
@@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec4 inColor;
|
||||
layout(location = 0) out flat vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(inPosition, 0.0, 1.0);
|
||||
fragColor = inColor;
|
||||
}
|
||||
8
src/java.desktop/share/glsl/vulkan/color_max_rect.frag
Normal file
8
src/java.desktop/share/glsl/vulkan/color_max_rect.frag
Normal file
@@ -0,0 +1,8 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in flat vec4 fragColor;
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = fragColor;
|
||||
}
|
||||
19
src/java.desktop/share/glsl/vulkan/color_max_rect.vert
Normal file
19
src/java.desktop/share/glsl/vulkan/color_max_rect.vert
Normal file
@@ -0,0 +1,19 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
vec2 invViewport2; // 2.0/viewport
|
||||
} push;
|
||||
|
||||
vec4 colors[3] = vec4[](
|
||||
vec4(1,0,0,1),
|
||||
vec4(0,1,0,1),
|
||||
vec4(0,0,1,1)
|
||||
);
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = colors[gl_VertexIndex % 3];
|
||||
gl_Position = vec4(inPosition * push.invViewport2 - 1.0, 0.0, 1.0);
|
||||
gl_PointSize = 1.0f;
|
||||
}
|
||||
@@ -1297,19 +1297,17 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
|
||||
int ry = ginfo->subpixelResolutionY;
|
||||
ADJUST_SUBPIXEL_GLYPH_POSITION(glyphx, rx);
|
||||
ADJUST_SUBPIXEL_GLYPH_POSITION(glyphy, ry);
|
||||
int subx = 0, suby = 0;
|
||||
// see DrawGlyphList.c FLOOR_ASSIGN & getSubpixelGlyphImage
|
||||
if (glyphx >= 0.0f && glyphy >= 0.0f) {
|
||||
x = (int) glyphx;
|
||||
y = (int) glyphy;
|
||||
subx = ((int) (glyphx * (float) rx)) % rx;
|
||||
suby = ((int) (glyphy * (float) ry)) % ry;
|
||||
float fx = floor(glyphx);
|
||||
float fy = floor(glyphy);
|
||||
x = (int) fx;
|
||||
y = (int) fy;
|
||||
int subimage;
|
||||
if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
|
||||
subimage = 0;
|
||||
} else {
|
||||
float fx = floor(glyphx), fy = floor(glyphy);
|
||||
x = (int) fx;
|
||||
y = (int) fy;
|
||||
subx = (int) ((glyphx - fx) * (float) rx);
|
||||
suby = (int) ((glyphy - fy) * (float) ry);
|
||||
int subx = (int) ((glyphx - fx) * (float) rx);
|
||||
int suby = (int) ((glyphy - fy) * (float) ry);
|
||||
subimage = subx + suby * rx;
|
||||
}
|
||||
|
||||
if (ginfo->image == NULL) {
|
||||
@@ -1321,12 +1319,6 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
|
||||
OGLContext_InitGrayRenderHints(env, oglc);
|
||||
}
|
||||
// grayscale or monochrome glyph data
|
||||
int subimage;
|
||||
if ((rx == 1 && ry == 1) || rx <= 0 || ry <= 0) {
|
||||
subimage = 0;
|
||||
} else {
|
||||
subimage = subx + suby * rx;
|
||||
}
|
||||
if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
|
||||
ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <memory.h>
|
||||
#include "CArrayUtil.h"
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
void* CARR_array_alloc(size_t elem_size, size_t capacity) {
|
||||
CARR_array_t *pvec = malloc(elem_size * capacity + offsetof(CARR_array_t, data));
|
||||
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) {
|
||||
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));
|
||||
if (new_vec == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
free(vec);
|
||||
return new_vec->data;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#ifndef C_ARRAY_UTIL_H
|
||||
#define C_ARRAY_UTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define ARRAY_CAPACITY_MULT 2
|
||||
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);
|
||||
|
||||
/**
|
||||
* Allocate array
|
||||
* @param T type of elements
|
||||
* @param SIZE size of the array
|
||||
*/
|
||||
#define ARRAY_ALLOC(T, SIZE) (T*)CARR_array_alloc(sizeof(T), SIZE)
|
||||
|
||||
|
||||
#define ARRAY_T(P) (CARR_array_t *)((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
|
||||
|
||||
/**
|
||||
* @param P pointer to the first data element of the array
|
||||
* @return capacity of the array
|
||||
*/
|
||||
#define ARRAY_CAPACITY(P) (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])
|
||||
|
||||
/**
|
||||
* Deallocate the vector
|
||||
* @param P pointer to the first data element of the array
|
||||
*/
|
||||
#define ARRAY_FREE(P) free(ARRAY_T(P))
|
||||
|
||||
/**
|
||||
* Apply function to the vector
|
||||
* @param P pointer to the first data element of the array
|
||||
* @param F function to apply
|
||||
*/
|
||||
#define ARRAY_APPLY(P, F) do { \
|
||||
for (uint32_t _i = 0; _i < ARRAY_SIZE(P); _i++) F(&(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
|
||||
*/
|
||||
#define ARRAY_SHRINK_TO_FIT(PP) do { \
|
||||
*PP = CARR_array_realloc(ARRAY_T(*PP), ARRAY_SIZE(*PP)); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Add element to the end of the array
|
||||
* @param PP pointer to the pointer to the first data element 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)++; \
|
||||
} while(0)
|
||||
|
||||
#define SARRAY_COUNT_OF(STATIC_ARRAY) (sizeof(STATIC_ARRAY)/sizeof(STATIC_ARRAY[0]))
|
||||
|
||||
#endif // CARRAYUTILS_H
|
||||
812
src/java.desktop/share/native/common/java2d/vulkan/VKBase.c
Normal file
812
src/java.desktop/share/native/common/java2d/vulkan/VKBase.c
Normal file
@@ -0,0 +1,812 @@
|
||||
/*
|
||||
* 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 <malloc.h>
|
||||
#include <Trace.h>
|
||||
#include "jvm_md.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKVertex.h"
|
||||
#include "CArrayUtil.h"
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.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]))
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
extern struct wl_display *wl_display;
|
||||
#endif
|
||||
|
||||
static jboolean verbose;
|
||||
static jint requestedDeviceNumber = -1;
|
||||
static VKGraphicsEnvironment* geInstance = NULL;
|
||||
static void* pVulkanLib = NULL;
|
||||
#define DEBUG
|
||||
#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 DEF_VK_PROC_RET_IF_ERR(INST, NAME, RETVAL) PFN_ ## NAME NAME = (PFN_ ## NAME ) vulkanLibProc(INST, #NAME); \
|
||||
if (NAME == NULL) { \
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Required api is not supported. %s is missing.", #NAME)\
|
||||
vulkanLibClose(); \
|
||||
return RETVAL; \
|
||||
}
|
||||
|
||||
|
||||
#define VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(SNAME, NAME) do { \
|
||||
SNAME->NAME = (PFN_ ## NAME ) vulkanLibProc( SNAME->vkInstance, #NAME); \
|
||||
if (SNAME->NAME == NULL) { \
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Required api is not supported. %s is missing.", #NAME)\
|
||||
vulkanLibClose(); \
|
||||
return NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void vulkanLibClose() {
|
||||
if (pVulkanLib != NULL) {
|
||||
if (geInstance != NULL) {
|
||||
if (geInstance->layers != NULL) {
|
||||
free(geInstance->layers);
|
||||
}
|
||||
if (geInstance->extensions != NULL) {
|
||||
free(geInstance->extensions);
|
||||
}
|
||||
ARRAY_FREE(geInstance->physicalDevices);
|
||||
if (geInstance->devices != NULL) {
|
||||
PFN_vkDestroyDevice vkDestroyDevice = vulkanLibProc(geInstance->vkInstance, "vkDestroyDevice");
|
||||
|
||||
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 (vkDestroyDevice != NULL && geInstance->devices[i].device != NULL) {
|
||||
vkDestroyDevice(geInstance->devices[i].device, NULL);
|
||||
}
|
||||
}
|
||||
free(geInstance->devices);
|
||||
}
|
||||
|
||||
if (geInstance->vkInstance != NULL) {
|
||||
PFN_vkDestroyInstance vkDestroyInstance = vulkanLibProc(geInstance->vkInstance, "vkDestroyInstance");
|
||||
if (vkDestroyInstance != NULL) {
|
||||
vkDestroyInstance(geInstance->vkInstance, NULL);
|
||||
}
|
||||
}
|
||||
free(geInstance);
|
||||
geInstance = NULL;
|
||||
}
|
||||
dlclose(pVulkanLib);
|
||||
pVulkanLib = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void* vulkanLibProc(VkInstance vkInstance, char* procName) {
|
||||
static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
|
||||
if (pVulkanLib == NULL) {
|
||||
pVulkanLib = dlopen(VULKAN_DLL, RTLD_NOW);
|
||||
if (pVulkanLib == NULL) {
|
||||
pVulkanLib = dlopen(VULKAN_1_DLL, RTLD_NOW);
|
||||
}
|
||||
if (pVulkanLib == NULL) {
|
||||
J2dRlsTrace1(J2D_TRACE_ERROR, "Failed to load %s\n", VULKAN_DLL)
|
||||
return NULL;
|
||||
}
|
||||
if (!vkGetInstanceProcAddr) {
|
||||
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) dlsym(pVulkanLib, "vkGetInstanceProcAddr");
|
||||
if (vkGetInstanceProcAddr == NULL) {
|
||||
J2dRlsTrace1(J2D_TRACE_ERROR,
|
||||
"Failed to get proc address of vkGetInstanceProcAddr from %s\n", VULKAN_DLL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* vkProc = vkGetInstanceProcAddr(vkInstance, procName);
|
||||
|
||||
if (vkProc == NULL) {
|
||||
J2dRlsTrace1(J2D_TRACE_ERROR, "%s is not supported\n", procName)
|
||||
return NULL;
|
||||
}
|
||||
return vkProc;
|
||||
}
|
||||
|
||||
|
||||
jboolean VK_Init(jboolean verb, jint requestedDevice) {
|
||||
verbose = verb;
|
||||
if (VKGE_graphics_environment() == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (!VK_FindDevices()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (!VK_CreateLogicalDevice(requestedDevice)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return VK_CreateLogicalDeviceRenderers();
|
||||
}
|
||||
|
||||
static const char* physicalDeviceTypeString(VkPhysicalDeviceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
#define STR(r) case VK_PHYSICAL_DEVICE_TYPE_ ##r: return #r
|
||||
STR(OTHER);
|
||||
STR(INTEGRATED_GPU);
|
||||
STR(DISCRETE_GPU);
|
||||
STR(VIRTUAL_GPU);
|
||||
STR(CPU);
|
||||
#undef STR
|
||||
default: return "UNKNOWN_DEVICE_TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
VKGraphicsEnvironment* VKGE_graphics_environment() {
|
||||
if (geInstance == NULL) {
|
||||
|
||||
DEF_VK_PROC_RET_IF_ERR(VK_NULL_HANDLE, vkEnumerateInstanceVersion, NULL);
|
||||
DEF_VK_PROC_RET_IF_ERR(VK_NULL_HANDLE, vkEnumerateInstanceExtensionProperties, NULL);
|
||||
DEF_VK_PROC_RET_IF_ERR(VK_NULL_HANDLE, vkEnumerateInstanceLayerProperties, NULL);
|
||||
DEF_VK_PROC_RET_IF_ERR(VK_NULL_HANDLE, vkCreateInstance, NULL);
|
||||
|
||||
uint32_t apiVersion = 0;
|
||||
|
||||
if (vkEnumerateInstanceVersion(&apiVersion) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: unable to enumerate Vulkan instance version\n")
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
J2dRlsTrace3(J2D_TRACE_INFO, "Vulkan: Available (%d.%d.%d)\n",
|
||||
VK_API_VERSION_MAJOR(apiVersion),
|
||||
VK_API_VERSION_MINOR(apiVersion),
|
||||
VK_API_VERSION_PATCH(apiVersion))
|
||||
|
||||
if (apiVersion < REQUIRED_VULKAN_VERSION) {
|
||||
J2dRlsTrace3(J2D_TRACE_ERROR, "Vulkan: Unsupported version. Required at least (%d.%d.%d)\n",
|
||||
VK_API_VERSION_MAJOR(REQUIRED_VULKAN_VERSION),
|
||||
VK_API_VERSION_MINOR(REQUIRED_VULKAN_VERSION),
|
||||
VK_API_VERSION_PATCH(REQUIRED_VULKAN_VERSION))
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
geInstance = (VKGraphicsEnvironment*)malloc(sizeof(VKGraphicsEnvironment));
|
||||
if (geInstance == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VKGraphicsEnvironment\n")
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*geInstance = (VKGraphicsEnvironment) {};
|
||||
uint32_t extensionsCount;
|
||||
// Get the number of extensions and layers
|
||||
if (vkEnumerateInstanceExtensionProperties(NULL,
|
||||
&extensionsCount,
|
||||
NULL) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: vkEnumerateInstanceExtensionProperties fails\n")
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
geInstance->extensions = ARRAY_ALLOC(VkExtensionProperties, extensionsCount);
|
||||
|
||||
if (geInstance->extensions == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkExtensionProperties\n")
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vkEnumerateInstanceExtensionProperties(NULL, &extensionsCount,
|
||||
geInstance->extensions) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: vkEnumerateInstanceExtensionProperties fails\n")
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ARRAY_SIZE(geInstance->extensions) = extensionsCount;
|
||||
|
||||
uint32_t layersCount;
|
||||
if (vkEnumerateInstanceLayerProperties(&layersCount, NULL) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: vkEnumerateInstanceLayerProperties fails\n")
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
geInstance->layers = ARRAY_ALLOC(VkLayerProperties, layersCount);
|
||||
if (geInstance->layers == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkLayerProperties\n")
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vkEnumerateInstanceLayerProperties(&layersCount,
|
||||
geInstance->layers) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: vkEnumerateInstanceLayerProperties fails\n")
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ARRAY_SIZE(geInstance->layers) = layersCount;
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported instance layers:\n")
|
||||
for (uint32_t i = 0; i < layersCount; i++) {
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char *) geInstance->layers[i].layerName)
|
||||
}
|
||||
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported instance extensions:\n")
|
||||
for (uint32_t i = 0; i < extensionsCount; i++) {
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char *) geInstance->extensions[i].extensionName)
|
||||
}
|
||||
|
||||
pchar* enabledLayers = ARRAY_ALLOC(pchar, MAX_ENABLED_LAYERS);
|
||||
pchar* enabledExtensions = ARRAY_ALLOC(pchar, MAX_ENABLED_EXTENSIONS);
|
||||
void *pNext = NULL;
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
ARRAY_PUSH_BACK(&enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
ARRAY_PUSH_BACK(&enabledExtensions, VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
|
||||
// Check required layers & extensions.
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(enabledExtensions); i++) {
|
||||
int notFound = 1;
|
||||
for (uint32_t j = 0; j < extensionsCount; j++) {
|
||||
if (strcmp((char *) geInstance->extensions[j].extensionName, enabledExtensions[i]) == 0) {
|
||||
notFound = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (notFound) {
|
||||
J2dRlsTrace1(J2D_TRACE_ERROR, "Vulkan: Required extension %s not found\n", enabledExtensions[i])
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Configure validation
|
||||
#ifdef DEBUG
|
||||
VkValidationFeatureEnableEXT enables[] = {
|
||||
// VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,
|
||||
// VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
|
||||
// VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT
|
||||
};
|
||||
|
||||
VkValidationFeaturesEXT features = {};
|
||||
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
|
||||
features.enabledValidationFeatureCount = COUNT_OF(enables);
|
||||
features.pEnabledValidationFeatures = enables;
|
||||
|
||||
// Includes the validation features into the instance creation process
|
||||
|
||||
int foundDebugLayer = 0;
|
||||
for (uint32_t i = 0; i < layersCount; i++) {
|
||||
if (strcmp((char *) geInstance->layers[i].layerName, VALIDATION_LAYER_NAME) == 0) {
|
||||
foundDebugLayer = 1;
|
||||
break;
|
||||
}
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char *) geInstance->layers[i].layerName)
|
||||
}
|
||||
int foundDebugExt = 0;
|
||||
for (uint32_t i = 0; i < extensionsCount; i++) {
|
||||
if (strcmp((char *) geInstance->extensions[i].extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
|
||||
foundDebugExt = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundDebugLayer && foundDebugExt) {
|
||||
ARRAY_PUSH_BACK(&enabledLayers, VALIDATION_LAYER_NAME);
|
||||
ARRAY_PUSH_BACK(&enabledExtensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
pNext = &features;
|
||||
} else {
|
||||
J2dRlsTrace2(J2D_TRACE_WARNING, "Vulkan: %s and %s are not supported\n",
|
||||
VALIDATION_LAYER_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)
|
||||
}
|
||||
#endif
|
||||
VkApplicationInfo applicationInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pNext = NULL,
|
||||
.pApplicationName = "OpenJDK",
|
||||
.applicationVersion = 0,
|
||||
.pEngineName = "OpenJDK",
|
||||
.engineVersion = 0,
|
||||
.apiVersion = REQUIRED_VULKAN_VERSION
|
||||
};
|
||||
|
||||
VkInstanceCreateInfo instanceCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pNext =pNext,
|
||||
.flags = 0,
|
||||
.pApplicationInfo = &applicationInfo,
|
||||
.enabledLayerCount = ARRAY_SIZE(enabledLayers),
|
||||
.ppEnabledLayerNames = (const char *const *) enabledLayers,
|
||||
.enabledExtensionCount = ARRAY_SIZE(enabledExtensions),
|
||||
.ppEnabledExtensionNames = (const char *const *) enabledExtensions
|
||||
};
|
||||
|
||||
if (vkCreateInstance(&instanceCreateInfo, NULL, &geInstance->vkInstance) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Failed to create Vulkan instance\n")
|
||||
vulkanLibClose();
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
return NULL;
|
||||
} else {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "Vulkan: Instance Created\n")
|
||||
}
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkEnumeratePhysicalDevices);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetPhysicalDeviceFeatures2);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetPhysicalDeviceProperties2);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkEnumerateDeviceLayerProperties);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkEnumerateDeviceExtensionProperties);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateShaderModule);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreatePipelineLayout);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateGraphicsPipelines);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkDestroyShaderModule);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetPhysicalDeviceSurfaceFormatsKHR);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetPhysicalDeviceSurfacePresentModesKHR);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateSwapchainKHR);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetSwapchainImagesKHR);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateImageView);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateFramebuffer);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateCommandPool);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkAllocateCommandBuffers);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateSemaphore);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateFence);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetDeviceQueue);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkWaitForFences);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkResetFences);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkAcquireNextImageKHR);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkResetCommandBuffer);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkQueueSubmit);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkQueuePresentKHR);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkBeginCommandBuffer);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdBeginRenderPass);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdBindPipeline);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdSetViewport);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdSetScissor);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdDraw);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkEndCommandBuffer);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdEndRenderPass);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateImage);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateSampler);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkAllocateMemory);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetPhysicalDeviceMemoryProperties);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkBindImageMemory);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateDescriptorSetLayout);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkUpdateDescriptorSets);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateDescriptorPool);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkAllocateDescriptorSets);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdBindDescriptorSets);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetImageMemoryRequirements);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateBuffer);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetBufferMemoryRequirements);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkBindBufferMemory);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkMapMemory);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkUnmapMemory);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdBindVertexBuffers);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateRenderPass);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkDestroyBuffer);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkFreeMemory);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkDestroyImageView);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkDestroyImage);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkDestroyFramebuffer);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkFlushMappedMemoryRanges);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCmdPushConstants);
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkGetPhysicalDeviceWaylandPresentationSupportKHR);
|
||||
VKGE_INIT_VK_PROC_RET_NULL_IF_ERR(geInstance, vkCreateWaylandSurfaceKHR);
|
||||
#endif
|
||||
|
||||
}
|
||||
return geInstance;
|
||||
}
|
||||
|
||||
jboolean VK_FindDevices() {
|
||||
uint32_t physicalDevicesCount;
|
||||
if (geInstance->vkEnumeratePhysicalDevices(geInstance->vkInstance,
|
||||
&physicalDevicesCount,
|
||||
NULL) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: vkEnumeratePhysicalDevices fails\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (physicalDevicesCount == 0) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Failed to find GPUs with Vulkan support\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
} else {
|
||||
J2dRlsTrace1(J2D_TRACE_INFO, "Vulkan: Found %d physical devices:\n", physicalDevicesCount)
|
||||
}
|
||||
|
||||
geInstance->physicalDevices = ARRAY_ALLOC(VkPhysicalDevice, physicalDevicesCount);
|
||||
if (geInstance->physicalDevices == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkPhysicalDevice\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (geInstance->vkEnumeratePhysicalDevices(
|
||||
geInstance->vkInstance,
|
||||
&physicalDevicesCount,
|
||||
geInstance->physicalDevices) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: vkEnumeratePhysicalDevices fails\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
geInstance->devices = ARRAY_ALLOC(VKLogicalDevice, physicalDevicesCount);
|
||||
if (geInstance->devices == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VKLogicalDevice\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < physicalDevicesCount; i++) {
|
||||
VkPhysicalDeviceVulkan12Features device12Features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
.pNext = NULL
|
||||
};
|
||||
|
||||
VkPhysicalDeviceFeatures2 deviceFeatures2 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
.pNext = &device12Features
|
||||
};
|
||||
|
||||
geInstance->vkGetPhysicalDeviceFeatures2(geInstance->physicalDevices[i], &deviceFeatures2);
|
||||
|
||||
VkPhysicalDeviceProperties2 deviceProperties2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
geInstance->vkGetPhysicalDeviceProperties2(geInstance->physicalDevices[i], &deviceProperties2);
|
||||
J2dRlsTrace5(J2D_TRACE_INFO, "\t- %s (%d.%d.%d, %s) ",
|
||||
(const char *) deviceProperties2.properties.deviceName,
|
||||
VK_API_VERSION_MAJOR(deviceProperties2.properties.apiVersion),
|
||||
VK_API_VERSION_MINOR(deviceProperties2.properties.apiVersion),
|
||||
VK_API_VERSION_PATCH(deviceProperties2.properties.apiVersion),
|
||||
physicalDeviceTypeString(deviceProperties2.properties.deviceType))
|
||||
|
||||
if (!deviceFeatures2.features.logicOp) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, " - hasLogicOp not supported, skipped \n")
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!device12Features.timelineSemaphore) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, " - hasTimelineSemaphore not supported, skipped \n")
|
||||
continue;
|
||||
}
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "\n")
|
||||
|
||||
uint32_t queueFamilyCount = 0;
|
||||
geInstance->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
geInstance->physicalDevices[i], &queueFamilyCount, NULL);
|
||||
|
||||
VkQueueFamilyProperties *queueFamilies = (VkQueueFamilyProperties*)calloc(queueFamilyCount,
|
||||
sizeof(VkQueueFamilyProperties));
|
||||
if (queueFamilies == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkQueueFamilyProperties\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
geInstance->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
geInstance->physicalDevices[i], &queueFamilyCount, queueFamilies);
|
||||
int64_t queueFamily = -1;
|
||||
for (uint32_t j = 0; j < queueFamilyCount; j++) {
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
VkBool32 presentationSupported =
|
||||
geInstance->vkGetPhysicalDeviceWaylandPresentationSupportKHR(
|
||||
geInstance->physicalDevices[i], j, wl_display);
|
||||
#endif
|
||||
char logFlags[5] = {
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT ? 'G' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_COMPUTE_BIT ? 'C' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_TRANSFER_BIT ? 'T' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT ? 'S' : '-',
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
presentationSupported ? 'P' : '-'
|
||||
#else
|
||||
'-'
|
||||
#endif
|
||||
};
|
||||
J2dRlsTrace3(J2D_TRACE_INFO, " %d queues in family (%.*s)\n", queueFamilies[j].queueCount, 5,
|
||||
logFlags)
|
||||
|
||||
// TODO use compute workloads? Separate transfer-only DMA queue?
|
||||
if (queueFamily == -1 && (queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
&& presentationSupported
|
||||
#endif
|
||||
) {
|
||||
queueFamily = j;
|
||||
}
|
||||
}
|
||||
free(queueFamilies);
|
||||
if (queueFamily == -1) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, " --------------------- Suitable queue not found, skipped \n")
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t layerCount;
|
||||
geInstance->vkEnumerateDeviceLayerProperties(geInstance->physicalDevices[i], &layerCount, NULL);
|
||||
VkLayerProperties *layers = (VkLayerProperties *) calloc(layerCount, sizeof(VkLayerProperties));
|
||||
if (layers == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkLayerProperties\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
geInstance->vkEnumerateDeviceLayerProperties(geInstance->physicalDevices[i], &layerCount, layers);
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported device layers:\n")
|
||||
for (uint32_t j = 0; j < layerCount; j++) {
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (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) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VkExtensionProperties\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
geInstance->vkEnumerateDeviceExtensionProperties(
|
||||
geInstance->physicalDevices[i], NULL, &extensionCount, extensions);
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported device extensions:\n")
|
||||
VkBool32 hasSwapChain = VK_FALSE;
|
||||
for (uint32_t j = 0; j < extensionCount; j++) {
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char *) extensions[j].extensionName)
|
||||
hasSwapChain = hasSwapChain ||
|
||||
strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, extensions[j].extensionName) == 0;
|
||||
}
|
||||
free(extensions);
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Found:\n")
|
||||
if (hasSwapChain) {
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " VK_KHR_SWAPCHAIN_EXTENSION_NAME\n")
|
||||
}
|
||||
|
||||
if (!hasSwapChain) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO,
|
||||
" --------------------- Required VK_KHR_SWAPCHAIN_EXTENSION_NAME not found, skipped \n")
|
||||
continue;
|
||||
}
|
||||
|
||||
pchar* deviceEnabledLayers = ARRAY_ALLOC(pchar, MAX_ENABLED_LAYERS);
|
||||
if (deviceEnabledLayers == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate deviceEnabledLayers array\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
pchar* deviceEnabledExtensions = ARRAY_ALLOC(pchar, MAX_ENABLED_EXTENSIONS);
|
||||
if (deviceEnabledExtensions == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot allocate deviceEnabledExtensions array\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ARRAY_PUSH_BACK(&deviceEnabledExtensions, VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
|
||||
// Validation layer
|
||||
#ifdef DEBUG
|
||||
int validationLayerNotSupported = 1;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (validationLayerNotSupported) {
|
||||
J2dRlsTrace1(J2D_TRACE_INFO, " %s device layer is not supported\n", VALIDATION_LAYER_NAME)
|
||||
}
|
||||
#endif
|
||||
free(layers);
|
||||
char* deviceName = strdup(deviceProperties2.properties.deviceName);
|
||||
if (deviceName == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Cannot duplicate deviceName\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ARRAY_PUSH_BACK(&geInstance->devices,
|
||||
((VKLogicalDevice) {
|
||||
.name = deviceName,
|
||||
.device = VK_NULL_HANDLE,
|
||||
.physicalDevice = geInstance->physicalDevices[i],
|
||||
.queueFamily = queueFamily,
|
||||
.enabledLayers = deviceEnabledLayers,
|
||||
.enabledExtensions = deviceEnabledExtensions,
|
||||
}));
|
||||
}
|
||||
if (ARRAY_SIZE(geInstance->devices) == 0) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "No compatible device found\n")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean VK_CreateLogicalDevice(jint requestedDevice) {
|
||||
requestedDeviceNumber = requestedDevice;
|
||||
|
||||
if (geInstance == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: VKGraphicsEnvironment is not initialized\n")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
DEF_VK_PROC_RET_IF_ERR(geInstance->vkInstance, vkCreateDevice, JNI_FALSE)
|
||||
DEF_VK_PROC_RET_IF_ERR(geInstance->vkInstance, vkCreatePipelineCache, JNI_FALSE)
|
||||
DEF_VK_PROC_RET_IF_ERR(geInstance->vkInstance, vkCreateRenderPass, JNI_FALSE)
|
||||
|
||||
requestedDeviceNumber = (requestedDeviceNumber == -1) ? 0 : requestedDeviceNumber;
|
||||
|
||||
if (requestedDeviceNumber < 0 || (uint32_t)requestedDeviceNumber >= ARRAY_SIZE(geInstance->devices)) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, " Requested device number (%d) not found, fallback to 0\n", requestedDeviceNumber);
|
||||
}
|
||||
requestedDeviceNumber = 0;
|
||||
}
|
||||
geInstance->enabledDeviceNum = requestedDeviceNumber;
|
||||
if (verbose) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(geInstance->devices); i++) {
|
||||
fprintf(stderr, " %c%d: %s\n", i == geInstance->enabledDeviceNum ? '*' : ' ',
|
||||
i, geInstance->devices[i].name);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
VKLogicalDevice* logicalDevice = &geInstance->devices[geInstance->enabledDeviceNum];
|
||||
float queuePriority = 1.0f;
|
||||
VkDeviceQueueCreateInfo queueCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.queueFamilyIndex = logicalDevice->queueFamily, // obtained separately
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority
|
||||
};
|
||||
|
||||
VkPhysicalDeviceFeatures features10 = { .logicOp = VK_TRUE };
|
||||
|
||||
VkDeviceCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.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,
|
||||
.pEnabledFeatures = &features10
|
||||
};
|
||||
|
||||
if (vkCreateDevice(logicalDevice->physicalDevice, &createInfo, NULL, &logicalDevice->device) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace1(J2D_TRACE_ERROR, "Cannot create device:\n %s\n",
|
||||
geInstance->devices[geInstance->enabledDeviceNum].name)
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
VkDevice device = logicalDevice->device;
|
||||
J2dRlsTrace1(J2D_TRACE_INFO, "Logical device (%s) created\n", logicalDevice->name)
|
||||
|
||||
|
||||
// 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 (geInstance->vkCreateCommandPool(device, &poolInfo, NULL, &logicalDevice->commandPool) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to create command pool!")
|
||||
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 (geInstance->vkAllocateCommandBuffers(device, &allocInfo, &logicalDevice->commandBuffer) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to allocate command buffers!");
|
||||
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 (geInstance->vkCreateSemaphore(device, &semaphoreInfo, NULL, &logicalDevice->imageAvailableSemaphore) != VK_SUCCESS ||
|
||||
geInstance->vkCreateSemaphore(device, &semaphoreInfo, NULL, &logicalDevice->renderFinishedSemaphore) != VK_SUCCESS ||
|
||||
geInstance->vkCreateFence(device, &fenceInfo, NULL, &logicalDevice->inFlightFence) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to create semaphores!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
geInstance->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(vertices);
|
||||
if (!logicalDevice->blitVertexBuffer) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot create vertex buffer\n")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
ARRAY_FREE(vertices);
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_OnUnload(__attribute__((unused)) JavaVM *vm, __attribute__((unused)) void *reserved) {
|
||||
vulkanLibClose();
|
||||
}
|
||||
@@ -1,453 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 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 "VKBase.h"
|
||||
#include <Trace.h>
|
||||
#include <set>
|
||||
#if defined(DEBUG)
|
||||
#include <csignal>
|
||||
#endif
|
||||
|
||||
#define VALIDATION_LAYER_NAME "VK_LAYER_KHRONOS_validation"
|
||||
static const uint32_t REQUIRED_VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 2, 0);
|
||||
|
||||
bool VKGraphicsEnvironment::_verbose = false;
|
||||
int VKGraphicsEnvironment::_requested_device_number = -1;
|
||||
std::unique_ptr<VKGraphicsEnvironment> VKGraphicsEnvironment::_ge_instance = nullptr;
|
||||
|
||||
// ========== Graphics environment ==========
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
static VkBool32 debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData
|
||||
) {
|
||||
auto data = (const vk::DebugUtilsMessengerCallbackDataEXT*) pCallbackData;
|
||||
if (data == nullptr) return 0;
|
||||
// Here we can filter messages like this:
|
||||
// if (std::strcmp(data->pMessageIdName, "UNASSIGNED-BestPractices-DrawState-ClearCmdBeforeDraw") == 0) return 0;
|
||||
|
||||
int level = J2D_TRACE_OFF;
|
||||
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) level = J2D_TRACE_VERBOSE;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) level = J2D_TRACE_INFO;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) level = J2D_TRACE_WARNING;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) level = J2D_TRACE_ERROR;
|
||||
|
||||
J2dRlsTraceLn(level, data->pMessage);
|
||||
|
||||
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
raise(SIGABRT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
VKGraphicsEnvironment *VKGraphicsEnvironment::graphics_environment() {
|
||||
if (!_ge_instance) {
|
||||
try {
|
||||
_ge_instance = std::unique_ptr<VKGraphicsEnvironment>(new VKGraphicsEnvironment());
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
J2dRlsTrace1(J2D_TRACE_ERROR, "Vulkan: %s\n", e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return _ge_instance.get();
|
||||
}
|
||||
|
||||
VKGraphicsEnvironment::VKGraphicsEnvironment() :
|
||||
_vk_context(), _vk_instance(nullptr), _default_device(nullptr) {
|
||||
// Load library.
|
||||
uint32_t version = _vk_context.enumerateInstanceVersion();
|
||||
J2dRlsTrace3(J2D_TRACE_INFO, "Vulkan: Available (%d.%d.%d)\n",
|
||||
VK_API_VERSION_MAJOR(version), VK_API_VERSION_MINOR(version), VK_API_VERSION_PATCH(version));
|
||||
|
||||
if (version < REQUIRED_VULKAN_VERSION) {
|
||||
throw std::runtime_error("Vulkan: Unsupported version");
|
||||
}
|
||||
|
||||
// Populate maps and log supported layers & extensions.
|
||||
std::set<std::string> layers, extensions;
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported instance layers:\n");
|
||||
for (auto &l: _vk_context.enumerateInstanceLayerProperties()) {
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char *) l.layerName);
|
||||
layers.emplace((char *) l.layerName);
|
||||
}
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported instance extensions:\n");
|
||||
for (auto &e: _vk_context.enumerateInstanceExtensionProperties(nullptr)) {
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char *) e.extensionName);
|
||||
extensions.emplace((char *) e.extensionName);
|
||||
}
|
||||
|
||||
std::vector<const char *> enabledLayers, enabledExtensions;
|
||||
const void *pNext = nullptr;
|
||||
|
||||
// Check required layers & extensions.
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
enabledExtensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
enabledExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
for (auto e: enabledExtensions) {
|
||||
if (extensions.find(e) == extensions.end()) {
|
||||
throw std::runtime_error(std::string("Vulkan: Required instance extension not supported:") +
|
||||
(char *) e);
|
||||
}
|
||||
}
|
||||
// Configure validation
|
||||
#ifdef DEBUG
|
||||
std::array<vk::ValidationFeatureEnableEXT, 2> enabledValidationFeatures = {
|
||||
// vk::ValidationFeatureEnableEXT::eGpuAssisted, // TODO GPU assisted validation is available only from Vulkan 1.1
|
||||
// vk::ValidationFeatureEnableEXT::eGpuAssistedReserveBindingSlot,
|
||||
vk::ValidationFeatureEnableEXT::eBestPractices,
|
||||
vk::ValidationFeatureEnableEXT::eSynchronizationValidation
|
||||
};
|
||||
vk::ValidationFeaturesEXT validationFeatures {enabledValidationFeatures};
|
||||
if (layers.find(VALIDATION_LAYER_NAME) != layers.end() &&
|
||||
extensions.find(VK_EXT_DEBUG_UTILS_EXTENSION_NAME) != extensions.end()) {
|
||||
enabledLayers.push_back(VALIDATION_LAYER_NAME);
|
||||
enabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
pNext = &validationFeatures;
|
||||
} else {
|
||||
J2dRlsTrace2(J2D_TRACE_WARNING, "Vulkan: %s and %s are not supported\n",
|
||||
VALIDATION_LAYER_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
vk::ApplicationInfo applicationInfo{
|
||||
/*pApplicationName*/ "OpenJDK",
|
||||
/*applicationVersion*/ 0,
|
||||
/*pEngineName*/ "OpenJDK",
|
||||
/*engineVersion*/ 0,
|
||||
/*apiVersion*/ REQUIRED_VULKAN_VERSION
|
||||
};
|
||||
|
||||
vk::InstanceCreateInfo instanceCreateInfo{
|
||||
/*flags*/ {},
|
||||
/*pApplicationInfo*/ &applicationInfo,
|
||||
/*ppEnabledLayerNames*/ enabledLayers,
|
||||
/*ppEnabledExtensionNames*/ enabledExtensions,
|
||||
/*pNext*/ pNext
|
||||
};
|
||||
|
||||
// Save context object at persistent address before passing it further.
|
||||
_vk_instance = vk::raii::Instance(_vk_context, instanceCreateInfo);
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "Vulkan: Instance created\n");
|
||||
|
||||
// Create debug messenger
|
||||
#if defined(DEBUG)
|
||||
if (pNext) {
|
||||
_debugMessenger = vk::raii::DebugUtilsMessengerEXT(_vk_instance, vk::DebugUtilsMessengerCreateInfoEXT {
|
||||
/*flags*/ {},
|
||||
/*messageSeverity*/ vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose,
|
||||
/*messageType*/ vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
|
||||
/*pfnUserCallback*/ &debugCallback
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Find suitable devices.
|
||||
for (auto &handle: _vk_instance.enumeratePhysicalDevices()) {
|
||||
VKDevice device {*_vk_instance, std::move(handle)};
|
||||
if (device.supported()) {
|
||||
_devices.push_back(std::make_unique<VKDevice>(std::move(device)));
|
||||
}
|
||||
}
|
||||
|
||||
if (_devices.empty()) {
|
||||
throw std::runtime_error("Vulkan: No suitable device found");
|
||||
}
|
||||
// Create virtual device for a physical device.
|
||||
// TODO integrated/discrete presets
|
||||
// TODO performance/power saving mode switch on the fly?
|
||||
int _default_device_number = 0; // TODO pick first just to check that virtual device creation works
|
||||
|
||||
if (_verbose) {
|
||||
fprintf(stderr, "Vulkan graphics devices:\n");
|
||||
}
|
||||
|
||||
_requested_device_number = (_requested_device_number == -1) ? 0 : _requested_device_number;
|
||||
if (_requested_device_number < 0 || _requested_device_number >= static_cast<int>(_devices.size())) {
|
||||
if (_verbose) {
|
||||
fprintf(stderr, " Requested device number (%d) not found, fallback to 0\n", _requested_device_number);
|
||||
}
|
||||
_requested_device_number = 0;
|
||||
}
|
||||
_default_device_number = _requested_device_number;
|
||||
if (_verbose) {
|
||||
for (auto devIter = _devices.begin(); devIter != _devices.end(); devIter++) {
|
||||
auto devNum = std::distance(begin(_devices), devIter);
|
||||
fprintf(stderr, " %c%ld: %s\n", devNum == _default_device_number ? '*' : ' ',
|
||||
devNum, (*devIter)->name().c_str());
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
_default_device = &*_devices[_default_device_number]; // TODO pick first just to check hat virtual device creation works
|
||||
_default_device->init();
|
||||
|
||||
}
|
||||
|
||||
vk::raii::Instance& VKGraphicsEnvironment::vk_instance() {
|
||||
return _vk_instance;
|
||||
}
|
||||
|
||||
void VKGraphicsEnvironment::dispose() {
|
||||
_ge_instance.reset();
|
||||
}
|
||||
|
||||
VKDevice& VKGraphicsEnvironment::default_device() {
|
||||
return *_default_device;
|
||||
}
|
||||
|
||||
// ========== Vulkan device ==========
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
extern struct wl_display *wl_display;
|
||||
#endif
|
||||
|
||||
VKDevice::VKDevice(vk::Instance instance, vk::raii::PhysicalDevice&& handle) :
|
||||
vk::raii::Device(nullptr), vk::raii::PhysicalDevice(nullptr), _instance(instance) {
|
||||
auto featuresChain = handle.getFeatures2<vk::PhysicalDeviceFeatures2,
|
||||
vk::PhysicalDeviceVulkan11Features,
|
||||
vk::PhysicalDeviceVulkan12Features>();
|
||||
const auto& features10 = featuresChain.get<vk::PhysicalDeviceFeatures2>().features;
|
||||
const auto& features11 = featuresChain.get<vk::PhysicalDeviceVulkan11Features>();
|
||||
const auto& features12 = featuresChain.get<vk::PhysicalDeviceVulkan12Features>();
|
||||
|
||||
auto propertiesChain = handle.getProperties2<vk::PhysicalDeviceProperties2,
|
||||
vk::PhysicalDeviceVulkan11Properties,
|
||||
vk::PhysicalDeviceVulkan12Properties>();
|
||||
const auto& properties10 = propertiesChain.get<vk::PhysicalDeviceProperties2>().properties;
|
||||
const auto& properties11 = propertiesChain.get<vk::PhysicalDeviceVulkan11Properties>();
|
||||
const auto& properties12 = propertiesChain.get<vk::PhysicalDeviceVulkan12Properties>();
|
||||
|
||||
const auto& queueFamilies = handle.getQueueFamilyProperties();
|
||||
|
||||
_name = (const char*) properties10.deviceName;
|
||||
J2dRlsTrace5(J2D_TRACE_INFO, "Vulkan: Found device %s (%d.%d.%d, %s)\n",
|
||||
(const char*) properties10.deviceName,
|
||||
VK_API_VERSION_MAJOR(properties10.apiVersion),
|
||||
VK_API_VERSION_MINOR(properties10.apiVersion),
|
||||
VK_API_VERSION_PATCH(properties10.apiVersion),
|
||||
vk::to_string(properties10.deviceType).c_str());
|
||||
|
||||
// Check API version.
|
||||
if (properties10.apiVersion < REQUIRED_VULKAN_VERSION) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, " Unsupported Vulkan version\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check supported features.
|
||||
if (!features10.logicOp) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, " Logic op not supported\n");
|
||||
return;
|
||||
}
|
||||
if (!features12.timelineSemaphore) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, " Timeline semaphore not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check supported queue families.
|
||||
for (unsigned int i = 0; i < queueFamilies.size(); i++) {
|
||||
const auto& family = queueFamilies[i];
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
bool presentationSupported = handle.getWaylandPresentationSupportKHR(i, *wl_display);
|
||||
#endif
|
||||
char logFlags[5] {
|
||||
family.queueFlags & vk::QueueFlagBits::eGraphics ? 'G' : '-',
|
||||
family.queueFlags & vk::QueueFlagBits::eCompute ? 'C' : '-',
|
||||
family.queueFlags & vk::QueueFlagBits::eTransfer ? 'T' : '-',
|
||||
family.queueFlags & vk::QueueFlagBits::eSparseBinding ? 'S' : '-',
|
||||
presentationSupported ? 'P' : '-'
|
||||
};
|
||||
J2dRlsTrace3(J2D_TRACE_INFO, " %d queues in family (%.*s)\n", family.queueCount, 5, logFlags);
|
||||
|
||||
// TODO use compute workloads? Separate transfer-only DMA queue?
|
||||
if (_queue_family == -1 && (family.queueFlags & vk::QueueFlagBits::eGraphics) && presentationSupported) {
|
||||
_queue_family = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (_queue_family == -1) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, " No suitable queue\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Populate maps and log supported layers & extensions.
|
||||
std::set<std::string> layers, extensions;
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported device layers:\n");
|
||||
for (auto& l : handle.enumerateDeviceLayerProperties()) {
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char*) l.layerName);
|
||||
layers.emplace((char*) l.layerName);
|
||||
}
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported device extensions:\n");
|
||||
for (auto& e : handle.enumerateDeviceExtensionProperties(nullptr)) {
|
||||
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char*) e.extensionName);
|
||||
extensions.emplace((char*) e.extensionName);
|
||||
}
|
||||
|
||||
// Check required layers & extensions.
|
||||
_enabled_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
bool requiredNotFound = false;
|
||||
for (auto e : _enabled_extensions) {
|
||||
if (extensions.find(e) == extensions.end()) {
|
||||
J2dRlsTrace1(J2D_TRACE_INFO, " Required device extension not supported: %s\n", (char*) e);
|
||||
requiredNotFound = true;
|
||||
}
|
||||
}
|
||||
if (requiredNotFound) return;
|
||||
_ext_memory_budget = extensions.find(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) != extensions.end();
|
||||
if (_ext_memory_budget) _enabled_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
|
||||
_khr_synchronization2 = extensions.find(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME) != extensions.end();
|
||||
if (_khr_synchronization2) _enabled_extensions.push_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
|
||||
_khr_dynamic_rendering = extensions.find(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME) != extensions.end();
|
||||
if (_khr_dynamic_rendering) _enabled_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
||||
|
||||
// Validation layer
|
||||
#ifdef DEBUG
|
||||
if (layers.find(VALIDATION_LAYER_NAME) != layers.end()) {
|
||||
_enabled_layers.push_back(VALIDATION_LAYER_NAME);
|
||||
} else {
|
||||
J2dRlsTrace1(J2D_TRACE_INFO, " %s device layer is not supported\n", VALIDATION_LAYER_NAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
// This device is supported
|
||||
((vk::raii::PhysicalDevice&) *this) = std::move(handle);
|
||||
}
|
||||
|
||||
void VKDevice::init() {
|
||||
float queuePriorities[1] {1.0f}; // We only use one queue for now
|
||||
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
|
||||
queueCreateInfos.push_back(vk::DeviceQueueCreateInfo {
|
||||
{}, queue_family(), 1, &queuePriorities[0]
|
||||
});
|
||||
|
||||
vk::PhysicalDeviceFeatures features10;
|
||||
features10.logicOp = true;
|
||||
vk::PhysicalDeviceVulkan12Features features12;
|
||||
features12.timelineSemaphore = true;
|
||||
|
||||
void *pNext = &features12;
|
||||
vk::PhysicalDeviceSynchronization2FeaturesKHR synchronization2Features;
|
||||
if (_khr_synchronization2) {
|
||||
synchronization2Features.synchronization2 = true;
|
||||
synchronization2Features.pNext = pNext;
|
||||
pNext = &synchronization2Features;
|
||||
}
|
||||
vk::PhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeatures;
|
||||
if (_khr_dynamic_rendering) {
|
||||
dynamicRenderingFeatures.dynamicRendering = true;
|
||||
dynamicRenderingFeatures.pNext = pNext;
|
||||
pNext = &dynamicRenderingFeatures;
|
||||
}
|
||||
|
||||
vk::DeviceCreateInfo deviceCreateInfo {
|
||||
/*flags*/ {},
|
||||
/*pQueueCreateInfos*/ queueCreateInfos,
|
||||
/*ppEnabledLayerNames*/ _enabled_layers,
|
||||
/*ppEnabledExtensionNames*/ _enabled_extensions,
|
||||
/*pEnabledFeatures*/ &features10,
|
||||
/*pNext*/ pNext
|
||||
};
|
||||
((vk::raii::Device&) *this) = {*this, deviceCreateInfo};
|
||||
_memory.init(_instance, *this, *this, REQUIRED_VULKAN_VERSION, _ext_memory_budget);
|
||||
_pipelines.init((vk::raii::Device&) *this, _khr_dynamic_rendering);
|
||||
_queue = getQueue(queue_family(), 0);
|
||||
_commandPool = createCommandPool(vk::CommandPoolCreateInfo {
|
||||
vk::CommandPoolCreateFlagBits::eTransient | vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
|
||||
queue_family()
|
||||
});
|
||||
vk::SemaphoreTypeCreateInfo semaphoreTypeCreateInfo { vk::SemaphoreType::eTimeline, 0 };
|
||||
_timelineSemaphore = createSemaphore(vk::SemaphoreCreateInfo {{}, &semaphoreTypeCreateInfo});
|
||||
_timelineCounter = 0;
|
||||
J2dRlsTrace1(J2D_TRACE_INFO, "Vulkan: Device created %s\n", _name.c_str());
|
||||
}
|
||||
|
||||
VKBuffer VKDevice::getVertexBuffer() {
|
||||
auto b = popPending<VKBuffer>(_pendingVertexBuffers);
|
||||
if (*b) {
|
||||
b.position() = 0;
|
||||
return b;
|
||||
} else {
|
||||
return _memory.allocateBuffer(64 * 1024, vk::BufferUsageFlagBits::eVertexBuffer,
|
||||
vma::AllocationCreateFlagBits::eMapped | vma::AllocationCreateFlagBits::eHostAccessSequentialWrite,
|
||||
vma::MemoryUsage::eAutoPreferHost);
|
||||
}
|
||||
}
|
||||
|
||||
vk::raii::CommandBuffer VKDevice::getCommandBuffer(vk::CommandBufferLevel level) {
|
||||
auto b = popPending<vk::raii::CommandBuffer>(level == vk::CommandBufferLevel::ePrimary ?
|
||||
_pendingPrimaryBuffers : _pendingSecondaryBuffers);
|
||||
if (*b) {
|
||||
b.reset({});
|
||||
return b;
|
||||
} else {
|
||||
return std::move(allocateCommandBuffers({*_commandPool, level, 1})[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void VKDevice::submitCommandBuffer(vk::raii::CommandBuffer&& primary,
|
||||
std::vector<vk::raii::CommandBuffer>& secondary,
|
||||
std::vector<VKBuffer>& vertexBuffers,
|
||||
std::vector<vk::Semaphore>& waitSemaphores,
|
||||
std::vector<vk::PipelineStageFlags>& waitStages,
|
||||
std::vector<vk::Semaphore>& signalSemaphores) {
|
||||
_timelineCounter++;
|
||||
signalSemaphores.insert(signalSemaphores.begin(), *_timelineSemaphore);
|
||||
vk::TimelineSemaphoreSubmitInfo timelineInfo { 0, nullptr, (uint32_t) signalSemaphores.size(), &_timelineCounter };
|
||||
queue().submit(vk::SubmitInfo {
|
||||
waitSemaphores, waitStages, *primary, signalSemaphores, &timelineInfo
|
||||
}, nullptr);
|
||||
pushPending(_pendingPrimaryBuffers, std::move(primary));
|
||||
pushPending(_pendingSecondaryBuffers, secondary);
|
||||
pushPending(_pendingVertexBuffers, vertexBuffers);
|
||||
signalSemaphores.clear();
|
||||
waitSemaphores.clear();
|
||||
waitStages.clear();
|
||||
}
|
||||
|
||||
extern "C" jboolean VK_Init(jboolean verbose, jint requestedDevice) {
|
||||
VKGraphicsEnvironment::set_verbose(verbose);
|
||||
VKGraphicsEnvironment::set_requested_device(requestedDevice);
|
||||
if (VKGraphicsEnvironment::graphics_environment() != nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
VKGraphicsEnvironment::dispose();
|
||||
}
|
||||
@@ -26,139 +26,124 @@
|
||||
|
||||
#ifndef VKBase_h_Included
|
||||
#define VKBase_h_Included
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VULKAN_HPP_NO_DEFAULT_DISPATCHER
|
||||
#include <queue>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "CArrayUtil.h"
|
||||
#include "jni.h"
|
||||
#include "VKMemory.h"
|
||||
#include "VKPipeline.h"
|
||||
#include "VKBuffer.h"
|
||||
|
||||
class VKDevice : public vk::raii::Device, public vk::raii::PhysicalDevice {
|
||||
friend class VKGraphicsEnvironment;
|
||||
typedef char* pchar;
|
||||
|
||||
vk::Instance _instance;
|
||||
std::string _name;
|
||||
std::vector<const char*> _enabled_layers, _enabled_extensions;
|
||||
bool _ext_memory_budget, _khr_synchronization2, _khr_dynamic_rendering;
|
||||
int _queue_family = -1;
|
||||
typedef struct {
|
||||
VkRenderPass renderPass;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
VkDescriptorPool descriptorPool;
|
||||
VkDescriptorSet descriptorSets;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkPipeline graphicsPipeline;
|
||||
} VKRenderer;
|
||||
|
||||
// Logical device state
|
||||
VKMemory _memory;
|
||||
VKPipelines _pipelines;
|
||||
vk::raii::Queue _queue = nullptr;
|
||||
vk::raii::CommandPool _commandPool = nullptr;
|
||||
vk::raii::Semaphore _timelineSemaphore = nullptr;
|
||||
uint64_t _timelineCounter = 0;
|
||||
uint64_t _lastReadTimelineCounter = 0;
|
||||
typedef struct {
|
||||
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;
|
||||
} VKLogicalDevice;
|
||||
|
||||
template <typename T> struct Pending {
|
||||
T resource;
|
||||
uint64_t counter;
|
||||
using Queue = std::queue<Pending<T>>;
|
||||
};
|
||||
Pending<vk::raii::CommandBuffer>::Queue _pendingPrimaryBuffers, _pendingSecondaryBuffers;
|
||||
Pending<VKBuffer>::Queue _pendingVertexBuffers;
|
||||
|
||||
template <typename T> T popPending(typename Pending<T>::Queue& queue) {
|
||||
if (!queue.empty()) {
|
||||
auto& f = queue.front();
|
||||
if (_lastReadTimelineCounter >= f.counter ||
|
||||
(_lastReadTimelineCounter = _timelineSemaphore.getCounterValue()) >= f.counter) {
|
||||
T resource = std::move(f.resource);
|
||||
queue.pop();
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
return T(nullptr);
|
||||
}
|
||||
template <typename T> void pushPending(typename Pending<T>::Queue& queue, T&& resource) {
|
||||
queue.push({std::move(resource), _timelineCounter});
|
||||
}
|
||||
template <typename T> void pushPending(typename Pending<T>::Queue& queue, std::vector<T>& resources) {
|
||||
for (T& r : resources) {
|
||||
pushPending(queue, std::move(r));
|
||||
}
|
||||
resources.clear();
|
||||
}
|
||||
typedef struct {
|
||||
VkInstance vkInstance;
|
||||
VkPhysicalDevice* physicalDevices;
|
||||
VKLogicalDevice* devices;
|
||||
uint32_t enabledDeviceNum;
|
||||
VkExtensionProperties* extensions;
|
||||
VkLayerProperties* layers;
|
||||
|
||||
explicit VKDevice(vk::Instance instance, vk::raii::PhysicalDevice&& handle);
|
||||
public:
|
||||
|
||||
bool synchronization2() {
|
||||
return _khr_synchronization2;
|
||||
}
|
||||
|
||||
bool dynamicRendering() {
|
||||
return _khr_dynamic_rendering;
|
||||
}
|
||||
|
||||
VKPipelines& pipelines() {
|
||||
return _pipelines;
|
||||
}
|
||||
|
||||
uint32_t queue_family() const {
|
||||
return (uint32_t) _queue_family;
|
||||
}
|
||||
|
||||
const vk::raii::Queue& queue() const {
|
||||
return _queue;
|
||||
}
|
||||
|
||||
void init(); // Creates actual logical device
|
||||
|
||||
VKBuffer getVertexBuffer();
|
||||
vk::raii::CommandBuffer getCommandBuffer(vk::CommandBufferLevel level);
|
||||
void submitCommandBuffer(vk::raii::CommandBuffer&& primary,
|
||||
std::vector<vk::raii::CommandBuffer>& secondary,
|
||||
std::vector<VKBuffer>& vertexBuffers,
|
||||
std::vector<vk::Semaphore>& waitSemaphores,
|
||||
std::vector<vk::PipelineStageFlags>& waitStages,
|
||||
std::vector<vk::Semaphore>& signalSemaphores);
|
||||
|
||||
bool supported() const { // Supported or not
|
||||
return *((const vk::raii::PhysicalDevice&) *this);
|
||||
}
|
||||
|
||||
explicit operator bool() const { // Initialized or not
|
||||
return *((const vk::raii::Device&) *this);
|
||||
}
|
||||
|
||||
const std::string& name() {
|
||||
return _name;
|
||||
}
|
||||
};
|
||||
|
||||
class VKGraphicsEnvironment {
|
||||
vk::raii::Context _vk_context;
|
||||
vk::raii::Instance _vk_instance;
|
||||
#if defined(DEBUG)
|
||||
vk::raii::DebugUtilsMessengerEXT _debugMessenger = nullptr;
|
||||
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
|
||||
PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2;
|
||||
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
|
||||
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
|
||||
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
|
||||
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR;
|
||||
PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
|
||||
#endif
|
||||
std::vector<std::unique_ptr<VKDevice>> _devices;
|
||||
VKDevice* _default_device;
|
||||
static bool _verbose;
|
||||
static int _requested_device_number;
|
||||
static std::unique_ptr<VKGraphicsEnvironment> _ge_instance;
|
||||
VKGraphicsEnvironment();
|
||||
public:
|
||||
static void set_verbose(bool verbose) { _verbose = verbose; }
|
||||
static void set_requested_device(int requested_device) { _requested_device_number = requested_device; }
|
||||
static VKGraphicsEnvironment* graphics_environment();
|
||||
static void dispose();
|
||||
VKDevice& default_device();
|
||||
vk::raii::Instance& vk_instance();
|
||||
};
|
||||
PFN_vkCreateShaderModule vkCreateShaderModule;
|
||||
PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
|
||||
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
|
||||
PFN_vkDestroyShaderModule vkDestroyShaderModule;
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
|
||||
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
|
||||
PFN_vkCreateImageView vkCreateImageView;
|
||||
PFN_vkCreateFramebuffer vkCreateFramebuffer;
|
||||
PFN_vkCreateCommandPool vkCreateCommandPool;
|
||||
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
|
||||
PFN_vkCreateSemaphore vkCreateSemaphore;
|
||||
PFN_vkCreateFence vkCreateFence;
|
||||
PFN_vkGetDeviceQueue vkGetDeviceQueue;
|
||||
PFN_vkWaitForFences vkWaitForFences;
|
||||
PFN_vkResetFences vkResetFences;
|
||||
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
|
||||
PFN_vkResetCommandBuffer vkResetCommandBuffer;
|
||||
PFN_vkQueueSubmit vkQueueSubmit;
|
||||
PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||
PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
|
||||
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
|
||||
PFN_vkCmdBindPipeline vkCmdBindPipeline;
|
||||
PFN_vkCmdSetViewport vkCmdSetViewport;
|
||||
PFN_vkCmdSetScissor vkCmdSetScissor;
|
||||
PFN_vkCmdDraw vkCmdDraw;
|
||||
PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
|
||||
PFN_vkEndCommandBuffer vkEndCommandBuffer;
|
||||
PFN_vkCreateImage vkCreateImage;
|
||||
PFN_vkCreateSampler vkCreateSampler;
|
||||
PFN_vkAllocateMemory vkAllocateMemory;
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
|
||||
PFN_vkBindImageMemory vkBindImageMemory;
|
||||
PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
|
||||
PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
|
||||
PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
|
||||
PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
|
||||
PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
|
||||
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
|
||||
PFN_vkCreateBuffer vkCreateBuffer;
|
||||
PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
|
||||
PFN_vkBindBufferMemory vkBindBufferMemory;
|
||||
PFN_vkMapMemory vkMapMemory;
|
||||
PFN_vkUnmapMemory vkUnmapMemory;
|
||||
PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
|
||||
PFN_vkCreateRenderPass vkCreateRenderPass;
|
||||
PFN_vkDestroyBuffer vkDestroyBuffer;
|
||||
PFN_vkFreeMemory vkFreeMemory;
|
||||
PFN_vkDestroyImageView vkDestroyImageView;
|
||||
PFN_vkDestroyImage vkDestroyImage;
|
||||
PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
|
||||
PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges;
|
||||
PFN_vkCmdPushConstants vkCmdPushConstants;
|
||||
} VKGraphicsEnvironment;
|
||||
|
||||
extern "C" {
|
||||
#endif //__cplusplus
|
||||
|
||||
jboolean VK_Init(jboolean verbose, jint requestedDevice);
|
||||
jboolean VK_FindDevices();
|
||||
jboolean VK_CreateLogicalDevice(jint requestedDeviceNumber);
|
||||
jboolean VK_CreateLogicalDeviceRenderers();
|
||||
|
||||
VKGraphicsEnvironment* VKGE_graphics_environment();
|
||||
void* vulkanLibProc(VkInstance vkInstance, char* procName);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
#endif //VKBase_h_Included
|
||||
|
||||
149
src/java.desktop/share/native/common/java2d/vulkan/VKBuffer.c
Normal file
149
src/java.desktop/share/native/common/java2d/vulkan/VKBuffer.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <Trace.h>
|
||||
#include "CArrayUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKBuffer.h"
|
||||
|
||||
VkResult VKBuffer_FindMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter,
|
||||
VkMemoryPropertyFlags properties, uint32_t* pMemoryType) {
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
ge->vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
|
||||
|
||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
*pMemoryType = i;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
VKBuffer* VKBuffer_Create(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties)
|
||||
{
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
VKBuffer* buffer = malloc(sizeof (VKBuffer));
|
||||
|
||||
VkBufferCreateInfo bufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = size,
|
||||
.usage = usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
|
||||
if (ge->vkCreateBuffer(logicalDevice->device, &bufferInfo, NULL, &buffer->buffer) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to allocate descriptor sets!")
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer->size = size;
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
ge->vkGetBufferMemoryRequirements(logicalDevice->device, 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!")
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memRequirements.size,
|
||||
.memoryTypeIndex = memoryType
|
||||
};
|
||||
|
||||
if (ge->vkAllocateMemory(logicalDevice->device, &allocInfo, NULL, &buffer->memory) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to allocate buffer memory!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ge->vkBindBufferMemory(logicalDevice->device, buffer->buffer, buffer->memory, 0) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to bind buffer memory!");
|
||||
return NULL;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
VKBuffer* VKBuffer_CreateFromData(void* vertices, VkDeviceSize bufferSize)
|
||||
{
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
VKBuffer* buffer = VKBuffer_Create(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 (ge->vkMapMemory(logicalDevice->device, buffer->memory, 0, bufferSize, 0, &data) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to map memory!");
|
||||
return NULL;
|
||||
}
|
||||
memcpy(data, vertices, bufferSize);
|
||||
|
||||
VkMappedMemoryRange memoryRange = {
|
||||
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
|
||||
.pNext = NULL,
|
||||
.memory = buffer->memory,
|
||||
.offset = 0,
|
||||
.size = VK_WHOLE_SIZE
|
||||
};
|
||||
|
||||
|
||||
if (ge->vkFlushMappedMemoryRanges(logicalDevice->device, 1, &memoryRange) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to flush memory!");
|
||||
return NULL;
|
||||
}
|
||||
ge->vkUnmapMemory(logicalDevice->device, buffer->memory);
|
||||
buffer->size = bufferSize;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void VKBuffer_free(VKBuffer* buffer) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
if (buffer != NULL) {
|
||||
if (buffer->buffer != VK_NULL_HANDLE) {
|
||||
ge->vkDestroyBuffer(logicalDevice->device, buffer->buffer, NULL);
|
||||
}
|
||||
if (buffer->memory != VK_NULL_HANDLE) {
|
||||
ge->vkFreeMemory(logicalDevice->device, buffer->memory, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -24,24 +24,23 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "VKShader.h"
|
||||
#ifndef VKBuffer_h_Included
|
||||
#define VKBuffer_h_Included
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
// Inline bytecode of all shaders
|
||||
#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
|
||||
typedef struct {
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceSize size;
|
||||
} VKBuffer;
|
||||
|
||||
void VKShaders::init(const vk::raii::Device& device) {
|
||||
// Declare file extensions as stage flags
|
||||
auto vert = vk::ShaderStageFlagBits::eVertex;
|
||||
auto frag = vk::ShaderStageFlagBits::eFragment;
|
||||
// Init all shader modules
|
||||
# define SHADER_ENTRY(NAME, TYPE) \
|
||||
NAME ## _ ## TYPE.init(device, sizeof NAME ## _ ## TYPE ## _data, NAME ## _ ## TYPE ## _data, TYPE);
|
||||
# include "vulkan/shader_list.h"
|
||||
# undef SHADER_ENTRY
|
||||
}
|
||||
VkResult VKBuffer_FindMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter,
|
||||
VkMemoryPropertyFlags properties, uint32_t* pMemoryType);
|
||||
|
||||
VKBuffer* VKBuffer_Create(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties);
|
||||
|
||||
VKBuffer* VKBuffer_CreateFromData(void* vertices, VkDeviceSize bufferSize);
|
||||
|
||||
void VKBuffer_free(VKBuffer* buffer);
|
||||
|
||||
#endif // VKBuffer_h_Included
|
||||
233
src/java.desktop/share/native/common/java2d/vulkan/VKImage.c
Normal file
233
src/java.desktop/share/native/common/java2d/vulkan/VKImage.c
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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 <Trace.h>
|
||||
#include "VKBase.h"
|
||||
#include "VKBuffer.h"
|
||||
#include "VKImage.h"
|
||||
|
||||
|
||||
VkBool32 VKImage_CreateView(VKImage* image) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = image->image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = image->format,
|
||||
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.subresourceRange.baseMipLevel = 0,
|
||||
.subresourceRange.levelCount = 1,
|
||||
.subresourceRange.baseArrayLayer = 0,
|
||||
.subresourceRange.layerCount = 1,
|
||||
};
|
||||
|
||||
if (ge->vkCreateImageView(logicalDevice->device, &viewInfo, NULL, &image->view) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot surface image view\n");
|
||||
return VK_FALSE;
|
||||
}
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
VkBool32 VKImage_CreateFramebuffer(VKImage *image, VkRenderPass renderPass) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
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 (ge->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(uint32_t width, uint32_t height,
|
||||
VkFormat format, VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties)
|
||||
{
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
VKImage* image = malloc(sizeof (VKImage));
|
||||
|
||||
if (!image) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot allocate data for image")
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image->format = format;
|
||||
image->extent = (VkExtent2D) {width, height};
|
||||
|
||||
VkImageCreateInfo imageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.extent.width = width,
|
||||
.extent.height = height,
|
||||
.extent.depth = 1,
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.format = format,
|
||||
.tiling = tiling,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.usage = usage,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
};
|
||||
|
||||
if (ge->vkCreateImage(logicalDevice->device, &imageInfo, NULL, &image->image) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot create surface image")
|
||||
VKImage_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
ge->vkGetImageMemoryRequirements(logicalDevice->device, image->image, &memRequirements);
|
||||
|
||||
uint32_t memoryType;
|
||||
if (VKBuffer_FindMemoryType(logicalDevice->physicalDevice,
|
||||
memRequirements.memoryTypeBits,
|
||||
properties, &memoryType) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Failed to find memory")
|
||||
VKImage_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memRequirements.size,
|
||||
.memoryTypeIndex = memoryType
|
||||
};
|
||||
|
||||
if (ge->vkAllocateMemory(logicalDevice->device, &allocInfo, NULL, &image->memory) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Failed to allocate image memory");
|
||||
VKImage_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ge->vkBindImageMemory(logicalDevice->device, image->image, image->memory, 0);
|
||||
|
||||
if (!VKImage_CreateView(image)) {
|
||||
VKImage_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
VKImage* VKImage_CreateImageArrayFromSwapChain(VkSwapchainKHR swapchainKhr, VkRenderPass renderPass,
|
||||
VkFormat format, VkExtent2D extent)
|
||||
{
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
uint32_t swapChainImagesCount;
|
||||
if (ge->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 (ge->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(&ARRAY_LAST(images))) {
|
||||
ARRAY_APPLY(images, VKImage_dealloc);
|
||||
ARRAY_FREE(images);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!VKImage_CreateFramebuffer(&ARRAY_LAST(images), renderPass)) {
|
||||
ARRAY_APPLY(images, VKImage_dealloc);
|
||||
ARRAY_FREE(images);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
void VKImage_dealloc(VKImage* image) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
if (!image) return;
|
||||
|
||||
if (image->framebuffer != VK_NULL_HANDLE) {
|
||||
ge->vkDestroyFramebuffer(logicalDevice->device, image->framebuffer, NULL);
|
||||
}
|
||||
|
||||
if (image->view != VK_NULL_HANDLE) {
|
||||
ge->vkDestroyImageView(logicalDevice->device, image->view, NULL);
|
||||
}
|
||||
|
||||
if (image->memory != VK_NULL_HANDLE) {
|
||||
ge->vkFreeMemory(logicalDevice->device, image->memory, NULL);
|
||||
}
|
||||
|
||||
if (image->image != VK_NULL_HANDLE && !image->noImageDealloc) {
|
||||
ge->vkDestroyImage(logicalDevice->device, image->image, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void VKImage_free(VKImage* image) {
|
||||
VKImage_dealloc(image);
|
||||
free(image);
|
||||
}
|
||||
56
src/java.desktop/share/native/common/java2d/vulkan/VKImage.h
Normal file
56
src/java.desktop/share/native/common/java2d/vulkan/VKImage.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 VKImage_h_Included
|
||||
#define VKImage_h_Included
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
typedef struct {
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
VkFramebuffer framebuffer;
|
||||
VkImageView view;
|
||||
VkFormat format;
|
||||
VkExtent2D extent;
|
||||
VkBool32 noImageDealloc;
|
||||
} VKImage;
|
||||
|
||||
VKImage* VKImage_Create(uint32_t width, uint32_t height,
|
||||
VkFormat format, VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties);
|
||||
|
||||
VKImage* VKImage_CreateImageArrayFromSwapChain(VkSwapchainKHR swapchainKhr,
|
||||
VkRenderPass renderPass,
|
||||
VkFormat format,
|
||||
VkExtent2D extent);
|
||||
|
||||
VkBool32 VKImage_CreateFramebuffer(VKImage *image, VkRenderPass renderPass);
|
||||
|
||||
void VKImage_free(VKImage* image);
|
||||
void VKImage_dealloc(VKImage* image);
|
||||
#endif // VKImage_h_Included
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -24,7 +24,9 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
#include "VKBase.h"
|
||||
#ifndef VKInit_h_Included
|
||||
#define VKInit_h_Included
|
||||
|
||||
// TODO ?
|
||||
jboolean VK_Init(jboolean verbose, jint requestedDevice);
|
||||
|
||||
#endif //VKInit_h_Included
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include "VKMemory.h"
|
||||
|
||||
void VKMemory::init(vk::Instance instance, const vk::raii::PhysicalDevice& physicalDevice,
|
||||
const vk::raii::Device& device, uint32_t apiVersion, bool extMemoryBudget) {
|
||||
vma::VulkanFunctions functions = vma::functionsFromDispatcher(physicalDevice.getDispatcher(), device.getDispatcher());
|
||||
vma::AllocatorCreateInfo createInfo {};
|
||||
createInfo.instance = instance;
|
||||
createInfo.physicalDevice = *physicalDevice;
|
||||
createInfo.device = *device;
|
||||
createInfo.pVulkanFunctions = &functions;
|
||||
createInfo.vulkanApiVersion = apiVersion;
|
||||
if (extMemoryBudget) {
|
||||
createInfo.flags |= vma::AllocatorCreateFlagBits::eExtMemoryBudget;
|
||||
}
|
||||
_allocator = vma::createAllocatorUnique(createInfo);
|
||||
*((vma::Allocator*) this) = *_allocator;
|
||||
}
|
||||
|
||||
VKBuffer VKMemory::allocateBuffer(uint32_t size, vk::BufferUsageFlags usage,
|
||||
vma::AllocationCreateFlags flags, vma::MemoryUsage memoryUsage) {
|
||||
VKBuffer b = nullptr;
|
||||
auto pair = createBufferUnique(vk::BufferCreateInfo {
|
||||
{}, size, usage, vk::SharingMode::eExclusive, {}
|
||||
}, vma::AllocationCreateInfo {
|
||||
flags,
|
||||
memoryUsage, {}, {}, (uint32_t) -1
|
||||
}, b._allocationInfo);
|
||||
b._buffer = std::move(pair.first);
|
||||
b._allocation = std::move(pair.second);
|
||||
b._size = size;
|
||||
return b;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 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 VKMemory_h_Included
|
||||
#define VKMemory_h_Included
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VULKAN_HPP_NO_DEFAULT_DISPATCHER
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
#include <vk_mem_alloc.hpp>
|
||||
|
||||
class VKBuffer {
|
||||
friend class VKMemory;
|
||||
vma::UniqueBuffer _buffer;
|
||||
vma::UniqueAllocation _allocation;
|
||||
vma::AllocationInfo _allocationInfo;
|
||||
uint32_t _size = 0;
|
||||
uint32_t _position = 0;
|
||||
public:
|
||||
VKBuffer(nullptr_t) {}
|
||||
vk::Buffer operator*() const {
|
||||
return *_buffer;
|
||||
}
|
||||
uint32_t size() const {
|
||||
return _size;
|
||||
}
|
||||
uint32_t& position() {
|
||||
return _position;
|
||||
}
|
||||
void* data() {
|
||||
return _allocationInfo.pMappedData;
|
||||
}
|
||||
};
|
||||
|
||||
class VKMemory : vma::Allocator {
|
||||
vma::UniqueAllocator _allocator;
|
||||
|
||||
public:
|
||||
void init(vk::Instance instance, const vk::raii::PhysicalDevice& physicalDevice,
|
||||
const vk::raii::Device& device, uint32_t apiVersion, bool extMemoryBudget);
|
||||
|
||||
VKBuffer allocateBuffer(uint32_t size, vk::BufferUsageFlags usage,
|
||||
vma::AllocationCreateFlags flags, vma::MemoryUsage memoryUsage);
|
||||
};
|
||||
|
||||
#endif //VKMemory_h_Included
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 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 "VKPipeline.h"
|
||||
|
||||
void VKPipelines::init(const vk::raii::Device& device, bool dynamicRendering) {
|
||||
shaders.init(device);
|
||||
|
||||
vk::Format format = vk::Format::eB8G8R8A8Unorm; // TODO
|
||||
|
||||
if (!dynamicRendering) {
|
||||
vk::AttachmentDescription attachmentDescription {
|
||||
/*flags*/ {},
|
||||
/*format*/ format,
|
||||
/*samples*/ vk::SampleCountFlagBits::e1,
|
||||
/*loadOp*/ vk::AttachmentLoadOp::eLoad,
|
||||
/*storeOp*/ vk::AttachmentStoreOp::eStore,
|
||||
/*stencilLoadOp*/ vk::AttachmentLoadOp::eDontCare,
|
||||
/*stencilStoreOp*/ vk::AttachmentStoreOp::eDontCare,
|
||||
/*initialLayout*/ vk::ImageLayout::eColorAttachmentOptimal,
|
||||
/*finalLayout*/ vk::ImageLayout::eColorAttachmentOptimal
|
||||
};
|
||||
vk::AttachmentReference attachmentReference { 0, vk::ImageLayout::eColorAttachmentOptimal };
|
||||
vk::SubpassDescription subpassDescription {
|
||||
/*flags*/ {},
|
||||
/*pipelineBindPoint*/ vk::PipelineBindPoint::eGraphics,
|
||||
/*inputAttachmentCount*/ 0,
|
||||
/*pInputAttachments*/ nullptr,
|
||||
/*colorAttachmentCount*/ 1,
|
||||
/*pColorAttachments*/ &attachmentReference,
|
||||
/*pResolveAttachments*/ nullptr,
|
||||
/*pDepthStencilAttachment*/ nullptr,
|
||||
/*preserveAttachmentCount*/ 0,
|
||||
/*pPreserveAttachments*/ nullptr,
|
||||
};
|
||||
// We don't know in advance, which operations to synchronize
|
||||
// with before and after the render pass, so do a full sync.
|
||||
std::array<vk::SubpassDependency, 2> subpassDependencies {vk::SubpassDependency{
|
||||
/*srcSubpass*/ VK_SUBPASS_EXTERNAL,
|
||||
/*dstSubpass*/ 0,
|
||||
/*srcStageMask*/ vk::PipelineStageFlagBits::eBottomOfPipe,
|
||||
/*dstStageMask*/ vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
/*srcAccessMask*/ {},
|
||||
/*dstAccessMask*/ vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
|
||||
/*dependencyFlags*/ {},
|
||||
}, vk::SubpassDependency{
|
||||
/*srcSubpass*/ 0,
|
||||
/*dstSubpass*/ VK_SUBPASS_EXTERNAL,
|
||||
/*srcStageMask*/ vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
/*dstStageMask*/ vk::PipelineStageFlagBits::eTopOfPipe,
|
||||
/*srcAccessMask*/ vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
|
||||
/*dstAccessMask*/ {},
|
||||
/*dependencyFlags*/ {},
|
||||
}};
|
||||
renderPass = device.createRenderPass(vk::RenderPassCreateInfo{
|
||||
/*flags*/ {},
|
||||
/*pAttachments*/ attachmentDescription,
|
||||
/*pSubpasses*/ subpassDescription,
|
||||
/*pDependencies*/ subpassDependencies
|
||||
});
|
||||
}
|
||||
|
||||
vk::PushConstantRange pushConstantRange {vk::ShaderStageFlagBits::eVertex, 0, sizeof(float) * 2};
|
||||
testLayout = device.createPipelineLayout(vk::PipelineLayoutCreateInfo {{}, {}, pushConstantRange});
|
||||
|
||||
std::array<vk::PipelineShaderStageCreateInfo, 2> testStages {shaders.test_vert.stage(), shaders.test_frag.stage()};
|
||||
vk::VertexInputBindingDescription vertexInputBindingDescription {0, 8, vk::VertexInputRate::eVertex};
|
||||
vk::VertexInputAttributeDescription vertexInputAttributeDescription {0, 0, vk::Format::eR32G32Sfloat, 0};
|
||||
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo {{}, vertexInputBindingDescription, vertexInputAttributeDescription};
|
||||
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo {{}, vk::PrimitiveTopology::eTriangleFan, false};
|
||||
vk::Viewport viewport;
|
||||
vk::Rect2D scissor;
|
||||
vk::PipelineViewportStateCreateInfo viewportStateCreateInfo {{}, viewport, scissor};
|
||||
vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo {
|
||||
{}, false, false, vk::PolygonMode::eFill, vk::CullModeFlagBits::eNone,
|
||||
vk::FrontFace::eClockwise, false, 0, 0, 0, 1
|
||||
};
|
||||
vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo {};
|
||||
vk::PipelineColorBlendAttachmentState colorBlendAttachmentState {false}; // TODO No blending yet
|
||||
colorBlendAttachmentState.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
|
||||
vk::PipelineColorBlendStateCreateInfo colorBlendStateCreateInfo {{}, false, vk::LogicOp::eXor, colorBlendAttachmentState};
|
||||
std::array<vk::DynamicState, 2> dynamicStates {vk::DynamicState::eViewport, vk::DynamicState::eScissor};
|
||||
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo {{}, dynamicStates};
|
||||
vk::PipelineRenderingCreateInfoKHR renderingCreateInfo {0, format};
|
||||
auto pipelines = device.createGraphicsPipelines(nullptr, {
|
||||
vk::GraphicsPipelineCreateInfo {
|
||||
{}, testStages,
|
||||
&vertexInputStateCreateInfo,
|
||||
&inputAssemblyStateCreateInfo,
|
||||
nullptr,
|
||||
&viewportStateCreateInfo,
|
||||
&rasterizationStateCreateInfo,
|
||||
&multisampleStateCreateInfo,
|
||||
nullptr,
|
||||
&colorBlendStateCreateInfo,
|
||||
&dynamicStateCreateInfo,
|
||||
*testLayout,
|
||||
*renderPass, 0, nullptr, 0,
|
||||
dynamicRendering ? &renderingCreateInfo : nullptr
|
||||
}
|
||||
});
|
||||
// TODO pipeline cache
|
||||
test = std::move(pipelines[0]);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -33,7 +33,9 @@
|
||||
#include "Trace.h"
|
||||
#include "jlong.h"
|
||||
#include "VKRenderQueue.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKVertex.h"
|
||||
|
||||
#define BYTES_PER_POLY_POINT \
|
||||
sun_java2d_pipe_BufferedRenderPipe_BYTES_PER_POLY_POINT
|
||||
@@ -61,12 +63,13 @@
|
||||
#define OFFSET_XFORM sun_java2d_vulkan_VKBlitLoops_OFFSET_XFORM
|
||||
#define OFFSET_ISOBLIT sun_java2d_vulkan_VKBlitLoops_OFFSET_ISOBLIT
|
||||
|
||||
static VKRenderer renderer;
|
||||
static VKSDOps *dstOps = NULL;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
(JNIEnv *env, jobject oglrq,
|
||||
jlong buf, jint limit)
|
||||
// TODO move this property to special drawing context structure
|
||||
static int color = -1;
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
(JNIEnv *env, jobject oglrq, jlong buf, jint limit)
|
||||
{
|
||||
unsigned char *b, *end;
|
||||
|
||||
@@ -103,7 +106,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DRAW_LINE(%d, %d, %d, %d)",
|
||||
x1, y1, x2, y2);
|
||||
renderer.drawLine(x1, y1, x2, y2);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT:
|
||||
@@ -115,7 +117,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DRAW_RECT(%d, %d, %d, %d)",
|
||||
x, y, w, h);
|
||||
renderer.drawRect(x, y, w, h);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY:
|
||||
@@ -128,7 +129,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint *yPoints = ((jint *)b) + nPoints;
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: DRAW_POLY");
|
||||
SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT);
|
||||
renderer.drawPoly();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL:
|
||||
@@ -136,7 +136,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint x = NEXT_INT(b);
|
||||
jint y = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: DRAW_PIXEL");
|
||||
renderer.drawPixel(x, y);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES:
|
||||
@@ -144,7 +143,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint count = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: DRAW_SCANLINES");
|
||||
SKIP_BYTES(b, count * BYTES_PER_SCANLINE);
|
||||
renderer.drawScanlines();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM:
|
||||
@@ -160,7 +158,6 @@ 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);
|
||||
renderer.drawParallelogram(x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
|
||||
@@ -188,7 +185,7 @@ 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);
|
||||
renderer.fillRect(x, y, w, h);
|
||||
VKRenderer_FillRect(x, y, w, h);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
|
||||
@@ -197,7 +194,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_SPANS");
|
||||
SKIP_BYTES(b, count * BYTES_PER_SPAN);
|
||||
renderer.fillSpans();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM:
|
||||
@@ -211,7 +207,6 @@ 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);
|
||||
renderer.fillParallelogram(x11, y11, dx21, dy21, dx12, dy12);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
|
||||
@@ -225,7 +220,59 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn6(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_AAPARALLELOGRAM(%f, %f, %f, %f, %f, %f)",
|
||||
x11, y11, dx21, dy21, dx12, dy12);
|
||||
renderer.fillAAParallelogram(x11, y11, dx21, dy21, dx12, dy12);
|
||||
|
||||
// TODO: For now rendering bounding box. Implement correct rendering using shaders
|
||||
if (dstOps != NULL) {
|
||||
VKSDOps *vksdOps = (VKSDOps *)dstOps;
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
float width = vksdOps->width;
|
||||
float height = vksdOps->height;
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_AAPARALLELOGRAM(W=%f, H=%f)",
|
||||
width, height);
|
||||
VKCVertex* cVertices = ARRAY_ALLOC(VKCVertex, 4);
|
||||
float px11 = -1.0f + x11 / width;
|
||||
float py11 = -1.0f + y11 / height;
|
||||
float px21 = -1.0f + (x11 + dx21) / width;
|
||||
float py21 = -1.0f + (y11 + dy21) / height;
|
||||
|
||||
ARRAY_PUSH_BACK(&cVertices, ((VKCVertex){px11,
|
||||
py11,
|
||||
RGBA_TO_L4(color)}));
|
||||
ARRAY_PUSH_BACK(&cVertices, ((VKCVertex){px21,
|
||||
py11,
|
||||
RGBA_TO_L4(color)}));
|
||||
ARRAY_PUSH_BACK(&cVertices, ((VKCVertex){px11,
|
||||
py21,
|
||||
RGBA_TO_L4(color)}));
|
||||
ARRAY_PUSH_BACK(&cVertices, ((VKCVertex){px21,
|
||||
py21,
|
||||
RGBA_TO_L4(color)}));
|
||||
J2dRlsTraceLn5(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_AAPARALLELOGRAM(color=%x, px11=%f, py11=%f, px21=%f, py21=%f)",
|
||||
color, px11, py11, px21, py21);
|
||||
VKBuffer* fillVertexBuffer = ARRAY_TO_VERTEX_BUF(cVertices);
|
||||
if (!fillVertexBuffer) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot create vertex buffer\n")
|
||||
break;
|
||||
}
|
||||
ARRAY_FREE(cVertices);
|
||||
|
||||
ge->vkWaitForFences(logicalDevice->device, 1, &logicalDevice->inFlightFence, VK_TRUE, UINT64_MAX);
|
||||
ge->vkResetFences(logicalDevice->device, 1, &logicalDevice->inFlightFence);
|
||||
|
||||
ge->vkResetCommandBuffer(logicalDevice->commandBuffer, 0);
|
||||
|
||||
VKRenderer_BeginRendering();
|
||||
|
||||
VKRenderer_ColorRender(
|
||||
vksdOps->image,
|
||||
fillVertexBuffer->buffer, 4
|
||||
);
|
||||
|
||||
VKRenderer_EndRendering(VK_FALSE, VK_FALSE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -256,7 +303,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
}
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: DRAW_GLYPH_LIST");
|
||||
SKIP_BYTES(b, numGlyphs * bytesPerGlyph);
|
||||
renderer.drawGlyphList();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -272,7 +318,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn6(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: COPY_AREA(%d, %d, %d, %d, %d, %d)",
|
||||
x, y, w, h, dx, dy);
|
||||
renderer.copyArea(x, y, w, h, dx, dy);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_BLIT:
|
||||
@@ -298,7 +343,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jboolean isoblit = EXTRACT_BOOLEAN(packedParams,
|
||||
OFFSET_ISOBLIT);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT");
|
||||
renderer.blit();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT:
|
||||
@@ -313,7 +357,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong pSrc = NEXT_LONG(b);
|
||||
jlong pDst = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: SURFACE_TO_SW_BLIT");
|
||||
renderer.surfaceToSwBlit();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
|
||||
@@ -328,7 +371,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
unsigned char *pMask = (masklen > 0) ? b : NULL;
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: MASK_FILL");
|
||||
SKIP_BYTES(b, masklen);
|
||||
renderer.maskFill();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT:
|
||||
@@ -340,7 +382,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint masklen = width * height * sizeof(jint);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: MASK_BLIT");
|
||||
SKIP_BYTES(b, masklen);
|
||||
renderer.maskBlit();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -354,14 +395,12 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_RECT_CLIP(%d, %d, %d, %d)",
|
||||
x1, y1, x2, y2);
|
||||
renderer.setRectClip(x1, y1, x2, y2);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: BEGIN_SHAPE_CLIP");
|
||||
renderer.beginShapeClip();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS:
|
||||
@@ -370,21 +409,18 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_SHAPE_CLIP_SPANS");
|
||||
SKIP_BYTES(b, count * BYTES_PER_SPAN);
|
||||
renderer.setShapeClipSpans();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: END_SHAPE_CLIP");
|
||||
renderer.endShapeClip();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_CLIP");
|
||||
renderer.resetClip();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE:
|
||||
@@ -394,7 +430,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint flags = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_ALPHA_COMPOSITE");
|
||||
renderer.setAlphaComposite();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
|
||||
@@ -402,14 +437,12 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint xorPixel = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_XOR_COMPOSITE");
|
||||
renderer.setXorComposite();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_COMPOSITE");
|
||||
renderer.resetComposite();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM:
|
||||
@@ -422,25 +455,40 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jdouble m12 = NEXT_DOUBLE(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_TRANSFORM");
|
||||
renderer.setTransform(m00, m10, m01, m11, m02, m12);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_TRANSFORM");
|
||||
renderer.resetTransform();
|
||||
}
|
||||
break;
|
||||
|
||||
// context-related ops
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES:
|
||||
{
|
||||
VKSurfaceData* src = NEXT_SURFACE(b);
|
||||
VKSurfaceData* dst = NEXT_SURFACE(b);
|
||||
VKSDOps* src = NEXT_SURFACE(b);
|
||||
VKSDOps* dst = NEXT_SURFACE(b);
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_SURFACES");
|
||||
renderer.setSurfaces(*src, *dst);
|
||||
dstOps = (VKSDOps *) jlong_to_ptr(dst);
|
||||
|
||||
if (dstOps != NULL && dstOps->drawableType == VKSD_WINDOW && dstOps->bgColorUpdated) {
|
||||
VKWinSDOps *winDstOps = (VKWinSDOps *)dstOps;
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
ge->vkWaitForFences(logicalDevice->device, 1, &logicalDevice->inFlightFence, VK_TRUE, UINT64_MAX);
|
||||
ge->vkResetFences(logicalDevice->device, 1, &logicalDevice->inFlightFence);
|
||||
|
||||
ge->vkResetCommandBuffer(logicalDevice->commandBuffer, 0);
|
||||
|
||||
VKRenderer_BeginRendering();
|
||||
|
||||
VKRenderer_ColorRenderMaxRect(winDstOps->vksdOps.image, winDstOps->vksdOps.bgColor);
|
||||
VKRenderer_EndRendering(VK_FALSE, VK_FALSE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
|
||||
@@ -448,15 +496,14 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_SCRATCH_SURFACE");
|
||||
renderer.setScratchSurface();
|
||||
dstOps = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
|
||||
{
|
||||
VKSurfaceData* surface = NEXT_SURFACE(b);
|
||||
VKSDOps* surface = NEXT_SURFACE(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FLUSH_SURFACE");
|
||||
renderer.flushSurface(*surface);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE:
|
||||
@@ -464,29 +511,27 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong pData = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DISPOSE_SURFACE");
|
||||
renderer.disposeSurface();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG:
|
||||
{
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DISPOSE_CONFIG");
|
||||
renderer.disposeConfig();
|
||||
"VKRenderQueue_flushBuffer: DISPOSE_CONFIG")
|
||||
dstOps = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: INVALIDATE_CONTEXT");
|
||||
renderer.invalidateContext();
|
||||
dstOps = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SYNC:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SYNC");
|
||||
renderer.sync();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -496,7 +541,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong window = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SWAP_BUFFERS");
|
||||
renderer.swapBuffers();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -513,15 +557,14 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_PAINT");
|
||||
renderer.resetPaint();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
|
||||
{
|
||||
jint pixel = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_COLOR");
|
||||
renderer.setColor((uint32_t) pixel);
|
||||
color = pixel;
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_COLOR %d", pixel);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
|
||||
@@ -535,7 +578,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint pixel2 = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_GRADIENT_PAINT");
|
||||
renderer.setGradientPaint();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT:
|
||||
@@ -552,7 +594,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
pixels = b; SKIP_BYTES(b, numStops * sizeof(jint));
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_LINEAR_GRADIENT_PAINT");
|
||||
renderer.setLinearGradientPaint();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_RADIAL_GRADIENT_PAINT:
|
||||
@@ -573,7 +614,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
pixels = b; SKIP_BYTES(b, numStops * sizeof(jint));
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_RADIAL_GRADIENT_PAINT");
|
||||
renderer.setRadialGradientPaint();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_TEXTURE_PAINT:
|
||||
@@ -589,7 +629,6 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jdouble yp3 = NEXT_DOUBLE(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_TEXTURE_PAINT");
|
||||
renderer.setTexturePaint();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -603,14 +642,12 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: ENABLE_CONVOLVE_OP");
|
||||
SKIP_BYTES(b, kernelWidth * kernelHeight * sizeof(jfloat));
|
||||
renderer.enableConvolveOp();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DISABLE_CONVOLVE_OP");
|
||||
renderer.disableConvolveOp();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_ENABLE_RESCALE_OP:
|
||||
@@ -623,14 +660,12 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: ENABLE_RESCALE_OP");
|
||||
SKIP_BYTES(b, numFactors * sizeof(jfloat) * 2);
|
||||
renderer.enableRescaleOp();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DISABLE_RESCALE_OP");
|
||||
renderer.disableRescaleOp();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_ENABLE_LOOKUP_OP:
|
||||
@@ -646,14 +681,12 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: ENABLE_LOOKUP_OP");
|
||||
SKIP_BYTES(b, numBands * bandLength * bytesPerElem);
|
||||
renderer.enableLookupOp();
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DISABLE_LOOKUP_OP");
|
||||
renderer.disableLookupOp();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -663,7 +696,46 @@ Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
return;
|
||||
}
|
||||
}
|
||||
renderer.flush();
|
||||
|
||||
if (dstOps != NULL && dstOps->drawableType == VKSD_WINDOW) {
|
||||
VKWinSDOps *winDstOps = (VKWinSDOps *)dstOps;
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
ge->vkWaitForFences(logicalDevice->device, 1, &logicalDevice->inFlightFence, VK_TRUE, UINT64_MAX);
|
||||
ge->vkResetFences(logicalDevice->device, 1, &logicalDevice->inFlightFence);
|
||||
|
||||
uint32_t imageIndex;
|
||||
ge->vkAcquireNextImageKHR(logicalDevice->device, winDstOps->swapchainKhr, UINT64_MAX,
|
||||
logicalDevice->imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
|
||||
|
||||
ge->vkResetCommandBuffer(logicalDevice->commandBuffer, 0);
|
||||
|
||||
VKRenderer_BeginRendering();
|
||||
|
||||
VKRenderer_TextureRender(
|
||||
&winDstOps->swapChainImages[imageIndex],
|
||||
winDstOps->vksdOps.image,
|
||||
logicalDevice->blitVertexBuffer->buffer, 4
|
||||
);
|
||||
|
||||
VKRenderer_EndRendering(VK_TRUE, VK_TRUE);
|
||||
|
||||
VkSemaphore signalSemaphores[] = {logicalDevice->renderFinishedSemaphore};
|
||||
|
||||
VkSwapchainKHR swapChains[] = {winDstOps->swapchainKhr};
|
||||
VkPresentInfoKHR presentInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = signalSemaphores,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = swapChains,
|
||||
.pImageIndices = &imageIndex
|
||||
};
|
||||
|
||||
ge->vkQueuePresentKHR(logicalDevice->queue, &presentInfo);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -38,12 +38,12 @@
|
||||
#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) ((VKSurfaceData*) (SurfaceDataOps*) jlong_to_ptr(NEXT_LONG(buf)))
|
||||
#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) += (numbytes)
|
||||
#define SKIP_BYTES(buf, numbytes) (buf) = ((unsigned char*)buf) + (numbytes)
|
||||
|
||||
/*
|
||||
* Extracts a value at the given offset from the provided packed value.
|
||||
|
||||
855
src/java.desktop/share/native/common/java2d/vulkan/VKRenderer.c
Normal file
855
src/java.desktop/share/native/common/java2d/vulkan/VKRenderer.c
Normal file
@@ -0,0 +1,855 @@
|
||||
/*
|
||||
* 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 <jlong.h>
|
||||
#include "Trace.h"
|
||||
#include "VKVertex.h"
|
||||
#include "VKRenderer.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
|
||||
|
||||
VkRenderPassCreateInfo* VKRenderer_GetGenericRenderPassInfo() {
|
||||
static VkAttachmentDescription colorAttachment = {
|
||||
.format = VK_FORMAT_B8G8R8A8_UNORM, //TODO: swapChain colorFormat
|
||||
.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_UNDEFINED,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
|
||||
};
|
||||
|
||||
static VkAttachmentReference colorReference = {
|
||||
.attachment = 0,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
};
|
||||
|
||||
static VkSubpassDescription subpassDescription = {
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.colorAttachmentCount = 1,
|
||||
.pColorAttachments = &colorReference
|
||||
};
|
||||
|
||||
// Subpass dependencies for layout transitions
|
||||
static 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
|
||||
};
|
||||
|
||||
static VkRenderPassCreateInfo renderPassInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &colorAttachment,
|
||||
.subpassCount = 1,
|
||||
.pSubpasses = &subpassDescription,
|
||||
.dependencyCount = 1,
|
||||
.pDependencies = &dependency
|
||||
};
|
||||
return &renderPassInfo;
|
||||
}
|
||||
|
||||
VkShaderModule createShaderModule(VkDevice device, uint32_t* shader, uint32_t sz) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VkShaderModuleCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = sz;
|
||||
createInfo.pCode = (uint32_t*)shader;
|
||||
VkShaderModule shaderModule;
|
||||
if (ge->vkCreateShaderModule(device, &createInfo, NULL, &shaderModule) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "failed to create shader module\n")
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
return shaderModule;
|
||||
}
|
||||
|
||||
VKRenderer* VKRenderer_CreateFillTexturePoly() {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
VKRenderer* fillTexturePoly = malloc(sizeof (VKRenderer ));
|
||||
|
||||
VkDevice device = logicalDevice->device;
|
||||
|
||||
if (ge->vkCreateRenderPass(logicalDevice->device, VKRenderer_GetGenericRenderPassInfo(),
|
||||
NULL, &fillTexturePoly->renderPass) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "Cannot create render pass for device")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// Create graphics pipeline
|
||||
VkShaderModule vertShaderModule = createShaderModule(device, blit_vert_data, sizeof (blit_vert_data));
|
||||
VkShaderModule fragShaderModule = createShaderModule(device, blit_frag_data, sizeof (blit_frag_data));
|
||||
|
||||
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = vertShaderModule,
|
||||
.pName = "main"
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo fragShaderStageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = fragShaderModule,
|
||||
.pName = "main"
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
|
||||
VKVertexDescr vertexDescr = VKVertex_GetTxVertexDescr();
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = vertexDescr.bindingDescriptionCount,
|
||||
.vertexAttributeDescriptionCount = vertexDescr.attributeDescriptionCount,
|
||||
.pVertexBindingDescriptions = vertexDescr.bindingDescriptions,
|
||||
.pVertexAttributeDescriptions = vertexDescr.attributeDescriptions
|
||||
};
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
||||
.primitiveRestartEnable = VK_FALSE
|
||||
};
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1,
|
||||
.scissorCount = 1
|
||||
};
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.rasterizerDiscardEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.lineWidth = 1.0f,
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
.depthBiasConstantFactor = 0.0f,
|
||||
.depthBiasClamp = 0.0f,
|
||||
.depthBiasSlopeFactor = 0.0f
|
||||
};
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.sampleShadingEnable = VK_FALSE,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
|
||||
};
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment = {
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||
VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT,
|
||||
.blendEnable = VK_FALSE
|
||||
};
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &colorBlendAttachment,
|
||||
.blendConstants[0] = 0.0f,
|
||||
.blendConstants[1] = 0.0f,
|
||||
.blendConstants[2] = 0.0f,
|
||||
.blendConstants[3] = 0.0f
|
||||
};
|
||||
|
||||
VkDynamicState dynamicStates[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR
|
||||
};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = dynamicStates
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutBinding samplerLayoutBinding = {
|
||||
.binding = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImmutableSamplers = NULL,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo layoutInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = 1,
|
||||
.pBindings = &samplerLayoutBinding
|
||||
};
|
||||
|
||||
if (ge->vkCreateDescriptorSetLayout(device, &layoutInfo, NULL, &fillTexturePoly->descriptorSetLayout) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "failed to create descriptor set layout!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &fillTexturePoly->descriptorSetLayout,
|
||||
.pushConstantRangeCount = 0
|
||||
};
|
||||
|
||||
if (ge->vkCreatePipelineLayout(device, &pipelineLayoutInfo, NULL,
|
||||
&fillTexturePoly->pipelineLayout) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "failed to create pipeline layout!\n")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.stageCount = 2,
|
||||
.pStages = shaderStages,
|
||||
.pVertexInputState = &vertexInputInfo,
|
||||
.pInputAssemblyState = &inputAssembly,
|
||||
.pViewportState = &viewportState,
|
||||
.pRasterizationState = &rasterizer,
|
||||
.pMultisampleState = &multisampling,
|
||||
.pColorBlendState = &colorBlending,
|
||||
.pDynamicState = &dynamicState,
|
||||
.layout = fillTexturePoly->pipelineLayout,
|
||||
.renderPass = fillTexturePoly->renderPass,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = -1
|
||||
};
|
||||
|
||||
if (ge->vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL,
|
||||
&fillTexturePoly->graphicsPipeline) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "failed to create graphics pipeline!\n")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
ge->vkDestroyShaderModule(device, fragShaderModule, NULL);
|
||||
ge->vkDestroyShaderModule(device, vertShaderModule, NULL);
|
||||
|
||||
VkSamplerCreateInfo samplerInfo = {
|
||||
.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,
|
||||
|
||||
.anisotropyEnable = VK_FALSE,
|
||||
.maxAnisotropy = 1.0f,
|
||||
|
||||
.compareEnable = VK_FALSE,
|
||||
.compareOp = VK_COMPARE_OP_ALWAYS,
|
||||
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
|
||||
.mipLodBias = 0.0f,
|
||||
.minLod = 0.0f,
|
||||
.maxLod = 0.0f
|
||||
};
|
||||
|
||||
if (ge->vkCreateSampler(device, &samplerInfo, NULL, &logicalDevice->textureSampler) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to create texture sampler!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
VkDescriptorPoolSize poolSize = {
|
||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo descrPoolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &poolSize,
|
||||
.maxSets = 1
|
||||
};
|
||||
|
||||
if (ge->vkCreateDescriptorPool(device, &descrPoolInfo, NULL, &fillTexturePoly->descriptorPool) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to create descriptor pool!")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
VkDescriptorSetAllocateInfo descrAllocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = fillTexturePoly->descriptorPool,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &fillTexturePoly->descriptorSetLayout
|
||||
};
|
||||
|
||||
if (ge->vkAllocateDescriptorSets(device, &descrAllocInfo, &fillTexturePoly->descriptorSets) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to allocate descriptor sets!");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return fillTexturePoly;
|
||||
}
|
||||
|
||||
|
||||
VKRenderer* VKRenderer_CreateFillColorPoly() {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
VKRenderer* fillColorPoly = malloc(sizeof (VKRenderer ));
|
||||
|
||||
VkDevice device = logicalDevice->device;
|
||||
|
||||
if (ge->vkCreateRenderPass(logicalDevice->device, VKRenderer_GetGenericRenderPassInfo(),
|
||||
NULL, &fillColorPoly->renderPass) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "Cannot create render pass for device")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// Create graphics pipeline
|
||||
VkShaderModule vertShaderModule = createShaderModule(device, color_vert_data, sizeof (color_vert_data));
|
||||
VkShaderModule fragShaderModule = createShaderModule(device, color_frag_data, sizeof (color_frag_data));
|
||||
|
||||
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = vertShaderModule,
|
||||
.pName = "main"
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo fragShaderStageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = fragShaderModule,
|
||||
.pName = "main"
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
|
||||
VKVertexDescr vertexDescr = VKVertex_GetCVertexDescr();
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = vertexDescr.bindingDescriptionCount,
|
||||
.vertexAttributeDescriptionCount = vertexDescr.attributeDescriptionCount,
|
||||
.pVertexBindingDescriptions = vertexDescr.bindingDescriptions,
|
||||
.pVertexAttributeDescriptions = vertexDescr.attributeDescriptions
|
||||
};
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
||||
.primitiveRestartEnable = VK_FALSE
|
||||
};
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1,
|
||||
.scissorCount = 1
|
||||
};
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.rasterizerDiscardEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.lineWidth = 1.0f,
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
.depthBiasConstantFactor = 0.0f,
|
||||
.depthBiasClamp = 0.0f,
|
||||
.depthBiasSlopeFactor = 0.0f
|
||||
};
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.sampleShadingEnable = VK_FALSE,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
|
||||
};
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment = {
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||
VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT,
|
||||
.blendEnable = VK_FALSE
|
||||
};
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &colorBlendAttachment,
|
||||
.blendConstants[0] = 0.0f,
|
||||
.blendConstants[1] = 0.0f,
|
||||
.blendConstants[2] = 0.0f,
|
||||
.blendConstants[3] = 0.0f
|
||||
};
|
||||
|
||||
VkDynamicState dynamicStates[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR
|
||||
};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = dynamicStates
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 0,
|
||||
.pushConstantRangeCount = 0
|
||||
};
|
||||
|
||||
if (ge->vkCreatePipelineLayout(device, &pipelineLayoutInfo, NULL,
|
||||
&fillColorPoly->pipelineLayout) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "failed to create pipeline layout!\n")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.stageCount = 2,
|
||||
.pStages = shaderStages,
|
||||
.pVertexInputState = &vertexInputInfo,
|
||||
.pInputAssemblyState = &inputAssembly,
|
||||
.pViewportState = &viewportState,
|
||||
.pRasterizationState = &rasterizer,
|
||||
.pMultisampleState = &multisampling,
|
||||
.pColorBlendState = &colorBlending,
|
||||
.pDynamicState = &dynamicState,
|
||||
.layout = fillColorPoly->pipelineLayout,
|
||||
.renderPass = fillColorPoly->renderPass,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = -1
|
||||
};
|
||||
|
||||
if (ge->vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL,
|
||||
&fillColorPoly->graphicsPipeline) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "failed to create graphics pipeline!\n")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
ge->vkDestroyShaderModule(device, fragShaderModule, NULL);
|
||||
ge->vkDestroyShaderModule(device, vertShaderModule, NULL);
|
||||
|
||||
return fillColorPoly;
|
||||
}
|
||||
|
||||
VKRenderer* VKRenderer_CreateFillMaxColorPoly() {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
VKRenderer* fillColorPoly = malloc(sizeof (VKRenderer ));
|
||||
|
||||
VkDevice device = logicalDevice->device;
|
||||
|
||||
if (ge->vkCreateRenderPass(logicalDevice->device, VKRenderer_GetGenericRenderPassInfo(),
|
||||
NULL, &fillColorPoly->renderPass) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "Cannot create render pass for device")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// Create graphics pipeline
|
||||
VkShaderModule vertShaderModule = createShaderModule(device, color_max_rect_vert_data, sizeof (color_max_rect_vert_data));
|
||||
VkShaderModule fragShaderModule = createShaderModule(device, color_max_rect_frag_data, sizeof (color_max_rect_frag_data));
|
||||
|
||||
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = vertShaderModule,
|
||||
.pName = "main"
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo fragShaderStageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = fragShaderModule,
|
||||
.pName = "main"
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = 0,
|
||||
.vertexAttributeDescriptionCount = 0,
|
||||
};
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
||||
.primitiveRestartEnable = VK_FALSE
|
||||
};
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1,
|
||||
.scissorCount = 1
|
||||
};
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.rasterizerDiscardEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.lineWidth = 1.0f,
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
.depthBiasConstantFactor = 0.0f,
|
||||
.depthBiasClamp = 0.0f,
|
||||
.depthBiasSlopeFactor = 0.0f
|
||||
};
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.sampleShadingEnable = VK_FALSE,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
|
||||
};
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment = {
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||
VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT,
|
||||
.blendEnable = VK_FALSE
|
||||
};
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &colorBlendAttachment,
|
||||
.blendConstants[0] = 0.0f,
|
||||
.blendConstants[1] = 0.0f,
|
||||
.blendConstants[2] = 0.0f,
|
||||
.blendConstants[3] = 0.0f
|
||||
};
|
||||
|
||||
VkDynamicState dynamicStates[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR
|
||||
};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = dynamicStates
|
||||
};
|
||||
|
||||
VkPushConstantRange pushConstantRange = {
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0,
|
||||
.size = sizeof(float) * 4
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 0,
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &pushConstantRange
|
||||
};
|
||||
|
||||
if (ge->vkCreatePipelineLayout(device, &pipelineLayoutInfo, NULL,
|
||||
&fillColorPoly->pipelineLayout) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "failed to create pipeline layout!\n")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.stageCount = 2,
|
||||
.pStages = shaderStages,
|
||||
.pVertexInputState = &vertexInputInfo,
|
||||
.pInputAssemblyState = &inputAssembly,
|
||||
.pViewportState = &viewportState,
|
||||
.pRasterizationState = &rasterizer,
|
||||
.pMultisampleState = &multisampling,
|
||||
.pColorBlendState = &colorBlending,
|
||||
.pDynamicState = &dynamicState,
|
||||
.layout = fillColorPoly->pipelineLayout,
|
||||
.renderPass = fillColorPoly->renderPass,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = -1
|
||||
};
|
||||
|
||||
if (ge->vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL,
|
||||
&fillColorPoly->graphicsPipeline) != VK_SUCCESS)
|
||||
{
|
||||
J2dRlsTrace(J2D_TRACE_INFO, "failed to create graphics pipeline!\n")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
ge->vkDestroyShaderModule(device, fragShaderModule, NULL);
|
||||
ge->vkDestroyShaderModule(device, vertShaderModule, NULL);
|
||||
|
||||
return fillColorPoly;
|
||||
}
|
||||
|
||||
void VKRenderer_BeginRendering() {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
VkCommandBufferBeginInfo beginInfo = {};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
|
||||
if (ge->vkBeginCommandBuffer(logicalDevice->commandBuffer, &beginInfo) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to begin recording command buffer!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void VKRenderer_EndRendering(VkBool32 notifyRenderFinish, VkBool32 waitForDisplayImage) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
if (ge->vkEndCommandBuffer(logicalDevice->commandBuffer) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "failed to record command buffer!")
|
||||
return;
|
||||
}
|
||||
|
||||
VkSemaphore waitSemaphores[] = {logicalDevice->imageAvailableSemaphore};
|
||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
VkSemaphore signalSemaphores[] = {logicalDevice->renderFinishedSemaphore};
|
||||
|
||||
VkSubmitInfo submitInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.waitSemaphoreCount = (waitForDisplayImage ? 1 : 0),
|
||||
.pWaitSemaphores = waitSemaphores,
|
||||
.pWaitDstStageMask = waitStages,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &logicalDevice->commandBuffer,
|
||||
.signalSemaphoreCount = (notifyRenderFinish ? 1 : 0),
|
||||
.pSignalSemaphores = signalSemaphores
|
||||
};
|
||||
|
||||
if (ge->vkQueueSubmit(logicalDevice->queue, 1, &submitInfo, logicalDevice->inFlightFence) != VK_SUCCESS) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,"failed to submit draw command buffer!")
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void VKRenderer_TextureRender(VKImage *destImage, VKImage *srcImage, VkBuffer vertexBuffer, uint32_t vertexNum)
|
||||
{
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
VkDescriptorImageInfo imageInfo = {
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.imageView = srcImage->view,
|
||||
.sampler = logicalDevice->textureSampler
|
||||
};
|
||||
|
||||
VkWriteDescriptorSet descriptorWrites = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = logicalDevice->fillTexturePoly->descriptorSets,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.pImageInfo = &imageInfo
|
||||
};
|
||||
|
||||
ge->vkUpdateDescriptorSets(logicalDevice->device, 1, &descriptorWrites, 0, NULL);
|
||||
|
||||
|
||||
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
VkRenderPassBeginInfo renderPassInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.renderPass = logicalDevice->fillTexturePoly->renderPass,
|
||||
.framebuffer = destImage->framebuffer,
|
||||
.renderArea.offset = (VkOffset2D){0, 0},
|
||||
.renderArea.extent = destImage->extent,
|
||||
.clearValueCount = 1,
|
||||
.pClearValues = &clearColor
|
||||
};
|
||||
|
||||
ge->vkCmdBeginRenderPass(logicalDevice->commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
ge->vkCmdBindPipeline(logicalDevice->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
logicalDevice->fillTexturePoly->graphicsPipeline);
|
||||
|
||||
VkBuffer vertexBuffers[] = {vertexBuffer};
|
||||
VkDeviceSize offsets[] = {0};
|
||||
ge->vkCmdBindVertexBuffers(logicalDevice->commandBuffer, 0, 1, vertexBuffers, offsets);
|
||||
VkViewport viewport = {
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.width = destImage->extent.width,
|
||||
.height = destImage->extent.height,
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f
|
||||
};
|
||||
|
||||
ge->vkCmdSetViewport(logicalDevice->commandBuffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor = {
|
||||
.offset = (VkOffset2D){0, 0},
|
||||
.extent = destImage->extent,
|
||||
};
|
||||
|
||||
ge->vkCmdSetScissor(logicalDevice->commandBuffer, 0, 1, &scissor);
|
||||
ge->vkCmdBindDescriptorSets(logicalDevice->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
logicalDevice->fillTexturePoly->pipelineLayout, 0, 1, &logicalDevice->fillTexturePoly->descriptorSets, 0, NULL);
|
||||
ge->vkCmdDraw(logicalDevice->commandBuffer, vertexNum, 1, 0, 0);
|
||||
|
||||
ge->vkCmdEndRenderPass(logicalDevice->commandBuffer);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void VKRenderer_ColorRender(VKImage *destImage, VkBuffer vertexBuffer, uint32_t vertexNum)
|
||||
{
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
|
||||
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
VkRenderPassBeginInfo renderPassInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.renderPass = logicalDevice->fillColorPoly->renderPass,
|
||||
.framebuffer = destImage->framebuffer,
|
||||
.renderArea.offset = (VkOffset2D){0, 0},
|
||||
.renderArea.extent = destImage->extent,
|
||||
.clearValueCount = 1,
|
||||
.pClearValues = &clearColor
|
||||
};
|
||||
|
||||
ge->vkCmdBeginRenderPass(logicalDevice->commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
ge->vkCmdBindPipeline(logicalDevice->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
logicalDevice->fillColorPoly->graphicsPipeline);
|
||||
|
||||
VkBuffer vertexBuffers[] = {vertexBuffer};
|
||||
VkDeviceSize offsets[] = {0};
|
||||
ge->vkCmdBindVertexBuffers(logicalDevice->commandBuffer, 0, 1, vertexBuffers, offsets);
|
||||
VkViewport viewport = {
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.width = destImage->extent.width,
|
||||
.height = destImage->extent.height,
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f
|
||||
};
|
||||
|
||||
ge->vkCmdSetViewport(logicalDevice->commandBuffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor = {
|
||||
.offset = (VkOffset2D){0, 0},
|
||||
.extent = destImage->extent,
|
||||
};
|
||||
|
||||
ge->vkCmdSetScissor(logicalDevice->commandBuffer, 0, 1, &scissor);
|
||||
ge->vkCmdDraw(logicalDevice->commandBuffer, vertexNum, 1, 0, 0);
|
||||
|
||||
ge->vkCmdEndRenderPass(logicalDevice->commandBuffer);
|
||||
|
||||
}
|
||||
|
||||
void VKRenderer_ColorRenderMaxRect(VKImage *destImage, uint32_t rgba) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
|
||||
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
VkRenderPassBeginInfo renderPassInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.renderPass = logicalDevice->fillMaxColorPoly->renderPass,
|
||||
.framebuffer = destImage->framebuffer,
|
||||
.renderArea.offset = (VkOffset2D){0, 0},
|
||||
.renderArea.extent = destImage->extent,
|
||||
.clearValueCount = 1,
|
||||
.pClearValues = &clearColor
|
||||
};
|
||||
|
||||
ge->vkCmdBeginRenderPass(logicalDevice->commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
ge->vkCmdBindPipeline(logicalDevice->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
logicalDevice->fillMaxColorPoly->graphicsPipeline);
|
||||
|
||||
struct PushConstants {
|
||||
float r, g, b, a;
|
||||
} pushConstants;
|
||||
|
||||
pushConstants = (struct PushConstants){RGBA_TO_L4(rgba)};
|
||||
|
||||
ge->vkCmdPushConstants(
|
||||
logicalDevice->commandBuffer,
|
||||
logicalDevice->fillMaxColorPoly->pipelineLayout,
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
0,
|
||||
sizeof(struct PushConstants),
|
||||
&pushConstants
|
||||
);
|
||||
|
||||
VkViewport viewport = {
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.width = destImage->extent.width,
|
||||
.height = destImage->extent.height,
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f
|
||||
};
|
||||
|
||||
ge->vkCmdSetViewport(logicalDevice->commandBuffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor = {
|
||||
.offset = (VkOffset2D){0, 0},
|
||||
.extent = destImage->extent,
|
||||
};
|
||||
|
||||
ge->vkCmdSetScissor(logicalDevice->commandBuffer, 0, 1, &scissor);
|
||||
ge->vkCmdDraw(logicalDevice->commandBuffer, 4, 1, 0, 0);
|
||||
|
||||
ge->vkCmdEndRenderPass(logicalDevice->commandBuffer);
|
||||
}
|
||||
|
||||
void
|
||||
VKRenderer_FillRect(jint x, jint y, jint w, jint h)
|
||||
{
|
||||
J2dTraceLn4(J2D_TRACE_INFO, "VKRenderer_FillRect %d %d %d %d", x, y, w, h);
|
||||
|
||||
if (w <= 0 || h <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
jboolean VK_CreateLogicalDeviceRenderers() {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
logicalDevice->fillTexturePoly = VKRenderer_CreateFillTexturePoly();
|
||||
logicalDevice->fillColorPoly = VKRenderer_CreateFillColorPoly();
|
||||
logicalDevice->fillMaxColorPoly = VKRenderer_CreateFillMaxColorPoly();
|
||||
if (!logicalDevice->fillTexturePoly || !logicalDevice->fillColorPoly || !logicalDevice->fillMaxColorPoly) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
#endif /* !HEADLESS */
|
||||
@@ -1,282 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 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 "VKRenderer.h"
|
||||
|
||||
VKRecorder::Vertex* VKRecorder::draw(uint32_t numVertices) {
|
||||
uint32_t bytes = numVertices * sizeof(VKRecorder::Vertex);
|
||||
if (_renderPass.vertexBuffer == nullptr && !_vertexBuffers.empty()) {
|
||||
_renderPass.vertexBuffer = &_vertexBuffers.back();
|
||||
_renderPass.commandBuffer->bindVertexBuffers(0, **_renderPass.vertexBuffer, vk::DeviceSize(0));
|
||||
}
|
||||
if (_renderPass.vertexBuffer == nullptr ||
|
||||
_renderPass.vertexBuffer->position() + bytes > _renderPass.vertexBuffer->size()) {
|
||||
_vertexBuffers.push_back(device().getVertexBuffer());
|
||||
_renderPass.vertexBuffer = &_vertexBuffers.back(); // TODO check that our number of vertices fit into single buffer at all
|
||||
_renderPass.commandBuffer->bindVertexBuffers(0, **_renderPass.vertexBuffer, vk::DeviceSize(0));
|
||||
}
|
||||
auto data = (uintptr_t) _renderPass.vertexBuffer->data() + _renderPass.vertexBuffer->position();
|
||||
uint32_t firstVertex = _renderPass.vertexBuffer->position() / sizeof(VKRecorder::Vertex);
|
||||
_renderPass.vertexBuffer->position() += bytes;
|
||||
_renderPass.commandBuffer->draw(numVertices, 1, firstVertex, 0);
|
||||
return (VKRecorder::Vertex*) data;
|
||||
}
|
||||
|
||||
VKDevice* VKRecorder::setDevice(VKDevice *device) {
|
||||
if (device != _device) {
|
||||
if (_device != nullptr) {
|
||||
flush();
|
||||
}
|
||||
std::swap(_device, device);
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
void VKRecorder::waitSemaphore(vk::Semaphore semaphore, vk::PipelineStageFlags stage) {
|
||||
_waitSemaphores.push_back(semaphore);
|
||||
_waitSemaphoreStages.push_back(stage);
|
||||
}
|
||||
|
||||
void VKRecorder::signalSemaphore(vk::Semaphore semaphore) {
|
||||
_signalSemaphores.push_back(semaphore);
|
||||
}
|
||||
|
||||
const vk::raii::CommandBuffer& VKRecorder::record(bool flushRenderPass) {
|
||||
if (!*_commandBuffer) {
|
||||
_commandBuffer = device().getCommandBuffer(vk::CommandBufferLevel::ePrimary);
|
||||
_commandBuffer.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit });
|
||||
}
|
||||
if (flushRenderPass && _renderPass.commandBuffer != nullptr) {
|
||||
_renderPass.commandBuffer->end();
|
||||
vk::Rect2D renderArea {{0, 0}, {_renderPass.surface->width(), _renderPass.surface->height()}};
|
||||
if (device().dynamicRendering()) {
|
||||
vk::RenderingAttachmentInfoKHR colorAttachmentInfo {
|
||||
_renderPass.surfaceView, vk::ImageLayout::eColorAttachmentOptimal,
|
||||
vk::ResolveModeFlagBits::eNone, {}, {},
|
||||
_renderPass.attachmentLoadOp, vk::AttachmentStoreOp::eStore,
|
||||
_renderPass.clearValue
|
||||
};
|
||||
_commandBuffer.beginRenderingKHR(vk::RenderingInfoKHR{
|
||||
vk::RenderingFlagBitsKHR::eContentsSecondaryCommandBuffers,
|
||||
renderArea, 1, 0, colorAttachmentInfo, {}, {}
|
||||
});
|
||||
} else {
|
||||
_commandBuffer.beginRenderPass(vk::RenderPassBeginInfo{
|
||||
/*renderPass*/ *device().pipelines().renderPass,
|
||||
/*framebuffer*/ _renderPass.surfaceFramebuffer,
|
||||
/*renderArea*/ renderArea,
|
||||
/*clearValueCount*/ 0,
|
||||
/*pClearValues*/ nullptr
|
||||
}, vk::SubpassContents::eSecondaryCommandBuffers);
|
||||
}
|
||||
_commandBuffer.executeCommands(**_renderPass.commandBuffer);
|
||||
if (device().dynamicRendering()) {
|
||||
_commandBuffer.endRenderingKHR();
|
||||
} else {
|
||||
_commandBuffer.endRenderPass();
|
||||
}
|
||||
_renderPass = {};
|
||||
}
|
||||
return _commandBuffer;
|
||||
}
|
||||
|
||||
const vk::raii::CommandBuffer& VKRecorder::render(VKSurfaceData& surface, vk::ClearColorValue* clear) {
|
||||
if (_renderPass.surface != &surface) {
|
||||
if (_renderPass.commandBuffer != nullptr) {
|
||||
record(true); // Flush current render pass
|
||||
}
|
||||
VKSurfaceImage i = surface.access(*this,
|
||||
vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
vk::AccessFlagBits::eColorAttachmentWrite,
|
||||
vk::ImageLayout::eColorAttachmentOptimal);
|
||||
_renderPass.surface = &surface;
|
||||
_renderPass.surfaceView = i.view;
|
||||
_renderPass.surfaceFramebuffer = i.framebuffer;
|
||||
_renderPass.attachmentLoadOp = vk::AttachmentLoadOp::eLoad;
|
||||
}
|
||||
if (clear != nullptr) {
|
||||
_renderPass.clearValue = *clear;
|
||||
_renderPass.attachmentLoadOp = vk::AttachmentLoadOp::eClear;
|
||||
}
|
||||
if (_renderPass.commandBuffer == nullptr || clear != nullptr) {
|
||||
if (_renderPass.commandBuffer == nullptr) {
|
||||
_secondaryBuffers.push_back(device().getCommandBuffer(vk::CommandBufferLevel::eSecondary));
|
||||
_renderPass.commandBuffer = &_secondaryBuffers.back();
|
||||
} else {
|
||||
// We already recorded some rendering commands, but it doesn't matter, as we'll clear the surface anyway.
|
||||
_renderPass.commandBuffer->reset({});
|
||||
}
|
||||
vk::Format format = surface.format();
|
||||
vk::CommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo {
|
||||
vk::RenderingFlagBitsKHR::eContentsSecondaryCommandBuffers,
|
||||
0, format
|
||||
};
|
||||
vk::CommandBufferInheritanceInfo inheritanceInfo;
|
||||
if (device().dynamicRendering()) {
|
||||
inheritanceInfo.pNext = &inheritanceRenderingInfo;
|
||||
} else {
|
||||
inheritanceInfo.renderPass = *device().pipelines().renderPass;
|
||||
inheritanceInfo.subpass = 0;
|
||||
inheritanceInfo.framebuffer = _renderPass.surfaceFramebuffer;
|
||||
}
|
||||
_renderPass.commandBuffer->begin({ vk::CommandBufferUsageFlagBits::eOneTimeSubmit |
|
||||
vk::CommandBufferUsageFlagBits::eRenderPassContinue, &inheritanceInfo });
|
||||
if (clear != nullptr && !device().dynamicRendering()) {
|
||||
// Our static render pass uses loadOp=LOAD, so clear attachment manually.
|
||||
_renderPass.commandBuffer->clearAttachments(vk::ClearAttachment {
|
||||
vk::ImageAspectFlagBits::eColor, 0, _renderPass.clearValue
|
||||
}, vk::ClearRect {vk::Rect2D{{0, 0}, {_renderPass.surface->width(), _renderPass.surface->height()}}, 0, 1});
|
||||
}
|
||||
}
|
||||
return *_renderPass.commandBuffer;
|
||||
}
|
||||
|
||||
void VKRecorder::flush() {
|
||||
if (!*_commandBuffer && _renderPass.commandBuffer == nullptr) {
|
||||
return;
|
||||
}
|
||||
record(true).end();
|
||||
device().submitCommandBuffer(std::move(_commandBuffer), _secondaryBuffers, _vertexBuffers,
|
||||
_waitSemaphores, _waitSemaphoreStages, _signalSemaphores);
|
||||
}
|
||||
|
||||
// draw ops
|
||||
|
||||
void VKRenderer::drawLine(jint x1, jint y1, jint x2, jint y2) {/*TODO*/}
|
||||
void VKRenderer::drawRect(jint x, jint y, jint w, jint h) {/*TODO*/}
|
||||
void VKRenderer::drawPoly(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::drawPixel(jint x, jint y) {/*TODO*/}
|
||||
void VKRenderer::drawScanlines(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::drawParallelogram(jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12,
|
||||
jfloat lwr21, jfloat lwr12) {/*TODO*/}
|
||||
void VKRenderer::drawAAParallelogram(jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12,
|
||||
jfloat lwr21, jfloat lwr12) {/*TODO*/}
|
||||
|
||||
// fill ops
|
||||
|
||||
void VKRenderer::fillRect(jint xi, jint yi, jint wi, jint hi) {
|
||||
// TODO
|
||||
auto& cb = render(*_dstSurface);
|
||||
// cb.clearAttachments(vk::ClearAttachment {vk::ImageAspectFlagBits::eColor, 0, _color},
|
||||
// vk::ClearRect {vk::Rect2D {{x, y}, {(uint32_t) w, (uint32_t) h}}, 0, 1});
|
||||
cb.bindPipeline(vk::PipelineBindPoint::eGraphics, *device().pipelines().test);
|
||||
cb.pushConstants<float>(*device().pipelines().testLayout, vk::ShaderStageFlagBits::eVertex, 0, {
|
||||
2.0f/(float)_dstSurface->width(), 2.0f/(float)_dstSurface->height()
|
||||
});
|
||||
vk::Viewport viewport {0, 0, (float) _dstSurface->width(), (float) _dstSurface->height(), 0, 1};
|
||||
cb.setViewport(0, viewport);
|
||||
vk::Rect2D scissor {{0, 0}, {_dstSurface->width(), _dstSurface->height()}};
|
||||
cb.setScissor(0, scissor);
|
||||
auto x = (float) xi, y = (float) yi, w = (float) wi, h = (float) hi;
|
||||
auto v = draw(4);
|
||||
v[0] = {x, y};
|
||||
v[1] = {x+w, y};
|
||||
v[2] = {x+w, y+h};
|
||||
v[3] = {x, y+h};
|
||||
}
|
||||
void VKRenderer::fillSpans(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::fillParallelogram(jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12) {/*TODO*/}
|
||||
void VKRenderer::fillAAParallelogram(jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12) {/*TODO*/}
|
||||
|
||||
// text-related ops
|
||||
|
||||
void VKRenderer::drawGlyphList(/*TODO*/) {/*TODO*/}
|
||||
|
||||
// copy-related ops
|
||||
|
||||
void VKRenderer::copyArea(jint x, jint y, jint w, jint h, jint dx, jint dy) {/*TODO*/}
|
||||
void VKRenderer::blit(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::surfaceToSwBlit(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::maskFill(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::maskBlit(/*TODO*/) {/*TODO*/}
|
||||
|
||||
// state-related ops
|
||||
|
||||
void VKRenderer::setRectClip(jint x1, jint y1, jint x2, jint y2) {/*TODO*/}
|
||||
void VKRenderer::beginShapeClip() {/*TODO*/}
|
||||
void VKRenderer::setShapeClipSpans(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::endShapeClip() {/*TODO*/}
|
||||
void VKRenderer::resetClip() {/*TODO*/}
|
||||
void VKRenderer::setAlphaComposite(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::setXorComposite(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::resetComposite() {/*TODO*/}
|
||||
void VKRenderer::setTransform(jdouble m00, jdouble m10,
|
||||
jdouble m01, jdouble m11,
|
||||
jdouble m02, jdouble m12) {/*TODO*/}
|
||||
void VKRenderer::resetTransform() {/*TODO*/}
|
||||
|
||||
// context-related ops
|
||||
|
||||
void VKRenderer::setSurfaces(VKSurfaceData& src, VKSurfaceData& dst) {
|
||||
if (&src.device() != &dst.device()) {
|
||||
throw std::runtime_error("src and dst surfaces use different devices!");
|
||||
}
|
||||
setDevice(&dst.device());
|
||||
_dstSurface = &dst;
|
||||
_srcSurface = &src;
|
||||
}
|
||||
void VKRenderer::setScratchSurface(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::flushSurface(VKSurfaceData& surface) {
|
||||
VKDevice* old = setDevice(&surface.device());
|
||||
surface.flush(*this);
|
||||
setDevice(old);
|
||||
}
|
||||
void VKRenderer::disposeSurface(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::disposeConfig(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::invalidateContext() {/*TODO*/}
|
||||
void VKRenderer::sync() {/*TODO*/}
|
||||
|
||||
// multibuffering ops
|
||||
|
||||
void VKRenderer::swapBuffers(/*TODO*/) {/*TODO*/}
|
||||
|
||||
// paint-related ops
|
||||
|
||||
void VKRenderer::resetPaint() {/*TODO*/}
|
||||
void VKRenderer::setColor(uint32_t pixel) {
|
||||
_color = pixel;
|
||||
}
|
||||
void VKRenderer::setGradientPaint(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::setLinearGradientPaint(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::setRadialGradientPaint(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::setTexturePaint(/*TODO*/) {/*TODO*/}
|
||||
|
||||
// BufferedImageOp-related ops
|
||||
|
||||
void VKRenderer::enableConvolveOp(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::disableConvolveOp() {/*TODO*/}
|
||||
void VKRenderer::enableRescaleOp(/*TODO*/) {/*TODO*/}
|
||||
void VKRenderer::disableRescaleOp() {/*TODO*/}
|
||||
void VKRenderer::enableLookupOp() {/*TODO*/}
|
||||
void VKRenderer::disableLookupOp() {/*TODO*/}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -26,149 +26,23 @@
|
||||
|
||||
#ifndef VKRenderer_h_Included
|
||||
#define VKRenderer_h_Included
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "j2d_md.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKSurfaceData.h"
|
||||
|
||||
class VKRecorder{
|
||||
VKDevice *_device;
|
||||
vk::raii::CommandBuffer _commandBuffer = nullptr;
|
||||
std::vector<vk::raii::CommandBuffer> _secondaryBuffers;
|
||||
std::vector<vk::Semaphore> _waitSemaphores, _signalSemaphores;
|
||||
std::vector<vk::PipelineStageFlags> _waitSemaphoreStages;
|
||||
std::vector<VKBuffer> _vertexBuffers;
|
||||
struct RenderPass {
|
||||
vk::raii::CommandBuffer *commandBuffer = nullptr;
|
||||
VKSurfaceData *surface = nullptr;
|
||||
VKBuffer *vertexBuffer = nullptr;
|
||||
vk::ImageView surfaceView;
|
||||
vk::Framebuffer surfaceFramebuffer; // Only if dynamic rendering is off.
|
||||
vk::AttachmentLoadOp attachmentLoadOp;
|
||||
vk::ClearValue clearValue;
|
||||
} _renderPass {};
|
||||
VKRenderer* VKRenderer_CreateFillTexturePoly();
|
||||
|
||||
protected:
|
||||
struct Vertex {
|
||||
float x, y;
|
||||
};
|
||||
VKRenderer* VKRenderer_CreateFillColorPoly();
|
||||
|
||||
Vertex* draw(uint32_t numVertices);
|
||||
VKRenderer* VKRenderer_CreateFillMaxColorPoly();
|
||||
|
||||
VKDevice& device() {
|
||||
return *_device;
|
||||
}
|
||||
VKDevice* setDevice(VKDevice *device);
|
||||
void VKRenderer_BeginRendering();
|
||||
void VKRenderer_EndRendering(VkBool32 notifyRenderFinish, VkBool32 waitForDisplayImage);
|
||||
void VKRenderer_TextureRender(VKImage *destImage, VKImage *srcImage, VkBuffer vertexBuffer, uint32_t vertexNum);
|
||||
void VKRenderer_ColorRender(VKImage *destImage, VkBuffer vertexBuffer, uint32_t vertexNum);
|
||||
void VKRenderer_ColorRenderMaxRect(VKImage *destImage, uint32_t rgba);
|
||||
// fill ops
|
||||
void VKRenderer_FillRect(jint x, jint y, jint w, jint h);
|
||||
|
||||
public:
|
||||
void waitSemaphore(vk::Semaphore semaphore, vk::PipelineStageFlags stage);
|
||||
|
||||
void signalSemaphore(vk::Semaphore semaphore);
|
||||
|
||||
const vk::raii::CommandBuffer& record(bool flushRenderPass = true); // Prepare for ordinary commands
|
||||
|
||||
const vk::raii::CommandBuffer& render(VKSurfaceData& surface,
|
||||
vk::ClearColorValue* clear = nullptr); // Prepare for render pass commands
|
||||
|
||||
void flush();
|
||||
};
|
||||
|
||||
class VKRenderer : private VKRecorder{
|
||||
VKSurfaceData *_srcSurface, *_dstSurface;
|
||||
struct alignas(16) Color {
|
||||
float r, g, b, a;
|
||||
Color& operator=(uint32_t c) {
|
||||
r = (float) ((c >> 16) & 0xff) / 255.0f;
|
||||
g = (float) ((c >> 8) & 0xff) / 255.0f;
|
||||
b = (float) (c & 0xff) / 255.0f;
|
||||
a = (float) ((c >> 24) & 0xff) / 255.0f;
|
||||
return *this;
|
||||
}
|
||||
operator vk::ClearValue() const {
|
||||
return vk::ClearColorValue {r, g, b, a};
|
||||
}
|
||||
} _color;
|
||||
|
||||
public:
|
||||
using VKRecorder::flush;
|
||||
|
||||
// draw ops
|
||||
void drawLine(jint x1, jint y1, jint x2, jint y2);
|
||||
void drawRect(jint x, jint y, jint w, jint h);
|
||||
void drawPoly(/*TODO*/);
|
||||
void drawPixel(jint x, jint y);
|
||||
void drawScanlines(/*TODO*/);
|
||||
void drawParallelogram(jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12,
|
||||
jfloat lwr21, jfloat lwr12);
|
||||
void drawAAParallelogram(jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12,
|
||||
jfloat lwr21, jfloat lwr12);
|
||||
|
||||
// fill ops
|
||||
void fillRect(jint x, jint y, jint w, jint h);
|
||||
void fillSpans(/*TODO*/);
|
||||
void fillParallelogram(jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12);
|
||||
void fillAAParallelogram(jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12);
|
||||
|
||||
// text-related ops
|
||||
void drawGlyphList(/*TODO*/);
|
||||
|
||||
// copy-related ops
|
||||
void copyArea(jint x, jint y, jint w, jint h, jint dx, jint dy);
|
||||
void blit(/*TODO*/);
|
||||
void surfaceToSwBlit(/*TODO*/);
|
||||
void maskFill(/*TODO*/);
|
||||
void maskBlit(/*TODO*/);
|
||||
|
||||
// state-related ops
|
||||
void setRectClip(jint x1, jint y1, jint x2, jint y2);
|
||||
void beginShapeClip();
|
||||
void setShapeClipSpans(/*TODO*/);
|
||||
void endShapeClip();
|
||||
void resetClip();
|
||||
void setAlphaComposite(/*TODO*/);
|
||||
void setXorComposite(/*TODO*/);
|
||||
void resetComposite();
|
||||
void setTransform(jdouble m00, jdouble m10,
|
||||
jdouble m01, jdouble m11,
|
||||
jdouble m02, jdouble m12);
|
||||
void resetTransform();
|
||||
|
||||
// context-related ops
|
||||
void setSurfaces(VKSurfaceData& src, VKSurfaceData& dst);
|
||||
void setScratchSurface(/*TODO*/);
|
||||
void flushSurface(VKSurfaceData& surface);
|
||||
void disposeSurface(/*TODO*/);
|
||||
void disposeConfig(/*TODO*/);
|
||||
void invalidateContext();
|
||||
void sync();
|
||||
|
||||
// multibuffering ops
|
||||
void swapBuffers(/*TODO*/);
|
||||
|
||||
// paint-related ops
|
||||
void resetPaint();
|
||||
void setColor(uint32_t pixel);
|
||||
void setGradientPaint(/*TODO*/);
|
||||
void setLinearGradientPaint(/*TODO*/);
|
||||
void setRadialGradientPaint(/*TODO*/);
|
||||
void setTexturePaint(/*TODO*/);
|
||||
|
||||
// BufferedImageOp-related ops
|
||||
void enableConvolveOp(/*TODO*/);
|
||||
void disableConvolveOp();
|
||||
void enableRescaleOp(/*TODO*/);
|
||||
void disableRescaleOp();
|
||||
void enableLookupOp();
|
||||
void disableLookupOp();
|
||||
};
|
||||
|
||||
#endif //__cplusplus
|
||||
#endif //VKRenderer_h_Included
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 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 VKShader_h_Included
|
||||
#define VKShader_h_Included
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VULKAN_HPP_NO_DEFAULT_DISPATCHER
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
class VKShader : public vk::raii::ShaderModule {
|
||||
friend struct VKShaders;
|
||||
vk::ShaderStageFlagBits _stage;
|
||||
void init(const vk::raii::Device& device, size_t size, const uint32_t* data, vk::ShaderStageFlagBits stage) {
|
||||
*((vk::raii::ShaderModule*) this) = device.createShaderModule({{}, size, data});
|
||||
_stage = stage;
|
||||
}
|
||||
public:
|
||||
VKShader() : vk::raii::ShaderModule(nullptr), _stage() {}
|
||||
vk::PipelineShaderStageCreateInfo stage(const vk::SpecializationInfo *specializationInfo = nullptr) {
|
||||
return vk::PipelineShaderStageCreateInfo {{}, _stage, **this, "main", specializationInfo};
|
||||
}
|
||||
};
|
||||
|
||||
struct VKShaders {
|
||||
// Actual list of shaders is autogenerated from source file names
|
||||
# define SHADER_ENTRY(NAME, TYPE) VKShader NAME ## _ ## TYPE;
|
||||
# include "vulkan/shader_list.h"
|
||||
# undef SHADER_ENTRY
|
||||
|
||||
void init(const vk::raii::Device& device);
|
||||
};
|
||||
|
||||
#endif //VKShader_h_Included
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 "jlong.h"
|
||||
#include "SurfaceData.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKVertex.h"
|
||||
#include "VKImage.h"
|
||||
#include <Trace.h>
|
||||
|
||||
void VKSD_InitImageSurface(VKSDOps *vksdo) {
|
||||
if (vksdo->image != VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
vksdo->image = VKImage_Create(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;
|
||||
}
|
||||
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
|
||||
if (!VKImage_CreateFramebuffer(vksdo->image, logicalDevice->fillTexturePoly->renderPass)) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot create framebuffer for window surface")
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void VKSD_InitWindowSurface(VKWinSDOps *vkwinsdo) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
|
||||
VkPhysicalDevice physicalDevice = logicalDevice->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);
|
||||
|
||||
ge->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface,
|
||||
&vkwinsdo->presentModeKhrCount, NULL);
|
||||
|
||||
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 (ge->vkCreateSwapchainKHR(logicalDevice->device, &createInfoKhr, NULL, &vkwinsdo->swapchainKhr) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "Cannot create swapchain\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vkwinsdo->swapChainImages = VKImage_CreateImageArrayFromSwapChain(
|
||||
vkwinsdo->swapchainKhr,
|
||||
logicalDevice->fillTexturePoly->renderPass,
|
||||
vkwinsdo->formatsKhr[0].format, extent);
|
||||
|
||||
if (!vkwinsdo->swapChainImages) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Cannot get swapchain images");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 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 "jni_util.h"
|
||||
#include "Disposer.h"
|
||||
#include "Trace.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKRenderer.h"
|
||||
|
||||
void VKSurfaceData::attachToJavaSurface(JNIEnv *env, jobject javaSurfaceData) {
|
||||
// SurfaceData utility functions operate on C structures and malloc/free,
|
||||
// But we are using C++ classes, so set up the disposer manually.
|
||||
// This is a C++ analogue of SurfaceData_InitOps / SurfaceData_SetOps.
|
||||
jboolean exception = false;
|
||||
if (JNU_GetFieldByName(env, &exception, javaSurfaceData, "pData", "J").j == 0 && !exception) {
|
||||
jlong ptr = ptr_to_jlong((SurfaceDataOps*) this);
|
||||
JNU_SetFieldByName(env, &exception, javaSurfaceData, "pData", "J", ptr);
|
||||
/* Register the data for disposal */
|
||||
Disposer_AddRecord(env, javaSurfaceData, [](JNIEnv *env, jlong ops) {
|
||||
if (ops != 0) {
|
||||
auto sd = (SurfaceDataOps*)jlong_to_ptr(ops);
|
||||
jobject sdObject = sd->sdObject;
|
||||
sd->Dispose(env, sd);
|
||||
if (sdObject != nullptr) {
|
||||
env->DeleteWeakGlobalRef(sdObject);
|
||||
}
|
||||
}
|
||||
}, ptr);
|
||||
} else if (!exception) {
|
||||
throw std::runtime_error("Attempting to set SurfaceData ops twice");
|
||||
}
|
||||
if (exception) {
|
||||
throw std::runtime_error("VKSurfaceData::attachToJavaSurface error");
|
||||
}
|
||||
sdObject = env->NewWeakGlobalRef(javaSurfaceData);
|
||||
}
|
||||
|
||||
VKSurfaceData::VKSurfaceData(uint32_t w, uint32_t h, uint32_t s, uint32_t bgc)
|
||||
: SurfaceDataOps(), _width(w), _height(h), _scale(s), _bg_color(bgc), _device(nullptr) {
|
||||
Lock = [](JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *rasInfo, jint lockFlags) {
|
||||
((VKSurfaceData*) ops)->_mutex.lock();
|
||||
return SD_SUCCESS;
|
||||
};
|
||||
Unlock = [](JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *rasInfo) {
|
||||
((VKSurfaceData*) ops)->_mutex.unlock();
|
||||
};
|
||||
Dispose = [](JNIEnv *env, SurfaceDataOps *ops) {
|
||||
delete (VKSurfaceData*) ops;
|
||||
};
|
||||
}
|
||||
|
||||
bool VKSurfaceData::barrier(VKRecorder& recorder, vk::Image image,
|
||||
vk::PipelineStageFlags stage, vk::AccessFlags access, vk::ImageLayout layout) {
|
||||
// TODO consider write/read access
|
||||
if (_lastStage != stage || _lastAccess != access || _layout != layout) {
|
||||
if (_device->synchronization2()) {
|
||||
vk::ImageMemoryBarrier2KHR barrier {
|
||||
(vk::PipelineStageFlags2KHR) (VkFlags) _lastStage,
|
||||
(vk::AccessFlags2KHR) (VkFlags) _lastAccess,
|
||||
(vk::PipelineStageFlags2KHR) (VkFlags) stage,
|
||||
(vk::AccessFlags2KHR) (VkFlags) access,
|
||||
_layout, layout,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
image, vk::ImageSubresourceRange {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}
|
||||
};
|
||||
recorder.record(false).pipelineBarrier2KHR(vk::DependencyInfoKHR {{}, {}, {}, barrier});
|
||||
} else {
|
||||
vk::ImageMemoryBarrier barrier {
|
||||
_lastAccess, access,
|
||||
_layout, layout,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
image, vk::ImageSubresourceRange {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}
|
||||
};
|
||||
recorder.record(false).pipelineBarrier(_lastStage, stage, {}, {}, {}, barrier);
|
||||
}
|
||||
_lastStage = stage;
|
||||
_lastAccess = access;
|
||||
_layout = layout;
|
||||
// TODO check write access
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
void VKSwapchainSurfaceData::revalidate(uint32_t w, uint32_t h, uint32_t s) {
|
||||
if (*_swapchain && s == scale() && w == width() && h == height() ) {
|
||||
J2dTraceLn1(J2D_TRACE_INFO,
|
||||
"VKSwapchainSurfaceData_revalidate is skipped: swapchain(%p)",
|
||||
*_swapchain);
|
||||
return;
|
||||
}
|
||||
VKSurfaceData::revalidate(w, h, s);
|
||||
if (!_device || !*_surface) {
|
||||
J2dTraceLn2(J2D_TRACE_ERROR,
|
||||
"VKSwapchainSurfaceData_revalidate is skipped: device(%p) surface(%p)",
|
||||
_device, *_surface);
|
||||
return;
|
||||
}
|
||||
|
||||
vk::SurfaceCapabilitiesKHR surfaceCapabilities = device().getSurfaceCapabilitiesKHR(*_surface);
|
||||
_format = vk::Format::eB8G8R8A8Unorm; // TODO?
|
||||
|
||||
// TODO all these parameters must be checked against device & surface capabilities
|
||||
vk::SwapchainCreateInfoKHR swapchainCreateInfo{
|
||||
{},
|
||||
*_surface,
|
||||
surfaceCapabilities.minImageCount,
|
||||
format(),
|
||||
vk::ColorSpaceKHR::eVkColorspaceSrgbNonlinear,
|
||||
{width(), height()}, // TODO According to spec we need to use surfaceCapabilities.currentExtent, which is not available at this point (it gives -1)... We'll figure this out later
|
||||
1,
|
||||
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst,
|
||||
vk::SharingMode::eExclusive,
|
||||
0,
|
||||
nullptr,
|
||||
vk::SurfaceTransformFlagBitsKHR::eIdentity,
|
||||
vk::CompositeAlphaFlagBitsKHR::eOpaque,
|
||||
vk::PresentModeKHR::eImmediate,
|
||||
true, *_swapchain
|
||||
};
|
||||
|
||||
device().waitIdle(); // TODO proper synchronization in case there are rendering operations for old swapchain in flight
|
||||
_images.clear();
|
||||
_swapchain = device().createSwapchainKHR(swapchainCreateInfo);
|
||||
for (vk::Image image : _swapchain.getImages()) {
|
||||
_images.push_back({image, device().createImageView(vk::ImageViewCreateInfo {
|
||||
{}, image, vk::ImageViewType::e2D, format(), {},
|
||||
vk::ImageSubresourceRange {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}
|
||||
})});
|
||||
if (!device().dynamicRendering()) {
|
||||
_images.back().framebuffer = device().createFramebuffer(vk::FramebufferCreateInfo{
|
||||
/*flags*/ {},
|
||||
/*renderPass*/ *device().pipelines().renderPass,
|
||||
/*attachmentCount*/ 1,
|
||||
/*pAttachments*/ &*_images.back().view,
|
||||
/*width*/ width(),
|
||||
/*height*/ height(),
|
||||
/*layers*/ 1
|
||||
});
|
||||
}
|
||||
}
|
||||
_currentImage = (uint32_t) -1;
|
||||
_freeSemaphore = nullptr;
|
||||
// TODO Now we need to repaint our surface... How is it done? No idea
|
||||
}
|
||||
|
||||
VKSurfaceImage VKSwapchainSurfaceData::access(VKRecorder& recorder,
|
||||
vk::PipelineStageFlags stage,
|
||||
vk::AccessFlags access,
|
||||
vk::ImageLayout layout) {
|
||||
// Acquire image
|
||||
bool semaphorePending = false;
|
||||
if (_currentImage == (uint32_t) -1) {
|
||||
if (!*_freeSemaphore) {
|
||||
_freeSemaphore = device().createSemaphore({});
|
||||
}
|
||||
auto img = _swapchain.acquireNextImage(-1, *_freeSemaphore, nullptr);
|
||||
vk::resultCheck(img.first, "vk::SwapchainKHR::acquireNextImage");
|
||||
_layout = vk::ImageLayout::eUndefined;
|
||||
_lastStage = _lastWriteStage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
_lastAccess = _lastWriteAccess = {};
|
||||
_currentImage = (int) img.second;
|
||||
std::swap(_images[_currentImage].semaphore, _freeSemaphore);
|
||||
semaphorePending = true;
|
||||
}
|
||||
// Insert barrier & semaphore
|
||||
auto& current = _images[_currentImage];
|
||||
barrier(recorder, current.image, stage, access, layout);
|
||||
if (semaphorePending) {
|
||||
recorder.waitSemaphore(*current.semaphore,
|
||||
vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eTransfer);
|
||||
}
|
||||
return {current.image, *current.view, *current.framebuffer};
|
||||
}
|
||||
|
||||
void VKSwapchainSurfaceData::flush(VKRecorder& recorder) {
|
||||
if (_currentImage == (uint32_t) -1) {
|
||||
return; // Nothing to flush
|
||||
}
|
||||
recorder.record(true); // Force flush current render pass before accessing image with present layout.
|
||||
access(recorder, vk::PipelineStageFlagBits::eTopOfPipe, {}, vk::ImageLayout::ePresentSrcKHR);
|
||||
auto& current = _images[_currentImage];
|
||||
recorder.signalSemaphore(*current.semaphore);
|
||||
recorder.flush();
|
||||
device().queue().presentKHR(vk::PresentInfoKHR {
|
||||
*current.semaphore, *_swapchain, _currentImage
|
||||
});
|
||||
_currentImage = (uint32_t) -1;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -27,10 +27,13 @@
|
||||
#ifndef VKSurfaceData_h_Included
|
||||
#define VKSurfaceData_h_Included
|
||||
|
||||
#include <mutex>
|
||||
#include <pthread.h>
|
||||
#include "jni.h"
|
||||
#include "SurfaceData.h"
|
||||
#include "sun_java2d_pipe_hw_AccelSurface.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKBuffer.h"
|
||||
#include "VKImage.h"
|
||||
|
||||
/**
|
||||
* These are shorthand names for the surface type constants defined in
|
||||
@@ -38,125 +41,64 @@
|
||||
*/
|
||||
#define VKSD_UNDEFINED sun_java2d_pipe_hw_AccelSurface_UNDEFINED
|
||||
#define VKSD_WINDOW sun_java2d_pipe_hw_AccelSurface_WINDOW
|
||||
#define VKSD_TEXTURE sun_java2d_pipe_hw_AccelSurface_TEXTURE
|
||||
#define VKSD_RT_TEXTURE sun_java2d_pipe_hw_AccelSurface_RT_TEXTURE
|
||||
|
||||
class VKRecorder;
|
||||
|
||||
struct VKSurfaceImage {
|
||||
vk::Image image;
|
||||
vk::ImageView view;
|
||||
vk::Framebuffer framebuffer; // Only if dynamic rendering is off.
|
||||
};
|
||||
|
||||
class VKSurfaceData : private SurfaceDataOps {
|
||||
std::recursive_mutex _mutex;
|
||||
uint32_t _width;
|
||||
uint32_t _height;
|
||||
uint32_t _scale; // TODO Is it needed there at all?
|
||||
uint32_t _bg_color;
|
||||
protected:
|
||||
VKDevice* _device;
|
||||
vk::Format _format;
|
||||
|
||||
vk::ImageLayout _layout = vk::ImageLayout::eUndefined;
|
||||
/**
|
||||
* 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.
|
||||
vk::PipelineStageFlags _lastStage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
vk::PipelineStageFlags _lastWriteStage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
vk::AccessFlags _lastAccess = {};
|
||||
vk::AccessFlags _lastWriteAccess = {};
|
||||
VkPipelineStageFlagBits lastStage;
|
||||
VkPipelineStageFlagBits lastWriteStage;
|
||||
VkAccessFlagBits lastAccess;
|
||||
VkAccessFlagBits lastWriteAccess;
|
||||
} VKSDOps;
|
||||
|
||||
/// Insert barrier if needed for given access and layout.
|
||||
bool barrier(VKRecorder& recorder, vk::Image image,
|
||||
vk::PipelineStageFlags stage, vk::AccessFlags access, vk::ImageLayout layout);
|
||||
public:
|
||||
VKSurfaceData(uint32_t w, uint32_t h, uint32_t s, uint32_t bgc);
|
||||
// No need to move, as object must only be created with "new".
|
||||
VKSurfaceData(VKSurfaceData&&) = delete;
|
||||
VKSurfaceData& operator=(VKSurfaceData&&) = delete;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
void attachToJavaSurface(JNIEnv *env, jobject javaSurfaceData);
|
||||
/**
|
||||
* Exported methods.
|
||||
*/
|
||||
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);
|
||||
|
||||
VKDevice& device() const {
|
||||
return *_device;
|
||||
}
|
||||
|
||||
vk::Format format() const {
|
||||
return _format;
|
||||
}
|
||||
|
||||
uint32_t width() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
uint32_t height() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
uint32_t scale() const {
|
||||
return _scale;
|
||||
}
|
||||
|
||||
uint32_t bg_color() const {
|
||||
return _bg_color;
|
||||
}
|
||||
|
||||
void set_bg_color(uint32_t bg_color) {
|
||||
if (_bg_color != bg_color) {
|
||||
_bg_color = bg_color;
|
||||
// TODO now we need to repaint the surface???
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~VKSurfaceData() = default;
|
||||
|
||||
virtual void revalidate(uint32_t w, uint32_t h, uint32_t s) {
|
||||
_width = w;
|
||||
_height = h;
|
||||
_scale = s;
|
||||
}
|
||||
|
||||
/// Prepare image for access (necessary barriers & layout transitions).
|
||||
virtual VKSurfaceImage access(VKRecorder& recorder,
|
||||
vk::PipelineStageFlags stage,
|
||||
vk::AccessFlags access,
|
||||
vk::ImageLayout layout) = 0;
|
||||
/// Flush all pending changes to the surface, including screen presentation for on-screen surfaces.
|
||||
virtual void flush(VKRecorder& recorder) = 0;
|
||||
};
|
||||
|
||||
class VKSwapchainSurfaceData : public VKSurfaceData {
|
||||
struct Image {
|
||||
vk::Image image;
|
||||
vk::raii::ImageView view;
|
||||
vk::raii::Framebuffer framebuffer = nullptr; // Only if dynamic rendering is off.
|
||||
vk::raii::Semaphore semaphore = nullptr;
|
||||
};
|
||||
|
||||
vk::raii::SurfaceKHR _surface = nullptr;
|
||||
vk::raii::SwapchainKHR _swapchain = nullptr;
|
||||
std::vector<Image> _images;
|
||||
uint32_t _currentImage = (uint32_t) -1;
|
||||
vk::raii::Semaphore _freeSemaphore = nullptr;
|
||||
|
||||
protected:
|
||||
void reset(VKDevice& device, vk::raii::SurfaceKHR surface) {
|
||||
_images.clear();
|
||||
_swapchain = nullptr;
|
||||
_surface = std::move(surface);
|
||||
_device = &device;
|
||||
}
|
||||
public:
|
||||
VKSwapchainSurfaceData(uint32_t w, uint32_t h, uint32_t s, uint32_t bgc)
|
||||
: VKSurfaceData(w, h, s, bgc) {};
|
||||
|
||||
virtual void revalidate(uint32_t w, uint32_t h, uint32_t s);
|
||||
|
||||
virtual VKSurfaceImage access(VKRecorder& recorder,
|
||||
vk::PipelineStageFlags stage,
|
||||
vk::AccessFlags access,
|
||||
vk::ImageLayout layout);
|
||||
virtual void flush(VKRecorder& recorder);
|
||||
};
|
||||
void VKSD_InitImageSurface(VKSDOps *vksdo);
|
||||
void VKSD_InitWindowSurface(VKWinSDOps *vkwinsdo);
|
||||
|
||||
#endif /* VKSurfaceData_h_Included */
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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_GetCVertexDescr() {
|
||||
static VkVertexInputBindingDescription bindingDescriptions[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.stride = sizeof(VKCVertex),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
||||
}
|
||||
};
|
||||
|
||||
static VkVertexInputAttributeDescription attributeDescriptions [] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(VKCVertex, px)
|
||||
},
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 1,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.offset = offsetof(VKCVertex, r)
|
||||
}
|
||||
};
|
||||
|
||||
return (VKVertexDescr) {
|
||||
.attributeDescriptions = attributeDescriptions,
|
||||
.attributeDescriptionCount = SARRAY_COUNT_OF(attributeDescriptions),
|
||||
.bindingDescriptions = bindingDescriptions,
|
||||
.bindingDescriptionCount = SARRAY_COUNT_OF(bindingDescriptions)
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 VKVertex_h_Included
|
||||
#define VKVertex_h_Included
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "VKBuffer.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(vertices) \
|
||||
VKBuffer_CreateFromData(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;
|
||||
float r, g, b, a;
|
||||
} VKCVertex;
|
||||
|
||||
VKVertexDescr VKVertex_GetTxVertexDescr();
|
||||
VKVertexDescr VKVertex_GetCVertexDescr();
|
||||
|
||||
|
||||
|
||||
#endif //VKVertex_h_Included
|
||||
@@ -67,7 +67,7 @@ int isNullScalerContext(void *context) {
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_font_NullFontScaler_getGlyphImage
|
||||
(JNIEnv *env, jobject scaler, jlong pContext, jint glyphCode) {
|
||||
void *nullscaler = calloc(sizeof(GlyphInfo), 1);
|
||||
void *nullscaler = calloc(1, sizeof(GlyphInfo));
|
||||
return ptr_to_jlong(nullscaler);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,11 +55,13 @@ import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
|
||||
import jdk.internal.misc.InnocuousThread;
|
||||
import sun.awt.X11.XBaseWindow;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
import com.sun.java.swing.plaf.gtk.GTKConstants.TextDirection;
|
||||
import sun.java2d.opengl.OGLRenderQueue;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
public abstract class UNIXToolkit extends SunToolkit
|
||||
{
|
||||
@@ -112,6 +114,16 @@ public abstract class UNIXToolkit extends SunToolkit
|
||||
private Boolean nativeGTKAvailable;
|
||||
private Boolean nativeGTKLoaded;
|
||||
private BufferedImage tmpImage = null;
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.UNIXToolkit");
|
||||
|
||||
private static void printError(String str) {
|
||||
log.fine(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeDesktopProperties() {
|
||||
initSystemPropertyWatcher();
|
||||
}
|
||||
|
||||
public static int getDatatransferTimeout() {
|
||||
@SuppressWarnings("removal")
|
||||
@@ -548,6 +560,8 @@ public abstract class UNIXToolkit extends SunToolkit
|
||||
return result;
|
||||
}
|
||||
|
||||
private static native int isSystemDarkColorScheme();
|
||||
|
||||
@Override
|
||||
public boolean isRunningOnXWayland() {
|
||||
return isOnXWayland();
|
||||
@@ -566,6 +580,43 @@ public abstract class UNIXToolkit extends SunToolkit
|
||||
// application icons).
|
||||
private static final WindowFocusListener waylandWindowFocusListener;
|
||||
|
||||
private static final String OS_THEME_IS_DARK = "awt.os.theme.isDark";
|
||||
|
||||
private static Thread systemPropertyWatcher = null;
|
||||
|
||||
private static native boolean dbusInit();
|
||||
|
||||
private void initSystemPropertyWatcher() {
|
||||
@SuppressWarnings("removal")
|
||||
String dbusEnabled = AccessController.doPrivileged(
|
||||
new GetPropertyAction("jbr.dbus.enabled", "true")).toLowerCase();
|
||||
if (!"true".equals(dbusEnabled) || !dbusInit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int initialSystemDarkColorScheme = isSystemDarkColorScheme();
|
||||
if (initialSystemDarkColorScheme >= 0) {
|
||||
setDesktopProperty(OS_THEME_IS_DARK, initialSystemDarkColorScheme != 0);
|
||||
|
||||
systemPropertyWatcher = InnocuousThread.newThread("SystemPropertyWatcher",
|
||||
() -> {
|
||||
while (true) {
|
||||
try {
|
||||
int isSystemDarkColorScheme = isSystemDarkColorScheme();
|
||||
if (isSystemDarkColorScheme >= 0) {
|
||||
setDesktopProperty(OS_THEME_IS_DARK, isSystemDarkColorScheme != 0);
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
systemPropertyWatcher.setDaemon(true);
|
||||
systemPropertyWatcher.start();
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
if (isOnXWayland()) {
|
||||
waylandWindowFocusListener = new WindowAdapter() {
|
||||
|
||||
@@ -33,12 +33,15 @@ import java.awt.im.spi.InputMethodContext;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.awt.X11GraphicsDevice;
|
||||
import sun.awt.X11GraphicsEnvironment;
|
||||
import sun.awt.X11InputMethod;
|
||||
@@ -303,6 +306,155 @@ public class XInputMethod extends X11InputMethod {
|
||||
}
|
||||
|
||||
|
||||
// JBR-6456: Sudden keyboard death on Linux using iBus.
|
||||
// xicDestroyMustBeDelayed, XIC_DELAYED_TO_BE_DESTROYED_CAPACITY, xicDelayedToBeDestroyed can only be accessed
|
||||
// under the AWT lock
|
||||
// See the #disposeXIC method for the purpose of these fields
|
||||
private static boolean xicDestroyMustBeDelayed = false;
|
||||
private static final int XIC_DELAYED_TO_BE_DESTROYED_CAPACITY = 16;
|
||||
private static final Queue<Long> xicDelayedToBeDestroyed = new ArrayDeque<>(XIC_DELAYED_TO_BE_DESTROYED_CAPACITY);
|
||||
|
||||
static void delayAllXICDestroyUntilAFurtherNotice() {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("delayAllXICDestroyUntilAFurtherNotice(): is being called", new Throwable("Stacktrace"));
|
||||
}
|
||||
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("delayAllXICDestroyUntilAFurtherNotice(): xicDestroyMustBeDelayed=={0}", xicDestroyMustBeDelayed);
|
||||
}
|
||||
|
||||
xicDestroyMustBeDelayed = true;
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
static void delayedXICDestroyShouldBeDone() {
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
xicDestroyMustBeDelayed = false;
|
||||
doDelayedXICDestroy(false, -1);
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static void doDelayedXICDestroy(boolean forced, int maxCountToDestroy) {
|
||||
final boolean isFineLoggable = log.isLoggable(PlatformLogger.Level.FINE);
|
||||
|
||||
if (isFineLoggable) {
|
||||
log.fine(
|
||||
"doDelayedXICDestroy(forced==" + forced + ", maxCountToDestroy==" + maxCountToDestroy + "): is being called",
|
||||
new Throwable("Stacktrace")
|
||||
);
|
||||
}
|
||||
|
||||
assert(SunToolkit.isAWTLockHeldByCurrentThread());
|
||||
assert(forced || !xicDestroyMustBeDelayed);
|
||||
|
||||
while ( (maxCountToDestroy != 0) && !xicDelayedToBeDestroyed.isEmpty() ) {
|
||||
final long pX11IMData = xicDelayedToBeDestroyed.remove();
|
||||
--maxCountToDestroy;
|
||||
|
||||
if (isFineLoggable) {
|
||||
log.fine("doDelayedXICDestroy(): destroying pX11IMData={0}", pX11IMData);
|
||||
}
|
||||
|
||||
assert(pX11IMData != 0);
|
||||
delayedDisposeXIC_disposeXICNative(pX11IMData);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disposeXIC() {
|
||||
awtLock();
|
||||
try {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("disposeXIC(): xicDestroyMustBeDelayed=={0}", xicDestroyMustBeDelayed);
|
||||
}
|
||||
|
||||
if (!xicDestroyMustBeDelayed) {
|
||||
// JBR-6456: Sudden keyboard death on Linux using iBus.
|
||||
// iBus's X11 frontend being run in the async mode (IBUS_ENABLE_SYNC_MODE=0) has a bug leading to a
|
||||
// violation of the communication protocol between iBus and Xlib (so-called "XIM protocol"),
|
||||
// later causing Xlib to behave unexpectedly from iBus's point of view, breaking iBus's
|
||||
// internal state. After all, iBus starts to "steal" all the keyboard events
|
||||
// (so that each call of XFilterEvent(...) with an instance of XKeyEvent returns True).
|
||||
// The initial iBus's bug only appears when XDestroyIC(...) gets called right after a call of
|
||||
// XFilterEvent(...) with an instance of XKeyEvent returned True,
|
||||
// meaning that iBus has started, but hasn't finished yet processing of the key event.
|
||||
// In case of AWT/Swing apps, XDestroyIC gets called whenever a focused HW window gets closed
|
||||
// (because it leads to disposing of the associated input context,
|
||||
// see java.awt.Window#doDispose and sun.awt.im.InputContext#dispose)
|
||||
// So, to work around iBus's bug, we have to avoid calling XDestroyIC until iBus finishes processing of
|
||||
// all the keyboard events it has already started processing of, i.e. until a call of
|
||||
// XFilterEvent(...) returns False.
|
||||
// To achieve that, the implemented fix delays destroying of input contexts whenever a call of
|
||||
// XFilterEvent(...) with an instance of XKeyEvent returns True until one of the next calls of
|
||||
// XFilterEvent(...) with the same instance of XKeyEvent returns False.
|
||||
// The delaying is implemented via storing the native pointers to the input contexts to
|
||||
// xicDelayedToBeDestroyed instead of applying XDestroyIC(...) immediately.
|
||||
// The xicDelayedToBeDestroyed's size is explicitly limited to
|
||||
// XIC_DELAYED_TO_BE_DESTROYED_CAPACITY. If the limit gets reached, a few input contexts gets
|
||||
// pulled from there and destroyed regardless of the current value of xicDestroyMustBeDelayed.
|
||||
// The xicDestroyMustBeDelayed field is responsible for indication whether it's required to delay
|
||||
// the destroying or not. It gets set in #delayAllXICDestroyUntilAFurtherNotice
|
||||
// and unset in delayedXICDestroyShouldBeDone; both are called by sun.awt.X11.XToolkit depending on
|
||||
// the value returned by the calls of sun.awt.X11.XlibWrapper#XFilterEvent.
|
||||
|
||||
super.disposeXIC();
|
||||
return;
|
||||
}
|
||||
|
||||
final long pX11IMData = pData;
|
||||
|
||||
// To make sure that the delayed to be destroyed input context won't get used by AWT/Swing or Xlib
|
||||
// by a mistake, the following things are done:
|
||||
// 1. The input method focus gets detached from the input context (via a call of XUnsetICFocus)
|
||||
// 2. All the native pointers to this instance of XInputMethod
|
||||
// (now it's just the variable currentX11InputMethodInstance in awt_InputMethod.c) get unset
|
||||
// 3. All the java pointers to the native context (now it's just sun.awt.X11InputMethodBase#pData)
|
||||
// get unset as well
|
||||
delayedDisposeXIC_preparation_unsetFocusAndDetachCurrentXICNative();
|
||||
|
||||
// 4. The state of the native context gets reset (effectively via a call of XmbResetIC)
|
||||
delayedDisposeXIC_preparation_resetSpecifiedCtxNative(pX11IMData);
|
||||
|
||||
if (pX11IMData == 0) {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("disposeXIC(): pX11IMData==NULL, skipped");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If the storage is full, a few input context are pulled from there and destroyed regardless of
|
||||
// the value of xicDestroyMustBeDelayed
|
||||
if (xicDelayedToBeDestroyed.size() >= XIC_DELAYED_TO_BE_DESTROYED_CAPACITY) {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(
|
||||
"disposeXIC(): xicDelayedToBeDestroyed.size()=={0} >= XIC_DELAYED_TO_BE_DESTROYED_CAPACITY",
|
||||
xicDelayedToBeDestroyed.size()
|
||||
);
|
||||
}
|
||||
|
||||
doDelayedXICDestroy(true, xicDelayedToBeDestroyed.size() - XIC_DELAYED_TO_BE_DESTROYED_CAPACITY + 1);
|
||||
}
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(
|
||||
"disposeXIC(): adding pX11IMData=={0} to xicDelayedToBeDestroyed (which already contains {1} elements)",
|
||||
pX11IMData, xicDelayedToBeDestroyed.size()
|
||||
);
|
||||
}
|
||||
xicDelayedToBeDestroyed.add(pX11IMData);
|
||||
} finally {
|
||||
awtUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void onXKeyEventFiltering(final boolean isXKeyEventFiltered) {
|
||||
// Fix of JBR-1573, JBR-2444, JBR-4394 (a.k.a. IDEA-246833).
|
||||
// Input method is considered broken if and only if all the following statements are true:
|
||||
@@ -616,6 +768,15 @@ public class XInputMethod extends X11InputMethod {
|
||||
private native void setXICFocusNative(long window, boolean value, boolean active);
|
||||
private native void adjustStatusWindow(long window);
|
||||
|
||||
// 1. Applies XUnsetICFocus to the current input context
|
||||
// 2. Unsets currentX11InputMethodInstance if it's set to this instance of XInputMethod
|
||||
// 3. Unsets sun.awt.X11InputMethodBase#pData
|
||||
private native void delayedDisposeXIC_preparation_unsetFocusAndDetachCurrentXICNative();
|
||||
// Applies XmbResetIC to the passed input context
|
||||
private static native void delayedDisposeXIC_preparation_resetSpecifiedCtxNative(long pX11IMData);
|
||||
// Applies XDestroyIC to the passed input context
|
||||
private static native void delayedDisposeXIC_disposeXICNative(long pX11IMData);
|
||||
|
||||
private native boolean doesFocusedXICSupportMovingCandidatesNativeWindow();
|
||||
|
||||
private native void adjustCandidatesNativeWindowPosition(int x, int y);
|
||||
|
||||
@@ -1020,11 +1020,22 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
final boolean isKeyEvent = ( (ev.get_type() == XConstants.KeyPress) ||
|
||||
(ev.get_type() == XConstants.KeyRelease) );
|
||||
|
||||
final long keyEventSerial = isKeyEvent ? ev.get_xkey().get_serial() : -1;
|
||||
|
||||
if (keyEventLog.isLoggable(PlatformLogger.Level.FINE) && isKeyEvent) {
|
||||
keyEventLog.fine("before XFilterEvent:" + ev);
|
||||
}
|
||||
if (XlibWrapper.XFilterEvent(ev.getPData(), w)) {
|
||||
if (isKeyEvent) {
|
||||
if (keyEventLog.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
keyEventLog.fine(
|
||||
"Setting lastFilteredKeyEventSerial=={0} to {1}",
|
||||
lastFilteredKeyEventSerial, keyEventSerial
|
||||
);
|
||||
}
|
||||
lastFilteredKeyEventSerial = keyEventSerial;
|
||||
|
||||
XInputMethod.delayAllXICDestroyUntilAFurtherNotice();
|
||||
XInputMethod.onXKeyEventFiltering(true);
|
||||
}
|
||||
continue;
|
||||
@@ -1036,6 +1047,14 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
|
||||
if (isKeyEvent) {
|
||||
XInputMethod.onXKeyEventFiltering(false);
|
||||
if (keyEventSerial == lastFilteredKeyEventSerial) {
|
||||
// JBR-6456: Sudden keyboard death on Linux using iBus.
|
||||
// If more than 1 key events are being processed by iBus
|
||||
// (i.e. more than one in a row calls of XFilterEvent(...) with instances of XKeyEvent have
|
||||
// returned true),
|
||||
// we have to postpone destroying until the very last one is completely processed)
|
||||
XInputMethod.delayedXICDestroyShouldBeDone();
|
||||
}
|
||||
}
|
||||
|
||||
dispatchEvent(ev);
|
||||
@@ -1107,6 +1126,14 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
|
||||
|
||||
// JBR-6456: Sudden keyboard death on Linux using iBus.
|
||||
// The field holds the value of sun.awt.X11.XKeyEvent#get_serial of the last key event, which
|
||||
// XFilterEvent(...) returned True for.
|
||||
// See the usages of the variable for more info.
|
||||
// See sun.awt.X11.XInputMethod#disposeXIC for the detailed explanation of the whole fix.
|
||||
private long lastFilteredKeyEventSerial = -1;
|
||||
|
||||
|
||||
/**
|
||||
* Listener installed to detect display changes.
|
||||
*/
|
||||
@@ -1215,7 +1242,9 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
}
|
||||
X11GraphicsDevice x11gd = (X11GraphicsDevice) gd;
|
||||
int screenNum = x11gd.getScreen();
|
||||
if (localEnv.runningXinerama() && screenNum != 0) {
|
||||
Rectangle screen = gc.getBounds();
|
||||
boolean isFirstScreen = screen.x == 0 && screen.y == 0;
|
||||
if (localEnv.runningXinerama() && !isFirstScreen) {
|
||||
// We cannot estimate insets for non-default screen,
|
||||
// there are often none.
|
||||
return new Insets(0, 0, 0, 0);
|
||||
@@ -1224,7 +1253,6 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
Rectangle workArea = getWorkArea(XlibUtil.getRootWindow(screenNum));
|
||||
Rectangle screen = gc.getBounds();
|
||||
if (workArea != null) {
|
||||
Point p = x11gd.scaleDown(workArea.x, workArea.y);
|
||||
workArea.x = p.x;
|
||||
@@ -1233,8 +1261,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
workArea.height = x11gd.scaleDown(workArea.height);
|
||||
workArea = workArea.intersection(screen);
|
||||
if (!workArea.isEmpty()) {
|
||||
int top = workArea.y - screen.y;
|
||||
int left = workArea.x - screen.x;
|
||||
int top = workArea.y;
|
||||
int left = workArea.x;
|
||||
int bottom = screen.height - workArea.height - top;
|
||||
int right = screen.width - workArea.width - left;
|
||||
return new Insets(top, left, bottom, right);
|
||||
@@ -1923,6 +1951,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
|
||||
localEnv.displayChanged());
|
||||
}
|
||||
}
|
||||
super.initializeDesktopProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -83,12 +83,12 @@ public final class X11GraphicsDevice extends GraphicsDevice
|
||||
|
||||
public X11GraphicsDevice(int screennum) {
|
||||
this.screen = screennum;
|
||||
this.bounds = getBoundsImpl();
|
||||
int scaleFactor = initScaleFactor(-1);
|
||||
synchronized (isScaleFactorDefault) {
|
||||
isScaleFactorDefault.set(scaleFactor == -1);
|
||||
this.scale = isScaleFactorDefault.get() ? 1 : scaleFactor;
|
||||
}
|
||||
this.bounds = getBoundsImpl();
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -256,11 +256,19 @@ public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
updateWaylandMonitorScaling();
|
||||
|
||||
for (int id = 0; id < numScreens; ++id) {
|
||||
devices.put(id, old.containsKey(id) ? old.remove(id) :
|
||||
new X11GraphicsDevice(id));
|
||||
X11GraphicsDevice reused = old.remove(id);
|
||||
X11GraphicsDevice gd = reused != null ? reused : new X11GraphicsDevice(id);
|
||||
devices.put(id, gd);
|
||||
if (LogDisplay.ENABLED) {
|
||||
LogDisplay log = reused != null ? LogDisplay.CHANGED : LogDisplay.ADDED;
|
||||
log.log(id, gd.getBounds(), gd.getScaleFactor());
|
||||
}
|
||||
}
|
||||
// if a device was not reused it should be invalidated
|
||||
for (X11GraphicsDevice gd : old.values()) {
|
||||
if (LogDisplay.ENABLED) {
|
||||
LogDisplay.REMOVED.log(gd.getScreen(), gd.getBounds(), gd.getScaleFactor());
|
||||
}
|
||||
oldDevices.add(new WeakReference<>(gd));
|
||||
}
|
||||
// Need to notify old devices, in case the user hold the reference to it
|
||||
|
||||
@@ -29,6 +29,7 @@ package sun.awt.wl;
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.AWTAccessor.ComponentAccessor;
|
||||
import sun.awt.PaintEventDispatcher;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.awt.event.IgnorePaintEvent;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
@@ -119,8 +120,8 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
boolean visible = false;
|
||||
|
||||
private final Object dataLock = new Object();
|
||||
int width; // protected by dataLock
|
||||
int height; // protected by dataLock
|
||||
int width; // in native pixels, protected by dataLock
|
||||
int height; // in native pixels, protected by dataLock
|
||||
int wlBufferScale; // protected by dataLock
|
||||
double effectiveScale; // protected by dataLock
|
||||
|
||||
@@ -354,7 +355,47 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
void updateSurfaceData() {
|
||||
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
|
||||
getBufferWidth(), getBufferHeight(), getBufferScale());
|
||||
updateWindowGeometry();
|
||||
}
|
||||
|
||||
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,
|
||||
// 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
nativeSetSurfaceSize(nativePtr, thisWidth, thisHeight);
|
||||
if (!surfaceData.getColorModel().hasAlpha()) {
|
||||
nativeSetOpaqueRegion(nativePtr,
|
||||
nativeVisibleBounds.x, nativeVisibleBounds.y,
|
||||
nativeVisibleBounds.width, nativeVisibleBounds.height);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void configureWLSurface() {
|
||||
@@ -523,11 +564,10 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scale of wl_buffer attached to this component's wl_surface.
|
||||
* Buffer coordinate space is linearly scaled wrt the component (or surface)
|
||||
* coordinate space, so component's coordinates have to be translated
|
||||
* to buffers' whenever Wayland protocol requires "buffer-local" coordinates.
|
||||
* See wl_surface.set_buffer_scale in wayland.xml for more details.
|
||||
* 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) {
|
||||
@@ -553,22 +593,6 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWindowGeometry() {
|
||||
// From xdg-shell.xml:
|
||||
// "The window geometry of a surface is its "visible bounds" from the
|
||||
// user's perspective. Client-side decorations often have invisible
|
||||
// portions like drop-shadows which should be ignored for the
|
||||
// purposes of aligning, placing and constraining windows"
|
||||
Rectangle nativeVisibleBounds = getVisibleBounds();
|
||||
nativeVisibleBounds.x = javaUnitsToSurfaceUnits(nativeVisibleBounds.x);
|
||||
nativeVisibleBounds.y = javaUnitsToSurfaceUnits(nativeVisibleBounds.y);
|
||||
nativeVisibleBounds.width = javaUnitsToSurfaceUnits(nativeVisibleBounds.width);
|
||||
nativeVisibleBounds.height = javaUnitsToSurfaceUnits(nativeVisibleBounds.height);
|
||||
performLocked(() -> nativeSetWindowGeometry(nativePtr,
|
||||
nativeVisibleBounds.x, nativeVisibleBounds.y,
|
||||
nativeVisibleBounds.width, nativeVisibleBounds.height));
|
||||
}
|
||||
|
||||
public void coalescePaintEvent(PaintEvent e) {
|
||||
Rectangle r = e.getUpdateRect();
|
||||
if (!(e instanceof IgnorePaintEvent)) {
|
||||
@@ -728,20 +752,6 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
public Dimension getMinimumSize() {
|
||||
return target.getSize();
|
||||
}
|
||||
|
||||
void setMinimumSizeTo(Dimension minSize) {
|
||||
Dimension nativeSize = constrainSize(minSize);
|
||||
nativeSize.width = javaUnitsToSurfaceUnits(nativeSize.width);
|
||||
nativeSize.height = javaUnitsToSurfaceUnits(nativeSize.height);
|
||||
performLocked(() -> nativeSetMinimumSize(nativePtr, nativeSize.width, nativeSize.height));
|
||||
}
|
||||
|
||||
void setMaximumSizeTo(Dimension maxSize) {
|
||||
Dimension nativeSize = constrainSize(maxSize);
|
||||
nativeSize.width = javaUnitsToSurfaceUnits(nativeSize.width);
|
||||
nativeSize.height = javaUnitsToSurfaceUnits(nativeSize.height);
|
||||
performLocked(() -> nativeSetMaximumSize(nativePtr, nativeSize.width, nativeSize.height));
|
||||
}
|
||||
|
||||
void showWindowMenu(int x, int y) {
|
||||
int xNative = javaUnitsToSurfaceUnits(x);
|
||||
@@ -1023,6 +1033,8 @@ public class WLComponentPeer implements ComponentPeer {
|
||||
private native void nativeRequestFullScreen(long ptr, int wlID);
|
||||
private native void nativeRequestUnsetFullScreen(long ptr);
|
||||
|
||||
private native void nativeSetSurfaceSize(long ptr, int width, int height);
|
||||
private native void nativeSetOpaqueRegion(long ptr, int x, int y, int width, int height);
|
||||
private native void nativeSetWindowGeometry(long ptr, int x, int y, int width, int height);
|
||||
private native void nativeSetMinimumSize(long ptr, int width, int height);
|
||||
private native void nativeSetMaximumSize(long ptr, int width, int height);
|
||||
|
||||
@@ -47,6 +47,7 @@ public abstract class WLDecoratedPeer extends WLWindowPeer {
|
||||
public abstract boolean isResizable();
|
||||
public abstract boolean isInteractivelyResizable();
|
||||
|
||||
public abstract boolean isFrameStateSupported(int state);
|
||||
public abstract void setState(int newState);
|
||||
public abstract int getState();
|
||||
public abstract void setExtendedState(int newState);
|
||||
|
||||
@@ -59,9 +59,14 @@ public class WLDialogPeer extends WLDecoratedPeer implements DialogPeer {
|
||||
return ((Dialog)target).getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFrameStateSupported(int state) {
|
||||
return state == Frame.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(int newState) {
|
||||
throw new UnsupportedOperationException();
|
||||
// Ignored
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,6 +76,6 @@ public class WLDialogPeer extends WLDecoratedPeer implements DialogPeer {
|
||||
|
||||
@Override
|
||||
public void setExtendedState(int newState) {
|
||||
throw new UnsupportedOperationException();
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,19 +33,28 @@ import java.util.function.Supplier;
|
||||
|
||||
public class WLFrameDecoration {
|
||||
private static final int HEIGHT = 30;
|
||||
private static final int BUTTON_ICON_SIZE = 3;
|
||||
private static final int BUTTON_CIRCLE_SIZE = 9;
|
||||
private static final int BUTTON_MAXIMIZED_LINE_GAP = 2;
|
||||
private static final int BUTTON_ICON_SIZE = 4;
|
||||
private static final int BUTTON_CIRCLE_SIZE = 10;
|
||||
private static final Font FONT = new Font(Font.DIALOG, Font.BOLD, 12);
|
||||
private static final Color BACKGROUND = Color.white;
|
||||
private static final Color ICON_BACKGROUND = new Color(0xe8e8e8);
|
||||
private static final Color ICON_HOVERED_BACKGROUND = new Color(0xe0e0e0);
|
||||
private static final Color ICON_PRESSED_BACKGROUND = Color.lightGray;
|
||||
private static final Color ACTIVE_BACKGROUND = new Color(0xebebeb);
|
||||
private static final Color ACTIVE_BACKGROUND_DARK = new Color(0x222222);
|
||||
private static final Color INACTIVE_BACKGROUND = new Color(0xfafafa);
|
||||
private static final Color INACTIVE_BACKGROUND_DARK = new Color(0x2c2c2c);
|
||||
private static final Color ICON_BACKGROUND = ACTIVE_BACKGROUND;
|
||||
private static final Color ICON_BACKGROUND_DARK = ACTIVE_BACKGROUND_DARK;
|
||||
private static final Color ICON_HOVERED_BACKGROUND = new Color(0xd1d1d1);
|
||||
private static final Color ICON_HOVERED_BACKGROUND_DARK = new Color(0x373737);
|
||||
private static final Color ICON_PRESSED_BACKGROUND = new Color(0xc0c0c0);
|
||||
private static final Color ICON_PRESSED_BACKGROUND_DARK = new Color(0x565656);
|
||||
private static final Color ACTIVE_FOREGROUND = Color.darkGray;
|
||||
private static final Color ACTIVE_FOREGROUND_DARK = new Color(0xf7f7f7);
|
||||
private static final Color INACTIVE_FOREGROUND = Color.gray;
|
||||
private static final Color INACTIVE_FOREGROUND_DARK = new Color(0xb5b5b5);
|
||||
private static final int SIGNIFICANT_DRAG_DISTANCE = 4;
|
||||
private static final int RESIZE_EDGE_THICKNESS = 5;
|
||||
|
||||
private static volatile boolean isDarkTheme = false;
|
||||
|
||||
private static final int XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1;
|
||||
private static final int XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2;
|
||||
private static final int XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4;
|
||||
@@ -144,6 +153,43 @@ public class WLFrameDecoration {
|
||||
return numButtons * HEIGHT;
|
||||
}
|
||||
|
||||
private static boolean isDarkTheme() {
|
||||
return isDarkTheme;
|
||||
}
|
||||
|
||||
private static void updateTheme() {
|
||||
Boolean isDark = (Boolean) Toolkit.getDefaultToolkit().getDesktopProperty("awt.os.theme.isDark");
|
||||
isDarkTheme = isDark != null && isDark;
|
||||
}
|
||||
|
||||
private static Color getBackgroundColor(boolean isActive) {
|
||||
if (isActive) {
|
||||
return isDarkTheme() ? ACTIVE_BACKGROUND_DARK : ACTIVE_BACKGROUND;
|
||||
} else {
|
||||
return isDarkTheme() ? INACTIVE_BACKGROUND_DARK : INACTIVE_BACKGROUND;
|
||||
}
|
||||
}
|
||||
|
||||
private static Color getIconBackground() {
|
||||
return isDarkTheme() ? ICON_BACKGROUND_DARK : ICON_BACKGROUND;
|
||||
}
|
||||
|
||||
private static Color getIconHoveredBackground() {
|
||||
return isDarkTheme() ? ICON_HOVERED_BACKGROUND_DARK : ICON_HOVERED_BACKGROUND;
|
||||
}
|
||||
|
||||
private static Color getIconPressedBackground() {
|
||||
return isDarkTheme() ? ICON_PRESSED_BACKGROUND_DARK : ICON_PRESSED_BACKGROUND;
|
||||
}
|
||||
|
||||
private static Color getForeground(boolean isActive) {
|
||||
if (isActive) {
|
||||
return isDarkTheme() ? ACTIVE_FOREGROUND_DARK : ACTIVE_FOREGROUND;
|
||||
} else {
|
||||
return isDarkTheme() ? INACTIVE_FOREGROUND_DARK : INACTIVE_FOREGROUND;
|
||||
}
|
||||
}
|
||||
|
||||
public void paint(final Graphics g) {
|
||||
if (isUndecorated) return;
|
||||
|
||||
@@ -152,6 +198,7 @@ public class WLFrameDecoration {
|
||||
if (width <= 0 || height <= 0) return;
|
||||
Graphics2D g2d = (Graphics2D) g.create(0, 0, width, HEIGHT);
|
||||
try {
|
||||
updateTheme();
|
||||
doPaint(g2d);
|
||||
} finally {
|
||||
g2d.dispose();
|
||||
@@ -162,12 +209,12 @@ public class WLFrameDecoration {
|
||||
private void doPaint(Graphics2D g) {
|
||||
int width = peer.getWidth();
|
||||
String title = peer.getTitle();
|
||||
Color foregroundColor = active ? ACTIVE_FOREGROUND : INACTIVE_FOREGROUND;
|
||||
Color foregroundColor = getForeground(active);
|
||||
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
g.setColor(BACKGROUND);
|
||||
g.setColor(getBackgroundColor(active));
|
||||
g.fillRect(0, 0, width, HEIGHT);
|
||||
|
||||
paintTitle(g, title, foregroundColor, width);
|
||||
@@ -204,8 +251,8 @@ public class WLFrameDecoration {
|
||||
|
||||
private void paintButtonBackground(Graphics2D g, Point center, ButtonState state) {
|
||||
if (active) {
|
||||
g.setColor(state.pressed ? ICON_PRESSED_BACKGROUND :
|
||||
state.hovered ? ICON_HOVERED_BACKGROUND : ICON_BACKGROUND);
|
||||
g.setColor(state.pressed ? getIconPressedBackground() :
|
||||
state.hovered ? getIconHoveredBackground() : getIconBackground());
|
||||
g.fill(new Ellipse2D.Float(center.x - BUTTON_CIRCLE_SIZE + .5f,
|
||||
center.y - BUTTON_CIRCLE_SIZE + .5f,
|
||||
2 * BUTTON_CIRCLE_SIZE, 2 * BUTTON_CIRCLE_SIZE));
|
||||
@@ -223,22 +270,28 @@ public class WLFrameDecoration {
|
||||
private void paintMaximizeButton(Graphics2D g, Point center, Color foregroundColor) {
|
||||
g.setColor(foregroundColor);
|
||||
if (peer.getState() == Frame.MAXIMIZED_BOTH) {
|
||||
g.drawRect(center.x - BUTTON_ICON_SIZE, center.y - BUTTON_ICON_SIZE + BUTTON_MAXIMIZED_LINE_GAP,
|
||||
2 * BUTTON_ICON_SIZE - BUTTON_MAXIMIZED_LINE_GAP, 2 * BUTTON_ICON_SIZE - BUTTON_MAXIMIZED_LINE_GAP);
|
||||
g.drawLine(center.x - BUTTON_ICON_SIZE + BUTTON_MAXIMIZED_LINE_GAP, center.y - BUTTON_ICON_SIZE,
|
||||
center.x + BUTTON_ICON_SIZE, center.y - BUTTON_ICON_SIZE);
|
||||
g.drawLine(center.x + BUTTON_ICON_SIZE, center.y - BUTTON_ICON_SIZE,
|
||||
center.x + BUTTON_ICON_SIZE, center.y + BUTTON_ICON_SIZE - BUTTON_MAXIMIZED_LINE_GAP);
|
||||
g.drawLine(center.x - BUTTON_ICON_SIZE, center.y,
|
||||
center.x, center.y - BUTTON_ICON_SIZE);
|
||||
g.drawLine(center.x, center.y - BUTTON_ICON_SIZE,
|
||||
center.x + BUTTON_ICON_SIZE, center.y);
|
||||
g.drawLine(center.x - BUTTON_ICON_SIZE, center.y,
|
||||
center.x, center.y + BUTTON_ICON_SIZE);
|
||||
g.drawLine(center.x, center.y + BUTTON_ICON_SIZE,
|
||||
center.x + BUTTON_ICON_SIZE, center.y);
|
||||
} else {
|
||||
g.drawRect(center.x - BUTTON_ICON_SIZE, center.y - BUTTON_ICON_SIZE,
|
||||
2 * BUTTON_ICON_SIZE, 2 * BUTTON_ICON_SIZE);
|
||||
g.drawLine(center.x - BUTTON_ICON_SIZE, center.y + BUTTON_ICON_SIZE / 2,
|
||||
center.x, center.y - BUTTON_ICON_SIZE / 2);
|
||||
g.drawLine(center.x, center.y - BUTTON_ICON_SIZE / 2,
|
||||
center.x + BUTTON_ICON_SIZE, center.y + BUTTON_ICON_SIZE / 2);
|
||||
}
|
||||
}
|
||||
|
||||
private void paintMinimizeButton(Graphics2D g, Point center, Color foregroundColor) {
|
||||
g.setColor(foregroundColor);
|
||||
g.drawLine(center.x - BUTTON_ICON_SIZE, center.y + BUTTON_ICON_SIZE,
|
||||
center.x + BUTTON_ICON_SIZE, center.y + BUTTON_ICON_SIZE);
|
||||
g.drawLine(center.x - BUTTON_ICON_SIZE, center.y - BUTTON_ICON_SIZE / 2,
|
||||
center.x, center.y + BUTTON_ICON_SIZE / 2);
|
||||
g.drawLine(center.x, center.y + BUTTON_ICON_SIZE / 2,
|
||||
center.x + BUTTON_ICON_SIZE, center.y - BUTTON_ICON_SIZE / 2);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@@ -320,7 +373,7 @@ public class WLFrameDecoration {
|
||||
} else if (e.getID() == MouseEvent.MOUSE_DRAGGED && pressedInDragStartArea() && isSignificantDrag(point)) {
|
||||
peer.startDrag();
|
||||
} else if (e.getID() == MouseEvent.MOUSE_CLICKED && e.getClickCount() == 2 && pressedInDragStartArea()
|
||||
&& peer.isResizable()) {
|
||||
&& peer.isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
|
||||
toggleMaximizedState();
|
||||
} else if (e.getID() == MouseEvent.MOUSE_MOVED && !pointerInside) {
|
||||
peer.updateCursorImmediately();
|
||||
|
||||
@@ -83,6 +83,15 @@ public class WLFramePeer extends WLDecoratedPeer implements FramePeer {
|
||||
return getFrame().getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFrameStateSupported(int state) {
|
||||
return switch (state) {
|
||||
case Frame.NORMAL, Frame.ICONIFIED, Frame.MAXIMIZED_BOTH, Frame.MAXIMIZED_HORIZ, Frame.MAXIMIZED_VERT ->
|
||||
true;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(int newState) {
|
||||
if (!isVisible()) return;
|
||||
|
||||
@@ -162,6 +162,11 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
width, height, widthMm, heightMm, scale);
|
||||
devices.add(gd);
|
||||
}
|
||||
if (LogDisplay.ENABLED) {
|
||||
double effectiveScale = effectiveScaleFrom(scale);
|
||||
LogDisplay log = newOutput ? LogDisplay.ADDED : LogDisplay.CHANGED;
|
||||
log.log(wlID, (int) (width / effectiveScale) + "x" + (int) (height / effectiveScale), effectiveScale);
|
||||
}
|
||||
}
|
||||
|
||||
updateTotalDisplayBounds();
|
||||
@@ -201,6 +206,11 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
.findFirst();
|
||||
if (deviceOptional.isPresent()) {
|
||||
final WLGraphicsDevice destroyedDevice = deviceOptional.get();
|
||||
if (LogDisplay.ENABLED) {
|
||||
WLGraphicsConfig config = (WLGraphicsConfig) destroyedDevice.getDefaultConfiguration();
|
||||
Rectangle bounds = config.getBounds();
|
||||
LogDisplay.REMOVED.log(wlID, bounds.width + "x" + bounds.height, config.getEffectiveScale());
|
||||
}
|
||||
devices.remove(destroyedDevice);
|
||||
final WLGraphicsDevice similarDevice = getSimilarDevice(destroyedDevice);
|
||||
if (similarDevice != null) destroyedDevice.invalidate(similarDevice);
|
||||
|
||||
@@ -89,13 +89,6 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void configureWLSurface() {
|
||||
super.configureWLSurface();
|
||||
updateMinimumSize();
|
||||
updateMaximumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getInsets() {
|
||||
return new Insets(0, 0, 0, 0);
|
||||
@@ -138,21 +131,7 @@ public class WLWindowPeer extends WLComponentPeer implements WindowPeer {
|
||||
|
||||
@Override
|
||||
public void updateMinimumSize() {
|
||||
final Dimension minSize = getMinimumSize();
|
||||
super.setMinimumSizeTo(minSize);
|
||||
}
|
||||
|
||||
public void updateMaximumSize() {
|
||||
// TODO: make sure this is called when our target's maximum size changes
|
||||
final Dimension maxSize = target.isMaximumSizeSet() ? target.getMaximumSize() : null;
|
||||
if (maxSize != null) super.setMaximumSizeTo(maxSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateSurfaceData() {
|
||||
updateMinimumSize();
|
||||
updateMaximumSize();
|
||||
super.updateSurfaceData();
|
||||
// No op, it gets updated at each resize
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -101,7 +101,7 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
|
||||
}
|
||||
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException("Not supported yet");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,11 +26,14 @@
|
||||
|
||||
package sun.java2d.wl;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Window;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.wl.WLComponentPeer;
|
||||
import sun.awt.wl.WLSMGraphicsConfig;
|
||||
import sun.java2d.SurfaceData;
|
||||
@@ -46,9 +49,14 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
|
||||
|
||||
public native void assignSurface(long surfacePtr);
|
||||
|
||||
private native void initOps(int width, int height, int scale, int backgroundRGB, int wlShmFormat);
|
||||
private native void initOps(int width, int height, int backgroundRGB, int wlShmFormat, boolean perfCountersEnabled);
|
||||
private static native void initIDs();
|
||||
|
||||
private WLSMSurfaceData(WLComponentPeer peer, SurfaceType surfaceType, ColorModel colorModel, int scale, int wlShmFormat) {
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
|
||||
private WLSMSurfaceData(WLComponentPeer peer, SurfaceType surfaceType, ColorModel colorModel, int wlShmFormat, boolean perfCountersEnabled) {
|
||||
super(surfaceType, colorModel);
|
||||
this.peer = peer;
|
||||
|
||||
@@ -60,10 +68,9 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
|
||||
int height = peer.getBufferHeight();
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(String.format("Shared memory surface data %dx%d x%d scale, format %d", width, height, scale, wlShmFormat));
|
||||
log.fine(String.format("Shared memory surface data %dx%d, format %d", width, height, wlShmFormat));
|
||||
}
|
||||
|
||||
initOps(width, height, scale, backgroundPixel, wlShmFormat);
|
||||
initOps(width, height, backgroundPixel, wlShmFormat, perfCountersEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +82,9 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
|
||||
}
|
||||
ColorModel cm = graphicsConfig.getColorModel();
|
||||
SurfaceType surfaceType = graphicsConfig.getSurfaceType();
|
||||
return new WLSMSurfaceData(peer, surfaceType, cm, graphicsConfig.getWlScale(), graphicsConfig.getWlShmFormat());
|
||||
Window target = peer.getTarget() instanceof Window ? (Window)peer.getTarget() : null;
|
||||
boolean perfCountersEnabled = target != null && AWTAccessor.getWindowAccessor().countersEnabled(target);
|
||||
return new WLSMSurfaceData(peer, surfaceType, cm, graphicsConfig.getWlShmFormat(), perfCountersEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,6 +150,30 @@ public class WLSMSurfaceData extends SurfaceData implements WLSurfaceDataExt {
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private void bufferAttached() {
|
||||
// Called from the native code when a buffer has just been attached to this surface
|
||||
// but the surface has not been committed yet.
|
||||
peer.updateSurfaceSize();
|
||||
}
|
||||
|
||||
private void countNewFrame() {
|
||||
// Called from the native code when this surface data has been sent to the Wayland server
|
||||
Component target = peer.getTarget();
|
||||
if (target instanceof Window window) {
|
||||
AWTAccessor.getWindowAccessor().bumpCounter(window, "java2d.native.frames");
|
||||
}
|
||||
}
|
||||
|
||||
private void countDroppedFrame() {
|
||||
// Called from the native code when an attempt was made to send this surface data to
|
||||
// the Wayland server, but that attempt was not successful. This can happen, for example,
|
||||
// when those attempts are too frequent.
|
||||
Component target = peer.getTarget();
|
||||
if (target instanceof Window window) {
|
||||
AWTAccessor.getWindowAccessor().bumpCounter(window, "java2d.native.framesDropped");
|
||||
}
|
||||
}
|
||||
|
||||
private native int pixelAt(int x, int y);
|
||||
private native int [] pixelsAt(int x, int y, int width, int height);
|
||||
}
|
||||
|
||||
@@ -26,25 +26,19 @@
|
||||
|
||||
package sun.java2d.wl;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.ImageCapabilities;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.VolatileImage;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
public class WLVolatileSurfaceManager extends VolatileSurfaceManager implements PropertyChangeListener {
|
||||
private static final String SCALE_PROPERTY_NAME = "graphicsContextScaleTransform";
|
||||
|
||||
public class WLVolatileSurfaceManager extends VolatileSurfaceManager {
|
||||
public WLVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
|
||||
super(vImg, context);
|
||||
Component component = vImg.getComponent();
|
||||
if (component != null) {
|
||||
component.addPropertyChangeListener(SCALE_PROPERTY_NAME, this);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isAccelerationEnabled() {
|
||||
@@ -63,9 +57,12 @@ public class WLVolatileSurfaceManager extends VolatileSurfaceManager implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
assert SCALE_PROPERTY_NAME.equals(evt.getPropertyName());
|
||||
|
||||
displayChanged();
|
||||
public int validate(GraphicsConfiguration gc) {
|
||||
AffineTransform newTx = gc.getDefaultTransform();
|
||||
if (!Objects.equals(atCurrent, newTx)) {
|
||||
// May need a different size on another display
|
||||
return VolatileImage.IMAGE_INCOMPATIBLE;
|
||||
}
|
||||
return super.validate(gc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -24,93 +24,114 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "jni.h"
|
||||
#include "WLVKSurfaceData.h"
|
||||
#include <jni_util.h>
|
||||
#include <Trace.h>
|
||||
#include <SurfaceData.h>
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKBase.h"
|
||||
#include <jni_util.h>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include "VKSurfaceData.h"
|
||||
#include "WLVKSurfaceData.h"
|
||||
|
||||
extern struct wl_display *wl_display;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_initOps
|
||||
(JNIEnv *env, jobject vksd, jint width, jint height, jint scale, jint backgroundRGB) {
|
||||
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);
|
||||
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
|
||||
auto *sd = new WLVKSurfaceData(width, height, scale, backgroundRGB);
|
||||
sd->attachToJavaSurface(env, vksd);
|
||||
#endif /* !HEADLESS */
|
||||
}
|
||||
VKWinSDOps *vkwinsdo = (VKWinSDOps *)SurfaceData_InitOps(env, vksd, sizeof(VKWinSDOps));
|
||||
vkwinsdo->vksdOps.drawableType = VKSD_WINDOW;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_vulkan_WLVKSurfaceData_assignSurface(JNIEnv *env, jobject wsd, jlong wlSurfacePtr)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
auto sd = (WLVKSurfaceData*)SurfaceData_GetOps(env, wsd);
|
||||
if (sd == nullptr) {
|
||||
if (vkwinsdo == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto wlSurface = (struct wl_surface*)jlong_to_ptr(wlSurfacePtr);
|
||||
J2dTraceLn2(J2D_TRACE_INFO, "WLVKSurfaceData_assignSurface wl_surface(%p) wl_display(%p)",
|
||||
wlSurface, wl_display);
|
||||
WLVKSDOps *wlvksdo = (WLVKSDOps *)malloc(sizeof(WLVKSDOps));
|
||||
|
||||
try {
|
||||
sd->validate(wlSurface);
|
||||
} catch (std::exception& e) {
|
||||
J2dRlsTrace1(J2D_TRACE_ERROR, "WLVKSurfaceData_assignSurface: %s\n", e.what());
|
||||
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 */
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
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;
|
||||
}
|
||||
WLVKSDOps* wlvksdo = (WLVKSDOps *)vkwinsdo->privOps;
|
||||
if (wlvksdo == NULL) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "WLVKSurfaceData_assignSurface: WLVKSDOps is NULL");
|
||||
return;
|
||||
}
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
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;
|
||||
|
||||
if (ge->vkCreateWaylandSurfaceKHR(ge->vkInstance,
|
||||
&surfaceCreateInfo,
|
||||
NULL,
|
||||
&vkwinsdo->surface) != VK_SUCCESS) {
|
||||
J2dRlsTrace(J2D_TRACE_ERROR, "WLVKSurfaceData_assignSurface: WLVKSDOps is NULL");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VKSD_InitImageSurface(&vkwinsdo->vksdOps);
|
||||
VKSD_InitWindowSurface(vkwinsdo);
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "WLVKSurfaceData_assignSurface: Created WaylandSurfaceKHR");
|
||||
|
||||
J2dTraceLn2(J2D_TRACE_INFO, "WLVKSurfaceData_assignSurface wl_surface(%p) wl_display(%p)", wlSurface, 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?
|
||||
// TODO?
|
||||
#endif /* !HEADLESS */
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_vulkan_WLVKSurfaceData_revalidate(JNIEnv *env, jobject wsd,
|
||||
jint width, jint height, jint scale)
|
||||
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
|
||||
auto sd = (WLVKSurfaceData*)SurfaceData_GetOps(env, wsd);
|
||||
if (sd == nullptr) {
|
||||
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);
|
||||
|
||||
try {
|
||||
sd->revalidate(width, height, scale);
|
||||
} catch (std::exception& e) {
|
||||
J2dRlsTrace1(J2D_TRACE_ERROR, "WLVKSurfaceData_revalidate: %s\n", e.what());
|
||||
}
|
||||
|
||||
vksdo->width = width;
|
||||
vksdo->height = height;
|
||||
vksdo->scale = scale;
|
||||
#endif /* !HEADLESS */
|
||||
}
|
||||
|
||||
void WLVKSurfaceData::validate(wl_surface* wls)
|
||||
{
|
||||
if (wls ==_wl_surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& device = VKGraphicsEnvironment::graphics_environment()->default_device();
|
||||
device.waitIdle(); // TODO wait until device is done with old swapchain
|
||||
auto surface = VKGraphicsEnvironment::graphics_environment()->vk_instance()
|
||||
.createWaylandSurfaceKHR({{}, wl_display, wls});
|
||||
|
||||
_wl_surface = wls;
|
||||
reset(device, std::move(surface));
|
||||
revalidate(width(), height(), scale());
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* 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
|
||||
@@ -27,18 +27,17 @@
|
||||
#ifndef WLVKSurfaceData_h_Included
|
||||
#define WLVKSurfaceData_h_Included
|
||||
|
||||
#include "awt_p.h"
|
||||
#include "VKSurfaceData.h"
|
||||
|
||||
#ifndef HEADLESS
|
||||
#ifdef HEADLESS
|
||||
#define WLVKSDOps void
|
||||
#else /* HEADLESS */
|
||||
|
||||
class WLVKSurfaceData : public VKSwapchainSurfaceData {
|
||||
wl_surface* _wl_surface;
|
||||
public:
|
||||
WLVKSurfaceData(uint32_t w, uint32_t h, uint32_t s, uint32_t bgc)
|
||||
: VKSwapchainSurfaceData(w, h, s, bgc), _wl_surface(nullptr) {}
|
||||
void validate(wl_surface* wls);
|
||||
};
|
||||
typedef struct _WLVKSDOps {
|
||||
struct wl_surface* wl_surface;
|
||||
} WLVKSDOps;
|
||||
|
||||
#endif /* HEADLESS */
|
||||
|
||||
#endif /* WLVKSurfaceData_h_Included */
|
||||
#endif /* WLVKSurfaceData_h_Included */
|
||||
@@ -73,6 +73,8 @@ AssertDrawLockIsHeld(WLSurfaceBufferManager* manager, const char * file, int lin
|
||||
#define MUTEX_LOCK(m) if (pthread_mutex_lock(&(m))) { WL_FATAL_ERROR("Failed to lock mutex"); }
|
||||
#define MUTEX_UNLOCK(m) if (pthread_mutex_unlock(&(m))) { WL_FATAL_ERROR("Failed to unlock mutex"); }
|
||||
|
||||
#define CLAMP(val, min, max) ((val) < (min) ? (min) : ((val) > (max) ? (max) : (val)))
|
||||
|
||||
/**
|
||||
* The maximum number of buffers that can be simultaneously in use by Wayland.
|
||||
* When a new frame is ready to be sent to Wayland and the number of buffers
|
||||
@@ -88,7 +90,6 @@ AssertDrawLockIsHeld(WLSurfaceBufferManager* manager, const char * file, int lin
|
||||
const int MAX_BUFFERS_IN_USE = 2;
|
||||
|
||||
static bool traceEnabled; // set the J2D_STATS env var to enable
|
||||
static bool traceFPSEnabled; // set the J2D_FPS env var to enable
|
||||
|
||||
/**
|
||||
* Represents one rectangular area linked into a list.
|
||||
@@ -269,9 +270,6 @@ struct WLSurfaceBufferManager {
|
||||
/// Does not exceed MAX_BUFFERS_IN_USE elements.
|
||||
WLSurfaceBuffer * buffersInUse; // only accessed under showLock
|
||||
|
||||
/// The scale of wl_surface (see Wayland docs for more info on that).
|
||||
jint scale; // only accessed under showLock
|
||||
|
||||
pthread_mutex_t drawLock;
|
||||
|
||||
/**
|
||||
@@ -280,6 +278,11 @@ struct WLSurfaceBufferManager {
|
||||
* on the screen.
|
||||
*/
|
||||
WLDrawBuffer bufferForDraw; // only accessed under drawLock
|
||||
|
||||
jobject surfaceDataWeakRef;
|
||||
BufferEventCallback frameSentCallback;
|
||||
BufferEventCallback frameDroppedCallback;
|
||||
BufferEventCallback bufferAttachedCallback;
|
||||
};
|
||||
|
||||
static inline void
|
||||
@@ -304,7 +307,7 @@ AssertShowLockIsHeld(WLSurfaceBufferManager* manager, const char * file, int lin
|
||||
static jlong
|
||||
GetJavaTimeNanos(void) {
|
||||
jlong result = 0;
|
||||
if (traceEnabled || traceFPSEnabled) {
|
||||
if (traceEnabled) {
|
||||
struct timespec tp;
|
||||
const jlong NANOSECS_PER_SEC = 1000000000L;
|
||||
int status = clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
@@ -330,24 +333,6 @@ WLBufferTrace(WLSurfaceBufferManager* manager, const char *fmt, ...)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WLBufferTraceFrame(WLSurfaceBufferManager* manager)
|
||||
{
|
||||
if (traceFPSEnabled) {
|
||||
static jlong lastFrameTime = 0;
|
||||
static int frameCount = 0;
|
||||
|
||||
jlong curTime = GetJavaTimeNanos();
|
||||
frameCount++;
|
||||
if (curTime - lastFrameTime > 1000000000L) {
|
||||
fprintf(stderr, "FPS: %d\n", frameCount);
|
||||
fflush(stderr);
|
||||
lastFrameTime = curTime;
|
||||
frameCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
SurfaceBufferSizeInBytes(WLSurfaceBuffer * buffer)
|
||||
{
|
||||
@@ -426,16 +411,14 @@ SurfaceBufferDestroy(WLSurfaceBuffer * buffer)
|
||||
static WLSurfaceBuffer *
|
||||
SurfaceBufferCreate(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
ASSERT_DRAW_LOCK_IS_HELD(manager);
|
||||
WLBufferTrace(manager, "SurfaceBufferCreate");
|
||||
|
||||
WLSurfaceBuffer * buffer = calloc(1, sizeof(WLSurfaceBuffer));
|
||||
if (!buffer) return NULL;
|
||||
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
buffer->width = manager->bufferForDraw.width;
|
||||
buffer->height = manager->bufferForDraw.height;
|
||||
MUTEX_UNLOCK(manager->drawLock);
|
||||
|
||||
buffer->bytesAllocated = SurfaceBufferSizeInBytes(buffer);
|
||||
buffer->wlPool = CreateShmPool(buffer->bytesAllocated, "jwlshm", (void**)&buffer->data, &buffer->fd);
|
||||
if (! buffer->wlPool) {
|
||||
@@ -467,32 +450,21 @@ SurfaceBufferCreate(WLSurfaceBufferManager * manager)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static bool
|
||||
SurfaceBufferNeedsResize(WLSurfaceBufferManager * manager, WLSurfaceBuffer* buffer)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
jint newWidth = manager->bufferForDraw.width;
|
||||
jint newHeight = manager->bufferForDraw.height;
|
||||
MUTEX_UNLOCK(manager->drawLock);
|
||||
|
||||
return newWidth != buffer->width || newHeight != buffer->height;
|
||||
}
|
||||
|
||||
static bool
|
||||
SurfaceBufferResize(WLSurfaceBufferManager * manager, WLSurfaceBuffer* buffer)
|
||||
{
|
||||
ASSERT_DRAW_LOCK_IS_HELD(manager);
|
||||
|
||||
assert(buffer != NULL);
|
||||
assert(buffer->wlBuffer != NULL);
|
||||
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
jint newWidth = manager->bufferForDraw.width;
|
||||
jint newHeight = manager->bufferForDraw.height;
|
||||
MUTEX_UNLOCK(manager->drawLock);
|
||||
|
||||
wl_buffer_destroy(buffer->wlBuffer);
|
||||
buffer->wlBuffer = NULL;
|
||||
DamageList_FreeAll(buffer->damageList);
|
||||
buffer->damageList = NULL;
|
||||
|
||||
buffer->width = newWidth;
|
||||
buffer->height = newHeight;
|
||||
@@ -584,6 +556,8 @@ SurfaceBufferNotifyReleased(WLSurfaceBufferManager * manager, struct wl_buffer *
|
||||
static void
|
||||
ShowBufferChooseFromFree(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
|
||||
assert(manager->buffersFree != NULL);
|
||||
|
||||
manager->bufferForShow.wlSurfaceBuffer = manager->buffersFree;
|
||||
@@ -594,12 +568,20 @@ ShowBufferChooseFromFree(WLSurfaceBufferManager * manager)
|
||||
static bool
|
||||
ShowBufferNeedsResize(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
return SurfaceBufferNeedsResize(manager, manager->bufferForShow.wlSurfaceBuffer);
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
ASSERT_DRAW_LOCK_IS_HELD(manager);
|
||||
|
||||
jint newWidth = manager->bufferForDraw.width;
|
||||
jint newHeight = manager->bufferForDraw.height;
|
||||
return newWidth != manager->bufferForShow.wlSurfaceBuffer->width || newHeight != manager->bufferForShow.wlSurfaceBuffer->height;
|
||||
}
|
||||
|
||||
static bool
|
||||
ShowBufferResize(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
ASSERT_DRAW_LOCK_IS_HELD(manager);
|
||||
|
||||
if (!SurfaceBufferResize(manager, manager->bufferForShow.wlSurfaceBuffer)) {
|
||||
SurfaceBufferDestroy(manager->bufferForShow.wlSurfaceBuffer);
|
||||
manager->bufferForShow.wlSurfaceBuffer = NULL;
|
||||
@@ -614,6 +596,8 @@ static bool
|
||||
ShowBufferCreate(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
ASSERT_DRAW_LOCK_IS_HELD(manager);
|
||||
|
||||
assert(manager->bufferForShow.wlSurfaceBuffer == NULL);
|
||||
|
||||
WLSurfaceBuffer* buffer = SurfaceBufferCreate(manager);
|
||||
@@ -630,6 +614,7 @@ static bool
|
||||
ShowBufferIsAvailable(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
ASSERT_DRAW_LOCK_IS_HELD(manager);
|
||||
|
||||
// Skip sending the next frame if the number of buffers that
|
||||
// had been sent to Wayland for displaying earlier is too large.
|
||||
@@ -660,19 +645,35 @@ ShowBufferIsAvailable(WLSurfaceBufferManager * manager)
|
||||
return false; // failed to resize, likely due to OOM
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (manager->frameDroppedCallback != NULL) {
|
||||
manager->frameDroppedCallback(manager->surfaceDataWeakRef);
|
||||
}
|
||||
}
|
||||
|
||||
return canSendMoreBuffers;
|
||||
}
|
||||
|
||||
static void
|
||||
TrySendShowBufferToWayland(WLSurfaceBufferManager * manager, bool sendNow)
|
||||
static bool
|
||||
TryCopyDrawBufferToShowBuffer(WLSurfaceBufferManager * manager, bool sendNow)
|
||||
{
|
||||
WLBufferTrace(manager, "TrySendShowBufferToWayland(%s)", sendNow ? "now" : "later");
|
||||
|
||||
MUTEX_LOCK(manager->drawLock); // So that the size doesn't change while we copy
|
||||
sendNow = sendNow && ShowBufferIsAvailable(manager);
|
||||
if (sendNow) {
|
||||
CopyDrawBufferToShowBuffer(manager);
|
||||
}
|
||||
MUTEX_UNLOCK(manager->drawLock);
|
||||
return sendNow;
|
||||
}
|
||||
|
||||
static void
|
||||
TrySendShowBufferToWayland(WLSurfaceBufferManager * manager, bool sendNow)
|
||||
{
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
|
||||
WLBufferTrace(manager, "TrySendShowBufferToWayland(%s)", sendNow ? "now" : "later");
|
||||
|
||||
if (TryCopyDrawBufferToShowBuffer(manager, sendNow)) {
|
||||
SendShowBufferToWayland(manager);
|
||||
} else {
|
||||
ScheduleFrameCallback(manager);
|
||||
@@ -767,7 +768,8 @@ SendShowBufferToWayland(WLSurfaceBufferManager * manager)
|
||||
|
||||
// wl_buffer_listener will release bufferForShow when Wayland's done with it
|
||||
wl_surface_attach(manager->wlSurface, buffer->wlBuffer, 0, 0);
|
||||
wl_surface_set_buffer_scale(manager->wlSurface, manager->scale);
|
||||
//NB: do not specify scale for the buffer; we scale with wp_viewporter
|
||||
manager->bufferAttachedCallback(manager->surfaceDataWeakRef);
|
||||
|
||||
// Better wait for the frame event so as not to overwhelm Wayland with
|
||||
// frequent surface updates that it cannot deliver to the screen anyway.
|
||||
@@ -785,32 +787,40 @@ SendShowBufferToWayland(WLSurfaceBufferManager * manager)
|
||||
|
||||
jlong endTime = GetJavaTimeNanos();
|
||||
WLBufferTrace(manager, "SendShowBufferToWayland (%lldns)", endTime - startTime);
|
||||
WLBufferTraceFrame(manager);
|
||||
if (manager->frameSentCallback != NULL) {
|
||||
manager->frameSentCallback(manager->surfaceDataWeakRef);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CopyDamagedArea(WLSurfaceBufferManager * manager, jint x, jint y, jint width, jint height)
|
||||
{
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
ASSERT_DRAW_LOCK_IS_HELD(manager);
|
||||
|
||||
assert(manager->bufferForShow.wlSurfaceBuffer != NULL);
|
||||
assert(manager->bufferForShow.wlSurfaceBuffer->data != NULL);
|
||||
assert(manager->bufferForDraw.data != NULL);
|
||||
assert(manager->bufferForDraw.width == manager->bufferForShow.wlSurfaceBuffer->width);
|
||||
assert(manager->bufferForDraw.height == manager->bufferForShow.wlSurfaceBuffer->height);
|
||||
assert(x >= 0);
|
||||
assert(y >= 0);
|
||||
assert(width >= 0);
|
||||
assert(height >= 0);
|
||||
assert(height + y >= 0);
|
||||
assert(width + x >= 0);
|
||||
assert(width <= manager->bufferForDraw.width);
|
||||
assert(height <= manager->bufferForDraw.height);
|
||||
assert(manager->bufferForShow.wlSurfaceBuffer->bytesAllocated >= DrawBufferSizeInBytes(manager));
|
||||
|
||||
jint bufferWidth = manager->bufferForDraw.width;
|
||||
jint bufferHeight = manager->bufferForDraw.height;
|
||||
|
||||
// Clamp the damaged area to the size of the destination in order not to crash in case of
|
||||
// an error on the client side that "damaged" an area larger than our buffer.
|
||||
x = CLAMP(x, 0, bufferWidth - 1);
|
||||
y = CLAMP(y, 0, bufferHeight - 1);
|
||||
width = CLAMP(width, 0, bufferWidth - x);
|
||||
height = CLAMP(height, 0, bufferHeight - y);
|
||||
|
||||
pixel_t * dest = manager->bufferForShow.wlSurfaceBuffer->data;
|
||||
pixel_t * src = manager->bufferForDraw.data;
|
||||
|
||||
for (jint i = y; i < height + y; i++) {
|
||||
pixel_t * dest_row = &dest[i * manager->bufferForDraw.width];
|
||||
pixel_t * src_row = &src [i * manager->bufferForDraw.width];
|
||||
pixel_t * dest_row = &dest[i * bufferWidth];
|
||||
pixel_t * src_row = &src [i * bufferWidth];
|
||||
for (jint j = x; j < width + x; j++) {
|
||||
dest_row[j] = src_row[j];
|
||||
}
|
||||
@@ -831,9 +841,11 @@ static void
|
||||
CopyDrawBufferToShowBuffer(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
ASSERT_SHOW_LOCK_IS_HELD(manager);
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
ASSERT_DRAW_LOCK_IS_HELD(manager);
|
||||
|
||||
if (manager->bufferForShow.wlSurfaceBuffer == NULL || manager->bufferForDraw.data == NULL) {
|
||||
if (manager->bufferForShow.wlSurfaceBuffer == NULL
|
||||
|| manager->bufferForDraw.data == NULL
|
||||
|| manager->bufferForDraw.resizePending) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -874,8 +886,6 @@ CopyDrawBufferToShowBuffer(WLSurfaceBufferManager * manager)
|
||||
|
||||
jlong endTime = GetJavaTimeNanos();
|
||||
WLBufferTrace(manager, "CopyDrawBufferToShowBuffer: copied %d area(s) in %lldns", count, endTime - startTime);
|
||||
|
||||
MUTEX_UNLOCK(manager->drawLock);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -934,10 +944,19 @@ HaveEnoughMemoryForWindow(jint width, jint height)
|
||||
}
|
||||
|
||||
WLSurfaceBufferManager *
|
||||
WLSBM_Create(jint width, jint height, jint scale, jint bgPixel, jint wlShmFormat)
|
||||
WLSBM_Create(jint width,
|
||||
jint height,
|
||||
jint bgPixel,
|
||||
jint wlShmFormat,
|
||||
jobject surfaceDataWeakRef,
|
||||
BufferEventCallback frameSentCallback,
|
||||
BufferEventCallback frameDroppedCallback,
|
||||
BufferEventCallback bufferAttachedCallback)
|
||||
{
|
||||
assert (surfaceDataWeakRef != NULL);
|
||||
assert (bufferAttachedCallback != NULL);
|
||||
|
||||
traceEnabled = getenv("J2D_STATS");
|
||||
traceFPSEnabled = getenv("J2D_FPS");
|
||||
|
||||
if (!HaveEnoughMemoryForWindow(width, height)) {
|
||||
return NULL;
|
||||
@@ -950,9 +969,12 @@ WLSBM_Create(jint width, jint height, jint scale, jint bgPixel, jint wlShmFormat
|
||||
|
||||
manager->bufferForDraw.width = width;
|
||||
manager->bufferForDraw.height = height;
|
||||
manager->scale = scale;
|
||||
manager->bgPixel = bgPixel;
|
||||
manager->format = wlShmFormat;
|
||||
manager->surfaceDataWeakRef = surfaceDataWeakRef;
|
||||
manager->frameSentCallback = frameSentCallback;
|
||||
manager->frameDroppedCallback = frameDroppedCallback;
|
||||
manager->bufferAttachedCallback = bufferAttachedCallback;
|
||||
|
||||
pthread_mutex_init(&manager->showLock, NULL);
|
||||
|
||||
@@ -996,6 +1018,9 @@ WLSBM_Destroy(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
J2dTrace1(J2D_TRACE_INFO, "WLSBM_Destroy: manger %p\n", manager);
|
||||
|
||||
JNIEnv* env = getEnv();
|
||||
(*env)->DeleteWeakGlobalRef(env, manager->surfaceDataWeakRef);
|
||||
|
||||
// NB: must never be called in parallel with the Wayland event handlers
|
||||
// because their callbacks retain a pointer to this manager.
|
||||
MUTEX_LOCK(manager->showLock);
|
||||
@@ -1047,7 +1072,7 @@ WLDrawBuffer *
|
||||
WLSBM_BufferAcquireForDrawing(WLSurfaceBufferManager * manager)
|
||||
{
|
||||
WLBufferTrace(manager, "WLSBM_BufferAcquireForDrawing(%d)", manager->bufferForDraw.frameID);
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
MUTEX_LOCK(manager->drawLock); // unlocked in WLSBM_BufferReturn()
|
||||
if (manager->bufferForDraw.resizePending) {
|
||||
WLBufferTrace(manager, "WLSBM_BufferAcquireForDrawing - creating a new draw buffer because the size has changed");
|
||||
DrawBufferResize(manager);
|
||||
@@ -1059,7 +1084,7 @@ void
|
||||
WLSBM_BufferReturn(WLSurfaceBufferManager * manager, WLDrawBuffer * buffer)
|
||||
{
|
||||
if (&manager->bufferForDraw == buffer) {
|
||||
MUTEX_UNLOCK(buffer->manager->drawLock);
|
||||
MUTEX_UNLOCK(buffer->manager->drawLock); // locked in WLSBM_BufferAcquireForDrawing()
|
||||
WLBufferTrace(manager, "WLSBM_BufferReturn(%d)", manager->bufferForDraw.frameID);
|
||||
} else {
|
||||
WL_FATAL_ERROR("WLSBM_BufferReturn() called with an unidentified buffer");
|
||||
@@ -1105,22 +1130,16 @@ WLSB_DataGet(WLDrawBuffer * buffer)
|
||||
}
|
||||
|
||||
void
|
||||
WLSBM_SizeChangeTo(WLSurfaceBufferManager * manager, jint width, jint height, jint scale)
|
||||
WLSBM_SizeChangeTo(WLSurfaceBufferManager * manager, jint width, jint height)
|
||||
{
|
||||
if (!HaveEnoughMemoryForWindow(width, height)) {
|
||||
JNU_ThrowOutOfMemoryError(getEnv(), "Wayland surface buffer too large");
|
||||
return;
|
||||
}
|
||||
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
MUTEX_LOCK(manager->showLock);
|
||||
const bool change_needed =
|
||||
manager->bufferForDraw.width != width
|
||||
|| manager->bufferForDraw.height != height
|
||||
|| manager->scale != scale;
|
||||
manager->scale = scale;
|
||||
|
||||
if (change_needed) {
|
||||
MUTEX_LOCK(manager->drawLock);
|
||||
if (manager->bufferForDraw.width != width || manager->bufferForDraw.height != height) {
|
||||
manager->bufferForDraw.width = width;
|
||||
manager->bufferForDraw.height = height;
|
||||
manager->bufferForDraw.resizePending = true;
|
||||
@@ -1136,8 +1155,8 @@ WLSBM_SizeChangeTo(WLSurfaceBufferManager * manager, jint width, jint height, ji
|
||||
WLBufferTrace(manager, "WLSBM_SizeChangeTo %dx%d", width, height);
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(manager->showLock);
|
||||
MUTEX_UNLOCK(manager->drawLock);
|
||||
MUTEX_UNLOCK(manager->showLock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,6 +48,9 @@ typedef struct WLDrawBuffer WLDrawBuffer;
|
||||
*/
|
||||
typedef uint32_t pixel_t;
|
||||
|
||||
typedef void (*BufferEventCallback)(jobject);
|
||||
|
||||
|
||||
/**
|
||||
* Create a WayLand Surface Buffer Manager for a surface of size width x height
|
||||
* pixels with the given background 32-bit pixel value and wl_shm_format.
|
||||
@@ -61,7 +64,11 @@ typedef uint32_t pixel_t;
|
||||
* the drawing to displaying buffer, synchronization, and sending
|
||||
* the appropriate notifications to Wayland.
|
||||
*/
|
||||
WLSurfaceBufferManager * WLSBM_Create(jint width, jint height, jint scale, jint bgPixel, jint wlShmFormat);
|
||||
WLSurfaceBufferManager * WLSBM_Create(jint width, jint height, jint bgPixel, jint wlShmFormat,
|
||||
jobject surfaceDataWeakRef,
|
||||
BufferEventCallback frameSentCallback,
|
||||
BufferEventCallback frameDroppedCallback,
|
||||
BufferEventCallback bufferAttachedCallback);
|
||||
|
||||
/**
|
||||
* Free all resources allocated for the WayLand Surface Buffer Manager,
|
||||
@@ -108,7 +115,7 @@ jint WLSBM_HeightGet(WLSurfaceBufferManager *);
|
||||
* displays things will change later, but before the changes in drawing buffer
|
||||
* are propagated to the display buffer.
|
||||
*/
|
||||
void WLSBM_SizeChangeTo(WLSurfaceBufferManager *, jint width, jint height, jint scale);
|
||||
void WLSBM_SizeChangeTo(WLSurfaceBufferManager *, jint width, jint height);
|
||||
|
||||
/**
|
||||
* Returns a buffer managed by the WayLand Surface Buffer Manager
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "Trace.h"
|
||||
#include "WLSMSurfaceData.h"
|
||||
#include "WLBuffers.h"
|
||||
#include "WLToolkit.h"
|
||||
|
||||
struct WLSDOps {
|
||||
SurfaceDataOps sdOps;
|
||||
@@ -63,6 +64,23 @@ typedef struct WLSDPrivate {
|
||||
WLDrawBuffer * wlBuffer;
|
||||
} WLSDPrivate;
|
||||
|
||||
static jmethodID countNewFrameMID;
|
||||
static jmethodID countDroppedFrameMID;
|
||||
static jmethodID bufferAttachedMID;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_wl_WLSMSurfaceData_initIDs
|
||||
(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
// NB: don't care if those "count" methods are found.
|
||||
countNewFrameMID = (*env)->GetMethodID(env, clazz, "countNewFrame", "()V");
|
||||
countDroppedFrameMID = (*env)->GetMethodID(env, clazz, "countDroppedFrame", "()V");
|
||||
CHECK_NULL_THROW_IE(env,
|
||||
bufferAttachedMID = (*env)->GetMethodID(env, clazz, "bufferAttached", "()V"),
|
||||
"Failed to find method WLSMSurfaceData.bufferAttached"
|
||||
);
|
||||
}
|
||||
|
||||
JNIEXPORT WLSDOps * JNICALL
|
||||
WLSMSurfaceData_GetOps(JNIEnv *env, jobject sData)
|
||||
{
|
||||
@@ -117,7 +135,7 @@ Java_sun_java2d_wl_WLSMSurfaceData_revalidate(JNIEnv *env, jobject wsd,
|
||||
return;
|
||||
}
|
||||
|
||||
WLSBM_SizeChangeTo(wsdo->bufferManager, width, height, scale);
|
||||
WLSBM_SizeChangeTo(wsdo->bufferManager, width, height);
|
||||
#endif /* !HEADLESS */
|
||||
}
|
||||
|
||||
@@ -177,6 +195,7 @@ Java_sun_java2d_wl_WLSMSurfaceData_pixelsAt(JNIEnv *env, jobject wsd, jint x, ji
|
||||
}
|
||||
|
||||
if (rasInfo.bounds.x2 - rasInfo.bounds.x1 < width || rasInfo.bounds.y2 - rasInfo.bounds.y1 < height) {
|
||||
SurfaceData_InvokeUnlock(env, ops, &rasInfo);
|
||||
JNU_ThrowByName(env, "java/lang/ArrayIndexOutOfBoundsException", "Surface too small");
|
||||
return NULL;
|
||||
}
|
||||
@@ -313,6 +332,46 @@ WLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
BufferAttachedHandler(jobject surfaceDataWeakRef)
|
||||
{
|
||||
JNIEnv *env = getEnv();
|
||||
jobject surfaceData = (*env)->NewLocalRef(env, surfaceDataWeakRef);
|
||||
if (surfaceData != NULL) {
|
||||
(*env)->CallVoidMethod(env, surfaceData, bufferAttachedMID);
|
||||
(*env)->DeleteLocalRef(env, surfaceData);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CountFrameSent(jobject surfaceDataWeakRef)
|
||||
{
|
||||
if (countNewFrameMID != NULL) {
|
||||
JNIEnv *env = getEnv();
|
||||
jobject surfaceData = (*env)->NewLocalRef(env, surfaceDataWeakRef);
|
||||
if (surfaceData != NULL) {
|
||||
(*env)->CallVoidMethod(env, surfaceData, countNewFrameMID);
|
||||
(*env)->DeleteLocalRef(env, surfaceData);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CountFrameDropped(jobject surfaceDataWeakRef)
|
||||
{
|
||||
if (countDroppedFrameMID != NULL) {
|
||||
JNIEnv *env = getEnv();
|
||||
jobject surfaceData = (*env)->NewLocalRef(env, surfaceDataWeakRef);
|
||||
if (surfaceData != NULL) {
|
||||
(*env)->CallVoidMethod(env, surfaceData, countDroppedFrameMID);
|
||||
(*env)->DeleteLocalRef(env, surfaceData);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_wl_WLSMSurfaceData
|
||||
* Method: initOps
|
||||
@@ -322,9 +381,9 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_wl_WLSMSurfaceData_initOps(JNIEnv *env, jobject wsd,
|
||||
jint width,
|
||||
jint height,
|
||||
jint scale,
|
||||
jint backgroundRGB,
|
||||
jint wlShmFormat)
|
||||
jint wlShmFormat,
|
||||
jboolean perfCountersEnabled)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
|
||||
@@ -343,11 +402,19 @@ Java_sun_java2d_wl_WLSMSurfaceData_initOps(JNIEnv *env, jobject wsd,
|
||||
height = 1;
|
||||
}
|
||||
|
||||
jobject surfaceDataWeakRef = NULL;
|
||||
surfaceDataWeakRef = (*env)->NewWeakGlobalRef(env, wsd);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
wsdo->sdOps.Lock = WLSD_Lock;
|
||||
wsdo->sdOps.Unlock = WLSD_Unlock;
|
||||
wsdo->sdOps.GetRasInfo = WLSD_GetRasInfo;
|
||||
wsdo->sdOps.Dispose = WLSD_Dispose;
|
||||
wsdo->bufferManager = WLSBM_Create(width, height, scale, backgroundRGB, wlShmFormat);
|
||||
wsdo->bufferManager = WLSBM_Create(width, height, backgroundRGB, wlShmFormat,
|
||||
surfaceDataWeakRef,
|
||||
perfCountersEnabled ? CountFrameSent : NULL,
|
||||
perfCountersEnabled ? CountFrameDropped : NULL,
|
||||
BufferAttachedHandler);
|
||||
if (wsdo->bufferManager == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Failed to create Wayland surface buffer manager");
|
||||
return;
|
||||
|
||||
@@ -90,6 +90,7 @@ static void delete_all_tokens(struct activation_token_list_item *list) {
|
||||
struct WLFrame {
|
||||
jobject nativeFramePeer; // weak reference
|
||||
struct wl_surface *wl_surface;
|
||||
struct wp_viewport *wp_viewport;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct gtk_surface1 *gtk_surface;
|
||||
struct WLFrame *parent;
|
||||
@@ -451,13 +452,14 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWLSurface
|
||||
if (frame->wl_surface) return;
|
||||
frame->wl_surface = wl_compositor_create_surface(wl_compositor);
|
||||
CHECK_NULL(frame->wl_surface);
|
||||
frame->wp_viewport = wp_viewporter_get_viewport(wp_viewporter, frame->wl_surface);
|
||||
CHECK_NULL(frame->wp_viewport);
|
||||
frame->xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, frame->wl_surface);
|
||||
CHECK_NULL(frame->xdg_surface);
|
||||
if (gtk_shell1 != NULL) {
|
||||
frame->gtk_surface = gtk_shell1_get_gtk_surface(gtk_shell1, frame->wl_surface);
|
||||
CHECK_NULL(frame->gtk_surface);
|
||||
}
|
||||
|
||||
wl_surface_add_listener(frame->wl_surface, &wl_surface_listener, frame);
|
||||
xdg_surface_add_listener(frame->xdg_surface, &xdg_surface_listener, frame);
|
||||
frame->toplevel = JNI_TRUE;
|
||||
@@ -530,6 +532,8 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWLPopup
|
||||
if (frame->wl_surface) return;
|
||||
frame->wl_surface = wl_compositor_create_surface(wl_compositor);
|
||||
CHECK_NULL(frame->wl_surface);
|
||||
frame->wp_viewport = wp_viewporter_get_viewport(wp_viewporter, frame->wl_surface);
|
||||
CHECK_NULL(frame->wp_viewport);
|
||||
frame->xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, frame->wl_surface);
|
||||
CHECK_NULL(frame->xdg_surface);
|
||||
|
||||
@@ -544,7 +548,6 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWLPopup
|
||||
CHECK_NULL(frame->xdg_popup);
|
||||
xdg_popup_add_listener(frame->xdg_popup, &xdg_popup_listener, frame);
|
||||
xdg_positioner_destroy(xdg_positioner);
|
||||
|
||||
// From xdg-shell.xml: "After creating a role-specific object and
|
||||
// setting it up, the client must perform an initial commit
|
||||
// without any buffer attached"
|
||||
@@ -586,6 +589,7 @@ DoHide(JNIEnv *env, struct WLFrame *frame)
|
||||
if (frame->gtk_surface != NULL) {
|
||||
gtk_surface1_destroy(frame->gtk_surface);
|
||||
}
|
||||
wp_viewport_destroy(frame->wp_viewport);
|
||||
xdg_surface_destroy(frame->xdg_surface);
|
||||
wl_surface_destroy(frame->wl_surface);
|
||||
delete_all_tokens(frame->activation_token_list);
|
||||
@@ -596,6 +600,7 @@ DoHide(JNIEnv *env, struct WLFrame *frame)
|
||||
frame->xdg_surface = NULL;
|
||||
frame->xdg_toplevel = NULL;
|
||||
frame->xdg_popup = NULL;
|
||||
frame->wp_viewport = NULL;
|
||||
frame->toplevel = JNI_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -644,6 +649,37 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeStartResize
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the size of the Wayland's surface in surface units.
|
||||
* For the resulting image on the screen to look sharp this size should be
|
||||
* multiple of backing buffer's size with the ratio matching the display scale.
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetSurfaceSize
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jint width, jint height)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame->wp_viewport != NULL) {
|
||||
wp_viewport_set_destination(frame->wp_viewport, width, height);
|
||||
// Do not flush here as this update needs to be committed together with the change
|
||||
// of the buffer's size and scale, if any.
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetOpaqueRegion
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jint x, jint y, jint width, jint height)
|
||||
{
|
||||
struct WLFrame *frame = jlong_to_ptr(ptr);
|
||||
if (frame->wl_surface != NULL) {
|
||||
struct wl_region* region = wl_compositor_create_region(wl_compositor);
|
||||
wl_region_add(region, x, y, width, height);
|
||||
wl_surface_set_opaque_region(frame->wl_surface, region);
|
||||
wl_region_destroy(region);
|
||||
// Do not flush here as this update needs to be committed together with the change
|
||||
// of the buffer's size and scale, if any.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetWindowGeometry
|
||||
(JNIEnv *env, jobject obj, jlong ptr, jint x, jint y, jint width, jint height)
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include "JNIUtilities.h"
|
||||
#include "WLToolkit.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKInit.h"
|
||||
|
||||
typedef struct WLOutput {
|
||||
struct WLOutput * next;
|
||||
|
||||
@@ -64,6 +64,7 @@ struct wl_display *wl_display = NULL;
|
||||
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 gtk_shell1* gtk_shell1 = NULL;
|
||||
struct wl_seat *wl_seat = NULL;
|
||||
@@ -524,6 +525,8 @@ registry_global(void *data, struct wl_registry *wl_registry,
|
||||
wl_ddm = wl_registry_bind(wl_registry, name,&wl_data_device_manager_interface, 3);
|
||||
} else if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) {
|
||||
zwp_selection_dm = wl_registry_bind(wl_registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
|
||||
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
|
||||
wp_viewporter = wl_registry_bind(wl_registry, name, &wp_viewporter_interface, 1);
|
||||
}
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#include "xdg-activation-v1-client-protocol.h"
|
||||
#include "primary-selection-client-protocol.h"
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "jvm_md.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
@@ -54,6 +55,7 @@ extern struct wl_display *wl_display;
|
||||
extern struct wl_pointer *wl_pointer;
|
||||
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 gtk_shell1* gtk_shell1; // optional, check for NULL before use
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
#ifndef GTK_CLIENT_PROTOCOL_H
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
#ifndef WP_PRIMARY_SELECTION_UNSTABLE_V1_CLIENT_PROTOCOL_H
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
/*
|
||||
* Copyright © 2013-2016 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||
#endif
|
||||
|
||||
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define WL_PRIVATE
|
||||
#endif
|
||||
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
extern const struct wl_interface wp_viewport_interface;
|
||||
|
||||
static const struct wl_interface *viewporter_types[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wp_viewport_interface,
|
||||
&wl_surface_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message wp_viewporter_requests[] = {
|
||||
{ "destroy", "", viewporter_types + 0 },
|
||||
{ "get_viewport", "no", viewporter_types + 4 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wp_viewporter_interface = {
|
||||
"wp_viewporter", 1,
|
||||
2, wp_viewporter_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
static const struct wl_message wp_viewport_requests[] = {
|
||||
{ "destroy", "", viewporter_types + 0 },
|
||||
{ "set_source", "ffff", viewporter_types + 0 },
|
||||
{ "set_destination", "ii", viewporter_types + 0 },
|
||||
};
|
||||
|
||||
WL_PRIVATE const struct wl_interface wp_viewport_interface = {
|
||||
"wp_viewport", 1,
|
||||
3, wp_viewport_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
#ifndef VIEWPORTER_CLIENT_PROTOCOL_H
|
||||
#define VIEWPORTER_CLIENT_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page page_viewporter The viewporter protocol
|
||||
* @section page_ifaces_viewporter Interfaces
|
||||
* - @subpage page_iface_wp_viewporter - surface cropping and scaling
|
||||
* - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface
|
||||
* @section page_copyright_viewporter Copyright
|
||||
* <pre>
|
||||
*
|
||||
* Copyright © 2013-2016 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
* </pre>
|
||||
*/
|
||||
struct wl_surface;
|
||||
struct wp_viewport;
|
||||
struct wp_viewporter;
|
||||
|
||||
#ifndef WP_VIEWPORTER_INTERFACE
|
||||
#define WP_VIEWPORTER_INTERFACE
|
||||
/**
|
||||
* @page page_iface_wp_viewporter wp_viewporter
|
||||
* @section page_iface_wp_viewporter_desc Description
|
||||
*
|
||||
* The global interface exposing surface cropping and scaling
|
||||
* capabilities is used to instantiate an interface extension for a
|
||||
* wl_surface object. This extended interface will then allow
|
||||
* cropping and scaling the surface contents, effectively
|
||||
* disconnecting the direct relationship between the buffer and the
|
||||
* surface size.
|
||||
* @section page_iface_wp_viewporter_api API
|
||||
* See @ref iface_wp_viewporter.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_wp_viewporter The wp_viewporter interface
|
||||
*
|
||||
* The global interface exposing surface cropping and scaling
|
||||
* capabilities is used to instantiate an interface extension for a
|
||||
* wl_surface object. This extended interface will then allow
|
||||
* cropping and scaling the surface contents, effectively
|
||||
* disconnecting the direct relationship between the buffer and the
|
||||
* surface size.
|
||||
*/
|
||||
extern const struct wl_interface wp_viewporter_interface;
|
||||
#endif
|
||||
#ifndef WP_VIEWPORT_INTERFACE
|
||||
#define WP_VIEWPORT_INTERFACE
|
||||
/**
|
||||
* @page page_iface_wp_viewport wp_viewport
|
||||
* @section page_iface_wp_viewport_desc Description
|
||||
*
|
||||
* An additional interface to a wl_surface object, which allows the
|
||||
* client to specify the cropping and scaling of the surface
|
||||
* contents.
|
||||
*
|
||||
* This interface works with two concepts: the source rectangle (src_x,
|
||||
* src_y, src_width, src_height), and the destination size (dst_width,
|
||||
* dst_height). The contents of the source rectangle are scaled to the
|
||||
* destination size, and content outside the source rectangle is ignored.
|
||||
* This state is double-buffered, and is applied on the next
|
||||
* wl_surface.commit.
|
||||
*
|
||||
* The two parts of crop and scale state are independent: the source
|
||||
* rectangle, and the destination size. Initially both are unset, that
|
||||
* is, no scaling is applied. The whole of the current wl_buffer is
|
||||
* used as the source, and the surface size is as defined in
|
||||
* wl_surface.attach.
|
||||
*
|
||||
* If the destination size is set, it causes the surface size to become
|
||||
* dst_width, dst_height. The source (rectangle) is scaled to exactly
|
||||
* this size. This overrides whatever the attached wl_buffer size is,
|
||||
* unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
|
||||
* has no content and therefore no size. Otherwise, the size is always
|
||||
* at least 1x1 in surface local coordinates.
|
||||
*
|
||||
* If the source rectangle is set, it defines what area of the wl_buffer is
|
||||
* taken as the source. If the source rectangle is set and the destination
|
||||
* size is not set, then src_width and src_height must be integers, and the
|
||||
* surface size becomes the source rectangle size. This results in cropping
|
||||
* without scaling. If src_width or src_height are not integers and
|
||||
* destination size is not set, the bad_size protocol error is raised when
|
||||
* the surface state is applied.
|
||||
*
|
||||
* The coordinate transformations from buffer pixel coordinates up to
|
||||
* the surface-local coordinates happen in the following order:
|
||||
* 1. buffer_transform (wl_surface.set_buffer_transform)
|
||||
* 2. buffer_scale (wl_surface.set_buffer_scale)
|
||||
* 3. crop and scale (wp_viewport.set*)
|
||||
* This means, that the source rectangle coordinates of crop and scale
|
||||
* are given in the coordinates after the buffer transform and scale,
|
||||
* i.e. in the coordinates that would be the surface-local coordinates
|
||||
* if the crop and scale was not applied.
|
||||
*
|
||||
* If src_x or src_y are negative, the bad_value protocol error is raised.
|
||||
* Otherwise, if the source rectangle is partially or completely outside of
|
||||
* the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
|
||||
* when the surface state is applied. A NULL wl_buffer does not raise the
|
||||
* out_of_buffer error.
|
||||
*
|
||||
* If the wl_surface associated with the wp_viewport is destroyed,
|
||||
* all wp_viewport requests except 'destroy' raise the protocol error
|
||||
* no_surface.
|
||||
*
|
||||
* If the wp_viewport object is destroyed, the crop and scale
|
||||
* state is removed from the wl_surface. The change will be applied
|
||||
* on the next wl_surface.commit.
|
||||
* @section page_iface_wp_viewport_api API
|
||||
* See @ref iface_wp_viewport.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_wp_viewport The wp_viewport interface
|
||||
*
|
||||
* An additional interface to a wl_surface object, which allows the
|
||||
* client to specify the cropping and scaling of the surface
|
||||
* contents.
|
||||
*
|
||||
* This interface works with two concepts: the source rectangle (src_x,
|
||||
* src_y, src_width, src_height), and the destination size (dst_width,
|
||||
* dst_height). The contents of the source rectangle are scaled to the
|
||||
* destination size, and content outside the source rectangle is ignored.
|
||||
* This state is double-buffered, and is applied on the next
|
||||
* wl_surface.commit.
|
||||
*
|
||||
* The two parts of crop and scale state are independent: the source
|
||||
* rectangle, and the destination size. Initially both are unset, that
|
||||
* is, no scaling is applied. The whole of the current wl_buffer is
|
||||
* used as the source, and the surface size is as defined in
|
||||
* wl_surface.attach.
|
||||
*
|
||||
* If the destination size is set, it causes the surface size to become
|
||||
* dst_width, dst_height. The source (rectangle) is scaled to exactly
|
||||
* this size. This overrides whatever the attached wl_buffer size is,
|
||||
* unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
|
||||
* has no content and therefore no size. Otherwise, the size is always
|
||||
* at least 1x1 in surface local coordinates.
|
||||
*
|
||||
* If the source rectangle is set, it defines what area of the wl_buffer is
|
||||
* taken as the source. If the source rectangle is set and the destination
|
||||
* size is not set, then src_width and src_height must be integers, and the
|
||||
* surface size becomes the source rectangle size. This results in cropping
|
||||
* without scaling. If src_width or src_height are not integers and
|
||||
* destination size is not set, the bad_size protocol error is raised when
|
||||
* the surface state is applied.
|
||||
*
|
||||
* The coordinate transformations from buffer pixel coordinates up to
|
||||
* the surface-local coordinates happen in the following order:
|
||||
* 1. buffer_transform (wl_surface.set_buffer_transform)
|
||||
* 2. buffer_scale (wl_surface.set_buffer_scale)
|
||||
* 3. crop and scale (wp_viewport.set*)
|
||||
* This means, that the source rectangle coordinates of crop and scale
|
||||
* are given in the coordinates after the buffer transform and scale,
|
||||
* i.e. in the coordinates that would be the surface-local coordinates
|
||||
* if the crop and scale was not applied.
|
||||
*
|
||||
* If src_x or src_y are negative, the bad_value protocol error is raised.
|
||||
* Otherwise, if the source rectangle is partially or completely outside of
|
||||
* the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
|
||||
* when the surface state is applied. A NULL wl_buffer does not raise the
|
||||
* out_of_buffer error.
|
||||
*
|
||||
* If the wl_surface associated with the wp_viewport is destroyed,
|
||||
* all wp_viewport requests except 'destroy' raise the protocol error
|
||||
* no_surface.
|
||||
*
|
||||
* If the wp_viewport object is destroyed, the crop and scale
|
||||
* state is removed from the wl_surface. The change will be applied
|
||||
* on the next wl_surface.commit.
|
||||
*/
|
||||
extern const struct wl_interface wp_viewport_interface;
|
||||
#endif
|
||||
|
||||
#ifndef WP_VIEWPORTER_ERROR_ENUM
|
||||
#define WP_VIEWPORTER_ERROR_ENUM
|
||||
enum wp_viewporter_error {
|
||||
/**
|
||||
* the surface already has a viewport object associated
|
||||
*/
|
||||
WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0,
|
||||
};
|
||||
#endif /* WP_VIEWPORTER_ERROR_ENUM */
|
||||
|
||||
#define WP_VIEWPORTER_DESTROY 0
|
||||
#define WP_VIEWPORTER_GET_VIEWPORT 1
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewporter
|
||||
*/
|
||||
#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wp_viewporter
|
||||
*/
|
||||
#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_wp_viewporter */
|
||||
static inline void
|
||||
wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_wp_viewporter */
|
||||
static inline void *
|
||||
wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
wp_viewporter_get_version(struct wp_viewporter *wp_viewporter)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) wp_viewporter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewporter
|
||||
*
|
||||
* Informs the server that the client will not be using this
|
||||
* protocol object anymore. This does not affect any other objects,
|
||||
* wp_viewport objects included.
|
||||
*/
|
||||
static inline void
|
||||
wp_viewporter_destroy(struct wp_viewporter *wp_viewporter)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) wp_viewporter,
|
||||
WP_VIEWPORTER_DESTROY);
|
||||
|
||||
wl_proxy_destroy((struct wl_proxy *) wp_viewporter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewporter
|
||||
*
|
||||
* Instantiate an interface extension for the given wl_surface to
|
||||
* crop and scale its content. If the given wl_surface already has
|
||||
* a wp_viewport object associated, the viewport_exists
|
||||
* protocol error is raised.
|
||||
*/
|
||||
static inline struct wp_viewport *
|
||||
wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface)
|
||||
{
|
||||
struct wl_proxy *id;
|
||||
|
||||
id = wl_proxy_marshal_constructor((struct wl_proxy *) wp_viewporter,
|
||||
WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, NULL, surface);
|
||||
|
||||
return (struct wp_viewport *) id;
|
||||
}
|
||||
|
||||
#ifndef WP_VIEWPORT_ERROR_ENUM
|
||||
#define WP_VIEWPORT_ERROR_ENUM
|
||||
enum wp_viewport_error {
|
||||
/**
|
||||
* negative or zero values in width or height
|
||||
*/
|
||||
WP_VIEWPORT_ERROR_BAD_VALUE = 0,
|
||||
/**
|
||||
* destination size is not integer
|
||||
*/
|
||||
WP_VIEWPORT_ERROR_BAD_SIZE = 1,
|
||||
/**
|
||||
* source rectangle extends outside of the content area
|
||||
*/
|
||||
WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2,
|
||||
/**
|
||||
* the wl_surface was destroyed
|
||||
*/
|
||||
WP_VIEWPORT_ERROR_NO_SURFACE = 3,
|
||||
};
|
||||
#endif /* WP_VIEWPORT_ERROR_ENUM */
|
||||
|
||||
#define WP_VIEWPORT_DESTROY 0
|
||||
#define WP_VIEWPORT_SET_SOURCE 1
|
||||
#define WP_VIEWPORT_SET_DESTINATION 2
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*/
|
||||
#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*/
|
||||
#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*/
|
||||
#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1
|
||||
|
||||
/** @ingroup iface_wp_viewport */
|
||||
static inline void
|
||||
wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data);
|
||||
}
|
||||
|
||||
/** @ingroup iface_wp_viewport */
|
||||
static inline void *
|
||||
wp_viewport_get_user_data(struct wp_viewport *wp_viewport)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
wp_viewport_get_version(struct wp_viewport *wp_viewport)
|
||||
{
|
||||
return wl_proxy_get_version((struct wl_proxy *) wp_viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*
|
||||
* The associated wl_surface's crop and scale state is removed.
|
||||
* The change is applied on the next wl_surface.commit.
|
||||
*/
|
||||
static inline void
|
||||
wp_viewport_destroy(struct wp_viewport *wp_viewport)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) wp_viewport,
|
||||
WP_VIEWPORT_DESTROY);
|
||||
|
||||
wl_proxy_destroy((struct wl_proxy *) wp_viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*
|
||||
* Set the source rectangle of the associated wl_surface. See
|
||||
* wp_viewport for the description, and relation to the wl_buffer
|
||||
* size.
|
||||
*
|
||||
* If all of x, y, width and height are -1.0, the source rectangle is
|
||||
* unset instead. Any other set of values where width or height are zero
|
||||
* or negative, or x or y are negative, raise the bad_value protocol
|
||||
* error.
|
||||
*
|
||||
* The crop and scale state is double-buffered state, and will be
|
||||
* applied on the next wl_surface.commit.
|
||||
*/
|
||||
static inline void
|
||||
wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) wp_viewport,
|
||||
WP_VIEWPORT_SET_SOURCE, x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_wp_viewport
|
||||
*
|
||||
* Set the destination size of the associated wl_surface. See
|
||||
* wp_viewport for the description, and relation to the wl_buffer
|
||||
* size.
|
||||
*
|
||||
* If width is -1 and height is -1, the destination size is unset
|
||||
* instead. Any other pair of values for width and height that
|
||||
* contains zero or negative values raises the bad_value protocol
|
||||
* error.
|
||||
*
|
||||
* The crop and scale state is double-buffered state, and will be
|
||||
* applied on the next wl_surface.commit.
|
||||
*/
|
||||
static inline void
|
||||
wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) wp_viewport,
|
||||
WP_VIEWPORT_SET_DESTINATION, width, height);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.19.0 */
|
||||
|
||||
#ifndef WAKEFIELD_CLIENT_PROTOCOL_H
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.18.0 */
|
||||
|
||||
#ifndef XDG_ACTIVATION_V1_CLIENT_PROTOCOL_H
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2023-2024 JetBrains s.r.o.
|
||||
*/
|
||||
|
||||
/* Generated by wayland-scanner 1.18.0 */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1638,6 +1638,81 @@ Java_sun_awt_X11_XInputMethod_releaseXICNative(JNIEnv *env,
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_X11_XInputMethod_delayedDisposeXIC_1preparation_1unsetFocusAndDetachCurrentXICNative
|
||||
(JNIEnv *env, jobject this)
|
||||
{
|
||||
DASSERT(env != NULL);
|
||||
X11InputMethodData *pX11IMData = NULL;
|
||||
|
||||
AWT_LOCK();
|
||||
|
||||
pX11IMData = getX11InputMethodData(env, this);
|
||||
if (pX11IMData == NULL) {
|
||||
AWT_UNLOCK();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pX11IMData->ic_active.xic != (XIC)0) {
|
||||
setXICFocus(pX11IMData->ic_active.xic, False);
|
||||
}
|
||||
if ( (pX11IMData->ic_passive.xic != (XIC)0) && (pX11IMData->ic_passive.xic != pX11IMData->ic_active.xic) ) {
|
||||
setXICFocus(pX11IMData->ic_passive.xic, False);
|
||||
}
|
||||
pX11IMData->current_ic = (XIC)0;
|
||||
|
||||
setX11InputMethodData(env, this, NULL);
|
||||
if ( (*env)->IsSameObject(env, pX11IMData->x11inputmethod, currentX11InputMethodInstance) == JNI_TRUE ) {
|
||||
// currentX11InputMethodInstance never holds a "unique" java ref - it only holds a "weak" copy of
|
||||
// _X11InputMethodData::x11inputmethod, so we mustn't DeleteGlobalRef here
|
||||
currentX11InputMethodInstance = NULL;
|
||||
currentFocusWindow = 0;
|
||||
}
|
||||
|
||||
AWT_UNLOCK();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_X11_XInputMethod_delayedDisposeXIC_1preparation_1resetSpecifiedCtxNative
|
||||
(JNIEnv *env, jclass clazz, const jlong pData)
|
||||
{
|
||||
X11InputMethodData * const pX11IMData = (X11InputMethodData *)pData;
|
||||
char* preeditText = NULL;
|
||||
|
||||
if (pX11IMData == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
AWT_LOCK();
|
||||
|
||||
if (pX11IMData->ic_active.xic != (XIC)0) {
|
||||
if ( (preeditText = XmbResetIC(pX11IMData->ic_active.xic)) != NULL ) {
|
||||
(void)XFree(preeditText); preeditText = NULL;
|
||||
}
|
||||
}
|
||||
if ( (pX11IMData->ic_passive.xic != (XIC)0) && (pX11IMData->ic_passive.xic != pX11IMData->ic_active.xic) ) {
|
||||
if ( (preeditText = XmbResetIC(pX11IMData->ic_passive.xic)) != NULL ) {
|
||||
(void)XFree(preeditText); preeditText = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
AWT_UNLOCK();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_X11_XInputMethod_delayedDisposeXIC_1disposeXICNative(JNIEnv *env, jclass clazz, jlong pData)
|
||||
{
|
||||
X11InputMethodData *pX11IMData = (X11InputMethodData *)pData;
|
||||
if (pX11IMData == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
AWT_LOCK();
|
||||
destroyX11InputMethodData(env, pX11IMData); pX11IMData = NULL; pData = 0;
|
||||
AWT_UNLOCK();
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
|
||||
jobject this,
|
||||
|
||||
@@ -154,6 +154,9 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
}
|
||||
for (int i = 0; i < screens.length; i++) {
|
||||
if (screens[i] instanceof Win32GraphicsDevice gd) {
|
||||
if (LogDisplay.ENABLED) {
|
||||
LogDisplay.REMOVED.log(i, "UNKNOWN", Double.NaN);
|
||||
}
|
||||
oldDevices.add(new WeakReference<>(gd));
|
||||
} else {
|
||||
// REMIND: can we ever have anything other than Win32GD?
|
||||
@@ -205,13 +208,16 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
*/
|
||||
|
||||
protected GraphicsDevice makeScreenDevice(int screennum) {
|
||||
GraphicsDevice device = null;
|
||||
Win32GraphicsDevice device = null;
|
||||
if (WindowsFlags.isD3DEnabled()) {
|
||||
device = D3DGraphicsDevice.createDevice(screennum);
|
||||
}
|
||||
if (device == null) {
|
||||
device = new Win32GraphicsDevice(screennum);
|
||||
}
|
||||
if (LogDisplay.ENABLED) {
|
||||
LogDisplay.ADDED.log(device.getScreen(), device.getBounds(), device.getDefaultScaleX());
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
@@ -2029,6 +2029,11 @@ void AwtFrame::_UpdateCustomTitleBar(void* p) {
|
||||
|
||||
// {end} Custom title bar support
|
||||
|
||||
UINT AwtFrame::GetCurrentWmSizeType()
|
||||
{
|
||||
return isZoomed() ? SIZE_MAXIMIZED : SIZENORMAL;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* WFramePeer native methods
|
||||
*/
|
||||
|
||||
@@ -242,6 +242,8 @@ private:
|
||||
RECT GetSysInsets();
|
||||
LRESULT HitTestNCA(int x, int y);
|
||||
|
||||
virtual UINT GetCurrentWmSizeType();
|
||||
|
||||
/*
|
||||
* Hashtable<Thread, BlockedThreadStruct> - a table that contains all the
|
||||
* information about non-toolkit threads with modal blocked embedded
|
||||
|
||||
@@ -1901,7 +1901,7 @@ void AwtWindow::WmDPIChanged(const LPARAM &lParam) {
|
||||
RECT *r = (RECT *) lParam;
|
||||
ReshapeNoScale(r->left, r->top, r->right - r->left, r->bottom - r->top);
|
||||
CheckIfOnNewScreen(true);
|
||||
WmSize(SIZENORMAL, r->right - r->left, r->bottom - r->top);
|
||||
WmSize(GetCurrentWmSizeType(), r->right - r->left, r->bottom - r->top);
|
||||
}
|
||||
|
||||
MsgRouting AwtWindow::WmEraseBkgnd(HDC hDC, BOOL& didErase)
|
||||
@@ -2324,6 +2324,10 @@ BOOL AwtWindow::CheckIfOnNewScreenWithDifferentScale() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
UINT AwtWindow::GetCurrentWmSizeType() {
|
||||
return SIZENORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if we've been moved onto another screen.
|
||||
* If so, update internal data, surfaces, etc.
|
||||
|
||||
@@ -138,6 +138,7 @@ public:
|
||||
virtual int GetScreenImOn();
|
||||
virtual BOOL CheckIfOnNewScreen(BOOL force);
|
||||
virtual BOOL CheckIfOnNewScreenWithDifferentScale();
|
||||
virtual UINT GetCurrentWmSizeType();
|
||||
virtual void Grab();
|
||||
virtual void Ungrab();
|
||||
virtual void Ungrab(BOOL doPost);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user