nvk: add cmd buffer framework
authorDave Airlie <airlied@redhat.com>
Tue, 31 May 2022 00:35:42 +0000 (10:35 +1000)
committerMarge Bot <emma+marge@anholt.net>
Fri, 4 Aug 2023 21:31:53 +0000 (21:31 +0000)
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>

src/nouveau/vulkan/meson.build
src/nouveau/vulkan/nvk_cmd_buffer.c [new file with mode: 0644]
src/nouveau/vulkan/nvk_cmd_buffer.h [new file with mode: 0644]
src/nouveau/vulkan/nvk_device.c

index f35709f..3d6dbe5 100644 (file)
@@ -1,6 +1,8 @@
 nvk_files = files(
   'nvk_buffer.c',
   'nvk_buffer.h',
+  'nvk_cmd_buffer.c',
+  'nvk_cmd_buffer.h',
   'nvk_device.c',
   'nvk_device.h',
   'nvk_device_memory.c',
diff --git a/src/nouveau/vulkan/nvk_cmd_buffer.c b/src/nouveau/vulkan/nvk_cmd_buffer.c
new file mode 100644 (file)
index 0000000..c53d03b
--- /dev/null
@@ -0,0 +1,211 @@
+#include "nvk_cmd_buffer.h"
+
+#include "nvk_device.h"
+#include "nvk_physical_device.h"
+
+#include "nouveau_push.h"
+
+static void
+nvk_destroy_cmd_buffer(struct nvk_cmd_buffer *cmd_buffer)
+{
+   list_del(&cmd_buffer->pool_link);
+
+   nouveau_ws_push_destroy(cmd_buffer->push);
+   vk_command_buffer_finish(&cmd_buffer->vk);
+   vk_free(&cmd_buffer->pool->vk.alloc, cmd_buffer);
+}
+
+static VkResult
+nvk_create_cmd_buffer(struct nvk_device *device, struct nvk_cmd_pool *pool,
+                      VkCommandBufferLevel level, VkCommandBuffer *pCommandBuffer)
+{
+   struct nvk_cmd_buffer *cmd_buffer;
+
+   cmd_buffer = vk_zalloc(&pool->vk.alloc, sizeof(*cmd_buffer), 8,
+                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (cmd_buffer == NULL)
+      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   VkResult result =
+      vk_command_buffer_init(&pool->vk, &cmd_buffer->vk, NULL, level);
+   if (result != VK_SUCCESS) {
+      vk_free(&cmd_buffer->pool->vk.alloc, cmd_buffer);
+      return result;
+   }
+
+   cmd_buffer->pool = pool;
+   list_addtail(&cmd_buffer->pool_link, &pool->cmd_buffers);
+
+   cmd_buffer->push = nouveau_ws_push_new(device->pdev->dev, NVK_CMD_BUF_SIZE);
+   *pCommandBuffer = nvk_cmd_buffer_to_handle(cmd_buffer);
+   return VK_SUCCESS;
+}
+
+static VkResult
+nvk_reset_cmd_buffer(struct nvk_cmd_buffer *cmd_buffer)
+{
+   vk_command_buffer_reset(&cmd_buffer->vk);
+   return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+nvk_CreateCommandPool(VkDevice _device, const VkCommandPoolCreateInfo *pCreateInfo,
+                      const VkAllocationCallbacks *pAllocator, VkCommandPool *pCmdPool)
+{
+   VK_FROM_HANDLE(nvk_device, device, _device);
+   struct nvk_cmd_pool *pool;
+
+   pool =
+      vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*pool), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (pool == NULL)
+      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   VkResult result = vk_command_pool_init(&device->vk, &pool->vk, pCreateInfo, pAllocator);
+   if (result != VK_SUCCESS) {
+      vk_free2(&device->vk.alloc, pAllocator, pool);
+      return result;
+   }
+
+   list_inithead(&pool->cmd_buffers);
+   list_inithead(&pool->free_cmd_buffers);
+
+   *pCmdPool = nvk_cmd_pool_to_handle(pool);
+   return VK_SUCCESS;
+}
+
+VKAPI_ATTR void VKAPI_CALL
+nvk_DestroyCommandPool(VkDevice _device, VkCommandPool commandPool,
+                       const VkAllocationCallbacks *pAllocator)
+{
+   VK_FROM_HANDLE(nvk_device, device, _device);
+   VK_FROM_HANDLE(nvk_cmd_pool, pool, commandPool);
+
+   if (!pool)
+      return;
+
+   list_for_each_entry_safe(struct nvk_cmd_buffer, cmd_buffer, &pool->cmd_buffers, pool_link)
+   {
+      nvk_destroy_cmd_buffer(cmd_buffer);
+   }
+
+   list_for_each_entry_safe(struct nvk_cmd_buffer, cmd_buffer, &pool->free_cmd_buffers, pool_link)
+   {
+      nvk_destroy_cmd_buffer(cmd_buffer);
+   }
+
+   vk_command_pool_finish(&pool->vk);
+   vk_free2(&device->vk.alloc, pAllocator, pool);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+nvk_ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags)
+{
+   VK_FROM_HANDLE(nvk_cmd_pool, pool, commandPool);
+   VkResult result;
+
+   list_for_each_entry(struct nvk_cmd_buffer, cmd_buffer, &pool->cmd_buffers, pool_link)
+   {
+      result = nvk_reset_cmd_buffer(cmd_buffer);
+      if (result != VK_SUCCESS)
+         return result;
+   }
+
+   return VK_SUCCESS;
+}
+
+VKAPI_ATTR void VKAPI_CALL
+nvk_TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags)
+{
+   VK_FROM_HANDLE(nvk_cmd_pool, pool, commandPool);
+
+   list_for_each_entry_safe(struct nvk_cmd_buffer, cmd_buffer, &pool->free_cmd_buffers, pool_link)
+   {
+      nvk_destroy_cmd_buffer(cmd_buffer);
+   }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+nvk_AllocateCommandBuffers(VkDevice _device,
+                           const VkCommandBufferAllocateInfo *pAllocateInfo,
+                           VkCommandBuffer *pCommandBuffers)
+{
+   VK_FROM_HANDLE(nvk_device, device, _device);
+   VK_FROM_HANDLE(nvk_cmd_pool, pool, pAllocateInfo->commandPool);
+   uint32_t i;
+   VkResult result = VK_SUCCESS;
+
+   for (i = 0; i < pAllocateInfo->commandBufferCount; i++) {
+      if (!list_is_empty(&pool->free_cmd_buffers)) {
+         struct nvk_cmd_buffer *cmd_buffer =
+            list_first_entry(&pool->free_cmd_buffers, struct nvk_cmd_buffer, pool_link);
+
+         list_del(&cmd_buffer->pool_link);
+         list_addtail(&cmd_buffer->pool_link, &pool->cmd_buffers);
+
+         result = nvk_reset_cmd_buffer(cmd_buffer);
+         vk_command_buffer_finish(&cmd_buffer->vk);
+         VkResult init_result =
+            vk_command_buffer_init(&pool->vk, &cmd_buffer->vk, NULL,
+                                   pAllocateInfo->level);
+         if (init_result != VK_SUCCESS)
+            result = init_result;
+
+         pCommandBuffers[i] = nvk_cmd_buffer_to_handle(cmd_buffer);
+      } else {
+         result = nvk_create_cmd_buffer(device, pool, pAllocateInfo->level, &pCommandBuffers[i]);
+      }
+      if (result != VK_SUCCESS)
+         break;
+   }
+
+   if (result != VK_SUCCESS) {
+      nvk_FreeCommandBuffers(_device, pAllocateInfo->commandPool, i, pCommandBuffers);
+      /* From the Vulkan 1.0.66 spec:
+       *
+       * "vkAllocateCommandBuffers can be used to create multiple
+       *  command buffers. If the creation of any of those command
+       *  buffers fails, the implementation must destroy all
+       *  successfully created command buffer objects from this
+       *  command, set all entries of the pCommandBuffers array to
+       *  NULL and return the error."
+       */
+      memset(pCommandBuffers, 0, sizeof(*pCommandBuffers) * pAllocateInfo->commandBufferCount);
+   }
+   return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL
+nvk_FreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
+                       const VkCommandBuffer *pCommandBuffers)
+{
+   VK_FROM_HANDLE(nvk_cmd_pool, pool, commandPool);
+   for (uint32_t i = 0; i < commandBufferCount; i++) {
+      VK_FROM_HANDLE(nvk_cmd_buffer, cmd_buffer, pCommandBuffers[i]);
+
+      if (!cmd_buffer)
+         continue;
+      assert(cmd_buffer->pool == pool);
+
+      list_del(&cmd_buffer->pool_link);
+      list_addtail(&cmd_buffer->pool_link, &pool->free_cmd_buffers);
+   }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+nvk_ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags)
+{
+   VK_FROM_HANDLE(nvk_cmd_buffer, cmd_buffer, commandBuffer);
+   return nvk_reset_cmd_buffer(cmd_buffer);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+nvk_BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo)
+{
+   return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+nvk_EndCommandBuffer(VkCommandBuffer commandBuffer)
+{
+   return VK_SUCCESS;
+}
diff --git a/src/nouveau/vulkan/nvk_cmd_buffer.h b/src/nouveau/vulkan/nvk_cmd_buffer.h
new file mode 100644 (file)
index 0000000..ac2d0d5
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef NVK_CMD_BUFFER_H
+#define NVK_CMD_BUFFER_H 1
+
+#include "nvk_private.h"
+
+#include "vulkan/runtime/vk_command_buffer.h"
+#include "vulkan/runtime/vk_command_pool.h"
+
+#define NVK_CMD_BUF_SIZE 64*1024
+
+struct nvk_cmd_pool {
+   struct vk_command_pool vk;
+   struct list_head cmd_buffers;
+   struct list_head free_cmd_buffers;
+};
+
+struct nvk_cmd_buffer {
+   struct vk_command_buffer vk;
+
+   struct nvk_cmd_pool *pool;
+   struct list_head pool_link;
+
+   struct nouveau_ws_push *push;
+};
+
+VK_DEFINE_HANDLE_CASTS(nvk_cmd_buffer, vk.base, VkCommandBuffer,
+                       VK_OBJECT_TYPE_COMMAND_BUFFER)
+VK_DEFINE_NONDISP_HANDLE_CASTS(nvk_cmd_pool, vk.base, VkCommandPool,
+                               VK_OBJECT_TYPE_COMMAND_POOL)
+
+#endif
index 1a648fd..b1285e5 100644 (file)
@@ -1,15 +1,24 @@
 #include "nvk_device.h"
 
+#include "nvk_cmd_buffer.h"
 #include "nvk_instance.h"
 #include "nvk_physical_device.h"
 
 #include "nouveau_context.h"
+#include "nouveau_push.h"
 
 #include "vulkan/wsi/wsi_common.h"
 
 static VkResult
-nvk_queue_submit(struct vk_queue *vqueue, struct vk_queue_submit *submission)
+nvk_queue_submit(struct vk_queue *queue, struct vk_queue_submit *submission)
 {
+   struct nvk_device *device = container_of(queue->base.device, struct nvk_device, vk);
+
+   for (unsigned i = 0; i < submission->command_buffer_count; i++) {
+      struct nvk_cmd_buffer *cmd = (struct nvk_cmd_buffer *)submission->command_buffers[i];
+      nouveau_ws_push_submit(cmd->push, device->pdev->dev, device->ctx);
+   }
+
    return VK_SUCCESS;
 }