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 const char* layers[] = {
"VK_LAYER_KHRONOS_validation" };
493 if (enableValidation) {
494 createInfo.enabledLayerCount = 1;
495 createInfo.ppEnabledLayerNames = layers;
498 VkResult result = vkCreateInstance(&createInfo, NULL, &ctx->
instance);
501 if (result != VK_SUCCESS) {
507 if (enableValidation) {
515#ifdef SBGL_PLATFORM_WAYLAND
516 VkWaylandSurfaceCreateInfoKHR createInfo = {
517 .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
521 if (vkCreateWaylandSurfaceKHR(ctx->
instance, &createInfo, NULL, &ctx->
surface) != VK_SUCCESS) {
522 fprintf(stderr,
"[Vulkan] Failed to create Wayland surface\n");
525#elif defined(SBGL_PLATFORM_X11)
526 VkXlibSurfaceCreateInfoKHR createInfo = {
527 .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
531 if (vkCreateXlibSurfaceKHR(ctx->
instance, &createInfo, NULL, &ctx->
surface) != VK_SUCCESS) {
532 fprintf(stderr,
"[Vulkan] Failed to create Xlib surface\n");
536 VkWin32SurfaceCreateInfoKHR createInfo = {
537 .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
541 if (vkCreateWin32SurfaceKHR(ctx->
instance, &createInfo, NULL, &ctx->
surface) != VK_SUCCESS) {
542 fprintf(stderr,
"[Vulkan] Failed to create Win32 surface\n");
547 printf(
"[Vulkan] Surface created successfully\n");
552 uint32_t deviceCount = 0;
553 vkEnumeratePhysicalDevices(ctx->
instance, &deviceCount, NULL);
554 if (deviceCount == 0) {
555 fprintf(stderr,
"[Vulkan] No physical devices found\n");
563 vkEnumeratePhysicalDevices(ctx->
instance, &deviceCount, devices);
565 for (uint32_t i = 0; i < deviceCount; i++) {
566 VkPhysicalDeviceProperties props;
567 vkGetPhysicalDeviceProperties(devices[i], &props);
568 if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
570 printf(
"[Vulkan] Selected Discrete GPU: %s\n", props.deviceName);
577 VkPhysicalDeviceProperties props;
579 printf(
"[Vulkan] Selected GPU: %s\n", props.deviceName);
587 uint32_t queueFamilyCount = 0;
588 vkGetPhysicalDeviceQueueFamilyProperties(ctx->
physicalDevice, &queueFamilyCount, NULL);
591 VkQueueFamilyProperties* queueFamilies =
595 vkGetPhysicalDeviceQueueFamilyProperties(ctx->
physicalDevice, &queueFamilyCount, queueFamilies);
597 int graphicsFamily = -1;
598 for (uint32_t i = 0; i < queueFamilyCount; i++) {
599 VkBool32 presentSupport =
false;
601 if ((queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && presentSupport) {
608 if (graphicsFamily == -1) {
609 fprintf(stderr,
"[Vulkan] No suitable queue family found\n");
614 float queuePriority = 1.0f;
615 VkDeviceQueueCreateInfo queueCreateInfo = {
616 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
619 .pQueuePriorities = &queuePriority,
622 VkPhysicalDeviceFeatures deviceFeatures = {
623 .multiDrawIndirect = VK_TRUE,
624 .shaderInt64 = VK_TRUE,
627 const char* deviceExtensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME,
628 VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
629 VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME };
631 VkPhysicalDeviceVulkan11Features features11 = {
632 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
633 .shaderDrawParameters = VK_TRUE,
636 VkPhysicalDeviceVulkan12Features features12 = {
637 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
638 .pNext = &features11,
639 .bufferDeviceAddress = VK_TRUE,
640 .hostQueryReset = VK_TRUE,
643 VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures = {
644 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
645 .pNext = &features12,
646 .dynamicRendering = VK_TRUE,
649 VkDeviceCreateInfo createInfo = {
650 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
651 .pNext = &dynamicRenderingFeatures,
652 .queueCreateInfoCount = 1,
653 .pQueueCreateInfos = &queueCreateInfo,
654 .pEnabledFeatures = &deviceFeatures,
655 .enabledExtensionCount = 3,
656 .ppEnabledExtensionNames = deviceExtensions,
660 fprintf(stderr,
"[Vulkan] Failed to create logical device\n");
664 volkLoadDeviceTable(&ctx->
vk, ctx->
device);
668 printf(
"[Vulkan] Logical Device created (Dynamic Rendering enabled)\n");
673 VkFormat candidates[] = { VK_FORMAT_D32_SFLOAT,
674 VK_FORMAT_D32_SFLOAT_S8_UINT,
675 VK_FORMAT_D24_UNORM_S8_UINT };
676 for (uint32_t i = 0; i < 3; i++) {
677 VkFormatProperties props;
678 vkGetPhysicalDeviceFormatProperties(ctx->
physicalDevice, candidates[i], &props);
679 if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
691 VkImageCreateInfo imageInfo = {
692 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
693 .imageType = VK_IMAGE_TYPE_2D,
700 .tiling = VK_IMAGE_TILING_OPTIMAL,
701 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
702 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
703 .samples = VK_SAMPLE_COUNT_1_BIT,
704 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
707 if (ctx->
vk.vkCreateImage(ctx->
device, &imageInfo, NULL, &ctx->
depthImage) != VK_SUCCESS)
710 VkMemoryRequirements memRequirements;
713 VkMemoryAllocateInfo allocInfo = {
714 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
715 .allocationSize = memRequirements.size,
718 memRequirements.memoryTypeBits,
719 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
723 if (ctx->
vk.vkAllocateMemory(ctx->
device, &allocInfo, NULL, &ctx->
depthMemory) != VK_SUCCESS)
728 VkImageViewCreateInfo viewInfo = {
729 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
731 .viewType = VK_IMAGE_VIEW_TYPE_2D,
733 .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
748 VkSurfaceCapabilitiesKHR capabilities;
751 VkExtent2D extent = { (uint32_t)w, (uint32_t)h };
752 if (capabilities.currentExtent.width != 0xFFFFFFFF) {
753 extent = capabilities.currentExtent;
756 if (extent.width == 0 || extent.height == 0) {
760 uint32_t formatCount;
762 if (formatCount == 0) {
763 fprintf(stderr,
"[Vulkan] No supported surface formats found\n");
766 VkSurfaceFormatKHR formats[64];
767 if (formatCount > 64)
771 VkSurfaceFormatKHR selectedFormat = formats[0];
772 for (uint32_t i = 0; i < formatCount; i++) {
773 if ((formats[i].format == VK_FORMAT_B8G8R8A8_SRGB ||
774 formats[i].format == VK_FORMAT_R8G8B8A8_SRGB) &&
775 formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
776 selectedFormat = formats[i];
781 uint32_t imageCount = capabilities.minImageCount + 1;
782 if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) {
783 imageCount = capabilities.maxImageCount;
786 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
787 uint32_t presentModeCount;
788 vkGetPhysicalDeviceSurfacePresentModesKHR(
794 if (presentModeCount > 0) {
795 VkPresentModeKHR presentModes[16];
796 if (presentModeCount > 16)
797 presentModeCount = 16;
798 vkGetPhysicalDeviceSurfacePresentModesKHR(
808 bool mailboxSupported =
false;
809 bool immediateSupported =
false;
810 for (uint32_t i = 0; i < presentModeCount; i++) {
811 if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
812 immediateSupported =
true;
813 if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
814 mailboxSupported =
true;
817 if (immediateSupported) {
818 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
819 }
else if (mailboxSupported) {
820 presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
824 VkSwapchainCreateInfoKHR createInfo = {
825 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
827 .minImageCount = imageCount,
828 .imageFormat = selectedFormat.format,
829 .imageColorSpace = selectedFormat.colorSpace,
830 .imageExtent = extent,
831 .imageArrayLayers = 1,
832 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
833 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
834 .preTransform = capabilities.currentTransform,
835 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
836 .presentMode = presentMode,
840 if (ctx->
vk.vkCreateSwapchainKHR(ctx->
device, &createInfo, NULL, &ctx->
swapchain) !=
842 fprintf(stderr,
"[Vulkan] Failed to create swapchain\n");
860 for (uint32_t i = 0; i < ctx->
imageCount; i++) {
861 VkImageViewCreateInfo viewInfo = {
862 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
864 .viewType = VK_IMAGE_VIEW_TYPE_2D,
866 .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
874 "[Vulkan] Swapchain created (%dx%d, %u images, format: %d)\n",
888 VkCommandPoolCreateInfo poolInfo = {
889 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
890 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
893 if (ctx->
vk.vkCreateCommandPool(ctx->
device, &poolInfo, NULL, &ctx->
commandPool) != VK_SUCCESS)
896 VkCommandBufferAllocateInfo allocInfo = {
897 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
899 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
906 VkSemaphoreCreateInfo semInfo = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
907 VkFenceCreateInfo fenceInfo = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
908 .flags = VK_FENCE_CREATE_SIGNALED_BIT };
917 if (ctx->
vk.vkCreateSemaphore(
923 ctx->
vk.vkCreateSemaphore(
938 VkQueryPoolCreateInfo queryPoolInfo = {
939 .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
940 .queryType = VK_QUERY_TYPE_TIMESTAMP,
944 if (ctx->
vk.vkCreateQueryPool(ctx->
device, &queryPoolInfo, NULL, &ctx->
queryPool) !=
951 VkPhysicalDeviceProperties props;
987 if (volkInitialize() != VK_SUCCESS) {
988 fprintf(stderr,
"[Vulkan] Failed to initialize volk\n");
1019 fprintf(stderr,
"[Vulkan] Failed to allocate resource arrays\n");
1044 ctx->
vk.vkDeviceWaitIdle(ctx->
device);
1098 ctx->
vk.vkDestroyDevice(ctx->
device, NULL);
1102 vkDestroyInstance(ctx->
instance, NULL);
1107 ctx->
vk.vkWaitForFences(
1132 VkResult result = ctx->
vk.vkAcquireNextImageKHR(
1143 if (result == VK_ERROR_OUT_OF_DATE_KHR) {
1146 }
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
1152 VkCommandBufferBeginInfo beginInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1157 ctx->
vk.vkCmdResetQueryPool(
1169 ctx->
vk.vkCmdWriteTimestamp(
1171 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1176 VkImageMemoryBarrier barriers[2] = { 0 };
1177 barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1178 barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1179 barriers[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1181 barriers[0].subresourceRange =
1182 (VkImageSubresourceRange){ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1185 barriers[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1187 barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1188 barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1189 barriers[1].newLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
1191 barriers[1].subresourceRange =
1192 (VkImageSubresourceRange){ .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
1195 barriers[1].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1197 ctx->
vk.vkCmdPipelineBarrier(
1199 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1200 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
1210 VkRenderingAttachmentInfo colorAttachment = {
1211 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
1213 .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1214 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1215 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1216 .clearValue = { { { r, g, b, a } } },
1219 VkRenderingAttachmentInfo depthAttachment = {
1220 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
1222 .imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
1223 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1224 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1225 .clearValue = { .depthStencil = { 1.0f, 0 } },
1228 VkRenderingInfo renderingInfo = {
1229 .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
1232 .colorAttachmentCount = 1,
1233 .pColorAttachments = &colorAttachment,
1234 .pDepthAttachment = &depthAttachment,
1243 ctx->
vk.vkCmdWriteTimestamp(
1245 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1252 VkImageMemoryBarrier barrier = {
1253 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1254 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1255 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1257 .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1260 .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1263 ctx->
vk.vkCmdPipelineBarrier(
1265 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1266 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1280 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1286 VkSubmitInfo submitInfo = {
1287 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1288 .waitSemaphoreCount = 1,
1290 .pWaitDstStageMask = waitStages,
1291 .commandBufferCount = 1,
1293 .signalSemaphoreCount = 1,
1294 .pSignalSemaphores = &signalSemaphore,
1299 VkPresentInfoKHR presentInfo = {
1300 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1301 .waitSemaphoreCount = 1,
1302 .pWaitSemaphores = &signalSemaphore,
1303 .swapchainCount = 1,
1307 VkResult result = ctx->
vk.vkQueuePresentKHR(ctx->
graphicsQueue, &presentInfo);
1309 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
1318 if (ctx && ctx->
device) {
1319 ctx->
vk.vkDeviceWaitIdle(ctx->
device);
1344 VkBufferCreateInfo bufferInfo = {
1345 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1352 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
1353 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
1357 if (ctx->
vk.vkCreateBuffer(ctx->
device, &bufferInfo, NULL, &buffer->
handle) != VK_SUCCESS) {
1361 VkMemoryRequirements memRequirements;
1362 ctx->
vk.vkGetBufferMemoryRequirements(ctx->
device, buffer->
handle, &memRequirements);
1366 VkDeviceMemory heapMemory = VK_NULL_HANDLE;
1367 void* heapMappedBase = NULL;
1393 ctx->
vk.vkBindBufferMemory(ctx->
device, buffer->
handle, heapMemory, offset);
1395 buffer->
size = size;
1398 buffer->
mapped = (
char*)heapMappedBase + offset;
1403 if (data && buffer->
mapped) {
1404 memcpy(buffer->
mapped, data, size);
1417 uint32_t index = (uint32_t)handle - 1;
1442 uint32_t index = (uint32_t)handle - 1;
1446 ctx->
vk.vkCmdFillBuffer(
1449 (VkDeviceSize)offset,
1466 uint32_t index = (uint32_t)handle - 1;
1498 uint32_t index = (uint32_t)handle - 1;
1502 VkBufferDeviceAddressInfo info = {
1503 .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
1507 return ctx->
vk.vkGetBufferDeviceAddress(ctx->
device, &info);
1513 const uint32_t* bytecode,
1524 VkShaderModuleCreateInfo createInfo = {
1525 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
1543 uint32_t index = (uint32_t)handle - 1;
1560 VkPipelineShaderStageCreateInfo shaderStages[2] = { 0 };
1564 fprintf(stderr,
"[Vulkan] Invalid vertex shader handle\n");
1569 fprintf(stderr,
"[Vulkan] Invalid vertex shader stage or inactive shader\n");
1572 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1573 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
1575 shaderStages[0].pName =
"main";
1579 fprintf(stderr,
"[Vulkan] Invalid fragment shader handle\n");
1584 fprintf(stderr,
"[Vulkan] Invalid fragment shader stage or inactive shader\n");
1587 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1588 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1590 shaderStages[1].pName =
"main";
1592 VkVertexInputBindingDescription bindingDescription = {
1595 .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
1601 VkVertexInputAttributeDescription,
1608 attributeDescriptions[i].binding = 0;
1610 attributeDescriptions[i].format =
1615 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
1616 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1617 .vertexBindingDescriptionCount = 1,
1618 .pVertexBindingDescriptions = &bindingDescription,
1620 .pVertexAttributeDescriptions = attributeDescriptions,
1623 VkPipelineInputAssemblyStateCreateInfo inputAssembly = {
1624 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
1625 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1626 .primitiveRestartEnable = VK_FALSE,
1629 VkPipelineViewportStateCreateInfo viewportState = {
1630 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
1635 VkPipelineRasterizationStateCreateInfo rasterizer = {
1636 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
1637 .depthClampEnable = VK_FALSE,
1638 .rasterizerDiscardEnable = VK_FALSE,
1639 .polygonMode = VK_POLYGON_MODE_FILL,
1641 .cullMode = VK_CULL_MODE_BACK_BIT,
1642 .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
1643 .depthBiasEnable = VK_FALSE,
1646 VkPipelineMultisampleStateCreateInfo multisampling = {
1647 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
1648 .sampleShadingEnable = VK_FALSE,
1649 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
1652 VkPipelineDepthStencilStateCreateInfo depthStencil = {
1653 .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
1654 .depthTestEnable = VK_TRUE,
1655 .depthWriteEnable = VK_TRUE,
1656 .depthCompareOp = VK_COMPARE_OP_LESS,
1657 .depthBoundsTestEnable = VK_FALSE,
1658 .stencilTestEnable = VK_FALSE,
1661 VkPipelineColorBlendAttachmentState colorBlendAttachment = {
1662 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
1663 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
1667 .colorBlendOp = VK_BLEND_OP_ADD,
1668 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
1669 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
1670 .alphaBlendOp = VK_BLEND_OP_ADD,
1673 VkPipelineColorBlendStateCreateInfo colorBlending = {
1674 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
1675 .logicOpEnable = VK_FALSE,
1676 .attachmentCount = 1,
1677 .pAttachments = &colorBlendAttachment,
1680 VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
1681 VkPipelineDynamicStateCreateInfo dynamicState = {
1682 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
1683 .dynamicStateCount = 2,
1684 .pDynamicStates = dynamicStates,
1687 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
1688 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1691 VkPushConstantRange pushConstantRange = {
1692 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
1696 pipelineLayoutInfo.pushConstantRangeCount = 1;
1697 pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
1699 if (ctx->
vk.vkCreatePipelineLayout(
1701 &pipelineLayoutInfo,
1709 VkPipelineRenderingCreateInfo renderingCreateInfo = {
1710 .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
1711 .colorAttachmentCount = 1,
1716 VkGraphicsPipelineCreateInfo pipelineInfo = {
1717 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1718 .pNext = &renderingCreateInfo,
1720 .pStages = shaderStages,
1721 .pVertexInputState = &vertexInputInfo,
1722 .pInputAssemblyState = &inputAssembly,
1723 .pViewportState = &viewportState,
1724 .pRasterizationState = &rasterizer,
1725 .pMultisampleState = &multisampling,
1726 .pDepthStencilState = &depthStencil,
1727 .pColorBlendState = &colorBlending,
1728 .pDynamicState = &dynamicState,
1730 .renderPass = VK_NULL_HANDLE,
1734 if (ctx->
vk.vkCreateGraphicsPipelines(
1755 uint32_t index = (uint32_t)handle - 1;
1776 fprintf(stderr,
"[Vulkan] Invalid compute shader handle\n");
1779 uint32_t shaderIndex = handle - 1;
1781 fprintf(stderr,
"[Vulkan] Invalid compute shader stage or inactive shader\n");
1785 VkPipelineShaderStageCreateInfo stageInfo = {
1786 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
1787 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
1792 VkPipelineLayoutCreateInfo layoutInfo = {
1793 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1798 VkPushConstantRange pushConstantRange = {
1799 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
1803 layoutInfo.pushConstantRangeCount = 1;
1804 layoutInfo.pPushConstantRanges = &pushConstantRange;
1806 if (ctx->
vk.vkCreatePipelineLayout(
1815 VkComputePipelineCreateInfo pipelineInfo = {
1816 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1821 if (ctx->
vk.vkCreateComputePipelines(
1842 uint32_t index = (uint32_t)handle - 1;
1858 uint32_t index = (uint32_t)handle - 1;
1862 ctx->
vk.vkCmdBindPipeline(
1864 VK_PIPELINE_BIND_POINT_COMPUTE,
1879 VkMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER };
1880 VkPipelineStageFlags srcStage = 0;
1881 VkPipelineStageFlags dstStage = 0;
1887 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
1888 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1889 srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
1890 dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1894 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
1895 barrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
1896 srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1897 dstStage = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
1901 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
1902 barrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
1903 srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1904 dstStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
1908 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
1909 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1910 srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
1911 dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1915 barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
1916 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1917 srcStage = VK_PIPELINE_STAGE_HOST_BIT;
1918 dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1922 barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
1923 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
1924 srcStage = VK_PIPELINE_STAGE_HOST_BIT;
1925 dstStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
1929 ctx->
vk.vkCmdPipelineBarrier(
1946 uint32_t index = (uint32_t)handle - 1;
1950 ctx->
vk.vkCmdBindPipeline(
1952 VK_PIPELINE_BIND_POINT_GRAPHICS,
1957 VkViewport viewport = {
1967 VkRect2D scissor = { .offset = { 0, 0 }, .extent = ctx->
swapchainExtent };
1974 uint32_t index = (uint32_t)handle - 1;
1979 VkDeviceSize offsets[] = { 0 };
1980 ctx->
vk.vkCmdBindVertexBuffers(
1988 ctx->
vk.vkCmdBindIndexBuffer(
1992 VK_INDEX_TYPE_UINT32
2003 uint32_t indexCount,
2004 uint32_t firstIndex,
2005 int32_t vertexOffset,
2006 uint32_t instanceCount
2008 ctx->
vk.vkCmdDrawIndexed(
2026 uint32_t index = (uint32_t)handle - 1;
2030 ctx->
vk.vkCmdDrawIndexedIndirect(
2033 (VkDeviceSize)offset,
2046 if (alignment > 0) {
2047 offset = (offset + alignment - 1) & ~(alignment - 1);
2051 fprintf(stderr,
"[Vulkan] Transient buffer overflow for frame %u!\n", frame);
2058 .size = (uint32_t)size,
2077 ctx->
vk.vkCmdPushConstants(
2080 VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
2089 ctx->
vk.vkCmdPushConstants(
2092 VK_SHADER_STAGE_COMPUTE_BIT,
2103 uint64_t results[2] = { 0 };
2104 VkResult res = ctx->
vk.vkGetQueryPoolResults(
2112 VK_QUERY_RESULT_64_BIT
2115 if (res == VK_SUCCESS) {
2116 uint64_t start = results[0];
2117 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