diff options
| author | aura <nw@moneybot.cc> | 2026-07-13 10:15:03 +0200 |
|---|---|---|
| committer | aura <nw@moneybot.cc> | 2026-07-13 10:15:03 +0200 |
| commit | 57d172df4db1451ba3caeeb0ca485d0845a61912 (patch) | |
| tree | ad0be7c8bec79a1eb58b25f2a631bc4b6809e7fd /src/vulkan.cpp | |
push source
Diffstat (limited to 'src/vulkan.cpp')
| -rw-r--r-- | src/vulkan.cpp | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/src/vulkan.cpp b/src/vulkan.cpp new file mode 100644 index 0000000..20fa449 --- /dev/null +++ b/src/vulkan.cpp @@ -0,0 +1,618 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "vulkan.h" +#include "gauges.h" +#include "spv.h" + +pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; + +INSTANCE_DATA g_instances[MAX_INSTANCES]; +DEVICE_DATA * g_devices[MAX_DEVICES]; + +INSTANCE_DATA* vk_find_instance( void* key ) { + for( I32 i = 0; i < MAX_INSTANCES; i++ ) + if( g_instances[i].key == key ) + return &g_instances[i]; + return 0; +} + +DEVICE_DATA* vk_find_device( void* key ) { + for( I32 i = 0; i < MAX_DEVICES; i++ ) + if( g_devices[i] && g_devices[i]->key == key ) + return g_devices[i]; + return 0; +} + +SWAP_DATA* vk_find_swap( DEVICE_DATA* d, VkSwapchainKHR sc ) { + for( I32 i = 0; i < MAX_SWAPS; i++ ) + if( d->swaps[i] && d->swaps[i]->sc == sc ) + return d->swaps[i]; + return 0; +} + +INSTANCE_DATA* vk_instance_register( VkInstance inst, PFN_vkGetInstanceProcAddr gipa ) { + pthread_mutex_lock( &g_lock ); + defer( pthread_mutex_unlock( &g_lock ) ); + + for( I32 i = 0; i < MAX_INSTANCES; i++ ) { + if( g_instances[i].key ) + continue; + + INSTANCE_DATA* id = &g_instances[i]; + id->key = GET_KEY( inst ); + id->instance = inst; + id->gipa = gipa; + id->destroy_instance = ( decltype( id->destroy_instance ) )gipa( inst, "vkDestroyInstance" ); + id->get_memory_properties = ( decltype( id->get_memory_properties ) )gipa( inst, "vkGetPhysicalDeviceMemoryProperties" ); + id->get_queue_family_properties = ( decltype( id->get_queue_family_properties ) )gipa( inst, "vkGetPhysicalDeviceQueueFamilyProperties" ); + return id; + } + return 0; +} + +void vk_instance_forget( VkInstance inst ) { + pthread_mutex_lock( &g_lock ); + defer( pthread_mutex_unlock( &g_lock ) ); + + INSTANCE_DATA* id = vk_find_instance( GET_KEY( inst ) ); + if( id ) + memset( id, 0, sizeof(* id ) ); +} + +void vk_device_register( DEVICE_DATA* d ) { + pthread_mutex_lock( &g_lock ); + defer( pthread_mutex_unlock( &g_lock ) ); + + for( I32 i = 0; i < MAX_DEVICES; i++ ) + if( !g_devices[i] ) { + g_devices[i] = d; + return; + } +} + +void vk_device_unregister( DEVICE_DATA* d ) { + pthread_mutex_lock( &g_lock ); + defer( pthread_mutex_unlock( &g_lock ) ); + + for( I32 i = 0; i < MAX_DEVICES; i++ ) + if( g_devices[i] == d ) + g_devices[i] = 0; +} + +void vk_device_add_queue( DEVICE_DATA* d, VkQueue q, U32 family ) { + pthread_mutex_lock( &g_lock ); + defer( pthread_mutex_unlock( &g_lock ) ); + + if( d->nqueues < MAX_QUEUES ) { + d->queues[d->nqueues].q = q; + d->queues[d->nqueues].family = family; + d->nqueues++; + } +} + +#define RESOLVE( field, name ) \ + d->field = (PFN_##name)gdpa( dev, #name ) + +void vk_resolve_device_procs( DEVICE_DATA* d, VkDevice dev, PFN_vkGetDeviceProcAddr gdpa ) { + RESOLVE( destroy_device, vkDestroyDevice ); + RESOLVE( get_device_queue, vkGetDeviceQueue ); + RESOLVE( get_device_queue2, vkGetDeviceQueue2 ); + RESOLVE( create_swapchain, vkCreateSwapchainKHR ); + RESOLVE( destroy_swapchain, vkDestroySwapchainKHR ); + RESOLVE( get_swapchain_images, vkGetSwapchainImagesKHR ); + RESOLVE( queue_present, vkQueuePresentKHR ); + RESOLVE( queue_submit, vkQueueSubmit ); + RESOLVE( device_wait_idle, vkDeviceWaitIdle ); + RESOLVE( create_image_view, vkCreateImageView ); + RESOLVE( destroy_image_view, vkDestroyImageView ); + RESOLVE( create_render_pass, vkCreateRenderPass ); + RESOLVE( destroy_render_pass, vkDestroyRenderPass ); + RESOLVE( create_framebuffer, vkCreateFramebuffer ); + RESOLVE( destroy_framebuffer, vkDestroyFramebuffer ); + RESOLVE( create_shader_module, vkCreateShaderModule ); + RESOLVE( destroy_shader_module, vkDestroyShaderModule ); + RESOLVE( create_pipeline_layout, vkCreatePipelineLayout ); + RESOLVE( destroy_pipeline_layout, vkDestroyPipelineLayout ); + RESOLVE( create_graphics_pipelines, vkCreateGraphicsPipelines ); + RESOLVE( destroy_pipeline, vkDestroyPipeline ); + RESOLVE( create_command_pool, vkCreateCommandPool ); + RESOLVE( destroy_command_pool, vkDestroyCommandPool ); + RESOLVE( allocate_command_buffers, vkAllocateCommandBuffers ); + RESOLVE( begin_command_buffer, vkBeginCommandBuffer ); + RESOLVE( end_command_buffer, vkEndCommandBuffer ); + RESOLVE( cmd_begin_render_pass, vkCmdBeginRenderPass ); + RESOLVE( cmd_end_render_pass, vkCmdEndRenderPass ); + RESOLVE( cmd_bind_pipeline, vkCmdBindPipeline ); + RESOLVE( cmd_bind_vertex_buffers, vkCmdBindVertexBuffers ); + RESOLVE( cmd_push_constants, vkCmdPushConstants ); + RESOLVE( cmd_set_viewport, vkCmdSetViewport ); + RESOLVE( cmd_set_scissor, vkCmdSetScissor ); + RESOLVE( cmd_draw, vkCmdDraw ); + RESOLVE( create_semaphore, vkCreateSemaphore ); + RESOLVE( destroy_semaphore, vkDestroySemaphore ); + RESOLVE( create_fence, vkCreateFence ); + RESOLVE( destroy_fence, vkDestroyFence ); + RESOLVE( wait_for_fences, vkWaitForFences ); + RESOLVE( reset_fences, vkResetFences ); + RESOLVE( create_buffer, vkCreateBuffer ); + RESOLVE( destroy_buffer, vkDestroyBuffer ); + RESOLVE( get_buffer_memory_requirements, vkGetBufferMemoryRequirements ); + RESOLVE( allocate_memory, vkAllocateMemory ); + RESOLVE( free_memory, vkFreeMemory ); + RESOLVE( bind_buffer_memory, vkBindBufferMemory ); + RESOLVE( map_memory, vkMapMemory ); + RESOLVE( unmap_memory, vkUnmapMemory ); +} + + +STAT vk_swap_create_render_pass( DEVICE_DATA* d, SWAP_DATA* s ) { + VkAttachmentDescription att = { + .format = s->fmt, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + }; + VkAttachmentReference ref = { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + VkSubpassDescription sub = { + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &ref, + }; + VkRenderPassCreateInfo rpci = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &att, + .subpassCount = 1, + .pSubpasses = &sub, + }; + if( d->create_render_pass( d->dev, &rpci, 0, &s->rp ) != VK_SUCCESS ) + return STAT_ERR; + return STAT_OK; +} + +STAT vk_swap_create_framebuffers( DEVICE_DATA* d, SWAP_DATA* s ) { + for( U32 i = 0; i < s->nimages; i++ ) { + VkImageViewCreateInfo vci = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = s->imgs[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = s->fmt, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + }, + }; + if( d->create_image_view( d->dev, &vci, 0, &s->views[i] ) != VK_SUCCESS ) + return STAT_ERR; + + VkFramebufferCreateInfo fci = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = s->rp, + .attachmentCount = 1, + .pAttachments = &s->views[i], + .width = s->extent.width, + .height = s->extent.height, + .layers = 1, + }; + if( d->create_framebuffer( d->dev, &fci, 0, &s->fbs[i] ) != VK_SUCCESS ) + return STAT_ERR; + } + return STAT_OK; +} + +STAT vk_swap_create_shaders( DEVICE_DATA* d, SWAP_DATA* s ) { + VkShaderModuleCreateInfo smci = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = gauge_vert_spv_len, + .pCode = (const U32*)gauge_vert_spv, + }; + if( d->create_shader_module( d->dev, &smci, 0, &s->vs ) != VK_SUCCESS ) + return STAT_ERR; + + smci.codeSize = gauge_frag_spv_len; + smci.pCode = (const U32*)gauge_frag_spv; + if( d->create_shader_module( d->dev, &smci, 0, &s->fs ) != VK_SUCCESS ) + return STAT_ERR; + + VkPushConstantRange pcr = { + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .offset = 0, + .size = 2 * sizeof(F32), + }; + VkPipelineLayoutCreateInfo plci = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pushConstantRangeCount = 1, + .pPushConstantRanges = &pcr, + }; + if( d->create_pipeline_layout( d->dev, &plci, 0, &s->pl ) != VK_SUCCESS ) + return STAT_ERR; + return STAT_OK; +} + +// jesus fucking christ +STAT vk_swap_create_pipeline( DEVICE_DATA* d, SWAP_DATA* s ) { + VkPipelineShaderStageCreateInfo stages[2] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = s->vs, + .pName = "main" + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = s->fs, + .pName = "main" + }, + }; + + VkVertexInputBindingDescription bind = { + .binding = 0, + .stride = sizeof( VERTEX ), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }; + VkVertexInputAttributeDescription attrs[2] = { + { + .location = 0, .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, .offset = 0 + }, + { + .location = 1, .binding = 0, + .format = VK_FORMAT_R8G8B8A8_UNORM, .offset = 8 + }, + }; + VkPipelineVertexInputStateCreateInfo vin = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &bind, + .vertexAttributeDescriptionCount = 2, + .pVertexAttributeDescriptions = attrs, + }; + VkPipelineInputAssemblyStateCreateInfo ia = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + }; + VkPipelineViewportStateCreateInfo vp = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .scissorCount = 1, + }; + VkPipelineRasterizationStateCreateInfo rs = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .lineWidth = 1.0f, + }; + VkPipelineMultisampleStateCreateInfo ms = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + }; + VkPipelineColorBlendAttachmentState ba = { + .blendEnable = VK_TRUE, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT, + }; + VkPipelineColorBlendStateCreateInfo cb = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &ba, + }; + VkDynamicState dyns[2] = { + VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, + }; + VkPipelineDynamicStateCreateInfo dyn = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = 2, + .pDynamicStates = dyns, + }; + VkGraphicsPipelineCreateInfo gpci = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = stages, + .pVertexInputState = &vin, + .pInputAssemblyState = &ia, + .pViewportState = &vp, + .pRasterizationState = &rs, + .pMultisampleState = &ms, + .pColorBlendState = &cb, + .pDynamicState = &dyn, + .layout = s->pl, + .renderPass = s->rp, + }; + if( d->create_graphics_pipelines( d->dev, VK_NULL_HANDLE, 1, &gpci, 0, &s->pipe ) != VK_SUCCESS ) + return STAT_ERR; + return STAT_OK; +} + +U32 find_memory_type( DEVICE_DATA* d, U32 bits, VkMemoryPropertyFlags want ) { + VkPhysicalDeviceMemoryProperties mp; + d->inst->get_memory_properties( d->phys, &mp ); + for( U32 m = 0; m < mp.memoryTypeCount; m++ ) + if( ( bits & ( 1u << m ) ) && + ( mp.memoryTypes[m].propertyFlags & want ) == want ) + return m; + return UINT32_MAX; +} + +STAT vk_swap_create_vbuffers( DEVICE_DATA* d, SWAP_DATA* s ) { + for( U32 i = 0; i < s->nimages; i++ ) { + VkBufferCreateInfo bci = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = MAX_VERTS * sizeof(VERTEX), + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + if( d->create_buffer( d->dev, &bci, 0, &s->vbufs[i] ) != VK_SUCCESS ) + return STAT_ERR; + + VkMemoryRequirements mr; + d->get_buffer_memory_requirements( d->dev, s->vbufs[i], &mr ); + U32 type = find_memory_type( + d, mr.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + ); + + if( type == UINT32_MAX ) + return STAT_ERR; + + VkMemoryAllocateInfo mai = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = mr.size, + .memoryTypeIndex = type, + }; + if( d->allocate_memory( d->dev, &mai, 0, &s->vmems[i] ) != VK_SUCCESS ) + return STAT_ERR; + if( d->bind_buffer_memory( d->dev, s->vbufs[i], s->vmems[i], 0 ) + != VK_SUCCESS ) + return STAT_ERR; + if( d->map_memory( d->dev, s->vmems[i], 0, VK_WHOLE_SIZE, 0, + &s->vmaps[i] ) != VK_SUCCESS ) + return STAT_ERR; + } + return STAT_OK; +} + +STAT vk_swap_create_sync( DEVICE_DATA* d, SWAP_DATA* s ) { + for( U32 i = 0; i < s->nimages; i++ ) { + VkSemaphoreCreateInfo sci = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + }; + if( d->create_semaphore( d->dev, &sci, 0, &s->sems[i] ) != VK_SUCCESS ) + return STAT_ERR; + + VkFenceCreateInfo fci = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, + }; + if( d->create_fence( d->dev, &fci, 0, &s->fences[i] ) != VK_SUCCESS ) + return STAT_ERR; + } + return STAT_OK; +} + +STAT swap_build_static( DEVICE_DATA* d, SWAP_DATA* s ) { + if( !OK( vk_swap_create_render_pass( d, s ) ) ) return STAT_ERR; + if( !OK( vk_swap_create_framebuffers( d, s ) ) ) return STAT_ERR; + if( !OK( vk_swap_create_shaders( d, s ) ) ) return STAT_ERR; + if( !OK( vk_swap_create_pipeline( d, s ) ) ) return STAT_ERR; + if( !OK( vk_swap_create_vbuffers( d, s ) ) ) return STAT_ERR; + if( !OK( vk_swap_create_sync( d, s ) ) ) return STAT_ERR; + return STAT_OK; +} + +SWAP_DATA* vk_swap_create( + DEVICE_DATA* d, + VkSwapchainKHR sc, + const VkSwapchainCreateInfoKHR* ci +) { + pthread_mutex_lock( &g_lock ); + defer( pthread_mutex_unlock( &g_lock ) ); + + SWAP_DATA* s = (SWAP_DATA*)calloc( 1, sizeof( SWAP_DATA ) ); + s->sc = sc; + s->fmt = ci->imageFormat; + s->extent = ci->imageExtent; + + U32 n = 0; + d->get_swapchain_images( d->dev, sc, &n, 0 ); + if( n > MAX_IMAGES ) + n = MAX_IMAGES; + s->nimages = n; + d->get_swapchain_images( d->dev, sc, &n, s->imgs ); + + if( !OK( swap_build_static( d, s ) ) ) { + dlog( "fhvkov: swapchain setup failed, overlay disabled for this swapchain\n" ); + s->broken = 1; + } + + for( I32 i = 0; i < MAX_SWAPS; i++ ) + if( !d->swaps[i] ) { + d->swaps[i] = s; + return s; + } + + vk_swap_destroy( d, s ); + return 0; +} + +STAT vk_swap_setup_frames( DEVICE_DATA* d, SWAP_DATA* s, VkQueue q ) { + U32 family = UINT32_MAX; + for( I32 i = 0; i < d->nqueues; i++ ) + if( d->queues[i].q == q ) { + family = d->queues[i].family; + break; + } + if( family == UINT32_MAX ) { + if( !d->warned_family ) { + dlog( "fhvkov: present queue family unknown, overlay disabled\n" ); + d->warned_family = 1; + } + return STAT_ERR; + } + + U32 nfam = 0; + d->inst->get_queue_family_properties( d->phys, &nfam, 0 ); + VkQueueFamilyProperties fam[16]; + if( nfam > 16 ) + nfam = 16; + d->inst->get_queue_family_properties( d->phys, &nfam, fam ); + if( family >= nfam || !(fam[family].queueFlags & VK_QUEUE_GRAPHICS_BIT) ) { + dlog( "fhvkov: present queue not graphics-capable, overlay disabled\n" ); + return STAT_ERR; + } + + VkCommandPoolCreateInfo cpci = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = family, + }; + if( d->create_command_pool( d->dev, &cpci, 0, &s->pool ) != VK_SUCCESS ) + return STAT_ERR; + + VkCommandBufferAllocateInfo cbai = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = s->pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = s->nimages, + }; + if( d->allocate_command_buffers( d->dev, &cbai, s->cbs ) != VK_SUCCESS ) + return STAT_ERR; + + s->frames_ready = true; + return STAT_OK; +} + +void vk_swap_destroy( DEVICE_DATA* d, SWAP_DATA* s ) { + d->device_wait_idle( d->dev ); + for( U32 i = 0; i < s->nimages; i++ ) { + if( s->vmaps[i] ) d->unmap_memory( d->dev, s->vmems[i] ); + if( s->vbufs[i] ) d->destroy_buffer( d->dev, s->vbufs[i], 0 ); + if( s->vmems[i] ) d->free_memory( d->dev, s->vmems[i], 0 ); + if( s->sems[i] ) d->destroy_semaphore( d->dev, s->sems[i], 0 ); + if( s->fences[i] ) d->destroy_fence( d->dev, s->fences[i], 0 ); + if( s->fbs[i] ) d->destroy_framebuffer( d->dev, s->fbs[i], 0 ); + if( s->views[i] ) d->destroy_image_view( d->dev, s->views[i], 0 ); + } + if( s->pool ) d->destroy_command_pool( d->dev, s->pool, 0 ); + if( s->pipe ) d->destroy_pipeline( d->dev, s->pipe, 0 ); + if( s->pl ) d->destroy_pipeline_layout( d->dev, s->pl, 0 ); + if( s->vs ) d->destroy_shader_module( d->dev, s->vs, 0 ); + if( s->fs ) d->destroy_shader_module( d->dev, s->fs, 0 ); + if( s->rp ) d->destroy_render_pass( d->dev, s->rp, 0 ); + free( s ); +} + +void vk_swap_forget( DEVICE_DATA* d, VkSwapchainKHR sc ) { + pthread_mutex_lock( &g_lock ); + defer( pthread_mutex_unlock( &g_lock ) ); + + for( I32 i = 0; i < MAX_SWAPS; i++ ) + if( d->swaps[i] && d->swaps[i]->sc == sc ) { + vk_swap_destroy( d, d->swaps[i] ); + d->swaps[i] = 0; + return; + } +} + +void vk_draw( DEVICE_DATA* d, SWAP_DATA* s, U32 idx ) { + VkCommandBuffer cb = s->cbs[idx]; + F32 w = (F32)s->extent.width, h = (F32)s->extent.height; + + VkCommandBufferBeginInfo bi = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + d->begin_command_buffer( cb, &bi ); + + VkRenderPassBeginInfo rbi = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = s->rp, + .framebuffer = s->fbs[idx], + .renderArea = { .extent = s->extent }, + }; + d->cmd_begin_render_pass( cb, &rbi, VK_SUBPASS_CONTENTS_INLINE ); + d->cmd_bind_pipeline( cb, VK_PIPELINE_BIND_POINT_GRAPHICS, s->pipe ); + + VkViewport vp = { 0.0f, 0.0f, w, h, 0.0f, 1.0f }; + d->cmd_set_viewport( cb, 0, 1, &vp ); + VkRect2D sc = { { 0, 0 }, s->extent }; + d->cmd_set_scissor( cb, 0, 1, &sc ); + + VkDeviceSize zero = 0; + d->cmd_bind_vertex_buffers( cb, 0, 1, &s->vbufs[idx], &zero ); + + F32 pc[2] = { 2.0f / w, 2.0f / h }; + d->cmd_push_constants( cb, s->pl, VK_SHADER_STAGE_VERTEX_BIT, 0, + sizeof( pc ), pc ); + + d->cmd_draw( cb, (U32)d->gauge.nverts, 1, 0, 0 ); + d->cmd_end_render_pass( cb ); + d->end_command_buffer( cb ); +} + +VkResult vk_present( + DEVICE_DATA* d, + SWAP_DATA* s, + VkQueue q, + const VkPresentInfoKHR* pi +) { + U32 idx = pi->pImageIndices[0]; + if( idx >= s->nimages ) + return d->queue_present( q, pi ); + + d->wait_for_fences( d->dev, 1, &s->fences[idx], VK_TRUE, UINT64_MAX ); + d->reset_fences( d->dev, 1, &s->fences[idx] ); + + overlay_build_cluster( d->overlay, &d->gauge, (F32)s->extent.width, (F32)s->extent.height, t_nows() ); + memcpy( s->vmaps[idx], d->gauge.verts, (PTR)d->gauge.nverts * sizeof( VERTEX ) ); + vk_draw( d, s, idx ); + + U32 nwait = pi->waitSemaphoreCount; + if( nwait > MAX_WAIT_SEMS ) + nwait = MAX_WAIT_SEMS; + VkPipelineStageFlags stages[MAX_WAIT_SEMS]; + for( U32 i = 0; i < nwait; i++ ) + stages[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + + VkSubmitInfo si = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = nwait, + .pWaitSemaphores = pi->pWaitSemaphores, + .pWaitDstStageMask = stages, + .commandBufferCount = 1, + .pCommandBuffers = &s->cbs[idx], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &s->sems[idx], + }; + + if( d->queue_submit( q, 1, &si, s->fences[idx] ) != VK_SUCCESS ) { + s->broken = true; + return d->queue_present( q, pi ); + } + + VkPresentInfoKHR pi2 = *pi; + pi2.waitSemaphoreCount = 1; + pi2.pWaitSemaphores = &s->sems[idx]; + + return d->queue_present( q, &pi2 ); +} |
