feat(renderer): Basic command list managemnent
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m41s
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m41s
				
			This commit is contained in:
		
							parent
							
								
									4febd1b3fa
								
							
						
					
					
						commit
						beba96b915
					
				@ -6,16 +6,19 @@
 | 
			
		||||
 | 
			
		||||
#include "renderer.h"
 | 
			
		||||
#include "render_resource.h"
 | 
			
		||||
#include "command_list.h"
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
/* Interface for the render device.
 | 
			
		||||
 * The device is responsible for executing command lists. */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    void *o;
 | 
			
		||||
    rt_render_device_get_physical_resource_manager_fn *GetPhysicalResourceManager;
 | 
			
		||||
    rt_render_device_submit_command_list_fn *SubmitCommandList;
 | 
			
		||||
} rt_render_device_i;
 | 
			
		||||
 | 
			
		||||
typedef bool rt_physical_resource_manager_is_present_fn(void *o, rt_render_resource_handle h);
 | 
			
		||||
@ -51,5 +54,6 @@ typedef struct {
 | 
			
		||||
} rt_render_backend_api;
 | 
			
		||||
 | 
			
		||||
extern rt_render_backend_api g_render_backend;
 | 
			
		||||
extern rt_render_device_i g_device_i;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										103
									
								
								src/renderer/command_list.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/renderer/command_list.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,103 @@
 | 
			
		||||
#include "command_list.h"
 | 
			
		||||
#include "backend_api.h"
 | 
			
		||||
 | 
			
		||||
#include <runtime/config.h>
 | 
			
		||||
#include <runtime/mem_arena.h>
 | 
			
		||||
#include <runtime/threading.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
RT_CVAR_SZ(r_PerFrameCommandListMemory, "Amount of memory to allocate for single frame command list management."
 | 
			
		||||
    " The total amount of memory will be this times the maximum number of frames in flight. (Default: 16 MB)",
 | 
			
		||||
    RT_MB(16));
 | 
			
		||||
 | 
			
		||||
static rt_arena _list_arenas[3];
 | 
			
		||||
static rt_arena *_current_arena = &_list_arenas[0];
 | 
			
		||||
static unsigned int _current_arena_idx = 0;
 | 
			
		||||
static rt_mutex *_mutex;
 | 
			
		||||
 | 
			
		||||
