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