feat(vk): Basic command list submit workflow
This commit is contained in:
parent
823b9ef9af
commit
33e596c9d6
@ -11,7 +11,7 @@
|
||||
typedef struct rt_physical_resource_manager_i rt_physical_resource_manager_i;
|
||||
|
||||
typedef rt_physical_resource_manager_i rt_render_device_get_physical_resource_manager_fn(void *o);
|
||||
typedef rt_result rt_render_device_submit_command_list_fn(void *o, rt_render_command_list *list);
|
||||
typedef rt_result rt_render_device_submit_command_list_fn(void *o, const rt_render_command_list *list);
|
||||
|
||||
/* Interface for the render device.
|
||||
* The device is responsible for executing command lists. */
|
||||
|
@ -49,7 +49,7 @@ void CommandListsOnBeginFrame(void) {
|
||||
#define COMMAND_LIST_MAX_LENGTH (COMMAND_LIST_CAPACITY / AVERAGE_COMMAND_DATA_SIZE)
|
||||
|
||||
/* Get a new render command list. */
|
||||
RT_DLLEXPORT rt_begin_render_command_list_result rtBeginRenderCommandList(void) {
|
||||
RT_DLLEXPORT rt_begin_render_command_list_result rtBeginRenderCommandList(rt_render_queue queue) {
|
||||
size_t mem_required = COMMAND_LIST_MAX_LENGTH * sizeof(rt_render_command_header) + COMMAND_LIST_CAPACITY;
|
||||
rtLockMutex(_mutex);
|
||||
void *mem = rtArenaPush(_current_arena, mem_required);
|
||||
@ -60,6 +60,7 @@ RT_DLLEXPORT rt_begin_render_command_list_result rtBeginRenderCommandList(void)
|
||||
}
|
||||
rt_render_command_list list = {
|
||||
.headers = mem,
|
||||
.target_queue = queue,
|
||||
.data = (void *)((rt_render_command_header *)mem + COMMAND_LIST_MAX_LENGTH),
|
||||
.length = 0u,
|
||||
.data_capacity = COMMAND_LIST_CAPACITY,
|
||||
@ -72,7 +73,7 @@ RT_DLLEXPORT rt_begin_render_command_list_result rtBeginRenderCommandList(void)
|
||||
}
|
||||
|
||||
/* Lowlevel function that writes the data to the queue. */
|
||||
RT_DLLEXPORT rt_result rtEncodeRenderCommand(rt_render_command_list *list, rt_render_command_type type, rt_render_queue queue, const void *data) {
|
||||
RT_DLLEXPORT rt_result rtEncodeRenderCommand(rt_render_command_list *list, rt_render_command_type type, const void *data) {
|
||||
size_t data_size = 0u;
|
||||
switch (type) {
|
||||
case RT_RENDER_COMMAND_DRAW_INDIRECT:
|
||||
@ -87,9 +88,7 @@ RT_DLLEXPORT rt_result rtEncodeRenderCommand(rt_render_command_list *list, rt_re
|
||||
rtReportError("RENDERER", "Reached maximum lenght or capacity of command list.");
|
||||
return RT_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
list->headers[list->length].type = type;
|
||||
list->headers[list->length].target_queue = queue;
|
||||
++list->length;
|
||||
char *dest = (char *)list->data + list->data_end;
|
||||
memcpy(dest, data, data_size);
|
||||
@ -97,7 +96,7 @@ RT_DLLEXPORT rt_result rtEncodeRenderCommand(rt_render_command_list *list, rt_re
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Submit a finished command list to the graphics device. The list will not be usable after this function is done. */
|
||||
RT_DLLEXPORT rt_result rtSubmitCommandList(rt_render_command_list *list) {
|
||||
/* Submit a finished command list to the graphics device. */
|
||||
RT_DLLEXPORT rt_result rtSubmitCommandList(const rt_render_command_list *list) {
|
||||
return g_device_i.SubmitCommandList(g_device_i.o, list);
|
||||
}
|
||||
|
@ -8,6 +8,9 @@
|
||||
/* Types of render commands */
|
||||
typedef enum {
|
||||
RT_RENDER_COMMAND_DRAW_INDIRECT,
|
||||
|
||||
|
||||
RT_RENDER_COMMAND_COUNT,
|
||||
} rt_render_command_type;
|
||||
|
||||
typedef enum {
|
||||
@ -27,15 +30,21 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
uint32_t target_queue;
|
||||
} rt_render_command_header;
|
||||
|
||||
typedef struct {
|
||||
/* One header per command */
|
||||
rt_render_command_header *headers;
|
||||
|
||||
/* Contains the command data */
|
||||
void *data;
|
||||
|
||||
/* Number of encoded commands */
|
||||
uint32_t length;
|
||||
|
||||
/* Tne device queue to which this list should be submitted*/
|
||||
uint32_t target_queue;
|
||||
|
||||
/* Information used while encoding.
|
||||
* In the future, it would be possible to move this to another struct that is discarded after
|
||||
* encoding is finished.
|
||||
@ -57,20 +66,20 @@ typedef struct {
|
||||
} rt_begin_render_command_list_result;
|
||||
|
||||
/* Get a new render command list. */
|
||||
RT_DLLEXPORT rt_begin_render_command_list_result rtBeginRenderCommandList(void);
|
||||
RT_DLLEXPORT rt_begin_render_command_list_result rtBeginRenderCommandList(rt_render_queue queue);
|
||||
|
||||
/* Lowlevel function that writes the data to the queue. */
|
||||
RT_DLLEXPORT rt_result rtEncodeRenderCommand(rt_render_command_list *list, rt_render_command_type type, rt_render_queue queue, const void *data);
|
||||
RT_DLLEXPORT rt_result rtEncodeRenderCommand(rt_render_command_list *list, rt_render_command_type type, const void *data);
|
||||
|
||||
/* Helper functions for specific commands */
|
||||
RT_INLINE rt_result rtEncodeDrawIndirect(rt_render_command_list *list, const rt_draw_indirect_data *draw_indirect_data) {
|
||||
return rtEncodeRenderCommand(list, RT_RENDER_COMMAND_DRAW_INDIRECT, RT_RENDER_QUEUE_GRAPHICS, draw_indirect_data);
|
||||
return rtEncodeRenderCommand(list, RT_RENDER_COMMAND_DRAW_INDIRECT, draw_indirect_data);
|
||||
}
|
||||
|
||||
/* *** Submission *** */
|
||||
|
||||
/* Submit a finished command list to the graphics device. The list will not be usable after this function is done. */
|
||||
RT_DLLEXPORT rt_result rtSubmitCommandList(rt_render_command_list *list);
|
||||
/* Submit a finished command list to the graphics device. */
|
||||
RT_DLLEXPORT rt_result rtSubmitCommandList(const rt_render_command_list *list);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
196
src/renderer/vk/command_buffers.c
Normal file
196
src/renderer/vk/command_buffers.c
Normal file
@ -0,0 +1,196 @@
|
||||
#include "command_buffers.h"
|
||||
#include "device.h"
|
||||
|
||||
/* We need one command pool per frame per thread. */
|
||||
#include <stdlib.h>
|
||||
#include <volk/volk.h>
|
||||
#include <runtime/runtime.h>
|
||||
#include <runtime/atomics.h>
|
||||
|
||||
struct rt_vk_command_pool_set {
|
||||
VkCommandPool graphics;
|
||||
VkCommandPool compute;
|
||||
VkCommandPool transfer;
|
||||
} ;
|
||||
|
||||
typedef struct {
|
||||
long indices[3];
|
||||
} rt_thread_pool_indices;
|
||||
|
||||
static RT_THREAD_LOCAL rt_thread_pool_indices t_pool_indices;
|
||||
static RT_THREAD_LOCAL bool t_are_indices_initialized[3] = {false, false, false};
|
||||
|
||||
rt_vk_command_pool_array rtReserveCommandPoolArray(long max_threads) {
|
||||
rt_vk_command_pool_array array;
|
||||
array.next_unused = 0;
|
||||
array.capacity = 0;
|
||||
array.pools = calloc(max_threads, sizeof(rt_vk_command_pool_set));
|
||||
if (!array.pools)
|
||||
return array;
|
||||
array.capacity = max_threads;
|
||||
return array;
|
||||
}
|
||||
|
||||
void rtReleaseCommandPoolArray(rt_vk_command_pool_array *array) {
|
||||
free(array->pools);
|
||||
array->pools = NULL;
|
||||
array->capacity = 0;
|
||||
array->next_unused = 0;
|
||||
}
|
||||
|
||||
static rt_vk_command_pool_set *GetThreadsPoolSet(rt_vk_device *dev, uint32_t frame_id) {
|
||||
uint32_t slot = frame_id % dev->max_frames_in_flight;
|
||||
if (!t_are_indices_initialized[slot]) {
|
||||
/* Alloc the set */
|
||||
rt_vk_command_pool_set *set = NULL;
|
||||
long index = rtAtomic32Inc(&dev->frames[slot].command_pools.next_unused) - 1; /* Inc returns the new value */
|
||||
if (index >= dev->frames[slot].command_pools.capacity) {
|
||||
rtReportError("VK", "Ran out of space for per-thread command buffers. Try to increase r_VkMaxThreads");
|
||||
return NULL;
|
||||
}
|
||||
set = &dev->frames[slot].command_pools.pools[index];
|
||||
|
||||
/* Create the pools */
|
||||
{
|
||||
VkCommandPoolCreateInfo pool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||
.queueFamilyIndex = dev->graphics_family,
|
||||
};
|
||||
if (vkCreateCommandPool(dev->device, &pool_info, dev->alloc_cb, &set->graphics) != VK_SUCCESS) {
|
||||
rtReportError("VK", "vkCreateCommandPool failed.");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef RT_DEBUG
|
||||
uint32_t thread_id = rtGetCurrentThreadId();
|
||||
char name[128];
|
||||
rtSPrint(name, 128, "Graphics Command Pool (FrameSlot %u, Thread %u)", slot, thread_id);
|
||||
VkDebugUtilsObjectNameInfoEXT name_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectHandle = (uint64_t)set->graphics,
|
||||
.objectType = VK_OBJECT_TYPE_COMMAND_POOL,
|
||||
.pObjectName = name,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(dev->device, &name_info);
|
||||
#endif
|
||||
}
|
||||
if (dev->compute_family != dev->graphics_family) {
|
||||
VkCommandPoolCreateInfo pool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||
.queueFamilyIndex = dev->compute_family,
|
||||
};
|
||||
if (vkCreateCommandPool(dev->device, &pool_info, dev->alloc_cb, &set->compute) != VK_SUCCESS) {
|
||||
rtReportError("VK", "vkCreateCommandPool failed.");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef RT_DEBUG
|
||||
uint32_t thread_id = rtGetCurrentThreadId();
|
||||
char name[128];
|
||||
rtSPrint(name, 128, "Compute Command Pool (FrameSlot %u, Thread %u)", slot, thread_id);
|
||||
VkDebugUtilsObjectNameInfoEXT name_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectHandle = (uint64_t)set->compute,
|
||||
.objectType = VK_OBJECT_TYPE_COMMAND_POOL,
|
||||
.pObjectName = name,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(dev->device, &name_info);
|
||||
#endif
|
||||
} else {
|
||||
set->compute = set->graphics;
|
||||
}
|
||||
if (dev->transfer_family != dev->graphics_family && dev->transfer_family != dev->compute_family) {
|
||||
VkCommandPoolCreateInfo pool_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||
.queueFamilyIndex = dev->transfer_family,
|
||||
};
|
||||
if (vkCreateCommandPool(dev->device, &pool_info, dev->alloc_cb, &set->transfer) != VK_SUCCESS) {
|
||||
rtReportError("VK", "vkCreateCommandPool failed.");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef RT_DEBUG
|
||||
uint32_t thread_id = rtGetCurrentThreadId();
|
||||
char name[128];
|
||||
rtSPrint(name, 128, "Transfer Command Pool (FrameSlot %u, Thread %u)", slot, thread_id);
|
||||
VkDebugUtilsObjectNameInfoEXT name_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectHandle = (uint64_t)set->transfer,
|
||||
.objectType = VK_OBJECT_TYPE_COMMAND_POOL,
|
||||
.pObjectName = name,
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(dev->device, &name_info);
|
||||
#endif
|
||||
}
|
||||
else if (dev->transfer_family == dev->graphics_family) {
|
||||
set->transfer = set->graphics;
|
||||
} else {
|
||||
RT_ASSERT(dev->transfer_family == dev->compute_family, "");
|
||||
set->transfer = set->compute;
|
||||
}
|
||||
|
||||
t_pool_indices.indices[slot] = index;
|
||||
t_are_indices_initialized[slot] = true;
|
||||
}
|
||||
|
||||
long index = t_pool_indices.indices[slot];
|
||||
#ifdef RT_DEBUG
|
||||
if (index >= dev->frames[slot].command_pools.next_unused)
|
||||
return NULL;
|
||||
#endif
|
||||
return &dev->frames[slot].command_pools.pools[index];
|
||||
}
|
||||
|
||||
VkCommandPool rtGetGraphicsCommandPool(rt_vk_device *dev) {
|
||||
rt_vk_command_pool_set *set = GetThreadsPoolSet(dev, dev->current_frame_id);
|
||||
return RT_VERIFY(set)->graphics;
|
||||
}
|
||||
|
||||
VkCommandPool rtGetComputeCommandPool(rt_vk_device *dev) {
|
||||
rt_vk_command_pool_set *set = GetThreadsPoolSet(dev, dev->current_frame_id);
|
||||
return RT_VERIFY(set)->compute;
|
||||
}
|
||||
|
||||
VkCommandPool rtGetTransferCommandPool(rt_vk_device *dev) {
|
||||
rt_vk_command_pool_set *set = GetThreadsPoolSet(dev, dev->current_frame_id);
|
||||
return RT_VERIFY(set)->transfer;
|
||||
}
|
||||
|
||||
VkCommandBuffer rtAllocateGraphicsCommandBuffer(rt_vk_device *dev) {
|
||||
VkCommandPool pool = rtGetGraphicsCommandPool(dev);
|
||||
VkCommandBufferAllocateInfo alloc_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = pool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
VkCommandBuffer cmdbuf = VK_NULL_HANDLE;
|
||||
vkAllocateCommandBuffers(dev->device, &alloc_info, &cmdbuf);
|
||||
return cmdbuf;
|
||||
}
|
||||
|
||||
VkCommandBuffer rtAllocateComputeCommandBuffer(rt_vk_device *dev) {
|
||||
VkCommandPool pool = rtGetComputeCommandPool(dev);
|
||||
VkCommandBufferAllocateInfo alloc_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = pool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
VkCommandBuffer cmdbuf = VK_NULL_HANDLE;
|
||||
vkAllocateCommandBuffers(dev->device, &alloc_info, &cmdbuf);
|
||||
return cmdbuf;
|
||||
}
|
||||
|
||||
VkCommandBuffer rtAllocateTransferCommandBuffer(rt_vk_device *dev) {
|
||||
VkCommandPool pool = rtGetTransferCommandPool(dev);
|
||||
VkCommandBufferAllocateInfo alloc_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = pool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
VkCommandBuffer cmdbuf = VK_NULL_HANDLE;
|
||||
vkAllocateCommandBuffers(dev->device, &alloc_info, &cmdbuf);
|
||||
return cmdbuf;
|
||||
}
|
29
src/renderer/vk/command_buffers.h
Normal file
29
src/renderer/vk/command_buffers.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef RT_VK_COMMAND_LISTS_H
|
||||
#define RT_VK_COMMAND_LISTS_H
|
||||
|
||||
#include <volk/volk.h>
|
||||
|
||||
struct rt_vk_device;
|
||||
|
||||
typedef struct rt_vk_command_pool_set rt_vk_command_pool_set;
|
||||
|
||||
/* Contains an array of command pools. Threads safe an index into the array
|
||||
* to access their own command pool set. */
|
||||
typedef struct {
|
||||
rt_vk_command_pool_set *pools;
|
||||
long capacity;
|
||||
long next_unused;
|
||||
} rt_vk_command_pool_array;
|
||||
|
||||
rt_vk_command_pool_array rtReserveCommandPoolArray(long max_threads);
|
||||
void rtReleaseCommandPoolArray(rt_vk_command_pool_array *array);
|
||||
|
||||
VkCommandPool rtGetGraphicsCommandPool(struct rt_vk_device *dev);
|
||||
VkCommandPool rtGetComputeCommandPool(struct rt_vk_device *dev);
|
||||
VkCommandPool rtGetTransferCommandPool(struct rt_vk_device *dev);
|
||||
|
||||
VkCommandBuffer rtAllocateGraphicsCommandBuffer(struct rt_vk_device *dev);
|
||||
VkCommandBuffer rtAllocateComputeCommandBuffer(struct rt_vk_device *dev);
|
||||
VkCommandBuffer rtAllocateTransferCommandBuffer(struct rt_vk_device *dev);
|
||||
|
||||
#endif
|
@ -19,6 +19,7 @@ RT_CVAR_I(r_VkEnableAPIAllocTracking,
|
||||
RT_CVAR_S(r_VkPhysDeviceName, "Name of the selected physical device. Default: \"\"", "");
|
||||
|
||||
RT_CVAR_I(r_VkMaxFramesInFlight, "Maximum number of frames in flight. [2/3] Default: 2", 2);
|
||||
RT_CVAR_UI(r_VkMaxThreads, "Maximum number of threads used. (Default: 128)", 128);
|
||||
|
||||
static VkAllocationCallbacks _tracking_alloc_cbs;
|
||||
|
||||
@ -564,6 +565,8 @@ static rt_result CreatePerFrameObjects(rt_vk_device *dev) {
|
||||
name_info.objectHandle = (uint64_t)dev->frames[i].swapchain_transitioned;
|
||||
vkSetDebugUtilsObjectNameEXT(dev->device, &name_info);
|
||||
#endif
|
||||
|
||||
dev->frames[i].command_pools = rtReserveCommandPoolArray(r_VkMaxThreads.ui);
|
||||
}
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
@ -627,6 +630,10 @@ rt_create_vk_device_result rtCreateVkDevice(const rt_renderer_window_info *info)
|
||||
goto out;
|
||||
dev.bindless_registry = bindless_registry_result.bindless_registry;
|
||||
|
||||
dev.created_pools = calloc(128 * 9, sizeof(VkCommandPool));
|
||||
dev.created_pool_count = 0;
|
||||
dev.max_created_pools = 128 * 9;
|
||||
|
||||
rt_time_delta initTime = rtTimeBetween(initBegin, rtTimeNow());
|
||||
rtLog("VK", "Init complete. Took %lf seconds.", initTime);
|
||||
|
||||
@ -637,6 +644,7 @@ out:
|
||||
void rtDestroyVkDevice(rt_vk_device *dev) {
|
||||
rtLog("VK", "Shutdown");
|
||||
vkDeviceWaitIdle(dev->device);
|
||||
free(dev->created_pools);
|
||||
rtDestroyVkBindlessRegistry(&dev->bindless_registry);
|
||||
rtDestroyVkPhysicalResourceManager(&dev->phys_res_mgr);
|
||||
DestroySwapchain(dev);
|
||||
@ -662,25 +670,98 @@ rt_physical_resource_manager_i rtVkDevGetPhysicalResourceManager(void *o) {
|
||||
return iface;
|
||||
}
|
||||
|
||||
rt_result rtVkDevSubmitCommandList(void *o, rt_render_command_list *list) {
|
||||
/* Dummy implementation */
|
||||
RT_UNUSED(o);
|
||||
|
||||
size_t data_off = 0;
|
||||
for (uint32_t i = 0; i < list->length; ++i) {
|
||||
if (list->headers[i].type != RT_RENDER_COMMAND_DRAW_INDIRECT)
|
||||
break;
|
||||
rtLog("VK", "DrawIndirect %u", i);
|
||||
rtLog("VK", "Target queue: %u", list->headers[i].target_queue);
|
||||
|
||||
RT_VERIFY(data_off < list->data_end);
|
||||
rt_draw_indirect_data *data = (rt_draw_indirect_data *)((char *)list->data + data_off);
|
||||
rtLog("VK", "buffer %u draw_count %u offset %u stride %u",
|
||||
data->buffer.value,
|
||||
data->draw_count,
|
||||
data->offset,
|
||||
data->stride);
|
||||
data_off += sizeof(rt_draw_indirect_data);
|
||||
/* Commands */
|
||||
static rt_result DrawIndirectImpl(rt_vk_device *dev, VkCommandBuffer cmdbuf, const void *_data) {
|
||||
const rt_draw_indirect_data *data = _data;
|
||||
const rt_vk_physical_resource *buffer_resource = rtGetVkPhysicalResource(&dev->phys_res_mgr, data->buffer);
|
||||
if (!buffer_resource) {
|
||||
rtLog("VK", "Invalid buffer in draw indirect data");
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
RT_ASSERT(buffer_resource->type == RT_RENDER_RESOURCE_TYPE_BUFFER,
|
||||
"Buffer handle in draw indirect data does not reference a buffer object");
|
||||
vkCmdDrawIndirect(cmdbuf, buffer_resource->buffer, data->offset, data->draw_count, data->stride);
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
typedef rt_result rt_vk_render_command_impl_fn(rt_vk_device *dev, VkCommandBuffer cmdbuf, const void *data);
|
||||
|
||||
static size_t _command_data_sizes[RT_RENDER_COMMAND_COUNT] = {
|
||||
sizeof(rt_draw_indirect_data),
|
||||
};
|
||||
|
||||
static rt_vk_render_command_impl_fn *_command_impls[RT_RENDER_COMMAND_COUNT] = {
|
||||
DrawIndirectImpl,
|
||||
};
|
||||
|
||||
rt_result rtVkDevSubmitCommandList(void *o, const rt_render_command_list *list) {
|
||||
rt_vk_device *dev = o;
|
||||
size_t data_off = 0;
|
||||
rt_result res = RT_SUCCESS;
|
||||
|
||||
/* Prepare command buffer */
|
||||
VkQueue queue = VK_NULL_HANDLE;
|
||||
VkCommandBuffer cmdbuf = VK_NULL_HANDLE;
|
||||
if (list->target_queue == RT_RENDER_QUEUE_GRAPHICS) {
|
||||
cmdbuf = rtAllocateComputeCommandBuffer(dev);
|
||||
queue = dev->graphics_queue;
|
||||
}
|
||||
else if (list->target_queue == RT_RENDER_QUEUE_COMPUTE) {
|
||||
cmdbuf = rtAllocateComputeCommandBuffer(dev);
|
||||
queue = dev->compute_queue;
|
||||
}
|
||||
else if (list->target_queue == RT_RENDER_QUEUE_TRANSFER) {
|
||||
cmdbuf = rtAllocateTransferCommandBuffer(dev);
|
||||
queue = dev->transfer_queue;
|
||||
}
|
||||
else {
|
||||
RT_ASSERT("VK", "Invalid target queue");
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
VkCommandBufferBeginInfo begin_info = {.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT};
|
||||
if (vkBeginCommandBuffer(cmdbuf, &begin_info) != VK_SUCCESS) {
|
||||
rtLog("VK", "vkBeginCommandBuffer failed");
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
/* Iterate over all commands and decode them */
|
||||
for (uint32_t i = 0; i < list->length; ++i) {
|
||||
rt_render_command_header header = list->headers[i];
|
||||
RT_ASSERT(header.type < RT_RENDER_COMMAND_COUNT,
|
||||
"Invalid render command type.");
|
||||
const void *data = (const char *)list->data + data_off;
|
||||
res = _command_impls[header.type](dev, cmdbuf, data);
|
||||
if (res != RT_SUCCESS)
|
||||
break;
|
||||
data_off += _command_data_sizes[header.type];
|
||||
}
|
||||
if (res != RT_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* End the command buffers and create submit info */
|
||||
vkEndCommandBuffer(cmdbuf);
|
||||
|
||||
/* Submit it! */
|
||||
VkCommandBufferSubmitInfo cmdbuf_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
|
||||
.commandBuffer = cmdbuf
|
||||
};
|
||||
|
||||
VkSubmitInfo2 submit_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
|
||||
.commandBufferInfoCount = 1,
|
||||
.pCommandBufferInfos = &cmdbuf_info,
|
||||
.waitSemaphoreInfoCount = 0,
|
||||
.pWaitSemaphoreInfos = NULL,
|
||||
.signalSemaphoreInfoCount = 0,
|
||||
.pSignalSemaphoreInfos = NULL,
|
||||
};
|
||||
if (vkQueueSubmit2(queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
|
||||
rtLog("VK"," vkQueueSubmit2 failed");
|
||||
res = RT_UNKNOWN_ERROR;
|
||||
}
|
||||
return res;
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "physical_resource_manager.h"
|
||||
#include "bindless_registry.h"
|
||||
#include "command_buffers.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
struct HINSTANCE__;
|
||||
@ -31,6 +32,8 @@ typedef struct {
|
||||
VkSemaphore render_finished;
|
||||
VkSemaphore image_available;
|
||||
VkSemaphore swapchain_transitioned;
|
||||
|
||||
rt_vk_command_pool_array command_pools;
|
||||
} rt_vk_frame_data;
|
||||
|
||||
typedef struct rt_vk_device {
|
||||
@ -76,6 +79,11 @@ typedef struct rt_vk_device {
|
||||
rt_vk_physical_resource_manager phys_res_mgr;
|
||||
rt_vk_bindless_registry bindless_registry;
|
||||
|
||||
/* *** Save created command pools in a list to clean them up at exit */
|
||||
VkCommandPool *created_pools;
|
||||
long created_pool_count;
|
||||
long max_created_pools;
|
||||
|
||||
/* *** Debug utils *** */
|
||||
#ifdef RT_DEBUG
|
||||
VkDebugUtilsMessengerEXT messenger;
|
||||
@ -93,6 +101,6 @@ void rtDestroyVkDevice(rt_vk_device *dev);
|
||||
|
||||
/* rt_render_device_i functions */
|
||||
rt_physical_resource_manager_i rtVkDevGetPhysicalResourceManager(void *o);
|
||||
rt_result rtVkDevSubmitCommandList(void *o, rt_render_command_list *list);
|
||||
rt_result rtVkDevSubmitCommandList(void *o, const rt_render_command_list *list);
|
||||
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@
|
||||
extern rt_cvar r_VkEnableAPIAllocTracking;
|
||||
extern rt_cvar r_VkPhysDeviceName;
|
||||
extern rt_cvar r_VkMaxFramesInFlight;
|
||||
extern rt_cvar r_VkMaxThreads;
|
||||
extern rt_cvar r_VkPreferMailboxMode;
|
||||
extern rt_cvar r_VkPreferRelaxedMode;
|
||||
extern rt_cvar r_VkEnableVSync;
|
||||
@ -21,6 +22,7 @@ void VkRegisterCVARs(void) {
|
||||
rtRegisterCVAR(&r_VkEnableAPIAllocTracking);
|
||||
rtRegisterCVAR(&r_VkPhysDeviceName);
|
||||
rtRegisterCVAR(&r_VkMaxFramesInFlight);
|
||||
rtRegisterCVAR(&r_VkMaxThreads);
|
||||
rtRegisterCVAR(&r_VkPreferMailboxMode);
|
||||
rtRegisterCVAR(&r_VkPreferRelaxedMode);
|
||||
rtRegisterCVAR(&r_VkEnableVSync);
|
||||
|
@ -14,10 +14,12 @@ if get_option('build_vk')
|
||||
|
||||
vk_renderer_lib = library('rtvk',
|
||||
'bindless_registry.h',
|
||||
'command_buffers.h',
|
||||
'device.h',
|
||||
'physical_resource_manager.h',
|
||||
|
||||
'bindless_registry.c',
|
||||
'command_buffers.c',
|
||||
'device.c',
|
||||
'init.c',
|
||||
'physical_resource_manager.c',
|
||||
|
@ -147,6 +147,17 @@ void rtVkPhysicalResourceManagerDestroy(void *o, rt_render_resource_handle handl
|
||||
rtUnlockWrite(&phys_res_mgr->lock);
|
||||
}
|
||||
|
||||
rt_vk_physical_resource *rtGetVkPhysicalResource(rt_vk_physical_resource_manager *phys_res_mgr, rt_render_resource_handle handle) {
|
||||
rt_vk_physical_resource *resource = NULL;
|
||||
rtLockRead(&phys_res_mgr->lock);
|
||||
uint32_t slot = rtHashtableLookup(&phys_res_mgr->resource_lut, handle.value, UINT32_MAX);
|
||||
if (slot != UINT32_MAX) {
|
||||
resource = &phys_res_mgr->resources[slot];
|
||||
}
|
||||
rtUnlockRead(&phys_res_mgr->lock);
|
||||
return resource;
|
||||
}
|
||||
|
||||
/* Call this with a held write lock! */
|
||||
static uint32_t AllocStorageSlot(rt_vk_physical_resource_manager *phys_res_mgr, rt_render_resource_handle h) {
|
||||
if (phys_res_mgr->free_slot_count > 0u) {
|
||||
|
@ -52,6 +52,8 @@ rt_create_vk_physical_resource_manager_result rtCreateVkPhysicalResourceManager(
|
||||
|
||||
void rtDestroyVkPhysicalResourceManager(rt_vk_physical_resource_manager *phys_res_mgr);
|
||||
|
||||
rt_vk_physical_resource *rtGetVkPhysicalResource(rt_vk_physical_resource_manager *phys_res_mgr, rt_render_resource_handle handle);
|
||||
|
||||
/* rt_physical_resource_manager_i functions */
|
||||
bool rtVkPhysicalResourceManagerIsPresent(void *o, rt_render_resource_handle handle);
|
||||
void rtVkPhysicalResourceManagerDestroy(void *o, rt_render_resource_handle handle);
|
||||
|
Loading…
Reference in New Issue
Block a user