feat(vk): Basic command list submit workflow
Some checks failed
Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m45s
Ubuntu Cross to Win64 / Compile for linux (1.4.0, ubuntu-latest) (push) Successful in 1m28s

This commit is contained in:
Kevin Trogant 2024-08-04 13:31:40 +02:00
parent 823b9ef9af
commit 33e596c9d6
11 changed files with 371 additions and 32 deletions

View File

@ -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. */

View File

@ -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);
}

View File

@ -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

View 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;
}

View 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

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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',

View File

@ -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) {

View File

@ -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);