mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-07 18:09:38 +01:00
JBR-6543 Vulkan: migrate current code to pure c (#267)
JBR-6543 Vulkan: migrate current code to pure c Replaced C++ vulkan rendering with C one
This commit is contained in:
committed by
Maxim Kartashev
parent
f1d7f7e1a2
commit
ccd3804dc3
@@ -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])
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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,19 +24,23 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef VKPipeline_h_Included
|
||||
#define VKPipeline_h_Included
|
||||
#ifndef VKBuffer_h_Included
|
||||
#define VKBuffer_h_Included
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "VKShader.h"
|
||||
typedef struct {
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceSize size;
|
||||
} VKBuffer;
|
||||
|
||||
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;
|
||||
VkResult VKBuffer_FindMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter,
|
||||
VkMemoryPropertyFlags properties, uint32_t* pMemoryType);
|
||||
|
||||
void init(const vk::raii::Device& device, bool dynamicRendering);
|
||||
};
|
||||
VKBuffer* VKBuffer_Create(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties);
|
||||
|
||||
#endif //VKPipeline_h_Included
|
||||
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 */
|
||||
@@ -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,41 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "VKShader.h"
|
||||
#ifndef VKVertex_h_Included
|
||||
#define VKVertex_h_Included
|
||||
|
||||
// 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
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "VKBuffer.h"
|
||||
|
||||
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
|
||||
}
|
||||
#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
|
||||
@@ -101,7 +101,7 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
|
||||
}
|
||||
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException("Not supported yet");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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 */
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include "JNIUtilities.h"
|
||||
#include "WLToolkit.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKInit.h"
|
||||
|
||||
typedef struct WLOutput {
|
||||
struct WLOutput * next;
|
||||
|
||||
Reference in New Issue
Block a user