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:
Alexey Ushakov
2024-05-29 19:47:58 +02:00
committed by Maxim Kartashev
parent f1d7f7e1a2
commit ccd3804dc3
36 changed files with 2980 additions and 1858 deletions

View File

@@ -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])

View 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);
}

View 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;
}

View File

@@ -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;
}

View 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;
}

View File

@@ -0,0 +1,8 @@
#version 450
layout(location = 0) in flat vec4 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
outColor = fragColor;
}

View 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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View 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();
}

View File

@@ -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();
}

View File

@@ -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

View 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);
}
}
}

View File

@@ -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

View 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);
}

View 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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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]);
}

View File

@@ -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 */

View File

@@ -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.

View 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 */

View File

@@ -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*/}

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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

View File

@@ -101,7 +101,7 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
}
public SurfaceData getReplacement() {
throw new UnsupportedOperationException("Not supported yet");
return null;
}
@Override

View File

@@ -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());
}

View File

@@ -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 */

View File

@@ -31,7 +31,7 @@
#include "JNIUtilities.h"
#include "WLToolkit.h"
#include "VKBase.h"
#include "VKInit.h"
typedef struct WLOutput {
struct WLOutput * next;