6#define VK_NO_PROTOTYPES
9#ifdef SBGL_PLATFORM_X11
18#define SBGL_MAX_FRAMES_IN_FLIGHT 2
19#define SBGL_MAX_SWAPCHAIN_IMAGES 8
20#define SBGL_TRANSIENT_BUFFER_SIZE (16 * 1024 * 1024)
21#define SBGL_STATIC_HEAP_SIZE (128 * 1024 * 1024)
22#define SBGL_DYNAMIC_HEAP_SIZE (128 * 1024 * 1024)
23#define SBGL_MANAGED_HEAP_SIZE (512 * 1024 * 1024)
102 struct VolkDeviceTable
vk;
174 for (uint32_t i = 0; i < ctx->
imageCount; i++) {
186 while (w == 0 || h == 0) {
191 ctx->
vk.vkDeviceWaitIdle(ctx->
device);
197#define SBGL_VK_PUSH_CONSTANT_SIZE 128
199static VKAPI_ATTR VkBool32 VKAPI_CALL
201 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
202 VkDebugUtilsMessageTypeFlagsEXT messageType,
203 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
210 (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
215 __FILE__, __LINE__, __func__,
216 pCallbackData->pMessage);
222 VkDebugUtilsMessengerCreateInfoEXT createInfo = {
223 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
224 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
225 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
226 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
227 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
232 PFN_vkCreateDebugUtilsMessengerEXT func =
233 (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
234 ctx->
instance,
"vkCreateDebugUtilsMessengerEXT");
240 VkDebugUtilsMessengerEXT messenger;
241 if (func(ctx->
instance, &createInfo, NULL, &messenger) != VK_SUCCESS) {
251 return VK_FORMAT_R32_SFLOAT;
253 return VK_FORMAT_R32G32_SFLOAT;
255 return VK_FORMAT_R32G32B32_SFLOAT;
257 return VK_FORMAT_R32G32B32A32_SFLOAT;
259 return VK_FORMAT_R16G16B16A16_SNORM;
261 return VK_FORMAT_R8G8B8A8_UNORM;
263 return VK_FORMAT_UNDEFINED;
269 VkPhysicalDeviceMemoryProperties memProperties;
270 vkGetPhysicalDeviceMemoryProperties(ctx->
physicalDevice, &memProperties);
272 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
273 if ((typeFilter & (1 << i)) &&
274 (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
284 uint32_t alignedSize = (uint32_t)((size + 255) & ~255);
301 uint32_t alignedSize = (uint32_t)((size + 255) & ~255);
320 uint32_t alignedSize = (uint32_t)((size + 255) & ~255);
328 uint32_t offset = range->
offset;
330 if (range->
size > alignedSize) {
346 .offset = offset + alignedSize,
347 .size = range->
size - alignedSize,
352 range->
size = alignedSize;
398 fprintf(stderr,
"[Vulkan] managed_heap_free: offset %u not found in tracked ranges (possible double-free or corruption)\n", offset);
410 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
417 VkMemoryAllocateFlagsInfo flagsInfo = {
418 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO,
419 .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT,
422 VkMemoryAllocateInfo allocInfo = {
423 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
425 .memoryTypeIndex = memoryTypeIndex,
464 VkApplicationInfo appInfo = {
465 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
466 .pApplicationName =
"SBgl Application",
467 .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
468 .pEngineName =
"SBgl",
469 .engineVersion = VK_MAKE_VERSION(1, 0, 0),
470 .apiVersion = VK_API_VERSION_1_3,
473 const char* extensions[] = {
474 VK_KHR_SURFACE_EXTENSION_NAME,
475#ifdef SBGL_PLATFORM_WAYLAND
476 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
477#elif defined(SBGL_PLATFORM_X11)
478 VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
480 VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
484 VkInstanceCreateInfo createInfo = {
485 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
486 .pApplicationInfo = &appInfo,
487 .enabledExtensionCount =
sizeof(extensions) /
sizeof(extensions[0]),
488 .ppEnabledExtensionNames = extensions,
491 if (enableValidation) {
492 const char* layers[] = {
"VK_LAYER_KHRONOS_validation" };
493 createInfo.enabledLayerCount = 1;
494 createInfo.ppEnabledLayerNames = layers;
497 VkResult result = vkCreateInstance(&createInfo, NULL, &ctx->
instance);
500 if (result != VK_SUCCESS) {
506 if (enableValidation) {
514#ifdef SBGL_PLATFORM_WAYLAND
515 VkWaylandSurfaceCreateInfoKHR createInfo = {
516 .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
520 if (vkCreateWaylandSurfaceKHR(ctx->
instance, &createInfo, NULL, &ctx->
surface) != VK_SUCCESS) {
521 fprintf(stderr,
"[Vulkan] Failed to create Wayland surface\n");
524#elif defined(SBGL_PLATFORM_X11)
525 VkXlibSurfaceCreateInfoKHR createInfo = {
526 .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
530 if (vkCreateXlibSurfaceKHR(ctx->
instance, &createInfo, NULL, &ctx->
surface) != VK_SUCCESS) {
531 fprintf(stderr,
"[Vulkan] Failed to create Xlib surface\n");
535 VkWin32SurfaceCreateInfoKHR createInfo = {
536 .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
540 if (vkCreateWin32SurfaceKHR(ctx->
instance, &createInfo, NULL, &ctx->
surface) != VK_SUCCESS) {
541 fprintf(stderr,
"[Vulkan] Failed to create Win32 surface\n");
546 printf(
"[Vulkan] Surface created successfully\n");
551 uint32_t deviceCount = 0;
552 vkEnumeratePhysicalDevices(ctx->
instance, &deviceCount, NULL);
553 if (deviceCount == 0) {
554 fprintf(stderr,
"[Vulkan] No physical devices found\n");
562 vkEnumeratePhysicalDevices(ctx->
instance, &deviceCount, devices);
564 for (uint32_t i = 0; i < deviceCount; i++) {
565 VkPhysicalDeviceProperties props;
566 vkGetPhysicalDeviceProperties(devices[i], &props);
567 if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
569 printf(
"[Vulkan] Selected Discrete GPU: %s\n", props.deviceName);
576 VkPhysicalDeviceProperties props;
578 printf(
"[Vulkan] Selected GPU: %s\n", props.deviceName);
586 uint32_t queueFamilyCount = 0;
587 vkGetPhysicalDeviceQueueFamilyProperties(ctx->
physicalDevice, &queueFamilyCount, NULL);
590 VkQueueFamilyProperties* queueFamilies =
594 vkGetPhysicalDeviceQueueFamilyProperties(ctx->
physicalDevice, &queueFamilyCount, queueFamilies);
596 int graphicsFamily = -1;
597 for (uint32_t i = 0; i < queueFamilyCount; i++) {
598 VkBool32 presentSupport =
false;
600 if ((queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && presentSupport) {
607 if (graphicsFamily == -1) {
608 fprintf(stderr,
"[Vulkan] No suitable queue family found\n");
613 float queuePriority = 1.0f;
614 VkDeviceQueueCreateInfo queueCreateInfo = {
615 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
618 .pQueuePriorities = &queuePriority,
621 VkPhysicalDeviceFeatures deviceFeatures = {
622 .multiDrawIndirect = VK_TRUE,
623 .shaderInt64 = VK_TRUE,
626 const char* deviceExtensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME,
627 VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
628 VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME };
630 VkPhysicalDeviceVulkan11Features features11 = {
631 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
632 .shaderDrawParameters = VK_TRUE,
635 VkPhysicalDeviceVulkan12Features features12 = {
636 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
637 .pNext = &features11,
638 .bufferDeviceAddress = VK_TRUE,
639 .hostQueryReset = VK_TRUE,
642 VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures = {
643 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
644 .pNext = &features12,
645 .dynamicRendering = VK_TRUE,
648 VkDeviceCreateInfo createInfo = {
649 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
650 .pNext = &dynamicRenderingFeatures,
651 .queueCreateInfoCount = 1,
652 .pQueueCreateInfos = &queueCreateInfo,
653 .pEnabledFeatures = &deviceFeatures,
654 .enabledExtensionCount = 3,
655 .ppEnabledExtensionNames = deviceExtensions,
659 fprintf(stderr,
"[Vulkan] Failed to create logical device\n");
663 volkLoadDeviceTable(&ctx->
vk, ctx->
device);
667 printf(
"[Vulkan] Logical Device created (Dynamic Rendering enabled)\n");
672 VkFormat candidates[] = { VK_FORMAT_D32_SFLOAT,
673 VK_FORMAT_D32_SFLOAT_S8_UINT,
674 VK_FORMAT_D24_UNORM_S8_UINT };
675 for (uint32_t i = 0; i < 3; i++) {
676 VkFormatProperties props;
677 vkGetPhysicalDeviceFormatProperties(ctx->
physicalDevice, candidates[i], &props);
678 if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
690 VkImageCreateInfo imageInfo = {
691 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
692 .imageType = VK_IMAGE_TYPE_2D,
699 .tiling = VK_IMAGE_TILING_OPTIMAL,
700 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
701 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
702 .samples = VK_SAMPLE_COUNT_1_BIT,
703 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
706 if (ctx->
vk.vkCreateImage(ctx->
device, &imageInfo, NULL, &ctx->
depthImage) != VK_SUCCESS)
709 VkMemoryRequirements memRequirements;
712 VkMemoryAllocateInfo allocInfo = {
713 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
714 .allocationSize = memRequirements.size,
717 memRequirements.memoryTypeBits,
718 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
722 if (ctx->
vk.vkAllocateMemory(ctx->
device, &allocInfo, NULL, &ctx->
depthMemory) != VK_SUCCESS)
727 VkImageViewCreateInfo viewInfo = {
728 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
730 .viewType = VK_IMAGE_VIEW_TYPE_2D,
732 .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
747 VkSurfaceCapabilitiesKHR capabilities;
750 VkExtent2D extent = { (uint32_t)w, (uint32_t)h };
751 if (capabilities.currentExtent.width != 0xFFFFFFFF) {
752 extent = capabilities.currentExtent;
755 if (extent.width == 0 || extent.height == 0) {
759 uint32_t formatCount;
761 if (formatCount == 0) {
762 fprintf(stderr,
"[Vulkan] No supported surface formats found\n");
765 VkSurfaceFormatKHR formats[64];
766 if (formatCount > 64)
770 VkSurfaceFormatKHR selectedFormat = formats[0];
771 for (uint32_t i = 0; i < formatCount; i++) {
772 if ((formats[i].format == VK_FORMAT_B8G8R8A8_SRGB ||
773 formats[i].format == VK_FORMAT_R8G8B8A8_SRGB) &&
774 formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
775 selectedFormat = formats[i];
780 uint32_t imageCount = capabilities.minImageCount + 1;
781 if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) {
782 imageCount = capabilities.maxImageCount;
785 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
786 uint32_t presentModeCount;
787 vkGetPhysicalDeviceSurfacePresentModesKHR(
793 if (presentModeCount > 0) {
794 VkPresentModeKHR presentModes[16];
795 if (presentModeCount > 16)
796 presentModeCount = 16;
797 vkGetPhysicalDeviceSurfacePresentModesKHR(
807 bool mailboxSupported =
false;
808 bool immediateSupported =
false;
809 for (uint32_t i = 0; i < presentModeCount; i++) {
810 if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
811 immediateSupported =
true;
812 if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
813 mailboxSupported =
true;
816 if (immediateSupported) {
817 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
818 }
else if (mailboxSupported) {
819 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
823 VkSwapchainCreateInfoKHR createInfo = {
824 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
826 .minImageCount = imageCount,
827 .imageFormat = selectedFormat.format,
828 .imageColorSpace = selectedFormat.colorSpace,
829 .imageExtent = extent,
830 .imageArrayLayers = 1,
831 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
832 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
833 .preTransform = capabilities.currentTransform,
834 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
835 .presentMode = presentMode,
839 if (ctx->
vk.vkCreateSwapchainKHR(ctx->
device, &createInfo, NULL, &ctx->
swapchain) !=
841 fprintf(stderr,
"[Vulkan] Failed to create swapchain\n");
859 for (uint32_t i = 0; i < ctx->
imageCount; i++) {
860 VkImageViewCreateInfo viewInfo = {
861 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
863 .viewType = VK_IMAGE_VIEW_TYPE_2D,
865 .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
873 "[Vulkan] Swapchain created (%dx%d, %u images, format: %d)\n",
887 VkCommandPoolCreateInfo poolInfo = {
888 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
889 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
892 if (ctx->
vk.vkCreateCommandPool(ctx->
device, &poolInfo, NULL, &ctx->
commandPool) != VK_SUCCESS)
895 VkCommandBufferAllocateInfo allocInfo = {
896 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
898 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
905 VkSemaphoreCreateInfo semInfo = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
906 VkFenceCreateInfo fenceInfo = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
907 .flags = VK_FENCE_CREATE_SIGNALED_BIT };
916 if (ctx->
vk.vkCreateSemaphore(
922 ctx->
vk.vkCreateSemaphore(
937 VkQueryPoolCreateInfo queryPoolInfo = {
938 .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
939 .queryType = VK_QUERY_TYPE_TIMESTAMP,
943 if (ctx->
vk.vkCreateQueryPool(ctx->
device, &queryPoolInfo, NULL, &ctx->
queryPool) !=
950 VkPhysicalDeviceProperties props;
986 if (volkInitialize() != VK_SUCCESS) {
987 fprintf(stderr,
"[Vulkan] Failed to initialize volk\n");
1018 fprintf(stderr,
"[Vulkan] Failed to allocate resource arrays\n");
1043 ctx->
vk.vkDeviceWaitIdle(ctx->
device);
1097 ctx->
vk.vkDestroyDevice(ctx->
device, NULL);
1101 vkDestroyInstance(ctx->
instance, NULL);
1106 ctx->
vk.vkWaitForFences(
1131 VkResult result = ctx->
vk.vkAcquireNextImageKHR(
1142 if (result == VK_ERROR_OUT_OF_DATE_KHR) {
1145 }
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
1151 VkCommandBufferBeginInfo beginInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1156 ctx->
vk.vkCmdResetQueryPool(
1168 ctx->
vk.vkCmdWriteTimestamp(
1170 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1175 VkImageMemoryBarrier barriers[2] = { 0 };
1176 barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1177 barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1178 barriers[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1180 barriers[0].subresourceRange =
1181 (VkImageSubresourceRange){ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1184 barriers[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1186 barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1187 barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1188 barriers[1].newLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
1190 barriers[1].subresourceRange =
1191 (VkImageSubresourceRange){ .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
1194 barriers[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1196 ctx->
vk.vkCmdPipelineBarrier(
1198 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1199 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
1209 VkRenderingAttachmentInfo colorAttachment = {
1210 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
1212 .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1213 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1214 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1215 .clearValue = { { { r, g, b, a } } },
1218 VkRenderingAttachmentInfo depthAttachment = {
1219 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
1221 .imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
1222 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1223 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1224 .clearValue = { .depthStencil = { 1.0f, 0 } },
1227 VkRenderingInfo renderingInfo = {
1228 .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
1231 .colorAttachmentCount = 1,
1232 .pColorAttachments = &colorAttachment,
1233 .pDepthAttachment = &depthAttachment,
1242 ctx->
vk.vkCmdWriteTimestamp(
1244 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1251 VkImageMemoryBarrier barrier = {
1252 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1253 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1254 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1256 .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1259 .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1262 ctx->
vk.vkCmdPipelineBarrier(
1264 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1265 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1279 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1285 VkSubmitInfo submitInfo = {
1286 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1287 .waitSemaphoreCount = 1,
1289 .pWaitDstStageMask = waitStages,
1290 .commandBufferCount = 1,
1292 .signalSemaphoreCount = 1,
1293 .pSignalSemaphores = &signalSemaphore,
1298 VkPresentInfoKHR presentInfo = {
1299 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1300 .waitSemaphoreCount = 1,
1301 .pWaitSemaphores = &signalSemaphore,
1302 .swapchainCount = 1,
1306 VkResult result = ctx->
vk.vkQueuePresentKHR(ctx->
graphicsQueue, &presentInfo);
1308 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
1317 if (ctx && ctx->
device) {
1318 ctx->
vk.vkDeviceWaitIdle(ctx->
device);
1343 VkBufferCreateInfo bufferInfo = {
1344 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1351 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
1352 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
1356 if (ctx->
vk.vkCreateBuffer(ctx->
device, &bufferInfo, NULL, &buffer->
handle) != VK_SUCCESS) {
1360 VkMemoryRequirements memRequirements;
1361 ctx->
vk.vkGetBufferMemoryRequirements(ctx->
device, buffer->
handle, &memRequirements);
1365 VkDeviceMemory heapMemory = VK_NULL_HANDLE;
1366 void* heapMappedBase = NULL;
1392 ctx->
vk.vkBindBufferMemory(ctx->
device, buffer->
handle, heapMemory, offset);
1394 buffer->
size = size;
1397 buffer->
mapped = (
char*)heapMappedBase + offset;
1402 if (data && buffer->
mapped) {
1403 memcpy(buffer->
mapped, data, size);
1416 uint32_t index = (uint32_t)handle - 1;
1441 uint32_t index = (uint32_t)handle - 1;
1445 ctx->
vk.vkCmdFillBuffer(
1448 (VkDeviceSize)offset,
1465 uint32_t index = (uint32_t)handle - 1;
1497 uint32_t index = (uint32_t)handle - 1;
1501 VkBufferDeviceAddressInfo info = {
1502 .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
1506 return ctx->
vk.vkGetBufferDeviceAddress(ctx->
device, &info);
1512 const uint32_t* bytecode,
1523 VkShaderModuleCreateInfo createInfo = {
1524 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
1542 uint32_t index = (uint32_t)handle - 1;
1559 VkPipelineShaderStageCreateInfo shaderStages[2] = { 0 };
1563 fprintf(stderr,
"[Vulkan] Invalid vertex shader handle\n");
1568 fprintf(stderr,
"[Vulkan] Invalid vertex shader stage or inactive shader\n");
1571 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1572 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
1574 shaderStages[0].pName =
"main";
1578 fprintf(stderr,
"[Vulkan] Invalid fragment shader handle\n");
1583 fprintf(stderr,
"[Vulkan] Invalid fragment shader stage or inactive shader\n");
1586 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1587 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1589 shaderStages[1].pName =
"main";
1591 VkVertexInputBindingDescription bindingDescription = {
1594 .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
1600 VkVertexInputAttributeDescription,
1607 attributeDescriptions[i].binding = 0;
1609 attributeDescriptions[i].format =
1614 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
1615 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1616 .vertexBindingDescriptionCount = 1,
1617 .pVertexBindingDescriptions = &bindingDescription,
1619 .pVertexAttributeDescriptions = attributeDescriptions,
1622 VkPipelineInputAssemblyStateCreateInfo inputAssembly = {
1623 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
1624 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1625 .primitiveRestartEnable = VK_FALSE,
1628 VkPipelineViewportStateCreateInfo viewportState = {
1629 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
1634 VkPipelineRasterizationStateCreateInfo rasterizer = {
1635 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
1636 .depthClampEnable = VK_FALSE,
1637 .rasterizerDiscardEnable = VK_FALSE,
1638 .polygonMode = VK_POLYGON_MODE_FILL,
1640 .cullMode = VK_CULL_MODE_BACK_BIT,
1641 .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
1642 .depthBiasEnable = VK_FALSE,
1645 VkPipelineMultisampleStateCreateInfo multisampling = {
1646 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
1647 .sampleShadingEnable = VK_FALSE,
1648 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
1651 VkPipelineDepthStencilStateCreateInfo depthStencil = {
1652 .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
1653 .depthTestEnable = VK_TRUE,
1654 .depthWriteEnable = VK_TRUE,
1655 .depthCompareOp = VK_COMPARE_OP_LESS,
1656 .depthBoundsTestEnable = VK_FALSE,
1657 .stencilTestEnable = VK_FALSE,
1660 VkPipelineColorBlendAttachmentState colorBlendAttachment = {
1661 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
1662 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
1666 .colorBlendOp = VK_BLEND_OP_ADD,
1667 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
1668 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
1669 .alphaBlendOp = VK_BLEND_OP_ADD,
1672 VkPipelineColorBlendStateCreateInfo colorBlending = {
1673 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
1674 .logicOpEnable = VK_FALSE,
1675 .attachmentCount = 1,
1676 .pAttachments = &colorBlendAttachment,
1679 VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
1680 VkPipelineDynamicStateCreateInfo dynamicState = {
1681 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
1682 .dynamicStateCount = 2,
1683 .pDynamicStates = dynamicStates,
1686 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
1687 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1690 VkPushConstantRange pushConstantRange = {
1691 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
1695 pipelineLayoutInfo.pushConstantRangeCount = 1;
1696 pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
1698 if (ctx->
vk.vkCreatePipelineLayout(
1700 &pipelineLayoutInfo,
1708 VkPipelineRenderingCreateInfo renderingCreateInfo = {
1709 .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
1710 .colorAttachmentCount = 1,
1715 VkGraphicsPipelineCreateInfo pipelineInfo = {
1716 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1717 .pNext = &renderingCreateInfo,
1719 .pStages = shaderStages,
1720 .pVertexInputState = &vertexInputInfo,
1721 .pInputAssemblyState = &inputAssembly,
1722 .pViewportState = &viewportState,
1723 .pRasterizationState = &rasterizer,
1724 .pMultisampleState = &multisampling,
1725 .pDepthStencilState = &depthStencil,
1726 .pColorBlendState = &colorBlending,
1727 .pDynamicState = &dynamicState,
1729 .renderPass = VK_NULL_HANDLE,
1733 if (ctx->
vk.vkCreateGraphicsPipelines(
1754 uint32_t index = (uint32_t)handle - 1;
1775 fprintf(stderr,
"[Vulkan] Invalid compute shader handle\n");
1778 uint32_t shaderIndex = handle - 1;
1780 fprintf(stderr,
"[Vulkan] Invalid compute shader stage or inactive shader\n");
1784 VkPipelineShaderStageCreateInfo stageInfo = {
1785 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
1786 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
1791 VkPipelineLayoutCreateInfo layoutInfo = {
1792 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1797 VkPushConstantRange pushConstantRange = {
1798 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
1802 layoutInfo.pushConstantRangeCount = 1;
1803 layoutInfo.pPushConstantRanges = &pushConstantRange;
1805 if (ctx->
vk.vkCreatePipelineLayout(
1814 VkComputePipelineCreateInfo pipelineInfo = {
1815 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1820 if (ctx->
vk.vkCreateComputePipelines(
1841 uint32_t index = (uint32_t)handle - 1;
1857 uint32_t index = (uint32_t)handle - 1;
1861 ctx->
vk.vkCmdBindPipeline(
1863 VK_PIPELINE_BIND_POINT_COMPUTE,
1878 VkMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER };
1879 VkPipelineStageFlags srcStage = 0;
1880 VkPipelineStageFlags dstStage = 0;
1886 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
1887 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1888 srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
1889 dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1893 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
1894 barrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
1895 srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1896 dstStage = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
1900 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
1901 barrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
1902 srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1903 dstStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
1907 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
1908 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1909 srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
1910 dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1914 barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
1915 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1916 srcStage = VK_PIPELINE_STAGE_HOST_BIT;
1917 dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1921 barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
1922 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
1923 srcStage = VK_PIPELINE_STAGE_HOST_BIT;
1924 dstStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
1928 ctx->
vk.vkCmdPipelineBarrier(
1945 uint32_t index = (uint32_t)handle - 1;
1949 ctx->
vk.vkCmdBindPipeline(
1951 VK_PIPELINE_BIND_POINT_GRAPHICS,
1956 VkViewport viewport = {
1966 VkRect2D scissor = { .offset = { 0, 0 }, .extent = ctx->
swapchainExtent };
1973 uint32_t index = (uint32_t)handle - 1;
1978 VkDeviceSize offsets[] = { 0 };
1979 ctx->
vk.vkCmdBindVertexBuffers(
1987 ctx->
vk.vkCmdBindIndexBuffer(
1991 VK_INDEX_TYPE_UINT32
2002 uint32_t indexCount,
2003 uint32_t firstIndex,
2004 int32_t vertexOffset,
2005 uint32_t instanceCount
2007 ctx->
vk.vkCmdDrawIndexed(
2025 uint32_t index = (uint32_t)handle - 1;
2029 ctx->
vk.vkCmdDrawIndexedIndirect(
2032 (VkDeviceSize)offset,
2045 if (alignment > 0) {
2046 offset = (offset + alignment - 1) & ~(alignment - 1);
2050 fprintf(stderr,
"[Vulkan] Transient buffer overflow for frame %u!\n", frame);
2057 .size = (uint32_t)size,
2076 ctx->
vk.vkCmdPushConstants(
2079 VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
2088 ctx->
vk.vkCmdPushConstants(
2091 VK_SHADER_STAGE_COMPUTE_BIT,
2102 uint64_t results[2] = { 0 };
2103 VkResult res = ctx->
vk.vkGetQueryPoolResults(
2111 VK_QUERY_RESULT_64_BIT
2114 if (res == VK_SUCCESS) {
2115 uint64_t start = results[0];
2116 uint64_t end = results[1];
static bool create_sync_and_command(sbgl_GfxContext *ctx)
void sbgl_gfx_Shutdown(sbgl_GfxContext *ctx)
void sbgl_gfx_BindComputePipeline(sbgl_GfxContext *ctx, sbgl_ComputePipeline handle)
void sbgl_gfx_Draw(sbgl_GfxContext *ctx, uint32_t vertexCount, uint32_t firstVertex, uint32_t instanceCount)
static bool create_instance(sbgl_GfxContext *ctx, bool enableValidation)
uint64_t sbgl_gfx_GetBufferDeviceAddress(sbgl_GfxContext *ctx, sbgl_Buffer handle)
Retrieves the 64-bit GPU virtual address for a buffer.
sbgl_GfxContext * sbgl_gfx_Init(sbgl_Window *window, struct SblArena *arena, const sbgl_ResourceLimits *limits, bool enableValidation)
Initializes the graphics backend with configurable resource limits.
sbgl_Buffer sbgl_gfx_CreateBuffer(sbgl_GfxContext *ctx, sbgl_BufferUsage usage, size_t size, const void *data)
void sbgl_gfx_EndRenderPass(sbgl_GfxContext *ctx)
Ends the current graphics rendering pass.
void sbgl_gfx_DestroyShader(sbgl_GfxContext *ctx, sbgl_Shader handle)
void sbgl_gfx_DispatchCompute(sbgl_GfxContext *ctx, uint32_t x, uint32_t y, uint32_t z)
void sbgl_gfx_DestroyPipeline(sbgl_GfxContext *ctx, sbgl_Pipeline handle)
static bool create_heaps(sbgl_GfxContext *ctx)
#define SBGL_VK_PUSH_CONSTANT_SIZE
void sbgl_gfx_BindPipeline(sbgl_GfxContext *ctx, sbgl_Pipeline handle)
static VKAPI_ATTR VkBool32 VKAPI_CALL sbgl_vk_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData)
static bool find_depth_format(sbgl_GfxContext *ctx)
static bool create_swapchain(sbgl_GfxContext *ctx, sbgl_Window *window)
void * sbgl_gfx_MapBuffer(sbgl_GfxContext *ctx, sbgl_Buffer handle)
bool sbgl_gfx_BeginFrame(sbgl_GfxContext *ctx)
Starts a new frame, acquiring an image and starting the command buffer.
static bool select_physical_device(sbgl_GfxContext *ctx)
void sbgl_gfx_MemoryBarrier(sbgl_GfxContext *ctx, sbgl_BarrierType type)
static VkFormat sbgl_to_vk_format(sbgl_Format format)
static void managed_heap_free(sbgl_GfxContext *ctx, uint32_t offset)
static void recreate_swapchain(sbgl_GfxContext *ctx)
static uint32_t find_memory_type(sbgl_GfxContext *ctx, uint32_t typeFilter, VkMemoryPropertyFlags properties)
#define SBGL_STATIC_HEAP_SIZE
#define SBGL_DYNAMIC_HEAP_SIZE
float sbgl_gfx_GetGpuTime(sbgl_GfxContext *ctx)
Retrieves the elapsed GPU time for the previous frame in milliseconds.
void sbgl_gfx_UnmapBuffer(sbgl_GfxContext *ctx, sbgl_Buffer handle)
static void sbgl_setup_debug_utils(sbgl_GfxContext *ctx)
#define SBGL_MAX_FRAMES_IN_FLIGHT
void sbgl_gfx_DrawIndexed(sbgl_GfxContext *ctx, uint32_t indexCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t instanceCount)
static const sbgl_ResourceLimits sbgl_DefaultResourceLimits
static uint32_t static_heap_alloc(sbgl_GfxContext *ctx, size_t size)
#define SBGL_MAX_SWAPCHAIN_IMAGES
#define SBGL_MANAGED_HEAP_SIZE
sbgl_Shader sbgl_gfx_LoadShader(sbgl_GfxContext *ctx, sbgl_ShaderStage stage, const uint32_t *bytecode, size_t size)
sbgl_Pipeline sbgl_gfx_CreatePipeline(sbgl_GfxContext *ctx, const sbgl_PipelineConfig *config)
void sbgl_gfx_PushConstants(sbgl_GfxContext *ctx, size_t size, const void *data)
static void cleanup_swapchain(sbgl_GfxContext *ctx)
#define SBGL_TRANSIENT_BUFFER_SIZE
static bool create_depth_resources(sbgl_GfxContext *ctx)
static bool create_logical_device(sbgl_GfxContext *ctx)
sbgl_GfxTransientAllocation sbgl_gfx_AllocateTransient(sbgl_GfxContext *ctx, size_t size, uint32_t alignment)
Allocates a slice of GPU-visible memory for transient per-frame data.
static bool create_telemetry_resources(sbgl_GfxContext *ctx)
void sbgl_gfx_DestroyBuffer(sbgl_GfxContext *ctx, sbgl_Buffer handle)
void sbgl_gfx_DeviceWaitIdle(sbgl_GfxContext *ctx)
void sbgl_gfx_DestroyBufferDeferred(sbgl_GfxContext *ctx, sbgl_Buffer handle)
Marks a buffer for destruction after current frames complete.
void sbgl_gfx_DrawIndirect(sbgl_GfxContext *ctx, sbgl_Buffer handle, size_t offset, uint32_t drawCount)
Submits a batch of draw calls stored in a GPU buffer.
int32_t sbgl_gfx_GetLastVkResult(sbgl_GfxContext *ctx)
Retrieves the last VkResult from the backend for error inspection.
void sbgl_gfx_FillBuffer(sbgl_GfxContext *ctx, sbgl_Buffer handle, size_t offset, size_t size, uint32_t value)
Performs a hardware-accelerated buffer fill.
static uint32_t dynamic_heap_alloc(sbgl_GfxContext *ctx, size_t size)
sbgl_ComputePipeline sbgl_gfx_CreateComputePipeline(sbgl_GfxContext *ctx, sbgl_Shader handle)
uint32_t sbgl_gfx_GetFrameIndex(sbgl_GfxContext *ctx)
Retrieves the current backend frame index.
static uint32_t managed_heap_alloc(sbgl_GfxContext *ctx, size_t size)
void sbgl_gfx_DestroyComputePipeline(sbgl_GfxContext *ctx, sbgl_ComputePipeline handle)
void sbgl_gfx_BindBuffer(sbgl_GfxContext *ctx, sbgl_Buffer handle, sbgl_BufferUsage usage)
static bool create_transient_resources(sbgl_GfxContext *ctx)
void sbgl_gfx_EndFrame(sbgl_GfxContext *ctx)
Submits the current frame's commands and presents the image.
static bool create_surface(sbgl_GfxContext *ctx, sbgl_Window *window)
void sbgl_gfx_BeginRenderPass(sbgl_GfxContext *ctx, float r, float g, float b, float a)
Starts a graphics rendering pass.
sbgl_LogLevel
Logging severity levels.
void sbgl_internal_log_impl(sbgl_LogLevel level, sbgl_LogCategory category, const char *file, int line, const char *function, const char *message)
@ SBGL_BLEND_MODE_ADDITIVE
#define SBGL_INVALID_OFFSET
sbgl_BufferUsage
Buffer usage flags.
@ SBGL_BUFFER_USAGE_INDEX
@ SBGL_BUFFER_USAGE_INDIRECT
@ SBGL_BUFFER_USAGE_TRANSFER_DST
@ SBGL_BUFFER_USAGE_STORAGE
@ SBGL_BUFFER_USAGE_VERTEX
sbgl_Result
Result codes for engine operations.
@ SBGL_ERROR_OUT_OF_MEMORY
sbgl_Format
Data formats for vertex attributes.
@ SBGL_FORMAT_R8G8B8A8_UNORM
@ SBGL_FORMAT_R32G32_SFLOAT
@ SBGL_FORMAT_R16G16B16A16_SNORM
@ SBGL_FORMAT_R32G32B32_SFLOAT
@ SBGL_FORMAT_R32G32B32A32_SFLOAT
sbgl_BarrierType
Memory barrier types for compute synchronization.
@ SBGL_BARRIER_COMPUTE_TO_INDIRECT
@ SBGL_BARRIER_GRAPHICS_TO_COMPUTE
@ SBGL_BARRIER_COMPUTE_TO_COMPUTE
@ SBGL_BARRIER_HOST_TO_GRAPHICS
@ SBGL_BARRIER_HOST_TO_COMPUTE
@ SBGL_BARRIER_COMPUTE_TO_GRAPHICS
uint32_t sbgl_Buffer
Handle for a GPU-side buffer.
uint32_t sbgl_Shader
Handle for a shader module.
sbgl_ShaderStage
Shader stage flags.
@ SBGL_SHADER_STAGE_COMPUTE
@ SBGL_SHADER_STAGE_FRAGMENT
@ SBGL_SHADER_STAGE_VERTEX
uint32_t sbgl_ComputePipeline
Handle for a compute pipeline.
uint32_t sbgl_Pipeline
Handle for a graphics pipeline.
#define SBGL_INVALID_HANDLE
Arena allocator implementation.
SBL_ARENA_DEF void * sbl_arena_alloc_zero(SblArena *arena, uint64_t size)
SBL_ARENA_DEF SblArenaMark sbl_arena_mark(SblArena *arena)
#define SBL_ARENA_PUSH_STRUCT_ZERO(arena, type)
#define SBL_ARENA_PUSH_ARRAY(arena, type, count)
SBL_ARENA_DEF void sbl_arena_rewind(SblArena *arena, SblArenaMark mark)
Bookmark for arena state.
void * transientMapped[SBGL_MAX_FRAMES_IN_FLIGHT]
sbgl_Buffer deferredBuffers[SBGL_MAX_FRAMES_IN_FLIGHT][64]
sbgl_GfxDynamicHeap dynamicHeap
SblArenaMark swapchainMark
VkCommandBuffer commandBuffers[SBGL_MAX_FRAMES_IN_FLIGHT]
uint32_t transientOffsets[SBGL_MAX_FRAMES_IN_FLIGHT]
VkSemaphore imageAvailableSemaphores[SBGL_MAX_SWAPCHAIN_IMAGES]
sbgl_Buffer transientBuffers[SBGL_MAX_FRAMES_IN_FLIGHT]
VkSemaphore renderFinishedSemaphores[SBGL_MAX_SWAPCHAIN_IMAGES]
SBGL_VulkanShader * shaders
uint32_t graphicsQueueFamily
struct VolkDeviceTable vk
uint32_t deferredCount[SBGL_MAX_FRAMES_IN_FLIGHT]
sbgl_GfxManagedHeap managedHeap
sbgl_ResourceLimits limits
SBGL_VulkanBuffer * buffers
SBGL_VulkanPipeline * pipelines
VkDeviceMemory depthMemory
VkFence inFlightFences[SBGL_MAX_FRAMES_IN_FLIGHT]
SBGL_VulkanComputePipeline * computePipelines
uint32_t currentImageIndex
sbgl_Pipeline boundPipeline
VkCommandPool commandPool
sbgl_GfxStaticHeap staticHeap
VkExtent2D swapchainExtent
VkImageView depthImageView
sbgl_ComputePipeline boundComputePipeline
VkPhysicalDevice physicalDevice
sbgl_GfxMemoryRange ranges[1024]
Represents a slice of a persistent GPU buffer used for transient data.
Standard Vulkan Indirect Draw command layout.
Configuration for creating a graphics pipeline.
sbgl_Shader fragmentShader
sbgl_VertexLayout vertexLayout
Resource limits for engine initialization.
const sbgl_VertexAttribute * attributes