Load framegraphs from resource files
This commit is contained in:
parent
bdd3db98bb
commit
cc49a017f9
64
assets/test.framegraph
Normal file
64
assets/test.framegraph
Normal file
@ -0,0 +1,64 @@
|
||||
render_targets {
|
||||
color0 {
|
||||
format R8G8B8A8_SRGB;
|
||||
width 1024;
|
||||
height 768;
|
||||
sample_count 4;
|
||||
}
|
||||
|
||||
swapchain_out {
|
||||
format SWAPCHAIN;
|
||||
width SWAPCHAIN;
|
||||
height SWAPCHAIN;
|
||||
sample_count 1;
|
||||
}
|
||||
|
||||
depth0 {
|
||||
format DEPTH24_STENCIL8;
|
||||
width 512;
|
||||
height 384;
|
||||
sample_count 4;
|
||||
}
|
||||
}
|
||||
|
||||
passes {
|
||||
pass0 {
|
||||
writes {
|
||||
color0 {
|
||||
clear_value {
|
||||
r 1.0;
|
||||
g 1.0;
|
||||
b 1.0;
|
||||
a 1.0;
|
||||
}
|
||||
|
||||
clear YES;
|
||||
discard NO;
|
||||
}
|
||||
|
||||
depth0 {
|
||||
clear_value {
|
||||
d 0.0;
|
||||
s 0;
|
||||
}
|
||||
|
||||
clear YES;
|
||||
discard YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass1 {
|
||||
reads {
|
||||
color0 {
|
||||
mode SAMPLED;
|
||||
}
|
||||
}
|
||||
writes {
|
||||
swapchain_out {
|
||||
clear NO;
|
||||
discard NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -28,6 +28,8 @@ elif compiler.get_argument_syntax() == 'msvc'
|
||||
if buildtype == 'debug'
|
||||
add_project_arguments(['/RTCsu'], language : ['c', 'cpp'])
|
||||
endif
|
||||
# Allow nameless struct/unions (standard in C11)
|
||||
add_project_arguments(['/wd4201'], language : 'cpp')
|
||||
endif
|
||||
|
||||
if get_option('default_library') == 'static'
|
||||
@ -98,6 +100,7 @@ if get_option('build_asset_compiler')
|
||||
|
||||
'src/runtime/asset_compiler.c',
|
||||
'src/runtime/description_parser.c',
|
||||
'src/runtime/framegraph_processor.c',
|
||||
'src/runtime/pipeline_processor.c',
|
||||
'src/runtime/shader_compiler.c',
|
||||
]
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "runtime/gfx.h"
|
||||
#include "runtime/resources.h"
|
||||
#include "runtime/mem_arena.h"
|
||||
|
||||
static rt_framegraph *_framegraph;
|
||||
|
||||
@ -6,6 +8,7 @@ static rt_framegraph *_framegraph;
|
||||
void Init(void) {
|
||||
rtLog("GAME", "Init");
|
||||
|
||||
#if 0
|
||||
rt_render_target_id rt_ids[4] = {rtCalculateRenderTargetID("rt0", sizeof("rt0")),
|
||||
rtCalculateRenderTargetID("rt1", sizeof("rt1")),
|
||||
rtCalculateRenderTargetID("rt2", sizeof("rt2")),
|
||||
@ -54,8 +57,16 @@ void Init(void) {
|
||||
};
|
||||
rtSetRelptr(&info.render_passes, passes);
|
||||
rtSetRelptr(&info.render_targets, rts);
|
||||
#endif
|
||||
|
||||
_framegraph = rtCreateFramegraph(&info);
|
||||
rt_resource_id id = rtGetResourceID("assets/test.framegraph");
|
||||
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
|
||||
rt_resource *resource =
|
||||
rtArenaPush(temp.arena, rtGetResourceSize(id));
|
||||
|
||||
rtGetResource(id, resource);
|
||||
|
||||
_framegraph = rtCreateFramegraph(resource->data);
|
||||
}
|
||||
|
||||
/* Called after exiting the main-loop and before the runtime starts its shutdown */
|
||||
|
@ -2,10 +2,26 @@
|
||||
|
||||
VkFormat rtPixelFormatToVkFormat(rt_pixel_format format) {
|
||||
switch (format) {
|
||||
case RT_PIXEL_FORMAT_R8G8B8A8_UNORM:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case RT_PIXEL_FORMAT_B8G8R8A8_UNORM:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
case RT_PIXEL_FORMAT_R8G8B8A8_SRGB:
|
||||
return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
case RT_PIXEL_FORMAT_B8G8R8A8_SRGB:
|
||||
return VK_FORMAT_B8G8R8A8_SRGB;
|
||||
case RT_PIXEL_FORMAT_R8G8B8_UNORM:
|
||||
return VK_FORMAT_R8G8B8_UNORM;
|
||||
case RT_PIXEL_FORMAT_B8G8R8_UNORM:
|
||||
return VK_FORMAT_B8G8R8_UNORM;
|
||||
case RT_PIXEL_FORMAT_R8G8B8_SRGB:
|
||||
return VK_FORMAT_R8G8B8_SRGB;
|
||||
case RT_PIXEL_FORMAT_B8G8R8_SRGB:
|
||||
return VK_FORMAT_B8G8R8_SRGB;
|
||||
case RT_PIXEL_FORMAT_DEPTH24_STENCIL8:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
case RT_PIXEL_FORMAT_DEPTH32:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
@ -20,6 +36,8 @@ VkSampleCountFlagBits rtSampleCountToFlags(unsigned int count) {
|
||||
while (count > 1) {
|
||||
if ((counts & count) == 0)
|
||||
count >>= 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return (VkSampleCountFlagBits)count;
|
||||
}
|
@ -175,7 +175,7 @@ rt_render_target_handle RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_t
|
||||
slot->render_target.format = g_swapchain.format;
|
||||
slot->render_target.match_swapchain |= RT_RENDER_TARGET_MATCH_SWAPCHAIN_FORMAT;
|
||||
}
|
||||
if (info->format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8) {
|
||||
if (info->format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8 || info->format == RT_PIXEL_FORMAT_DEPTH32) {
|
||||
slot->render_target.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||
|
@ -65,9 +65,11 @@ static rt_asset_db _asset_db;
|
||||
static rt_processing_queue _processing_queue;
|
||||
|
||||
extern RT_ASSET_PROCESSOR_FN(PipelineProcessor);
|
||||
extern RT_ASSET_PROCESSOR_FN(FramegraphProcessor);
|
||||
|
||||
static rt_asset_processor _processors[] = {
|
||||
{.file_ext = ".pipeline", .proc = PipelineProcessor}
|
||||
{.file_ext = ".pipeline", .proc = PipelineProcessor},
|
||||
{.file_ext = ".framegraph", .proc = FramegraphProcessor},
|
||||
};
|
||||
|
||||
static void ProcessorThreadEntry(void *);
|
||||
|
@ -17,10 +17,34 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
float v[4];
|
||||
struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
};
|
||||
} rt_color;
|
||||
|
||||
/* NOTE(kevin): When you add a value here, you need to handle them in
|
||||
* framegraph_processor.c : ParseFramegraph
|
||||
* and in the render target and texture functions of all renderers. */
|
||||
|
||||
typedef enum {
|
||||
RT_PIXEL_FORMAT_INVALID,
|
||||
|
||||
RT_PIXEL_FORMAT_R8G8B8A8_UNORM,
|
||||
RT_PIXEL_FORMAT_B8G8R8A8_UNORM,
|
||||
RT_PIXEL_FORMAT_R8G8B8A8_SRGB,
|
||||
RT_PIXEL_FORMAT_B8G8R8A8_SRGB,
|
||||
RT_PIXEL_FORMAT_R8G8B8_UNORM,
|
||||
RT_PIXEL_FORMAT_B8G8R8_UNORM,
|
||||
RT_PIXEL_FORMAT_R8G8B8_SRGB,
|
||||
RT_PIXEL_FORMAT_B8G8R8_SRGB,
|
||||
|
||||
RT_PIXEL_FORMAT_DEPTH24_STENCIL8,
|
||||
RT_PIXEL_FORMAT_DEPTH32,
|
||||
|
||||
/* Special value indicating whichever format the swapchain uses */
|
||||
RT_PIXEL_FORMAT_SWAPCHAIN,
|
||||
@ -28,6 +52,21 @@ typedef enum {
|
||||
RT_PIXEL_FORMAT_count,
|
||||
} rt_pixel_format;
|
||||
|
||||
/* In renderer_api.h -> Not necessary for almost all gfx usage */
|
||||
typedef struct rt_renderer_init_info_s rt_renderer_init_info;
|
||||
|
||||
RT_DLLEXPORT void rtRegisterRendererCVars(void);
|
||||
|
||||
RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info);
|
||||
|
||||
RT_DLLEXPORT void rtShutdownGFX(void);
|
||||
|
||||
/* *********************************************************************
|
||||
* Framegraph API
|
||||
*
|
||||
* The framegraph is used to organize and schedule the work for a frame.
|
||||
* *********************************************************************/
|
||||
|
||||
/* Special value for the .width and .height fields of rt_render_target_info
|
||||
* to indicate that these should be set to the width or height of the swapchain, respectively. */
|
||||
#define RT_RENDER_TARGET_SIZE_SWAPCHAIN 0
|
||||
@ -44,8 +83,8 @@ typedef struct {
|
||||
} rt_render_target_info;
|
||||
|
||||
typedef enum {
|
||||
RT_RENDER_TARGET_READ_INPUT_ATTACHMENT,
|
||||
RT_RENDER_TARGET_READ_SAMPLED,
|
||||
RT_RENDER_TARGET_READ_INPUT_ATTACHMENT,
|
||||
|
||||
RT_RENDER_TARGET_READ_count,
|
||||
} rt_render_target_read_mode;
|
||||
@ -66,7 +105,7 @@ typedef enum {
|
||||
typedef struct {
|
||||
rt_render_target_id render_target;
|
||||
union {
|
||||
float color[4];
|
||||
rt_color color;
|
||||
struct {
|
||||
float depth;
|
||||
int32_t stencil;
|
||||
@ -102,20 +141,6 @@ typedef struct {
|
||||
rt_render_pass_finalize_fn *Finalize;
|
||||
} rt_render_pass_bind_fns;
|
||||
|
||||
/* In renderer_api.h -> Not necessary for almost all gfx usage */
|
||||
typedef struct rt_renderer_init_info_s rt_renderer_init_info;
|
||||
|
||||
RT_DLLEXPORT void rtRegisterRendererCVars(void);
|
||||
|
||||
RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info);
|
||||
|
||||
RT_DLLEXPORT void rtShutdownGFX(void);
|
||||
|
||||
|
||||
/* Framegraph API
|
||||
*
|
||||
* The framegraph is used to organize and schedule the work for a frame.
|
||||
*/
|
||||
|
||||
typedef struct rt_framegraph_s rt_framegraph;
|
||||
|
||||
|
@ -310,6 +310,7 @@ static bool ValidateInfo(const rt_framegraph_info *info) {
|
||||
rtReportError(
|
||||
"GFX",
|
||||
"Framegraph pass %u reads too many rendertargets: %u (maximum allowed is %u)",
|
||||
i,
|
||||
passes[i].read_render_target_count,
|
||||
RT_RENDERPASS_MAX_READS);
|
||||
return false;
|
||||
@ -317,6 +318,7 @@ static bool ValidateInfo(const rt_framegraph_info *info) {
|
||||
rtReportError(
|
||||
"GFX",
|
||||
"Framegraph pass %u writes too many rendertargets: %u (maximum allowed is %u)",
|
||||
i,
|
||||
passes[i].write_render_target_count,
|
||||
RT_RENDERPASS_MAX_WRITES);
|
||||
return false;
|
||||
|
@ -98,6 +98,16 @@ static size_t GetResourceDataSize(const rt_resource *resource) {
|
||||
const rt_shader_info *info = resource->data;
|
||||
return sizeof(rt_shader_info) + (info) ? info->bytecode_length : 0;
|
||||
} break;
|
||||
case RT_RESOURCE_FRAMEGRAPH: {
|
||||
const rt_framegraph_info *info = resource->data;
|
||||
size_t size = sizeof(*info) + sizeof(rt_render_target_info) * info->render_target_count +
|
||||
sizeof(rt_render_pass_info) * info->render_pass_count;
|
||||
const rt_render_pass_info *passes = rtResolveConstRelptr(&info->render_passes);
|
||||
for (uint32_t i = 0; i < info->render_pass_count; ++i) {
|
||||
size += passes[i].read_render_target_count * sizeof(rt_render_target_read) +
|
||||
passes[i].write_render_target_count * sizeof(rt_render_target_write);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
rtLog("RESMGR", "Tried to get size of an invalid resource type %u", resource->type);
|
||||
}
|
||||
@ -117,8 +127,38 @@ static void CopyResourceData(const rt_resource *resource, void *dest) {
|
||||
memcpy(dest_info + 1, rtResolveConstRelptr(&info->bytecode), info->bytecode_length);
|
||||
rtSetRelptr(&dest_info->bytecode, (void *)(dest_info + 1));
|
||||
} break;
|
||||
case RT_RESOURCE_FRAMEGRAPH: {
|
||||
const rt_framegraph_info *info = resource->data;
|
||||
rt_framegraph_info *dest_info = dest;
|
||||
memcpy(dest_info, info, sizeof(*info));
|
||||
memcpy(dest_info + 1,
|
||||
rtResolveConstRelptr(&info->render_targets),
|
||||
info->render_target_count * sizeof(rt_render_target_info));
|
||||
rtSetRelptr(&dest_info->render_targets, (void *)(dest_info + 1));
|
||||
char *passes_begin =
|
||||
(char *)(dest_info + 1) + info->render_target_count * sizeof(rt_render_target_info);
|
||||
memcpy(passes_begin,
|
||||
rtResolveConstRelptr(&info->render_passes),
|
||||
info->render_pass_count * sizeof(rt_render_pass_info));
|
||||
char *read_write_dest = passes_begin + info->render_pass_count * sizeof(rt_render_pass_info);
|
||||
rt_render_pass_info *passes_dest = (rt_render_pass_info *)passes_begin;
|
||||
const rt_render_pass_info *passes =
|
||||
(const rt_render_pass_info *)rtResolveConstRelptr(&info->render_passes);
|
||||
for (uint32_t i = 0; i < info->render_pass_count; ++i) {
|
||||
rtSetRelptr(&passes_dest[i].read_render_targets, read_write_dest);
|
||||
memcpy(read_write_dest,
|
||||
rtResolveConstRelptr(&passes[i].read_render_targets),
|
||||
sizeof(rt_render_target_read) * passes[i].read_render_target_count);
|
||||
read_write_dest += sizeof(rt_render_target_read) * passes[i].read_render_target_count;
|
||||
rtSetRelptr(&passes_dest[i].write_render_targets, read_write_dest);
|
||||
memcpy(read_write_dest,
|
||||
rtResolveConstRelptr(&passes[i].write_render_targets),
|
||||
sizeof(rt_render_target_write) * passes[i].write_render_target_count);
|
||||
read_write_dest += sizeof(rt_render_target_write) * passes[i].write_render_target_count;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
rtLog("RESMGR", "Tried to get copy a resource of invalid type %u", resource->type);
|
||||
rtLog("RESMGR", "Tried to copy a resource of invalid type %u", resource->type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,6 +789,15 @@ RT_DLLEXPORT void rtPrefetchResources(const rt_resource_id *ids, uint32_t count)
|
||||
}
|
||||
}
|
||||
|
||||
RT_DLLEXPORT rt_resource_id rtGetResourceID(const char *name) {
|
||||
size_t name_len = strlen(name);
|
||||
rt_resource_id id = (rt_resource_id)rtHashBytes(name, name_len);
|
||||
if (id == RT_INVALID_RESOURCE_ID || id == RT_TOMBSTONE_ID)
|
||||
id = ~id;
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
RT_DLLEXPORT rt_result rtCreateResources(uint32_t count,
|
||||
const char **names,
|
||||
const rt_resource *resources,
|
||||
@ -764,11 +813,7 @@ RT_DLLEXPORT rt_result rtCreateResources(uint32_t count,
|
||||
|
||||
rtLockWrite(&_namespace.lock);
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
size_t name_len = strlen(names[i]);
|
||||
rt_resource_id id = (rt_resource_id)rtHashBytes(names[i], name_len);
|
||||
if (id == RT_INVALID_RESOURCE_ID || id == RT_TOMBSTONE_ID)
|
||||
id = ~id;
|
||||
|
||||
rt_resource_id id = rtGetResourceID(names[i]);
|
||||
bool inserted = false;
|
||||
for (size_t j = 0; j < ns_size; ++j) {
|
||||
size_t at = (id + j) % ns_size;
|
||||
|
@ -35,6 +35,8 @@ typedef enum {
|
||||
/* A pipeline state object */
|
||||
RT_RESOURCE_PIPELINE,
|
||||
|
||||
RT_RESOURCE_FRAMEGRAPH,
|
||||
|
||||
RT_RESOURCE_TYPE_count,
|
||||
} rt_resource_type;
|
||||
|
||||
@ -74,6 +76,10 @@ RT_DLLEXPORT void rtPrefetchResources(const rt_resource_id *ids, uint32_t count)
|
||||
/* Returns the size of a resource in bytes, or 0 if the resource id is invalid. */
|
||||
RT_DLLEXPORT size_t rtGetResourceSize(rt_resource_id id);
|
||||
|
||||
/* Returns the resource id that maps to a given name.
|
||||
* Does not check if a resource with that id does exist. */
|
||||
RT_DLLEXPORT rt_resource_id rtGetResourceID(const char *name);
|
||||
|
||||
/* Logs information about a resource. Useful for debugging */
|
||||
RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resource);
|
||||
|
||||
|
@ -61,6 +61,26 @@ RT_DLLEXPORT void rtLockWrite(rt_rwlock *lock);
|
||||
|
||||
RT_DLLEXPORT void rtUnlockWrite(rt_rwlock *lock);
|
||||
|
||||
/* Semaphore */
|
||||
typedef struct {
|
||||
volatile int counter;
|
||||
int max;
|
||||
rt_condition_var *cond;
|
||||
} rt_semaphore;
|
||||
|
||||
typedef struct {
|
||||
bool ok;
|
||||
rt_semaphore semaphore;
|
||||
} rt_create_semaphore_result;
|
||||
|
||||
RT_DLLEXPORT rt_create_semaphore_result rtCreateSemaphore(int initial_value, int max_value);
|
||||
|
||||
RT_DLLEXPORT void rtDestroySemaphore(rt_semaphore *sem);
|
||||
|
||||
RT_DLLEXPORT void rtSignalSemaphore(rt_semaphore *sem);
|
||||
|
||||
RT_DLLEXPORT void rtWaitOnSemaphore(rt_semaphore *sem);
|
||||
|
||||
/* Threads */
|
||||
|
||||
typedef struct rt_thread_s rt_thread;
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "threading.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Based on: https://eli.thegreenplace.net/2019/implementing-reader-writer-locks/ */
|
||||
|
||||
RT_DLLEXPORT rt_create_rwlock_result rtCreateRWLock(void) {
|
||||
@ -26,7 +24,7 @@ RT_DLLEXPORT void rtLockRead(rt_rwlock *lock) {
|
||||
|
||||
RT_DLLEXPORT void rtUnlockRead(rt_rwlock *lock) {
|
||||
rtLockConditionVar(lock->cond);
|
||||
assert(lock->reader_count > 0);
|
||||
RT_ASSERT(lock->reader_count > 0, "Tried to unlock a read-write lock that is not held.");
|
||||
--lock->reader_count;
|
||||
bool signal = lock->reader_count == 0;
|
||||
rtUnlockConditionVar(lock->cond, signal);
|
||||
|
Loading…
Reference in New Issue
Block a user