Differentiate between graphics and compile passes
This commit is contained in:
parent
bc6076b786
commit
ee24cd4903
@ -23,6 +23,7 @@ render_targets {
|
||||
|
||||
passes {
|
||||
pass0 {
|
||||
type GRAPHICS;
|
||||
writes {
|
||||
color0 {
|
||||
clear_value {
|
||||
@ -49,6 +50,7 @@ passes {
|
||||
}
|
||||
|
||||
pass1 {
|
||||
type GRAPHICS;
|
||||
reads {
|
||||
color0 {
|
||||
mode SAMPLED;
|
||||
@ -56,7 +58,13 @@ passes {
|
||||
}
|
||||
writes {
|
||||
swapchain_out {
|
||||
clear NO;
|
||||
clear_value {
|
||||
r 1.0;
|
||||
g 0.0;
|
||||
b 0.0;
|
||||
a 1.0;
|
||||
}
|
||||
clear YES;
|
||||
discard NO;
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ void UpdateThreadEntry(void *param) {
|
||||
while (!g_main_loop.shutdown) {
|
||||
/* Wait until the render thread has catched up */
|
||||
rtWaitOnSemaphore(&g_main_loop.update_proceed);
|
||||
rtLog("UT", "Processing %u", g_main_loop.u_frame_id);
|
||||
//rtLog("UT", "Processing %u", g_main_loop.u_frame_id);
|
||||
|
||||
(g_main_loop.GameUpdate)();
|
||||
|
||||
rtLog("UT", "Finished %u", g_main_loop.u_frame_id);
|
||||
//rtLog("UT", "Finished %u", g_main_loop.u_frame_id);
|
||||
g_main_loop.u_frame_id += 1;
|
||||
/* Signal the render thread that data is available */
|
||||
rtSignalSemaphore(&g_main_loop.render_proceed);
|
||||
@ -37,13 +37,13 @@ void RenderThreadEntry(void *param) {
|
||||
rtLog("RT", "RenderThread Entry");
|
||||
while (!g_main_loop.shutdown) {
|
||||
rtWaitOnSemaphore(&g_main_loop.render_proceed);
|
||||
rtLog("RT", "Processing %u", g_main_loop.r_frame_id);
|
||||
//rtLog("RT", "Processing %u", g_main_loop.r_frame_id);
|
||||
|
||||
rtBeginGFXFrame(g_main_loop.r_frame_id);
|
||||
(g_main_loop.GameRender)();
|
||||
rtEndGFXFrame(g_main_loop.r_frame_id);
|
||||
|
||||
rtLog("RT", "Finished %u", g_main_loop.r_frame_id);
|
||||
//rtLog("RT", "Finished %u", g_main_loop.r_frame_id);
|
||||
g_main_loop.r_frame_id += 1;
|
||||
/* Signal the update thread that we have finished and it can proceed */
|
||||
rtSignalSemaphore(&g_main_loop.update_proceed);
|
||||
|
@ -393,6 +393,22 @@ static void ProcessorThreadEntry(void *param) {
|
||||
}
|
||||
}
|
||||
|
||||
RT_DLLEXPORT void rtWaitForAssetProcessing(void) {
|
||||
int turns = 5;
|
||||
while (turns > 0) {
|
||||
rtSleep(100);
|
||||
int in_processing_count = 0;
|
||||
for (int i = 0; i < rt_AssetDBSize.i; ++i) {
|
||||
rtLockRead(&_asset_db.lock);
|
||||
if (_asset_db.files[i] != RT_INVALID_FILE_ID && _asset_db.data[i].in_processing)
|
||||
++in_processing_count;
|
||||
rtUnlockRead(&_asset_db.lock);
|
||||
}
|
||||
if (!in_processing_count)
|
||||
--turns;
|
||||
}
|
||||
}
|
||||
|
||||
/* Utilities for asset processors*/
|
||||
|
||||
rt_loaded_asset LoadAsset(rt_file_id file) {
|
||||
|
@ -15,6 +15,9 @@ RT_DLLEXPORT rt_result rtInitAssetCompiler(void);
|
||||
|
||||
RT_DLLEXPORT void rtShutdownAssetCompiler(void);
|
||||
|
||||
/* Wait until all pending assets are processed. */
|
||||
RT_DLLEXPORT void rtWaitForAssetProcessing(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -7,19 +7,6 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
rt_render_target_info *render_targets;
|
||||
rt_render_pass_info *render_passes;
|
||||
rt_render_target_read *reads;
|
||||
rt_render_target_write *writes;
|
||||
uint32_t render_target_count;
|
||||
uint32_t render_pass_count;
|
||||
uint32_t read_capacity;
|
||||
uint32_t write_capacity;
|
||||
uint32_t read_count;
|
||||
uint32_t write_count;
|
||||
} rt_parsed_framegraph;
|
||||
|
||||
static int RenderTargetExists(const rt_framegraph_info *framegraph, rt_render_target_id id) {
|
||||
const rt_render_target_info *render_targets = rtResolveConstRelptr(&framegraph->render_targets);
|
||||
for (uint32_t i = 0; i < framegraph->render_target_count; ++i) {
|
||||
@ -236,6 +223,33 @@ static rt_result ParseFramegraph(const char *text,
|
||||
|
||||
passes[i].id =
|
||||
rtCalculateRenderPassID(pass_stmt->attribute.start, pass_stmt->attribute.length);
|
||||
rtSetRelptr(&passes[i].name, NULL);
|
||||
passes[i].name_len = 0;
|
||||
|
||||
passes[i].type = RT_RENDER_PASS_TYPE_GRAPHICS;
|
||||
const rt_parsed_stmt *type_stmt = rtFindStatement(&state, pass_stmt->list_index, "type");
|
||||
if (type_stmt) {
|
||||
if (type_stmt->form != RT_STMT_FORM_VALUE) {
|
||||
rtLog("AC",
|
||||
"Expected GRAPHICS or COMPUTE as the value of \"passes.%.*s.type\" in %s",
|
||||
pass_stmt->attribute.length,
|
||||
pass_stmt->attribute.start,
|
||||
file_path);
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
if (rtCompareSpanToString(type_stmt->value, "GRAPHICS") == 0) {
|
||||
passes[i].type = RT_RENDER_PASS_TYPE_GRAPHICS;
|
||||
} else if (rtCompareSpanToString(type_stmt->value, "COMPUTE") == 0) {
|
||||
passes[i].type = RT_RENDER_PASS_TYPE_COMPUTE;
|
||||
} else {
|
||||
rtLog("AC",
|
||||
"Expected GRAPHICS or COMPUTE as the value of \"passes.%.*s.type\" in %s",
|
||||
pass_stmt->attribute.length,
|
||||
pass_stmt->attribute.start,
|
||||
file_path);
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
const rt_parsed_stmt *write_list_stmt =
|
||||
rtFindStatement(&state, pass_stmt->list_index, "writes");
|
||||
|
@ -18,7 +18,7 @@ static void PassPrepare(rt_render_pass_id pass,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
rtLog("GAME", "Prepare pass %x", pass);
|
||||
//rtLog("GAME", "Prepare pass %x", pass);
|
||||
}
|
||||
|
||||
static void PassExecute(rt_render_pass_id pass,
|
||||
@ -26,7 +26,7 @@ static void PassExecute(rt_render_pass_id pass,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
rtLog("GAME", "Execute pass %x", pass);
|
||||
//rtLog("GAME", "Execute pass %x", pass);
|
||||
}
|
||||
|
||||
static void PassFinalize(rt_render_pass_id pass,
|
||||
@ -34,7 +34,7 @@ static void PassFinalize(rt_render_pass_id pass,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
rtLog("GAME", "Finalize pass %x", pass);
|
||||
//rtLog("GAME", "Finalize pass %x", pass);
|
||||
}
|
||||
|
||||
/* Called after the runtime has finished its initialization and before entering the main-loop*/
|
||||
@ -42,12 +42,11 @@ void Init(void) {
|
||||
rtLog("GAME", "Init");
|
||||
rtInitAssetCompiler();
|
||||
|
||||
rt_resource_id resid = rtGetResourceID("assets/test.framegraph");
|
||||
while (rtGetResourceSize(resid) == 0)
|
||||
rtSleep(10);
|
||||
rtWaitForAssetProcessing();
|
||||
|
||||
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
|
||||
|
||||
rt_resource_id resid = rtGetResourceID("assets/test.framegraph");
|
||||
size_t size = rtGetResourceSize(resid);
|
||||
rt_resource *res = rtArenaPush(temp.arena, size);
|
||||
rtGetResource(resid, res);
|
||||
@ -57,8 +56,8 @@ void Init(void) {
|
||||
rt_render_pass_bind_fns bind = {.Execute = PassExecute,
|
||||
.Prepare = PassPrepare,
|
||||
.Finalize = PassFinalize};
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass0", sizeof("pass0")-1), &bind);
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass1", sizeof("pass1")-1), &bind);
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass0", sizeof("pass0") - 1), &bind);
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass1", sizeof("pass1") - 1), &bind);
|
||||
}
|
||||
|
||||
/* Called after exiting the main-loop and before the runtime starts its shutdown */
|
||||
|
@ -118,8 +118,19 @@ typedef struct {
|
||||
rt_render_target_write_flags flags;
|
||||
} rt_render_target_write;
|
||||
|
||||
typedef enum {
|
||||
RT_RENDER_PASS_TYPE_GRAPHICS,
|
||||
RT_RENDER_PASS_TYPE_COMPUTE,
|
||||
} rt_render_pass_type;
|
||||
|
||||
typedef struct {
|
||||
rt_render_pass_id id;
|
||||
|
||||
/* For debug purposes, can be 0 */
|
||||
rt_relptr name;
|
||||
uint32_t name_len;
|
||||
|
||||
rt_render_pass_type type;
|
||||
/* list of rt_render_target_reads */
|
||||
rt_relptr read_render_targets;
|
||||
/* list of rt_render_target_writes */
|
||||
|
@ -29,6 +29,8 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
rt_render_pass_id id;
|
||||
rt_render_pass_type type;
|
||||
const char *name;
|
||||
int execution_level;
|
||||
unsigned int read_count;
|
||||
unsigned int write_count;
|
||||
@ -52,6 +54,11 @@ static rt_framegraph *_framegraphs;
|
||||
static rt_framegraph *_first_free;
|
||||
static rt_mutex *_free_list_lock;
|
||||
|
||||
#define NAMES_CAPACITY 512
|
||||
static char _name_buffer[512];
|
||||
static char *_name_next;
|
||||
static rt_mutex *_name_lock;
|
||||
|
||||
static void ReturnFrameGraph(rt_framegraph *framegraph) {
|
||||
rtLockMutex(_free_list_lock);
|
||||
framegraph->next_free = _first_free;
|
||||
@ -63,18 +70,25 @@ rt_result InitFramegraphManager(void) {
|
||||
_free_list_lock = rtCreateMutex();
|
||||
if (!_free_list_lock)
|
||||
return RT_UNKNOWN_ERROR;
|
||||
_name_lock = rtCreateMutex();
|
||||
if (!_name_lock) {
|
||||
rtDestroyMutex(_free_list_lock);
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
_framegraphs = calloc((size_t)rt_MaxFramegraphs.i, sizeof(rt_framegraph));
|
||||
if (!_framegraphs)
|
||||
return RT_OUT_OF_MEMORY;
|
||||
for (int i = 0; i < rt_MaxFramegraphs.i; ++i)
|
||||
_framegraphs[i].next_free = (i < rt_MaxFramegraphs.i - 1) ? &_framegraphs[i + 1] : NULL;
|
||||
_first_free = &_framegraphs[0];
|
||||
_name_next = &_name_buffer[0];
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
void ShutdownFramegraphManager(void) {
|
||||
free(_framegraphs);
|
||||
rtDestroyMutex(_free_list_lock);
|
||||
rtDestroyMutex(_name_lock);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@ -226,6 +240,28 @@ CreateRenderPasses(rt_framegraph *graph, const rt_framegraph_info *info, rt_aren
|
||||
graph->passes[i].write_count = pass_info[i].write_render_target_count;
|
||||
graph->passes[i].read_count = pass_info[i].read_render_target_count;
|
||||
graph->passes[i].id = pass_info[i].id;
|
||||
graph->passes[i].type = pass_info[i].type;
|
||||
graph->passes[i].name = NULL;
|
||||
|
||||
const char *name = rtResolveConstRelptr(&pass_info[i].name);
|
||||
if (name) {
|
||||
size_t name_strlen = strlen(name);
|
||||
if (name_strlen + 1 == pass_info[i].name_len) {
|
||||
rtLockMutex(_name_lock);
|
||||
ptrdiff_t name_off = _name_next - _name_buffer;
|
||||
if ((name_off + pass_info[i].name_len) < NAMES_CAPACITY) {
|
||||
char *dst_name = _name_next;
|
||||
memcpy(dst_name, name, pass_info[i].name_len);
|
||||
_name_next += pass_info[i].name_len;
|
||||
graph->passes[i].name = dst_name;
|
||||
} else {
|
||||
rtLog("GFX", "Ran out of storage for debug name %s", name);
|
||||
}
|
||||
rtUnlockMutex(_name_lock);
|
||||
} else {
|
||||
rtLog("GFX", "Declared name-length for pass %u does not match strlen()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort by execution level */
|
||||
@ -409,7 +445,7 @@ static rt_render_target *GetRenderTarget(rt_framegraph *framegraph, rt_render_ta
|
||||
}
|
||||
|
||||
static void
|
||||
BeginPass(rt_framegraph *framegraph, uint32_t pass_idx, rt_command_buffer_handle cmdbuf) {
|
||||
BeginGraphicsPass(rt_framegraph *framegraph, uint32_t pass_idx, rt_command_buffer_handle cmdbuf) {
|
||||
const rt_render_target_write *writes = framegraph->passes[pass_idx].writes;
|
||||
const rt_render_target_read *reads = framegraph->passes[pass_idx].reads;
|
||||
uint32_t write_count = framegraph->passes[pass_idx].write_count;
|
||||
@ -500,6 +536,45 @@ BeginPass(rt_framegraph *framegraph, uint32_t pass_idx, rt_command_buffer_handle
|
||||
g_renderer.CmdBeginPass(cmdbuf, &begin_info);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
BeginComputePass(rt_framegraph *framegraph, uint32_t pass_idx, rt_command_buffer_handle cmdbuf) {
|
||||
const rt_render_target_write *writes = framegraph->passes[pass_idx].writes;
|
||||
const rt_render_target_read *reads = framegraph->passes[pass_idx].reads;
|
||||
uint32_t write_count = framegraph->passes[pass_idx].write_count;
|
||||
uint32_t read_count = framegraph->passes[pass_idx].read_count;
|
||||
|
||||
for (uint32_t i = 0; i < write_count; ++i) {
|
||||
rt_render_target *rt = GetRenderTarget(framegraph, writes[i].render_target);
|
||||
RT_ASSERT(rt != NULL, "Invalid render target in pass write.");
|
||||
g_renderer.CmdTransitionRenderTarget(cmdbuf,
|
||||
rt->api_render_target,
|
||||
RT_RENDER_TARGET_STATE_STORAGE_IMAGE);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < read_count; ++i) {
|
||||
rt_render_target *rt = GetRenderTarget(framegraph, reads[i].render_target);
|
||||
RT_ASSERT(rt != NULL, "Invalid render target in pass read.");
|
||||
/* We need to transition the render target */
|
||||
|
||||
switch (reads[i].mode) {
|
||||
case RT_RENDER_TARGET_READ_SAMPLED:
|
||||
g_renderer.CmdTransitionRenderTarget(cmdbuf,
|
||||
rt->api_render_target,
|
||||
RT_RENDER_TARGET_STATE_SAMPLED_IMAGE);
|
||||
break;
|
||||
case RT_RENDER_TARGET_READ_DIRECT:
|
||||
g_renderer.CmdTransitionRenderTarget(cmdbuf,
|
||||
rt->api_render_target,
|
||||
RT_RENDER_TARGET_STATE_STORAGE_IMAGE);
|
||||
break;
|
||||
default:
|
||||
RT_ASSERT(0, "Invalid render target read mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
|
||||
int execution_level = framegraph->passes[0].execution_level;
|
||||
uint32_t level_start = 0;
|
||||
@ -519,18 +594,23 @@ RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
|
||||
framegraph->passes[pass_idx].id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
rt_render_pass_id id = framegraph->passes[pass_idx].id;
|
||||
const rt_render_target_write *writes = framegraph->passes[pass_idx].writes;
|
||||
const rt_render_target_read *reads = framegraph->passes[pass_idx].reads;
|
||||
uint32_t write_count = framegraph->passes[pass_idx].write_count;
|
||||
uint32_t read_count = framegraph->passes[pass_idx].read_count;
|
||||
*/
|
||||
|
||||
/* TODO(Kevin): Every one of these should be a job-dispatch*/
|
||||
|
||||
rt_alloc_command_buffer_info cmdbuf_alloc = {
|
||||
.target_queue = RT_GRAPHICS_QUEUE,
|
||||
};
|
||||
bool is_graphics_pass =
|
||||
framegraph->passes[pass_idx].type == RT_RENDER_PASS_TYPE_GRAPHICS;
|
||||
rt_command_buffer_handle cmdbuf;
|
||||
rt_alloc_command_buffer_info cmdbuf_alloc = {
|
||||
.target_queue = is_graphics_pass ? RT_GRAPHICS_QUEUE : RT_COMPUTE_QUEUE,
|
||||
};
|
||||
if (g_renderer.AllocCommandBuffers(1, &cmdbuf_alloc, &cmdbuf) != RT_SUCCESS) {
|
||||
rtLog("GFX",
|
||||
"Failed to allocate a command buffer for framegraph pass %u (%x)",
|
||||
@ -539,8 +619,13 @@ RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BeginPass(framegraph, pass_idx, cmdbuf);
|
||||
if (is_graphics_pass) {
|
||||
BeginGraphicsPass(framegraph, pass_idx, cmdbuf);
|
||||
} else {
|
||||
BeginComputePass(framegraph, pass_idx, cmdbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
framegraph->passes[pass_idx].bound_fns.Prepare(id,
|
||||
writes,
|
||||
write_count,
|
||||
@ -556,12 +641,14 @@ RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
|
||||
write_count,
|
||||
reads,
|
||||
read_count);
|
||||
|
||||
*/
|
||||
if (is_graphics_pass) {
|
||||
g_renderer.CmdEndPass(cmdbuf);
|
||||
}
|
||||
|
||||
rt_submit_command_buffers_info submit = {.command_buffer_count = 1,
|
||||
.command_buffers = &cmdbuf};
|
||||
g_renderer.SubmitCommandBuffers(RT_GRAPHICS_QUEUE, &submit);
|
||||
g_renderer.SubmitCommandBuffers(is_graphics_pass ? RT_GRAPHICS_QUEUE : RT_COMPUTE_QUEUE, &submit);
|
||||
}
|
||||
|
||||
/* Start next level */
|
||||
|
@ -43,6 +43,8 @@ extern rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t,
|
||||
rt_gpu_semaphore_handle *);
|
||||
extern void RT_RENDERER_API_FN(DestroySemaphores)(uint32_t count, rt_gpu_semaphore_handle *);
|
||||
extern uint64_t RT_RENDERER_API_FN(GetSemaphoreValue)(rt_gpu_semaphore_handle);
|
||||
extern rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetSwapchainAvailableSemaphore)(void);
|
||||
extern rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetRenderFinishedSemaphore)(void);
|
||||
extern void RT_RENDERER_API_FN(CmdBeginPass)(rt_command_buffer_handle,
|
||||
const rt_cmd_begin_pass_info *);
|
||||
extern void RT_RENDERER_API_FN(CmdEndPass)(rt_command_buffer_handle);
|
||||
@ -87,6 +89,8 @@ static bool LoadRenderer(void) {
|
||||
RETRIEVE_SYMBOL(CreateSemaphores, rt_create_gpu_semaphores_fn);
|
||||
RETRIEVE_SYMBOL(DestroySemaphores, rt_destroy_gpu_semaphores_fn);
|
||||
RETRIEVE_SYMBOL(GetSemaphoreValue, rt_get_gpu_semaphore_value_fn);
|
||||
RETRIEVE_SYMBOL(GetSwapchainAvailableSemaphore, rt_get_swapchain_available_semaphore_fn);
|
||||
RETRIEVE_SYMBOL(GetRenderFinishedSemaphore, rt_get_render_finished_semaphore_fn);
|
||||
RETRIEVE_SYMBOL(CmdBeginPass, rt_cmd_begin_pass_fn);
|
||||
RETRIEVE_SYMBOL(CmdEndPass, rt_cmd_end_pass_fn);
|
||||
RETRIEVE_SYMBOL(CmdTransitionRenderTarget, rt_cmd_transition_render_target_fn);
|
||||
@ -114,6 +118,8 @@ static bool LoadRenderer(void) {
|
||||
g_renderer.CreateSemaphores = &rtRenCreateSemaphores;
|
||||
g_renderer.DestroySemaphores = &rtRenDestroySemaphores;
|
||||
g_renderer.GetSemaphoreValue = &rtRenGetSemaphoreValue;
|
||||
g_renderer.GetSwapchainAvailableSemaphore = &rtRenGetSwapchainAvailableSemaphore;
|
||||
g_renderer.GetRenderFinishedSemaphore = &rtRenGetRenderFinishedSemaphore;
|
||||
g_renderer.CmdBeginPass = &rtRenCmdBeginPass;
|
||||
g_renderer.CmdEndPass = &rtRenCmdEndPass;
|
||||
g_renderer.CmdTransitionRenderTarget = &rtRenCmdTransitionRenderTarget;
|
||||
|
@ -203,6 +203,8 @@ typedef rt_result rt_create_gpu_semaphores_fn(uint32_t count,
|
||||
rt_gpu_semaphore_handle *p_semaphores);
|
||||
typedef void rt_destroy_gpu_semaphores_fn(uint32_t count, rt_gpu_semaphore_handle *semaphores);
|
||||
typedef uint64_t rt_get_gpu_semaphore_value_fn(rt_gpu_semaphore_handle semaphore);
|
||||
typedef rt_gpu_semaphore_handle rt_get_swapchain_available_semaphore_fn(void);
|
||||
typedef rt_gpu_semaphore_handle rt_get_render_finished_semaphore_fn(void);
|
||||
|
||||
typedef void rt_cmd_begin_pass_fn(rt_command_buffer_handle cmdbuf,
|
||||
const rt_cmd_begin_pass_info *info);
|
||||
@ -227,6 +229,8 @@ typedef struct {
|
||||
rt_create_gpu_semaphores_fn *CreateSemaphores;
|
||||
rt_destroy_gpu_semaphores_fn *DestroySemaphores;
|
||||
rt_get_gpu_semaphore_value_fn *GetSemaphoreValue;
|
||||
rt_get_swapchain_available_semaphore_fn *GetSwapchainAvailableSemaphore;
|
||||
rt_get_render_finished_semaphore_fn *GetRenderFinishedSemaphore;
|
||||
|
||||
/* Command Buffer Functions */
|
||||
rt_cmd_begin_pass_fn *CmdBeginPass;
|
||||
|
@ -334,9 +334,10 @@ out:
|
||||
}
|
||||
|
||||
VkCommandBuffer rtGetCommandBuffer(rt_command_buffer_handle cmdbuf) {
|
||||
if (!RT_IS_HANDLE_VALID(cmdbuf) || cmdbuf.index >= (uint32_t)rt_VkCommandBufferRingBufferSize.i)
|
||||
uint32_t mod = (uint32_t)rt_VkCommandBufferRingBufferSize.i;
|
||||
if (!RT_IS_HANDLE_VALID(cmdbuf))
|
||||
return VK_NULL_HANDLE;
|
||||
uint32_t slot = cmdbuf.index - 1;
|
||||
uint32_t slot = (cmdbuf.index - 1) % mod;
|
||||
if (_command_buffers[slot].version != cmdbuf.version) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
@ -164,6 +164,9 @@ void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_handle cmdb
|
||||
rt_render_target_state new_state) {
|
||||
GET_CMDBUF(cmdbuf, cmdbuf_handle)
|
||||
uint32_t image_index = g_gpu.current_frame_id % g_gpu.max_frames_in_flight;
|
||||
if (render_target.index == g_renderer.GetSwapchainRenderTarget().index) {
|
||||
image_index = rtGetFrameData(g_gpu.current_frame_id)->swapchain_image_index;
|
||||
}
|
||||
|
||||
rt_render_target *rt = rtGetRenderTarget(render_target);
|
||||
if (!rt) {
|
||||
@ -213,7 +216,7 @@ void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_handle cmdb
|
||||
VkDebugUtilsLabelEXT debug_label = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||
.pLabelName = "Transition Render Target",
|
||||
.color = {0.f, 0.f, 0.f, 0.f},
|
||||
.color = {.13f, .54f, .13f, .75f},
|
||||
};
|
||||
vkCmdBeginDebugUtilsLabelEXT(cmdbuf, &debug_label);
|
||||
#endif
|
||||
|
@ -41,6 +41,11 @@ void RT_RENDERER_API_FN(BeginFrame)(unsigned int frame_id) {
|
||||
} else if (acquire_res != VK_SUCCESS) {
|
||||
rtReportError("vk", "vkAcquireNextImageKHR failed: %u", acquire_res);
|
||||
}
|
||||
|
||||
/* Update the swapchain render target */
|
||||
rt_render_target_handle swap_rt_handle = g_renderer.GetSwapchainRenderTarget();
|
||||
rt_render_target *swap_rt = rtGetRenderTarget(swap_rt_handle);
|
||||
swap_rt->states[frame->swapchain_image_index] = RT_RENDER_TARGET_STATE_INVALID;
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) {
|
||||
@ -64,13 +69,12 @@ void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) {
|
||||
#ifdef RT_DEBUG
|
||||
VkDebugUtilsLabelEXT debug_label = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||
.color = {0.f, 0.f, 0.f, 0.f},
|
||||
.color = {.13f, .54f, .13f, 1.f},
|
||||
.pLabelName = "Transition Swapchain"
|
||||
};
|
||||
vkCmdBeginDebugUtilsLabelEXT(cmd, &debug_label);
|
||||
#endif
|
||||
|
||||
|
||||
VkImageMemoryBarrier2 image_barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||
@ -115,12 +119,6 @@ void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update the swapchain render target */
|
||||
rt_render_target_handle swap_rt_handle = g_renderer.GetSwapchainRenderTarget();
|
||||
rt_render_target *swap_rt = rtGetRenderTarget(swap_rt_handle);
|
||||
swap_rt->states[image_index] = RT_RENDER_TARGET_STATE_INVALID;
|
||||
|
||||
|
||||
VkPresentInfoKHR present_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pImageIndices = &image_index,
|
||||
|
@ -96,4 +96,6 @@ VkSampleCountFlagBits rtSampleCountToFlags(unsigned int count);
|
||||
|
||||
VkQueue rtGetQueue(rt_gpu_queue queue);
|
||||
|
||||
const char *rtVkFormatToString(VkFormat format);
|
||||
|
||||
#endif
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "gpu.h"
|
||||
|
||||
#include "runtime/config.h"
|
||||
#include "runtime/threading.h"
|
||||
#include "runtime/handles.h"
|
||||
#include "runtime/threading.h"
|
||||
|
||||
#include "gfx/renderer_api.h"
|
||||
|
||||
@ -10,11 +10,15 @@
|
||||
|
||||
RT_CVAR_I(rt_VkMaxSemaphores, "Maximum number of semaphores. Default: 1024", 1024);
|
||||
|
||||
#define SWAPCHAIN_AVAILABLE_SEMAPHORE_INDEX 0xffffff
|
||||
#define RENDER_FINISHED_SEMAPHORE_INDEX 0xfffffe
|
||||
|
||||
typedef struct rt_gpu_semaphore_s {
|
||||
uint32_t version;
|
||||
VkSemaphore semaphore;
|
||||
uint64_t current_value;
|
||||
/* TODO: State tracking. We want to ensure that we don't introduce gpu hangs by waiting on a not-signaled semaphore. */
|
||||
/* TODO: State tracking. We want to ensure that we don't introduce gpu hangs by waiting on a
|
||||
* not-signaled semaphore. */
|
||||
|
||||
struct rt_gpu_semaphore_s *next_free;
|
||||
} rt_gpu_semaphore;
|
||||
@ -58,7 +62,9 @@ void ShutdownSemaphoreManagement(void) {
|
||||
}
|
||||
}
|
||||
|
||||
rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count, const rt_gpu_semaphore_info *info, rt_gpu_semaphore_handle *p_semaphores) {
|
||||
rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count,
|
||||
const rt_gpu_semaphore_info *info,
|
||||
rt_gpu_semaphore_handle *p_semaphores) {
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
rtLockMutex(_lock);
|
||||
rt_gpu_semaphore *sem = _first_free;
|
||||
@ -120,6 +126,15 @@ void RT_RENDERER_API_FN(DestroySemaphores)(uint32_t count, rt_gpu_semaphore_hand
|
||||
|
||||
VkSemaphore rtGetSemaphore(rt_gpu_semaphore_handle handle) {
|
||||
uint32_t index = handle.index;
|
||||
|
||||
if (index == SWAPCHAIN_AVAILABLE_SEMAPHORE_INDEX) {
|
||||
rt_frame_data *fd = rtGetFrameData(g_gpu.current_frame_id);
|
||||
return fd->image_available;
|
||||
} else if (index == RENDER_FINISHED_SEMAPHORE_INDEX) {
|
||||
rt_frame_data *fd = rtGetFrameData(g_gpu.current_frame_id);
|
||||
return fd->render_finished;
|
||||
}
|
||||
|
||||
if (!RT_IS_HANDLE_VALID(handle) || index >= (uint32_t)rt_VkMaxSemaphores.i)
|
||||
return VK_NULL_HANDLE;
|
||||
if (_semaphores[index].version != handle.version)
|
||||
@ -138,3 +153,17 @@ uint64_t RT_RENDERER_API_FN(GetSemaphoreValue)(rt_gpu_semaphore_handle semaphore
|
||||
&_semaphores[index].current_value);
|
||||
return _semaphores[index].current_value;
|
||||
}
|
||||
|
||||
rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetSwapchainAvailableSemaphore)(void) {
|
||||
return (rt_gpu_semaphore_handle){
|
||||
.version = 1,
|
||||
.index = SWAPCHAIN_AVAILABLE_SEMAPHORE_INDEX,
|
||||
};
|
||||
}
|
||||
|
||||
rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetRenderFinishedSemaphore)(void) {
|
||||
return (rt_gpu_semaphore_handle){
|
||||
.version = 1,
|
||||
.index = RENDER_FINISHED_SEMAPHORE_INDEX,
|
||||
};
|
||||
}
|
@ -54,3 +54,30 @@ VkQueue rtGetQueue(rt_gpu_queue queue) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
const char *rtVkFormatToString(VkFormat format) {
|
||||
switch (format) {
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
return "R8G8B8A8_UNORM";
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
return "B8G8R8A8_UNORM";
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
return "R8G8B8A8_SRGB";
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
return "B8G8R8A8_SRGB";
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
return "R8G8B8_UNORM";
|
||||
case VK_FORMAT_B8G8R8_UNORM:
|
||||
return "B8G8R8_UNORM";
|
||||
case VK_FORMAT_R8G8B8_SRGB:
|
||||
return "R8G8B8_SRGB";
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
return "B8G8R8_SRGB";
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
return "D24_UNORM_S8_UINT";
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
return "D32_SFLOAT";
|
||||
default:
|
||||
return "UNDEFINED";
|
||||
}
|
||||
}
|
@ -58,26 +58,33 @@ static bool CreateImageAndView(VkExtent2D extent,
|
||||
};
|
||||
vkGetPhysicalDeviceFormatProperties2(g_gpu.phys_device, format, &props);
|
||||
if ((props.formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0) {
|
||||
rtLog("vk", "Requested render target format can not be sampled.");
|
||||
rtLog("vk",
|
||||
"Requested render target format %s can not be sampled.",
|
||||
rtVkFormatToString(format));
|
||||
usage &= ~VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
}
|
||||
if ((props.formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) {
|
||||
rtLog("vk", "Requested render target format can not be used for storage.");
|
||||
rtLog("vk",
|
||||
"Requested render target format %s can not be used for storage.",
|
||||
rtVkFormatToString(format));
|
||||
usage &= ~VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
}
|
||||
if (((usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0) &&
|
||||
((props.formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ==
|
||||
0)) {
|
||||
rtReportError("vk",
|
||||
"Tried to create a render target color attachment, but the format does not "
|
||||
"support the color attachment usage.");
|
||||
rtReportError(
|
||||
"vk",
|
||||
"Tried to create a render target color attachment, but the format %s does not "
|
||||
"support the color attachment usage.",
|
||||
rtVkFormatToString(format));
|
||||
return false;
|
||||
} else if (((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) &&
|
||||
((props.formatProperties.optimalTilingFeatures &
|
||||
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)) {
|
||||
rtReportError("vk",
|
||||
"Tried to create a render target depth/stencil attachment, but the format "
|
||||
"does not support the depth/stencil attachment usage.");
|
||||
"Tried to create a render target depth/stencil attachment, but the format %s"
|
||||
"does not support the depth/stencil attachment usage.",
|
||||
rtVkFormatToString(format));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user