diff --git a/src/renderer/init.c b/src/renderer/init.c index 1f407c8..4dcb83b 100644 --- a/src/renderer/init.c +++ b/src/renderer/init.c @@ -1,9 +1,12 @@ #include "renderer.h" #include "backend_api.h" +#include "runtime/runtime.h" +#include #include RT_CVAR_S(rt_Renderer, "The used renderer. Available options: vk, dx11. (Default: vk)", "vk"); +extern rt_cvar r_MaxRenderResources; RT_DLLEXPORT void rtRegisterRenderCVARs(void) { rtRegisterCVAR(&rt_Renderer); @@ -13,10 +16,23 @@ RT_DLLEXPORT void rtRegisterRenderBackendCVARs(void) { g_render_backend.RegisterCVARs(); } +rt_render_device_i g_device_i; + +extern rt_result InitVirtualResourceRegistry(void); +extern void ShutdownVirtualResourceRegistry(void); RT_DLLEXPORT rt_result rtInitRenderer(const rt_renderer_window_info *info) { rt_render_backend_init_result backend_res = g_render_backend.Init(info); - return backend_res.result; + if (backend_res.result != RT_SUCCESS) + return backend_res.result; + g_device_i = backend_res.device; + + rt_result res; + if ((res = InitVirtualResourceRegistry()) != RT_SUCCESS) { + g_render_backend.Shutdown(); + return res; + } + return res; } RT_DLLEXPORT void rtShutdownRenderer(void) { diff --git a/src/renderer/meson.build b/src/renderer/meson.build index e5913ae..e427f29 100644 --- a/src/renderer/meson.build +++ b/src/renderer/meson.build @@ -19,11 +19,14 @@ renderer_lib = library('renderer', 'backend_api.h', 'renderer.h', 'render_mesh.h', + 'render_resource.h', + 'virtual_resource_registry.h', 'init.c', 'load_stub.c', 'meshlet_pools.c', 'render_mesh.c', + 'virtual_resource_registry.c', dependencies: [m_dep, thread_dep], link_with: renderer_link_libs, include_directories: engine_incdir, diff --git a/src/renderer/render_resource.h b/src/renderer/render_resource.h new file mode 100644 index 0000000..7dac3a0 --- /dev/null +++ b/src/renderer/render_resource.h @@ -0,0 +1,97 @@ +#ifndef RT_RENDERER_RENDER_RESOURCE_H +#define RT_RENDERER_RENDER_RESOURCE_H + +#include +#include +#include + +typedef enum { + RT_RENDER_RESOURCE_TYPE_INVALID, + RT_RENDER_RESOURCE_TYPE_BUFFER, + RT_RENDER_RESOURCE_TYPE_TEXTURE2D, + /* Max is 2**6 = 64 */ +} rt_render_resource_type; + +/* Handle to a render resource. + * The layout is: + * | type : 6 | version : 6 | index : 20 | + * MSB LSB + */ +typedef struct { + uint32_t value; +} rt_render_resource_handle; + +#define RT_RENDER_RESOURCE_MAX_VERSION 0x3f + +/* Extract the type part of a render resource handle */ +static RT_INLINE rt_render_resource_type rtGetRenderResourceHandleType(rt_render_resource_handle h) { + return (rt_render_resource_type)((h.value >> 26) & 0x3f); +} + +/* Extract the version part of a render resource handle */ +static RT_INLINE uint32_t rtGetRenderResourceHandleVersion(rt_render_resource_handle h) { + return (h.value >> 20) & 0x3f; +} + +/* Extract the index part of a render resource handle */ +static RT_INLINE uint32_t rtGetRenderResourceHandleIndex(rt_render_resource_handle h) { + return h.value & 0xfffff; +} + +/* Create a render resource handle. This only does the required bit-shifting, it does not actually register any resource for the handle. */ +static RT_INLINE rt_render_resource_handle rtMakeRenderResourceHandle(rt_render_resource_type type, uint32_t version, uint32_t index) { + rt_render_resource_handle h; + h.value = ((type & 0x3f) << 26u) | ((version & 0x3f) << 20u) | (index & 0xfffff); + return h; +} + +/* Resource description structs */ + +typedef enum { + RT_RENDER_BUFFER_USAGE_NONE = 0, + RT_RENDER_BUFFER_USAGE_VERTEX_BUFFER = 0x01, + RT_RENDER_BUFFER_USAGE_INDEX_BUFFER = 0x02, + RT_RENDER_BUFFER_USAGE_STORAGE_BUFFER = 0x04, + + /* The buffer will be used as a source to populate other resources + * with data */ + RT_RENDER_BUFFER_USAGE_UPLOAD_BUFFER = 0x10, +} rt_render_buffer_usage_flags; + +typedef enum { + /* The buffer can reside in memory that can only be accessed by the GPU */ + RT_RENDER_BUFFER_ACCESS_GPU_ONLY = 0x01, + + /* The buffer needs to be in CPU accessible memory */ + RT_RENDER_BUFFER_ACCESS_CPU_AND_GPU = 0x02, + + /* The buffer is short-lived (will be destroyed at the end of the frame) */ + RT_RENDER_BUFFER_ACCESS_TRANSIENT = 0x04, +} rt_render_buffer_access_flags; + +/* Describes a gpu buffer */ +typedef struct { + /* The required size in bytes */ + size_t size; + + /* Bitmask describing the usage of the buffer */ + rt_render_buffer_usage_flags usage; + + /* Bitmask describing the access the buffer needs to support */ + rt_render_buffer_access_flags access; + + /* ResourceID of the resource that will be used to populate this buffer. */ + rt_resource_id source_resource; +} rt_render_buffer_desc; + +/* Describes a gpu texture */ +typedef struct { + /* Width in pixels */ + uint32_t width; + + /* Height in pixels */ + uint32_t height; +} rt_render_texture2d_desc; + +#endif + diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h index df2129a..1bff8a9 100644 --- a/src/renderer/renderer.h +++ b/src/renderer/renderer.h @@ -42,7 +42,6 @@ RT_DLLEXPORT rt_result rtLoadRenderBackend(void); RT_DLLEXPORT void rtRegisterRenderBackendCVARs(void); - RT_DLLEXPORT rt_result rtInitRenderer(const rt_renderer_window_info *window); RT_DLLEXPORT void rtShutdownRenderer(void); diff --git a/src/renderer/virtual_resource_registry.c b/src/renderer/virtual_resource_registry.c new file mode 100644 index 0000000..503cdb4 --- /dev/null +++ b/src/renderer/virtual_resource_registry.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include + + +#include "virtual_resource_registry.h" +#include "render_resource.h" + +RT_CVAR_SZ(r_MaxRenderResources, "Maximum number of render resources that can exist simultaneously. (Default: 16384)", 16384); + +typedef struct { + rt_render_resource_handle *handles; + struct { + union { + /* For management */ + uint32_t next_free; + + rt_render_buffer_desc buffer; + rt_render_texture2d_desc texture2d; + }; + } *descs; + uint32_t first_free; + rt_rwlock lock; +} rt_description_table; + +static rt_description_table _description_tab; + +rt_result InitVirtualResourceRegistry(void) { + _description_tab.handles = calloc(r_MaxRenderResources.sz, sizeof(rt_render_resource_handle)); + if (!_description_tab.handles) + return RT_OUT_OF_MEMORY; + _description_tab.descs = calloc(r_MaxRenderResources.sz, sizeof(*_description_tab.descs)); + if (!_description_tab.descs) { + free(_description_tab.handles); + return RT_OUT_OF_MEMORY; + } + rt_create_rwlock_result lock_res = rtCreateRWLock(); + if (!lock_res.ok) { + free(_description_tab.handles); + free(_description_tab.descs); + return RT_UNKNOWN_ERROR; + } + _description_tab.lock = lock_res.lock; + _description_tab.first_free = 0; + for (uint32_t i = 0; i < r_MaxRenderResources.sz; ++i) { + _description_tab.descs[i].next_free = i + 1; + } + return RT_SUCCESS; +} + +void ShutdownVirtualResourceRegistry(void) { + free(_description_tab.handles); + free(_description_tab.descs); + rtDestroyRWLock(&_description_tab.lock); +} + +/* Returns true if the handle refers to an existing resource. */ +bool rtIsRenderResourceKnown(rt_render_resource_handle h) { + uint32_t idx = rtGetRenderResourceHandleIndex(h); + if (idx >= r_MaxRenderResources.sz) + return false; + rtLockRead(&_description_tab.lock); + bool is_known = _description_tab.handles[idx].value == h.value; + rtUnlockRead(&_description_tab.lock); + return is_known; +} + +static const void *GetResourceDescription(rt_render_resource_handle h) { + rt_render_resource_type type = rtGetRenderResourceHandleType(h); + uint32_t idx = rtGetRenderResourceHandleIndex(h); + if (idx >= r_MaxRenderResources.sz) + return false; + const void *desc = NULL; + rtLockRead(&_description_tab.lock); + if (_description_tab.handles[idx].value == h.value) { + switch (type) { + case RT_RENDER_RESOURCE_TYPE_BUFFER: + desc = &_description_tab.descs[idx].buffer; + break; + case RT_RENDER_RESOURCE_TYPE_TEXTURE2D: + desc = &_description_tab.descs[idx].texture2d; + break; + default: + desc = NULL; + break; + } + } + rtUnlockRead(&_description_tab.lock); + return desc; +} + +/* Returns a pointer to the resource description or NULL, if the handle does not refer to a valid buffer */ +const rt_render_buffer_desc *rtGetRenderBufferDescription(rt_render_resource_handle h) { + return GetResourceDescription(h); +} + +/* Returns a pointer to the resource description or NULL, if the handle does not refer to a valid texture2d */ +const rt_render_texture2d_desc *rtGetRenderTexture2DDescription(rt_render_resource_handle h) { + return GetResourceDescription(h); +} + +static rt_render_resource_handle AllocSlot(rt_render_resource_type type, const void *desc) { + rt_render_resource_handle h = rtMakeRenderResourceHandle(RT_RENDER_RESOURCE_TYPE_INVALID, 0, 0); + rtLockWrite(&_description_tab.lock); + uint32_t slot = _description_tab.first_free; + if (slot < r_MaxRenderResources.sz) { + _description_tab.first_free = _description_tab.descs[slot].next_free; + uint32_t current_version = rtGetRenderResourceHandleVersion(_description_tab.handles[slot]); + uint32_t next_version = (current_version + 1) & RT_RENDER_RESOURCE_MAX_VERSION; + h = rtMakeRenderResourceHandle(type, next_version, slot); + _description_tab.handles[slot] = h; + switch (type) { + case RT_RENDER_RESOURCE_TYPE_BUFFER: + memcpy(&_description_tab.descs[slot].buffer, desc, sizeof(rt_render_buffer_desc)); + break; + case RT_RENDER_RESOURCE_TYPE_TEXTURE2D: + memcpy(&_description_tab.descs[slot].texture2d, desc, sizeof(rt_render_texture2d_desc)); + break; + default: + rtReportError("RENDERER", "Tried to create a resource with invalid type %u", type); + break; + } + } + rtUnlockWrite(&_description_tab.lock); + return h; +} + +/* Stores the render buffer description and returns a handle to the new resource. */ +rt_render_resource_handle rtCreateRenderBuffer(const rt_render_buffer_desc *desc) { + return AllocSlot(RT_RENDER_RESOURCE_TYPE_BUFFER, desc); +} + +/* Stores the texture2d description and returns a handle to the new resource. */ +rt_render_resource_handle rtCreateRenderTexture2D(const rt_render_texture2d_desc *desc) { + return AllocSlot(RT_RENDER_RESOURCE_TYPE_TEXTURE2D, desc); +} diff --git a/src/renderer/virtual_resource_registry.h b/src/renderer/virtual_resource_registry.h new file mode 100644 index 0000000..a8b8e69 --- /dev/null +++ b/src/renderer/virtual_resource_registry.h @@ -0,0 +1,33 @@ +#ifndef RT_RENDERER_VIRTUAL_RESOURCE_REGISTRY_H +#define RT_RENDERER_VIRTUAL_RESOURCE_REGISTRY_H + +#include +#include +#include "render_resource.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns true if the handle refers to an existing resource. */ +bool rtIsRenderResourceKnown(rt_render_resource_handle h); + +/* Returns a pointer to the resource description or NULL, if the handle does not refer to a valid buffer */ +const rt_render_buffer_desc *rtGetRenderBufferDescription(rt_render_resource_handle h); + +/* Returns a pointer to the resource description or NULL, if the handle does not refer to a valid texture2d */ +const rt_render_texture2d_desc *rtGetRenderTexture2DDescription(rt_render_resource_handle h); + +/* Stores the render buffer description and returns a handle to the new resource. */ +rt_render_resource_handle rtCreateRenderBuffer(const rt_render_buffer_desc *desc); + +/* Stores the texture2d description and returns a handle to the new resource. */ +rt_render_resource_handle rtCreateRenderTexture2D(const rt_render_texture2d_desc *desc); + +#ifdef __cplusplus +} +#endif + +#endif +