vulkan.c (104281B)
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 = arena_stream(arena_from_memory(buffer, sizeof(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_array_no_zero(&vulkan_context->entity_arena, VulkanEntity, 1); 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 #define X(name, ...) name = (name##_fn *)vkGetInstanceProcAddr(0, #name); 1068 VkBaseProcedureList 1069 #undef X 1070 1071 u32 enabled_validation_layers_count = 0; 1072 const char *enabled_validation_layers[countof(vk_validation_layers)]; 1073 1074 u32 enabled_instance_extensions_count = 0; 1075 const char *enabled_instance_extensions[countof(vk_required_instance_extensions) + countof(vk_instance_debug_extensions)]; 1076 1077 static_assert(countof(vk_required_instance_extensions) == 0, ""); 1078 //for EachElement(vk_required_instance_extensions, it) 1079 // enabled_instance_extensions[enabled_instance_extensions_count++] = vk_required_instance_extensions[it]; 1080 1081 #if BEAMFORMER_DEBUG 1082 { 1083 u32 layer_count = 0; 1084 vkEnumerateInstanceLayerProperties(&layer_count, 0); 1085 1086 VkLayerProperties *layers = push_array(&arena, VkLayerProperties, layer_count); 1087 str8 *layer_str8s = push_array(&arena, str8, layer_count); 1088 vkEnumerateInstanceLayerProperties(&layer_count, layers); 1089 1090 for (u32 i = 0; i < layer_count; i++) 1091 layer_str8s[i] = str8_from_c_str(layers[i].layerName); 1092 1093 for EachElement(vk_validation_layers, it) { 1094 for(u32 i = 0; i < layer_count; i++) { 1095 if (str8_equal(vk_validation_layers[it], layer_str8s[i])) { 1096 u32 index = enabled_validation_layers_count++; 1097 enabled_validation_layers[index] = (char *)vk_validation_layers[it].data; 1098 vulkan_config.layers.enabled.E[it] = 1; 1099 vulkan_config.layers.version.E[it] = layers[i].specVersion; 1100 break; 1101 } 1102 } 1103 } 1104 1105 if (countof(vk_validation_layers) != enabled_validation_layers_count) { 1106 i32 missing_count = countof(vk_validation_layers) - enabled_validation_layers_count; 1107 stream_append_str8s(err, vulkan_info("missing validation layer"), 1108 missing_count > 1 ? str8("s:") : str8(":"), str8("\n")); 1109 1110 for EachElement(vk_validation_layers, it) 1111 if (vulkan_config.layers.enabled.E[it] == 0) 1112 stream_append_str8s(err, str8(" "), vk_validation_layers[it], str8("\n")); 1113 } 1114 1115 u32 instance_extension_count = 0; 1116 vkEnumerateInstanceExtensionProperties(0, &instance_extension_count, 0); 1117 1118 VkExtensionProperties *instance_extensions = push_array(&arena, VkExtensionProperties, instance_extension_count); 1119 str8 *instance_ext_str8s = push_array(&arena, str8, instance_extension_count); 1120 vkEnumerateInstanceExtensionProperties(0, &instance_extension_count, instance_extensions); 1121 for EachIndex(instance_extension_count, it) 1122 instance_ext_str8s[it] = str8_from_c_str(instance_extensions[it].extensionName); 1123 1124 for EachElement(vk_instance_debug_extensions, it) { 1125 for EachIndex(instance_extension_count, i) { 1126 if (str8_equal(vk_instance_debug_extensions[it], instance_ext_str8s[i])) { 1127 u32 index = enabled_instance_extensions_count++; 1128 enabled_instance_extensions[index] = (char *)vk_instance_debug_extensions[it].data; 1129 vulkan_config.instance.E[it] = 1; 1130 break; 1131 } 1132 } 1133 } 1134 } 1135 #endif 1136 1137 VkApplicationInfo app_info = { 1138 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 1139 .pApplicationName = BEAMFORMER_NAME_STRING, 1140 .applicationVersion = 0, 1141 .pEngineName = "No Engine", 1142 .engineVersion = 0, 1143 .apiVersion = VK_MAKE_API_VERSION(1, 3, 0, 0), 1144 }; 1145 1146 VkInstanceCreateInfo instance_create_info = { 1147 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 1148 .pApplicationInfo = &app_info, 1149 .ppEnabledExtensionNames = enabled_instance_extensions, 1150 .enabledExtensionCount = enabled_instance_extensions_count, 1151 .ppEnabledLayerNames = enabled_validation_layers, 1152 .enabledLayerCount = enabled_validation_layers_count, 1153 }; 1154 1155 #if 0 && BEAMFORMER_DEBUG 1156 VkValidationFeatureEnableEXT validation_feature_enables[] = { 1157 VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, 1158 VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT, 1159 VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, 1160 VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT, 1161 }; 1162 1163 VkValidationFeaturesEXT validation_features = { 1164 .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, 1165 .enabledValidationFeatureCount = countof(validation_feature_enables), 1166 .pEnabledValidationFeatures = validation_feature_enables, 1167 }; 1168 1169 instance_create_info.pNext = &validation_features; 1170 #endif 1171 1172 vkCreateInstance(&instance_create_info, 0, &vulkan_context->handle); 1173 1174 #define X(name, ...) name = (name##_fn *)vkGetInstanceProcAddr(vulkan_context->handle, #name); 1175 VkInstanceProcedureList 1176 #undef X 1177 } 1178 1179 function void 1180 vk_load_physical_device(Arena arena, Stream *err) 1181 { 1182 VulkanContext *vk = vulkan_context; 1183 1184 u32 device_count; 1185 vkEnumeratePhysicalDevices(vk->handle, &device_count, 0); 1186 1187 VkPhysicalDevice *devices = push_array(&arena, typeof(*devices), device_count); 1188 vkEnumeratePhysicalDevices(vk->handle, &device_count, devices); 1189 1190 i32 best_index = -1, best_score = -1; 1191 for (u32 i = 0; i < device_count; i++) { 1192 Arena scratch = arena; 1193 VkPhysicalDeviceProperties2 *dp = push_struct(&scratch, typeof(*dp)); 1194 dp->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 1195 vkGetPhysicalDeviceProperties2(devices[i], dp); 1196 1197 i32 score = 0; 1198 if (dp->properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) 1199 score++; 1200 1201 if (score > best_score) { 1202 best_score = score; 1203 best_index = (i32)i; 1204 } 1205 } 1206 1207 vk->physical_device = best_index >= 0 ? devices[best_index] : 0; 1208 if (!vk->physical_device) 1209 fatal(vulkan_info("failed to find a suitable GPU\n")); 1210 1211 VkPhysicalDeviceProperties2 dp = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; 1212 VkPhysicalDeviceVulkan11Properties v11p = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES}; 1213 dp.pNext = &v11p; 1214 1215 vkGetPhysicalDeviceProperties2(vk->physical_device, &dp); 1216 1217 stream_append_str8s(err, vulkan_info("selecting device: "), str8_from_c_str(dp.properties.deviceName), str8("\n")); 1218 stream_append_str8(err, vulkan_info("Vulkan Version: ")); 1219 { 1220 u32 dv = dp.properties.apiVersion; 1221 stream_appendf(err, "%u.%u.%u\n", VK_API_VERSION_MAJOR(dv), VK_API_VERSION_MINOR(dv), VK_API_VERSION_PATCH(dv)); 1222 } 1223 1224 { 1225 Arena scratch = arena; 1226 u32 extension_count = 0; 1227 vkEnumerateDeviceExtensionProperties(vk->physical_device, 0, &extension_count, 0); 1228 VkExtensionProperties *extensions = push_array(&scratch, VkExtensionProperties, extension_count); 1229 vkEnumerateDeviceExtensionProperties(vk->physical_device, 0, &extension_count, extensions); 1230 1231 str8 *ext_str8s = push_array(&scratch, str8, extension_count); 1232 for (u32 index = 0; index < extension_count; index++) 1233 ext_str8s[index] = str8_from_c_str(extensions[index].extensionName); 1234 1235 b8 *supported = push_array(&scratch, b8, countof(vk_required_device_extensions)); 1236 for EachIndex(extension_count, index) 1237 for EachElement(vk_required_device_extensions, it) 1238 supported[it] |= str8_equal(vk_required_device_extensions[it], ext_str8s[index]); 1239 1240 u32 supported_count = 0; 1241 for EachElement(vk_required_device_extensions, it) 1242 supported_count += supported[it]; 1243 1244 u32 missing_count = countof(vk_required_device_extensions) - supported_count; 1245 if (missing_count) { 1246 stream_append_str8s(err, vulkan_info("fatal error: missing required device extension"), 1247 missing_count > 1 ? str8("s") : str8(""), str8(":\n")); 1248 for EachElement(vk_required_device_extensions, it) { 1249 if (!supported[it]) { 1250 str8 name = vk_required_device_extensions[it]; 1251 stream_append_str8s(err, vulkan_info(" "), name, str8("\n")); 1252 } 1253 } 1254 fatal(stream_to_str8(err)); 1255 } 1256 1257 for EachIndex(extension_count, index) 1258 for EachElement(vk_optional_device_extensions, it) 1259 vulkan_config.optional.E[it] |= str8_equal(vk_optional_device_extensions[it], ext_str8s[index]); 1260 1261 #if BEAMFORMER_DEBUG 1262 for EachIndex(extension_count, index) 1263 for EachElement(vk_debug_extensions, it) 1264 vulkan_config.debug.E[it] |= str8_equal(vk_debug_extensions[it], ext_str8s[index]); 1265 #endif 1266 } 1267 1268 { 1269 VkPhysicalDeviceFeatures2 df = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; 1270 VkPhysicalDeviceVulkan11Features v11f = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES}; 1271 VkPhysicalDeviceVulkan12Features v12f = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES}; 1272 VkPhysicalDeviceVulkan13Features v13f = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES}; 1273 df.pNext = &v11f; 1274 v11f.pNext = &v12f; 1275 v12f.pNext = &v13f; 1276 vkGetPhysicalDeviceFeatures2(vk->physical_device, &df); 1277 1278 { 1279 b32 all_supported = 1; 1280 #define X(name, ...) all_supported &= df.features.name; 1281 VK_REQUIRED_PHYSICAL_FEATURES 1282 #undef X 1283 1284 if (!all_supported) { 1285 stream_append_str8(err, vulkan_info("fatal error: missing physical device features:\n")); 1286 #define X(name, ...) if (!df.features.name) stream_append_str8(err, str8(" " #name "\n")); 1287 VK_REQUIRED_PHYSICAL_FEATURES 1288 #undef X 1289 fatal(stream_to_str8(err)); 1290 } 1291 } 1292 1293 { 1294 b32 all_supported = 1; 1295 #define X(name, ...) all_supported &= v11f.name; 1296 VK_REQUIRED_PHYSICAL_11_FEATURES 1297 #undef X 1298 1299 if (!all_supported) { 1300 stream_append_str8(err, vulkan_info("fatal error: missing physical device features:\n")); 1301 #define X(name, ...) if (!v11f.name) stream_append_str8(err, str8(" " #name "\n")); 1302 VK_REQUIRED_PHYSICAL_11_FEATURES 1303 #undef X 1304 fatal(stream_to_str8(err)); 1305 } 1306 } 1307 1308 { 1309 b32 all_supported = 1; 1310 #define X(name, ...) all_supported &= v12f.name; 1311 VK_REQUIRED_PHYSICAL_12_FEATURES 1312 #undef X 1313 1314 if (!all_supported) { 1315 stream_append_str8(err, vulkan_info("fatal error: missing physical device features:\n")); 1316 #define X(name, ...) if (!v12f.name) stream_append_str8(err, str8(" " #name "\n")); 1317 VK_REQUIRED_PHYSICAL_12_FEATURES 1318 #undef X 1319 fatal(stream_to_str8(err)); 1320 } 1321 } 1322 1323 { 1324 b32 all_supported = 1; 1325 #define X(name, ...) all_supported &= v13f.name; 1326 VK_REQUIRED_PHYSICAL_13_FEATURES 1327 #undef X 1328 1329 if (!all_supported) { 1330 stream_append_str8(err, vulkan_info("fatal error: missing physical device features:\n")); 1331 #define X(name, ...) if (!v13f.name) stream_append_str8(err, str8(" " #name "\n")); 1332 VK_REQUIRED_PHYSICAL_13_FEATURES 1333 #undef X 1334 fatal(stream_to_str8(err)); 1335 } 1336 } 1337 1338 if (vulkan_config.optional.cooperative_matrix) { 1339 Arena scratch = arena; 1340 u32 property_count = 0; 1341 vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR(vk->physical_device, &property_count, 0); 1342 1343 VkCooperativeMatrixPropertiesKHR *mat = push_array(&scratch, 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 if (vk->memory_info.memory_type_indices[VulkanMemoryKind_Host] == -1) { 1426 stream_append_str8(err, vulkan_info("fatal error: vulkan driver does not provide host visible memory\n")); 1427 fatal(stream_to_str8(err)); 1428 } 1429 1430 for EachElement(vk->memory_info.memory_type_indices, it) { 1431 u32 ti = vk->memory_info.memory_type_indices[it]; 1432 u32 flags = bmp->memoryTypes[ti].propertyFlags; 1433 vk->memory_info.memory_host_coherent[it] = (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0; 1434 } 1435 1436 vulkan_config.driver_api_version = dp.properties.apiVersion; 1437 vk->memory_info.max_allocation_size = v11p.maxMemoryAllocationSize; 1438 vk->memory_info.non_coherent_atom_size = dp.properties.limits.nonCoherentAtomSize; 1439 vk->gpu_info.vendor = dp.properties.vendorID; 1440 vk->gpu_info.gpu_heap_size = bmp->memoryHeaps[vk->memory_info.gpu_heap_index].size; 1441 vk->gpu_info.timestamp_period_ns = dp.properties.limits.timestampPeriod; 1442 vk->gpu_info.max_image_dimension_2D = dp.properties.limits.maxImageDimension2D; 1443 vk->gpu_info.max_image_dimension_3D = dp.properties.limits.maxImageDimension3D; 1444 vk->gpu_info.max_msaa_samples = round_down_power_of_two(dp.properties.limits.framebufferColorSampleCounts); 1445 vk->gpu_info.subgroup_size = v11p.subgroupSize; 1446 vk->gpu_info.max_compute_shared_memory_size = dp.properties.limits.maxComputeSharedMemorySize; 1447 1448 // IMPORTANT(rnp): memory must only be pushed at the end of the function 1449 vk->gpu_info.name = push_str8(&vk->arena, str8_from_c_str(dp.properties.deviceName)); 1450 1451 #if BEAMFORMER_DEBUG 1452 { 1453 b32 mismatch = 0; 1454 for EachElement(vk_validation_layers, it) { 1455 u32 lv = vulkan_config.layers.version.E[it]; 1456 u32 dv = vulkan_config.driver_api_version; 1457 if (lv < dv) { 1458 mismatch = 1; 1459 stream_append_str8s(err, vulkan_info("warning: validaton layer \""), 1460 vk_validation_layers[it], str8("\" version: ")); 1461 stream_appendf(err, "%u.%u.%u", VK_API_VERSION_MAJOR(lv), VK_API_VERSION_MINOR(lv), VK_API_VERSION_PATCH(lv)); 1462 stream_append_str8(err, str8(" lower than driver API version: ")); 1463 stream_appendf(err, "%u.%u.%u\n", VK_API_VERSION_MAJOR(dv), VK_API_VERSION_MINOR(dv), VK_API_VERSION_PATCH(dv)); 1464 } 1465 } 1466 1467 if (mismatch) 1468 stream_append_str8(err, vulkan_info("DO NOT report any bugs without updating your validation layers!\n")); 1469 } 1470 #endif 1471 } 1472 1473 function void 1474 vk_load_queues(Arena *memory, Stream *err) 1475 { 1476 /////////////////////////////////////////////////////// 1477 // NOTE(rnp): try to allocate an appropriate queue for 1478 // each of the following tasks: 1479 // * UI Rendering (Graphics) 1480 // * Beamforming (Compute) 1481 // * Upload (Transfer) 1482 // Then create a logical device ready for use 1483 1484 VulkanContext *vk = vulkan_context; 1485 1486 u32 queue_family_count; 1487 vkGetPhysicalDeviceQueueFamilyProperties(vk->physical_device, &queue_family_count, 0); 1488 1489 TempArena arena_save = begin_temp_arena(memory); 1490 VkQueueFamilyProperties *queues = push_array(memory, typeof(*queues), queue_family_count); 1491 vkGetPhysicalDeviceQueueFamilyProperties(vk->physical_device, &queue_family_count, queues); 1492 1493 i32 queue_indices[VulkanQueueKind_Count]; 1494 for EachElement(queue_indices, it) queue_indices[it] = -1; 1495 1496 /////////////////////////////////////////////////////////////// 1497 // NOTE(rnp): start by assigning queue families for each queue 1498 1499 /* NOTE(rnp): try for exclusive transfer queue */ 1500 #if !ForceSingleQueue 1501 { 1502 u32 mask = VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_COMPUTE_BIT|VK_QUEUE_TRANSFER_BIT; 1503 u32 max_timestamp_bits = 0; 1504 for (u32 index = 0; index < queue_family_count; index++) { 1505 if ((queues[index].queueFlags & mask) == VK_QUEUE_TRANSFER_BIT) { 1506 if (queues[index].timestampValidBits > max_timestamp_bits) { 1507 max_timestamp_bits = queues[index].timestampValidBits; 1508 queue_indices[VulkanQueueKind_Transfer] = (i32)index; 1509 } 1510 } 1511 } 1512 } 1513 1514 /* NOTE(rnp): try for compute separate from graphics */ 1515 for (u32 index = 0; index < queue_family_count; index++) { 1516 if ((queues[index].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0 && 1517 (queues[index].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) 1518 { 1519 queue_indices[VulkanQueueKind_Compute] = (i32)index; 1520 break; 1521 } 1522 } 1523 #endif /* !ForceSingleQueue */ 1524 1525 /* NOTE(rnp): find graphics family and verify it is exclusive */ 1526 b32 multi_graphics = 0; 1527 for (u32 index = 0; index < queue_family_count; index++) { 1528 if ((queues[index].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { 1529 // TODO(rnp): check for presentation support 1530 multi_graphics = queue_indices[VulkanQueueKind_Graphics] != -1; 1531 queue_indices[VulkanQueueKind_Graphics] = (i32)index; 1532 } 1533 } 1534 1535 if (multi_graphics) 1536 stream_append_str8(err, vulkan_info("warning: multiple queue families reported graphics support\n")); 1537 1538 if (queue_indices[VulkanQueueKind_Graphics] == -1) { 1539 stream_append_str8(err, vulkan_info("fatal error: GPU does not support graphics presentation\n")); 1540 fatal(stream_to_str8(err)); 1541 } 1542 1543 if (queue_indices[VulkanQueueKind_Compute] == -1) 1544 if ((queues[queue_indices[VulkanQueueKind_Graphics]].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0) 1545 queue_indices[VulkanQueueKind_Compute] = queue_indices[VulkanQueueKind_Graphics]; 1546 1547 if (queue_indices[VulkanQueueKind_Compute] == -1) { 1548 stream_append_str8(err, vulkan_info("fatal error: GPU does not support compute\n")); 1549 fatal(stream_to_str8(err)); 1550 } 1551 1552 if (queue_indices[VulkanQueueKind_Transfer] == -1) { 1553 if ((queues[queue_indices[VulkanQueueKind_Compute]].queueFlags & VK_QUEUE_TRANSFER_BIT) != 0) 1554 queue_indices[VulkanQueueKind_Transfer] = queue_indices[VulkanQueueKind_Compute]; 1555 else if ((queues[queue_indices[VulkanQueueKind_Graphics]].queueFlags & VK_QUEUE_TRANSFER_BIT) != 0) 1556 queue_indices[VulkanQueueKind_Transfer] = queue_indices[VulkanQueueKind_Graphics]; 1557 } 1558 1559 if (queue_indices[VulkanQueueKind_Transfer] == -1) { 1560 stream_append_str8(err, vulkan_info("fatal error: GPU does not support data transfer\n")); 1561 fatal(stream_to_str8(err)); 1562 } 1563 1564 ///////////////////////////////////////////////////////////////// 1565 // NOTE(rnp): if queues share families try to allocate subqueues 1566 1567 u32 assigned_subindices[VulkanQueueKind_Count] = {0}; 1568 i32 queue_subindices[VulkanQueueKind_Count] = {0}; 1569 1570 assigned_subindices[VulkanQueueKind_Graphics] += 1; 1571 1572 if (queue_indices[VulkanQueueKind_Compute] == queue_indices[VulkanQueueKind_Graphics]) { 1573 if (assigned_subindices[VulkanQueueKind_Graphics] < queues[queue_indices[VulkanQueueKind_Graphics]].queueCount) 1574 queue_subindices[VulkanQueueKind_Compute] = assigned_subindices[VulkanQueueKind_Graphics]++; 1575 } else { 1576 assigned_subindices[VulkanQueueKind_Compute] += 1; 1577 } 1578 1579 if (queue_indices[VulkanQueueKind_Transfer] == queue_indices[VulkanQueueKind_Graphics]) { 1580 if (assigned_subindices[VulkanQueueKind_Graphics] < queues[queue_indices[VulkanQueueKind_Graphics]].queueCount) 1581 queue_subindices[VulkanQueueKind_Transfer] = assigned_subindices[VulkanQueueKind_Graphics]++; 1582 } else if (queue_indices[VulkanQueueKind_Transfer] == queue_indices[VulkanQueueKind_Compute]) { 1583 if (assigned_subindices[VulkanQueueKind_Compute] < queues[queue_indices[VulkanQueueKind_Compute]].queueCount) 1584 queue_subindices[VulkanQueueKind_Transfer] = assigned_subindices[VulkanQueueKind_Compute]++; 1585 } else { 1586 assigned_subindices[VulkanQueueKind_Transfer] += 1; 1587 } 1588 1589 for EachElement(assigned_subindices, it) 1590 vk->unique_queues += assigned_subindices[it]; 1591 1592 end_temp_arena(arena_save); 1593 1594 ///////////////////////////////////////////// 1595 // NOTE(rnp): fill in info and create device 1596 for EachElement(vk->queues, it) { 1597 u32 index = queue_subindices[it]; 1598 for (i32 i = 0; i < queue_indices[it]; i++) 1599 index += assigned_subindices[i]; 1600 vk->queue_indices[it] = index; 1601 } 1602 1603 for EachElement(vk->queues, it) { 1604 if (vk->queues[vk->queue_indices[it]] == 0) { 1605 vk->queues[vk->queue_indices[it]] = push_struct(memory, VulkanQueue); 1606 vk->queues[vk->queue_indices[it]]->queue_family = queue_indices[it]; 1607 vk->queues[vk->queue_indices[it]]->queue_index = queue_subindices[it]; 1608 } 1609 vk->queues[it] = vk->queues[vk->queue_indices[it]]; 1610 } 1611 1612 for EachElement(vk->command_pools, it) 1613 vk->command_pools[it] = push_struct(memory, VulkanCommandPool); 1614 1615 VkDeviceQueueCreateInfo queue_create_infos[VulkanQueueKind_Count]; 1616 1617 f32 queue_priorities[VulkanQueueKind_Count][VulkanQueueKind_Count]; 1618 for (u32 i = 0; i < VulkanQueueKind_Count; i++) 1619 for (u32 j = 0; j < VulkanQueueKind_Count; j++) 1620 queue_priorities[i][j] = 1.0f; 1621 queue_priorities[queue_indices[VulkanQueueKind_Compute]][queue_subindices[VulkanQueueKind_Compute]] = 0.5f; 1622 1623 u32 queue_create_index = 0; 1624 b32 queue_info_filled[VulkanQueueKind_Count] = {0}; 1625 for (u32 q = 0; q < vk->unique_queues; q++) { 1626 u32 base_q = queue_indices[q]; 1627 if (!queue_info_filled[base_q]) { 1628 queue_create_infos[queue_create_index++] = (VkDeviceQueueCreateInfo){ 1629 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 1630 .queueFamilyIndex = base_q, 1631 .queueCount = assigned_subindices[q], 1632 .pQueuePriorities = queue_priorities[q], 1633 }; 1634 } 1635 queue_info_filled[base_q] = 1; 1636 } 1637 1638 u32 enabled_count = 0; 1639 const char *enabled_extensions[MAX_ENABLED_EXTENSIONS]; 1640 1641 for EachElement(vk_required_device_extensions, it) 1642 enabled_extensions[enabled_count++] = (char *)vk_required_device_extensions[it].data; 1643 1644 for EachElement(vk_optional_device_extensions, it) 1645 if (vulkan_config.optional.E[it]) 1646 enabled_extensions[enabled_count++] = (char *)vk_optional_device_extensions[it].data; 1647 1648 for EachElement(vk_debug_extensions, it) 1649 if (vulkan_config.debug.E[it]) 1650 enabled_extensions[enabled_count++] = (char *)vk_debug_extensions[it].data; 1651 1652 VkDeviceCreateInfo device_create_info = { 1653 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 1654 .pQueueCreateInfos = queue_create_infos, 1655 .queueCreateInfoCount = queue_create_index, 1656 .ppEnabledExtensionNames = enabled_extensions, 1657 .enabledExtensionCount = enabled_count, 1658 }; 1659 1660 VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR pdsre = { 1661 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR, 1662 .shaderRelaxedExtendedInstruction = 1, 1663 }; 1664 if (vulkan_config.debug.shader_relaxed_extended_instruction) { 1665 pdsre.pNext = (void *)device_create_info.pNext; 1666 device_create_info.pNext = &pdsre; 1667 } 1668 1669 VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop_mat_features = { 1670 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR, 1671 .cooperativeMatrix = 1, 1672 .cooperativeMatrixRobustBufferAccess = 0, 1673 }; 1674 if (vk->gpu_info.cooperative_matrix) { 1675 coop_mat_features.pNext = (void *)device_create_info.pNext; 1676 device_create_info.pNext = &coop_mat_features; 1677 } 1678 1679 VkPhysicalDeviceRobustness2FeaturesKHR robust2 = { 1680 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR, 1681 .pNext = (void *)device_create_info.pNext, 1682 .nullDescriptor = 1, 1683 }; 1684 device_create_info.pNext = &robust2; 1685 1686 VkPhysicalDeviceVulkan13Features v13f = { 1687 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, 1688 .pNext = (void *)device_create_info.pNext, 1689 #define X(name, ...) .name = 1, 1690 VK_REQUIRED_PHYSICAL_13_FEATURES 1691 #undef X 1692 }; 1693 device_create_info.pNext = &v13f; 1694 1695 VkPhysicalDeviceVulkan12Features v12f = { 1696 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, 1697 .pNext = (void *)device_create_info.pNext, 1698 #define X(name, ...) .name = 1, 1699 VK_REQUIRED_PHYSICAL_12_FEATURES 1700 #undef X 1701 }; 1702 device_create_info.pNext = &v12f; 1703 1704 VkPhysicalDeviceVulkan11Features v11f = { 1705 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES, 1706 .pNext = (void *)device_create_info.pNext, 1707 #define X(name, ...) .name = 1, 1708 VK_REQUIRED_PHYSICAL_11_FEATURES 1709 #undef X 1710 }; 1711 device_create_info.pNext = &v11f; 1712 1713 VkPhysicalDeviceFeatures2 device_features = { 1714 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, 1715 .pNext = (void *)device_create_info.pNext, 1716 .features = { 1717 #define X(name, ...) .name = 1, 1718 VK_REQUIRED_PHYSICAL_FEATURES 1719 #undef X 1720 }, 1721 }; 1722 device_create_info.pNext = &device_features; 1723 1724 vkCreateDevice(vk->physical_device, &device_create_info, 0, &vk->device); 1725 1726 #define X(name, ...) name = (name##_fn *)vkGetDeviceProcAddr(vk->device, #name); 1727 VkDeviceProcedureList 1728 #undef X 1729 1730 for (u32 q = 0; q < vk->unique_queues; q++) { 1731 VulkanQueue *qp = vk->queues[q]; 1732 vkGetDeviceQueue(vk->device, qp->queue_family, qp->queue_index, &qp->queue); 1733 1734 qp->timeline_semaphore = vk_make_semaphore(0); 1735 } 1736 1737 vk->queues[VulkanQueueKind_Graphics]->pipeline_stage_flags |= VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT; 1738 vk->queues[VulkanQueueKind_Compute]->pipeline_stage_flags |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; 1739 1740 for EachElement(vk->command_pools, it) { 1741 VulkanCommandPool *vcp = vk->command_pools[it]; 1742 1743 VkCommandPoolCreateInfo command_pool_create_info = { 1744 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 1745 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, 1746 .queueFamilyIndex = vk->queues[it]->queue_family, 1747 }; 1748 1749 vkCreateCommandPool(vk->device, &command_pool_create_info, 0, &vcp->handle); 1750 1751 VkCommandBufferAllocateInfo command_buffer_allocate_info = { 1752 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1753 .commandPool = vcp->handle, 1754 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1755 .commandBufferCount = countof(vcp->buffers), 1756 }; 1757 vkAllocateCommandBuffers(vk->device, &command_buffer_allocate_info, vcp->buffers); 1758 1759 VkQueryPoolCreateInfo query_pool_create_info = { 1760 .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, 1761 .queryType = VK_QUERY_TYPE_TIMESTAMP, 1762 .queryCount = MaxCommandBuffersInFlight * MaxCommandBufferTimestamps, 1763 }; 1764 vkCreateQueryPool(vk->device, &query_pool_create_info, 0, &vcp->query_pool); 1765 } 1766 } 1767 1768 function void 1769 vk_load_graphics(void) 1770 { 1771 VulkanContext *vk = vulkan_context; 1772 1773 // NOTE: swap chain image format 1774 { 1775 } 1776 1777 // NOTE: depth/stencil format 1778 { 1779 VkFormat depth_formats[] = { 1780 VK_FORMAT_D32_SFLOAT_S8_UINT, 1781 VK_FORMAT_D24_UNORM_S8_UINT, 1782 VK_FORMAT_D16_UNORM_S8_UINT, 1783 }; 1784 1785 vk->depth_stencil_format = VK_FORMAT_UNDEFINED; 1786 for EachElement(depth_formats, it) { 1787 VkFormatProperties3 format_properties3 = {.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3}; 1788 VkFormatProperties2 format_properties2 = { 1789 .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, 1790 .pNext = &format_properties3, 1791 }; 1792 vkGetPhysicalDeviceFormatProperties2(vk->physical_device, depth_formats[it], &format_properties2); 1793 if (format_properties3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT) { 1794 vk->depth_stencil_format = depth_formats[it]; 1795 break; 1796 } 1797 } 1798 } 1799 } 1800 1801 function void 1802 vk_load_descriptor_block(void) 1803 { 1804 // NOTE(rnp): 1805 // * One Descriptor Pool 1806 // * One Descriptor Set Per Resource Kind 1807 // * Shaders know the ResourceKind enumeration 1808 // * Shaders know the per set binding points 1809 1810 VulkanContext *vk = vulkan_context; 1811 1812 // NOTE(rnp): Pool 1813 VkDescriptorPoolSize pool_sizes[] = { 1814 { 1815 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1816 .descriptorCount = BeamformerShaderBufferSlot_Count, 1817 }, 1818 }; 1819 static_assert(countof(pool_sizes) == BeamformerShaderResourceKind_Count, ""); 1820 1821 VkDescriptorPoolCreateInfo pool_create_info = { 1822 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1823 .maxSets = BeamformerShaderResourceKind_Count, 1824 .poolSizeCount = countof(pool_sizes), 1825 .pPoolSizes = pool_sizes, 1826 }; 1827 1828 vkCreateDescriptorPool(vk->device, &pool_create_info, 0, &vk->descriptor_pool); 1829 1830 // NOTE(rnp): Set Layouts 1831 VkDescriptorSetLayoutCreateInfo layout_create_info = { 1832 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 1833 }; 1834 1835 { 1836 VkDescriptorSetLayoutBinding layout_bindings[BeamformerShaderBufferSlot_Count]; 1837 for EachEnumValue(BeamformerShaderBufferSlot, it) { 1838 layout_bindings[it] = (VkDescriptorSetLayoutBinding){ 1839 .binding = it, 1840 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1841 .descriptorCount = 1, 1842 .stageFlags = VK_SHADER_STAGE_ALL, 1843 }; 1844 } 1845 layout_create_info.bindingCount = countof(layout_bindings), 1846 layout_create_info.pBindings = layout_bindings, 1847 vkCreateDescriptorSetLayout(vk->device, &layout_create_info, 0, 1848 vk->descriptor_set_layouts + BeamformerShaderResourceKind_Buffer); 1849 } 1850 1851 // NOTE(rnp): Sets 1852 VkDescriptorSetAllocateInfo set_allocate_info = { 1853 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 1854 .descriptorPool = vk->descriptor_pool, 1855 .descriptorSetCount = countof(vk->descriptor_sets), 1856 .pSetLayouts = vk->descriptor_set_layouts, 1857 }; 1858 static_assert(countof(vk->descriptor_set_layouts) == countof(vk->descriptor_sets), ""); 1859 vkAllocateDescriptorSets(vk->device, &set_allocate_info, vk->descriptor_sets); 1860 1861 vk_label_object(DESCRIPTOR_POOL, vk->descriptor_pool, str8("Beamformer Resources"), str8("Pool")); 1862 1863 DeferLoop(take_lock(&vk->arena_lock, -1), release_lock(&vk->arena_lock)) { 1864 Arena scratch = vk->arena; 1865 for EachElement(vk->descriptor_sets, it) { 1866 Stream sb = arena_stream(scratch); 1867 stream_append_str8s(&sb, str8("Beamformer "), beamformer_shader_resource_kind_strings[it], str8("s")); 1868 vk_label_object(DESCRIPTOR_SET, vk->descriptor_sets[it], stream_to_str8(&sb), str8("Set")); 1869 vk_label_object(DESCRIPTOR_SET_LAYOUT, vk->descriptor_set_layouts[it], stream_to_str8(&sb), str8("Set Layout")); 1870 } 1871 } 1872 1873 // NOTE(rnp): junk API requirement that doesn't allow 0 initialization 1874 for EachElement(vk->descriptor_buffer_infos, it) 1875 vk->descriptor_buffer_infos[it].range = VK_WHOLE_SIZE; 1876 } 1877 1878 /////////////////////// 1879 // NOTE(rnp): User API 1880 1881 DEBUG_IMPORT void 1882 vk_load(OSLibrary vulkan_library_handle, Arena *memory, Stream *err) 1883 { 1884 #define X(name, ...) name = (name##_fn *)os_lookup_symbol(vulkan_library_handle, #name); 1885 VkLoaderProcedureList 1886 #undef X 1887 1888 if (!vkGetInstanceProcAddr) { 1889 stream_append_str8(err, vulkan_info("fatal error: failed to find \"vkGetInstanceProcAddr\"\n")); 1890 fatal(stream_to_str8(err)); 1891 } 1892 1893 VulkanContext *vk = vulkan_context; 1894 vk->entity_arena = sub_arena_end(memory, KB(64), KB(4)); 1895 vk->arena = sub_arena_end(memory, KB(96), KB(4)); 1896 1897 vk_load_instance(vk->arena, err); 1898 vk_load_physical_device(vk->arena, err); 1899 vk_load_queues(&vk->arena, err); 1900 vk_load_graphics(); 1901 vk_load_descriptor_block(); 1902 1903 read_only local_persist str8 default_compute_shader = str8("" 1904 "#version 430 core\n" 1905 "layout(push_constant) uniform pc { uint data[256 / 4]; };\n" 1906 "void main() {}\n" 1907 "\n"); 1908 VulkanPipelineCreateInfo compute_create_info = {.text = default_compute_shader, .name = str8("error_compute_shader")}; 1909 vk->default_compute_pipeline = vk_compute_pipeline_from_info(vk->arena, &compute_create_info, 256); 1910 1911 read_only local_persist str8 default_vertex_shader = str8("" 1912 "#version 430 core\n" 1913 "layout(push_constant) uniform pc { uint data[256 / 4]; };\n" 1914 "void main() {gl_Position = vec4(0);}\n" 1915 "\n"); 1916 read_only local_persist str8 default_fragment_shader = str8("" 1917 "#version 430 core\n" 1918 "layout(location = 0) out vec4 out_colour;" 1919 "layout(push_constant) uniform pc { uint data[256 / 4]; };\n" 1920 "void main() {out_colour = vec4(0.5f, 0.0f, 0.5f, 1.0f);}\n" 1921 "\n"); 1922 1923 VulkanPipelineCreateInfo pipeline_create_infos[2] = { 1924 { 1925 .kind = VulkanShaderKind_Vertex, 1926 .text = default_vertex_shader, 1927 .name = str8("error_vertex_shader"), 1928 }, 1929 { 1930 .kind = VulkanShaderKind_Fragment, 1931 .text = default_fragment_shader, 1932 .name = str8("error_fragment_shader"), 1933 }, 1934 }; 1935 vk->default_graphics_pipeline = vk_graphics_pipeline_from_infos(vk->arena, pipeline_create_infos, 2, 256); 1936 1937 // TODO: setup ui render pipeline 1938 1939 if (err->widx > 0) { 1940 os_console_log(err->data, err->widx); 1941 stream_reset(err, 0); 1942 } 1943 } 1944 1945 DEBUG_IMPORT GPUInfo * 1946 vk_gpu_info(void) 1947 { 1948 return &vulkan_context->gpu_info; 1949 } 1950 1951 function void 1952 vk_vulkan_buffer_release(VulkanBuffer *vb) 1953 { 1954 VulkanContext *vk = vulkan_context; 1955 VulkanEntity *e = (VulkanEntity *)((u8 *)vb - offsetof(VulkanEntity, as)); 1956 // TODO(rnp): this happens implicitly, probably just delete this if block 1957 if (vb->host_pointer) 1958 vkUnmapMemory(vk->device, vb->memory); 1959 1960 if (vb->buffer) 1961 vkDestroyBuffer(vk->device, vb->buffer, 0); 1962 1963 vk_release_memory(vb->memory, vb->memory_kind != VulkanMemoryKind_Host ? vb->memory_size : 0); 1964 vk_entity_release(e); 1965 } 1966 1967 DEBUG_IMPORT void 1968 vk_buffer_release(GPUBuffer *b) 1969 { 1970 if ValidVulkanHandle(b->handle) 1971 vk_vulkan_buffer_release(vk_entity_data(b->handle, VulkanEntityKind_Buffer)); 1972 zero_struct(b); 1973 } 1974 1975 DEBUG_IMPORT void 1976 vk_buffer_allocate(GPUBuffer *b, GPUBufferAllocateInfo *info) 1977 { 1978 VulkanContext *vk = vulkan_context; 1979 1980 vk_buffer_release(b); 1981 1982 assert(info->size > 0); 1983 1984 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Buffer); 1985 VulkanBufferAllocateInfo vulkan_buffer_allocate_info = { 1986 .gpu_buffer = b, 1987 .size = (u64)info->size, 1988 .flags = info->flags, 1989 .index_type = VK_INDEX_TYPE_NONE_KHR, 1990 .label = info->label, 1991 .export = info->export, 1992 }; 1993 1994 u32 queue_index_hit_count[VulkanQueueKind_Count] = {0}; 1995 for (u32 it = 0; it < info->timeline_count; it++) 1996 queue_index_hit_count[vk->queue_indices[info->timelines_used[it]]]++; 1997 1998 for EachElement(queue_index_hit_count, it) { 1999 if (queue_index_hit_count[it] > 0) { 2000 u32 index = vulkan_buffer_allocate_info.queue_family_count++; 2001 vulkan_buffer_allocate_info.queue_family_indices[index] = vk->queues[vk->queue_indices[it]]->queue_family; 2002 } 2003 } 2004 2005 if (vk_buffer_allocate_common(&e->as.buffer, &vulkan_buffer_allocate_info)) { 2006 b->handle.value[0] = (u64)e; 2007 } else { 2008 vk_entity_release(e); 2009 } 2010 } 2011 2012 DEBUG_IMPORT b32 2013 vk_buffer_needs_sync(GPUBuffer *b) 2014 { 2015 b32 result = 0; 2016 if ValidVulkanHandle(b->handle) { 2017 VulkanBuffer *vb = vk_entity_data(b->handle, VulkanEntityKind_Buffer); 2018 2019 // TODO(rnp): not correct check. need to check if we used transfer queue 2020 result = vb->memory_kind != VulkanMemoryKind_BAR; 2021 } 2022 2023 return result; 2024 } 2025 2026 DEBUG_IMPORT u64 2027 vk_round_up_to_sync_size(u64 size, u64 min) 2028 { 2029 i64 round = (i64)Max(min, vulkan_context->memory_info.non_coherent_atom_size); 2030 u64 result = (u64)round_up_to((i64)size, round); 2031 return result; 2032 } 2033 2034 function force_inline void 2035 vk_buffer_buffer_copy(VulkanBuffer *destination, VulkanBuffer *source, u64 destination_offset, u64 source_offset, u64 size, b32 non_temporal) 2036 { 2037 VulkanContext *vk = vulkan_context; 2038 2039 switch (source->memory_kind) { 2040 case VulkanMemoryKind_BAR: 2041 { 2042 switch (destination->memory_kind) { 2043 case VulkanMemoryKind_Host:{ 2044 if (destination->memory) { 2045 // TODO(rnp): there is likely a more efficient way of doing this in this case 2046 InvalidCodePath; 2047 } else { 2048 assert(source->host_pointer); 2049 b32 coherent = vk->memory_info.memory_host_coherent[source->memory_kind]; 2050 if (!coherent) { 2051 u64 nca_size = vk->memory_info.non_coherent_atom_size; 2052 VkMappedMemoryRange mrs[1] = {{ 2053 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 2054 .memory = source->memory, 2055 .offset = source_offset - (source_offset % nca_size), 2056 .size = vk_round_up_to_sync_size(size, nca_size), 2057 }}; 2058 vkInvalidateMappedMemoryRanges(vk->device, countof(mrs), mrs); 2059 } 2060 2061 void *dest = (u8 *)destination->host_pointer + destination_offset; 2062 void *src = (u8 *)source->host_pointer + source_offset; 2063 2064 // NOTE(rnp): don't trash the CPU cache for large data stores 2065 if (non_temporal) memory_copy_non_temporal(dest, src, size); 2066 else memory_copy(dest, src, size); 2067 } 2068 }break; 2069 InvalidDefaultCase; 2070 } 2071 }break; 2072 2073 case VulkanMemoryKind_Host:{ 2074 switch (destination->memory_kind) { 2075 case VulkanMemoryKind_BAR:{ 2076 assert(destination->host_pointer); 2077 2078 void *dest = (u8 *)destination->host_pointer + destination_offset; 2079 void *src = (u8 *)source->host_pointer + source_offset; 2080 2081 // NOTE(rnp): don't trash the CPU cache for large data stores 2082 if (non_temporal) memory_copy_non_temporal(dest, src, size); 2083 else memory_copy(dest, src, size); 2084 2085 b32 coherent = vk->memory_info.memory_host_coherent[destination->memory_kind]; 2086 if (!coherent) { 2087 u64 nca_size = vk->memory_info.non_coherent_atom_size; 2088 VkMappedMemoryRange mrs[1] = {{ 2089 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 2090 .memory = destination->memory, 2091 .offset = destination_offset - (destination_offset % nca_size), 2092 .size = vk_round_up_to_sync_size(size, nca_size), 2093 }}; 2094 vkFlushMappedMemoryRanges(vk->device, countof(mrs), mrs); 2095 } 2096 }break; 2097 InvalidDefaultCase; 2098 2099 } 2100 }break; 2101 2102 // TODO(rnp): use transfer queue when not mapped 2103 InvalidDefaultCase; 2104 } 2105 } 2106 2107 DEBUG_IMPORT void 2108 vk_buffer_range_upload(GPUBuffer *b, void *data, u64 offset, u64 size, b32 non_temporal) 2109 { 2110 VulkanBuffer *db = vk_entity_data(b->handle, VulkanEntityKind_Buffer); 2111 VulkanBuffer sb = { 2112 .host_pointer = data, 2113 .memory_kind = VulkanMemoryKind_Host, 2114 }; 2115 vk_buffer_buffer_copy(db, &sb, offset, 0, size, non_temporal); 2116 } 2117 2118 DEBUG_IMPORT void 2119 vk_buffer_range_download(void *destination, GPUBuffer *source, u64 offset, u64 size, b32 non_temporal) 2120 { 2121 VulkanBuffer *sb = vk_entity_data(source->handle, VulkanEntityKind_Buffer); 2122 VulkanBuffer db = { 2123 .host_pointer = destination, 2124 .memory_kind = VulkanMemoryKind_Host, 2125 }; 2126 vk_buffer_buffer_copy(&db, sb, 0, offset, size, non_temporal); 2127 } 2128 2129 DEBUG_IMPORT void 2130 vk_render_model_release(GPUBuffer *model) 2131 { 2132 if ValidVulkanHandle(model->handle) 2133 vk_vulkan_buffer_release(vk_entity_data(model->handle, VulkanEntityKind_RenderModel)); 2134 zero_struct(model); 2135 } 2136 2137 DEBUG_IMPORT void 2138 vk_render_model_allocate(GPUBuffer *model, void *indices, u64 index_count, u64 model_size, str8 label) 2139 { 2140 vk_render_model_release(model); 2141 2142 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_RenderModel); 2143 2144 assert(index_count <= U32_MAX); 2145 VkIndexType index_type; 2146 if (index_count <= U16_MAX) index_type = VK_INDEX_TYPE_UINT16; 2147 else index_type = VK_INDEX_TYPE_UINT32; 2148 2149 i64 indices_size = round_up_to(vk_index_size(index_type) * index_count, 64); 2150 2151 i64 size = round_up_to(model_size + indices_size, 64); 2152 assert(size > 0); 2153 2154 VulkanBufferAllocateInfo vulkan_buffer_allocate_info = { 2155 .gpu_buffer = model, 2156 .size = (u64)size, 2157 .flags = VulkanUsageFlag_HostReadWrite, 2158 .index_type = index_type, 2159 .label = label, 2160 .queue_family_count = 1, 2161 .queue_family_indices[0] = vulkan_context->queues[VulkanQueueKind_Graphics]->queue_family, 2162 }; 2163 if (vk_buffer_allocate_common(&e->as.buffer, &vulkan_buffer_allocate_info)) { 2164 model->handle.value[0] = (u64)e; 2165 model->index_count = index_count; 2166 model->gpu_pointer += indices_size; 2167 2168 VulkanBuffer sb = { 2169 .host_pointer = indices, 2170 .memory_kind = VulkanMemoryKind_Host, 2171 }; 2172 2173 vk_buffer_buffer_copy(&e->as.buffer, &sb, 0, 0, vk_index_size(index_type) * index_count, 0); 2174 } else { 2175 vk_entity_release(e); 2176 } 2177 } 2178 2179 DEBUG_IMPORT void 2180 vk_render_model_range_upload(GPUBuffer *model, void *data, u64 offset, u64 size, b32 non_temporal) 2181 { 2182 VulkanBuffer *db = vk_entity_data(model->handle, VulkanEntityKind_RenderModel); 2183 VulkanBuffer sb = { 2184 .host_pointer = data, 2185 .memory_kind = VulkanMemoryKind_Host, 2186 }; 2187 2188 offset += round_up_to(vk_index_size(db->index_type) * model->index_count, 64); 2189 2190 vk_buffer_buffer_copy(db, &sb, offset, 0, size, non_temporal); 2191 } 2192 2193 DEBUG_IMPORT void 2194 vk_image_release(GPUImage *image) 2195 { 2196 if ValidVulkanHandle(image->image) { 2197 VulkanContext *vk = vulkan_context; 2198 VulkanImage *vi = vk_entity_data(image->image, VulkanEntityKind_Image); 2199 2200 vkDestroyImageView(vk->device, vi->view, 0); 2201 vkDestroyImage(vk->device, vi->image, 0); 2202 vk_release_memory(vi->memory, image->memory_size); 2203 2204 vk_entity_release((VulkanEntity *)image->image.value[0]); 2205 } 2206 zero_struct(image); 2207 } 2208 2209 DEBUG_IMPORT void 2210 vk_image_allocate(GPUImage *image, u32 width, u32 height, u32 mips, u32 samples, 2211 VulkanImageUsage usage, VulkanUsageFlags flags, OSHandle *export, str8 label) 2212 { 2213 assert(IsPowerOfTwo(samples)); 2214 2215 vk_image_release(image); 2216 2217 VulkanContext *vk = vulkan_context; 2218 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Image); 2219 VulkanImage *vi = &e->as.image; 2220 2221 image->image.value[0] = (u64)e; 2222 image->width = Min(width, vk->gpu_info.max_image_dimension_2D); 2223 image->height = Min(height, vk->gpu_info.max_image_dimension_2D); 2224 image->mip_map_levels = Max(mips, 1); 2225 image->samples = Min(samples, vk->gpu_info.max_msaa_samples); 2226 2227 VkFormat usage_format_map[VulkanImageUsage_Count + 1] = { 2228 [VulkanImageUsage_None] = VK_FORMAT_UNDEFINED, 2229 //[VulkanImageUsage_Colour] = VK_FORMAT_R8G8B8A8_SRGB, 2230 [VulkanImageUsage_Colour] = VK_FORMAT_R8G8B8A8_UNORM, 2231 [VulkanImageUsage_DepthStencil] = vk->depth_stencil_format, 2232 [VulkanImageUsage_Count] = VK_FORMAT_UNDEFINED, 2233 }; 2234 2235 read_only local_persist VkImageUsageFlagBits usage_extra_bit_map[VulkanImageUsage_Count + 1] = { 2236 [VulkanImageUsage_None] = 0, 2237 [VulkanImageUsage_Colour] = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 2238 [VulkanImageUsage_DepthStencil] = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 2239 [VulkanImageUsage_Count] = 0, 2240 }; 2241 2242 read_only local_persist VkImageAspectFlags usage_image_aspect_map[VulkanImageUsage_Count + 1] = { 2243 [VulkanImageUsage_None] = 0, 2244 [VulkanImageUsage_Colour] = VK_IMAGE_ASPECT_COLOR_BIT, 2245 [VulkanImageUsage_DepthStencil] = VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT, 2246 [VulkanImageUsage_Count] = 0, 2247 }; 2248 2249 usage = Clamp((u32)usage, 0, VulkanImageUsage_Count); 2250 VkImageUsageFlagBits usage_flags = usage_extra_bit_map[usage]; 2251 2252 if (flags & VulkanUsageFlag_ImageSampling) usage_flags |= VK_IMAGE_USAGE_SAMPLED_BIT; 2253 if (flags & VulkanUsageFlag_TransferSource) usage_flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; 2254 if (flags & VulkanUsageFlag_TransferDestination) usage_flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; 2255 2256 u32 queue_family = vk->queues[VulkanQueueKind_Graphics]->queue_family; 2257 VkImageCreateInfo image_create_info = { 2258 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 2259 .flags = export ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0, 2260 .imageType = VK_IMAGE_TYPE_2D, 2261 .format = usage_format_map[usage], 2262 .extent = {image->width, image->height, 1}, 2263 .mipLevels = image->mip_map_levels, 2264 .arrayLayers = 1, 2265 .samples = image->samples, 2266 .tiling = VK_IMAGE_TILING_OPTIMAL, 2267 .usage = usage_flags, 2268 // NOTE(rnp): needed if multiple queue families are accessed 2269 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 2270 .queueFamilyIndexCount = 1, 2271 .pQueueFamilyIndices = &queue_family, 2272 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2273 }; 2274 2275 VkExternalMemoryImageCreateInfo external_memory_image_create_info = { 2276 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, 2277 .handleTypes = OS_WINDOWS ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT 2278 : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, 2279 }; 2280 2281 if (export) image_create_info.pNext = &external_memory_image_create_info; 2282 2283 vkCreateImage(vk->device, &image_create_info, 0, &vi->image); 2284 2285 VkMemoryRequirements memory_requirements; 2286 vkGetImageMemoryRequirements(vk->device, vi->image, &memory_requirements); 2287 2288 VkMemoryDedicatedAllocateInfo dedicated_allocate_info = { 2289 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, 2290 .image = vi->image, 2291 }; 2292 2293 if (vk_allocate_memory(&vi->memory, memory_requirements.size, VulkanMemoryKind_Device, 0, &dedicated_allocate_info, export)) { 2294 image->memory_size = memory_requirements.size; 2295 vkBindImageMemory(vk->device, vi->image, vi->memory, 0); 2296 2297 VkImageViewCreateInfo image_view_info = { 2298 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 2299 .image = vi->image, 2300 .viewType = VK_IMAGE_VIEW_TYPE_2D, 2301 .format = usage_format_map[usage], 2302 .subresourceRange = { 2303 .aspectMask = usage_image_aspect_map[usage], 2304 .baseMipLevel = 0, 2305 .levelCount = 1, 2306 .baseArrayLayer = 0, 2307 .layerCount = 1, 2308 }, 2309 }; 2310 vkCreateImageView(vk->device, &image_view_info, 0, &vi->view); 2311 2312 vk_label_object(IMAGE, vi->image, label, str8("Image")); 2313 vk_label_object(IMAGE_VIEW, vi->view, label, str8("Image View")); 2314 vk_label_object(DEVICE_MEMORY, vi->memory, label, str8("Memory")); 2315 } else { 2316 vkDestroyImage(vk->device, vi->image, 0); 2317 vk_entity_release(e); 2318 zero_struct(image); 2319 } 2320 } 2321 2322 DEBUG_IMPORT VulkanHandle 2323 vk_create_semaphore(OSHandle *export) 2324 { 2325 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Semaphore); 2326 e->as.semaphore = vk_make_semaphore(export); 2327 VulkanHandle result = {(u64)e}; 2328 return result; 2329 } 2330 2331 DEBUG_IMPORT b32 2332 vk_host_wait_timeline(VulkanTimeline timeline, u64 value, u64 timeout_ns) 2333 { 2334 b32 result = 0; 2335 if Between(timeline, 0, VulkanTimeline_Count - 1) { 2336 VulkanContext *vk = vulkan_context; 2337 VulkanQueue *vq = vk->queues[timeline]; 2338 VkSemaphoreWaitInfo semaphore_wait_info = { 2339 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, 2340 .pSemaphores = &vq->timeline_semaphore.semaphore, 2341 .semaphoreCount = 1, 2342 .pValues = &value, 2343 }; 2344 result = vkWaitSemaphores(vk->device, &semaphore_wait_info, timeout_ns) == VK_SUCCESS; 2345 } 2346 return result; 2347 } 2348 2349 DEBUG_IMPORT u64 2350 vk_host_signal_timeline(VulkanTimeline timeline) 2351 { 2352 u64 result = -1; 2353 if Between(timeline, 0, VulkanTimeline_Count - 1) { 2354 VulkanContext *vk = vulkan_context; 2355 VulkanQueue *vq = vk->queues[timeline]; 2356 VulkanSemaphore *vs = &vq->timeline_semaphore; 2357 result = ++vs->value; 2358 VkSemaphoreSignalInfo ssi = { 2359 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, 2360 .semaphore = vs->semaphore, 2361 .value = result, 2362 }; 2363 vkSignalSemaphore(vk->device, &ssi); 2364 } 2365 return result; 2366 } 2367 2368 DEBUG_IMPORT VulkanHandle 2369 vk_pipeline(VulkanPipelineCreateInfo *infos, u32 count, u32 push_constants_size) 2370 { 2371 assert(Between(count, 1, 2)); 2372 assert(count == 2 || infos[0].kind == VulkanShaderKind_Compute); 2373 2374 VulkanHandle result = {0}; 2375 DeferLoop(take_lock(&vulkan_context->arena_lock, -1), release_lock(&vulkan_context->arena_lock)) 2376 { 2377 Arena arena = vulkan_context->arena; 2378 2379 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_Pipeline); 2380 result = (VulkanHandle){(u64)e}; 2381 2382 if (count == 2) e->as.pipeline = vk_graphics_pipeline_from_infos(arena, infos, count, push_constants_size); 2383 else e->as.pipeline = vk_compute_pipeline_from_info(arena, infos, push_constants_size); 2384 } 2385 return result; 2386 } 2387 2388 DEBUG_IMPORT b32 2389 vk_pipeline_valid(VulkanHandle h) 2390 { 2391 b32 result = 0; 2392 if ValidVulkanHandle(h) { 2393 VulkanPipeline *vp = vk_entity_data(h, VulkanEntityKind_Pipeline); 2394 if (vp->stage_flags == VK_SHADER_STAGE_COMPUTE_BIT) 2395 result = vp->pipeline != vulkan_context->default_compute_pipeline.pipeline; 2396 else 2397 result = vp->pipeline != vulkan_context->default_graphics_pipeline.pipeline; 2398 } 2399 return result; 2400 } 2401 2402 DEBUG_IMPORT void 2403 vk_pipeline_release(VulkanHandle h) 2404 { 2405 if (vk_pipeline_valid(h)) { 2406 VulkanEntity *e = (VulkanEntity *)h.value[0]; 2407 VulkanTimeline timeline; 2408 if (e->as.pipeline.stage_flags == VK_SHADER_STAGE_COMPUTE_BIT) timeline = VulkanTimeline_Compute; 2409 else timeline = VulkanTimeline_Graphics; 2410 2411 // NOTE(rnp): block more command buffers from being recorded 2412 VulkanCommandPool *vcp = vulkan_context->command_pools[timeline]; 2413 DeferLoop(take_lock(&vcp->lock, -1), release_lock(&vcp->lock)) { 2414 u32 index = (vcp->next_index - 1) % countof(vcp->buffers); 2415 vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL); 2416 vkDestroyPipeline(vulkan_context->device, e->as.pipeline.pipeline, 0); 2417 vkDestroyPipelineLayout(vulkan_context->device, e->as.pipeline.layout, 0); 2418 2419 if (&e->as.pipeline == vcp->bound_pipeline) 2420 vcp->bound_pipeline = 0; 2421 } 2422 vk_entity_release(e); 2423 } 2424 } 2425 2426 DEBUG_IMPORT void 2427 vk_bind_shader_resources(BeamformerShaderResourceInfo *infos, u64 info_count) 2428 { 2429 VulkanContext *vk = vulkan_context; 2430 2431 VkWriteDescriptorSet write_sets[BeamformerShaderResourceKind_Count] = {0}; 2432 2433 for EachIndex(info_count, it) { 2434 switch (infos[it].kind) { 2435 case BeamformerShaderResourceKind_Buffer:{ 2436 VulkanBuffer *vb = vk_entity_data(infos[it].handle, VulkanEntityKind_Buffer); 2437 vk->descriptor_buffer_infos[infos[it].slot].buffer = vb->buffer; 2438 vk->descriptor_buffer_infos[infos[it].slot].offset = 0; 2439 vk->descriptor_buffer_infos[infos[it].slot].range = vb->memory_size; 2440 }break; 2441 2442 InvalidDefaultCase; 2443 } 2444 } 2445 2446 write_sets[BeamformerShaderResourceKind_Buffer].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 2447 write_sets[BeamformerShaderResourceKind_Buffer].dstSet = vk->descriptor_sets[BeamformerShaderResourceKind_Buffer]; 2448 write_sets[BeamformerShaderResourceKind_Buffer].dstBinding = 0; 2449 write_sets[BeamformerShaderResourceKind_Buffer].descriptorCount = countof(vk->descriptor_buffer_infos); 2450 write_sets[BeamformerShaderResourceKind_Buffer].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 2451 write_sets[BeamformerShaderResourceKind_Buffer].pBufferInfo = vk->descriptor_buffer_infos; 2452 2453 vkUpdateDescriptorSets(vk->device, countof(write_sets), write_sets, 0, 0); 2454 } 2455 2456 DEBUG_IMPORT VulkanHandle 2457 vk_command_begin(VulkanTimeline timeline) 2458 { 2459 VulkanHandle result = {0}; 2460 if Between(timeline, 0, VulkanTimeline_Count - 1) { 2461 VulkanContext *vk = vulkan_context; 2462 VulkanCommandPool *vcp = vk->command_pools[timeline]; 2463 2464 take_lock(&vcp->lock, -1); 2465 2466 VulkanEntity *e = vk_entity_allocate(VulkanEntityKind_CommandBuffer); 2467 VulkanCommandBuffer *vcb = &e->as.command_buffer; 2468 vcb->timeline = timeline; 2469 vcb->buffer_index = vcp->next_index++ % countof(vcp->buffers); 2470 2471 u32 index = vcb->buffer_index; 2472 // TODO(rnp): probably not the best to have this here but it will likely not be hit 2473 b32 wait_result = vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL); 2474 assert(wait_result); 2475 2476 vcp->queries_occupied[index] = 0; 2477 2478 VkCommandBufferBeginInfo buffer_begin_info = { 2479 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 2480 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 2481 }; 2482 2483 vkBeginCommandBuffer(vcp->buffers[index], &buffer_begin_info); 2484 vkCmdResetQueryPool(vcp->buffers[index], vcp->query_pool, index * MaxCommandBufferTimestamps, 2485 MaxCommandBufferTimestamps); 2486 2487 result = (VulkanHandle){(u64)e}; 2488 } 2489 return result; 2490 } 2491 2492 DEBUG_IMPORT void 2493 vk_command_bind_pipeline(VulkanHandle command, VulkanHandle pipeline) 2494 { 2495 if ValidVulkanHandle(command) { 2496 VulkanContext *vk = vulkan_context; 2497 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2498 VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; 2499 2500 VulkanPipeline *vp = 0; 2501 if ValidVulkanHandle(pipeline) { 2502 vp = vk_entity_data(pipeline, VulkanEntityKind_Pipeline); 2503 } else if (vcb->timeline == VulkanTimeline_Compute) { 2504 vp = &vk->default_compute_pipeline; 2505 } else if (vcb->timeline == VulkanTimeline_Graphics) { 2506 vp = &vk->default_graphics_pipeline; 2507 } else { 2508 InvalidCodePath; 2509 } 2510 2511 read_only local_persist VkPipelineBindPoint bind_point_lut[VulkanTimeline_Count] = { 2512 [VulkanTimeline_Graphics] = VK_PIPELINE_BIND_POINT_GRAPHICS, 2513 [VulkanTimeline_Compute] = VK_PIPELINE_BIND_POINT_COMPUTE, 2514 [VulkanTimeline_Transfer] = -1, 2515 }; 2516 2517 VkPipelineBindPoint bind_point = bind_point_lut[vcb->timeline]; 2518 assert(bind_point != (VkPipelineBindPoint)-1); 2519 2520 vkCmdBindPipeline(vcp->buffers[vcb->buffer_index], bind_point, vp->pipeline); 2521 vkCmdBindDescriptorSets(vcp->buffers[vcb->buffer_index], bind_point, vp->layout, 2522 0, countof(vk->descriptor_sets), vk->descriptor_sets, 0, 0); 2523 vcp->bound_pipeline = vp; 2524 } 2525 } 2526 2527 DEBUG_IMPORT void 2528 vk_command_buffer_memory_barriers(VulkanHandle command, GPUMemoryBarrierInfo *barriers, u64 count) 2529 { 2530 if ValidVulkanHandle(command) { 2531 VulkanContext *vk = vulkan_context; 2532 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2533 VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; 2534 VulkanQueue *vq = vk->queues[vcb->timeline]; 2535 2536 DeferLoop(take_lock(&vk->arena_lock, -1), release_lock(&vk->arena_lock)) 2537 { 2538 Arena arena = vk->arena; 2539 u32 valid_count = 0; 2540 VkBufferMemoryBarrier2 *memory_barriers = push_array(&arena, VkBufferMemoryBarrier2, count); 2541 for (u64 it = 0; it < count; it++) { 2542 if ValidVulkanHandle(barriers[it].gpu_buffer->handle) { 2543 u32 index = valid_count++; 2544 VulkanBuffer *vb = vk_entity_data(barriers[it].gpu_buffer->handle, VulkanEntityKind_Buffer); 2545 memory_barriers[index].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2; 2546 memory_barriers[index].srcStageMask = vq->pipeline_stage_flags; 2547 memory_barriers[index].srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT; 2548 memory_barriers[index].dstStageMask = vq->pipeline_stage_flags; 2549 memory_barriers[index].dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT; 2550 memory_barriers[index].srcQueueFamilyIndex = vq->queue_family; 2551 memory_barriers[index].dstQueueFamilyIndex = vq->queue_family; 2552 memory_barriers[index].buffer = vb->buffer; 2553 memory_barriers[index].offset = barriers[it].offset; 2554 memory_barriers[index].size = barriers[it].size; 2555 } 2556 } 2557 2558 VkDependencyInfo dependancy_info = { 2559 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, 2560 .bufferMemoryBarrierCount = valid_count, 2561 .pBufferMemoryBarriers = memory_barriers, 2562 }; 2563 2564 vkCmdPipelineBarrier2(vcp->buffers[vcb->buffer_index], &dependancy_info); 2565 } 2566 } 2567 } 2568 2569 DEBUG_IMPORT void 2570 vk_command_clear_buffer(VulkanHandle command, GPUBuffer *buffer, u64 offset, u64 size, u32 clear_word) 2571 { 2572 assert((offset % 4) == 0); 2573 assert((size % 4) == 0); 2574 if ValidVulkanHandle(command) { 2575 VulkanBuffer *vb = vk_entity_data(buffer->handle, VulkanEntityKind_Buffer); 2576 VkCommandBuffer cmd = vk_command_buffer(command); 2577 vkCmdFillBuffer(cmd, vb->buffer, offset, size, clear_word); 2578 } 2579 } 2580 2581 DEBUG_IMPORT void 2582 vk_command_dispatch_compute(VulkanHandle command, uv3 dispatch) 2583 { 2584 assert(dispatch.x <= U16_MAX); 2585 assert(dispatch.y <= U16_MAX); 2586 assert(dispatch.z <= U16_MAX); 2587 if ValidVulkanHandle(command) { 2588 VkCommandBuffer cmd = vk_command_buffer(command); 2589 vkCmdDispatch(cmd, dispatch.x, dispatch.y, dispatch.z); 2590 } 2591 } 2592 2593 DEBUG_IMPORT void 2594 vk_command_push_constants(VulkanHandle command, u32 offset, u32 size, void *values) 2595 { 2596 if ValidVulkanHandle(command) { 2597 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2598 VulkanCommandPool *vcp = vulkan_context->command_pools[vcb->timeline]; 2599 VulkanPipeline *vp = vcp->bound_pipeline; 2600 2601 assert(vp); 2602 2603 vkCmdPushConstants(vcp->buffers[vcb->buffer_index], vp->layout, vp->stage_flags, offset, size, values); 2604 } 2605 } 2606 2607 DEBUG_IMPORT void 2608 vk_command_timestamp(VulkanHandle command) 2609 { 2610 if ValidVulkanHandle(command) { 2611 VulkanContext *vk = vulkan_context; 2612 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2613 VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; 2614 2615 read_only local_persist VkPipelineStageFlags2 stage_lut[VulkanTimeline_Count] = { 2616 [VulkanTimeline_Graphics] = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, 2617 [VulkanTimeline_Compute] = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, 2618 [VulkanTimeline_Transfer] = -1, 2619 }; 2620 2621 VkPipelineStageFlags2 stage = stage_lut[vcb->timeline]; 2622 assert(stage != (VkPipelineStageFlags2)-1); 2623 2624 if (vcp->queries_occupied[vcb->buffer_index] < MaxCommandBufferTimestamps) { 2625 u32 query_index = vcp->queries_occupied[vcb->buffer_index]++; 2626 vkCmdWriteTimestamp2(vcp->buffers[vcb->buffer_index], stage, vcp->query_pool, 2627 vcb->buffer_index * MaxCommandBufferTimestamps + query_index); 2628 } 2629 } 2630 } 2631 2632 DEBUG_IMPORT void 2633 vk_command_wait_timeline(VulkanHandle command, VulkanTimeline timeline, u64 value) 2634 { 2635 if (ValidVulkanHandle(command) && Between(timeline, 0, VulkanTimeline_Count - 1)) { 2636 VulkanContext *vk = vulkan_context; 2637 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2638 2639 u32 wait_index = vk->queue_indices[timeline]; 2640 vcb->in_flight_wait_values[wait_index] = Max(value, vcb->in_flight_wait_values[wait_index]); 2641 } 2642 } 2643 2644 DEBUG_IMPORT u64 2645 vk_command_end(VulkanHandle command, VulkanHandle wait_semaphore, VulkanHandle finished_semaphore) 2646 { 2647 u64 result = -1; 2648 if ValidVulkanHandle(command) { 2649 VulkanContext *vk = vulkan_context; 2650 VulkanCommandBuffer *vcb = vk_entity_data(command, VulkanEntityKind_CommandBuffer); 2651 VulkanCommandPool *vcp = vk->command_pools[vcb->timeline]; 2652 VulkanQueue *vq = vk->queues[vcb->timeline]; 2653 VulkanSemaphore *vs = &vq->timeline_semaphore; 2654 2655 vkEndCommandBuffer(vcp->buffers[vcb->buffer_index]); 2656 2657 DeferLoop(take_lock(&vq->lock, -1), release_lock(&vq->lock)) { 2658 VkCommandBufferSubmitInfo command_buffer_submit_info = { 2659 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, 2660 .commandBuffer = vcp->buffers[vcb->buffer_index], 2661 }; 2662 2663 result = ++vs->value; 2664 2665 u32 signal_submit_info_count = 1; 2666 VkSemaphoreSubmitInfo signal_submit_infos[2] = {{ 2667 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, 2668 .semaphore = vs->semaphore, 2669 .value = result, 2670 .stageMask = vq->pipeline_stage_flags, 2671 }}; 2672 2673 if ValidVulkanHandle(finished_semaphore) { 2674 VulkanSemaphore *fs = vk_entity_data(finished_semaphore, VulkanEntityKind_Semaphore); 2675 signal_submit_infos[signal_submit_info_count++] = (VkSemaphoreSubmitInfo){ 2676 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, 2677 .semaphore = fs->semaphore, 2678 .stageMask = vq->pipeline_stage_flags, 2679 }; 2680 } 2681 2682 u32 wait_submit_info_count = 0; 2683 VkSemaphoreSubmitInfo wait_submit_infos[VulkanQueueKind_Count + 1]; 2684 for (u32 i = 0; i < vk->unique_queues; i++) { 2685 u32 queue_index = vk->queue_indices[i]; 2686 if (vcb->in_flight_wait_values[queue_index] > 0) { 2687 VulkanQueue *q = vk->queues[queue_index]; 2688 VkSemaphoreSubmitInfo wait_ssi = { 2689 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, 2690 .semaphore = q->timeline_semaphore.semaphore, 2691 .value = vcb->in_flight_wait_values[queue_index], 2692 .stageMask = q->pipeline_stage_flags, 2693 }; 2694 wait_submit_infos[wait_submit_info_count++] = wait_ssi; 2695 } 2696 } 2697 2698 if ValidVulkanHandle(wait_semaphore) { 2699 VulkanSemaphore *ws = vk_entity_data(wait_semaphore, VulkanEntityKind_Semaphore); 2700 wait_submit_infos[wait_submit_info_count++] = (VkSemaphoreSubmitInfo){ 2701 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, 2702 .semaphore = ws->semaphore, 2703 .stageMask = vq->pipeline_stage_flags, 2704 }; 2705 } 2706 2707 VkSubmitInfo2 submit_info = { 2708 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, 2709 .commandBufferInfoCount = 1, 2710 .pCommandBufferInfos = &command_buffer_submit_info, 2711 .waitSemaphoreInfoCount = wait_submit_info_count, 2712 .pWaitSemaphoreInfos = wait_submit_infos, 2713 .signalSemaphoreInfoCount = signal_submit_info_count, 2714 .pSignalSemaphoreInfos = signal_submit_infos, 2715 }; 2716 2717 vkQueueSubmit2(vq->queue, 1, &submit_info, 0); 2718 2719 vcp->bound_pipeline = 0; 2720 2721 atomic_store_u64(vcp->submission_values + vcb->buffer_index, result); 2722 } 2723 2724 release_lock(&vcp->lock); 2725 2726 vk_entity_release((VulkanEntity *)command.value[0]); 2727 } 2728 return result; 2729 } 2730 2731 DEBUG_IMPORT void 2732 vk_command_begin_rendering(VulkanHandle command, GPUImage *colour, GPUImage *depth, GPUImage *resolve) 2733 { 2734 if ValidVulkanHandle(command) { 2735 VkCommandBuffer cmd = vk_command_buffer(command); 2736 2737 assert((colour->width == depth->width) && (colour->height == depth->height)); 2738 2739 VulkanImage *ci = vk_entity_data(colour->image, VulkanEntityKind_Image); 2740 VulkanImage *di = vk_entity_data(depth->image, VulkanEntityKind_Image); 2741 VulkanImage *ri = 0; 2742 if (resolve) ri = vk_entity_data(resolve->image, VulkanEntityKind_Image); 2743 2744 // NOTE: Layout Transitions 2745 { 2746 u32 image_memory_barrier_count = 2; 2747 VkImageMemoryBarrier2 image_memory_barriers[3] = { 2748 { 2749 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, 2750 .srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, 2751 .srcAccessMask = 0, 2752 .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, 2753 .dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT|VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, 2754 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2755 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 2756 .image = ci->image, 2757 .subresourceRange = { 2758 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 2759 .baseMipLevel = 0, 2760 .levelCount = 1, 2761 .baseArrayLayer = 0, 2762 .layerCount = 1, 2763 }, 2764 }, 2765 { 2766 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, 2767 .srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, 2768 .srcAccessMask = 0, 2769 .dstStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, 2770 .dstAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 2771 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2772 .newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 2773 .image = di->image, 2774 .subresourceRange = { 2775 .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT, 2776 .baseMipLevel = 0, 2777 .levelCount = 1, 2778 .baseArrayLayer = 0, 2779 .layerCount = 1, 2780 }, 2781 }, 2782 }; 2783 2784 if (resolve) image_memory_barriers[image_memory_barrier_count++] = (VkImageMemoryBarrier2){ 2785 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, 2786 .srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, 2787 .srcAccessMask = 0, 2788 .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT|VK_PIPELINE_STAGE_2_RESOLVE_BIT, 2789 .dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT|VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, 2790 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 2791 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 2792 .image = ri->image, 2793 .subresourceRange = { 2794 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 2795 .baseMipLevel = 0, 2796 .levelCount = 1, 2797 .baseArrayLayer = 0, 2798 .layerCount = 1, 2799 }, 2800 }; 2801 2802 VkDependencyInfo dependency_info = { 2803 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, 2804 .imageMemoryBarrierCount = image_memory_barrier_count, 2805 .pImageMemoryBarriers = image_memory_barriers, 2806 }; 2807 2808 vkCmdPipelineBarrier2(cmd, &dependency_info); 2809 } 2810 2811 VkRenderingAttachmentInfo colour_attachment = { 2812 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, 2813 .imageView = ci->view, 2814 .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 2815 .resolveMode = ri ? VK_RESOLVE_MODE_AVERAGE_BIT : 0, 2816 .resolveImageView = ri ? ri->view : 0, 2817 .resolveImageLayout = ri ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : 0, 2818 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 2819 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 2820 .clearValue = {.color = {{0.0f, 0.0f, 0.0f, 0.0f}}}, 2821 }; 2822 2823 VkRenderingAttachmentInfo depth_stencil_attachment = { 2824 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, 2825 .imageView = di->view, 2826 .imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 2827 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 2828 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 2829 .clearValue = {.depthStencil = {1.0f, 0}}, 2830 }; 2831 2832 VkRenderingInfo rendering_info = { 2833 .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, 2834 .renderArea = {.offset = {0}, .extent = {colour->width, colour->height}}, 2835 .layerCount = 1, 2836 .colorAttachmentCount = 1, 2837 .pColorAttachments = &colour_attachment, 2838 .pDepthAttachment = &depth_stencil_attachment, 2839 .pStencilAttachment = &depth_stencil_attachment, 2840 }; 2841 2842 vkCmdBeginRendering(cmd, &rendering_info); 2843 } 2844 } 2845 2846 DEBUG_IMPORT void 2847 vk_command_draw(VulkanHandle command, GPUBuffer *model) 2848 { 2849 if (ValidVulkanHandle(command) && ValidVulkanHandle(model->handle)) { 2850 VkCommandBuffer cmd = vk_command_buffer(command); 2851 VulkanBuffer *vb = vk_entity_data(model->handle, VulkanEntityKind_RenderModel); 2852 vkCmdBindIndexBuffer2(cmd, vb->buffer, 0, vk_index_size(vb->index_type) * model->index_count, vb->index_type); 2853 vkCmdDrawIndexed(cmd, model->index_count, 1, 0, 0, 0); 2854 } 2855 } 2856 2857 DEBUG_IMPORT void 2858 vk_command_scissor(VulkanHandle command, u32 width, u32 height, u32 x_offset, u32 y_offset) 2859 { 2860 if ValidVulkanHandle(command) { 2861 VkCommandBuffer cmd = vk_command_buffer(command); 2862 VkRect2D scissor = {.offset = {x_offset, y_offset}, .extent = {width, height}}; 2863 vkCmdSetScissor(cmd, 0, 1, &scissor); 2864 } 2865 } 2866 2867 DEBUG_IMPORT void 2868 vk_command_viewport(VulkanHandle command, f32 width, f32 height, f32 x_offset, f32 y_offset, f32 min_depth, f32 max_depth) 2869 { 2870 if ValidVulkanHandle(command) { 2871 VkCommandBuffer cmd = vk_command_buffer(command); 2872 VkViewport viewport = {x_offset, y_offset, width, height, min_depth, max_depth}; 2873 vkCmdSetViewport(cmd, 0, 1, &viewport); 2874 } 2875 } 2876 2877 DEBUG_IMPORT void 2878 vk_command_end_rendering(VulkanHandle command) 2879 { 2880 if ValidVulkanHandle(command) vkCmdEndRendering(vk_command_buffer(command)); 2881 } 2882 2883 DEBUG_IMPORT void 2884 vk_command_copy_buffer(VulkanHandle command, GPUBuffer *restrict destination, 2885 GPUBuffer *restrict source, u64 source_offset, i64 size) 2886 { 2887 if (ValidVulkanHandle(command) && ValidVulkanHandle(destination->handle) && ValidVulkanHandle(source->handle)) { 2888 VkCommandBuffer cmd = vk_command_buffer(command); 2889 VulkanBuffer *db = vk_entity_data(destination->handle, VulkanEntityKind_Buffer); 2890 VulkanBuffer *sb = vk_entity_data(source->handle, VulkanEntityKind_Buffer); 2891 2892 VkBufferCopy2 buffer_copy = { 2893 .sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2, 2894 .srcOffset = source_offset, 2895 .dstOffset = 0, 2896 .size = size, 2897 }; 2898 2899 VkCopyBufferInfo2 copy_buffer_info = { 2900 .sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, 2901 .srcBuffer = sb->buffer, 2902 .dstBuffer = db->buffer, 2903 .regionCount = 1, 2904 .pRegions = &buffer_copy, 2905 }; 2906 2907 vkCmdCopyBuffer2(cmd, ©_buffer_info); 2908 } 2909 } 2910 2911 DEBUG_IMPORT u64 * 2912 vk_command_read_timestamps(VulkanTimeline timeline, Arena *arena) 2913 { 2914 u64 *result = 0; 2915 if Between(timeline, 0, VulkanTimeline_Count - 1) { 2916 VulkanContext *vk = vulkan_context; 2917 VulkanCommandPool *vcp = vk->command_pools[timeline]; 2918 DeferLoop(take_lock(&vcp->lock, -1), release_lock(&vcp->lock)) { 2919 u32 index = (vcp->next_index - 1) % countof(vcp->buffers); 2920 u32 count = vcp->queries_occupied[index]; 2921 if (count > 0) { 2922 result = push_array(arena, u64, count + 1); 2923 result[0] = count; 2924 2925 vk_host_wait_timeline(timeline, vcp->submission_values[index], -1ULL); 2926 2927 vkGetQueryPoolResults(vk->device, vcp->query_pool, index * MaxCommandBufferTimestamps, count, 2928 count * sizeof(u64), result + 1, 8, VK_QUERY_RESULT_WAIT_BIT); 2929 } 2930 } 2931 } else { 2932 result = push_array(arena, u64, 1); 2933 } 2934 return result; 2935 }