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_SECTION_END
67   DRI_CONF_SECTION_DEBUG
68      DRI_CONF_VK_WSI_FORCE_BGRA8_UNORM_FIRST(false)
69   DRI_CONF_SECTION_END
70   /* clang-format on */
71};
72
73static VkResult
74vn_instance_init_renderer_versions(struct vn_instance *instance)
75{
76   uint32_t instance_version = 0;
77   VkResult result =
78      vn_call_vkEnumerateInstanceVersion(instance, &instance_version);
79   if (result != VK_SUCCESS) {
80      if (VN_DEBUG(INIT))
81         vn_log(instance, "failed to enumerate renderer instance version");
82      return result;
83   }
84
85   if (instance_version < VN_MIN_RENDERER_VERSION) {
86      if (VN_DEBUG(INIT)) {
87         vn_log(instance, "unsupported renderer instance version %d.%d",
88                VK_VERSION_MAJOR(instance_version),
89                VK_VERSION_MINOR(instance_version));
90      }
91      return VK_ERROR_INITIALIZATION_FAILED;
92   }
93
94   if (VN_DEBUG(INIT)) {
95      vn_log(instance, "renderer instance version %d.%d.%d",
96             VK_VERSION_MAJOR(instance_version),
97             VK_VERSION_MINOR(instance_version),
98             VK_VERSION_PATCH(instance_version));
99   }
100
101   /* request at least VN_MIN_RENDERER_VERSION internally */
102   instance->renderer_api_version =
103      MAX2(instance->base.base.app_info.api_version, VN_MIN_RENDERER_VERSION);
104
105   /* instance version for internal use is capped */
106   instance_version = MIN3(instance_version, instance->renderer_api_version,
107                           instance->renderer_info.vk_xml_version);
108   assert(instance_version >= VN_MIN_RENDERER_VERSION);
109
110   instance->renderer_version = instance_version;
111
112   return VK_SUCCESS;
113}
114
115static VkResult
116vn_instance_init_ring(struct vn_instance *instance)
117{
118   const size_t buf_size = instance->experimental.largeRing
119                              ? VN_INSTANCE_LARGE_RING_SIZE
120                              : VN_INSTANCE_RING_SIZE;
121   /* 32-bit seqno for renderer roundtrips */
122   const size_t extra_size = sizeof(uint32_t);
123   struct vn_ring_layout layout;
124   vn_ring_get_layout(buf_size, extra_size, &layout);
125
126   instance->ring.shmem =
127      vn_renderer_shmem_create(instance->renderer, layout.shmem_size);
128   if (!instance->ring.shmem) {
129      if (VN_DEBUG(INIT))
130         vn_log(instance, "failed to allocate/map ring shmem");
131      return VK_ERROR_OUT_OF_HOST_MEMORY;
132   }
133
134   mtx_init(&instance->ring.mutex, mtx_plain);
135
136   struct vn_ring *ring = &instance->ring.ring;
137   vn_ring_init(ring, instance->renderer, &layout,
138                instance->ring.shmem->mmap_ptr);
139
140   instance->ring.id = (uintptr_t)ring;
141
142   const struct VkRingCreateInfoMESA info = {
143      .sType = VK_STRUCTURE_TYPE_RING_CREATE_INFO_MESA,
144      .resourceId = instance->ring.shmem->res_id,
145      .size = layout.shmem_size,
146      .idleTimeout = 50ull * 1000 * 1000,
147      .headOffset = layout.head_offset,
148      .tailOffset = layout.tail_offset,
149      .statusOffset = layout.status_offset,
150      .bufferOffset = layout.buffer_offset,
151      .bufferSize = layout.buffer_size,
152      .extraOffset = layout.extra_offset,
153      .extraSize = layout.extra_size,
154   };
155
156   uint32_t create_ring_data[64];
157   struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL(
158      create_ring_data, sizeof(create_ring_data));
159   vn_encode_vkCreateRingMESA(&local_enc, 0, instance->ring.id, &info);
160   vn_renderer_submit_simple(instance->renderer, create_ring_data,
161                             vn_cs_encoder_get_len(&local_enc));
162
163   vn_cs_encoder_init_indirect(&instance->ring.upload, instance,
164                               1 * 1024 * 1024);
165
166   mtx_init(&instance->ring.roundtrip_mutex, mtx_plain);
167   instance->ring.roundtrip_next = 1;
168
169   return VK_SUCCESS;
170}
171
172static struct vn_renderer_shmem *
173vn_instance_get_reply_shmem_locked(struct vn_instance *instance,
174                                   size_t size,
175                                   void **ptr);
176
177static VkResult
178vn_instance_init_experimental_features(struct vn_instance *instance)
179{
180   if (instance->renderer_info.vk_mesa_venus_protocol_spec_version !=
181       100000) {
182      if (VN_DEBUG(INIT))
183         vn_log(instance, "renderer supports no experimental features");
184      return VK_SUCCESS;
185   }
186
187   size_t struct_size = sizeof(instance->experimental);
188
189   /* prepare the reply shmem */
190   const size_t reply_size =
191      vn_sizeof_vkGetVenusExperimentalFeatureData100000MESA_reply(
192         &struct_size, &instance->experimental);
193   void *reply_ptr;
194   struct vn_renderer_shmem *reply_shmem =
195      vn_instance_get_reply_shmem_locked(instance, reply_size, &reply_ptr);
196   if (!reply_shmem)
197      return VK_ERROR_OUT_OF_HOST_MEMORY;
198
199   /* encode the command */
200   uint32_t local_data[16];
201   struct vn_cs_encoder local_enc =
202      VN_CS_ENCODER_INITIALIZER_LOCAL(local_data, sizeof(local_data));
203   vn_encode_vkGetVenusExperimentalFeatureData100000MESA(
204      &local_enc, VK_COMMAND_GENERATE_REPLY_BIT_EXT, &struct_size,
205      &instance->experimental);
206
207   VkResult result = vn_renderer_submit_simple_sync(
208      instance->renderer, local_data, vn_cs_encoder_get_len(&local_enc));
209   if (result != VK_SUCCESS) {
210      vn_renderer_shmem_unref(instance->renderer, reply_shmem);
211      return result;
212   }
213
214   struct vn_cs_decoder reply_dec =
215      VN_CS_DECODER_INITIALIZER(reply_ptr, reply_size);
216   vn_decode_vkGetVenusExperimentalFeatureData100000MESA_reply(
217      &reply_dec, &struct_size, &instance->experimental);
218   vn_renderer_shmem_unref(instance->renderer, reply_shmem);
219
220   if (VN_DEBUG(INIT)) {
221      vn_log(instance,
222             "VkVenusExperimentalFeatures100000MESA is as below:"
223             "\n\tmemoryResourceAllocationSize = %u"
224             "\n\tglobalFencing = %u"
225             "\n\tlargeRing = %u",
226             instance->experimental.memoryResourceAllocationSize,
227             instance->experimental.globalFencing,
228             instance->experimental.largeRing);
229   }
230
231   return VK_SUCCESS;
232}
233
234static VkResult
235vn_instance_init_renderer(struct vn_instance *instance)
236{
237   const VkAllocationCallbacks *alloc = &instance->base.base.alloc;
238
239   VkResult result = vn_renderer_create(instance, alloc, &instance->renderer);
240   if (result != VK_SUCCESS)
241      return result;
242
243   vn_renderer_get_info(instance->renderer, &instance->renderer_info);
244
245   uint32_t version = vn_info_wire_format_version();
246   if (instance->renderer_info.wire_format_version != version) {
247      if (VN_DEBUG(INIT)) {
248         vn_log(instance, "wire format version %d != %d",
249                instance->renderer_info.wire_format_version, version);
250      }
251      return VK_ERROR_INITIALIZATION_FAILED;
252   }
253
254   version = vn_info_vk_xml_version();
255   if (instance->renderer_info.vk_xml_version > version)
256      instance->renderer_info.vk_xml_version = version;
257   if (instance->renderer_info.vk_xml_version < VN_MIN_RENDERER_VERSION) {
258      if (VN_DEBUG(INIT)) {
259         vn_log(instance, "vk xml version %d.%d.%d < %d.%d.%d",
260                VK_VERSION_MAJOR(instance->renderer_info.vk_xml_version),
261                VK_VERSION_MINOR(instance->renderer_info.vk_xml_version),
262                VK_VERSION_PATCH(instance->renderer_info.vk_xml_version),
263                VK_VERSION_MAJOR(VN_MIN_RENDERER_VERSION),
264                VK_VERSION_MINOR(VN_MIN_RENDERER_VERSION),
265                VK_VERSION_PATCH(VN_MIN_RENDERER_VERSION));
266      }
267      return VK_ERROR_INITIALIZATION_FAILED;
268   }
269
270   version = vn_info_extension_spec_version("VK_EXT_command_serialization");
271   if (instance->renderer_info.vk_ext_command_serialization_spec_version >
272       version) {
273      instance->renderer_info.vk_ext_command_serialization_spec_version =
274         version;
275   }
276
277   version = vn_info_extension_spec_version("VK_MESA_venus_protocol");
278   if (instance->renderer_info.vk_mesa_venus_protocol_spec_version >
279       version) {
280      instance->renderer_info.vk_mesa_venus_protocol_spec_version = version;
281   }
282
283   if (VN_DEBUG(INIT)) {
284      vn_log(instance, "connected to renderer");
285      vn_log(instance, "wire format version %d",
286             instance->renderer_info.wire_format_version);
287      vn_log(instance, "vk xml version %d.%d.%d",
288             VK_VERSION_MAJOR(instance->renderer_info.vk_xml_version),
289             VK_VERSION_MINOR(instance->renderer_info.vk_xml_version),
290             VK_VERSION_PATCH(instance->renderer_info.vk_xml_version));
291      vn_log(
292         instance, "VK_EXT_command_serialization spec version %d",
293         instance->renderer_info.vk_ext_command_serialization_spec_version);
294      vn_log(instance, "VK_MESA_venus_protocol spec version %d",
295             instance->renderer_info.vk_mesa_venus_protocol_spec_version);
296   }
297
298   return VK_SUCCESS;
299}
300
301VkResult
302vn_instance_submit_roundtrip(struct vn_instance *instance,
303                             uint32_t *roundtrip_seqno)
304{
305   uint32_t write_ring_extra_data[8];
306   struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL(
307      write_ring_extra_data, sizeof(write_ring_extra_data));
308
309   /* submit a vkWriteRingExtraMESA through the renderer */
310   mtx_lock(&instance->ring.roundtrip_mutex);
311   const uint32_t seqno = instance->ring.roundtrip_next++;
312   vn_encode_vkWriteRingExtraMESA(&local_enc, 0, instance->ring.id, 0, seqno);
313   VkResult result =
314      vn_renderer_submit_simple(instance->renderer, write_ring_extra_data,
315                                vn_cs_encoder_get_len(&local_enc));
316   mtx_unlock(&instance->ring.roundtrip_mutex);
317
318   *roundtrip_seqno = seqno;
319   return result;
320}
321
322void
323vn_instance_wait_roundtrip(struct vn_instance *instance,
324                           uint32_t roundtrip_seqno)
325{
326   const struct vn_ring *ring = &instance->ring.ring;
327   const volatile atomic_uint *ptr = ring->shared.extra;
328   uint32_t iter = 0;
329   do {
330      const uint32_t cur = atomic_load_explicit(ptr, memory_order_acquire);
331      if (cur >= roundtrip_seqno || roundtrip_seqno - cur >= INT32_MAX)
332         break;
333      vn_relax(&iter, "roundtrip");
334   } while (true);
335}
336
337struct vn_instance_submission {
338   const struct vn_cs_encoder *cs;
339   struct vn_ring_submit *submit;
340
341   struct {
342      struct vn_cs_encoder cs;
343      struct vn_cs_encoder_buffer buffer;
344      uint32_t data[64];
345   } indirect;
346};
347
348static const struct vn_cs_encoder *
349vn_instance_submission_get_cs(struct vn_instance_submission *submit,
350                              const struct vn_cs_encoder *cs,
351                              bool direct)
352{
353   if (direct)
354      return cs;
355
356   VkCommandStreamDescriptionMESA local_descs[8];
357   VkCommandStreamDescriptionMESA *descs = local_descs;
358   if (cs->buffer_count > ARRAY_SIZE(local_descs)) {
359      descs =
360         malloc(sizeof(VkCommandStreamDescriptionMESA) * cs->buffer_count);
361      if (!descs)
362         return NULL;
363   }
364
365   uint32_t desc_count = 0;
366   for (uint32_t i = 0; i < cs->buffer_count; i++) {
367      const struct vn_cs_encoder_buffer *buf = &cs->buffers[i];
368      if (buf->committed_size) {
369         descs[desc_count++] = (VkCommandStreamDescriptionMESA){
370            .resourceId = buf->shmem->res_id,
371            .offset = buf->offset,
372            .size = buf->committed_size,
373         };
374      }
375   }
376
377   const size_t exec_size = vn_sizeof_vkExecuteCommandStreamsMESA(
378      desc_count, descs, NULL, 0, NULL, 0);
379   void *exec_data = submit->indirect.data;
380   if (exec_size > sizeof(submit->indirect.data)) {
381      exec_data = malloc(exec_size);
382      if (!exec_data) {
383         if (descs != local_descs)
384            free(descs);
385         return NULL;
386      }
387   }
388
389   submit->indirect.buffer = VN_CS_ENCODER_BUFFER_INITIALIZER(exec_data);
390   submit->indirect.cs =
391      VN_CS_ENCODER_INITIALIZER(&submit->indirect.buffer, exec_size);
392   vn_encode_vkExecuteCommandStreamsMESA(&submit->indirect.cs, 0, desc_count,
393                                         descs, NULL, 0, NULL, 0);
394   vn_cs_encoder_commit(&submit->indirect.cs);
395
396   if (descs != local_descs)
397      free(descs);
398
399   return &submit->indirect.cs;
400}
401
402static struct vn_ring_submit *
403vn_instance_submission_get_ring_submit(struct vn_ring *ring,
404                                       const struct vn_cs_encoder *cs,
405                                       struct vn_renderer_shmem *extra_shmem,
406                                       bool direct)
407{
408   const uint32_t shmem_count =
409      (direct ? 0 : cs->buffer_count) + (extra_shmem ? 1 : 0);
410   struct vn_ring_submit *submit = vn_ring_get_submit(ring, shmem_count);
411   if (!submit)
412      return NULL;
413
414   submit->shmem_count = shmem_count;
415   if (!direct) {
416      for (uint32_t i = 0; i < cs->buffer_count; i++) {
417         submit->shmems[i] =
418            vn_renderer_shmem_ref(ring->renderer, cs->buffers[i].shmem);
419      }
420   }
421   if (extra_shmem) {
422      submit->shmems[shmem_count - 1] =
423         vn_renderer_shmem_ref(ring->renderer, extra_shmem);
424   }
425
426   return submit;
427}
428
429static void
430vn_instance_submission_cleanup(struct vn_instance_submission *submit)
431{
432   if (submit->cs == &submit->indirect.cs &&
433       submit->indirect.buffer.base != submit->indirect.data)
434      free(submit->indirect.buffer.base);
435}
436
437static VkResult
438vn_instance_submission_prepare(struct vn_instance_submission *submit,
439                               const struct vn_cs_encoder *cs,
440                               struct vn_ring *ring,
441                               struct vn_renderer_shmem *extra_shmem,
442                               bool direct)
443{
444   submit->cs = vn_instance_submission_get_cs(submit, cs, direct);
445   if (!submit->cs)
446      return VK_ERROR_OUT_OF_HOST_MEMORY;
447
448   submit->submit =
449      vn_instance_submission_get_ring_submit(ring, cs, extra_shmem, direct);
450   if (!submit->submit) {
451      vn_instance_submission_cleanup(submit);
452      return VK_ERROR_OUT_OF_HOST_MEMORY;
453   }
454
455   return VK_SUCCESS;
456}
457
458static bool
459vn_instance_submission_can_direct(const struct vn_instance *instance,
460                                  const struct vn_cs_encoder *cs)
461{
462   const size_t threshold = instance->experimental.largeRing
463                               ? VN_INSTANCE_LARGE_RING_DIRECT_THRESHOLD
464                               : VN_INSTANCE_RING_DIRECT_THRESHOLD;
465   return vn_cs_encoder_get_len(cs) <= threshold;
466}
467
468static struct vn_cs_encoder *
469vn_instance_ring_cs_upload_locked(struct vn_instance *instance,
470                                  const struct vn_cs_encoder *cs)
471{
472   assert(!cs->indirect && cs->buffer_count == 1);
473   const void *cs_data = cs->buffers[0].base;
474   const size_t cs_size = cs->total_committed_size;
475   assert(cs_size == vn_cs_encoder_get_len(cs));
476
477   struct vn_cs_encoder *upload = &instance->ring.upload;
478   vn_cs_encoder_reset(upload);
479
480   if (!vn_cs_encoder_reserve(upload, cs_size))
481      return NULL;
482
483   vn_cs_encoder_write(upload, cs_size, cs_data, cs_size);
484   vn_cs_encoder_commit(upload);
485   vn_instance_wait_roundtrip(instance, upload->current_buffer_roundtrip);
486
487   return upload;
488}
489
490static VkResult
491vn_instance_ring_submit_locked(struct vn_instance *instance,
492                               const struct vn_cs_encoder *cs,
493                               struct vn_renderer_shmem *extra_shmem,
494                               uint32_t *ring_seqno)
495{
496   struct vn_ring *ring = &instance->ring.ring;
497
498   const bool direct = vn_instance_submission_can_direct(instance, cs);
499   if (!direct && !cs->indirect) {
500      cs = vn_instance_ring_cs_upload_locked(instance, cs);
501      if (!cs)
502         return VK_ERROR_OUT_OF_HOST_MEMORY;
503      assert(cs->indirect);
504   }
505
506   struct vn_instance_submission submit;
507   VkResult result =
508      vn_instance_submission_prepare(&submit, cs, ring, extra_shmem, direct);
509   if (result != VK_SUCCESS)
510      return result;
511
512   uint32_t seqno;
513   const bool notify = vn_ring_submit(ring, submit.submit, submit.cs, &seqno);
514   if (notify) {
515      uint32_t notify_ring_data[8];
516      struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL(
517         notify_ring_data, sizeof(notify_ring_data));
518      vn_encode_vkNotifyRingMESA(&local_enc, 0, instance->ring.id, seqno, 0);
519      vn_renderer_submit_simple(instance->renderer, notify_ring_data,
520                                vn_cs_encoder_get_len(&local_enc));
521   }
522
523   vn_instance_submission_cleanup(&submit);
524
525   if (ring_seqno)
526      *ring_seqno = seqno;
527
528   return VK_SUCCESS;
529}
530
531VkResult
532vn_instance_ring_submit(struct vn_instance *instance,
533                        const struct vn_cs_encoder *cs)
534{
535   mtx_lock(&instance->ring.mutex);
536   VkResult result = vn_instance_ring_submit_locked(instance, cs, NULL, NULL);
537   mtx_unlock(&instance->ring.mutex);
538
539   return result;
540}
541
542static bool
543vn_instance_grow_reply_shmem_locked(struct vn_instance *instance, size_t size)
544{
545   const size_t min_shmem_size = 1 << 20;
546
547   size_t shmem_size =
548      instance->reply.size ? instance->reply.size : min_shmem_size;
549   while (shmem_size < size) {
550      shmem_size <<= 1;
551      if (!shmem_size)
552         return false;
553   }
554
555   struct vn_renderer_shmem *shmem =
556      vn_renderer_shmem_create(instance->renderer, shmem_size);
557   if (!shmem)
558      return false;
559
560   if (instance->reply.shmem)
561      vn_renderer_shmem_unref(instance->renderer, instance->reply.shmem);
562   instance->reply.shmem = shmem;
563   instance->reply.size = shmem_size;
564   instance->reply.used = 0;
565   instance->reply.ptr = shmem->mmap_ptr;
566
567   return true;
568}
569
570static struct vn_renderer_shmem *
571vn_instance_get_reply_shmem_locked(struct vn_instance *instance,
572                                   size_t size,
573                                   void **ptr)
574{
575   if (unlikely(instance->reply.used + size > instance->reply.size)) {
576      if (!vn_instance_grow_reply_shmem_locked(instance, size))
577         return NULL;
578
579      uint32_t set_reply_command_stream_data[16];
580      struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL(
581         set_reply_command_stream_data,
582         sizeof(set_reply_command_stream_data));
583      const struct VkCommandStreamDescriptionMESA stream = {
584         .resourceId = instance->reply.shmem->res_id,
585         .size = instance->reply.size,
586      };
587      vn_encode_vkSetReplyCommandStreamMESA(&local_enc, 0, &stream);
588      vn_cs_encoder_commit(&local_enc);
589
590      if (likely(instance->ring.id)) {
591         vn_instance_roundtrip(instance);
592         vn_instance_ring_submit_locked(instance, &local_enc, NULL, NULL);
593      } else {
594         vn_renderer_submit_simple(instance->renderer,
595                                   set_reply_command_stream_data,
596                                   vn_cs_encoder_get_len(&local_enc));
597      }
598   }
599
600   /* TODO avoid this seek command and go lock-free? */
601   uint32_t seek_reply_command_stream_data[8];
602   struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL(
603      seek_reply_command_stream_data, sizeof(seek_reply_command_stream_data));
604   const size_t offset = instance->reply.used;
605   vn_encode_vkSeekReplyCommandStreamMESA(&local_enc, 0, offset);
606   vn_cs_encoder_commit(&local_enc);
607
608   if (likely(instance->ring.id)) {
609      vn_instance_ring_submit_locked(instance, &local_enc, NULL, NULL);
610   } else {
611      vn_renderer_submit_simple(instance->renderer,
612                                seek_reply_command_stream_data,
613                                vn_cs_encoder_get_len(&local_enc));
614   }
615
616   *ptr = instance->reply.ptr + offset;
617   instance->reply.used += size;
618
619   return vn_renderer_shmem_ref(instance->renderer, instance->reply.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   const VkAllocationCallbacks *alloc =
695      pAllocator ? pAllocator : vk_default_allocator();
696   struct vn_instance *instance;
697   VkResult result;
698
699   vn_debug_init();
700   vn_trace_init();
701
702   instance = vk_zalloc(alloc, sizeof(*instance), VN_DEFAULT_ALIGN,
703                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
704   if (!instance)
705      return vn_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
706
707   struct vk_instance_dispatch_table dispatch_table;
708   vk_instance_dispatch_table_from_entrypoints(
709      &dispatch_table, &vn_instance_entrypoints, true);
710   vk_instance_dispatch_table_from_entrypoints(
711      &dispatch_table, &wsi_instance_entrypoints, false);
712   result = vn_instance_base_init(&instance->base,
713                                  &vn_instance_supported_extensions,
714                                  &dispatch_table, pCreateInfo, alloc);
715   if (result != VK_SUCCESS) {
716      vk_free(alloc, instance);
717      return vn_error(NULL, result);
718   }
719
720   mtx_init(&instance->physical_device.mutex, mtx_plain);
721
722   if (!vn_icd_supports_api_version(
723          instance->base.base.app_info.api_version)) {
724      result = VK_ERROR_INCOMPATIBLE_DRIVER;
725      goto fail;
726   }
727
728   if (pCreateInfo->enabledLayerCount) {
729      result = VK_ERROR_LAYER_NOT_PRESENT;
730      goto fail;
731   }
732
733   result = vn_instance_init_renderer(instance);
734   if (result != VK_SUCCESS)
735      goto fail;
736
737   result = vn_instance_init_experimental_features(instance);
738   if (result != VK_SUCCESS)
739      goto fail;
740
741   result = vn_instance_init_ring(instance);
742   if (result != VK_SUCCESS)
743      goto fail;
744
745   result = vn_instance_init_renderer_versions(instance);
746   if (result != VK_SUCCESS)
747      goto fail;
748
749   VkInstanceCreateInfo local_create_info = *pCreateInfo;
750   local_create_info.ppEnabledExtensionNames = NULL;
751   local_create_info.enabledExtensionCount = 0;
752   pCreateInfo = &local_create_info;
753
754   VkApplicationInfo local_app_info;
755   if (instance->base.base.app_info.api_version <
756       instance->renderer_api_version) {
757      if (pCreateInfo->pApplicationInfo) {
758         local_app_info = *pCreateInfo->pApplicationInfo;
759         local_app_info.apiVersion = instance->renderer_api_version;
760      } else {
761         local_app_info = (const VkApplicationInfo){
762            .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
763            .apiVersion = instance->renderer_api_version,
764         };
765      }
766      local_create_info.pApplicationInfo = &local_app_info;
767   }
768
769   VkInstance instance_handle = vn_instance_to_handle(instance);
770   result =
771      vn_call_vkCreateInstance(instance, pCreateInfo, NULL, &instance_handle);
772   if (result != VK_SUCCESS)
773      goto fail;
774
775   driParseOptionInfo(&instance->available_dri_options, vn_dri_options,
776                      ARRAY_SIZE(vn_dri_options));
777   driParseConfigFiles(&instance->dri_options,
778                       &instance->available_dri_options, 0, "venus", NULL, NULL,
779                       instance->base.base.app_info.app_name,
780                       instance->base.base.app_info.app_version,
781                       instance->base.base.app_info.engine_name,
782                       instance->base.base.app_info.engine_version);
783
784   *pInstance = instance_handle;
785
786   return VK_SUCCESS;
787
788fail:
789   if (instance->reply.shmem)
790      vn_renderer_shmem_unref(instance->renderer, instance->reply.shmem);
791
792   if (instance->ring.shmem) {
793      uint32_t destroy_ring_data[4];
794      struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL(
795         destroy_ring_data, sizeof(destroy_ring_data));
796      vn_encode_vkDestroyRingMESA(&local_enc, 0, instance->ring.id);
797      vn_renderer_submit_simple(instance->renderer, destroy_ring_data,
798                                vn_cs_encoder_get_len(&local_enc));
799
800      mtx_destroy(&instance->ring.roundtrip_mutex);
801      vn_cs_encoder_fini(&instance->ring.upload);
802      vn_renderer_shmem_unref(instance->renderer, instance->ring.shmem);
803      vn_ring_fini(&instance->ring.ring);
804      mtx_destroy(&instance->ring.mutex);
805   }
806
807   if (instance->renderer)
808      vn_renderer_destroy(instance->renderer, alloc);
809
810   mtx_destroy(&instance->physical_device.mutex);
811
812   vn_instance_base_fini(&instance->base);
813   vk_free(alloc, instance);
814
815   return vn_error(NULL, result);
816}
817
818void
819vn_DestroyInstance(VkInstance _instance,
820                   const VkAllocationCallbacks *pAllocator)
821{
822   struct vn_instance *instance = vn_instance_from_handle(_instance);
823   const VkAllocationCallbacks *alloc =
824      pAllocator ? pAllocator : &instance->base.base.alloc;
825
826   if (!instance)
827      return;
828
829   if (instance->physical_device.initialized) {
830      for (uint32_t i = 0; i < instance->physical_device.device_count; i++)
831         vn_physical_device_fini(&instance->physical_device.devices[i]);
832      vk_free(alloc, instance->physical_device.devices);
833      vk_free(alloc, instance->physical_device.groups);
834   }
835   mtx_destroy(&instance->physical_device.mutex);
836
837   vn_call_vkDestroyInstance(instance, _instance, NULL);
838
839   vn_renderer_shmem_unref(instance->renderer, instance->reply.shmem);
840
841   uint32_t destroy_ring_data[4];
842   struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER_LOCAL(
843      destroy_ring_data, sizeof(destroy_ring_data));
844   vn_encode_vkDestroyRingMESA(&local_enc, 0, instance->ring.id);
845   vn_renderer_submit_simple(instance->renderer, destroy_ring_data,
846                             vn_cs_encoder_get_len(&local_enc));
847
848   mtx_destroy(&instance->ring.roundtrip_mutex);
849   vn_cs_encoder_fini(&instance->ring.upload);
850   vn_ring_fini(&instance->ring.ring);
851   mtx_destroy(&instance->ring.mutex);
852   vn_renderer_shmem_unref(instance->renderer, instance->ring.shmem);
853
854   vn_renderer_destroy(instance->renderer, alloc);
855
856   driDestroyOptionCache(&instance->dri_options);
857   driDestroyOptionInfo(&instance->available_dri_options);
858
859   vn_instance_base_fini(&instance->base);
860   vk_free(alloc, instance);
861}
862
863PFN_vkVoidFunction
864vn_GetInstanceProcAddr(VkInstance _instance, const char *pName)
865{
866   struct vn_instance *instance = vn_instance_from_handle(_instance);
867   return vk_instance_get_proc_addr(&instance->base.base,
868                                    &vn_instance_entrypoints, pName);
869}
870