1/* 2 * Copyright 2019 Google LLC 3 * SPDX-License-Identifier: MIT 4 * 5 * based in part on anv and radv which are: 6 * Copyright © 2015 Intel Corporation 7 * Copyright © 2016 Red Hat. 8 * Copyright © 2016 Bas Nieuwenhuizen 9 */ 10 11#include "vn_instance.h" 12 13#include "util/driconf.h" 14#include "venus-protocol/vn_protocol_driver_info.h" 15#include "venus-protocol/vn_protocol_driver_instance.h" 16#include "venus-protocol/vn_protocol_driver_transport.h" 17 18#include "vn_icd.h" 19#include "vn_physical_device.h" 20#include "vn_renderer.h" 21 22#define VN_INSTANCE_LARGE_RING_SIZE (64 * 1024) 23#define VN_INSTANCE_LARGE_RING_DIRECT_THRESHOLD \ 24 (VN_INSTANCE_LARGE_RING_SIZE / 16) 25 26/* this must not exceed 2KiB for the ring to fit in a 4K page */ 27#define VN_INSTANCE_RING_SIZE (2 * 1024) 28#define VN_INSTANCE_RING_DIRECT_THRESHOLD (VN_INSTANCE_RING_SIZE / 8) 29 30/* 31 * Instance extensions add instance-level or physical-device-level 32 * functionalities. It seems renderer support is either unnecessary or 33 * optional. We should be able to advertise them or lie about them locally. 34 */ 35static const struct vk_instance_extension_table 36 vn_instance_supported_extensions = { 37 /* promoted to VK_VERSION_1_1 */ 38 .KHR_device_group_creation = true, 39 .KHR_external_fence_capabilities = true, 40 .KHR_external_memory_capabilities = true, 41 .KHR_external_semaphore_capabilities = true, 42 .KHR_get_physical_device_properties2 = true, 43 44#ifdef VN_USE_WSI_PLATFORM 45 .KHR_get_surface_capabilities2 = true, 46 .KHR_surface = true, 47 .KHR_surface_protected_capabilities = true, 48#endif 49#ifdef VK_USE_PLATFORM_WAYLAND_KHR 50 .KHR_wayland_surface = true, 51#endif 52#ifdef VK_USE_PLATFORM_XCB_KHR 53 .KHR_xcb_surface = true, 54#endif 55#ifdef VK_USE_PLATFORM_XLIB_KHR 56 .KHR_xlib_surface = true, 57#endif 58 }; 59 60static const driOptionDescription vn_dri_options[] = { 61 /* clang-format off */ 62 DRI_CONF_SECTION_PERFORMANCE 63 DRI_CONF_VK_X11_ENSURE_MIN_IMAGE_COUNT(false) 64 DRI_CONF_VK_X11_OVERRIDE_MIN_IMAGE_COUNT(0) 65 DRI_CONF_VK_X11_STRICT_IMAGE_COUNT(false) 66 DRI_CONF_VK_XWAYLAND_WAIT_READY(true) 67 DRI_CONF_VENUS_IMPLICIT_FENCING(false) 68 DRI_CONF_SECTION_END 69 DRI_CONF_SECTION_DEBUG 70 DRI_CONF_VK_WSI_FORCE_BGRA8_UNORM_FIRST(false) 71 DRI_CONF_SECTION_END 72 /* clang-format on */ 73}; 74 75static VkResult 76vn_instance_init_renderer_versions(struct vn_instance *instance) 77{ 78 uint32_t instance_version = 0; 79 VkResult result = 80 vn_call_vkEnumerateInstanceVersion(instance, &instance_version); 81 if (result != VK_SUCCESS) { 82 if (VN_DEBUG(INIT)) 83 vn_log(instance, "failed to enumerate renderer instance version"); 84 return result; 85 } 86 87 if (instance_version < VN_MIN_RENDERER_VERSION) { 88 if (VN_DEBUG(INIT)) { 89 vn_log(instance, "unsupported renderer instance version %d.%d", 90 VK_VERSION_MAJOR(instance_version), 91 VK_VERSION_MINOR(instance_version)); 92 } 93 return VK_ERROR_INITIALIZATION_FAILED; 94 } 95 96 if (VN_DEBUG(INIT)) { 97 vn_log(instance, "renderer instance version %d.%d.%d", 98 VK_VERSION_MAJOR(instance_version), 99 VK_VERSION_MINOR(instance_version), 100 VK_VERSION_PATCH(instance_version)); 101 } 102 103 /* request at least VN_MIN_RENDERER_VERSION internally */ 104 instance->renderer_api_version = 105 MAX2(instance->base.base.app_info.api_version, VN_MIN_RENDERER_VERSION); 106 107 /* instance version for internal use is capped */ 108 instance_version = MIN3(instance_version, instance->renderer_api_version, 109 instance->renderer->info.vk_xml_version); 110 assert(instance_version >= VN_MIN_RENDERER_VERSION); 111 112 instance->renderer_version = instance_version; 113 114 return VK_SUCCESS; 115} 116 117static VkResult 118vn_instance_init_ring(struct vn_instance *instance) 119{ 120 const size_t buf_size = instance->experimental.largeRing 121 ? VN_INSTANCE_LARGE_RING_SIZE 122 : VN_INSTANCE_RING_SIZE; 123 /* 32-bit seqno for renderer roundtrips */ 124 const size_t extra_size = sizeof(uint32_t); 125 struct vn_ring_layout layout; 126 vn_ring_get_layout(buf_size, extra_size, &layout); 127 128 instance->ring.shmem = 129 vn_renderer_shmem_create(instance->renderer, layout.shmem_size); 130 if (!instance->ring.shmem) { 131 if (VN_DEBUG(INIT)) 132 vn_log(instance, "failed to allocate/map ring shmem"); 133 return VK_ERROR_OUT_OF_HOST_MEMORY; 134 } 135 136 mtx_init(&instance->ring.mutex, mtx_plain); 137 138 struct vn_ring *ring = &instance->ring.ring; 139 vn_ring_init(ring, instance->renderer, &layout, 140 instance->ring.shmem->mmap_ptr); 141 142 instance->ring.id = (uintptr_t)ring; 143 144 const struct VkRingCreateInfoMESA info = { 145 .sType = VK_STRUCTURE_TYPE_RING_CREATE_INFO_MESA, 146 .resourceId = instance->ring.shmem->res_id, 147 .size = layout.shmem_size, 148 .idleTimeout = 50ull * 1000 * 1000, 149 .headOffset = layout.head_offset, 150 .tailOffset = layout.tail_offset, 151 .statusOffset = layout.status_offset, 152 .bufferOffset = layout.buffer_offset, 153 .bufferSize = layout.buffer_size, 154 .extraOffset = layout.extra_offset, 155 .extraSize = layout.extra_size, 156 }; 157 158 uint32_t create_ring_data[64]; 159 struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL( 160 create_ring_data, sizeof(create_ring_data)); 161 vn_encode_vkCreateRingMESA(&local_enc, 0, instance->ring.id, &info); 162 vn_renderer_submit_simple(instance->renderer, create_ring_data, 163 vn_cs_encoder_get_len(&local_enc)); 164 165 vn_cs_encoder_init(&instance->ring.upload, instance, 166 VN_CS_ENCODER_STORAGE_SHMEM_ARRAY, 1 * 1024 * 1024); 167 168 mtx_init(&instance->ring.roundtrip_mutex, mtx_plain); 169 instance->ring.roundtrip_next = 1; 170 171 return VK_SUCCESS; 172} 173 174static struct vn_renderer_shmem * 175vn_instance_get_reply_shmem_locked(struct vn_instance *instance, 176 size_t size, 177 void **ptr); 178 179static VkResult 180vn_instance_init_experimental_features(struct vn_instance *instance) 181{ 182 if (instance->renderer->info.vk_mesa_venus_protocol_spec_version != 183 100000) { 184 if (VN_DEBUG(INIT)) 185 vn_log(instance, "renderer supports no experimental features"); 186 return VK_SUCCESS; 187 } 188 189 size_t struct_size = sizeof(instance->experimental); 190 191 /* prepare the reply shmem */ 192 const size_t reply_size = 193 vn_sizeof_vkGetVenusExperimentalFeatureData100000MESA_reply( 194 &struct_size, &instance->experimental); 195 void *reply_ptr; 196 struct vn_renderer_shmem *reply_shmem = 197 vn_instance_get_reply_shmem_locked(instance, reply_size, &reply_ptr); 198 if (!reply_shmem) 199 return VK_ERROR_OUT_OF_HOST_MEMORY; 200 201 /* encode the command */ 202 uint32_t local_data[16]; 203 struct vn_cs_encoder local_enc = 204 VN_CS_ENCODER_INITIALIZER_LOCAL(local_data, sizeof(local_data)); 205 vn_encode_vkGetVenusExperimentalFeatureData100000MESA( 206 &local_enc, VK_COMMAND_GENERATE_REPLY_BIT_EXT, &struct_size, 207 &instance->experimental); 208 209 VkResult result = vn_renderer_submit_simple_sync( 210 instance->renderer, local_data, vn_cs_encoder_get_len(&local_enc)); 211 if (result != VK_SUCCESS) { 212 vn_renderer_shmem_unref(instance->renderer, reply_shmem); 213 return result; 214 } 215 216 struct vn_cs_decoder reply_dec = 217 VN_CS_DECODER_INITIALIZER(reply_ptr, reply_size); 218 vn_decode_vkGetVenusExperimentalFeatureData100000MESA_reply( 219 &reply_dec, &struct_size, &instance->experimental); 220 vn_renderer_shmem_unref(instance->renderer, reply_shmem); 221 222 if (VN_DEBUG(INIT)) { 223 vn_log(instance, 224 "VkVenusExperimentalFeatures100000MESA is as below:" 225 "\n\tmemoryResourceAllocationSize = %u" 226 "\n\tglobalFencing = %u" 227 "\n\tlargeRing = %u", 228 instance->experimental.memoryResourceAllocationSize, 229 instance->experimental.globalFencing, 230 instance->experimental.largeRing); 231 } 232 233 return VK_SUCCESS; 234} 235 236static VkResult 237vn_instance_init_renderer(struct vn_instance *instance) 238{ 239 const VkAllocationCallbacks *alloc = &instance->base.base.alloc; 240 241 VkResult result = vn_renderer_create(instance, alloc, &instance->renderer); 242 if (result != VK_SUCCESS) 243 return result; 244 245 struct vn_renderer_info *renderer_info = &instance->renderer->info; 246 uint32_t version = vn_info_wire_format_version(); 247 if (renderer_info->wire_format_version != version) { 248 if (VN_DEBUG(INIT)) { 249 vn_log(instance, "wire format version %d != %d", 250 renderer_info->wire_format_version, version); 251 } 252 return VK_ERROR_INITIALIZATION_FAILED; 253 } 254 255 version = vn_info_vk_xml_version(); 256 if (renderer_info->vk_xml_version > version) 257 renderer_info->vk_xml_version = version; 258 if (renderer_info->vk_xml_version < VN_MIN_RENDERER_VERSION) { 259 if (VN_DEBUG(INIT)) { 260 vn_log(instance, "vk xml version %d.%d.%d < %d.%d.%d", 261 VK_VERSION_MAJOR(renderer_info->vk_xml_version), 262 VK_VERSION_MINOR(renderer_info->vk_xml_version), 263 VK_VERSION_PATCH(renderer_info->vk_xml_version), 264 VK_VERSION_MAJOR(VN_MIN_RENDERER_VERSION), 265 VK_VERSION_MINOR(VN_MIN_RENDERER_VERSION), 266 VK_VERSION_PATCH(VN_MIN_RENDERER_VERSION)); 267 } 268 return VK_ERROR_INITIALIZATION_FAILED; 269 } 270 271 uint32_t spec_version = 272 vn_extension_get_spec_version("VK_EXT_command_serialization"); 273 if (renderer_info->vk_ext_command_serialization_spec_version > 274 spec_version) { 275 renderer_info->vk_ext_command_serialization_spec_version = spec_version; 276 } 277 278 spec_version = vn_extension_get_spec_version("VK_MESA_venus_protocol"); 279 if (renderer_info->vk_mesa_venus_protocol_spec_version > spec_version) 280 renderer_info->vk_mesa_venus_protocol_spec_version = spec_version; 281 282 if (VN_DEBUG(INIT)) { 283 vn_log(instance, "connected to renderer"); 284 vn_log(instance, "wire format version %d", 285 renderer_info->wire_format_version); 286 vn_log(instance, "vk xml version %d.%d.%d", 287 VK_VERSION_MAJOR(renderer_info->vk_xml_version), 288 VK_VERSION_MINOR(renderer_info->vk_xml_version), 289 VK_VERSION_PATCH(renderer_info->vk_xml_version)); 290 vn_log(instance, "VK_EXT_command_serialization spec version %d", 291 renderer_info->vk_ext_command_serialization_spec_version); 292 vn_log(instance, "VK_MESA_venus_protocol spec version %d", 293 renderer_info->vk_mesa_venus_protocol_spec_version); 294 vn_log(instance, "supports blob id 0: %d", 295 renderer_info->supports_blob_id_0); 296 vn_log(instance, "allow_vk_wait_syncs: %d", 297 renderer_info->allow_vk_wait_syncs); 298 } 299 300 return VK_SUCCESS; 301} 302 303VkResult 304vn_instance_submit_roundtrip(struct vn_instance *instance, 305 uint32_t *roundtrip_seqno) 306{ 307 uint32_t write_ring_extra_data[8]; 308 struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL( 309 write_ring_extra_data, sizeof(write_ring_extra_data)); 310 311 /* submit a vkWriteRingExtraMESA through the renderer */ 312 mtx_lock(&instance->ring.roundtrip_mutex); 313 const uint32_t seqno = instance->ring.roundtrip_next++; 314 vn_encode_vkWriteRingExtraMESA(&local_enc, 0, instance->ring.id, 0, seqno); 315 VkResult result = 316 vn_renderer_submit_simple(instance->renderer, write_ring_extra_data, 317 vn_cs_encoder_get_len(&local_enc)); 318 mtx_unlock(&instance->ring.roundtrip_mutex); 319 320 *roundtrip_seqno = seqno; 321 return result; 322} 323 324static bool 325roundtrip_seqno_ge(uint32_t a, uint32_t b) 326{ 327 /* a >= b, but deal with wrapping as well */ 328 return (a - b) <= INT32_MAX; 329} 330 331void 332vn_instance_wait_roundtrip(struct vn_instance *instance, 333 uint32_t roundtrip_seqno) 334{ 335 VN_TRACE_FUNC(); 336 const struct vn_ring *ring = &instance->ring.ring; 337 const volatile atomic_uint *ptr = ring->shared.extra; 338 uint32_t iter = 0; 339 do { 340 const uint32_t cur = atomic_load_explicit(ptr, memory_order_acquire); 341 if (roundtrip_seqno_ge(cur, roundtrip_seqno)) 342 break; 343 vn_relax(&iter, "roundtrip"); 344 } while (true); 345} 346 347struct vn_instance_submission { 348 const struct vn_cs_encoder *cs; 349 struct vn_ring_submit *submit; 350 351 struct { 352 struct vn_cs_encoder cs; 353 struct vn_cs_encoder_buffer buffer; 354 uint32_t data[64]; 355 } indirect; 356}; 357 358static const struct vn_cs_encoder * 359vn_instance_submission_get_cs(struct vn_instance_submission *submit, 360 const struct vn_cs_encoder *cs, 361 bool direct) 362{ 363 if (direct) 364 return cs; 365 366 VkCommandStreamDescriptionMESA local_descs[8]; 367 VkCommandStreamDescriptionMESA *descs = local_descs; 368 if (cs->buffer_count > ARRAY_SIZE(local_descs)) { 369 descs = 370 malloc(sizeof(VkCommandStreamDescriptionMESA) * cs->buffer_count); 371 if (!descs) 372 return NULL; 373 } 374 375 uint32_t desc_count = 0; 376 for (uint32_t i = 0; i < cs->buffer_count; i++) { 377 const struct vn_cs_encoder_buffer *buf = &cs->buffers[i]; 378 if (buf->committed_size) { 379 descs[desc_count++] = (VkCommandStreamDescriptionMESA){ 380 .resourceId = buf->shmem->res_id, 381 .offset = buf->offset, 382 .size = buf->committed_size, 383 }; 384 } 385 } 386 387 const size_t exec_size = vn_sizeof_vkExecuteCommandStreamsMESA( 388 desc_count, descs, NULL, 0, NULL, 0); 389 void *exec_data = submit->indirect.data; 390 if (exec_size > sizeof(submit->indirect.data)) { 391 exec_data = malloc(exec_size); 392 if (!exec_data) { 393 if (descs != local_descs) 394 free(descs); 395 return NULL; 396 } 397 } 398 399 submit->indirect.buffer = VN_CS_ENCODER_BUFFER_INITIALIZER(exec_data); 400 submit->indirect.cs = 401 VN_CS_ENCODER_INITIALIZER(&submit->indirect.buffer, exec_size); 402 vn_encode_vkExecuteCommandStreamsMESA(&submit->indirect.cs, 0, desc_count, 403 descs, NULL, 0, NULL, 0); 404 vn_cs_encoder_commit(&submit->indirect.cs); 405 406 if (descs != local_descs) 407 free(descs); 408 409 return &submit->indirect.cs; 410} 411 412static struct vn_ring_submit * 413vn_instance_submission_get_ring_submit(struct vn_ring *ring, 414 const struct vn_cs_encoder *cs, 415 struct vn_renderer_shmem *extra_shmem, 416 bool direct) 417{ 418 const uint32_t shmem_count = 419 (direct ? 0 : cs->buffer_count) + (extra_shmem ? 1 : 0); 420 struct vn_ring_submit *submit = vn_ring_get_submit(ring, shmem_count); 421 if (!submit) 422 return NULL; 423 424 submit->shmem_count = shmem_count; 425 if (!direct) { 426 for (uint32_t i = 0; i < cs->buffer_count; i++) { 427 submit->shmems[i] = 428 vn_renderer_shmem_ref(ring->renderer, cs->buffers[i].shmem); 429 } 430 } 431 if (extra_shmem) { 432 submit->shmems[shmem_count - 1] = 433 vn_renderer_shmem_ref(ring->renderer, extra_shmem); 434 } 435 436 return submit; 437} 438 439static void 440vn_instance_submission_cleanup(struct vn_instance_submission *submit) 441{ 442 if (submit->cs == &submit->indirect.cs && 443 submit->indirect.buffer.base != submit->indirect.data) 444 free(submit->indirect.buffer.base); 445} 446 447static VkResult 448vn_instance_submission_prepare(struct vn_instance_submission *submit, 449 const struct vn_cs_encoder *cs, 450 struct vn_ring *ring, 451 struct vn_renderer_shmem *extra_shmem, 452 bool direct) 453{ 454 submit->cs = vn_instance_submission_get_cs(submit, cs, direct); 455 if (!submit->cs) 456 return VK_ERROR_OUT_OF_HOST_MEMORY; 457 458 submit->submit = 459 vn_instance_submission_get_ring_submit(ring, cs, extra_shmem, direct); 460 if (!submit->submit) { 461 vn_instance_submission_cleanup(submit); 462 return VK_ERROR_OUT_OF_HOST_MEMORY; 463 } 464 465 return VK_SUCCESS; 466} 467 468static bool 469vn_instance_submission_can_direct(const struct vn_instance *instance, 470 const struct vn_cs_encoder *cs) 471{ 472 const size_t threshold = instance->experimental.largeRing 473 ? VN_INSTANCE_LARGE_RING_DIRECT_THRESHOLD 474 : VN_INSTANCE_RING_DIRECT_THRESHOLD; 475 return vn_cs_encoder_get_len(cs) <= threshold; 476} 477 478static struct vn_cs_encoder * 479vn_instance_ring_cs_upload_locked(struct vn_instance *instance, 480 const struct vn_cs_encoder *cs) 481{ 482 VN_TRACE_FUNC(); 483 assert(cs->storage_type == VN_CS_ENCODER_STORAGE_POINTER && 484 cs->buffer_count == 1); 485 const void *cs_data = cs->buffers[0].base; 486 const size_t cs_size = cs->total_committed_size; 487 assert(cs_size == vn_cs_encoder_get_len(cs)); 488 489 struct vn_cs_encoder *upload = &instance->ring.upload; 490 vn_cs_encoder_reset(upload); 491 492 if (!vn_cs_encoder_reserve(upload, cs_size)) 493 return NULL; 494 495 vn_cs_encoder_write(upload, cs_size, cs_data, cs_size); 496 vn_cs_encoder_commit(upload); 497 498 if (unlikely(!instance->renderer->info.supports_blob_id_0)) 499 vn_instance_wait_roundtrip(instance, upload->current_buffer_roundtrip); 500 501 return upload; 502} 503 504static VkResult 505vn_instance_ring_submit_locked(struct vn_instance *instance, 506 const struct vn_cs_encoder *cs, 507 struct vn_renderer_shmem *extra_shmem, 508 uint32_t *ring_seqno) 509{ 510 struct vn_ring *ring = &instance->ring.ring; 511 512 const bool direct = vn_instance_submission_can_direct(instance, cs); 513 if (!direct && cs->storage_type == VN_CS_ENCODER_STORAGE_POINTER) { 514 cs = vn_instance_ring_cs_upload_locked(instance, cs); 515 if (!cs) 516 return VK_ERROR_OUT_OF_HOST_MEMORY; 517 assert(cs->storage_type != VN_CS_ENCODER_STORAGE_POINTER); 518 } 519 520 struct vn_instance_submission submit; 521 VkResult result = 522 vn_instance_submission_prepare(&submit, cs, ring, extra_shmem, direct); 523 if (result != VK_SUCCESS) 524 return result; 525 526 uint32_t seqno; 527 const bool notify = vn_ring_submit(ring, submit.submit, submit.cs, &seqno); 528 if (notify) { 529 uint32_t notify_ring_data[8]; 530 struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL( 531 notify_ring_data, sizeof(notify_ring_data)); 532 vn_encode_vkNotifyRingMESA(&local_enc, 0, instance->ring.id, seqno, 0); 533 vn_renderer_submit_simple(instance->renderer, notify_ring_data, 534 vn_cs_encoder_get_len(&local_enc)); 535 } 536 537 vn_instance_submission_cleanup(&submit); 538 539 if (ring_seqno) 540 *ring_seqno = seqno; 541 542 return VK_SUCCESS; 543} 544 545VkResult 546vn_instance_ring_submit(struct vn_instance *instance, 547 const struct vn_cs_encoder *cs) 548{ 549 mtx_lock(&instance->ring.mutex); 550 VkResult result = vn_instance_ring_submit_locked(instance, cs, NULL, NULL); 551 mtx_unlock(&instance->ring.mutex); 552 553 return result; 554} 555 556static struct vn_renderer_shmem * 557vn_instance_get_reply_shmem_locked(struct vn_instance *instance, 558 size_t size, 559 void **out_ptr) 560{ 561 VN_TRACE_FUNC(); 562 struct vn_renderer_shmem_pool *pool = &instance->reply_shmem_pool; 563 const struct vn_renderer_shmem *saved_pool_shmem = pool->shmem; 564 565 size_t offset; 566 struct vn_renderer_shmem *shmem = 567 vn_renderer_shmem_pool_alloc(instance->renderer, pool, size, &offset); 568 if (!shmem) 569 return NULL; 570 571 assert(shmem == pool->shmem); 572 *out_ptr = shmem->mmap_ptr + offset; 573 574 if (shmem != saved_pool_shmem) { 575 uint32_t set_reply_command_stream_data[16]; 576 struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL( 577 set_reply_command_stream_data, 578 sizeof(set_reply_command_stream_data)); 579 const struct VkCommandStreamDescriptionMESA stream = { 580 .resourceId = shmem->res_id, 581 .size = pool->size, 582 }; 583 vn_encode_vkSetReplyCommandStreamMESA(&local_enc, 0, &stream); 584 vn_cs_encoder_commit(&local_enc); 585 586 /* vn_instance_init_experimental_features calls this before the ring is 587 * created 588 */ 589 if (likely(instance->ring.id)) { 590 if (unlikely(!instance->renderer->info.supports_blob_id_0)) 591 vn_instance_roundtrip(instance); 592 593 vn_instance_ring_submit_locked(instance, &local_enc, NULL, NULL); 594 } else { 595 vn_renderer_submit_simple(instance->renderer, 596 set_reply_command_stream_data, 597 vn_cs_encoder_get_len(&local_enc)); 598 } 599 } 600 601 /* TODO avoid this seek command and go lock-free? */ 602 uint32_t seek_reply_command_stream_data[8]; 603 struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL( 604 seek_reply_command_stream_data, sizeof(seek_reply_command_stream_data)); 605 vn_encode_vkSeekReplyCommandStreamMESA(&local_enc, 0, offset); 606 vn_cs_encoder_commit(&local_enc); 607 608 /* vn_instance_init_experimental_features calls this before the ring is 609 * created 610 */ 611 if (likely(instance->ring.id)) { 612 vn_instance_ring_submit_locked(instance, &local_enc, NULL, NULL); 613 } else { 614 vn_renderer_submit_simple(instance->renderer, 615 seek_reply_command_stream_data, 616 vn_cs_encoder_get_len(&local_enc)); 617 } 618 619 return shmem; 620} 621 622void 623vn_instance_submit_command(struct vn_instance *instance, 624 struct vn_instance_submit_command *submit) 625{ 626 void *reply_ptr = NULL; 627 submit->reply_shmem = NULL; 628 629 mtx_lock(&instance->ring.mutex); 630 631 if (vn_cs_encoder_is_empty(&submit->command)) 632 goto fail; 633 vn_cs_encoder_commit(&submit->command); 634 635 if (submit->reply_size) { 636 submit->reply_shmem = vn_instance_get_reply_shmem_locked( 637 instance, submit->reply_size, &reply_ptr); 638 if (!submit->reply_shmem) 639 goto fail; 640 } 641 642 uint32_t ring_seqno; 643 VkResult result = vn_instance_ring_submit_locked( 644 instance, &submit->command, submit->reply_shmem, &ring_seqno); 645 646 mtx_unlock(&instance->ring.mutex); 647 648 submit->reply = VN_CS_DECODER_INITIALIZER(reply_ptr, submit->reply_size); 649 650 if (submit->reply_size && result == VK_SUCCESS) 651 vn_ring_wait(&instance->ring.ring, ring_seqno); 652 653 return; 654 655fail: 656 instance->ring.command_dropped++; 657 mtx_unlock(&instance->ring.mutex); 658} 659 660/* instance commands */ 661 662VkResult 663vn_EnumerateInstanceVersion(uint32_t *pApiVersion) 664{ 665 *pApiVersion = VN_MAX_API_VERSION; 666 return VK_SUCCESS; 667} 668 669VkResult 670vn_EnumerateInstanceExtensionProperties(const char *pLayerName, 671 uint32_t *pPropertyCount, 672 VkExtensionProperties *pProperties) 673{ 674 if (pLayerName) 675 return vn_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); 676 677 return vk_enumerate_instance_extension_properties( 678 &vn_instance_supported_extensions, pPropertyCount, pProperties); 679} 680 681VkResult 682vn_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount, 683 VkLayerProperties *pProperties) 684{ 685 *pPropertyCount = 0; 686 return VK_SUCCESS; 687} 688 689VkResult 690vn_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, 691 const VkAllocationCallbacks *pAllocator, 692 VkInstance *pInstance) 693{ 694 VN_TRACE_FUNC(); 695 const VkAllocationCallbacks *alloc = 696 pAllocator ? pAllocator : vk_default_allocator(); 697 struct vn_instance *instance; 698 VkResult result; 699 700 vn_env_init(); 701 vn_trace_init(); 702 703 instance = vk_zalloc(alloc, sizeof(*instance), VN_DEFAULT_ALIGN, 704 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 705 if (!instance) 706 return vn_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY); 707 708 struct vk_instance_dispatch_table dispatch_table; 709 vk_instance_dispatch_table_from_entrypoints( 710 &dispatch_table, &vn_instance_entrypoints, true); 711 vk_instance_dispatch_table_from_entrypoints( 712 &dispatch_table, &wsi_instance_entrypoints, false); 713 result = vn_instance_base_init(&instance->base, 714 &vn_instance_supported_extensions, 715 &dispatch_table, pCreateInfo, alloc); 716 if (result != VK_SUCCESS) { 717 vk_free(alloc, instance); 718 return vn_error(NULL, result); 719 } 720 721 mtx_init(&instance->physical_device.mutex, mtx_plain); 722 mtx_init(&instance->cs_shmem.mutex, mtx_plain); 723 724 if (!vn_icd_supports_api_version( 725 instance->base.base.app_info.api_version)) { 726 result = VK_ERROR_INCOMPATIBLE_DRIVER; 727 goto fail; 728 } 729 730 if (pCreateInfo->enabledLayerCount) { 731 result = VK_ERROR_LAYER_NOT_PRESENT; 732 goto fail; 733 } 734 735 result = vn_instance_init_renderer(instance); 736 if (result != VK_SUCCESS) 737 goto fail; 738 739 vn_cs_renderer_protocol_info_init(instance); 740 741 vn_renderer_shmem_pool_init(instance->renderer, 742 &instance->reply_shmem_pool, 1u << 20); 743 744 result = vn_instance_init_experimental_features(instance); 745 if (result != VK_SUCCESS) 746 goto fail; 747 748 result = vn_instance_init_ring(instance); 749 if (result != VK_SUCCESS) 750 goto fail; 751 752 result = vn_instance_init_renderer_versions(instance); 753 if (result != VK_SUCCESS) 754 goto fail; 755 756 vn_renderer_shmem_pool_init(instance->renderer, &instance->cs_shmem.pool, 757 8u << 20); 758 759 VkInstanceCreateInfo local_create_info = *pCreateInfo; 760 local_create_info.ppEnabledExtensionNames = NULL; 761 local_create_info.enabledExtensionCount = 0; 762 pCreateInfo = &local_create_info; 763 764 VkApplicationInfo local_app_info; 765 if (instance->base.base.app_info.api_version < 766 instance->renderer_api_version) { 767 if (pCreateInfo->pApplicationInfo) { 768 local_app_info = *pCreateInfo->pApplicationInfo; 769 local_app_info.apiVersion = instance->renderer_api_version; 770 } else { 771 local_app_info = (const VkApplicationInfo){ 772 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 773 .apiVersion = instance->renderer_api_version, 774 }; 775 } 776 local_create_info.pApplicationInfo = &local_app_info; 777 } 778 779 VkInstance instance_handle = vn_instance_to_handle(instance); 780 result = 781 vn_call_vkCreateInstance(instance, pCreateInfo, NULL, &instance_handle); 782 if (result != VK_SUCCESS) 783 goto fail; 784 785 driParseOptionInfo(&instance->available_dri_options, vn_dri_options, 786 ARRAY_SIZE(vn_dri_options)); 787 driParseConfigFiles(&instance->dri_options, 788 &instance->available_dri_options, 0, "venus", NULL, 789 NULL, instance->base.base.app_info.app_name, 790 instance->base.base.app_info.app_version, 791 instance->base.base.app_info.engine_name, 792 instance->base.base.app_info.engine_version); 793 794 instance->renderer->info.has_implicit_fencing = 795 driQueryOptionb(&instance->dri_options, "venus_implicit_fencing"); 796 797 *pInstance = instance_handle; 798 799 return VK_SUCCESS; 800 801fail: 802 if (instance->ring.shmem) { 803 uint32_t destroy_ring_data[4]; 804 struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL( 805 destroy_ring_data, sizeof(destroy_ring_data)); 806 vn_encode_vkDestroyRingMESA(&local_enc, 0, instance->ring.id); 807 vn_renderer_submit_simple(instance->renderer, destroy_ring_data, 808 vn_cs_encoder_get_len(&local_enc)); 809 810 mtx_destroy(&instance->ring.roundtrip_mutex); 811 vn_cs_encoder_fini(&instance->ring.upload); 812 vn_renderer_shmem_unref(instance->renderer, instance->ring.shmem); 813 vn_ring_fini(&instance->ring.ring); 814 mtx_destroy(&instance->ring.mutex); 815 } 816 817 vn_renderer_shmem_pool_fini(instance->renderer, 818 &instance->reply_shmem_pool); 819 820 if (instance->renderer) 821 vn_renderer_destroy(instance->renderer, alloc); 822 823 mtx_destroy(&instance->physical_device.mutex); 824 mtx_destroy(&instance->cs_shmem.mutex); 825 826 vn_instance_base_fini(&instance->base); 827 vk_free(alloc, instance); 828 829 return vn_error(NULL, result); 830} 831 832void 833vn_DestroyInstance(VkInstance _instance, 834 const VkAllocationCallbacks *pAllocator) 835{ 836 VN_TRACE_FUNC(); 837 struct vn_instance *instance = vn_instance_from_handle(_instance); 838 const VkAllocationCallbacks *alloc = 839 pAllocator ? pAllocator : &instance->base.base.alloc; 840 841 if (!instance) 842 return; 843 844 if (instance->physical_device.initialized) { 845 for (uint32_t i = 0; i < instance->physical_device.device_count; i++) 846 vn_physical_device_fini(&instance->physical_device.devices[i]); 847 vk_free(alloc, instance->physical_device.devices); 848 vk_free(alloc, instance->physical_device.groups); 849 } 850 mtx_destroy(&instance->physical_device.mutex); 851 852 vn_call_vkDestroyInstance(instance, _instance, NULL); 853 854 vn_renderer_shmem_pool_fini(instance->renderer, &instance->cs_shmem.pool); 855 mtx_destroy(&instance->cs_shmem.mutex); 856 857 uint32_t destroy_ring_data[4]; 858 struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL( 859 destroy_ring_data, sizeof(destroy_ring_data)); 860 vn_encode_vkDestroyRingMESA(&local_enc, 0, instance->ring.id); 861 vn_renderer_submit_simple(instance->renderer, destroy_ring_data, 862 vn_cs_encoder_get_len(&local_enc)); 863 864 mtx_destroy(&instance->ring.roundtrip_mutex); 865 vn_cs_encoder_fini(&instance->ring.upload); 866 vn_ring_fini(&instance->ring.ring); 867 mtx_destroy(&instance->ring.mutex); 868 vn_renderer_shmem_unref(instance->renderer, instance->ring.shmem); 869 870 vn_renderer_shmem_pool_fini(instance->renderer, 871 &instance->reply_shmem_pool); 872 873 vn_renderer_destroy(instance->renderer, alloc); 874 875 driDestroyOptionCache(&instance->dri_options); 876 driDestroyOptionInfo(&instance->available_dri_options); 877 878 vn_instance_base_fini(&instance->base); 879 vk_free(alloc, instance); 880} 881 882PFN_vkVoidFunction 883vn_GetInstanceProcAddr(VkInstance _instance, const char *pName) 884{ 885 struct vn_instance *instance = vn_instance_from_handle(_instance); 886 return vk_instance_get_proc_addr(&instance->base.base, 887 &vn_instance_entrypoints, pName); 888} 889