rt_result InitCommandLists(void) {
 | 
			
		||||
    _mutex = rtCreateMutex();
 | 
			
		||||
    if (!_mutex)
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < RT_ARRAY_COUNT(_list_arenas); ++i) {
 | 
			
		||||
        rt_create_arena_result arena_res = rtCreateArena(NULL, r_PerFrameCommandListMemory.sz);
 | 
			
		||||
        if (!arena_res.ok) {
 | 
			
		||||
            rtDestroyMutex(_mutex);
 | 
			
		||||
            return RT_OUT_OF_MEMORY;
 | 
			
		||||
        }
 | 
			
		||||
        _list_arenas[i] = arena_res.arena;
 | 
			
		||||
    }
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ShutdownCommandLists(void) {
 | 
			
		||||
    for (unsigned int i = 0; i < RT_ARRAY_COUNT(_list_arenas); ++i) {
 | 
			
		||||
        rtReleaseArena(&_list_arenas[i]);
 | 
			
		||||
    }
 | 
			
		||||
    rtDestroyMutex(_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CommandListsOnBeginFrame(void) {
 | 
			
		||||
    _current_arena_idx = (_current_arena_idx + 1) % RT_ARRAY_COUNT(_list_arenas);
 | 
			
		||||
    _current_arena = &_list_arenas[_current_arena_idx];
 | 
			
		||||
    rtArenaClear(_current_arena);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define COMMAND_LIST_CAPACITY RT_KB(512)
 | 
			
		||||
#define AVERAGE_COMMAND_DATA_SIZE sizeof(rt_draw_indirect_data)
 | 
			
		||||
#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) {
 | 
			
		||||
    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);
 | 
			
		||||
    rtUnlockMutex(_mutex);
 | 
			
		||||
    if (!mem) {
 | 
			
		||||
        rtReportError("RENDERER", "Ran out of memory for command lists.");
 | 
			
		||||
        return (rt_begin_render_command_list_result){.result = RT_OUT_OF_MEMORY};
 | 
			
		||||
    }
 | 
			
		||||
    rt_render_command_list list = {
 | 
			
		||||
        .headers = mem,
 | 
			
		||||
        .data = (void *)((rt_render_command_header *)mem + COMMAND_LIST_MAX_LENGTH),
 | 
			
		||||
        .length = 0u,
 | 
			
		||||
        .data_capacity =  COMMAND_LIST_CAPACITY,
 | 
			
		||||
        .data_end = 0u
 | 
			
		||||
    };
 | 
			
		||||
    return (rt_begin_render_command_list_result){
 | 
			
		||||
        .result = RT_SUCCESS,
 | 
			
		||||
        .list = list
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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) {
 | 
			
		||||
    size_t data_size = 0u;
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case RT_RENDER_COMMAND_DRAW_INDIRECT:
 | 
			
		||||
        data_size = sizeof(rt_draw_indirect_data);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        rtReportError("RENDERER", "Invalid render command type %u", type);
 | 
			
		||||
        return RT_INVALID_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (list->length == COMMAND_LIST_MAX_LENGTH || (list->data_end + data_size) > list->data_capacity) {
 | 
			
		||||
        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);
 | 
			
		||||
    list->data_end += data_size;
 | 
			
		||||
    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) {
 | 
			
		||||
    return g_device_i.SubmitCommandList(g_device_i.o, list);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								src/renderer/command_list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/renderer/command_list.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
#ifndef RT_RENDERER_COMMAND_LIST_H
 | 
			
		||||
#define RT_RENDERER_COMMAND_LIST_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <runtime/runtime.h>
 | 
			
		||||
#include "render_resource.h"
 | 
			
		||||
 | 
			
		||||
/* Types of render commands */
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_RENDER_COMMAND_DRAW_INDIRECT,
 | 
			
		||||
} rt_render_command_type;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_RENDER_QUEUE_GRAPHICS,
 | 
			
		||||
    RT_RENDER_QUEUE_COMPUTE,
 | 
			
		||||
    RT_RENDER_QUEUE_TRANSFER,
 | 
			
		||||
} rt_render_queue;
 | 
			
		||||
 | 
			
		||||
/* Structures containing command parameters */
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rt_render_buffer_handle buffer;
 | 
			
		||||
    uint32_t offset;
 | 
			
		||||
    uint32_t draw_count;
 | 
			
		||||
    uint32_t stride;
 | 
			
		||||
} rt_draw_indirect_data;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t type;
 | 
			
		||||
    uint32_t target_queue;
 | 
			
		||||
} rt_render_command_header;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rt_render_command_header *headers;
 | 
			
		||||
    void *data;
 | 
			
		||||
    /* Number of encoded commands */
 | 
			
		||||
    uint32_t length;
 | 
			
		||||
 | 
			
		||||
    /* Information used while encoding.
 | 
			
		||||
     * In the future, it would be possible to move this to another struct that is discarded after
 | 
			
		||||
     * encoding is finished.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    size_t data_capacity;
 | 
			
		||||
    size_t data_end;
 | 
			
		||||
} rt_render_command_list;
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* *** Encoding API *** */
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rt_result result;
 | 
			
		||||
    rt_render_command_list list;
 | 
			
		||||
} rt_begin_render_command_list_result;
 | 
			
		||||
 | 
			
		||||
