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