Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JBR-6543 Vulkan: migrate current code to pure c #267

Merged
merged 4 commits into from
May 29, 2024
Merged

Conversation

avu
Copy link
Collaborator

@avu avu commented Jan 11, 2024

No description provided.

@avu avu marked this pull request as draft January 11, 2024 20:04
@avu avu self-assigned this Jan 12, 2024
@avu avu requested a review from YaaZ January 12, 2024 10:20
Copy link
Member

@YaaZ YaaZ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it's much cleaner now, C API is not THAT bad after all :)

make/modules/java.desktop/lib/Awt2dLibraries.gmk Outdated Show resolved Hide resolved

#define ARRAY_CAPACITY_MULT 2
typedef struct {
size_t elem_size;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this field. It takes extra space, but there's no real value in having it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used for reallocation of the array to provide more space (see CArrayUtil.c CARR_array_realloc)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it is only used in reallocation, but this is such a compile time constant which is not usually stored explicitly. When adding an element and trying to reallocate an array we could probably get it from the parameter via sizeof

Comment on lines 281 to 283
char* enabledLayers[MAX_ENABLED_LAYERS];
uint32_t enabledLayersCount = 0;
char* enabledExtensions[MAX_ENABLED_EXTENSIONS];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use new dynamic arrays here?

return NULL;
} else {
J2dRlsTrace(J2D_TRACE_INFO, "Vulkan: Instance Created\n")
}
Copy link
Member

@YaaZ YaaZ Apr 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still actual (We need to set up a debug logger after creating an instance)

Comment on lines 650 to 651
geInstance->devices[i].name = strdup(deviceProperties2.properties.deviceName);
if (geInstance->devices[i].name == NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

devices[i] is wrong, we need devices[ARRAY_SIZE(devices)] instead

VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;

presentInfo.waitSemaphoreCount = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1

(uint32_t) (vkwinsdo->vksdOps.height)
};

uint32_t imageCount = vkwinsdo->capabilitiesKhr.minImageCount + 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason behind this minImageCount + 1? I think we should decide on the number of images in conjunction with the presentMode

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to allocate too many images

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, usual logic for choosing number of images is not to use minImageCount as a basis, but rather as a lower bound. presentMode should be a basis instead, for example in IMMEDIATE mode there's no reason to have more than one image, or there is no reason to have MAILBOX with two images, as then it will be identical to FIFO

Comment on lines 87 to 88
createInfoKhr.imageFormat = vkwinsdo->formatsKhr[0].format;
createInfoKhr.imageColorSpace = vkwinsdo->formatsKhr[0].colorSpace;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: the first reported format is not always the easiest "default" format, so we will need some more logic here.
We also need to use this format when creating the render pass, currently we are using hardcoded VK_FORMAT_B8G8R8A8_UNORM there

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, VK_FORMAT_B8G8R8A8_UNORM may be wrong too. If we want to work in sRGB color space (do we?), then we can get gamma correction done by the hardware with _SRGB formats.


createInfoKhr.preTransform = vkwinsdo->capabilitiesKhr.currentTransform;
createInfoKhr.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfoKhr.presentMode = VK_PRESENT_MODE_FIFO_KHR;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: inspect available modes and choose something better?

ge->vkResetFences(logicalDevice->device, 1, &logicalDevice->inFlightFence);

uint32_t imageIndex;
ge->vkAcquireNextImageKHR(logicalDevice->device, winDstOps->swapchainKhr, UINT64_MAX,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a TODO: handle swapchain lost/not optimal errors

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, this will fire on window resize

return buffer;
}

VKBuffer* VKBuffer_CreateFromData(void* vertices, VkDeviceSize bufferSize)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: we would need to implement some memory management strategy in order to not allocate memory once per buffer. We also don't want to create a new buffer each time we want to draw a bunch of vertices.

VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];

VKBuffer* buffer = VKBuffer_Create(bufferSize,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that we write to this buffer directly, VK_BUFFER_USAGE_TRANSFER_DST_BIT is not needed there. Also, memory which is both DEVICE_LOCAL and HOST_VISIBLE is usually very limited, so we need to use it very wisely and be ready to fall back to some other memory type.

VkMemoryPropertyFlags properties)
{
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
VKLogicalDevice* logicalDevice = &ge->devices[ge->enabledDeviceNum];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: carry necessary device-related context. This mutable global state will give us a lot of problems when we try to switch devices on the fly.

return NULL;
}

if (!VKImage_CreateFramebuffer(&ARRAY_LAST(images), renderPass)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: consider using single imageless framebuffer instead?

if (VK_CreateImage(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,
&vksdo->image, &vksdo->imageMemory) != VK_SUCCESS)
vksdo->image = VKImage_Create(vksdo->width, vksdo->height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VK_IMAGE_TILING_LINEAR is only for cases when we need to directly write into image memory (e.g. from host, not by blit command). Here I believe it's better to use VK_IMAGE_TILING_OPTIMAL

@@ -28,15 +28,37 @@
#define VKVertex_h_Included

#include <vulkan/vulkan.h>
#include "VKBuffer.h"

#define RGBA_TO_L4(c) \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is wrong. Our integer-encoded colors are in sRGB color space. Our rendering pipelines expect linear color space. Just normalizing to [0, 1] range is not enough.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check but looks like we have this problem for metal and opengl.

Replaced C++ vulkan rendering with C one
@avu avu marked this pull request as ready for review May 24, 2024 19:26
@@ -1,8 +1,8 @@
#version 450

layout(location = 0) in vec4 inColor;
layout(location = 0) in vec4 fragColor;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we consider gradient, or we can add flat here?

Comment on lines +794 to +804
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? We can render a full-screen quad with a simple vertex shader and without any vertex input at all. That would simplify the pipeline creation and we wouldn't need to create and bind the buffer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can add a separate shader with embedded coordinates. Here I've reused the shader that will be used for blitting arbitrary areas

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if we are blitting arbitrary area, if we are doing one draw call per rectangle, it will be much easier to go with the same vertex shader and specify position/size via push constants which will be recorded directly into the command buffer. If we are going to do batch blit with a single draw call, then sure we would better go with ordinary vertex buffer, but then we would need to support growing vertex buffer, maintain a pool or something

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we'll have both. For scan-converted shapes there will be bulk rendering, for rectangular blits there will be one draw call.

avu added 3 commits May 27, 2024 21:39
Resolved build failure for build env without vulkan headers
Review comments: moved VKImage_CreateFramebuffer to VKSD_InitImageSurface
@avu avu merged commit 3f05010 into jbr21 May 29, 2024
@mkurz
Copy link

mkurz commented May 29, 2024

How ready is Vulkan in the JBR now? Usable?

@avu
Copy link
Collaborator Author

avu commented May 30, 2024

@mkurz Not yet it's in the early stage hopefully we'll have something relatively feature-complete in several months.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants