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,14 +42,13 @@ 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);
 | 
			
		||||
 | 
			
		||||
    size_t size      = rtGetResourceSize(resid);
 | 
			
		||||
    rt_resource *res = rtArenaPush(temp.arena, size);
 | 
			
		||||
    rt_resource_id resid = rtGetResourceID("assets/test.framegraph");
 | 
			
		||||
    size_t size          = rtGetResourceSize(resid);
 | 
			
		||||
    rt_resource *res     = rtArenaPush(temp.arena, size);
 | 
			
		||||
    rtGetResource(resid, res);
 | 
			
		||||
 | 
			
		||||
    _framegraph = rtCreateFramegraph(res->data);
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
                g_renderer.CmdEndPass(cmdbuf);
 | 
			
		||||
                */
 | 
			
		||||
                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);
 | 
			
		||||
@ -99,24 +103,26 @@ static bool LoadRenderer(void) {
 | 
			
		||||
    }
 | 
			
		||||
#undef RETRIEVE_SYMBOL
 | 
			
		||||
#else
 | 
			
		||||
    g_renderer.RegisterCVars             = &rtRenRegisterCVars;
 | 
			
		||||
    g_renderer.Init                      = &rtRenInit;
 | 
			
		||||
    g_renderer.Shutdown                  = &rtRenShutdown;
 | 
			
		||||
    g_renderer.BeginFrame                = &rtRenBeginFrame;
 | 
			
		||||
    g_renderer.EndFrame                  = &rtRenEndFrame;
 | 
			
		||||
    g_renderer.CompilePipeline           = &rtRenCompilePipeline;
 | 
			
		||||
    g_renderer.DestroyPipeline           = &rtRenDestroyPipeline;
 | 
			
		||||
    g_renderer.CreateRenderTarget        = &rtRenCreateRenderTarget;
 | 
			
		||||
    g_renderer.GetSwapchainRenderTarget  = &rtRenGetSwapchainRenderTarget;
 | 
			
		||||
    g_renderer.DestroyRenderTarget       = &rtRenDestroyRenderTarget;
 | 
			
		||||
    g_renderer.AllocCommandBuffers       = &rtRenAllocCommandBuffers;
 | 
			
		||||
    g_renderer.SubmitCommandBuffers      = &rtRenSubmitCommandBuffers;
 | 
			
		||||
    g_renderer.CreateSemaphores          = &rtRenCreateSemaphores;
 | 
			
		||||
    g_renderer.DestroySemaphores         = &rtRenDestroySemaphores;
 | 
			
		||||
    g_renderer.GetSemaphoreValue         = &rtRenGetSemaphoreValue;
 | 
			
		||||
    g_renderer.CmdBeginPass              = &rtRenCmdBeginPass;
 | 
			
		||||
    g_renderer.CmdEndPass                = &rtRenCmdEndPass;
 | 
			
		||||
    g_renderer.CmdTransitionRenderTarget = &rtRenCmdTransitionRenderTarget;
 | 
			
		||||
    g_renderer.RegisterCVars                  = &rtRenRegisterCVars;
 | 
			
		||||
    g_renderer.Init                           = &rtRenInit;
 | 
			
		||||
    g_renderer.Shutdown                       = &rtRenShutdown;
 | 
			
		||||
    g_renderer.BeginFrame                     = &rtRenBeginFrame;
 | 
			
		||||
    g_renderer.EndFrame                       = &rtRenEndFrame;
 | 
			
		||||
    g_renderer.CompilePipeline                = &rtRenCompilePipeline;
 | 
			
		||||
    g_renderer.DestroyPipeline                = &rtRenDestroyPipeline;
 | 
			
		||||
    g_renderer.CreateRenderTarget             = &rtRenCreateRenderTarget;
 | 
			
		||||
    g_renderer.GetSwapchainRenderTarget       = &rtRenGetSwapchainRenderTarget;
 | 
			
		||||
    g_renderer.DestroyRenderTarget            = &rtRenDestroyRenderTarget;
 | 
			
		||||
    g_renderer.AllocCommandBuffers            = &rtRenAllocCommandBuffers;
 | 
			
		||||
    g_renderer.SubmitCommandBuffers           = &rtRenSubmitCommandBuffers;
 | 
			
		||||
    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;
 | 
			
		||||
#endif
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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