/* Get a new render command list. */
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
/* 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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* *** 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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -5,9 +5,11 @@
 | 
			
		||||
#include <runtime/config.h>
 | 
			
		||||
 | 
			
		||||
extern rt_cvar r_MaxRenderResources;
 | 
			
		||||
extern rt_cvar r_PerFrameCommandListMemory;
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtRegisterRenderCVARs(void) {
 | 
			
		||||
    rtRegisterCVAR(&r_MaxRenderResources);
 | 
			
		||||
    rtRegisterCVAR(&r_PerFrameCommandListMemory);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtRegisterRenderBackendCVARs(void) {
 | 
			
		||||
@ -18,6 +20,8 @@ rt_render_device_i g_device_i;
 | 
			
		||||
 | 
			
		||||
extern rt_result InitVirtualResourceRegistry(void);
 | 
			
		||||
extern void ShutdownVirtualResourceRegistry(void);
 | 
			
		||||
extern rt_result InitCommandLists(void);
 | 
			
		||||
extern void ShutdownCommandLists(void);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT rt_result rtInitRenderer(const rt_renderer_window_info *info) {
 | 
			
		||||
    rt_render_backend_init_result backend_res = g_render_backend.Init(info);
 | 
			
		||||
@ -30,9 +34,16 @@ RT_DLLEXPORT rt_result rtInitRenderer(const rt_renderer_window_info *info) {
 | 
			
		||||
        g_render_backend.Shutdown();
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    if ((res = InitCommandLists()) != RT_SUCCESS) {
 | 
			
		||||
        ShutdownVirtualResourceRegistry();
 | 
			
		||||
        g_render_backend.Shutdown();
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtShutdownRenderer(void) {
 | 
			
		||||
    ShutdownCommandLists();
 | 
			
		||||
    ShutdownVirtualResourceRegistry();
 | 
			
		||||
    g_render_backend.Shutdown();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,13 @@ endif
 | 
			
		||||
 | 
			
		||||
renderer_lib = library('renderer',
 | 
			
		||||
    'backend_api.h',
 | 
			
		||||
    'command_list.h',
 | 
			
		||||
    'renderer.h',
 | 
			
		||||
    'render_mesh.h',
 | 
			
		||||
    'render_resource.h',
 | 
			
		||||
    'virtual_resource_registry.h',
 | 
			
		||||
 | 
			
		||||
    'command_list.c',
 | 
			
		||||
    'init.c',
 | 
			
		||||
    'load_stub.c',
 | 
			
		||||
    'meshlet_pools.c',
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,11 @@ typedef struct {
 | 
			
		||||
    uint32_t value;
 | 
			
		||||
} rt_render_resource_handle;
 | 
			
		||||
 | 
			
		||||
/* Aliases for render_resource_handle to be able to express the type of expected resources in code. */
 | 
			
		||||
 | 
			
		||||
typedef rt_render_resource_handle rt_render_buffer_handle;
 | 
			
		||||
typedef rt_render_resource_handle rt_render_texture2d_handle;
 | 
			
		||||
 | 
			
		||||
#define RT_RENDER_RESOURCE_MAX_VERSION 0x3f
 | 
			
		||||
 | 
			
		||||
/* Extract the type part of a render resource handle */
 | 
			
		||||
@ -84,6 +89,20 @@ typedef struct {
 | 
			
		||||
    rt_resource_id source_resource;
 | 
			
		||||
} rt_render_buffer_desc;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_TEXTURE_FORMAT_B8G8R8A8_SRGB,
 | 
			
		||||
 | 
			
		||||
    RT_TEXTURE_FORMAT_MAX,
 | 
			
		||||
} rt_texture_format;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_TEXTURE_USAGE_NONE                     = 0x00,
 | 
			
		||||
    RT_TEXTURE_USAGE_COLOR_ATTACHMENT         = 0x01,
 | 
			
		||||
    RT_TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT = 0x02,
 | 
			
		||||
    RT_TEXTURE_USAGE_SAMPLED_IMAGE            = 0x04,
 | 
			
		||||
    RT_TEXTURE_USAGE_STORAGE_IMAGE            = 0x10,
 | 
			
		||||
} rt_texture_usage_flags;
 | 
			
		||||
 | 
			
		||||
/* Describes a gpu texture */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    /* Width in pixels */
 | 
			
		||||
