vulkan.c (104673B)
1 /* See LICENSE for license details. */ 2 // TODO(rnp) 3 // [ ]: what is needed for HDR? I think it makes sense to just default to it nowadays 4 // [ ]: once opengl is removed switch images to SRGB and/or 16 bit Float 5 // [ ]: VK_KHR_robustness2 probably shouldn't be required but it also might not matter 6 7 #include "beamformer_internal.h" 8 #include "vulkan.h" 9 #include "external/glslang/glslang/Include/glslang_c_interface.h" 10 11 #define ForceSingleQueue (0) 12 13 #define glslang_info(s) str8("[glslang] " s) 14 #define vulkan_info(s) str8("[vulkan] " s) 15 16 #define ValidVulkanHandle(h) ((h).value[0] != 0) 17 18 #define MaxCommandBuffersInFlight BeamformerMaxRawDataFramesInFlight 19 #define MaxCommandBufferTimestamps (1024) 20 21 typedef enum { 22 VulkanQueueKind_Graphics, 23 VulkanQueueKind_Compute, 24 VulkanQueueKind_Transfer, 25 VulkanQueueKind_Count, 26 } VulkanQueueKind; 27 28 typedef enum { 29 VulkanMemoryKind_Device, 30 VulkanMemoryKind_BAR, 31 VulkanMemoryKind_Host, 32 VulkanMemoryKind_Count, 33 } VulkanMemoryKind; 34 35 typedef struct { 36 VkDeviceMemory memory; 37 VkBuffer buffer; 38 u64 memory_size; 39 40 void * host_pointer; 41 42 VulkanMemoryKind memory_kind; 43 44 // NOTE: only used when the buffer is backing a VulkanRenderModel. 45 VkIndexType index_type; 46 } VulkanBuffer; 47 48 typedef struct { 49 VkDeviceMemory memory; 50 VkImage image; 51 VkImageView view; 52 } VulkanImage; 53 54 typedef struct { 55 VkPipeline pipeline; 56 VkPipelineLayout layout; 57 VkShaderStageFlags stage_flags; 58 } VulkanPipeline; 59 60 typedef struct { 61 VkSemaphore semaphore; 62 u64 value; 63 } VulkanSemaphore; 64 65 typedef struct { 66 VulkanTimeline timeline; 67 u32 buffer_index; 68 69 // NOTE(rnp): since there may not be QueueKind_Count queues, when putting values into this 70 // array you must be careful to map through the queue_indices array in the vulkan_context. 71 u64 in_flight_wait_values[VulkanQueueKind_Count]; 72 } VulkanCommandBuffer; 73 74 typedef enum { 75 VulkanEntityKind_Buffer, 76 VulkanEntityKind_CommandBuffer, 77 VulkanEntityKind_Image, 78 VulkanEntityKind_Pipeline, 79 VulkanEntityKind_RenderModel, 80 VulkanEntityKind_Semaphore, 81 } VulkanEntityKind; 82 83 typedef struct VulkanEntity VulkanEntity; 84 struct VulkanEntity { 85 VulkanEntity * next; 86 VulkanEntityKind kind; 87 union { 88 VulkanBuffer buffer; 89 VulkanCommandBuffer command_buffer; 90 VulkanImage image; 91 VulkanPipeline pipeline; 92 VulkanSemaphore semaphore; 93 } as; 94 }; 95 96 typedef alignas(64) struct { 97 i32 lock; 98 99 u16 queue_family; 100 u16 queue_index; 101 VkQueue queue; 102 103 VulkanSemaphore timeline_semaphore; 104 105 VkPipelineStageFlags2 pipeline_stage_flags; 106 } VulkanQueue; 107 static_assert(alignof(VulkanQueue) == 64, "VulkanQueue must be placed on its own cacheline"); 108 109 typedef alignas(64) struct { 110 i32 lock; 111 u32 next_index; 112 113 VulkanPipeline *bound_pipeline; 114 115 VkCommandPool handle; 116 VkQueryPool query_pool; 117 VkCommandBuffer buffers[MaxCommandBuffersInFlight]; 118 119 u64 submission_values[MaxCommandBuffersInFlight]; 120 u32 queries_occupied[MaxCommandBuffersInFlight]; 121 } VulkanCommandPool; 122 123 typedef struct { 124 Arena *arena; 125 i32 arena_lock; 126 127 VkInstance handle; 128 VkDevice device; 129 VkPhysicalDevice physical_device; 130 131 VkDescriptorPool descriptor_pool; 132 VkDescriptorSetLayout descriptor_set_layouts[BeamformerShaderResourceKind_Count]; 133 VkDescriptorSet descriptor_sets[BeamformerShaderResourceKind_Count]; 134 // NOTE(rnp): must store these if we want to allow partial updates easily 135 VkDescriptorBufferInfo descriptor_buffer_infos[BeamformerShaderBufferSlot_Count]; 136 137 // NOTE(rnp): fallback for when a shader fails to compile 138 VulkanPipeline default_compute_pipeline; 139 VulkanPipeline default_graphics_pipeline; 140 141 GPUInfo gpu_info; 142 143 struct { 144 u64 max_allocation_size; 145 u64 non_coherent_atom_size; 146 u8 gpu_heap_index; 147 i8 memory_type_indices[VulkanMemoryKind_Count]; 148 b8 memory_host_coherent[VulkanMemoryKind_Count]; 149 static_assert(VK_MAX_MEMORY_HEAPS < I8_MAX, ""); 150 static_assert(VK_MAX_MEMORY_TYPES < U8_MAX, ""); 151 } memory_info; 152 153 VulkanCommandPool * command_pools[VulkanTimeline_Count]; 154 VulkanQueue * queues[VulkanQueueKind_Count]; 155 // NOTE(rnp): there are a few places in the code where simply going through the queues map 156 // is not sufficient. those places need to know of the unique queues which unique queue 157 // is being referred to. that code uses this map instead. 158 u16 queue_indices[VulkanQueueKind_Count]; 159 u16 unique_queues; 160 161 VkFormat swap_chain_image_format; 162 VkFormat depth_stencil_format; 163 164 VulkanEntity *entity_freelist; 165 Arena *entity_arena; 166 i32 entity_lock; 167 } VulkanContext; 168 169 read_only global const char *vk_required_instance_extensions[] = { 170 }; 171 172 #if OS_WINDOWS 173 #define VK_OS_REQUIRED_DEVICE_EXTENSIONS_LIST \ 174 X("VK_KHR_external_memory_win32") \ 175 X("VK_KHR_external_semaphore_win32") \ 176 177 #else 178 #define VK_OS_REQUIRED_DEVICE_EXTENSIONS_LIST \ 179 X("VK_KHR_external_memory_fd") \ 180 X("VK_KHR_external_semaphore_fd") \ 181 182 #endif 183 184 #define VK_REQUIRED_DEVICE_EXTENSIONS_LIST \ 185 X("VK_KHR_16bit_storage") \ 186 X("VK_KHR_external_memory") \ 187 X("VK_KHR_external_semaphore") \ 188 X("VK_KHR_robustness2") \ 189 X("VK_KHR_storage_buffer_storage_class") \ 190 X("VK_KHR_timeline_semaphore") \ 191 VK_OS_REQUIRED_DEVICE_EXTENSIONS_LIST 192 193 #define X(str) str8_comp(str), 194 read_only global str8 vk_required_device_extensions[] = {VK_REQUIRED_DEVICE_EXTENSIONS_LIST}; 195 #undef X 196 197 #define VK_OPTIONAL_DEVICE_EXTENSIONS_LIST \ 198 X(VK_KHR, cooperative_matrix) \ 199 200 #define X(p, s, ...) str8_comp(#p "_" #s), 201 read_only global str8 vk_optional_device_extensions[] = {VK_OPTIONAL_DEVICE_EXTENSIONS_LIST}; 202 #undef X 203 204 #define VK_REQUIRED_PHYSICAL_FEATURES \ 205 X(shaderInt16) \ 206 X(shaderInt64) \ 207 208 #define VK_REQUIRED_PHYSICAL_11_FEATURES \ 209 X(storageBuffer16BitAccess) \ 210 211 #define VK_REQUIRED_PHYSICAL_12_FEATURES \ 212 X(bufferDeviceAddress) \ 213 X(shaderFloat16) \ 214 X(timelineSemaphore) \ 215 X(vulkanMemoryModel) \ 216 217 #define VK_REQUIRED_PHYSICAL_13_FEATURES \ 218 X(dynamicRendering) \ 219 X(synchronization2) \ 220 221 #define VK_DEBUG_EXTENSIONS \ 222 X(VK_KHR, shader_non_semantic_info) \ 223 X(VK_KHR, shader_relaxed_extended_instruction) \ 224 225 #define X(p, s, ...) str8_comp(#p "_" #s), 226 read_only global str8 vk_debug_extensions[] = {VK_DEBUG_EXTENSIONS}; 227 #undef X 228 229 #define VK_INSTANCE_DEBUG_EXTENSIONS_LIST \ 230 X(VK_EXT, debug_utils) \ 231 232 #define X(p, s, ...) str8_comp(#p "_" #s), 233 read_only global str8 vk_instance_debug_extensions[] = {VK_INSTANCE_DEBUG_EXTENSIONS_LIST}; 234 #undef X 235 236 #if BEAMFORMER_DEBUG 237 #define VK_VALIDATION_LAYERS_LIST \ 238 X(KHRONOS, validation) \ 239 240 #else 241 #define VK_VALIDATION_LAYERS_LIST 242 #endif 243 244 read_only global str8 vk_validation_layers[] = { 245 #define X(vendor, name, ...) str8_comp("VK_LAYER_" #vendor "_" #name), 246 VK_VALIDATION_LAYERS_LIST 247 #undef X 248 }; 249 250 global struct { 251 u32 driver_api_version; 252 union { 253 struct { 254 #define X(_, name, ...) b8 name; 255 VK_OPTIONAL_DEVICE_EXTENSIONS_LIST 256 #undef X 257 }; 258 b8 E[countof(vk_optional_device_extensions)]; 259 } optional; 260 261 union { 262 struct { 263 #define X(_, name, ...) b8 name; 264 VK_DEBUG_EXTENSIONS 265 #undef X 266 }; 267 b8 E[countof(vk_debug_extensions)]; 268 } debug; 269 270 union { 271 struct { 272 #define X(_, name, ...) b8 name; 273 VK_INSTANCE_DEBUG_EXTENSIONS_LIST 274 #undef X 275 }; 276 b8 E[countof(vk_instance_debug_extensions)]; 277 } instance; 278 279 #if BEAMFORMER_DEBUG 280 struct { 281 union { 282 struct { 283 #define X(_, name, ...) b8 name; 284 VK_VALIDATION_LAYERS_LIST 285 #undef X 286 }; 287 b8 E[countof(vk_validation_layers)]; 288 } enabled; 289 290 union { 291 struct { 292 #define X(_, name, ...) u32 name; 293 VK_VALIDATION_LAYERS_LIST 294 #undef X 295 }; 296 u32 E[countof(vk_validation_layers)]; 297 } version; 298 } layers; 299 #endif 300 } vulkan_config; 301 302 #define MAX_ENABLED_EXTENSIONS ( countof(vk_required_device_extensions) \ 303 + countof(vk_optional_device_extensions) \ 304 + countof(vk_debug_extensions) \ 305 ) 306 307 global VulkanContext vulkan_context[1]; 308 309 /* NOTE(rnp): the idea here is to set reasonable development constraints. 310 * They should probably not match one to one with the maximums of the dev 311 * machine's hardware. Instead these are here to cause compile time failure 312 * for features which are not expected to work everywhere. */ 313 global glslang_resource_t glslc_resource_constraints[1] = {{ 314 .max_compute_work_group_count_x = 65535, 315 .max_compute_work_group_count_y = 65535, 316 .max_compute_work_group_count_z = 65535, 317 .max_compute_work_group_size_x = 1024, 318 .max_compute_work_group_size_y = 1024, 319 .max_compute_work_group_size_z = 1024, 320 321 // NOTE: taken from glslang defaults 322 .max_lights = 32, 323 .max_clip_planes = 6, 324 .max_texture_units = 32, 325 .max_texture_coords = 32, 326 .max_vertex_attribs = 64, 327 .max_vertex_uniform_components = 4096, 328 .max_varying_floats = 64, 329 .max_vertex_texture_image_units = 32, 330 .max_combined_texture_image_units = 80, 331 .max_texture_image_units = 32, 332 .max_fragment_uniform_components = 4096, 333 .max_draw_buffers = 32, 334 .max_vertex_uniform_vectors = 128, 335 .max_varying_vectors = 8, 336 .max_fragment_uniform_vectors = 16, 337 .max_vertex_output_vectors = 16, 338 .max_fragment_input_vectors = 15, 339 .min_program_texel_offset = -8, 340 .max_program_texel_offset = 7, 341 .max_clip_distances = 8, 342 .max_compute_uniform_components = 1024, 343 .max_compute_texture_image_units = 16, 344 .max_compute_image_uniforms = 8, 345 .max_compute_atomic_counters = 8, 346 .max_compute_atomic_counter_buffers = 1, 347 .max_varying_components = 60, 348 .max_vertex_output_components = 64, 349 .max_fragment_input_components = 128, 350 .max_image_units = 8, 351 .max_combined_image_units_and_fragment_outputs = 8, 352 .max_combined_shader_output_resources = 8, 353 .max_image_samples = 0, 354 .max_vertex_image_uniforms = 0, 355 .max_fragment_image_uniforms = 8, 356 .max_combined_image_uniforms = 8, 357 .max_viewports = 16, 358 .max_vertex_atomic_counters = 0, 359 .max_fragment_atomic_counters = 8, 360 .max_combined_atomic_counters = 8, 361 .max_atomic_counter_bindings = 1, 362 .max_vertex_atomic_counter_buffers = 0, 363 .max_fragment_atomic_counter_buffers = 1, 364 .max_combined_atomic_counter_buffers = 1, 365 .max_atomic_counter_buffer_size = 16384, 366 .max_transform_feedback_buffers = 4, 367 .max_transform_feedback_interleaved_components = 64, 368 .max_cull_distances = 8, 369 .max_combined_clip_and_cull_distances = 8, 370 .max_samples = 4, 371 .max_mesh_output_vertices_ext = 256, 372 .max_mesh_output_primitives_ext = 256, 373 .max_mesh_work_group_size_x_ext = 128, 374 .max_mesh_work_group_size_y_ext = 128, 375 .max_mesh_work_group_size_z_ext = 128, 376 .max_task_work_group_size_x_ext = 128, 377 .max_task_work_group_size_y_ext = 128, 378 .max_task_work_group_size_z_ext = 128, 379 .max_mesh_view_count_ext = 4, 380 .max_dual_source_draw_buffers_ext = 1, 381 382 .limits = { 383 .non_inductive_for_loops = 1, 384 .while_loops = 1, 385 .do_while_loops = 1, 386 .general_uniform_indexing = 1, 387 .general_attribute_matrix_vector_indexing = 1, 388 .general_varying_indexing = 1, 389 .general_sampler_indexing = 1, 390 .general_variable_indexing = 1, 391 .general_constant_matrix_vector_indexing = 1, 392 }, 393 }}; 394 395 #if BEAMFORMER_RENDERDOC_HOOKS 396 DEBUG_IMPORT void * 397 vk_renderdoc_instance_handle(void) 398 { 399 return *((void **)vulkan_context->handle); 400 } 401 #endif 402 403 #if BEAMFORMER_DEBUG 404 #define vk_label_object(k, h, label, extra) vk_label_object_(VK_OBJECT_TYPE_##k, (u64)h, label, extra) 405 function void 406 vk_label_object_(VkObjectType kind, u64 handle, str8 label, str8 extra) 407 { 408 local_persist u8 buffer[1024]; 409 Stream sb = stream_from_buffer(buffer, countof(buffer)); 410 if (vulkan_config.instance.debug_utils && label.length > 0) { 411 stream_append_str8s(&sb, label, str8(" ("), extra, str8(")")); 412 stream_append_byte(&sb, 0); 413 if (!sb.errors) { 414 VkDebugUtilsObjectNameInfoEXT object_name_info = { 415 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 416 .objectType = kind, 417 .objectHandle = handle, 418 .pObjectName = (char *)sb.data, 419 }; 420 vkSetDebugUtilsObjectNameEXT(vulkan_context->device, &object_name_info); 421 } 422 } 423 } 424 #else 425 #define vk_label_object(...) 426 #define vk_label_object_(...) 427 #endif 428 429 function VulkanEntity * 430 vk_entity_allocate(VulkanEntityKind kind) 431 { 432 VulkanEntity *result = 0; 433 DeferLoop(take_lock(&vulkan_context->entity_lock, -1), release_lock(&vulkan_context->entity_lock)) 434 { 435 result = SLLPopFreelist(vulkan_context->entity_freelist); 436 if (!result) result = push_struct_no_zero(vulkan_context->entity_arena, VulkanEntity); 437 } 438 439 zero_struct(result); 440 result->kind = kind; 441 return result; 442 } 443 444 function void 445 vk_entity_release(VulkanEntity *entity) 446 { 447 DeferLoop(take_lock(&vulkan_context->entity_lock, -1), release_lock(&vulkan_context->entity_lock)) 448 { 449 SLLStackPush(vulkan_context->entity_freelist, entity, next); 450 } 451 } 452 453 function void * 454 vk_entity_data(VulkanHandle h, VulkanEntityKind kind) 455 { 456 VulkanEntity *e = (VulkanEntity *)h.value[0]; 457 assert(ValidVulkanHandle(h) && e->kind == kind); 458 return &e->as; 459 } 460 461 function VkCommandBuffer 462 vk_command_buffer(VulkanHandle h) 463 { 464 VulkanCommandBuffer *vcb = vk_entity_data(h, VulkanEntityKind_CommandBuffer); 465 VulkanCommandPool *vcp = vulkan_context->command_pools[vcb->timeline]; 466 VkCommandBuffer result = vcp->buffers[vcb->buffer_index]; 467 return result; 468 } 469 470 #define glslang_log(a, ...) glslang_log_(a, arg_list(str8, __VA_ARGS__)) 471 function void 472 glslang_log_(Arena *arena, str8 *items, u64 count) 473 { 474 Stream sb = arena_stream(arena); 475 stream_append_str8(&sb, glslang_info("")); 476 stream_append_str8s_(&sb, items, count); 477 if (sb.data[sb.widx - 1] != '\n') stream_append_byte(&sb, '\n'); 478 os_console_log(sb.data, sb.widx); 479 } 480 481 function str8 482 glsl_to_spirv(Arena *arena, u32 kind, str8 shader_text, str8 name) 483 { 484 /* NOTE(rnp): glslang's garbage c interface doesn't expose internal usage of strings with length */ 485 assert(shader_text.data[shader_text.length] == 0); 486 487 glslang_input_t input = { 488 .language = GLSLANG_SOURCE_GLSL, 489 .stage = kind, 490 .client = GLSLANG_CLIENT_VULKAN, 491 .client_version = GLSLANG_TARGET_VULKAN_1_4, 492 .target_language = GLSLANG_TARGET_SPV, 493 .target_language_version = GLSLANG_TARGET_SPV_1_6, 494 .code = (c8 *)shader_text.data, 495 .default_version = 460, 496 .default_profile = GLSLANG_NO_PROFILE, 497 .force_default_version_and_profile = 0, 498 .forward_compatible = 0, 499 .messages = GLSLANG_MSG_DEFAULT_BIT, 500 .resource = glslc_resource_constraints, 501 }; 502 glslang_shader_t *shader = glslang_shader_create(&input); 503 504 str8 error = {0}; 505 if (glslang_shader_preprocess(shader, &input)) { 506 if (!glslang_shader_parse(shader, &input)) 507 error = str8("parsing failed"); 508 } else { 509 error = str8("preprocessing failed"); 510 } 511 512 if (error.length) { 513 glslang_log(arena, name, str8(": "), error, str8("\n"), 514 str8_from_c_str((c8 *)glslang_shader_get_info_log(shader)), 515 str8_from_c_str((c8 *)glslang_shader_get_info_debug_log(shader))); 516 glslang_shader_delete(shader); 517 shader = 0; 518 } 519 520 str8 result = {0}; 521 if (shader) { 522 glslang_program_t *program = glslang_program_create(); 523 glslang_program_add_shader(program, shader); 524 i32 messages = GLSLANG_MSG_DEBUG_INFO_BIT|GLSLANG_MSG_SPV_RULES_BIT|GLSLANG_MSG_VULKAN_RULES_BIT; 525 if (glslang_program_link(program, messages)) { 526 glslang_spv_options_t options = {.validate = 1,}; 527 528 if (vulkan_config.debug.shader_non_semantic_info && 529 vulkan_config.debug.shader_relaxed_extended_instruction) 530 { 531 options.generate_debug_info = 1; 532 options.emit_nonsemantic_shader_debug_info = 1; 533 options.emit_nonsemantic_shader_debug_source = 1; 534 } 535 536 glslang_program_add_source_text(program, kind, (c8 *)shader_text.data, shader_text.length); 537 glslang_program_SPIRV_generate_with_options(program, kind, &options); 538 539 u32 words = glslang_program_SPIRV_get_size(program); 540 result.data = (u8 *)push_array(arena, u32, words); 541 result.length = words * sizeof(u32); 542 glslang_program_SPIRV_get(program, (u32 *)result.data); 543 544 str8 spirv_msg = str8_from_c_str((c8 *)glslang_program_SPIRV_get_messages(program)); 545 if (spirv_msg.length) glslang_log(arena, name, str8(": spirv info: "), spirv_msg); 546 } else { 547 glslang_log(arena, name, str8(": shader linking failed\n"), 548 str8_from_c_str((c8 *)glslang_program_get_info_log(program)), 549 str8_from_c_str((c8 *)glslang_program_get_info_debug_log(program))); 550 } 551 glslang_shader_delete(shader); 552 glslang_program_delete(program); 553 } 554 555 return result; 556 } 557 558 function u32 559 vk_shader_kind_to_glslang_shader_kind(u32 kind) 560 { 561 u32 result = ctz_u64(kind); 562 return result; 563 } 564 565 function VkShaderModule 566 vk_compile_shader_module(Arena *arena, u32 kind, str8 text, str8 name) 567 { 568 VkShaderModule result = {0}; 569 str8 spirv = glsl_to_spirv(arena, vk_shader_kind_to_glslang_shader_kind(kind), text, name); 570 VkShaderModuleCreateInfo create_info = { 571 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 572 .codeSize = (u64)spirv.length, 573 .pCode = (u32 *)spirv.data, 574 }; 575 if (spirv.length > 0) vkCreateShaderModule(vulkan_context->device, &create_info, 0, &result); 576 577 return result; 578 } 579 580 function VkShaderStageFlags 581 vk_stage_flags_from_shader_kind(VulkanShaderKind kind) 582 { 583 read_only local_persist VkShaderStageFlags map[VulkanShaderKind_Count + 1] = { 584 [VulkanShaderKind_Vertex] = VK_SHADER_STAGE_VERTEX_BIT, 585 [VulkanShaderKind_Mesh] = VK_SHADER_STAGE_MESH_BIT_EXT, 586 [VulkanShaderKind_Fragment] = VK_SHADER_STAGE_FRAGMENT_BIT, 587 [VulkanShaderKind_Compute] = VK_SHADER_STAGE_COMPUTE_BIT, 588 [VulkanShaderKind_Count] = 0, 589 }; 590 VkShaderStageFlags result = map[Clamp((u32)kind, 0, VulkanShaderKind_Count)]; 591 return result; 592 } 593 594 function VkSpecializationMapEntry * 595 vk_specialization_map_from_struct_id(Arena *arena, i32 struct_id) 596 { 597 assert(struct_id >= 0); 598 MetaStructInfo *si = meta_struct_info_by_id + struct_id; 599 MetaStructMember *sm = meta_struct_members_by_id[struct_id]; 600 VkSpecializationMapEntry *result = push_array(arena, VkSpecializationMapEntry, si->member_count); 601 for EachIndex(si->member_count, it) { 602 result[it].constantID = it; 603 result[it].offset = sm[it].offset; 604 result[it].size = meta_kind_byte_sizes[sm[it].type_id]; 605 } 606 return result; 607 } 608 609 function VulkanPipeline 610 vk_compute_pipeline_from_info(Arena *arena, VulkanPipelineCreateInfo *info, u32 push_constants_size) 611 { 612 VulkanPipeline result = {.stage_flags = VK_SHADER_STAGE_COMPUTE_BIT}; 613 VkShaderModule module = vk_compile_shader_module(arena, VK_SHADER_STAGE_COMPUTE_BIT, info->text, info->name); 614 if (module) { 615 VkPushConstantRange push_constant_range = { 616 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, 617 .offset = 0, 618 .size = push_constants_size, 619 }; 620 621 VkPipelineLayoutCreateInfo pipeline_layout_create_info = { 622 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 623 .setLayoutCount = countof(vulkan_context->descriptor_set_layouts), 624 .pSetLayouts = vulkan_context->descriptor_set_layouts, 625 .pushConstantRangeCount = push_constants_size ? 1 : 0, 626 .pPushConstantRanges = push_constants_size ? &push_constant_range : 0, 627 }; 628 629 vkCreatePipelineLayout(vulkan_context->device, &pipeline_layout_create_info, 0, &result.layout); 630 631 VkComputePipelineCreateInfo pipeline_create_info = { 632 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, 633 .layout = result.layout, 634 .stage = { 635 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 636 .stage = VK_SHADER_STAGE_COMPUTE_BIT, 637 .module = module, 638 .pName = "main", 639 }, 640 }; 641 642 VkSpecializationInfo specialization_info = {0}; 643 if (info->specialization_data && info->specialization_struct_id >= 0) { 644 MetaStructInfo *si = meta_struct_info_by_id + info->specialization_struct_id; 645 pipeline_create_info.stage.pSpecializationInfo = &specialization_info; 646 specialization_info.pMapEntries = vk_specialization_map_from_struct_id(arena, info->specialization_struct_id); 647 specialization_info.mapEntryCount = si->member_count; 648 specialization_info.dataSize = si->size; 649 specialization_info.pData = info->specialization_data; 650 } 651 652 vkCreateComputePipelines(vulkan_context->device, 0, 1, &pipeline_create_info, 0, &result.pipeline); 653 654 vk_label_object(PIPELINE, result.pipeline, info->name, str8("Pipeline")); 655 vk_label_object(PIPELINE_LAYOUT, result.layout, info->name, str8("Pipeline Layout")); 656 vk_label_object(SHADER_MODULE, module, info->name, str8("Module")); 657 658 vkDestroyShaderModule(vulkan_context->device, module, 0); 659 } 660 if (result.pipeline == 0) result = vulkan_context->default_compute_pipeline; 661 662 return result; 663 } 664 665 function VulkanPipeline 666 vk_graphics_pipeline_from_infos(Arena *arena, VulkanPipelineCreateInfo *infos, u32 count, u32 push_constants_size) 667 { 668 assume(count == 2); 669 670 VulkanPipeline result = {0}; 671 VkShaderModule modules[2]; 672 673 modules[0] = vk_compile_shader_module(arena, vk_stage_flags_from_shader_kind(infos[0].kind), 674 infos[0].text, infos[0].name); 675 modules[1] = vk_compile_shader_module(arena, vk_stage_flags_from_shader_kind(infos[1].kind), 676 infos[1].text, infos[1].name); 677 if (modules[0] && modules[1]) { 678 result.stage_flags = vk_stage_flags_from_shader_kind(infos[0].kind) 679 | vk_stage_flags_from_shader_kind(infos[1].kind); 680 681 VkPushConstantRange pcr = { 682 .stageFlags = result.stage_flags, 683 .offset = 0, 684 .size = push_constants_size, 685 }; 686 687 VkPipelineLayoutCreateInfo pipeline_layout_info = { 688 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 689 .setLayoutCount = countof(vulkan_context->descriptor_set_layouts), 690 .pSetLayouts = vulkan_context->descriptor_set_layouts, 691 .pushConstantRangeCount = push_constants_size ? 1 : 0, 692 .pPushConstantRanges = push_constants_size ? &pcr : 0, 693 }; 694 695 vkCreatePipelineLayout(vulkan_context->device, &pipeline_layout_info, 0, &result.layout); 696 697 VkPipelineShaderStageCreateInfo shader_stage_create_infos[2] = { 698 { 699 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 700 .stage = vk_stage_flags_from_shader_kind(infos[0].kind), 701 .module = modules[0], 702 .pName = "main", 703 }, 704 { 705 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 706 .stage = vk_stage_flags_from_shader_kind(infos[1].kind), 707 .module = modules[1], 708 .pName = "main", 709 }, 710 }; 711 712 VkPipelineVertexInputStateCreateInfo vertex_input_info = { 713 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 714 }; 715 716 VkPipelineInputAssemblyStateCreateInfo input_assembly_info = { 717 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 718 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 719 }; 720 721 VkPipelineViewportStateCreateInfo viewport_info = { 722 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 723 .viewportCount = 1, 724 .scissorCount = 1, 725 }; 726 727 VkPipelineRasterizationStateCreateInfo rasterization_info = { 728 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 729 .polygonMode = VK_POLYGON_MODE_FILL, 730 .lineWidth = 1.0f, 731 .cullMode = VK_CULL_MODE_BACK_BIT, 732 .frontFace = VK_FRONT_FACE_CLOCKWISE, 733 }; 734 735 VkPipelineMultisampleStateCreateInfo multisampling_info = { 736 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 737 .rasterizationSamples = vulkan_context->gpu_info.max_msaa_samples, 738 }; 739 740 VkPipelineDepthStencilStateCreateInfo depth_test_create_info = { 741 .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, 742 .depthTestEnable = 1, 743 .depthWriteEnable = 1, 744 .depthCompareOp = VK_COMPARE_OP_LESS, 745 .depthBoundsTestEnable = 1, 746 .stencilTestEnable = 0, 747 .front = {0}, 748 .back = {0}, 749 .minDepthBounds = 0.0f, 750 .maxDepthBounds = 1.0f, 751 }; 752 753 u32 colour_mask = VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT; 754 VkPipelineColorBlendAttachmentState blend_state = { 755 .colorWriteMask = colour_mask, 756 .blendEnable = 1, 757 .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, 758 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, 759 .colorBlendOp = VK_BLEND_OP_ADD, 760 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, 761 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, 762 .alphaBlendOp = VK_BLEND_OP_ADD, 763 }; 764 765 VkPipelineColorBlendStateCreateInfo colour_blend_state_create = { 766 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 767 .logicOpEnable = 0, 768 .logicOp = VK_LOGIC_OP_COPY, 769 .attachmentCount = 1, 770 .pAttachments = &blend_state, 771 }; 772 773 VkDynamicState dynamic_states[] = { 774 VK_DYNAMIC_STATE_VIEWPORT, 775 VK_DYNAMIC_STATE_SCISSOR, 776 }; 777 778 VkPipelineDynamicStateCreateInfo dynamic_state_info = { 779 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 780 .dynamicStateCount = countof(dynamic_states), 781 .pDynamicStates = dynamic_states, 782 }; 783 784 //VkFormat colour_attachment_format = VK_FORMAT_R8G8B8A8_SRGB; 785 VkFormat colour_attachment_format = VK_FORMAT_R8G8B8A8_UNORM; 786 VkPipelineRenderingCreateInfo rendering_create_info = { 787 .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, 788 .colorAttachmentCount = 1, 789 .pColorAttachmentFormats = &colour_attachment_format, 790 .depthAttachmentFormat = vulkan_context->depth_stencil_format, 791 .stencilAttachmentFormat = vulkan_context->depth_stencil_format, 792 }; 793 794 VkGraphicsPipelineCreateInfo pci = { 795 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 796 .pNext = &rendering_create_info, 797 .stageCount = countof(shader_stage_create_infos), 798 .pStages = shader_stage_create_infos, 799 .pVertexInputState = &vertex_input_info, 800 .pInputAssemblyState = &input_assembly_info, 801 .pViewportState = &viewport_info, 802 .pRasterizationState = &rasterization_info, 803 .pMultisampleState = &multisampling_info, 804 .pDepthStencilState = &depth_test_create_info, 805 .pColorBlendState = &colour_blend_state_create, 806 .pDynamicState = &dynamic_state_info, 807 .layout = result.layout, 808 }; 809 810 vkCreateGraphicsPipelines(vulkan_context->device, 0, 1, &pci,0, &result.pipeline); 811 812 str8 extras[] = { 813 [VulkanShaderKind_Vertex] = str8_comp("Vertex Module"), 814 [VulkanShaderKind_Mesh] = str8_comp("Mesh Module"), 815 [VulkanShaderKind_Fragment] = str8_comp("Fragment Module"), 816 }; 817 assert(infos[0].kind < countof(extras)); 818 assert(infos[1].kind < countof(extras)); 819 820 vk_label_object(PIPELINE, result.pipeline, infos[0].name, str8("Pipeline")); 821 vk_label_object(PIPELINE_LAYOUT, result.layout, infos[0].name, str8("Pipeline Layout")); 822 //vk_label_object_(VK_OBJECT_TYPE_SHADER_MODULE, (u64)modules[0], infos[0].name, extras[infos[0].kind]); 823 //vk_label_object_(VK_OBJECT_TYPE_SHADER_MODULE, (u64)modules[1], infos[1].name, extras[infos[1].kind]); 824 } 825 826 if (modules[0]) vkDestroyShaderModule(vulkan_context->device, modules[0], 0); 827 if (modules[1]) vkDestroyShaderModule(vulkan_context->device, modules[1], 0); 828 829 if (result.pipeline == 0) result = vulkan_context->default_graphics_pipeline; 830 831 return result; 832 } 833 834 function VulkanSemaphore 835 vk_make_semaphore(OSHandle *export) 836 { 837 VulkanContext *vk = vulkan_context; 838 839 VkSemaphoreCreateInfo sci = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; 840 VkExportSemaphoreCreateInfo esci = { 841 .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, 842 .handleTypes = OS_WINDOWS ? VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT 843 : VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, 844 }; 845 VkSemaphoreTypeCreateInfo stc = { 846 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, 847 .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, 848 }; 849 850 if (export) sci.pNext = &esci; 851 else sci.pNext = &stc; 852 853 VulkanSemaphore result = {0}; 854 855 vkCreateSemaphore(vk->device, &sci, 0, &result.semaphore); 856 857 if (export) { 858 if (OS_WINDOWS) { 859 VkSemaphoreGetWin32HandleInfoKHR ghi = { 860 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR, 861 .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, 862 .semaphore = result.semaphore, 863 }; 864 void *handle; 865 vkGetSemaphoreWin32HandleKHR(vk->device, &ghi, &handle); 866 export->value[0] = (u64)handle; 867 } else { 868 VkSemaphoreGetFdInfoKHR ghi = { 869 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR, 870 .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, 871 .semaphore = result.semaphore, 872 }; 873 i32 handle; 874 vkGetSemaphoreFdKHR(vk->device, &ghi, &handle); 875 export->value[0] = (u64)handle; 876 } 877 } 878 879 return result; 880 } 881 882 function void 883 vk_release_memory(VkDeviceMemory memory, u64 size) 884 { 885 VulkanContext *vk = vulkan_context; 886 vkFreeMemory(vk->device, memory, 0); 887 atomic_add_u64(&vk->gpu_info.gpu_heap_used, -size); 888 } 889 890 function b32 891 vk_allocate_memory(VkDeviceMemory *memory, u64 size, VulkanMemoryKind kind, VkMemoryAllocateFlags flags, 892 VkMemoryDedicatedAllocateInfo *dedicated_allocate_info, OSHandle *export) 893 { 894 VulkanContext *vk = vulkan_context; 895 896 VkExportMemoryAllocateInfo export_info = { 897 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, 898 .handleTypes = OS_WINDOWS ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT 899 : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, 900 }; 901 902 VkMemoryAllocateFlagsInfo memory_allocate_flags_info = { 903 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, 904 .flags = flags, 905 .pNext = dedicated_allocate_info, 906 }; 907 908 if (export) { 909 export_info.pNext = dedicated_allocate_info; 910 memory_allocate_flags_info.pNext = &export_info; 911 } 912 913 VkMemoryAllocateInfo memory_allocate_info = { 914 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 915 .allocationSize = size, 916 .memoryTypeIndex = vk->memory_info.memory_type_indices[kind], 917 .pNext = &memory_allocate_flags_info, 918 }; 919 920 b32 result = vkAllocateMemory(vk->device, &memory_allocate_info, 0, memory) == VK_SUCCESS; 921 if (result) { 922 atomic_add_u64(&vk->gpu_info.gpu_heap_used, memory_allocate_info.allocationSize); 923 924 if (export) { 925 if (OS_WINDOWS) { 926 VkMemoryGetWin32HandleInfoKHR handle_info = { 927 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR, 928 .memory = *memory, 929 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, 930 }; 931 void *handle; 932 vkGetMemoryWin32HandleKHR(vk->device, &handle_info, &handle); 933 export->value[0] = (u64)handle; 934 } else { 935 VkMemoryGetFdInfoKHR fd_info = { 936 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, 937 .memory = *memory, 938 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, 939 }; 940 i32 fd; 941 vkGetMemoryFdKHR(vk->device, &fd_info, &fd); 942 export->value[0] = (u64)fd; 943 } 944 } 945 } 946 return result; 947 } 948 949 function u32 950 vk_index_size(VkIndexType type) 951 { 952 u32 result = 0; 953 switch (type) { 954 case VK_INDEX_TYPE_UINT16:{ result = 2; }break; 955 case VK_INDEX_TYPE_UINT32:{ result = 4; }break; 956 InvalidDefaultCase; 957 } 958 return result; 959 } 960 961 typedef struct { 962 GPUBuffer *gpu_buffer; 963 u64 size; 964 VulkanUsageFlags flags; 965 u32 queue_family_count; 966 u32 queue_family_indices[VulkanTimeline_Count]; 967 VkIndexType index_type; 968 OSHandle *export; 969 str8 label; 970 } VulkanBufferAllocateInfo; 971 972 function b32 973 vk_buffer_allocate_common(VulkanBuffer *vb, VulkanBufferAllocateInfo *ai) 974 { 975 VulkanContext *vk = vulkan_context; 976 977 // TODO(rnp): this probably should be handled, its usually 4GB. likely 978 // need to chain multiple allocations and handle it in shader code 979 u64 clamp_size = vk->memory_info.max_allocation_size & ~(vk->memory_info.non_coherent_atom_size - 1); 980 981 // NOTE(rnp): renderdoc can't handle buffers that are too close to the allocation size limit 982 if (renderdoc_attached()) 983 clamp_size -= MB(8); 984 985 u64 size = Min(ai->size, clamp_size); 986 987 VkBufferCreateInfo buffer_create_info = { 988 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 989 .usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT|VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 990 .size = size, 991 .sharingMode = ai->queue_family_count > 1 ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE, 992 .queueFamilyIndexCount = ai->queue_family_count, 993 .pQueueFamilyIndices = ai->queue_family_indices, 994 }; 995 996 if (ai->flags & VulkanUsageFlag_TransferSource) 997 buffer_create_info.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; 998 999 if (ai->flags & VulkanUsageFlag_TransferDestination) 1000 buffer_create_info.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; 1001 1002 if (ai->index_type != VK_INDEX_TYPE_NONE_KHR) 1003 buffer_create_info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; 1004 1005 VkExternalMemoryBufferCreateInfo external_memory_buffer_create_info = { 1006 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, 1007 .handleTypes = OS_WINDOWS ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT 1008 : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, 1009 }; 1010 1011 if (ai->export) buffer_create_info.pNext = &external_memory_buffer_create_info; 1012 1013 vkCreateBuffer(vk->device, &buffer_create_info, 0, &vb->buffer); 1014 vk_label_object(BUFFER, vb->buffer, ai->label, str8("Buffer")); 1015 1016 VkMemoryRequirements memory_requirements; 1017 vkGetBufferMemoryRequirements(vk->device, vb->buffer, &memory_requirements); 1018 1019 assert((u64)size <= memory_requirements.size); 1020 size = memory_requirements.size; 1021 1022 VkMemoryDedicatedAllocateInfo dedicated_allocate_info = { 1023 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, 1024 .buffer = vb->buffer, 1025 }; 1026 1027 /* NOTE(rnp): to create a CPU writable buffer: 1028 * 1. try to allocate and map the entire buffer 1029 * - this may fail if the buffer is bigger than the BAR size 1030 * (unknowable from vulkan), or the memory space has become 1031 * too fragmented (unlikely) 1032 * 2. if allocation or mapping fails we must chain a host buffer 1033 * for staging. If this happens in practice we should add 1034 * the ability to import an existing external allocation 1035 */ 1036 b32 host_read_write = (ai->flags & VulkanUsageFlag_HostReadWrite) != 0; 1037 vb->memory_kind = host_read_write ? VulkanMemoryKind_BAR : VulkanMemoryKind_Device; 1038 1039 b32 result = 0; 1040 // TODO(rnp): this may fail if the allocation is too big for the BAR size 1041 // it needs to handled properly 1042 if (vk_allocate_memory(&vb->memory, size, vb->memory_kind, VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, &dedicated_allocate_info, ai->export)) { 1043 result = 1; 1044 ai->gpu_buffer->size = size; 1045 vb->memory_size = size; 1046 1047 vb->index_type = ai->index_type; 1048 1049 vk_label_object(DEVICE_MEMORY, vb->memory, ai->label, str8("Memory")); 1050 1051 if (host_read_write) 1052 vkMapMemory(vk->device, vb->memory, 0, size, 0, &vb->host_pointer); 1053 1054 vkBindBufferMemory(vk->device, vb->buffer, vb->memory, 0); 1055 VkBufferDeviceAddressInfo buffer_device_address_info = { 1056 .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, 1057 .buffer = vb->buffer, 1058 }; 1059 ai->gpu_buffer->gpu_pointer = vkGetBufferDeviceAddress(vk->device, &buffer_device_address_info); 1060 } 1061 return result; 1062 } 1063 1064 function void 1065 vk_load_instance(Arena *arena, Stream *err) 1066 { 1067 Temp scratch = temp_begin(arena); 1068 #define X(name, ...) name = (name##_fn *)vkGetInstanceProcAddr(0, #name); 1069 VkBaseProcedureList 1070 #undef X 1071 1072 u32 enabled_validation_layers_count = 0; 1073 const char *enabled_validation_layers[countof(vk_validation_layers)]; 1074 1075 u32 enabled_instance_extensions_count = 0; 1076 const char *enabled_instance_extensions[countof(vk_required_instance_extensions) + countof(vk_instance_debug_extensions)]; 1077 1078 static_assert(countof(vk_required_instance_extensions) == 0, ""); 1079 //for EachElement(vk_required_instance_extensions, it) 1080 // enabled_instance_extensions[enabled_instance_extensions_count++] = vk_required_instance_extensions[it]; 1081 1082 #if BEAMFORMER_DEBUG 1083 { 1084 u32 layer_count = 0; 1085 vkEnumerateInstanceLayerProperties(&layer_count, 0); 1086 1087 VkLayerProperties *layers = push_array(arena, VkLayerProperties, layer_count); 1088 str8 *layer_str8s = push_array(arena, str8, layer_count); 1089 vkEnumerateInstanceLayerProperties(&layer_count, layers); 1090 1091 for (u32 i = 0; i < layer_count; i++) 1092 layer_str8s[i] = str8_from_c_str(layers[i].layerName); 1093 1094 for EachElement(vk_validation_layers, it) { 1095 for(u32 i = 0; i < layer_count; i++) { 1096 if (str8_equal(vk_validation_layers[it], layer_str8s[i])) { 1097 u32 index = enabled_validation_layers_count++; 1098 enabled_validation_layers[index] = (char *)vk_validation_layers[it].data; 1099 vulkan_config.layers.enabled.E[it] = 1; 1100 vulkan_config.layers.version.E[it] = layers[i].specVersion; 1101 break; 1102 } 1103 } 1104 } 1105 1106 if (countof(vk_validation_layers) != enabled_validation_layers_count) { 1107 i32 missing_count = countof(vk_validation_layers) - enabled_validation_layers_count; 1108 stream_append_str8s(err, vulkan_info("missing validation layer"), 1109 missing_count > 1 ? str8("s:") : str8(":"), str8("\n")); 1110 1111 for EachElement(vk_validation_layers, it) 1112 if (vulkan_config.layers.enabled.E[it] == 0) 1113 stream_append_str8s(err, str8(" "), vk_validation_layers[it], str8("\n")); 1114 } 1115 1116 u32 instance_extension_count = 0; 1117 vkEnumerateInstanceExtensionProperties(0, &instance_extension_count, 0); 1118 1119 VkExtensionProperties *instance_extensions = push_array(arena, VkExtensionProperties, instance_extension_count); 1120 str8 *instance_ext_str8s = push_array(arena, str8, instance_extension_count); 1121 vkEnumerateInstanceExtensionProperties(0, &instance_extension_count, instance_extensions); 1122 for EachIndex(instance_extension_count, it) 1123 instance_ext_str8s[it] = str8_from_c_str(instance_extensions[it].extensionName); 1124 1125 for EachElement(vk_instance_debug_extensions, it) { 1126 for EachIndex(instance_extension_count, i) { 1127 if (str8_equal(vk_instance_debug_extensions[it], instance_ext_str8s[i])) { 1128 u32 index = enabled_instance_extensions_count++; 1129 enabled_instance_extensions[index] = (char *)vk_instance_debug_extensions[it].data; 1130 vulkan_config.instance.E[it] = 1; 1131 break; 1132 } 1133 } 1134 } 1135 } 1136 #endif 1137 1138 VkApplicationInfo app_info = { 1139 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 1140 .pApplicationName = BEAMFORMER_NAME_STRING, 1141 .applicationVersion = 0, 1142 .pEngineName = "No Engine", 1143 .engineVersion = 0, 1144 .apiVersion = VK_MAKE_API_VERSION(1, 3, 0, 0), 1145 }; 1146 1147 VkInstanceCreateInfo instance_create_info = { 1148 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 1149 .pApplicationInfo = &app_info, 1150 .ppEnabledExtensionNames = enabled_instance_extensions, 1151 .enabledExtensionCount = enabled_instance_extensions_count, 1152 .ppEnabledLayerNames = enabled_validation_layers, 1153 .enabledLayerCount = enabled_validation_layers_count, 1154 }; 1155 1156 #if 0 && BEAMFORMER_DEBUG 1157 VkValidationFeatureEnableEXT validation_feature_enables[] = { 1158 VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, 1159 VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT, 1160 VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, 1161 VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT, 1162 }; 1163 1164 VkValidationFeaturesEXT validation_features = { 1165 .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, 1166 .enabledValidationFeatureCount = countof(validation_feature_enables), 1167 .pEnabledValidationFeatures = validation_feature_enables, 1168 }; 1169 1170 instance_create_info.pNext = &validation_features; 1171 #endif 1172 1173 vkCreateInstance(&instance_create_info, 0, &vulkan_context->handle); 1174 1175 #define X(name, ...) name = (name##_fn *)vkGetInstanceProcAddr(vulkan_context->handle, #name); 1176 VkInstanceProcedureList 1177 #undef X 1178 temp_end(scratch); 1179 } 1180 1181 function void 1182 vk_load_physical_device(Arena *arena, Stream *err) 1183 { 1184 Temp scratch = temp_begin(arena); 1185 VulkanContext *vk = vulkan_context; 1186 1187 u32 device_count; 1188 vkEnumeratePhysicalDevices(vk->handle, &device_count, 0); 1189 1190 VkPhysicalDevice *devices = push_array(arena, typeof(*devices), device_count); 1191 vkEnumeratePhysicalDevices(vk->handle, &device_count, devices); 1192 1193 i32 best_index = -1, best_score = -1; 1194 for (u32 i = 0; i < device_count; i++) { 1195 VkPhysicalDeviceProperties2 *dp = push_struct(arena, typeof(*dp)); 1196 dp->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 1197 vkGetPhysicalDeviceProperties2(devices[i], dp); 1198 1199 i32 score = 0; 1200 if (dp->properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) 1201 score++; 1202 1203 if (score > best_score) { 1204 best_score = score; 1205 best_index = (i32)i; 1206 } 1207 } 1208 1209 vk->physical_device = best_index >= 0 ? devices[best_index] : 0; 1210 if (!vk->physical_device) 1211 fatal(vulkan_info("failed to find a suitable GPU\n")); 1212 1213 VkPhysicalDeviceProperties2 dp = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; 1214 VkPhysicalDeviceVulkan11Properties v11p = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES}; 1215 dp.pNext = &v11p; 1216 1217 vkGetPhysicalDeviceProperties2(vk->physical_device, &dp); 1218 1219 stream_append_str8s(err, vulkan_info("selecting device: "), str8_from_c_str(dp.properties.deviceName), str8("\n")); 1220 stream_append_str8(err, vulkan_info("Vulkan Version: ")); 1221 { 1222 u32 dv = dp.properties.apiVersion; 1223 stream_appendf(err, "%u.%u.%u\n", VK_API_VERSION_MAJOR(dv), VK_API_VERSION_MINOR(dv), VK_API_VERSION_PATCH(dv)); 1224 } 1225 1226 { 1227 u32 extension_count = 0; 1228 vkEnumerateDeviceExtensionProperties(vk->physical_device, 0, &extension_count, 0); 1229 VkExtensionProperties *extensions = push_array(arena, VkExtensionProperties, extension_count); 1230 vkEnumerateDeviceExtensionProperties(vk->physical_device, 0, &extension_count, extensions); 1231 1232 str8 *ext_str8s = push_array(arena, str8, extension_count); 1233 for (u32 index = 0; index < extension_count; index++) 1234 ext_str8s[index] = str8_from_c_str(extensions[index].extensionName); 1235 1236 b8 *supported = push_array(arena, b8, countof(vk_required_device_extensions)); 1237 for EachIndex(extension_count, index) 1238 for EachElement(vk_required_device_extensions, it) 1239 supported[it] |= str8_equal(vk_required_device_extensions[it], ext_str8s[index]); 1240 1241 u32 supported_count = 0; 1242 for EachElement(vk_required_device_extensions, it) 1243 supported_count += supported[it]; 1244 1245 u32 missing_count = countof(vk_required_device_extensions) - supported_count; 1246 if (missing_count) { 1247 stream_append_str8s(err, vulkan_info("fatal error: missing required device extension"), 1248 missing_count > 1 ? str8("s") : str8(""), str8(":\n")); 1249 for EachElement(vk_required_device_extensions, it) { 1250 if (!supported[it]) { 1251 str8 name = vk_required_device_extensions[it]; 1252 stream_append_str8s(err, vulkan_info(" "), name, str8("\n")); 1253 } 1254 } 1255 fatal(stream_to_str8(err)); 1256 } 1257 1258 for EachIndex(extension_count, index) 1259 for EachElement(vk_optional_device_extensions, it) 1260 vulkan_config.optional.E[it] |= str8_equal(vk_optional_device_extensions[it], ext_str8s[index]); 1261 1262 #if BEAMFORMER_DEBUG 1263 for EachIndex(extension_count, index) 1264 for EachElement(vk_debug_extensions, it) 1265 vulkan_config.debug.E[it] |= str8_equal(vk_debug_extensions[it], ext_str8s[index]); 1266 #endif 1267 } 1268 1269 { 1270 VkPhysicalDeviceFeatures2 df = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; 1271 VkPhysicalDeviceVulkan11Features v11f = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES}; 1272 VkPhysicalDeviceVulkan12Features v12f = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES}; 1273 VkPhysicalDeviceVulkan13Features v13f = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES}; 1274 df.pNext = &v11f; 1275 v11f.pNext = &v12f; 1276 v12f.pNext = &v13f; 1277 vkGetPhysicalDeviceFeatures2(vk->physical_device, &df); 1278 1279 { 1280 b32 all_supported = 1; 1281 #define X(name, ...) all_supported &= df.features.name; 1282 VK_REQUIRED_PHYSICAL_FEATURES 1283 #undef X 1284 1285 if (!all_supported) { 1286 stream_append_str8(err, vulkan_info("fatal error: missing physical device features:\n")); 1287 #define X(name, ...) if (!df.features.name) stream_append_str8(err, str8(" " #name "\n")); 1288 VK_REQUIRED_PHYSICAL_FEATURES 1289 #undef X 1290 fatal(stream_to_str8(err)); 1291 } 1292 } 1293 1294 { 1295 b32 all_supported = 1; 1296 #define X(name, ...) all_supported &= v11f.name; 1297 VK_REQUIRED_PHYSICAL_11_FEATURES 1298 #undef X 1299 1300 if (!all_supported) { 1301 stream_append_str8(err, vulkan_info("fatal error: missing physical device features:\n")); 1302 #define X(name, ...) if (!v11f.name) stream_append_str8(err, str8(" " #name "\n")); 1303 VK_REQUIRED_PHYSICAL_11_FEATURES 1304 #undef X 1305 fatal(stream_to_str8(err)); 1306 } 1307 } 1308 1309 { 1310 b32 all_supported = 1; 1311 #define X(name, ...) all_supported &= v12f.name; 1312 VK_REQUIRED_PHYSICAL_12_FEATURES 1313 #undef X 1314 1315 if (!all_supported) { 1316 stream_append_str8(err, vulkan_info("fatal error: missing physical device features:\n")); 1317 #define X(name, ...) if (!v12f.name) stream_append_str8(err, str8(" " #name "\n")); 1318 VK_REQUIRED_PHYSICAL_12_FEATURES 1319 #undef X 1320 fatal(stream_to_str8(err)); 1321 } 1322 } 1323 1324 { 1325 b32 all_supported = 1; 1326 #define X(name, ...) all_supported &= v13f.name; 1327 VK_REQUIRED_PHYSICAL_13_FEATURES 1328 #undef X 1329 1330 if (!all_supported) { 1331 stream_append_str8(err, vulkan_info("fatal error: missing physical device features:\n")); 1332 #define X(name, ...) if (!v13f.name) stream_append_str8(err, str8(" " #name "\n")); 1333 VK_REQUIRED_PHYSICAL_13_FEATURES 1334 #undef X 1335 fatal(stream_to_str8(err)); 1336 } 1337 } 1338 1339 if (vulkan_config.optional.cooperative_matrix) { 1340 u32 property_count = 0; 1341 vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR(vk->physical_device, &property_count, 0); 1342 1343 VkCooperativeMatrixPropertiesKHR *mat = push_array(arena, VkCooperativeMatrixPropertiesKHR, property_count); 1344 1345 // NOTE(rnp): validation layer stupidity 1346 for EachIndex(property_count, it) 1347 mat[it].sType = VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR; 1348 1349 vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR(vk->physical_device, &property_count, mat); 1350 b32 supported = 0; 1351 // TODO(rnp): for now the requirements are hardcoded, it is possible to support a couple 1352 // variations if needed. 1353 for EachIndex(property_count, it) { 1354 b32 match = 1; 1355 supported &= mat[it].scope == VK_SCOPE_SUBGROUP_KHR; 1356 1357 supported &= mat[it].MSize == 16; 1358 supported &= mat[it].NSize == 16; 1359 supported &= mat[it].KSize == 16; 1360 1361 supported &= mat[it].AType == VK_COMPONENT_TYPE_FLOAT16_KHR; 1362 supported &= mat[it].BType == VK_COMPONENT_TYPE_FLOAT16_KHR; 1363 supported &= mat[it].CType == VK_COMPONENT_TYPE_FLOAT32_KHR; 1364 supported &= mat[it].ResultType == VK_COMPONENT_TYPE_FLOAT32_KHR; 1365 1366 supported |= match; 1367 } 1368 vk->gpu_info.cooperative_matrix = supported; 1369 } 1370 } 1371 1372 VkPhysicalDeviceMemoryProperties2 mp = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2}; 1373 vkGetPhysicalDeviceMemoryProperties2(vk->physical_device, &mp); 1374 1375 VkPhysicalDeviceMemoryProperties *bmp = &mp.memoryProperties; 1376 1377 // NOTE(rnp): vulkan spec says that highest performance memory types must 1378 // come first. just take the first one found. 1379 1380 for (u32 i = 0; i < bmp->memoryHeapCount; i++) { 1381 if (bmp->memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { 1382 vk->memory_info.gpu_heap_index = i; 1383 break; 1384 } 1385 } 1386 1387 for (u32 i = 0; i < bmp->memoryTypeCount; i++) { 1388 if (bmp->memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { 1389 assert(bmp->memoryTypes[i].heapIndex == vk->memory_info.gpu_heap_index); 1390 vk->memory_info.memory_type_indices[VulkanMemoryKind_Device] = i; 1391 break; 1392 } 1393 } 1394 1395 // TODO(rnp): it is possible that this isn't available. for devices like that we would need 1396 // to copy into a staging buffer then DMA. For now that is unsupported. 1397 u32 bar_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT|VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; 1398 i32 bar_index = -1; 1399 for (u32 i = 0; i < bmp->memoryTypeCount; i++) { 1400 if ((bmp->memoryTypes[i].propertyFlags & bar_flags) == bar_flags) { 1401 assert(bmp->memoryTypes[i].heapIndex == vk->memory_info.gpu_heap_index); 1402 bar_index = (i32)i; 1403 break; 1404 } 1405 } 1406 1407 // TODO(rnp): this shouldn't be fatal 1408 if (bar_index == -1) { 1409 stream_append_str8(err, vulkan_info("fatal error: GPU does not support host bar memory\n")); 1410 fatal(stream_to_str8(err)); 1411 } 1412 1413 vk->memory_info.memory_type_indices[VulkanMemoryKind_BAR] = bar_index; 1414 1415 vk->memory_info.memory_type_indices[VulkanMemoryKind_Host] = -1; 1416 for (u32 i = 0; i < bmp->memoryTypeCount; i++) { 1417 if ((bmp->memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) { 1418 if (bmp->memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 1419 vk->memory_info.memory_type_indices[VulkanMemoryKind_Host] = (i8)i; 1420 break; 1421 } 1422 } 1423 } 1424 1425 // NOTE(rnp): some devices are fully unified so the only memory type is BAR memory 1426 if (vk->memory_info.memory_type_indices[VulkanMemoryKind_Host] == -1 && bar_index != -1) 1427 vk->memory_info.memory_type_indices[VulkanMemoryKind_Host] = bar_index; 1428 1429 if (vk->memory_info.memory_type_indices[VulkanMemoryKind_Host] == -1) { 1430 stream_append_str8(err, vulkan_info("fatal error: vulkan driver does not provide host visible memory\n")); 1431 fatal(stream_to_str8(err)); 1432 } 1433 1434 for EachElement(vk->memory_info.memory_type_indices, it) { 1435 u32 ti = vk->memory_info.memory_type_indices[it]; 1436 u32 flags = bmp->memoryTypes[ti].propertyFlags; 1437 vk->memory_info.memory_host_coherent[it] = (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0; 1438 } 1439 1440 vulkan_config.driver_api_version = dp.properties.apiVersion; 1441 vk->memory_info.max_allocation_size = v11p.maxMemoryAllocationSize; 1442 vk->memory_info.non_coherent_atom_size = dp.properties.limits.nonCoherentAtomSize; 1443 vk->gpu_info.vendor = dp.properties.vendorID; 1444 vk->gpu_info.gpu_heap_size = bmp->memoryHeaps[vk->memory_info.gpu_heap_index].size; 1445 vk->gpu_info.timestamp_period_ns = dp.properties.limits.timestampPeriod; 1446 vk->gpu_info.max_image_dimension_2D = dp.properties.limits.maxImageDimension2D; 1447 vk->gpu_info.max_image_dimension_3D = dp.properties.limits.maxImageDimension3D; 1448 vk->gpu_info.max_msaa_samples = round_down_power_of_two(dp.properties.limits.framebufferColorSampleCounts); 1449 vk->gpu_info.subgroup_size = v11p.subgroupSize; 1450 vk->gpu_info.max_compute_shared_memory_size = dp.properties.limits.maxComputeSharedMemorySize; 1451 1452 temp_end(scratch); 1453 // IMPORTANT(rnp): memory must only be pushed at the end of the function 1454 vk->gpu_info.name = push_str8(vk->arena, str8_from_c_str(dp.properties.deviceName)); 1455 1456 #if BEAMFORMER_DEBUG 1457 { 1458 b32 mismatch = 0; 1459 for EachElement(vk_validation_layers, it) { 1460 u32 lv = vulkan_config.layers.version.E[it]; 1461 u32 dv = vulkan_config.driver_api_version; 1462 if (lv < dv) { 1463 mismatch = 1; 1464 stream_append_str8s(err, vulkan_info("warning: validaton layer \""), 1465 vk_validation_layers[it], str8("\" version: ")); 1466 stream_appendf(err, "%u.%u.%u", VK_API_VERSION_MAJOR(lv), VK_API_VERSION_MINOR(lv), VK_API_VERSION_PATCH(lv)); 1467 stream_append_str8(err, str8(" lower than driver API version: ")); 1468 stream_appendf(err, "%u.%u.%u\n", VK_API_VERSION_MAJOR(dv), VK_API_VERSION_MINOR(dv), VK_API_VERSION_PATCH(dv)); 1469 } 1470 } 1471 1472 if (mismatch) 1473 stream_append_str8(err, vulkan_info("DO NOT report any bugs without updating your validation layers!\n")); 1474 } 1475 #endif 1476 } 1477 1478 function void 1479 vk_load_queues(Arena *arena, Stream *err) 1480 { 1481 /////////////////////////////////////////////////////// 1482 // NOTE(rnp): try to allocate an appropriate queue for 1483 // each of the following tasks: 1484 // * UI Rendering (Graphics) 1485 // * Beamforming (Compute) 1486 // * Upload (Transfer) 1487 // Then create a logical device ready for use 1488 1489 VulkanContext *vk = vulkan_context; 1490 1491 u32 queue_family_count; 1492 vkGetPhysicalDeviceQueueFamilyProperties(vk->physical_device, &queue_family_count, 0); 1493 1494 Temp scratch = temp_begin(arena); 1495 VkQueueFamilyProperties *queues = push_array(arena, typeof(*queues), queue_family_count); 1496 vkGetPhysicalDeviceQueueFamilyProperties(vk->physical_device, &queue_family_count, queues); 1497 1498 i32 queue_indices[VulkanQueueKind_Count]; 1499 for EachElement(queue_indices, it) queue_indices[it] = -1; 1500 1501 /////////////////////////////////////////////////////////////// 1502 // NOTE(rnp): start by assigning queue families for each queue 1503 1504 /* NOTE(rnp): try for exclusive transfer queue */ 1505 #if !ForceSingleQueue 1506 { 1507 u32 mask = VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT|VK_QUEUE_TRANSFER_BIT; 1508 u32 max_timestamp_bits = 0; 1509 for (u32 index = 0; index < queue_family_count; index++) { 1510 if ((queues[index].queueFlags & mask) == VK_QUEUE_TRANSFER_BIT) { 1511 if (queues[index].timestampValidBits > max_timestamp_bits) { 1512 max_timestamp_bits = queues[index].timestampValidBits; 1513 queue_indices[VulkanQueueKind_Transfer] = (i32)index; 1514 } 1515 } 1516 } 1517 } 1518 1519 /* NOTE(rnp): try for compute separate from graphics */ 1520 for (u32 index = 0; index < queue_family_count; index++) { 1521 if ((queues[index].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0 && 1522 (queues[index].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) 1523 { 1524 queue_indices[VulkanQueueKind_Compute] = (i32)index; 1525 break; 1526 } 1527 } 1528 #endif /* !ForceSingleQueue */ 1529 1530 /* NOTE(rnp): find graphics family and verify it is exclusive */ 1531 b32 multi_graphics = 0; 1532 for (u32 index = 0; index < queue_family_count; index++) { 1533 if ((queues[index].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { 1534 // TODO(rnp): check for presentation support 1535 multi_graphics = queue_indices[VulkanQueueKind_Graphics] != -1; 1536 queue_indices[VulkanQueueKind_Graphics] = (i32)index; 1537 } 1538 } 1539 1540 if (multi_graphics) 1541 stream_append_str8(err, vulkan_info("warning: multiple queue families reported graphics support\n")); 1542 1543 if (queue_indices[VulkanQueueKind_Graphics] == -1) { 1544 stream_append_str8(err, vulkan_info("fatal error: GPU does not support graphics presentation\n")); 1545 fatal(stream_to_str8(err)); 1546 } 1547 1548 if (queue_indices[VulkanQueueKind_Compute] == -1) 1549 if ((queues[queue_indices[VulkanQueueKind_Graphics]].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0) 1550 queue_indices[VulkanQueueKind_Compute] = queue_indices[VulkanQueueKind_Graphics]; 1551 1552 if (queue_indices[VulkanQueueKind_Compute] == -1) { 1553 stream_append_str8(err, vulkan_info("fatal error: GPU does not support compute\n")); 1554 fatal(stream_to_str8(err)); 1555 } 1556 1557 if (queue_indices[VulkanQueueKind_Transfer] == -1) { 1558 if ((queues[queue_indices[VulkanQueueKind_Compute]].queueFlags & VK_QUEUE_TRANSFER_BIT) != 0) 1559 queue_indices[VulkanQueueKind_Transfer] = queue_indices[VulkanQueueKind_Compute]; 1560 else if ((queues[queue_indices[VulkanQueueKind_Graphics]].queueFlags & VK_QUEUE_TRANSFER_BIT) != 0) 1561 queue_indices[VulkanQueueKind_Transfer] = queue_indices[VulkanQueueKind_Graphics]; 1562 } 1563 1564 if (queue_indices[VulkanQueueKind_Transfer] == -1) { 1565 stream_append_str8(err, vulkan_info("fatal error: GPU does not support data transfer\n")); 1566 fatal(stream_to_str8(err)); 1567 } 1568 1569 ///////////////////////////////////////////////////////////////// 1570 // NOTE(rnp): if queues share families try to allocate subqueues 1571 1572 u32 assigned_subindices[VulkanQueueKind_Count] = {0}; 1573 i32 queue_subindices[VulkanQueueKind_Count] = {0}; 1574 1575 assigned_subindices[VulkanQueueKind_Graphics] += 1; 1576 1577 if (queue_indices[VulkanQueueKind_Compute] == queue_indices[VulkanQueueKind_Graphics]) { 1578 if (assigned_subindices[VulkanQueueKind_Graphics] < queues[queue_indices[VulkanQueueKind_Graphics]].queueCount) 1579 queue_subindices[VulkanQueueKind_Compute] = assigned_subindices[VulkanQueueKind_Graphics]++; 1580 } else { 1581 assigned_subindices[VulkanQueueKind_Compute] += 1; 1582 } 1583 1584 if (queue_indices[VulkanQueueKind_Transfer] == queue_indices[VulkanQueueKind_Graphics]) { 1585 if (assigned_subindices[VulkanQueueKind_Graphics] < queues[queue_indices[VulkanQueueKind_Graphics]].queueCount) 1586 queue_subindices[VulkanQueueKind_Transfer] = assigned_subindices[VulkanQueueKind_Graphics]++; 1587 } else if (queue_indices[VulkanQueueKind_Transfer] == queue_indices[VulkanQueueKind_Compute]) { 1588 if (assigned_subindices[VulkanQueueKind_Compute] < queues[queue_indices[VulkanQueueKind_Compute]].queueCount) 1589 queue_subindices[VulkanQueueKind_Transfer] = assigned_subindices[VulkanQueueKind_Compute]++; 1590 } else { 1591 assigned_subindices[VulkanQueueKind_Transfer] += 1; 1592 } 1593 1594 for EachElement(assigned_subindices, it) 1595 vk->unique_queues += assigned_subindices[it]; 1596 1597 temp_end(scratch); 1598 1599 ///////////////////////////////////////////// 1600 // NOTE(rnp): fill in info and create device 1601 for EachElement(vk->queues, it) { 1602 u32 index = queue_subindices[it]; 1603 for (i32 i = 0; i < queue_indices[it]; i++) 1604 index += assigned_subindices[i]; 1605 vk->queue_indices[it] = index; 1606 } 1607 1608 for EachElement(vk->queues, it) { 1609 if (vk->queues[vk->queue_indices[it]] == 0) { 1610 vk->queues[vk->queue_indices[it]] = push_struct(vk->arena, VulkanQueue); 1611 vk->queues[vk->queue_indices[it]]->queue_family = queue_indices[it]; 1612 vk->queues[vk->queue_indices[it]]->queue_index = queue_subindices[it]; 1613 } 1614 vk->queues[it] = vk->queues[vk->queue_indices[it]]; 1615 } 1616 1617 for EachElement(vk->command_pools, it) 1618 vk->command_pools[it] = push_struct(vk->arena, VulkanCommandPool); 1619 1620 VkDeviceQueueCreateInfo queue_create_infos[VulkanQueueKind_Count]; 1621 1622 f32 queue_priorities[VulkanQueueKind_Count][VulkanQueueKind_Count]; 1623 for (u32 i = 0; i < VulkanQueueKind_Count; i++) 1624 for (u32 j = 0; j < VulkanQueueKind_Count; j++) 1625 queue_priorities[i][j] = 1.0f; 1626 queue_priorities[queue_indices[VulkanQueueKind_Compute]][queue_subindices[VulkanQueueKind_Compute]] = 0.5f; 1627 1628 u32 queue_create_index = 0; 1629 b32 queue_info_filled[VulkanQueueKind_Count] = {0}; 1630 for (u32 q = 0; q < vk->unique_queues; q++) { 1631 u32 base_q = queue_indices[q]; 1632 if (!queue_info_filled[base_q]) { 1633 queue_create_infos[queue_create_index++] = (VkDeviceQueueCreateInfo){ 1634 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 1635 .queueFamilyIndex = base_q, 1636 .queueCount = assigned_subindices[q], 1637 .pQueuePriorities = queue_priorities[q], 1638 }; 1639 } 1640 queue_info_filled[base_q] = 1; 1641 } 1642 1643 u32 enabled_count = 0; 1644 const char *enabled_extensions[MAX_ENABLED_EXTENSIONS]; 1645 1646 for EachElement(vk_required_device_extensions, it) 1647 enabled_extensions[enabled_count++] = (char *)vk_required_device_extensions[it].data; 1648 1649 for EachElement(vk_optional_device_extensions, it) 1650 if (vulkan_config.optional.E[it]) 1651 enabled_extensions[enabled_count++] = (char *)vk_optional_device_extensions[it].data; 1652 1653 for EachElement(vk_debug_extensions, it) 1654 if (vulkan_config.debug.E[it]) 1655 enabled_extensions[enabled_count++] = (char *)vk_debug_extensions[it].data; 1656 1657 VkDeviceCreateInfo device_create_info = { 1658 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 1659 .pQueueCreateInfos = queue_create_infos, 1660 .queueCreateInfoCount = queue_create_index, 1661 .ppEnabledExtensionNames = enabled_extensions, 1662 .enabledExtensionCount = enabled_count, 1663 }; 1664 1665 VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR pdsre = { 1666 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR, 1667 .shaderRelaxedExtendedInstruction = 1, 1668 }; 1669 if (vulkan_config.debug.shader_relaxed_extended_instruction) { 1670 pdsre.pNext = (void *)device_create_info.pNext; 1671 device_create_info.pNext = &pdsre; 1672 } 1673 1674 VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop_mat_features = { 1675 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR, 1676 .cooperativeMatrix = 1, 1677 .cooperativeMatrixRobustBufferAccess = 0, 1678 }; 1679 if (vk->gpu_info.cooperative_matrix) { 1680 coop_mat_features.pNext = (void *)device_create_info.pNext; 1681 device_create_info.pNext = &coop_mat_features; 1682 } 1683 1684 VkPhysicalDeviceRobustness2FeaturesKHR robust2 = { 1685 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR, 1686 .pNext = (void *)device_create_info.pNext, 1687 .nullDescriptor = 1, 1688 }; 1689 device_create_info.pNext = &robust2; 1690 1691 VkPhysicalDeviceVulkan13Features v13f = { 1692 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, 1693 .pNext = (void *)device_create_info.pNext, 1694 #define X(name, ...) .name = 1, 1695 VK_REQUIRED_PHYSICAL_13_FEATURES 1696 #undef X 1697 }; 1698 device_create_info.pNext = &v13f; 1699 1700 VkPhysicalDeviceVulkan12Features v12f = { 1701 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, 1702 .pNext = (void *)device_create_info.pNext, 1703 #define X(name, ...) .name = 1, 1704 VK_REQUIRED_PHYSICAL_12_FEATURES 1705 #undef X 1706 }; 1707 device_create_info.pNext = &v12f; 1708 1709 VkPhysicalDeviceVulkan11Features v11f = { 1710 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES, 1711 .pNext = (void *)device_create_info.pNext, 1712 #define X(name, ...) .name = 1, 1713 VK_REQUIRED_PHYSICAL_11_FEATURES 1714 #undef X 1715 }; 1716 device_create_info.pNext = &v11f; 1717 1718 VkPhysicalDeviceFeatures2 device_features = { 1719 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, 1720 .pNext = (void *)device_create_info.pNext, 1721 .features = { 1722 #define X(name, ...) .name = 1, 1723 VK_REQUIRED_PHYSICAL_FEATURES 1724 #undef X 1725 }, 1726 }; 1727 device_create_info.pNext = &device_features; 1728 1729 vkCreateDevice(vk->physical_device, &device_create_info, 0, &vk->device); 1730 1731 #define X(name, ...) name = (name##_fn *)vkGetDeviceProcAddr(vk->device, #name); 1732 VkDeviceProcedureList 1733 #undef X 1734 1735 for (u32 q = 0; q < vk->unique_queues; q++) { 1736 VulkanQueue *qp = vk->queues[q]; 1737 vkGetDeviceQueue(vk->device, qp->queue_family, qp->queue_index, &qp->queue); 1738 1739 qp->timeline_semaphore = vk_make_semaphore(0); 1740 } 1741 1742 vk->queues[VulkanQueueKind_Graphics]->pipeline_stage_flags |= VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT; 1743 vk->queues[VulkanQueueKind_Compute]->pipeline_stage_flags |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; 1744 1745 for EachElement(vk->command_pools, it) { 1746 VulkanCommandPool *vcp = vk->command_pools[it]; 1747 1748 VkCommandPoolCreateInfo command_pool_create_info = { 1749 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 1750 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, 1751 .queueFamilyIndex = vk->queues[it]->queue_family, 1752 }; 1753 1754 vkCreateCommandPool(vk->device, &command_pool_create_info, 0, &vcp->handle); 1755 1756 VkCommandBufferAllocateInfo command_buffer_allocate_info = { 1757 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1758 .commandPool = vcp->handle, 1759 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1760 .commandBufferCount = countof(vcp->buffers), 1761 }; 1762 vkAllocateCommandBuffers(vk->device, &command_buffer_allocate_info, vcp->buffers); 1763 1764 VkQueryPoolCreateInfo query_pool_create_info = { 1765 .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, 1766 .queryType = VK_QUERY_TYPE_TIMESTAMP, 1767 .queryCount = MaxCommandBuffersInFlight * MaxCommandBufferTimestamps, 1768 }; 1769 vkCreateQueryPool(vk->device, &query_pool_create_info, 0, &vcp->query_pool); 1770 } 1771 } 1772 1773 function void 1774 vk_load_graphics(void) 1775 { 1776 VulkanContext *vk = vulkan_context; 1777 1778 // NOTE: swap chain image format 1779 { 1780 } 1781 1782 // NOTE: depth/stencil format 1783 { 1784 VkFormat depth_formats[] = { 1785 VK_FORMAT_D32_SFLOAT_S8_UINT, 1786 VK_FORMAT_D24_UNORM_S8_UINT, 1787 VK_FORMAT_D16_UNORM_S8_UINT, 1788 }; 1789 1790 vk->depth_stencil_format = VK_FORMAT_UNDEFINED; 1791 for EachElement(depth_formats, it) { 1792 VkFormatProperties3 format_properties3 = {.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3}; 1793 VkFormatProperties2 format_properties2 = { 1794 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, 1795 .pNext = &format_properties3, 1796 }; 1797 vkGetPhysicalDeviceFormatProperties2(vk->physical_device, depth_formats[it], &format_properties2); 1798 if (format_properties3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT) { 1799 vk->depth_stencil_format = depth_formats[it]; 1800 break; 1801 } 1802 } 1803 } 1804 } 1805 1806 function void 1807 vk_load_descriptor_block(void) 1808 { 1809 // NOTE(rnp): 1810 // * One Descriptor Pool 1811 // * One Descriptor Set Per Resource Kind 1812 // * Shaders know the ResourceKind enumeration 1813 // * Shaders know the per set binding points 1814 1815 VulkanContext *vk = vulkan_context; 1816 1817 // NOTE(rnp): Pool 1818 VkDescriptorPoolSize pool_sizes[] = { 1819 { 1820 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1821 .descriptorCount = BeamformerShaderBufferSlot_Count, 1822 }, 1823 }; 1824 static_assert(countof(pool_sizes) == BeamformerShaderResourceKind_Count, ""); 1825 1826 VkDescriptorPoolCreateInfo pool_create_info = { 1827 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1828 .maxSets = BeamformerShaderResourceKind_Count, 1829 .poolSizeCount = countof(pool_sizes), 1830 .pPoolSizes = pool_sizes, 1831 }; 1832 1833 vkCreateDescriptorPool(vk->device, &pool_create_info, 0, &vk->descriptor_pool); 1834 1835 // NOTE(rnp): Set Layouts 1836 VkDescriptorSetLayoutCreateInfo layout_create_info = { 1837 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 1838 }; 1839 1840 { 1841 VkDescriptorSetLayoutBinding layout_bindings[BeamformerShaderBufferSlot_Count]; 1842 for EachEnumValue(BeamformerShaderBufferSlot, it) { 1843 layout_bindings[it] = (VkDescriptorSetLayoutBinding){ 1844 .binding = it, 1845 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1846 .descriptorCount = 1, 1847 .stageFlags = VK_SHADER_STAGE_ALL, 1848 }; 1849 } 1850 layout_create_info.bindingCount = countof(layout_bindings), 1851 layout_create_info.pBindings = layout_bindings, 1852 vkCreateDescriptorSetLayout(vk->device, &layout_create_info, 0, 1853 vk->descriptor_set_layouts + BeamformerShaderResourceKind_Buffer); 1854 } 1855 1856 // NOTE(rnp): Sets 1857 VkDescriptorSetAllocateInfo set_allocate_info = { 1858 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 1859 .descriptorPool = vk->descriptor_pool, 1860 .descriptorSetCount = countof(vk->descriptor_sets), 1861 .pSetLayouts = vk->descriptor_set_layouts, 1862 }; 1863 static_assert(countof(vk->descriptor_set_layouts) == countof(vk->descriptor_sets), ""); 1864 vkAllocateDescriptorSets(vk->device, &set_allocate_info, vk->descriptor_sets); 1865 1866 vk_label_object(DESCRIPTOR_POOL, vk->descriptor_pool, str8("Beamformer Resources"), str8("Pool")); 1867 1868 Temp scratch; 1869 DeferLoop(take_lock(&vk->arena_lock, -1), release_lock(&vk->arena_lock)) 1870 DeferLoop(scratch = temp_begin(vk->arena), temp_end(scratch)) 1871 { 1872 for EachElement(vk->descriptor_sets, it) { 1873 Stream sb = arena_stream(vk->arena); 1874 stream_append_str8s(&sb, str8("Beamformer "), beamformer_shader_resource_kind_strings[it], str8("s")); 1875 vk_label_object(DESCRIPTOR_SET, vk->descriptor_sets[it], stream_to_str8(&sb), str8("Set")); 1876 vk_label_object(DESCRIPTOR_SET_LAYOUT, vk->descriptor_set_layouts[it], stream_to_str8(&sb), str8("Set Layout")); 1877 } 1878 } 1879 1880 // NOTE(rnp): junk API requirement that doesn't allow 0 initialization 1881 for EachElement(vk->descriptor_buffer_infos, it) 1882 vk->descriptor_buffer_infos[it].range = VK_WHOLE_SIZE; 1883 } 1884 1885 /////////////////////// 1886 // NOTE(rnp): User API 1887 1888 DEBUG_IMPORT void 1889 vk_load(OSLibrary vulkan_library_handle, Stream *err) 1890 { 1891 #define X(name, ...) name = (name##_fn *)os_lookup_symbol(vulkan_library_handle, #name); 1892 VkLoaderProcedureList 1893 #undef X 1894 1895 if (!vkGetInstanceProcAddr) { 1896 stream_append_str8(err, vulkan_info("fatal error: failed to find \"vkGetInstanceProcAddr\"\n")); 1897 fatal(stream_to_str8(err)); 1898 } 1899 1900 VulkanContext *vk = vulkan_context; 1901 vk->arena = arena_create(.name = "Vulkan Arena"); 1902 vk->entity_arena = arena_create(.name = "Vulkan Entity Arena"); 1903 1904 vk_load_instance(vk->arena, err); 1905 vk_load_physical_device(vk->arena, err); 1906 vk_load_queues(vk->arena, err); 1907 vk_load_graphics(); 1908 vk_load_descriptor_block(); 1909 1910 read_only local_persist str8 default_compute_shader = str8("" 1911 "#version 430 core\n" 1912 "layout(push_constant) uniform pc { uint data[256 / 4]; };\n" 1913 "void main() {}\n" 1914 "\n"); 1915 VulkanPipelineCreateInfo compute_create_info = {.text = default_compute_shader, .name = str8("error_compute_shader")}; 1916 vk->default_compute_pipeline = vk_compute_pipeline_from_info(vk->arena, &compute_create_info, 256); 1917 1918 read_only local_persist str8 default_vertex_shader = str8("" 1919 "#version 430 core\n" 1920 "layout(push_constant) uniform pc { uint data[256 / 4]; };\n" 1921 "void main() {gl_Position = vec4(0);}\n" 1922 "\n"); 1923 read_only local_persist str8 default_fragment_shader = str8("" 1924 "#version 430 core\n" 1925 "layout(location = 0) out vec4 out_colour;" 1926 "layout(push_constant) uniform pc { uint data[256 / 4]; };\n" 1927 "void main() {out_colour = vec4(0.5f, 0.0f, 0.5f, 1.0f);}\n" 1928 "\n"); 1929 1930 VulkanPipelineCreateInfo pipeline_create_infos[2] = { 1931 { 1932 .kind = VulkanShaderKind_Vertex, 1933 .text = default_vertex_shader, 1934 .name = str8("error_vertex_shader"), 1935 }, 1936 { 1937 .kind = VulkanShaderKind_Fragment, 1938 .text = default_fragment_shader, 1939 .name = str8("error_fragment_shader"), 1940 }, 1941 }; 1942 vk->default_graphics_pipeline = vk_graphics_pipeline_from_infos(vk->arena, pipeline_create_infos, 2, 256); 1943 1944 // TODO: setup ui render pipeline 1945 1946 if (err->widx > 0) { 1947 os_console_log(err->data, err->widx); 1948 stream_reset(err, 0); 1949 } 1950 } 1951 1952 DEBUG_IMPORT GPUInfo * 1953 vk_gpu_info(void) 1954 { 1955 return &vulkan_context->gpu_info; 1956 } 1957 1958 function void 1959 vk_vulkan_buffer_release(VulkanBuffer *vb) 1960 { 1961 VulkanContext *vk = vulkan_context; 1962 VulkanEntity *e = (VulkanEntity *)((u8 *)vb - offsetof(VulkanEntity, as)); 1963 // TODO(rnp): this happens implicitly, probably just delete this if block 1964 if (vb->host_pointer) 1965 vkUnmapMemory(vk->device, vb->memory); 1966 1967 if (vb->buffer) 1968 vkDestroyBuffer(vk->device, vb->buffer, 0); 1969 1970 vk_release_memory(vb->memory, vb->memory_kind != VulkanMemoryKind_Host ? vb->memory_size : 0); 1971 vk_entity_release(e); 1972 } 1973 1974 DEBUG_IMPORT void 1975 vk_buffer_release(GPUBuffer *b) 1976 { 1977 if ValidVulkanHandle(b->handle) 1978 vk_vulkan_buffer_release(vk_entity_data(b->handle, VulkanEntityKind_Buffer)); 1979 zero_struct(b); 1980 } 1981 1982 DEBUG_IMPORT void 1983 vk_buffer_allocate(GPUBuffer *b, GPUBufferAllocateInfo *info) 1984 { 1985 VulkanContext *vk = vulkan_context; 1986 1987 vk_buffer_release(b); 1988 1989 assert(info->size > 0); 1990 1991 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Buffer); 1992 VulkanBufferAllocateInfo vulkan_buffer_allocate_info = { 1993 .gpu_buffer = b, 1994 .size = (u64)info->size, 1995 .flags = info->flags, 1996 .index_type = VK_INDEX_TYPE_NONE_KHR, 1997 .label = info->label, 1998 .export = info->export, 1999 }; 2000 2001 u32 queue_index_hit_count[VulkanQueueKind_Count] = {0}; 2002 for (u32 it = 0; it < info->timeline_count; it++) 2003 queue_index_hit_count[vk->queue_indices[info->timelines_used[it]]]++; 2004 2005 for EachElement(queue_index_hit_count, it) { 2006 if (queue_index_hit_count[it] > 0) { 2007 u32 index = vulkan_buffer_allocate_info.queue_family_count++; 2008 vulkan_buffer_allocate_info.queue_family_indices[index] = vk->queues[vk->queue_indices[it]]->queue_family; 2009 } 2010 } 2011 2012 if (vk_buffer_allocate_common(&e->as.buffer, &vulkan_buffer_allocate_info)) { 2013 b->handle.value[0] = (u64)e; 2014 } else { 2015 vk_entity_release(e); 2016 } 2017 } 2018 2019 DEBUG_IMPORT b32 2020 vk_buffer_needs_sync(GPUBuffer *b) 2021 { 2022 b32 result = 0; 2023 if ValidVulkanHandle(b->handle) { 2024 VulkanBuffer *vb = vk_entity_data(b->handle, VulkanEntityKind_Buffer); 2025 2026 // TODO(rnp): not correct check. need to check if we used transfer queue 2027 result = vb->memory_kind != VulkanMemoryKind_BAR; 2028 } 2029 2030 return result; 2031 } 2032 2033 DEBUG_IMPORT u64 2034 vk_round_up_to_sync_size(u64 size, u64 min) 2035 { 2036 i64 round = (i64)Max(min, vulkan_context->memory_info.non_coherent_atom_size); 2037 u64 result = (u64)round_up_to((i64)size, round); 2038 return result; 2039 } 2040 2041 function force_inline void 2042 vk_buffer_buffer_copy(VulkanBuffer *destination, VulkanBuffer *source, u64 destination_offset, u64 source_offset, u64 size, b32 non_temporal) 2043 { 2044 VulkanContext *vk = vulkan_context; 2045 2046 switch (source->memory_kind) { 2047 case VulkanMemoryKind_BAR: 2048 { 2049 switch (destination->memory_kind) { 2050 case VulkanMemoryKind_Host:{ 2051 if (destination->memory) { 2052 // TODO(rnp): there is likely a more efficient way of doing this in this case 2053 InvalidCodePath; 2054 } else { 2055 assert(source->host_pointer); 2056 b32 coherent = vk->memory_info.memory_host_coherent[source->memory_kind]; 2057 if (!coherent) { 2058 u64 nca_size = vk->memory_info.non_coherent_atom_size; 2059 VkMappedMemoryRange mrs[1] = {{ 2060 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 2061 .memory = source->memory, 2062 .offset = source_offset - (source_offset % nca_size), 2063 .size = vk_round_up_to_sync_size(size, nca_size), 2064 }}; 2065 vkInvalidateMappedMemoryRanges(vk->device, countof(mrs), mrs); 2066 } 2067 2068 void *dest = (u8 *)destination->host_pointer + destination_offset; 2069 void *src = (u8 *)source->host_pointer + source_offset; 2070 2071 // NOTE(rnp): don't trash the CPU cache for large data stores 2072 if (non_temporal) memory_copy_non_temporal(dest, src, size); 2073 else memory_copy(dest, src, size); 2074 } 2075 }break; 2076 InvalidDefaultCase; 2077 } 2078 }break; 2079 2080 case VulkanMemoryKind_Host:{ 2081 switch (destination->memory_kind) { 2082 case VulkanMemoryKind_BAR:{ 2083 assert(destination->host_pointer); 2084 2085 void *dest = (u8 *)destination->host_pointer + destination_offset; 2086 void *src = (u8 *)source->host_pointer + source_offset; 2087 2088 // NOTE(rnp): don't trash the CPU cache for large data stores 2089 if (non_temporal) memory_copy_non_temporal(dest, src, size); 2090 else memory_copy(dest, src, size); 2091 2092 b32 coherent = vk->memory_info.memory_host_coherent[destination->memory_kind]; 2093 if (!coherent) { 2094 u64 nca_size = vk->memory_info.non_coherent_atom_size; 2095 VkMappedMemoryRange mrs[1] = {{ 2096 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 2097 .memory = destination->memory, 2098 .offset = destination_offset - (destination_offset % nca_size), 2099 .size = vk_round_up_to_sync_size(size, nca_size), 2100 }}; 2101 vkFlushMappedMemoryRanges(vk->device, countof(mrs), mrs); 2102 } 2103 }break; 2104 InvalidDefaultCase; 2105 2106 } 2107 }break; 2108 2109 // TODO(rnp): use transfer queue when not mapped 2110 InvalidDefaultCase; 2111 } 2112 } 2113 2114 DEBUG_IMPORT void 2115 vk_buffer_range_upload(GPUBuffer *b, void *data, u64 offset, u64 size, b32 non_temporal) 2116 { 2117 VulkanBuffer *db = vk_entity_data(b->handle, VulkanEntityKind_Buffer); 2118 VulkanBuffer sb = { 2119 .host_pointer = data, 2120 .memory_kind = VulkanMemoryKind_Host, 2121 }; 2122 vk_buffer_buffer_copy(db, &sb, offset, 0, size, non_temporal); 2123 } 2124 2125 DEBUG_IMPORT void 2126 vk_buffer_range_download(void *destination, GPUBuffer *source, u64 offset, u64 size, b32 non_temporal) 2127 { 2128 VulkanBuffer *sb = vk_entity_data(source->handle, VulkanEntityKind_Buffer); 2129 VulkanBuffer db = { 2130 .host_pointer = destination, 2131 .memory_kind = VulkanMemoryKind_Host, 2132 }; 2133 vk_buffer_buffer_copy(&db, sb, 0, offset, size, non_temporal); 2134 } 2135 2136 DEBUG_IMPORT void 2137 vk_render_model_release(GPUBuffer *model) 2138 { 2139 if ValidVulkanHandle(model->handle) 2140 vk_vulkan_buffer_release(vk_entity_data(model->handle, VulkanEntityKind_RenderModel)); 2141 zero_struct(model); 2142 } 2143 2144 DEBUG_IMPORT void 2145 vk_render_model_allocate(GPUBuffer *model, void *indices, u64 index_count, u64 model_size, str8 label) 2146 { 2147 vk_render_model_release(model); 2148 2149 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_RenderModel); 2150 2151 assert(index_count <= U32_MAX); 2152 VkIndexType index_type; 2153 if (index_count <= U16_MAX) index_type = VK_INDEX_TYPE_UINT16; 2154 else index_type = VK_INDEX_TYPE_UINT32; 2155 2156 i64 indices_size = round_up_to(vk_index_size(index_type) * index_count, 64); 2157 2158 i64 size = round_up_to(model_size + indices_size, 64); 2159 assert(size > 0); 2160 2161 VulkanBufferAllocateInfo vulkan_buffer_allocate_info = { 2162 .gpu_buffer = model, 2163 .size = (u64)size, 2164 .flags = VulkanUsageFlag_HostReadWrite, 2165 .index_type = index_type, 2166 .label = label, 2167 .queue_family_count = 1, 2168 .queue_family_indices[0] = vulkan_context->queues[VulkanQueueKind_Graphics]->queue_family, 2169 }; 2170 if (vk_buffer_allocate_common(&e->as.buffer, &vulkan_buffer_allocate_info)) { 2171 model->handle.value[0] = (u64)e; 2172 model->index_count = index_count; 2173 model->gpu_pointer += indices_size; 2174 2175 VulkanBuffer sb = { 2176 .host_pointer = indices, 2177 .memory_kind = VulkanMemoryKind_Host, 2178 }; 2179 2180 vk_buffer_buffer_copy(&e->as.buffer, &sb, 0, 0, vk_index_size(index_type) * index_count, 0); 2181 } else { 2182 vk_entity_release(e); 2183 } 2184 } 2185 2186 DEBUG_IMPORT void 2187 vk_render_model_range_upload(GPUBuffer *model, void *data, u64 offset, u64 size, b32 non_temporal) 2188 { 2189 VulkanBuffer *db = vk_entity_data(model->handle, VulkanEntityKind_RenderModel); 2190 VulkanBuffer sb = { 2191 .host_pointer = data, 2192 .memory_kind = VulkanMemoryKind_Host, 2193 }; 2194 2195 offset += round_up_to(vk_index_size(db->index_type) * model->index_count, 64); 2196 2197 vk_buffer_buffer_copy(db, &sb, offset, 0, size, non_temporal); 2198 } 2199 2200 DEBUG_IMPORT void 2201 vk_image_release(GPUImage *image) 2202 { 2203 if ValidVulkanHandle(image->image) { 2204 VulkanContext *vk = vulkan_context; 2205 VulkanImage *vi = vk_entity_data(image->image, VulkanEntityKind_Image); 2206 2207 vkDestroyImageView(vk->device, vi->view, 0); 2208 vkDestroyImage(vk->device, vi->image, 0); 2209 vk_release_memory(vi->memory, image->memory_size); 2210 2211 vk_entity_release((VulkanEntity *)image->image.value[0]); 2212 } 2213 zero_struct(image); 2214 } 2215 2216 DEBUG_IMPORT void 2217 vk_image_allocate(GPUImage *image, u32 width, u32 height, u32 mips, u32 samples, 2218 VulkanImageUsage usage, VulkanUsageFlags flags, OSHandle *export, str8 label) 2219 { 2220 assert(IsPowerOfTwo(samples)); 2221 2222 vk_image_release(image); 2223 2224 VulkanContext *vk = vulkan_context; 2225 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Image); 2226 VulkanImage *vi = &e->as.image; 2227 2228 image->image.value[0] = (u64)e; 2229 image->width = Min(width, vk->gpu_info.max_image_dimension_2D); 2230 image->height = Min(height, vk->gpu_info.max_image_dimension_2D); 2231 image->mip_map_levels = Max(mips, 1); 2232 image->samples = Min(samples, vk->gpu_info.max_msaa_samples); 2233 2234 VkFormat usage_format_map[VulkanImageUsage_Count + 1] = { 2235 [VulkanImageUsage_None] = VK_FORMAT_UNDEFINED, 2236 //[VulkanImageUsage_Colour] = VK_FORMAT_R8G8B8A8_SRGB, 2237 [VulkanImageUsage_Colour] = VK_FORMAT_R8G8B8A8_UNORM, 2238 [VulkanImageUsage_DepthStencil] = vk->depth_stencil_format, 2239 [VulkanImageUsage_Count] = VK_FORMAT_UNDEFINED, 2240 }; 2241 2242 read_only local_persist VkImageUsageFlagBits usage_extra_bit_map[VulkanImageUsage_Count + 1] = { 2243 [VulkanImageUsage_None] = 0, 2244 [VulkanImageUsage_Colour] = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 2245 [VulkanImageUsage_DepthStencil] = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 2246 [VulkanImageUsage_Count] = 0, 2247 }; 2248 2249 read_only local_persist VkImageAspectFlags usage_image_aspect_map[VulkanImageUsage_Count + 1] = { 2250 [VulkanImageUsage_None] = 0, 2251 [VulkanImageUsage_Colour] = VK_IMAGE_ASPECT_COLOR_BIT, 2252 [VulkanImageUsage_DepthStencil] = VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT, 2253 [VulkanImageUsage_Count] = 0, 2254 }; 2255 2256 usage = Clamp((u32)usage, 0, VulkanImageUsage_Count); 2257 VkImageUsageFlagBits usage_flags = usage_extra_bit_map[usage]; 2258 2259 if (flags & VulkanUsageFlag_ImageSampling) usage_flags |= VK_IMAGE_USAGE_SAMPLED_BIT; 2260 if (flags & VulkanUsageFlag_TransferSource) usage_flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; 2261 if (flags & VulkanUsageFlag_TransferDestination) usage_flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; 2262 2263 u32 queue_family = vk->queues[VulkanQueueKind_Graphics]->queue_family; 2264 VkImageCreateInfo image_create_info = { 2265 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 2266 .flags = export ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0, 2267 .imageType = VK_IMAGE_TYPE_2D, 2268 .format = usage_format_map[usage], 2269 .extent = {image->width, image->height, 1}, 2270 .mipLevels = image->mip_map_levels, 2271 .arrayLayers = 1, 2272 .samples = image->samples, 2273 .tiling = VK_IMAGE_TILING_OPTIMAL, 2274 .usage = usage_flags, 2275 // NOTE(rnp): needed if multiple queue families are accessed 2276 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 2277 .queueFamilyIndexCount = 1, 2278 .pQueueFamilyIndices = &queue_family, 2279 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2280 }; 2281 2282 VkExternalMemoryImageCreateInfo external_memory_image_create_info = { 2283 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, 2284 .handleTypes = OS_WINDOWS ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT 2285 : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, 2286 }; 2287 2288 if (export) image_create_info.pNext = &external_memory_image_create_info; 2289 2290 vkCreateImage(vk->device, &image_create_info, 0, &vi->image); 2291 2292 VkMemoryRequirements memory_requirements; 2293 vkGetImageMemoryRequirements(vk->device, vi->image, &memory_requirements); 2294 2295 VkMemoryDedicatedAllocateInfo dedicated_allocate_info = { 2296 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, 2297 .image = vi->image, 2298 }; 2299 2300 if (vk_allocate_memory(&vi->memory, memory_requirements.size, VulkanMemoryKind_Device, 0, &dedicated_allocate_info, export)) { 2301 image->memory_size = memory_requirements.size; 2302 vkBindImageMemory(vk->device, vi->image, vi->memory, 0); 2303 2304 VkImageViewCreateInfo image_view_info = { 2305 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 2306 .image = vi->image, 2307 .viewType = VK_IMAGE_VIEW_TYPE_2D, 2308 .format = usage_format_map[usage], 2309 .subresourceRange = { 2310 .aspectMask = usage_image_aspect_map[usage], 2311 .baseMipLevel = 0, 2312 .levelCount = 1, 2313 .baseArrayLayer = 0, 2314 .layerCount = 1, 2315 }, 2316 }; 2317 vkCreateImageView(vk->device, &image_view_info, 0, &vi->view); 2318 2319 vk_label_object(IMAGE, vi->image, label, str8("Image")); 2320 vk_label_object(IMAGE_VIEW, vi->view, label, str8("Image View")); 2321 vk_label_object(DEVICE_MEMORY, vi->memory, label, str8("Memory")); 2322 } else { 2323 vkDestroyImage(vk->device, vi->image, 0); 2324 vk_entity_release(e); 2325 zero_struct(image); 2326 } 2327 } 2328 2329 DEBUG_IMPORT VulkanHandle 2330 vk_create_semaphore(OSHandle *export) 2331 { 2332 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Semaphore); 2333 e->as.semaphore = vk_make_semaphore(export); 2334 VulkanHandle result = {(u64)e}; 2335 return result; 2336 } 2337 2338 DEBUG_IMPORT b32 2339 vk_host_wait_timeline(VulkanTimeline timeline, u64 value, u64 timeout_ns) 2340 { 2341 b32 result = 0; 2342 if Between(timeline, 0, VulkanTimeline_Count - 1) { 2343 VulkanContext *vk = vulkan_context; 2344 VulkanQueue *vq = vk->queues[timeline]; 2345 VkSemaphoreWaitInfo semaphore_wait_info = { 2346 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, 2347 .pSemaphores = &vq->timeline_semaphore.semaphore, 2348 .semaphoreCount = 1, 2349 .pValues = &value, 2350 }; 2351 result = vkWaitSemaphores(vk->device, &semaphore_wait_info, timeout_ns) == VK_SUCCESS; 2352 } 2353 return result; 2354 } 2355 2356 DEBUG_IMPORT u64 2357 vk_host_signal_timeline(VulkanTimeline timeline) 2358 { 2359 u64 result = -1; 2360 if Between(timeline, 0, VulkanTimeline_Count - 1) { 2361 VulkanContext *vk = vulkan_context; 2362 VulkanQueue *vq = vk->queues[timeline]; 2363 VulkanSemaphore *vs = &vq->timeline_semaphore; 2364 result = ++vs->value; 2365 VkSemaphoreSignalInfo ssi = { 2366 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, 2367 .semaphore = vs->semaphore, 2368 .value = result, 2369 }; 2370 vkSignalSemaphore(vk->device, &ssi); 2371 } 2372 return result; 2373 } 2374 2375 DEBUG_IMPORT VulkanHandle 2376 vk_pipeline(VulkanPipelineCreateInfo *infos, u32 count, u32 push_constants_size) 2377 { 2378 assert(Between(count, 1, 2)); 2379 assert(count == 2 || infos[0].kind == VulkanShaderKind_Compute); 2380 2381 VulkanHandle result = {0}; 2382 Temp scratch; 2383 DeferLoop(take_lock(&vulkan_context->arena_lock, -1), release_lock(&vulkan_context->arena_lock)) 2384 DeferLoop(scratch = temp_begin(vulkan_context->arena), temp_end(scratch)) 2385 { 2386 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Pipeline); 2387 result = (VulkanHandle){(u64)e}; 2388 2389 if (count == 2) e->as.pipeline = vk_graphics_pipeline_from_infos(scratch.arena, infos, count, push_constants_size); 2390 else e->as.pipeline = vk_compute_pipeline_from_info(scratch.arena, infos, push_constants_size); 2391 } 2392 return result; 2393 } 2394 2395 DEBUG_IMPORT b32 2396 vk_pipeline_valid(VulkanHandle h) 2397 { 2398 b32 result = 0; 2399 if ValidVulkanHandle(h) { 2400 VulkanPipeline *vp = vk_entity_data(h, VulkanEntityKind_Pipeline); 2401 if (vp->stage_flags == VK_SHADER_STAGE_COMPUTE_BIT) 2402 result = vp->pipeline != vulkan_context->default_compute_pipeline.pipeline; 2403 else 2404 result = vp->pipeline != vulkan_context->default_graphics_pipeline.pipeline; 2405 } 2406 return result; 2407 } 2408 2409 DEBUG_IMPORT void 2410 vk_pipeline_release(VulkanHandle h) 2411 { 2412 if (vk_pipeline_valid(h)) { 2413 VulkanEntity *e = (VulkanEntity *)h.value[0]; 2414 VulkanTimeline timeline; 2415 if (e->as.pipeline.stage_flags == VK_SHADER_STAGE_COMPUTE_BIT) timeline = VulkanTimeline_Compute; 2416 else timeline = VulkanTimeline_Graphics; 2417 2418 // NOTE(rnp): block more command buffers from being recorded 2419 VulkanCommandPool *vcp = vulkan_context->command_pools[timeline]; 2420 DeferLoop(take_lock(&vcp->lock, -1), release_lock(&vcp->lock)) { 2421 u32 index = (vcp->next_index - 1) % countof(vcp->buffers); 2422 vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL); 2423 vkDestroyPipeline(vulkan_context->device, e->as.pipeline.pipeline, 0); 2424 vkDestroyPipelineLayout(vulkan_context->device, e->as.pipeline.layout, 0); 2425 2426 if (&e->as.pipeline == vcp->bound_pipeline) 2427 vcp->bound_pipeline = 0; 2428 } 2429 vk_entity_release(e); 2430 } 2431 } 2432 2433 DEBUG_IMPORT void 2434 vk_bind_shader_resources(BeamformerShaderResourceInfo *infos, u64 info_count) 2435 { 2436 VulkanContext *vk = vulkan_context; 2437 2438 VkWriteDescriptorSet write_sets[BeamformerShaderResourceKind_Count] = {0}; 2439 2440 for EachIndex(info_count, it) { 2441 switch (infos[it].kind) { 2442 case BeamformerShaderResourceKind_Buffer:{ 2443 VulkanBuffer *vb = vk_entity_data(infos[it].handle, VulkanEntityKind_Buffer); 2444 vk->descriptor_buffer_infos[infos[it].slot].buffer = vb->buffer; 2445 vk->descriptor_buffer_infos[infos[it].slot].offset = 0; 2446 vk->descriptor_buffer_infos[infos[it].slot].range = vb->memory_size; 2447 }break; 2448 2449 InvalidDefaultCase; 2450 } 2451 } 2452 2453 write_sets[BeamformerShaderResourceKind_Buffer].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 2454 write_sets[BeamformerShaderResourceKind_Buffer].dstSet = vk->descriptor_sets[BeamformerShaderResourceKind_Buffer]; 2455 write_sets[BeamformerShaderResourceKind_Buffer].dstBinding = 0; 2456 write_sets[BeamformerShaderResourceKind_Buffer].descriptorCount = countof(vk->descriptor_buffer_infos); 2457 write_sets[BeamformerShaderResourceKind_Buffer].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 2458 write_sets[BeamformerShaderResourceKind_Buffer].pBufferInfo = vk->descriptor_buffer_infos; 2459 2460 vkUpdateDescriptorSets(vk->device, countof(write_sets), write_sets, 0, 0); 2461 } 2462 2463 DEBUG_IMPORT VulkanHandle 2464 vk_command_begin(VulkanTimeline timeline) 2465 { 2466 VulkanHandle result = {0}; 2467 if Between(timeline, 0, VulkanTimeline_Count - 1) { 2468 VulkanContext *vk = vulkan_context; 2469 VulkanCommandPool *vcp = vk->command_pools[timeline]; 2470 2471 take_lock(&vcp->lock, -1); 2472 2473 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_CommandBuffer); 2474 VulkanCommandBuffer *vcb = &e->as.command_buffer; 2475 vcb->timeline = timeline; 2476 vcb->buffer_index = vcp->next_index++ % countof(vcp->buffers); 2477 2478 u32 index = vcb->buffer_index; 2479 // TODO(rnp): probably not the best to have this here but it will likely not be hit 2480 b32 wait_result = vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL); 2481 assert(wait_result); 2482 2483 vcp->queries_occupied[index] = 0; 2484 2485 VkCommandBufferBeginInfo buffer_begin_info = { 2486 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 2487 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 2488 }; 2489 2490 vkBeginCommandBuffer(vcp->buffers[index], &buffer_begin_info); 2491 vkCmdResetQueryPool(vcp->buffers[index], vcp->query_pool, index * MaxCommandBufferTimestamps, 2492 MaxCommandBufferTimestamps); 2493 2494 result = (VulkanHandle){(u64)e}; 2495 } 2496 return result; 2497 } 2498 2499 DEBUG_IMPORT void 2500 vk_command_bind_pipeline(VulkanHandle command, VulkanHandle pipeline) 2501 { 2502 if ValidVulkanHandle(command) { 2503 VulkanContext *vk = vulkan_context; 2504 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2505 VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; 2506 2507 VulkanPipeline *vp = 0; 2508 if ValidVulkanHandle(pipeline) { 2509 vp = vk_entity_data(pipeline, VulkanEntityKind_Pipeline); 2510 } else if (vcb->timeline == VulkanTimeline_Compute) { 2511 vp = &vk->default_compute_pipeline; 2512 } else if (vcb->timeline == VulkanTimeline_Graphics) { 2513 vp = &vk->default_graphics_pipeline; 2514 } else { 2515 InvalidCodePath; 2516 } 2517 2518 read_only local_persist VkPipelineBindPoint bind_point_lut[VulkanTimeline_Count] = { 2519 [VulkanTimeline_Graphics] = VK_PIPELINE_BIND_POINT_GRAPHICS, 2520 [VulkanTimeline_Compute] = VK_PIPELINE_BIND_POINT_COMPUTE, 2521 [VulkanTimeline_Transfer] = -1, 2522 }; 2523 2524 VkPipelineBindPoint bind_point = bind_point_lut[vcb->timeline]; 2525 assert(bind_point != (VkPipelineBindPoint)-1); 2526 2527 vkCmdBindPipeline(vcp->buffers[vcb->buffer_index], bind_point, vp->pipeline); 2528 vkCmdBindDescriptorSets(vcp->buffers[vcb->buffer_index], bind_point, vp->layout, 2529 0, countof(vk->descriptor_sets), vk->descriptor_sets, 0, 0); 2530 vcp->bound_pipeline = vp; 2531 } 2532 } 2533 2534 DEBUG_IMPORT void 2535 vk_command_buffer_memory_barriers(VulkanHandle command, GPUMemoryBarrierInfo *barriers, u64 count) 2536 { 2537 if ValidVulkanHandle(command) { 2538 VulkanContext *vk = vulkan_context; 2539 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2540 VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; 2541 VulkanQueue *vq = vk->queues[vcb->timeline]; 2542 2543 Temp scratch; 2544 DeferLoop(take_lock(&vk->arena_lock, -1), release_lock(&vk->arena_lock)) 2545 DeferLoop(scratch = temp_begin(vk->arena), temp_end(scratch)) 2546 { 2547 u32 valid_count = 0; 2548 VkBufferMemoryBarrier2 *memory_barriers = push_array(vk->arena, VkBufferMemoryBarrier2, count); 2549 for (u64 it = 0; it < count; it++) { 2550 if ValidVulkanHandle(barriers[it].gpu_buffer->handle) { 2551 u32 index = valid_count++; 2552 VulkanBuffer *vb = vk_entity_data(barriers[it].gpu_buffer->handle, VulkanEntityKind_Buffer); 2553 memory_barriers[index].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2; 2554 memory_barriers[index].srcStageMask = vq->pipeline_stage_flags; 2555 memory_barriers[index].srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT; 2556 memory_barriers[index].dstStageMask = vq->pipeline_stage_flags; 2557 memory_barriers[index].dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT; 2558 memory_barriers[index].srcQueueFamilyIndex = vq->queue_family; 2559 memory_barriers[index].dstQueueFamilyIndex = vq->queue_family; 2560 memory_barriers[index].buffer = vb->buffer; 2561 memory_barriers[index].offset = barriers[it].offset; 2562 memory_barriers[index].size = barriers[it].size; 2563 } 2564 } 2565 2566 VkDependencyInfo dependancy_info = { 2567 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, 2568 .bufferMemoryBarrierCount = valid_count, 2569 .pBufferMemoryBarriers = memory_barriers, 2570 }; 2571 2572 vkCmdPipelineBarrier2(vcp->buffers[vcb->buffer_index], &dependancy_info); 2573 } 2574 } 2575 } 2576 2577 DEBUG_IMPORT void 2578 vk_command_clear_buffer(VulkanHandle command, GPUBuffer *buffer, u64 offset, u64 size, u32 clear_word) 2579 { 2580 assert((offset % 4) == 0); 2581 assert((size % 4) == 0); 2582 if ValidVulkanHandle(command) { 2583 VulkanBuffer *vb = vk_entity_data(buffer->handle, VulkanEntityKind_Buffer); 2584 VkCommandBuffer cmd = vk_command_buffer(command); 2585 vkCmdFillBuffer(cmd, vb->buffer, offset, size, clear_word); 2586 } 2587 } 2588 2589 DEBUG_IMPORT void 2590 vk_command_dispatch_compute(VulkanHandle command, uv3 dispatch) 2591 { 2592 assert(dispatch.x <= U16_MAX); 2593 assert(dispatch.y <= U16_MAX); 2594 assert(dispatch.z <= U16_MAX); 2595 if ValidVulkanHandle(command) { 2596 VkCommandBuffer cmd = vk_command_buffer(command); 2597 vkCmdDispatch(cmd, dispatch.x, dispatch.y, dispatch.z); 2598 } 2599 } 2600 2601 DEBUG_IMPORT void 2602 vk_command_push_constants(VulkanHandle command, u32 offset, u32 size, void *values) 2603 { 2604 if ValidVulkanHandle(command) { 2605 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2606 VulkanCommandPool *vcp = vulkan_context->command_pools[vcb->timeline]; 2607 VulkanPipeline *vp = vcp->bound_pipeline; 2608 2609 assert(vp); 2610 2611 vkCmdPushConstants(vcp->buffers[vcb->buffer_index], vp->layout, vp->stage_flags, offset, size, values); 2612 } 2613 } 2614 2615 DEBUG_IMPORT void 2616 vk_command_timestamp(VulkanHandle command) 2617 { 2618 if ValidVulkanHandle(command) { 2619 VulkanContext *vk = vulkan_context; 2620 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2621 VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; 2622 2623 read_only local_persist VkPipelineStageFlags2 stage_lut[VulkanTimeline_Count] = { 2624 [VulkanTimeline_Graphics] = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, 2625 [VulkanTimeline_Compute] = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, 2626 [VulkanTimeline_Transfer] = -1, 2627 }; 2628 2629 VkPipelineStageFlags2 stage = stage_lut[vcb->timeline]; 2630 assert(stage != (VkPipelineStageFlags2)-1); 2631 2632 if (vcp->queries_occupied[vcb->buffer_index] < MaxCommandBufferTimestamps) { 2633 u32 query_index = vcp->queries_occupied[vcb->buffer_index]++; 2634 vkCmdWriteTimestamp2(vcp->buffers[vcb->buffer_index], stage, vcp->query_pool, 2635 vcb->buffer_index * MaxCommandBufferTimestamps + query_index); 2636 } 2637 } 2638 } 2639 2640 DEBUG_IMPORT void 2641 vk_command_wait_timeline(VulkanHandle command, VulkanTimeline timeline, u64 value) 2642 { 2643 if (ValidVulkanHandle(command) && Between(timeline, 0, VulkanTimeline_Count - 1)) { 2644 VulkanContext *vk = vulkan_context; 2645 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2646 2647 u32 wait_index = vk->queue_indices[timeline]; 2648 vcb->in_flight_wait_values[wait_index] = Max(value, vcb->in_flight_wait_values[wait_index]); 2649 } 2650 } 2651 2652 DEBUG_IMPORT u64 2653 vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle finished_semaphore) 2654 { 2655 u64 result = -1; 2656 if ValidVulkanHandle(command) { 2657 VulkanContext *vk = vulkan_context; 2658 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2659 VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; 2660 VulkanQueue *vq = vk->queues[vcb->timeline]; 2661 VulkanSemaphore *vs = &vq->timeline_semaphore; 2662 2663 vkEndCommandBuffer(vcp->buffers[vcb->buffer_index]); 2664 2665 DeferLoop(take_lock(&vq->lock, -1), release_lock(&vq->lock)) { 2666 VkCommandBufferSubmitInfo command_buffer_submit_info = { 2667 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, 2668 .commandBuffer = vcp->buffers[vcb->buffer_index], 2669 }; 2670 2671 result = ++vs->value; 2672 2673 u32 signal_submit_info_count = 1; 2674 VkSemaphoreSubmitInfo signal_submit_infos[2] = {{ 2675 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, 2676 .semaphore = vs->semaphore, 2677 .value = result, 2678 .stageMask = vq->pipeline_stage_flags, 2679 }}; 2680 2681 if ValidVulkanHandle(finished_semaphore) { 2682 VulkanSemaphore *fs = vk_entity_data(finished_semaphore, VulkanEntityKind_Semaphore); 2683 signal_submit_infos[signal_submit_info_count++] = (VkSemaphoreSubmitInfo){ 2684 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, 2685 .semaphore = fs->semaphore, 2686 .stageMask = vq->pipeline_stage_flags, 2687 }; 2688 } 2689 2690 u32 wait_submit_info_count = 0; 2691 VkSemaphoreSubmitInfo wait_submit_infos[VulkanQueueKind_Count + 1]; 2692 for (u32 i = 0; i < vk->unique_queues; i++) { 2693 u32 queue_index = vk->queue_indices[i]; 2694 if (vcb->in_flight_wait_values[queue_index] > 0) { 2695 VulkanQueue *q = vk->queues[queue_index]; 2696 VkSemaphoreSubmitInfo wait_ssi = { 2697 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, 2698 .semaphore = q->timeline_semaphore.semaphore, 2699 .value = vcb->in_flight_wait_values[queue_index], 2700 .stageMask = q->pipeline_stage_flags, 2701 }; 2702 wait_submit_infos[wait_submit_info_count++] = wait_ssi; 2703 } 2704 } 2705 2706 if ValidVulkanHandle(wait_semaphore) { 2707 VulkanSemaphore *ws = vk_entity_data(wait_semaphore, VulkanEntityKind_Semaphore); 2708 wait_submit_infos[wait_submit_info_count++] = (VkSemaphoreSubmitInfo){ 2709 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, 2710 .semaphore = ws->semaphore, 2711 .stageMask = vq->pipeline_stage_flags, 2712 }; 2713 } 2714 2715 VkSubmitInfo2 submit_info = { 2716 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, 2717 .commandBufferInfoCount = 1, 2718 .pCommandBufferInfos = &command_buffer_submit_info, 2719 .waitSemaphoreInfoCount = wait_submit_info_count, 2720 .pWaitSemaphoreInfos = wait_submit_infos, 2721 .signalSemaphoreInfoCount = signal_submit_info_count, 2722 .pSignalSemaphoreInfos = signal_submit_infos, 2723 }; 2724 2725 vkQueueSubmit2(vq->queue, 1, &submit_info, 0); 2726 2727 vcp->bound_pipeline = 0; 2728 2729 atomic_store_u64(vcp->submission_values + vcb->buffer_index, result); 2730 } 2731 2732 release_lock(&vcp->lock); 2733 2734 vk_entity_release((VulkanEntity *)command.value[0]); 2735 } 2736 return result; 2737 } 2738 2739 DEBUG_IMPORT void 2740 vk_command_begin_rendering(VulkanHandle command, GPUImage *colour, GPUImage *depth, GPUImage *resolve) 2741 { 2742 if ValidVulkanHandle(command) { 2743 VkCommandBuffer cmd = vk_command_buffer(command); 2744 2745 assert((colour->width == depth->width) && (colour->height == depth->height)); 2746 2747 VulkanImage *ci = vk_entity_data(colour->image, VulkanEntityKind_Image); 2748 VulkanImage *di = vk_entity_data(depth->image, VulkanEntityKind_Image); 2749 VulkanImage *ri = 0; 2750 if (resolve) ri = vk_entity_data(resolve->image, VulkanEntityKind_Image); 2751 2752 // NOTE: Layout Transitions 2753 { 2754 u32 image_memory_barrier_count = 2; 2755 VkImageMemoryBarrier2 image_memory_barriers[3] = { 2756 { 2757 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, 2758 .srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, 2759 .srcAccessMask = 0, 2760 .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, 2761 .dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT|VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, 2762 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2763 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 2764 .image = ci->image, 2765 .subresourceRange = { 2766 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 2767 .baseMipLevel = 0, 2768 .levelCount = 1, 2769 .baseArrayLayer = 0, 2770 .layerCount = 1, 2771 }, 2772 }, 2773 { 2774 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, 2775 .srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, 2776 .srcAccessMask = 0, 2777 .dstStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, 2778 .dstAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 2779 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2780 .newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 2781 .image = di->image, 2782 .subresourceRange = { 2783 .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT, 2784 .baseMipLevel = 0, 2785 .levelCount = 1, 2786 .baseArrayLayer = 0, 2787 .layerCount = 1, 2788 }, 2789 }, 2790 }; 2791 2792 if (resolve) image_memory_barriers[image_memory_barrier_count++] = (VkImageMemoryBarrier2){ 2793 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, 2794 .srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, 2795 .srcAccessMask = 0, 2796 .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT|VK_PIPELINE_STAGE_2_RESOLVE_BIT, 2797 .dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT|VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, 2798 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2799 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 2800 .image = ri->image, 2801 .subresourceRange = { 2802 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 2803 .baseMipLevel = 0, 2804 .levelCount = 1, 2805 .baseArrayLayer = 0, 2806 .layerCount = 1, 2807 }, 2808 }; 2809 2810 VkDependencyInfo dependency_info = { 2811 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, 2812 .imageMemoryBarrierCount = image_memory_barrier_count, 2813 .pImageMemoryBarriers = image_memory_barriers, 2814 }; 2815 2816 vkCmdPipelineBarrier2(cmd, &dependency_info); 2817 } 2818 2819 VkRenderingAttachmentInfo colour_attachment = { 2820 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, 2821 .imageView = ci->view, 2822 .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 2823 .resolveMode = ri ? VK_RESOLVE_MODE_AVERAGE_BIT : 0, 2824 .resolveImageView = ri ? ri->view : 0, 2825 .resolveImageLayout = ri ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : 0, 2826 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 2827 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 2828 .clearValue = {.color = {{0.0f, 0.0f, 0.0f, 0.0f}}}, 2829 }; 2830 2831 VkRenderingAttachmentInfo depth_stencil_attachment = { 2832 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, 2833 .imageView = di->view, 2834 .imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 2835 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 2836 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 2837 .clearValue = {.depthStencil = {1.0f, 0}}, 2838 }; 2839 2840 VkRenderingInfo rendering_info = { 2841 .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, 2842 .renderArea = {.offset = {0}, .extent = {colour->width, colour->height}}, 2843 .layerCount = 1, 2844 .colorAttachmentCount = 1, 2845 .pColorAttachments = &colour_attachment, 2846 .pDepthAttachment = &depth_stencil_attachment, 2847 .pStencilAttachment = &depth_stencil_attachment, 2848 }; 2849 2850 vkCmdBeginRendering(cmd, &rendering_info); 2851 } 2852 } 2853 2854 DEBUG_IMPORT void 2855 vk_command_draw(VulkanHandle command, GPUBuffer *model) 2856 { 2857 if (ValidVulkanHandle(command) && ValidVulkanHandle(model->handle)) { 2858 VkCommandBuffer cmd = vk_command_buffer(command); 2859 VulkanBuffer *vb = vk_entity_data(model->handle, VulkanEntityKind_RenderModel); 2860 vkCmdBindIndexBuffer2(cmd, vb->buffer, 0, vk_index_size(vb->index_type) * model->index_count, vb->index_type); 2861 vkCmdDrawIndexed(cmd, model->index_count, 1, 0, 0, 0); 2862 } 2863 } 2864 2865 DEBUG_IMPORT void 2866 vk_command_scissor(VulkanHandle command, u32 width, u32 height, u32 x_offset, u32 y_offset) 2867 { 2868 if ValidVulkanHandle(command) { 2869 VkCommandBuffer cmd = vk_command_buffer(command); 2870 VkRect2D scissor = {.offset = {x_offset, y_offset}, .extent = {width, height}}; 2871 vkCmdSetScissor(cmd, 0, 1, &scissor); 2872 } 2873 } 2874 2875 DEBUG_IMPORT void 2876 vk_command_viewport(VulkanHandle command, f32 width, f32 height, f32 x_offset, f32 y_offset, f32 min_depth, f32 max_depth) 2877 { 2878 if ValidVulkanHandle(command) { 2879 VkCommandBuffer cmd = vk_command_buffer(command); 2880 VkViewport viewport = {x_offset, y_offset, width, height, min_depth, max_depth}; 2881 vkCmdSetViewport(cmd, 0, 1, &viewport); 2882 } 2883 } 2884 2885 DEBUG_IMPORT void 2886 vk_command_end_rendering(VulkanHandle command) 2887 { 2888 if ValidVulkanHandle(command) vkCmdEndRendering(vk_command_buffer(command)); 2889 } 2890 2891 DEBUG_IMPORT void 2892 vk_command_copy_buffer(VulkanHandle command, GPUBuffer *restrict destination, 2893 GPUBuffer *restrict source, u64 source_offset, i64 size) 2894 { 2895 if (ValidVulkanHandle(command) && ValidVulkanHandle(destination->handle) && ValidVulkanHandle(source->handle)) { 2896 VkCommandBuffer cmd = vk_command_buffer(command); 2897 VulkanBuffer *db = vk_entity_data(destination->handle, VulkanEntityKind_Buffer); 2898 VulkanBuffer *sb = vk_entity_data(source->handle, VulkanEntityKind_Buffer); 2899 2900 VkBufferCopy2 buffer_copy = { 2901 .sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2, 2902 .srcOffset = source_offset, 2903 .dstOffset = 0, 2904 .size = size, 2905 }; 2906 2907 VkCopyBufferInfo2 copy_buffer_info = { 2908 .sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, 2909 .srcBuffer = sb->buffer, 2910 .dstBuffer = db->buffer, 2911 .regionCount = 1, 2912 .pRegions = &buffer_copy, 2913 }; 2914 2915 vkCmdCopyBuffer2(cmd, ©_buffer_info); 2916 } 2917 } 2918 2919 DEBUG_IMPORT u64 * 2920 vk_command_read_timestamps(VulkanTimeline timeline, Arena *arena) 2921 { 2922 u64 *result = 0; 2923 if Between(timeline, 0, VulkanTimeline_Count - 1) { 2924 VulkanContext *vk = vulkan_context; 2925 VulkanCommandPool *vcp = vk->command_pools[timeline]; 2926 DeferLoop(take_lock(&vcp->lock, -1), release_lock(&vcp->lock)) { 2927 u32 index = (vcp->next_index - 1) % countof(vcp->buffers); 2928 u32 count = vcp->queries_occupied[index]; 2929 if (count > 0) { 2930 result = push_array(arena, u64, count + 1); 2931 result[0] = count; 2932 2933 vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL); 2934 2935 vkGetQueryPoolResults(vk->device, vcp->query_pool, index * MaxCommandBufferTimestamps, count, 2936 count * sizeof(u64), result + 1, 8, VK_QUERY_RESULT_WAIT_BIT); 2937 } 2938 } 2939 } else { 2940 result = push_array(arena, u64, 1); 2941 } 2942 return result; 2943 }