venus: initial support for vkCreateInstance
authorChia-I Wu <olvaffe@gmail.com>
Tue, 29 Oct 2019 19:03:53 +0000 (12:03 -0700)
committerMarge Bot <eric+marge@anholt.net>
Thu, 8 Apr 2021 17:15:37 +0000 (17:15 +0000)
Connect to the renderer.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
Reviewed-by: Ryan Neph <ryanneph@google.com>
Reviewed-by: Gert Wollny <gert.wollny@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5800>

src/virtio/vulkan/vn_cs.c
src/virtio/vulkan/vn_cs.h
src/virtio/vulkan/vn_device.c
src/virtio/vulkan/vn_device.h

index 158dcbf..d11062e 100644 (file)
@@ -190,15 +190,28 @@ vn_cs_encoder_reserve_internal(struct vn_cs_encoder *enc, size_t size)
          return false;
    }
 
-   /* TODO allocate bo */
-   struct vn_renderer_bo *bo = NULL;
-   void *base = NULL;
-   VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
+   struct vn_renderer_bo *bo;
+   VkResult result =
+      vn_renderer_bo_create_cpu(enc->instance->renderer, buf_size, &bo);
    if (result != VK_SUCCESS)
       return false;
 
+   void *base = vn_renderer_bo_map(bo);
+   if (!base) {
+      vn_renderer_bo_unref(bo);
+      return false;
+   }
+
+   uint32_t roundtrip;
+   result = vn_instance_submit_roundtrip(enc->instance, &roundtrip);
+   if (result != VK_SUCCESS) {
+      vn_renderer_bo_unref(bo);
+      return false;
+   }
+
    vn_cs_encoder_add_buffer(enc, bo, 0, base, buf_size);
    enc->current_buffer_size = buf_size;
+   enc->current_buffer_roundtrip = roundtrip;
 
    vn_cs_encoder_sanity_check(enc);
 
