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