@ -91,6 +110,21 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
    /* Height in pixels */
 | 
			
		||||
    uint32_t height;
 | 
			
		||||
 | 
			
		||||
    /* Pixel format */
 | 
			
		||||
    rt_texture_format format;
 | 
			
		||||
 | 
			
		||||
    /* Number of samples */
 | 
			
		||||
    uint32_t samples;
 | 
			
		||||
 | 
			
		||||
    /* Number of mip levels */
 | 
			
		||||
    uint32_t mip_levels;
 | 
			
		||||
 | 
			
		||||
    /* Bitmask of usages this texture needs to support */
 | 
			
		||||
    rt_texture_usage_flags usage;
 | 
			
		||||
 | 
			
		||||
    /* ResourceID of the resource that will be used to populate this texture. */
 | 
			
		||||
    rt_resource_id source_resource;
 | 
			
		||||
} rt_render_texture2d_desc;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -656,3 +656,26 @@ 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);
 | 
			
		||||
    }
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -89,5 +89,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);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,7 @@ rt_render_backend_init_result VkInit(const rt_renderer_window_info *info) {
 | 
			
		||||
    rt_render_device_i device_i = {
 | 
			
		||||
        .o =  &_device,
 | 
			
		||||
        .GetPhysicalResourceManager = rtVkDevGetPhysicalResourceManager,
 | 
			
		||||
        .SubmitCommandList = rtVkDevSubmitCommandList,
 | 
			
		||||
    };
 | 
			
		||||
    res.device = device_i;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -147,6 +147,19 @@ void rtVkPhysicalResourceManagerDestroy(void *o, rt_render_resource_handle handl
 | 
			
		||||
    rtUnlockWrite(&phys_res_mgr->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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) {
 | 
			
		||||
        uint32_t slot = phys_res_mgr->free_slots[--phys_res_mgr->free_slot_count];
 | 
			
		||||
        /* The hashtable is large enough that this should never fail */
 | 
			
		||||
        rt_result insert_res = rtHashtableInsert(&phys_res_mgr->resource_lut, (uint64_t)h.value, (uint64_t)slot);
 | 
			
		||||
        RT_UNUSED(insert_res);
 | 
			
		||||
        RT_VERIFY(insert_res == RT_SUCCESS);
 | 
			
		||||
        return slot;
 | 
			
		||||
    }
 | 
			
		||||
    return UINT32_MAX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rt_result rtVkPhysicalResourceManagerCreateBuffer(void *o, rt_render_resource_handle h, const rt_render_buffer_desc *desc) {
 | 
			
		||||
    rt_vk_physical_resource_manager *phys_res_mgr = o;
 | 
			
		||||
 | 
			
		||||
@ -190,28 +203,89 @@ rt_result rtVkPhysicalResourceManagerCreateBuffer(void *o, rt_render_resource_ha
 | 
			
		||||
    /* Store */
 | 
			
		||||
    rt_result res = RT_SUCCESS;
 | 
			
		||||
    rtLockWrite(&phys_res_mgr->lock);
 | 
			
		||||
    if (phys_res_mgr->free_slot_count > 0u) {
 | 
			
		||||
        uint32_t slot = phys_res_mgr->free_slots[--phys_res_mgr->free_slot_count];
 | 
			
		||||
    uint32_t slot = AllocStorageSlot(phys_res_mgr, h);
 | 
			
		||||
    if (slot != UINT32_MAX) {
 | 
			
		||||
        phys_res_mgr->resources[slot].type = RT_RENDER_RESOURCE_TYPE_BUFFER;
 | 
			
		||||
        phys_res_mgr->resources[slot].buffer = buffer;
 | 
			
		||||
        phys_res_mgr->resources[slot].allocation = allocation;
 | 
			
		||||
 | 
			
		||||
        /* The hashtable is large enough that this should never fail */
 | 
			
		||||
        rt_result insert_res = rtHashtableInsert(&phys_res_mgr->resource_lut, (uint64_t)h.value, (uint64_t)slot);
 | 
			
		||||
        RT_UNUSED(insert_res);
 | 
			
		||||
        RT_VERIFY(insert_res == RT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        rtLog("VK", "Could not create buffer, because no free slots for storing it are available.");
 | 
			
		||||
        vmaDestroyBuffer(phys_res_mgr->allocator, buffer, allocation);
 | 
			
		||||
    } else {
 | 
			
		||||
        res = RT_OUT_OF_MEMORY;
 | 
			
		||||
        vmaDestroyBuffer(phys_res_mgr->allocator, buffer, allocation);
 | 
			
		||||
        rtLog("VK","Could not create buffer because no storage space is available.");
 | 
			
		||||
    }
 | 
			
		||||
    rtUnlockWrite(&phys_res_mgr->lock);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VkFormat RtTextureFormatToVkFormat(rt_texture_format texture_format) {
 | 
			
		||||
    RT_ASSERT(texture_format < RT_TEXTURE_FORMAT_MAX, "Invalid format");
 | 
			
		||||
    VkFormat formats[RT_TEXTURE_FORMAT_MAX] = {
 | 
			
		||||
        VK_FORMAT_B8G8R8A8_SRGB, // RT_TEXTURE_FORMAT_B8G8R8A8_SRGB
 | 
			
		||||
    };
 | 
			
		||||
    return formats[texture_format];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VkImageUsageFlagBits RtTextureUsageToVkImageUsage(rt_texture_usage_flags usage_flags) {
 | 
			
		||||
    VkImageUsageFlagBits usage = 0;
 | 
			
		||||
    if ((usage_flags & RT_TEXTURE_USAGE_COLOR_ATTACHMENT) != 0)
 | 
			
		||||
        usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 | 
			
		||||
    if ((usage_flags & RT_TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT) != 0)
 | 
			
		||||
        usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
 | 
			
		||||
    if ((usage_flags & RT_TEXTURE_USAGE_SAMPLED_IMAGE) != 0)
 | 
			
		||||
        usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
 | 
			
		||||
    if ((usage_flags & RT_TEXTURE_USAGE_STORAGE_IMAGE) != 0)
 | 
			
		||||
        usage |= VK_IMAGE_USAGE_STORAGE_BIT;
 | 
			
		||||
    return usage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rt_result rtVkPhysicalResourceManagerCreateTexture2D(void *o, rt_render_resource_handle h, const rt_render_texture2d_desc *desc) {
 | 
			
		||||
    RT_NOT_IMPLEMENTED;
 | 
			
		||||
    rt_vk_physical_resource_manager *phys_res_mgr = o;
 | 
			
		||||
 | 
			
		||||
    VkFormat format = RtTextureFormatToVkFormat(desc->format);
 | 
			
		||||
    VkExtent3D extent = {.width = desc->width, .height = desc->height, .depth = 1};
 | 
			
		||||
    VkImageUsageFlagBits usage = RtTextureUsageToVkImageUsage(desc->usage);
 | 
			
		||||
 | 
			
		||||
    VkImageCreateInfo image_info = {
 | 
			
		||||
        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
 | 
			
		||||
        .extent = extent,
 | 
			
		||||
        .format = format,
 | 
			
		||||
        .imageType = VK_IMAGE_TYPE_2D,
 | 
			
		||||
        .sharingMode = VK_SHARING_MODE_CONCURRENT,
 | 
			
		||||
        .queueFamilyIndexCount = phys_res_mgr->dev->unique_family_count,
 | 
			
		||||
        .pQueueFamilyIndices = &phys_res_mgr->dev->unique_families[0],
 | 
			
		||||
        .mipLevels = 1,
 | 
			
		||||
        .samples = VK_SAMPLE_COUNT_1_BIT,
 | 
			
		||||
        .arrayLayers = 1,
 | 
			
		||||
        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
 | 
			
		||||
        .usage = usage,
 | 
			
		||||
        .tiling = VK_IMAGE_TILING_OPTIMAL,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    VmaAllocationCreateInfo alloc_info = {
 | 
			
		||||
        .usage = VMA_MEMORY_USAGE_AUTO,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    VkImage image;
 | 
			
		||||
    VmaAllocation allocation;
 | 
			
		||||
    if (vmaCreateImage(phys_res_mgr->allocator, &image_info, &alloc_info, &image, &allocation, NULL) != VK_SUCCESS) {
 | 
			
		||||
        rtLog("VK", "Failed to create image.");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    /* Store */
 | 
			
		||||
    rt_result res = RT_SUCCESS;
 | 
			
		||||
    rtLockWrite(&phys_res_mgr->lock);
 | 
			
		||||
    uint32_t slot = AllocStorageSlot(phys_res_mgr, h);
 | 
			
		||||
    if (slot != UINT32_MAX) {
 | 
			
		||||
        phys_res_mgr->resources[slot].type = RT_RENDER_RESOURCE_TYPE_BUFFER;
 | 
			
		||||
        phys_res_mgr->resources[slot].image = image;
 | 
			
		||||
        phys_res_mgr->resources[slot].allocation = allocation;
 | 
			
		||||
    } else {
 | 
			
		||||
        res = RT_OUT_OF_MEMORY;
 | 
			
		||||
        vmaDestroyImage(phys_res_mgr->allocator, image, allocation);
 | 
			
		||||
        rtLog("VK","Could not create image because no storage space is available.");
 | 
			
		||||
    }
 | 
			
		||||
    rtUnlockWrite(&phys_res_mgr->lock);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user