Differentiate between graphics and compile passes

This commit is contained in:
Kevin Trogant 2024-02-27 10:00:00 +01:00
parent bc6076b786
commit ee24cd4903
17 changed files with 292 additions and 77 deletions

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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) {

View 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

View File

@ -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");

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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,

View File

@ -96,4 +96,6 @@ VkSampleCountFlagBits rtSampleCountToFlags(unsigned int count);
VkQueue rtGetQueue(rt_gpu_queue queue);
const char *rtVkFormatToString(VkFormat format);
#endif

View File

@ -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,
};
}

View File

@ -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";
}
}

View File

@ -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;
}