index 1a0ba16..3c52926 100644 (file)
@@ -46,6 +46,7 @@ struct vn_cs_encoder {
 
    /* the current buffer is buffers[buffer_count - 1].bo */
    size_t current_buffer_size;
+   uint32_t current_buffer_roundtrip;
 
    /* cur is the write pointer.  When cur passes end, the slow path is
     * triggered.
index 3a655f5..dcd916d 100644 (file)
 
 #include "vn_device.h"
 
+#include "util/driconf.h"
+#include "venus-protocol/vn_protocol_driver.h"
+
 #include "vn_icd.h"
+#include "vn_renderer.h"
+
+/* require and request at least Vulkan 1.1 at both instance and device levels
+ */
+#define VN_MIN_RENDERER_VERSION VK_API_VERSION_1_1
 
 /*
  * Instance extensions add instance-level or physical-device-level
 static const struct vk_instance_extension_table
    vn_instance_supported_extensions;
 
+static const driOptionDescription vn_dri_options[] = {
+   /* clang-format off */
+   DRI_CONF_SECTION_PERFORMANCE
+      DRI_CONF_VK_X11_ENSURE_MIN_IMAGE_COUNT(false)
+      DRI_CONF_VK_X11_OVERRIDE_MIN_IMAGE_COUNT(0)
+      DRI_CONF_VK_X11_STRICT_IMAGE_COUNT(false)
+   DRI_CONF_SECTION_END
+   DRI_CONF_SECTION_DEBUG
+      DRI_CONF_VK_WSI_FORCE_BGRA8_UNORM_FIRST(false)
+   DRI_CONF_SECTION_END
+   /* clang-format on */
+};
+
+static VkResult
+vn_instance_init_version(struct vn_instance *instance)
+{
+   uint32_t renderer_version = 0;
+   VkResult result =
+      vn_call_vkEnumerateInstanceVersion(instance, &renderer_version);
+   if (result != VK_SUCCESS) {
+      if (VN_DEBUG(INIT))
+         vn_log(instance, "failed to enumerate renderer instance version");
+      return result;
+   }
+
+   if (renderer_version < VN_MIN_RENDERER_VERSION) {
+      if (VN_DEBUG(INIT)) {
+         vn_log(instance, "unsupported renderer instance version %d.%d",
+                VK_VERSION_MAJOR(instance->renderer_version),
+                VK_VERSION_MINOR(instance->renderer_version));
+      }
+      return VK_ERROR_INITIALIZATION_FAILED;
+   }
+
+   instance->renderer_version =
+      instance->base.base.app_info.api_version > VN_MIN_RENDERER_VERSION
+         ? instance->base.base.app_info.api_version
+         : VN_MIN_RENDERER_VERSION;
+
+   if (VN_DEBUG(INIT)) {
+      vn_log(instance, "vk instance version %d.%d.%d",
+             VK_VERSION_MAJOR(instance->renderer_version),
+             VK_VERSION_MINOR(instance->renderer_version),
+             VK_VERSION_PATCH(instance->renderer_version));
+   }
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+vn_instance_init_ring(struct vn_instance *instance)
+{
+   /* 32-bit seqno for renderer roundtrips */
+   const size_t extra_size = sizeof(uint32_t);
+   struct vn_ring_layout layout;
+   vn_ring_get_layout(extra_size, &layout);
+
+   void *ring_ptr;
+   VkResult result = vn_renderer_bo_create_cpu(
+      instance->renderer, layout.bo_size, &instance->ring.bo);
+   if (result == VK_SUCCESS) {
+      ring_ptr = vn_renderer_bo_map(instance->ring.bo);
+      if (!ring_ptr)
+         result = VK_ERROR_OUT_OF_DEVICE_MEMORY;
+   }
+   if (result != VK_SUCCESS) {
+      if (VN_DEBUG(INIT))
+         vn_log(instance, "failed to allocate/map ring bo");
+      return result;
+   }
+
+   mtx_init(&instance->ring.mutex, mtx_plain);
+
+   struct vn_ring *ring = &instance->ring.ring;
+   vn_ring_init(ring, &layout, ring_ptr);
+
+   instance->ring.id = (uintptr_t)ring;
+
+   const struct VkRingCreateInfoMESA info = {
+      .sType = VK_STRUCTURE_TYPE_RING_CREATE_INFO_MESA,
+      .resourceId = instance->ring.bo->res_id,
+      .size = layout.bo_size,
+      .idleTimeout = 50ull * 1000 * 1000,
+      .headOffset = layout.head_offset,
+      .tailOffset = layout.tail_offset,
+      .statusOffset = layout.status_offset,
+      .bufferOffset = layout.buffer_offset,
+      .bufferSize = layout.buffer_size,
+      .extraOffset = layout.extra_offset,
+      .extraSize = layout.extra_size,
+   };
+
+   uint32_t create_ring_data[64];
+   struct vn_cs_encoder local_enc =
+      VN_CS_ENCODER_INITIALIZER(create_ring_data, sizeof(create_ring_data));
+   vn_encode_vkCreateRingMESA(&local_enc, 0, instance->ring.id, &info);
+   vn_renderer_submit_simple(instance->renderer, create_ring_data,
+                             vn_cs_encoder_get_len(&local_enc));
+
+   vn_cs_encoder_init_indirect(&instance->ring.upload, instance,
+                               1 * 1024 * 1024);
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+vn_instance_init_renderer(struct vn_instance *instance)
+{
+   const VkAllocationCallbacks *alloc = &instance->base.base.alloc;
+
+   VkResult result = vn_renderer_create(instance, alloc, &instance->renderer);
+   if (result != VK_SUCCESS)
+      return result;
+
+   mtx_init(&instance->roundtrip_mutex, mtx_plain);
+   instance->roundtrip_next = 1;
+
+   vn_renderer_get_info(instance->renderer, &instance->renderer_info);
+
+   uint32_t version = vn_info_wire_format_version();
+   if (instance->renderer_info.wire_format_version != version) {
+      if (VN_DEBUG(INIT)) {
+         vn_log(instance, "wire format version %d != %d",
+                instance->renderer_info.wire_format_version, version);
+      }
+      return VK_ERROR_INITIALIZATION_FAILED;
+   }
+
+   version = vn_info_vk_xml_version();
+   if (instance->renderer_info.vk_xml_version > version)
+      instance->renderer_info.vk_xml_version = version;
+
+   version = vn_info_extension_spec_version("VK_EXT_command_serialization");
+   if (instance->renderer_info.vk_ext_command_serialization_spec_version >
+       version) {
+      instance->renderer_info.vk_ext_command_serialization_spec_version =
+         version;
+   }
+
+   version = vn_info_extension_spec_version("VK_MESA_venus_protocol");
+   if (instance->renderer_info.vk_mesa_venus_protocol_spec_version >
+       version) {
+      instance->renderer_info.vk_mesa_venus_protocol_spec_version = version;
+   }
+
+   if (VN_DEBUG(INIT)) {
+      vn_log(instance, "connected to renderer");
+      vn_log(instance, "wire format version %d",
+             instance->renderer_info.wire_format_version);
+      vn_log(instance, "vk xml version %d.%d.%d",
+             VK_VERSION_MAJOR(instance->renderer_info.vk_xml_version),
+             VK_VERSION_MINOR(instance->renderer_info.vk_xml_version),
+             VK_VERSION_PATCH(instance->renderer_info.vk_xml_version));
+      vn_log(
+         instance, "VK_EXT_command_serialization spec version %d",
+         instance->renderer_info.vk_ext_command_serialization_spec_version);
+      vn_log(instance, "VK_MESA_venus_protocol spec version %d",
+             instance->renderer_info.vk_mesa_venus_protocol_spec_version);
+   }
+
+   return VK_SUCCESS;
+}
+
+VkResult
+vn_instance_submit_roundtrip(struct vn_instance *instance,
+                             uint32_t *roundtrip_seqno)
+{
+   uint32_t write_ring_extra_data[8];
+   struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER(
+      write_ring_extra_data, sizeof(write_ring_extra_data));
+
+   /* submit a vkWriteRingExtraMESA through the renderer */
+   mtx_lock(&instance->roundtrip_mutex);
+   const uint32_t seqno = instance->roundtrip_next++;
+   vn_encode_vkWriteRingExtraMESA(&local_enc, 0, instance->ring.id, 0, seqno);
+   VkResult result =
+      vn_renderer_submit_simple(instance->renderer, write_ring_extra_data,
+                                vn_cs_encoder_get_len(&local_enc));
+   mtx_unlock(&instance->roundtrip_mutex);
+
+   *roundtrip_seqno = seqno;
+   return result;
+}
+
+static void
+vn_instance_wait_roundtrip(struct vn_instance *instance,
+                           uint32_t roundtrip_seqno)
+{
+   const struct vn_ring *ring = &instance->ring.ring;
+   const volatile atomic_uint *ptr = ring->shared.extra;
+   uint32_t iter = 0;
+   do {
+      const uint32_t cur = atomic_load_explicit(ptr, memory_order_acquire);
+      if (cur >= roundtrip_seqno || roundtrip_seqno - cur >= INT32_MAX)
+         break;
+      vn_relax(&iter);
+   } while (true);
+}
+
+static void
+vn_instance_roundtrip(struct vn_instance *instance)
+{
+   uint32_t roundtrip_seqno;
+   if (vn_instance_submit_roundtrip(instance, &roundtrip_seqno) == VK_SUCCESS)
+      vn_instance_wait_roundtrip(instance, roundtrip_seqno);
+}
+
+struct vn_instance_submission {
+   uint32_t local_cs_data[64];
+
+   void *cs_data;
+   size_t cs_size;
+   struct vn_ring_submit *submit;
+};
+
+static void *
+vn_instance_submission_indirect_cs(struct vn_instance_submission *submit,
+                                   const struct vn_cs_encoder *cs,
+                                   size_t *cs_size)
+{
+   VkCommandStreamDescriptionMESA local_descs[8];
+   VkCommandStreamDescriptionMESA *descs = local_descs;
+   if (cs->buffer_count > ARRAY_SIZE(local_descs)) {
+      descs =
+         malloc(sizeof(VkCommandStreamDescriptionMESA) * cs->buffer_count);
+      if (!descs)
+         return NULL;
+   }
+
+   uint32_t desc_count = 0;
+   for (uint32_t i = 0; i < cs->buffer_count; i++) {
+      const struct vn_cs_encoder_buffer *buf = &cs->buffers[i];
+      if (buf->committed_size) {
+         descs[desc_count++] = (VkCommandStreamDescriptionMESA){
+            .resourceId = buf->bo->res_id,
+            .offset = buf->offset,
+            .size = buf->committed_size,
+         };
+      }
+   }
+
+   const size_t exec_size = vn_sizeof_vkExecuteCommandStreamsMESA(
+      desc_count, descs, NULL, 0, NULL, 0);
+   void *exec_data = submit->local_cs_data;
+   if (exec_size > sizeof(submit->local_cs_data)) {
+      exec_data = malloc(exec_size);
+      if (!exec_data)
+         goto out;
+   }
+
+   struct vn_cs_encoder local_enc =
+      VN_CS_ENCODER_INITIALIZER(exec_data, exec_size);
+   vn_encode_vkExecuteCommandStreamsMESA(&local_enc, 0, desc_count, descs,
+                                         NULL, 0, NULL, 0);
+
+   *cs_size = vn_cs_encoder_get_len(&local_enc);
+
+out:
+   if (descs != local_descs)
+      free(descs);
+
+   return exec_data;
+}
+
+static void *
+vn_instance_submission_direct_cs(struct vn_instance_submission *submit,
+                                 const struct vn_cs_encoder *cs,
+                                 size_t *cs_size)
+{
+   if (cs->buffer_count == 1) {
+      *cs_size = cs->buffers[0].committed_size;
+      return cs->buffers[0].base;
+   }
+
+   assert(vn_cs_encoder_get_len(cs) <= sizeof(submit->local_cs_data));
+   void *dst = submit->local_cs_data;
+   for (uint32_t i = 0; i < cs->buffer_count; i++) {
+      const struct vn_cs_encoder_buffer *buf = &cs->buffers[i];
+      memcpy(dst, buf->base, buf->committed_size);
+      dst += buf->committed_size;
+   }
+
+   *cs_size = dst - (void *)submit->local_cs_data;
+   return submit->local_cs_data;
+}
+
+static struct vn_ring_submit *
+vn_instance_submission_get_ring_submit(struct vn_ring *ring,
+                                       const struct vn_cs_encoder *cs,
+                                       struct vn_renderer_bo *extra_bo,
+                                       bool direct)
+{
+   const uint32_t bo_count =
+      (direct ? 0 : cs->buffer_count) + (extra_bo ? 1 : 0);
+   struct vn_ring_submit *submit = vn_ring_get_submit(ring, bo_count);
+   if (!submit)
+      return NULL;
+
+   submit->bo_count = bo_count;
+   if (!direct) {
+      for (uint32_t i = 0; i < cs->buffer_count; i++)
+         submit->bos[i] = vn_renderer_bo_ref(cs->buffers[i].bo);
+   }
+   if (extra_bo)
+      submit->bos[bo_count - 1] = vn_renderer_bo_ref(extra_bo);
+
+   return submit;
+}
+
+static void
+vn_instance_submission_cleanup(struct vn_instance_submission *submit,
+                               const struct vn_cs_encoder *cs)
+{
+   if (submit->cs_data != submit->local_cs_data &&
+       submit->cs_data != cs->buffers[0].base)
+      free(submit->cs_data);
+}
+
+static VkResult
+vn_instance_submission_prepare(struct vn_instance_submission *submit,
+                               const struct vn_cs_encoder *cs,
+                               struct vn_ring *ring,
+                               struct vn_renderer_bo *extra_bo,
+                               bool direct)
+{
+   if (direct) {
+      submit->cs_data =
+         vn_instance_submission_direct_cs(submit, cs, &submit->cs_size);
+   } else {
+      submit->cs_data =
+         vn_instance_submission_indirect_cs(submit, cs, &submit->cs_size);
+   }
+   if (!submit->cs_data)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   submit->submit =
+      vn_instance_submission_get_ring_submit(ring, cs, extra_bo, direct);
+   if (!submit->submit) {
+      vn_instance_submission_cleanup(submit, cs);
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+   }
+
+   return VK_SUCCESS;
+}
+
+static bool
+vn_instance_submission_can_direct(const struct vn_cs_encoder *cs)
+{
+   struct vn_instance_submission submit;
+   return vn_cs_encoder_get_len(cs) <= sizeof(submit.local_cs_data);
+}
+
+static struct vn_cs_encoder *
+vn_instance_ring_cs_upload_locked(struct vn_instance *instance,
+                                  const struct vn_cs_encoder *cs)
+{
+   assert(!cs->indirect && cs->buffer_count == 1);
+   const void *cs_data = cs->buffers[0].base;
+   const size_t cs_size = cs->total_committed_size;
+   assert(cs_size == vn_cs_encoder_get_len(cs));
+
+   struct vn_cs_encoder *upload = &instance->ring.upload;
+   vn_cs_encoder_reset(upload);
+
+   if (!vn_cs_encoder_reserve(upload, cs_size))
+      return NULL;
+
+   vn_cs_encoder_write(upload, cs_size, cs_data, cs_size);
+   vn_cs_encoder_commit(upload);
+   vn_instance_wait_roundtrip(instance, upload->current_buffer_roundtrip);
+
+   return upload;
+}
+
+static VkResult
+vn_instance_ring_submit_locked(struct vn_instance *instance,
+                               const struct vn_cs_encoder *cs,
+                               struct vn_renderer_bo *extra_bo,
+                               uint32_t *ring_seqno)
+{
+   struct vn_ring *ring = &instance->ring.ring;
+
+   const bool direct = vn_instance_submission_can_direct(cs);
+   if (!direct && !cs->indirect) {
+      cs = vn_instance_ring_cs_upload_locked(instance, cs);
+      if (!cs)
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+      assert(cs->indirect);
+   }
+
+   struct vn_instance_submission submit;
+   VkResult result =
+      vn_instance_submission_prepare(&submit, cs, ring, extra_bo, direct);
+   if (result != VK_SUCCESS)
+      return result;
+
+   uint32_t seqno;
+   const bool notify = vn_ring_submit(ring, submit.submit, submit.cs_data,
+                                      submit.cs_size, &seqno);
+   if (notify) {
+      uint32_t notify_ring_data[8];
+      struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER(
+         notify_ring_data, sizeof(notify_ring_data));
+      vn_encode_vkNotifyRingMESA(&local_enc, 0, instance->ring.id, seqno, 0);
+      vn_renderer_submit_simple(instance->renderer, notify_ring_data,
+                                vn_cs_encoder_get_len(&local_enc));
+   }
+
+   vn_instance_submission_cleanup(&submit, cs);
+
+   if (ring_seqno)
+      *ring_seqno = seqno;
+
+   return VK_SUCCESS;
+}
+
+static bool
+vn_instance_grow_reply_bo_locked(struct vn_instance *instance, size_t size)
+{
+   const size_t min_bo_size = 1 << 20;
+
+   size_t bo_size = instance->reply.size ? instance->reply.size : min_bo_size;
+   while (bo_size < size) {
+      bo_size <<= 1;
+      if (!bo_size)
+         return false;
+   }
+
+   struct vn_renderer_bo *bo;
+   VkResult result =
+      vn_renderer_bo_create_cpu(instance->renderer, bo_size, &bo);
+   if (result != VK_SUCCESS)
+      return false;
+
+   void *ptr = vn_renderer_bo_map(bo);
+   if (!ptr) {
+      vn_renderer_bo_unref(bo);
+      return false;
+   }
+
+   if (instance->reply.bo)
+      vn_renderer_bo_unref(instance->reply.bo);
+   instance->reply.bo = bo;
+   instance->reply.size = bo_size;
+   instance->reply.used = 0;
+   instance->reply.ptr = ptr;
+
+   return true;
+}
+
+static struct vn_renderer_bo *
+vn_instance_get_reply_bo_locked(struct vn_instance *instance,
+                                size_t size,
+                                void **ptr)
+{
+   if (unlikely(instance->reply.used + size > instance->reply.size)) {
+      if (!vn_instance_grow_reply_bo_locked(instance, size))
+         return NULL;
+
+      uint32_t set_reply_command_stream_data[16];
+      struct vn_cs_encoder local_enc =
+         VN_CS_ENCODER_INITIALIZER(set_reply_command_stream_data,
+                                   sizeof(set_reply_command_stream_data));
+      const struct VkCommandStreamDescriptionMESA stream = {
+         .resourceId = instance->reply.bo->res_id,
+         .size = instance->reply.size,
+      };
+      vn_encode_vkSetReplyCommandStreamMESA(&local_enc, 0, &stream);
+      vn_cs_encoder_commit(&local_enc);
+
+      vn_instance_roundtrip(instance);
+      vn_instance_ring_submit_locked(instance, &local_enc, NULL, NULL);
+   }
+
+   /* TODO avoid this seek command and go lock-free? */
+   uint32_t seek_reply_command_stream_data[8];
+   struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER(
+      seek_reply_command_stream_data, sizeof(seek_reply_command_stream_data));
+   const size_t offset = instance->reply.used;
+   vn_encode_vkSeekReplyCommandStreamMESA(&local_enc, 0, offset);
+   vn_cs_encoder_commit(&local_enc);
+   vn_instance_ring_submit_locked(instance, &local_enc, NULL, NULL);
+
+   *ptr = instance->reply.ptr + offset;
+   instance->reply.used += size;
+
+   return vn_renderer_bo_ref(instance->reply.bo);
+}
+
+void
+vn_instance_submit_command(struct vn_instance *instance,
+                           struct vn_instance_submit_command *submit)
+{
+   void *reply_ptr;
+   submit->reply_bo = NULL;
+
+   mtx_lock(&instance->ring.mutex);
+
+   if (vn_cs_encoder_is_empty(&submit->command))
+      goto fail;
+   vn_cs_encoder_commit(&submit->command);
+
+   if (submit->reply_size) {
+      submit->reply_bo = vn_instance_get_reply_bo_locked(
+         instance, submit->reply_size, &reply_ptr);
+      if (!submit->reply_bo)
+         goto fail;
+   }
+
+   uint32_t ring_seqno;
+   VkResult result = vn_instance_ring_submit_locked(
+      instance, &submit->command, submit->reply_bo, &ring_seqno);
+
+   mtx_unlock(&instance->ring.mutex);
+
+   submit->reply = VN_CS_DECODER_INITIALIZER(reply_ptr, submit->reply_size);
+
+   if (submit->reply_size && result == VK_SUCCESS)
+      vn_ring_wait(&instance->ring.ring, ring_seqno);
+
+   return;
+
+fail:
+   instance->ring.command_dropped++;
+   mtx_unlock(&instance->ring.mutex);
+}
+
 /* instance commands */
 
 VkResult
@@ -88,15 +623,80 @@ vn_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
       goto fail;
    }
 
-   if (pCreateInfo->enabledExtensionCount) {
-      result = VK_ERROR_EXTENSION_NOT_PRESENT;
+   result = vn_instance_init_renderer(instance);
+   if (result != VK_SUCCESS)
       goto fail;
+
+   result = vn_instance_init_ring(instance);
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   result = vn_instance_init_version(instance);
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   VkInstanceCreateInfo local_create_info;
+   local_create_info = *pCreateInfo;
+   local_create_info.ppEnabledExtensionNames = NULL;
+   local_create_info.enabledExtensionCount = 0;
+   pCreateInfo = &local_create_info;
+
+   /* request at least instance->renderer_version */
+   VkApplicationInfo local_app_info = {
+      .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+      .apiVersion = instance->renderer_version,
+   };
+   if (instance->base.base.app_info.api_version <
+       instance->renderer_version) {
+      if (pCreateInfo->pApplicationInfo) {
+         local_app_info = *pCreateInfo->pApplicationInfo;
+         local_app_info.apiVersion = instance->renderer_version;
+      }
+      local_create_info.pApplicationInfo = &local_app_info;
    }
 
-   *pInstance = vn_instance_to_handle(instance);
+   VkInstance instance_handle = vn_instance_to_handle(instance);
+   result =
+      vn_call_vkCreateInstance(instance, pCreateInfo, NULL, &instance_handle);
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   driParseOptionInfo(&instance->available_dri_options, vn_dri_options,
+                      ARRAY_SIZE(vn_dri_options));
+   driParseConfigFiles(&instance->dri_options,
+                       &instance->available_dri_options, 0, "venus", NULL,
+                       instance->base.base.app_info.app_name,
+                       instance->base.base.app_info.app_version,
+                       instance->base.base.app_info.engine_name,
+                       instance->base.base.app_info.engine_version);
+
+   *pInstance = instance_handle;
+
    return VK_SUCCESS;
 
 fail:
+   if (instance->reply.bo)
+      vn_renderer_bo_unref(instance->reply.bo);
+
+   if (instance->ring.bo) {
+      uint32_t destroy_ring_data[4];
+      struct vn_cs_encoder local_enc = VN_CS_ENCODER_INITIALIZER(
+         destroy_ring_data, sizeof(destroy_ring_data));
+      vn_encode_vkDestroyRingMESA(&local_enc, 0, instance->ring.id);
+      vn_renderer_submit_simple(instance->renderer, destroy_ring_data,
+                                vn_cs_encoder_get_len(&local_enc));
+
+      vn_cs_encoder_fini(&instance->ring.upload);
+      vn_renderer_bo_unref(instance->ring.bo);
+      vn_ring_fini(&instance->ring.ring);
+      mtx_destroy(&instance->ring.mutex);
+   }
+
+   if (instance->renderer) {
+      mtx_destroy(&instance->roundtrip_mutex);
+      vn_renderer_destroy(instance->renderer, alloc);
+   }
+
    vn_instance_base_fini(&instance->base);
    vk_free(alloc, instance);
 
@@ -114,6 +714,28 @@ vn_DestroyInstance(VkInstance _instance,
    if (!instance)
       return;
 
+   vn_call_vkDestroyInstance(instance, _instance, NULL);
+
+   vn_renderer_bo_unref(instance->reply.bo);
+
+   uint32_t destroy_ring_data[4];
+   struct vn_cs_encoder local_enc =
+      VN_CS_ENCODER_INITIALIZER(destroy_ring_data, sizeof(destroy_ring_data));
+   vn_encode_vkDestroyRingMESA(&local_enc, 0, instance->ring.id);
+   vn_renderer_submit_simple(instance->renderer, destroy_ring_data,
+                             vn_cs_encoder_get_len(&local_enc));
+
+   vn_cs_encoder_fini(&instance->ring.upload);
+   vn_ring_fini(&instance->ring.ring);
+   mtx_destroy(&instance->ring.mutex);
+   vn_renderer_bo_unref(instance->ring.bo);
+
+   mtx_destroy(&instance->roundtrip_mutex);
+   vn_renderer_destroy(instance->renderer, alloc);
+
+   driDestroyOptionCache(&instance->dri_options);
+   driDestroyOptionInfo(&instance->available_dri_options);
+
    vn_instance_base_fini(&instance->base);
    vk_free(alloc, instance);
 }
index ce5b7e3..950d628 100644 (file)
 
 #include "vn_common.h"
 
+#include "vn_cs.h"
+#include "vn_renderer.h"
+#include "vn_ring.h"
+
 struct vn_instance {
    struct vn_instance_base base;
+
+   struct driOptionCache dri_options;
+   struct driOptionCache available_dri_options;
+
+   struct vn_renderer *renderer;
+   struct vn_renderer_info renderer_info;
+   uint32_t renderer_version;
+
+   /* to synchronize renderer/ring */
+   mtx_t roundtrip_mutex;
+   uint32_t roundtrip_next;
+
+   struct {
+      mtx_t mutex;
+      struct vn_renderer_bo *bo;
+      struct vn_ring ring;
+      uint64_t id;
+
+      struct vn_cs_encoder upload;
+      uint32_t command_dropped;
+   } ring;
+
+   struct {
+      struct vn_renderer_bo *bo;
+      size_t size;
+      size_t used;
+      void *ptr;
+   } reply;
 };
 VK_DEFINE_HANDLE_CASTS(vn_instance,
                        base.base.base,
@@ -56,4 +88,23 @@ VK_DEFINE_HANDLE_CASTS(vn_command_buffer,
                        VkCommandBuffer,
                        VK_OBJECT_TYPE_COMMAND_BUFFER)
 
+VkResult
+vn_instance_submit_roundtrip(struct vn_instance *instance,
+                             uint32_t *roundtrip_seqno);
+
+struct vn_instance_submit_command {
+   /* empty command implies errors */
+   struct vn_cs_encoder command;
+   /* non-zero implies waiting */
+   size_t reply_size;
+
+   /* when reply_size is non-zero, NULL can be returned on errors */
+   struct vn_renderer_bo *reply_bo;
+   struct vn_cs_decoder reply;
+};
+
+void
+vn_instance_submit_command(struct vn_instance *instance,
+                           struct vn_instance_submit_command *submit);
+
 #endif /* VN_DEVICE_H */