Initial mesh_shaders sample commit
Test Compilation / Build evk (push) Has been cancelled

This commit is contained in:
2026-05-22 16:15:50 +03:00
parent be3d1d21e7
commit ccfc74a0a3
5 changed files with 406 additions and 1 deletions
+372
View File
@@ -0,0 +1,372 @@
#include <evk/evk.h>
#include <ev_numeric.h>
#include <ev_helpers.h>
#include <ev_log.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
evstring PROJECT_NAME = evstr("mesh_triangle");
char vertexShaderBytes[] = {
#embed "shaders/mesh_triangle.vert"
,'\0'
};
char fragmentShaderBytes[] = {
#embed "shaders/mesh_triangle.frag"
,'\0'
};
int main(void)
{
u32 width = 1280;
u32 height = 800;
evkInstance instance = evkCreateInstance((evkInstanceCreateInfo){
.applicationInfo = EV_DEFAULT(evkApplicationInfo),
.layers = svec_init(evstring, {
evstr("VK_LAYER_KHRONOS_validation"),
}),
.extensions = svec_init(evstring, {
evstr("VK_KHR_surface"),
// TODO Get these from GLFW
#if EV_OS_WINDOWS
evstr("VK_KHR_win32_surface"),
#elif EV_OS_LINUX
evstr("VK_KHR_xcb_surface"),
#endif
}),
});
if(instance.vk == EV_INVALID(VkInstance))
{
ev_log_error("Instance creation failed.");
goto InstanceCreationFailed;
}
ev_log_info("Instance was created successfully.");
evkDevice device = evkCreateDevice((evkDeviceCreateInfo) {
.instance = instance,
// TODO Add a fallback physical device option.
// .physicalDeviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU,
.physicalDeviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
.queueRequirements = svec_init(evkDeviceQueueRequirement, {
{ VK_QUEUE_GRAPHICS_BIT, 1 },
{ VK_QUEUE_COMPUTE_BIT , 1 },
}),
.deviceExtensions = svec_init(evstring, {
evstr("VK_KHR_swapchain"),
evstr("VK_KHR_dynamic_rendering"),
evstr("VK_KHR_depth_stencil_resolve"),
evstr("VK_KHR_create_renderpass2"),
evstr("VK_KHR_synchronization2"),
evstr("VK_KHR_buffer_device_address"),
evstr("VK_EXT_descriptor_indexing"),
evstr("VK_KHR_maintenance5"),
evstr("VK_EXT_descriptor_heap"),
evstr(VK_EXT_SHADER_OBJECT_EXTENSION_NAME),
evstr(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME),
}),
});
if(device.vk == EV_INVALID(VkDevice))
{
ev_log_error("Couldn't create a VkDevice");
goto DeviceCreationFailed;
}
ev_log_info("Logical Device created successfully.");
VkQueue graphicsQueue;
vkGetDeviceQueue(device.vk, device.queueFamilies[VK_QUEUE_GRAPHICS_BIT].familyIndex, 0, &graphicsQueue);
if (!glfwInit())
{
ev_log_error("GLFW Initialization failed.");
goto GLFWInitFailed;
}
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(width, height, "evk", NULL, NULL);
if(!window)
{
ev_log_error("Window Creation Failed.");
goto WindowCreationFailed;
}
VkSurfaceKHR surface;
VkResult err = EVK_CHECK(glfwCreateWindowSurface(instance.vk, window, NULL, &surface));
if (err)
{
ev_log_error("Surface creation failed.");
goto VKSurfaceCreationFailed;
}
evkGPUAllocator allocator = evkGPUCreateAllocator(device);
evkSwapChain swapChain = evkCreateSwapChain((evkSwapChainCreateInfo){
.device = device,
.surface = surface,
.width = width,
.height = height,
.imageCount = 3,
});
evkCommandPool commandPool = evkCreateCommandPool((evkCommandPoolCreateInfo) {
.device = device,
.queueFlags = VK_QUEUE_GRAPHICS_BIT,
.poolFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
});
vec(evkCommandBuffer) commandBuffers = evkAllocateCommandBuffers(device, commandPool, vec_len(&swapChain.images), true);
evkShaderCompiler compiler = evkCreateShaderCompiler();
evstring vertexShaderText = evstring_new(vertexShaderBytes);
evstring fragmentShaderText = evstring_new(fragmentShaderBytes);
evkShader vertShader = evkInitShaderFromString(device, compiler, evstr("mesh_triangle.vert"),vertexShaderText, VK_SHADER_STAGE_VERTEX_BIT);
evkShader fragShader = evkInitShaderFromString(device, compiler, evstr("mesh_triangle.frag"), fragmentShaderText, VK_SHADER_STAGE_FRAGMENT_BIT);
evstring_free(vertexShaderText);
evstring_free(fragmentShaderText);
evkDestroyShaderCompiler(compiler);
evkColorAttachment colorAttachment0 = {
swapChain.surfaceFormat.format,
EV_DEFAULT(VkPipelineColorBlendAttachmentState)
};
// TODO Get this from shader reflection data
// evkDescriptorSetLayout setLayout_0 = evkCreateDescriptorSetLayout(
// &device, svec_init(evkDescriptorBinding, {
// {
// .name = evstr("positions"),
// .binding = 0,
// .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
// .descriptorCount = 1,
// .stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS,
// },
// })
// );
// evkDescriptorSetLayout setLayout_0 = evkCreateDescriptorSetLayoutFromBindings(&device, vertShader.reflect.bindings);
// evkDescriptorSetLayout setLayout_0 = evkCreateDescriptorSetLayoutFromShaders(&device, svec_init(evkShader, {vertShader, fragShader}));
evkPipelineCreateInfo pipelineCreateInfo = EV_DEFAULT(evkPipelineCreateInfo,
dynamicStates = svec_init(VkDynamicState, {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
}),
shaderStages = svec_init(evkShader, {
vertShader,
fragShader,
}),
colorAttachments = svec_init(evkColorAttachment, {
colorAttachment0,
}),
viewportCountOverride = 1,
vertexBufferLayouts = svec_init(evkVertexBufferLayout, {
{{ // VB #0
{ EVK_VERTEX_ATTRIBUTE_POSITION, EVK_FMT_FLOAT32, 2 },
}},
}),
// setLayouts = svec_init(evkDescriptorSetLayout, {setLayout_0}),
);
evkBuffer resourceDescriptorHeap = evkCreateBuffer(&device, (evkBufferCreateInfo) {
.sizeInBytes = 16 * 4, // bufferDescriptorSize is 16 on my current device
.usage = VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
.exclusive = true,
.allocationCreateInfo = {
.allocationFlags = EVK_GPU_ALLOCATION_CREATE_MAPPED_BIT | EVK_GPU_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
.allocator = allocator,
}
});
evkBuffer uniBuf = evkCreateBuffer(&device, (evkBufferCreateInfo) {
.sizeInBytes = 12 * 4,
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
.allocationCreateInfo = {
.allocationFlags = EVK_GPU_ALLOCATION_CREATE_MAPPED_BIT | EVK_GPU_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
.allocator = allocator,
},
.exclusive = true,
});
float* uni_arr = (float*)uniBuf.allocData.allocationInfo.vma.pMappedData;
uni_arr[0] = 0.0f; uni_arr[1] = -0.5f; uni_arr[2] = 0.0f; uni_arr[3] = 1.0f;
uni_arr[4] = 0.5f; uni_arr[5] = 0.5f; uni_arr[6] = 0.0f; uni_arr[7] = 1.0f;
uni_arr[8] = -0.5f; uni_arr[9] = 0.5f; uni_arr[10] = 0.0f; uni_arr[11] = 1.0f;
// evkSetDescriptor(&set_0, evstr("vertexData"), &uniBuf);
VkResourceDescriptorInfoEXT resource = {
.sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT,
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.data.pAddressRange = &uniBuf.addressRange
};
VkHostAddressRangeEXT descriptor = {
.address = resourceDescriptorHeap.allocData.allocationInfo.vma.pMappedData,
.size = 16
};
vkWriteResourceDescriptorsEXT(device.vk, 1, &resource, &descriptor);
VkViewport viewport = EV_DEFAULT(VkViewport, width=width, height=height);
VkRect2D scissor = EV_DEFAULT(VkRect2D,extent.width=width, extent.height=height);
evkPipeline graphicsPipeline = evkCreatePipeline(device, pipelineCreateInfo);
u32 imageCount = vec_len(&swapChain.images);
VkFence drawFence = evkCreateFence(device, false);
vec(VkSemaphore) imageAcquiredSemaphores = vec_init(VkSemaphore);
vec(VkSemaphore) drawFinishedSemaphores = vec_init(VkSemaphore);
for(u32 i = 0; i < imageCount; i++)
{
imageAcquiredSemaphores[i] = evkCreateSemaphore(device);
drawFinishedSemaphores[i] = evkCreateSemaphore(device);
}
// VkSemaphore imageAcquiredSemaphore = evkCreateSemaphore(device);
// VkSemaphore drawFinishedSemaphore = evkCreateSemaphore(device);
i32 imageIdx = -1;
while(!glfwWindowShouldClose(window))
{
imageIdx = (imageIdx + 1) % imageCount;
u32 swapChainImageIdx;
EVK_CHECK(vkAcquireNextImageKHR(device.vk, swapChain.vk, UInt64.MAX, imageAcquiredSemaphores[imageIdx], VK_NULL_HANDLE, &swapChainImageIdx));
evkCommandBuffer cmdbuf = commandBuffers[imageIdx];
VkRenderingAttachmentInfoKHR colorAttachment = EV_DEFAULT(VkRenderingAttachmentInfoKHR,
imageView = swapChain.imageViews[swapChainImageIdx].vk,
loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
storeOp= VK_ATTACHMENT_STORE_OP_STORE,
);
VkRenderingInfo renderingInfo = EV_DEFAULT(VkRenderingInfo,
renderArea.extent = ((VkExtent2D){width, height}),
pColorAttachments = &colorAttachment,
colorAttachmentCount = 1,
);
evkBeginPrimaryCommandBuffer(&cmdbuf);
{
evkCmdImageBarrier(&cmdbuf, EV_DEFAULT(VkImageMemoryBarrier,
image = swapChain.images[swapChainImageIdx].vk,
newLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT
));
// VkDeviceSize offset = 0;
// vkCmdBindVertexBuffers(cmdbuf.vk, 0, 1, &vertBuf.vk, &offset);
// evkCmdBindDescriptorSets(&cmdbuf, &graphicsPipeline, svec_init(evkDescriptorSet, { set_0 }), svec_init(u32, { 0 }));
vkCmdSetScissor(cmdbuf.vk, 0, 1, &scissor);
vkCmdSetViewport(cmdbuf.vk, 0, 1, &viewport);
vkCmdBindResourceHeapEXT(cmdbuf.vk, &(VkBindHeapInfoEXT) {
.sType = VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT,
.heapRange = resourceDescriptorHeap.addressRange,
});
vkCmdBeginRenderingKHR(cmdbuf.vk, &renderingInfo);
evkCmdBindPipeline(&cmdbuf, &graphicsPipeline);
vkCmdDraw(cmdbuf.vk, 3, 1, 0, 0);
vkCmdEndRenderingKHR(cmdbuf.vk);
evkCmdImageBarrier(&cmdbuf, EV_DEFAULT(VkImageMemoryBarrier,
image = swapChain.images[swapChainImageIdx].vk,
oldLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR,
newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT
));
}
evkEndCommandBuffer(&cmdbuf);
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pCommandBuffers = &cmdbuf.vk, // TODO This won't work with more than a single cmdbuf
.commandBufferCount = 1,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &imageAcquiredSemaphores[imageIdx],
.pWaitDstStageMask = waitStages,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &drawFinishedSemaphores[swapChainImageIdx],
};
vkQueueSubmit(graphicsQueue, 1, &submitInfo, drawFence);
vkWaitForFences(device.vk, 1, &drawFence, VK_TRUE, UInt64.MAX);
vkResetFences(device.vk, 1, &drawFence);
VkPresentInfoKHR presentInfo = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &drawFinishedSemaphores[swapChainImageIdx],
.swapchainCount = 1,
.pSwapchains = &swapChain.vk,
.pImageIndices = &swapChainImageIdx,
};
vkQueuePresentKHR(graphicsQueue, &presentInfo);
vkResetCommandBuffer(cmdbuf.vk,VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
// Main Loop
glfwPollEvents();
}
vkQueueWaitIdle(graphicsQueue);
vkDestroyFence(device.vk, drawFence, NULL);
for(u32 i = 0; i < imageCount; i++)
{
vkDestroySemaphore(device.vk, imageAcquiredSemaphores[i], NULL);
vkDestroySemaphore(device.vk, drawFinishedSemaphores[i], NULL);
}
// vkDestroySemaphore(device.vk, imageAcquiredSemaphore, NULL);
// vkDestroySemaphore(device.vk, drawFinishedSemaphore, NULL);
evkDestroyPipeline(graphicsPipeline);
// evkDestroyBuffer(vertBuf);
evkDestroyBuffer(uniBuf);
// evkDestroyDescriptorSet(&device, &set_0);
// evkDestroyDescriptorSetLayout(&device, &setLayout_0);
evkDestroyShader(device, vertShader);
evkDestroyShader(device, fragShader);
evkFreeCommandBuffers(device, commandPool, commandBuffers);
evkDestroyCommandPool(device, commandPool);
evkGPUDestroyAllocator(allocator);
evkDestroySwapChain(device, swapChain);
// SwapchainCreationFailed:
vkDestroySurfaceKHR(instance.vk, swapChain.surface, NULL);
VKSurfaceCreationFailed:
WindowCreationFailed:
glfwTerminate();
GLFWInitFailed:
evkDestroyDevice(device);
DeviceCreationFailed:
evkDestroyInstance(instance);
InstanceCreationFailed:
return 0;
}
+10
View File
@@ -0,0 +1,10 @@
executable(
'mesh_shaders',
'mesh_shaders.c',
dependencies: [
dependency('evk'),
dependency('glfw3'),
],
c_args: evk_c_args,
)
@@ -0,0 +1,10 @@
#version 450
#pragma shader_stage(fragment)
#extension GL_EXT_descriptor_heap: require
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(0.f, 1.f, 0.f, 1.f);
}
@@ -0,0 +1,12 @@
#version 450
#pragma shader_stage(vertex)
#extension GL_EXT_descriptor_heap: require
layout(descriptor_heap) uniform data {
vec4 positions[3];
} vertexData[];
void main() {
gl_Position = vertexData[0].positions[gl_VertexIndex];
}
+2 -1
View File
@@ -1,2 +1,3 @@
# subdir('basic_triangle')
subdir('descriptor_heap')
# subdir('descriptor_heap')
subdir('mesh_shaders')