Seems like a valid chain of image transitions.
Now we need to draw something and also have the correct semaphore waits to establish dependencies.
This commit is contained in:
		
							parent
							
								
									1e49b14879
								
							
						
					
					
						commit
						bc6076b786
					
				@ -15,8 +15,8 @@ render_targets {
 | 
			
		||||
 | 
			
		||||
    depth0 {
 | 
			
		||||
        format DEPTH24_STENCIL8;
 | 
			
		||||
        width 512;
 | 
			
		||||
        height 384;
 | 
			
		||||
        width 1024;
 | 
			
		||||
        height 768;
 | 
			
		||||
        sample_count 4;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -75,12 +75,12 @@ subdir('src')
 | 
			
		||||
engine_link_libs = []
 | 
			
		||||
if get_option('default_library') == 'static'
 | 
			
		||||
  if get_option('static_renderer') == 'vk'
 | 
			
		||||
    engine_link_libs = [runtime_lib, vk_renderer_lib]
 | 
			
		||||
    engine_link_libs = [runtime_lib, gfx_lib, app_lib, vk_renderer_lib]
 | 
			
		||||
  else
 | 
			
		||||
    error('Invalid static_renderer option ', get_option('static_renderer'))
 | 
			
		||||
  endif
 | 
			
		||||
else
 | 
			
		||||
  engine_link_libs = [runtime_lib]
 | 
			
		||||
  engine_link_libs = [runtime_lib, gfx_lib, app_lib]
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Unit/Integration test driver
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,13 @@
 | 
			
		||||
#include "app.h"
 | 
			
		||||
#include "aio.h"
 | 
			
		||||
#include "buffer_manager.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "renderer_api.h"
 | 
			
		||||
#include "main_loop.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/aio.h"
 | 
			
		||||
#include "runtime/buffer_manager.h"
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/gfx.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
RT_CVAR_I(rt_Fullscreen, "Show window in fullscreen mode. [0/1] Default: 0", 0);
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
/* Platform specific application entry point */
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
#include "main_loop.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
#define RT_DONT_DEFINE_MAIN_LOOP_GLOBAL
 | 
			
		||||
#include "main_loop.h"
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/gfx.h"
 | 
			
		||||
 | 
			
		||||
RT_CVAR_I(rt_MaxFrameLatency, "Maximum latency between update and rendering. Default: 2", 2);
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
#ifndef RT_MAIN_LOOP_H
 | 
			
		||||
#define RT_MAIN_LOOP_H
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
#include "threading.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
 | 
			
		||||
typedef void rt_main_loop_update_fn(void);
 | 
			
		||||
typedef void rt_main_loop_render_fn(void);
 | 
			
		||||
							
								
								
									
										16
									
								
								src/app_framework/meson.build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/app_framework/meson.build
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
app_deps = [thread_dep, m_dep, windowing_dep]
 | 
			
		||||
app_lib = library('rtapp',
 | 
			
		||||
  # Project Sources
 | 
			
		||||
  'app.h',
 | 
			
		||||
  'main_loop.h',
 | 
			
		||||
  
 | 
			
		||||
  'app.c',
 | 
			
		||||
  'main_loop.c',
 | 
			
		||||
  dependencies : app_deps,
 | 
			
		||||
  include_directories : engine_incdir,
 | 
			
		||||
  link_with : [runtime_lib, gfx_lib],
 | 
			
		||||
  c_pch : 'pch/app_pch.h',
 | 
			
		||||
  install : true)
 | 
			
		||||
 | 
			
		||||
engine_libs += app_lib
 | 
			
		||||
engine_lib_paths += app_lib.full_path()
 | 
			
		||||
							
								
								
									
										1
									
								
								src/app_framework/pch/app_pch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/app_framework/pch/app_pch.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
#include "description_parser.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/buffer_manager.h"
 | 
			
		||||
#include "runtime/gfx.h"
 | 
			
		||||
#include "gfx/gfx.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
@ -559,11 +559,11 @@ static rt_result ParseFramegraph(const char *text,
 | 
			
		||||
                    }
 | 
			
		||||
                    if (rtCompareSpanToString(mode_stmt->value, "SAMPLED") == 0) {
 | 
			
		||||
                        read->mode = RT_RENDER_TARGET_READ_SAMPLED;
 | 
			
		||||
                    } else if (rtCompareSpanToString(mode_stmt->value, "INPUT_ATTACHMENT") == 0) {
 | 
			
		||||
                        read->mode = RT_RENDER_TARGET_READ_INPUT_ATTACHMENT;
 | 
			
		||||
                    } else if (rtCompareSpanToString(mode_stmt->value, "DIRECT") == 0) {
 | 
			
		||||
                        read->mode = RT_RENDER_TARGET_READ_DIRECT;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        rtLog("AC",
 | 
			
		||||
                              "Expected SAMPLED or INPUT_ATTACHMENT as the value of "
 | 
			
		||||
                              "Expected SAMPLED or DIRECT as the value of "
 | 
			
		||||
                              "\"passes.%.*s.writes.%.*s.mode\" in %s",
 | 
			
		||||
                              pass_stmt->attribute.length,
 | 
			
		||||
                              pass_stmt->attribute.start,
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,11 @@
 | 
			
		||||
 | 
			
		||||
#include "runtime/buffer_manager.h"
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/gfx.h"
 | 
			
		||||
#include "runtime/mem_arena.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/gfx.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
#include "runtime/mem_arena.h"
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
#include "runtime/app.h"
 | 
			
		||||
#include "app_framework/app.h"
 | 
			
		||||
 | 
			
		||||
extern void RegisterCVars(void);
 | 
			
		||||
extern void Init(void);
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,10 @@
 | 
			
		||||
#include "runtime/gfx.h"
 | 
			
		||||
#include "runtime/mem_arena.h"
 | 
			
		||||
#include "runtime/resources.h"
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/gfx.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#include "asset_compiler/asset_compiler.h"
 | 
			
		||||
 | 
			
		||||
void RegisterCVars(void) {
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
@ -88,7 +88,7 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_RENDER_TARGET_READ_SAMPLED,
 | 
			
		||||
    RT_RENDER_TARGET_READ_INPUT_ATTACHMENT,
 | 
			
		||||
    RT_RENDER_TARGET_READ_DIRECT,
 | 
			
		||||
 | 
			
		||||
    RT_RENDER_TARGET_READ_count,
 | 
			
		||||
} rt_render_target_read_mode;
 | 
			
		||||
@ -1,10 +1,11 @@
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "handles.h"
 | 
			
		||||
#include "hashing.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include "renderer_api.h"
 | 
			
		||||
#include "threading.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/handles.h"
 | 
			
		||||
#include "runtime/hashing.h"
 | 
			
		||||
#include "runtime/mem_arena.h"
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
@ -250,8 +251,16 @@ CreateRenderTargets(rt_framegraph *graph, const rt_framegraph_info *info, rt_are
 | 
			
		||||
        graph->render_targets[i].width        = render_targets[i].width;
 | 
			
		||||
        graph->render_targets[i].height       = render_targets[i].height;
 | 
			
		||||
        graph->render_targets[i].sample_count = render_targets[i].sample_count;
 | 
			
		||||
        graph->render_targets[i].api_render_target =
 | 
			
		||||
            g_renderer.CreateRenderTarget(&render_targets[i]);
 | 
			
		||||
 | 
			
		||||
        if (graph->render_targets[i].width != RT_RENDER_TARGET_SIZE_SWAPCHAIN ||
 | 
			
		||||
            graph->render_targets[i].height != RT_RENDER_TARGET_SIZE_SWAPCHAIN ||
 | 
			
		||||
            graph->render_targets[i].format != RT_PIXEL_FORMAT_SWAPCHAIN) {
 | 
			
		||||
 | 
			
		||||
            graph->render_targets[i].api_render_target =
 | 
			
		||||
                g_renderer.CreateRenderTarget(&render_targets[i]);
 | 
			
		||||
        } else {
 | 
			
		||||
            graph->render_targets[i].api_render_target = g_renderer.GetSwapchainRenderTarget();
 | 
			
		||||
        }
 | 
			
		||||
        if (!RT_IS_HANDLE_VALID(graph->render_targets[i].api_render_target)) {
 | 
			
		||||
            rtReportError("GFX", "Failed to create render target %u of framegraph.", i);
 | 
			
		||||
            for (uint32_t j = 0; j < i; ++j)
 | 
			
		||||
@ -259,6 +268,7 @@ CreateRenderTargets(rt_framegraph *graph, const rt_framegraph_info *info, rt_are
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    graph->render_target_count = info->render_target_count;
 | 
			
		||||
 | 
			
		||||
    result = true;
 | 
			
		||||
out:
 | 
			
		||||
@ -386,6 +396,110 @@ RT_DLLEXPORT void rtBindRenderPass(rt_framegraph *framegraph,
 | 
			
		||||
    rtLog("GFX", "Tried to bind functions to unknown render pass %x", id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool IsDepthFormat(rt_pixel_format format) {
 | 
			
		||||
    return format == RT_PIXEL_FORMAT_DEPTH32 || format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static rt_render_target *GetRenderTarget(rt_framegraph *framegraph, rt_render_target_id id) {
 | 
			
		||||
    for (uint32_t i = 0; i < framegraph->render_target_count; ++i) {
 | 
			
		||||
        if (framegraph->render_targets[i].id == id)
 | 
			
		||||
            return &framegraph->render_targets[i];
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
BeginPass(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;
 | 
			
		||||
 | 
			
		||||
    /* Convert reads and writes into the pass begin info for the renderer */
 | 
			
		||||
    rt_cmd_begin_pass_info begin_info;
 | 
			
		||||
    memset(&begin_info, 0, sizeof(begin_info));
 | 
			
		||||
 | 
			
		||||
    /* All written render targets need to have the same size */
 | 
			
		||||
    if (write_count > 0) {
 | 
			
		||||
        rt_render_target *rt = GetRenderTarget(framegraph, writes[0].render_target);
 | 
			
		||||
        RT_ASSERT(rt != NULL, "Invalid render target in pass write.");
 | 
			
		||||
        begin_info.render_area = (rt_rect2i){
 | 
			
		||||
            .offset = {             0,               0},
 | 
			
		||||
            .size   = {.x = rt->width, .y = rt->height}
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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_ATTACHMENT);
 | 
			
		||||
 | 
			
		||||
        if (!IsDepthFormat(rt->format)) {
 | 
			
		||||
            /* Add as color buffer */
 | 
			
		||||
            uint32_t cbidx = begin_info.color_buffer_count;
 | 
			
		||||
            RT_ASSERT(cbidx < 4, "Maximum of 4 colorbuffers per pass exceeded.");
 | 
			
		||||
            begin_info.color_buffers[cbidx] = rt->api_render_target;
 | 
			
		||||
            if ((writes[i].flags & RT_RENDER_TARGET_WRITE_CLEAR) != 0) {
 | 
			
		||||
                begin_info.color_buffer_loads[cbidx]              = RT_PASS_LOAD_MODE_CLEAR;
 | 
			
		||||
                begin_info.color_buffer_clear_values[cbidx].color = writes[i].clear.color;
 | 
			
		||||
            } else {
 | 
			
		||||
                begin_info.color_buffer_loads[cbidx] = RT_PASS_LOAD_MODE_LOAD;
 | 
			
		||||
            }
 | 
			
		||||
            if ((writes[i].flags & RT_RENDER_TARGET_WRITE_DISCARD) != 0) {
 | 
			
		||||
                begin_info.color_buffer_writes[cbidx] = RT_PASS_WRITE_MODE_DISCARD;
 | 
			
		||||
            } else {
 | 
			
		||||
                begin_info.color_buffer_writes[cbidx] = RT_PASS_WRITE_MODE_STORE;
 | 
			
		||||
            }
 | 
			
		||||
            ++begin_info.color_buffer_count;
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Add as depth buffer*/
 | 
			
		||||
            RT_ASSERT(!RT_IS_HANDLE_VALID(begin_info.depth_stencil_buffer),
 | 
			
		||||
                      "Only one depth/stencil buffer can be set!");
 | 
			
		||||
            begin_info.depth_stencil_buffer = rt->api_render_target;
 | 
			
		||||
            if ((writes[i].flags & RT_RENDER_TARGET_WRITE_CLEAR) != 0) {
 | 
			
		||||
                begin_info.depth_stencil_buffer_load = RT_PASS_LOAD_MODE_CLEAR;
 | 
			
		||||
                begin_info.depth_stencil_buffer_clear_value.depth_stencil.depth =
 | 
			
		||||
                    writes[i].clear.depth_stencil.depth;
 | 
			
		||||
                begin_info.depth_stencil_buffer_clear_value.depth_stencil.stencil =
 | 
			
		||||
                    writes[i].clear.depth_stencil.stencil;
 | 
			
		||||
            } else {
 | 
			
		||||
                begin_info.depth_stencil_buffer_load = RT_PASS_LOAD_MODE_LOAD;
 | 
			
		||||
            }
 | 
			
		||||
            if ((writes[i].flags & RT_RENDER_TARGET_WRITE_DISCARD) != 0) {
 | 
			
		||||
                begin_info.depth_stencil_buffer_write = RT_PASS_WRITE_MODE_DISCARD;
 | 
			
		||||
            } else {
 | 
			
		||||
                begin_info.depth_stencil_buffer_write = RT_PASS_WRITE_MODE_STORE;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_renderer.CmdBeginPass(cmdbuf, &begin_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
 | 
			
		||||
    int execution_level  = framegraph->passes[0].execution_level;
 | 
			
		||||
    uint32_t level_start = 0;
 | 
			
		||||
@ -413,6 +527,20 @@ RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
 | 
			
		||||
 | 
			
		||||
                /* TODO(Kevin): Every one of these should be a job-dispatch*/
 | 
			
		||||
 | 
			
		||||
                rt_alloc_command_buffer_info cmdbuf_alloc = {
 | 
			
		||||
                    .target_queue = RT_GRAPHICS_QUEUE,
 | 
			
		||||
                };
 | 
			
		||||
                rt_command_buffer_handle cmdbuf;
 | 
			
		||||
                if (g_renderer.AllocCommandBuffers(1, &cmdbuf_alloc, &cmdbuf) != RT_SUCCESS) {
 | 
			
		||||
                    rtLog("GFX",
 | 
			
		||||
                          "Failed to allocate a command buffer for framegraph pass %u (%x)",
 | 
			
		||||
                          pass_idx,
 | 
			
		||||
                          framegraph->passes[pass_idx].id);
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                BeginPass(framegraph, pass_idx, cmdbuf);
 | 
			
		||||
 | 
			
		||||
                framegraph->passes[pass_idx].bound_fns.Prepare(id,
 | 
			
		||||
                                                               writes,
 | 
			
		||||
                                                               write_count,
 | 
			
		||||
@ -428,6 +556,12 @@ RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
 | 
			
		||||
                                                                write_count,
 | 
			
		||||
                                                                reads,
 | 
			
		||||
                                                                read_count);
 | 
			
		||||
 | 
			
		||||
                g_renderer.CmdEndPass(cmdbuf);
 | 
			
		||||
 | 
			
		||||
                rt_submit_command_buffers_info submit = {.command_buffer_count = 1,
 | 
			
		||||
                                                         .command_buffers      = &cmdbuf};
 | 
			
		||||
                g_renderer.SubmitCommandBuffers(RT_GRAPHICS_QUEUE, &submit);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Start next level */
 | 
			
		||||
@ -2,12 +2,12 @@
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define RT_DONT_DEFINE_RENDERER_GLOBAL
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "dynamic_libs.h"
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/dynamic_libs.h"
 | 
			
		||||
 | 
			
		||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
			
		||||
 * For example, an attribute might be bound to "CELL_GRID", which would be
 | 
			
		||||
 * replaced with the (at the time of the invoke) grid buffer of the current
 | 
			
		||||
@ -31,6 +31,7 @@ extern rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_
 | 
			
		||||
extern void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle);
 | 
			
		||||
extern rt_render_target_handle
 | 
			
		||||
    RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_target_info *);
 | 
			
		||||
extern rt_render_target_handle RT_RENDERER_API_FN(GetSwapchainRenderTarget)(void);
 | 
			
		||||
extern void RT_RENDERER_API_FN(DestroyRenderTarget)(rt_render_target_handle);
 | 
			
		||||
extern rt_result RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t,
 | 
			
		||||
                                                         const rt_alloc_command_buffer_info *,
 | 
			
		||||
@ -42,6 +43,12 @@ 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 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);
 | 
			
		||||
extern void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_handle,
 | 
			
		||||
                                                          rt_render_target_handle,
 | 
			
		||||
                                                          rt_render_target_state);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern rt_result InitFramegraphManager(void);
 | 
			
		||||
@ -73,12 +80,16 @@ static bool LoadRenderer(void) {
 | 
			
		||||
        RETRIEVE_SYMBOL(CompilePipeline, rt_compile_pipeline_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(DestroyPipeline, rt_destroy_pipeline_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(CreateRenderTarget, rt_create_render_target_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(GetSwapchainRenderTarget, rt_get_swapchain_render_target_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(DestroyRenderTarget, rt_destroy_render_target_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(AllocCommandBuffers, rt_alloc_command_buffers_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(SubmitCommandBuffers, rt_submit_command_buffers_fn);
 | 
			
		||||
        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(CmdBeginPass, rt_cmd_begin_pass_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(CmdEndPass, rt_cmd_end_pass_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(CmdTransitionRenderTarget, rt_cmd_transition_render_target_fn);
 | 
			
		||||
    } else {
 | 
			
		||||
        rtReportError("GFX",
 | 
			
		||||
                      "Unsupported renderer backend: (%s) %s",
 | 
			
		||||
@ -88,20 +99,24 @@ 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.DestroyRenderTarget  = &rtRenDestroyRenderTarget;
 | 
			
		||||
    g_renderer.AllocCommandBuffers  = &rtRenAllocCommandBuffers;
 | 
			
		||||
    g_renderer.SubmitCommandBuffers = &rtRenSubmitCommandBuffers;
 | 
			
		||||
    g_renderer.CreateSemaphores     = &rtRenCreateSemaphores;
 | 
			
		||||
    g_renderer.DestroySemaphores    = &rtRenDestroySemaphores;
 | 
			
		||||
    g_renderer.GetSemaphoreValue    = &rtRenGetSemaphoreValue;
 | 
			
		||||
    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;
 | 
			
		||||
#endif
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								src/gfx/meson.build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/gfx/meson.build
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
gfx_deps = [thread_dep, m_dep]
 | 
			
		||||
gfx_lib = library('rtgfx',
 | 
			
		||||
  # Project Sources
 | 
			
		||||
  'gfx.h',
 | 
			
		||||
  'renderer_api.h',
 | 
			
		||||
  'render_list.h',
 | 
			
		||||
  
 | 
			
		||||
  'gfx_framegraph.c',
 | 
			
		||||
  'gfx_main.c',
 | 
			
		||||
  # Contrib Sources
 | 
			
		||||
  dependencies : gfx_deps,
 | 
			
		||||
  include_directories : engine_incdir,
 | 
			
		||||
  link_with : runtime_lib,
 | 
			
		||||
  c_pch : 'pch/gfx_pch.h',
 | 
			
		||||
  install : true)
 | 
			
		||||
 | 
			
		||||
engine_libs += gfx_lib
 | 
			
		||||
engine_lib_paths += gfx_lib.full_path()
 | 
			
		||||
							
								
								
									
										4
									
								
								src/gfx/pch/gfx_pch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/gfx/pch/gfx_pch.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
 | 
			
		||||
/* Commonly used runtime headers */
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
@ -6,8 +6,10 @@
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "resources.h"
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/resources.h"
 | 
			
		||||
#include "runtime/rt_math.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
@ -134,6 +136,51 @@ typedef struct {
 | 
			
		||||
    uint64_t initial_value;
 | 
			
		||||
} rt_gpu_semaphore_info;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_PASS_LOAD_MODE_LOAD,
 | 
			
		||||
    RT_PASS_LOAD_MODE_CLEAR,
 | 
			
		||||
} rt_pass_load_mode;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_PASS_WRITE_MODE_STORE,
 | 
			
		||||
    RT_PASS_WRITE_MODE_DISCARD,
 | 
			
		||||
} rt_pass_write_mode;
 | 
			
		||||
 | 
			
		||||
typedef union {
 | 
			
		||||
    rt_color color;
 | 
			
		||||
    struct {
 | 
			
		||||
        float depth;
 | 
			
		||||
        int32_t stencil;
 | 
			
		||||
    } depth_stencil;
 | 
			
		||||
} rt_pass_clear_value;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rt_render_target_handle color_buffers[4];
 | 
			
		||||
    rt_pass_load_mode color_buffer_loads[4];
 | 
			
		||||
    rt_pass_write_mode color_buffer_writes[4];
 | 
			
		||||
    rt_pass_clear_value color_buffer_clear_values[4];
 | 
			
		||||
    uint32_t color_buffer_count;
 | 
			
		||||
 | 
			
		||||
    rt_render_target_handle depth_stencil_buffer;
 | 
			
		||||
    rt_pass_load_mode depth_stencil_buffer_load;
 | 
			
		||||
    rt_pass_write_mode depth_stencil_buffer_write;
 | 
			
		||||
    rt_pass_clear_value depth_stencil_buffer_clear_value;
 | 
			
		||||
 | 
			
		||||
    rt_rect2i render_area;
 | 
			
		||||
} rt_cmd_begin_pass_info;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    /* Unusable, must be transitioned to an usable state first. */
 | 
			
		||||
    RT_RENDER_TARGET_STATE_INVALID,
 | 
			
		||||
 | 
			
		||||
    /* Used as a color- or depth-buffer */
 | 
			
		||||
    RT_RENDER_TARGET_STATE_ATTACHMENT,
 | 
			
		||||
 | 
			
		||||
    RT_RENDER_TARGET_STATE_SAMPLED_IMAGE,
 | 
			
		||||
 | 
			
		||||
    RT_RENDER_TARGET_STATE_STORAGE_IMAGE,
 | 
			
		||||
} rt_render_target_state;
 | 
			
		||||
 | 
			
		||||
/* Renderer API */
 | 
			
		||||
 | 
			
		||||
typedef void rt_register_renderer_cvars_fn(void);
 | 
			
		||||
@ -144,6 +191,7 @@ typedef void rt_end_frame_fn(unsigned int frame_id);
 | 
			
		||||
typedef rt_pipeline_handle rt_compile_pipeline_fn(const rt_pipeline_info *info);
 | 
			
		||||
typedef void rt_destroy_pipeline_fn(rt_pipeline_handle handle);
 | 
			
		||||
typedef rt_render_target_handle rt_create_render_target_fn(const rt_render_target_info *info);
 | 
			
		||||
typedef rt_render_target_handle rt_get_swapchain_render_target_fn(void);
 | 
			
		||||
typedef void rt_destroy_render_target_fn(rt_render_target_handle handle);
 | 
			
		||||
typedef rt_result rt_alloc_command_buffers_fn(uint32_t count,
 | 
			
		||||
                                              const rt_alloc_command_buffer_info *info,
 | 
			
		||||
@ -156,6 +204,13 @@ typedef rt_result rt_create_gpu_semaphores_fn(uint32_t count,
 | 
			
		||||
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 void rt_cmd_begin_pass_fn(rt_command_buffer_handle cmdbuf,
 | 
			
		||||
                                  const rt_cmd_begin_pass_info *info);
 | 
			
		||||
typedef void rt_cmd_end_pass_fn(rt_command_buffer_handle cmdbuf);
 | 
			
		||||
typedef void rt_cmd_transition_render_target_fn(rt_command_buffer_handle cmdbuf,
 | 
			
		||||
                                                rt_render_target_handle render_target,
 | 
			
		||||
                                                rt_render_target_state new_state);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rt_register_renderer_cvars_fn *RegisterCVars;
 | 
			
		||||
    rt_init_renderer_fn *Init;
 | 
			
		||||
@ -165,12 +220,18 @@ typedef struct {
 | 
			
		||||
    rt_compile_pipeline_fn *CompilePipeline;
 | 
			
		||||
    rt_destroy_pipeline_fn *DestroyPipeline;
 | 
			
		||||
    rt_create_render_target_fn *CreateRenderTarget;
 | 
			
		||||
    rt_get_swapchain_render_target_fn *GetSwapchainRenderTarget;
 | 
			
		||||
    rt_destroy_render_target_fn *DestroyRenderTarget;
 | 
			
		||||
    rt_alloc_command_buffers_fn *AllocCommandBuffers;
 | 
			
		||||
    rt_submit_command_buffers_fn *SubmitCommandBuffers;
 | 
			
		||||
    rt_create_gpu_semaphores_fn *CreateSemaphores;
 | 
			
		||||
    rt_destroy_gpu_semaphores_fn *DestroySemaphores;
 | 
			
		||||
    rt_get_gpu_semaphore_value_fn *GetSemaphoreValue;
 | 
			
		||||
 | 
			
		||||
    /* Command Buffer Functions */
 | 
			
		||||
    rt_cmd_begin_pass_fn *CmdBeginPass;
 | 
			
		||||
    rt_cmd_end_pass_fn *CmdEndPass;
 | 
			
		||||
    rt_cmd_transition_render_target_fn *CmdTransitionRenderTarget;
 | 
			
		||||
} rt_renderer_api;
 | 
			
		||||
 | 
			
		||||
#define RT_RENDERER_API_FN(name) RT_DLLEXPORT rtRen##name
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
subdir('runtime')
 | 
			
		||||
subdir('asset_compiler')
 | 
			
		||||
subdir('gfx')
 | 
			
		||||
subdir('app_framework')
 | 
			
		||||
 | 
			
		||||
# Renderer libs
 | 
			
		||||
subdir('renderer/vk')
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,12 @@
 | 
			
		||||
 | 
			
		||||
#include "runtime/atomics.h"
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/handles.h"
 | 
			
		||||
#include "runtime/mem_arena.h"
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
RT_CVAR_I(rt_VkMaxCommandPools,
 | 
			
		||||
@ -54,8 +56,10 @@ rt_result InitCommandBufferManagement(void) {
 | 
			
		||||
        return RT_OUT_OF_MEMORY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Keep 0 free as a "Not initialized" value for t_first_pool */
 | 
			
		||||
    _next_pools = 1;
 | 
			
		||||
    /* We keep 0 free as a "Not initialized" value for t_first_pool.
 | 
			
		||||
     * The atomicinc used to acquire a pool returns the incremented value, so 0 is never returned.
 | 
			
		||||
     */
 | 
			
		||||
    _next_pools = 0;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -183,7 +187,7 @@ rt_result RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t count,
 | 
			
		||||
    if ((int)t_first_pool >= rt_VkMaxCommandPools.i)
 | 
			
		||||
        return RT_OUT_OF_MEMORY;
 | 
			
		||||
 | 
			
		||||
    uint32_t frame_id = 0;
 | 
			
		||||
    uint32_t frame_id = g_gpu.current_frame_id % g_gpu.max_frames_in_flight;
 | 
			
		||||
    rt_result result  = RT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
    /* TODO: We should probably batch allocations of the same type */
 | 
			
		||||
@ -216,7 +220,13 @@ rt_result RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t count,
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        p_command_buffers[i].index   = slot;
 | 
			
		||||
        VkCommandBufferBeginInfo begin_info = {
 | 
			
		||||
            .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
 | 
			
		||||
            .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
 | 
			
		||||
        };
 | 
			
		||||
        vkBeginCommandBuffer(_command_buffers[slot].command_buffer, &begin_info);
 | 
			
		||||
 | 
			
		||||
        p_command_buffers[i].index   = (slot + 1);
 | 
			
		||||
        p_command_buffers[i].version = _command_buffers[slot].version;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -243,13 +253,13 @@ rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue queue,
 | 
			
		||||
 | 
			
		||||
    VkSemaphoreSubmitInfo *wait_semaphores =
 | 
			
		||||
        RT_ARENA_PUSH_ARRAY(temp.arena, VkSemaphoreSubmitInfo, info->wait_semaphore_count);
 | 
			
		||||
    if (!wait_semaphores) {
 | 
			
		||||
    if (!wait_semaphores && info->wait_semaphore_count > 0) {
 | 
			
		||||
        result = RT_OUT_OF_MEMORY;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    VkSemaphoreSubmitInfo *signal_semaphores =
 | 
			
		||||
        RT_ARENA_PUSH_ARRAY(temp.arena, VkSemaphoreSubmitInfo, info->signal_semaphore_count);
 | 
			
		||||
    if (!signal_semaphores) {
 | 
			
		||||
    if (!signal_semaphores && info->signal_semaphore_count > 0) {
 | 
			
		||||
        result = RT_OUT_OF_MEMORY;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
@ -277,7 +287,12 @@ rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue queue,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (uint32_t i = 0; i < count; ++i) {
 | 
			
		||||
        uint32_t slot = info->command_buffers[i].index;
 | 
			
		||||
        if (!RT_IS_HANDLE_VALID(info->command_buffers[i])) {
 | 
			
		||||
            rtLog("vk", "Tried to submit an invalid command buffer.");
 | 
			
		||||
            result = RT_INVALID_VALUE;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        uint32_t slot = info->command_buffers[i].index - 1;
 | 
			
		||||
        if (_command_buffers[slot].version != info->command_buffers[i].version) {
 | 
			
		||||
            rtLog("vk",
 | 
			
		||||
                  "Mismatch between handle version and stored version while submitting a command "
 | 
			
		||||
@ -294,6 +309,8 @@ rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue queue,
 | 
			
		||||
        command_buffers[i].pNext         = NULL;
 | 
			
		||||
        command_buffers[i].deviceMask    = 0;
 | 
			
		||||
        command_buffers[i].commandBuffer = _command_buffers[slot].command_buffer;
 | 
			
		||||
 | 
			
		||||
        vkEndCommandBuffer(command_buffers[i].commandBuffer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkSubmitInfo2 submit_info = {
 | 
			
		||||
@ -311,6 +328,126 @@ rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue queue,
 | 
			
		||||
        result = RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    rtReturnTemporaryArena(temp);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VkCommandBuffer rtGetCommandBuffer(rt_command_buffer_handle cmdbuf) {
 | 
			
		||||
    if (!RT_IS_HANDLE_VALID(cmdbuf) || cmdbuf.index >= (uint32_t)rt_VkCommandBufferRingBufferSize.i)
 | 
			
		||||
        return VK_NULL_HANDLE;
 | 
			
		||||
    uint32_t slot = cmdbuf.index - 1;
 | 
			
		||||
    if (_command_buffers[slot].version != cmdbuf.version) {
 | 
			
		||||
        return VK_NULL_HANDLE;
 | 
			
		||||
    }
 | 
			
		||||
    return _command_buffers[slot].command_buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VkCommandBuffer rtAllocSingleCommandBuffer(rt_gpu_queue queue) {
 | 
			
		||||
    rt_thread_pools *pools = &_pools[t_first_pool];
 | 
			
		||||
    if (t_first_pool == 0) {
 | 
			
		||||
        /* Acquire pools */
 | 
			
		||||
        t_first_pool = rtAtomic32Inc(&_next_pools);
 | 
			
		||||
        RT_ASSERT((int)t_first_pool < rt_VkMaxCommandPools.i, "Too many command pools created.");
 | 
			
		||||
 | 
			
		||||
        pools                = &_pools[t_first_pool];
 | 
			
		||||
        rt_result create_res = CreatePools(pools);
 | 
			
		||||
        if (create_res != RT_SUCCESS)
 | 
			
		||||
            return VK_NULL_HANDLE;
 | 
			
		||||
    }
 | 
			
		||||
    if ((int)t_first_pool >= rt_VkMaxCommandPools.i)
 | 
			
		||||
        return VK_NULL_HANDLE;
 | 
			
		||||
 | 
			
		||||
    uint32_t frame_id  = g_gpu.current_frame_id % g_gpu.max_frames_in_flight;
 | 
			
		||||
    VkCommandPool pool = pools->graphics_pools[frame_id];
 | 
			
		||||
    if (queue == RT_COMPUTE_QUEUE)
 | 
			
		||||
        pool = pools->compute_pools[frame_id];
 | 
			
		||||
    else if (queue == RT_TRANSFER_QUEUE)
 | 
			
		||||
        pool = pools->transfer_pools[frame_id];
 | 
			
		||||
 | 
			
		||||
    VkCommandBufferAllocateInfo alloc_info = {
 | 
			
		||||
        .sType              = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
 | 
			
		||||
        .level              = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
 | 
			
		||||
        .commandBufferCount = 1,
 | 
			
		||||
        .commandPool        = pool,
 | 
			
		||||
    };
 | 
			
		||||
    VkCommandBuffer cmdbuf;
 | 
			
		||||
    if (vkAllocateCommandBuffers(g_gpu.device, &alloc_info, &cmdbuf) != VK_SUCCESS) {
 | 
			
		||||
        return VK_NULL_HANDLE;
 | 
			
		||||
    }
 | 
			
		||||
    return cmdbuf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rt_result rtSubmitSingleCommandBuffer(VkCommandBuffer command_buffer,
 | 
			
		||||
                                      const VkSemaphore *wait_semaphores,
 | 
			
		||||
                                      const uint32_t *wait_values,
 | 
			
		||||
                                      uint32_t wait_semaphore_count,
 | 
			
		||||
                                      const VkSemaphore *signal_semaphores,
 | 
			
		||||
                                      const uint32_t *signal_values,
 | 
			
		||||
                                      uint32_t signal_semaphore_count,
 | 
			
		||||
                                      rt_gpu_queue queue) {
 | 
			
		||||
 | 
			
		||||
    rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
 | 
			
		||||
    if (!temp.arena)
 | 
			
		||||
        return RT_OUT_OF_MEMORY;
 | 
			
		||||
    VkQueue target_queue = rtGetQueue(queue);
 | 
			
		||||
    rt_result result     = RT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
    VkSemaphoreSubmitInfo *wait_semaphore_info =
 | 
			
		||||
        RT_ARENA_PUSH_ARRAY(temp.arena, VkSemaphoreSubmitInfo, wait_semaphore_count);
 | 
			
		||||
    if (!wait_semaphore_info && wait_semaphore_count > 0) {
 | 
			
		||||
        result = RT_OUT_OF_MEMORY;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    VkSemaphoreSubmitInfo *signal_semaphore_info =
 | 
			
		||||
        RT_ARENA_PUSH_ARRAY(temp.arena, VkSemaphoreSubmitInfo, signal_semaphore_count);
 | 
			
		||||
    if (!signal_semaphore_info && signal_semaphore_count > 0) {
 | 
			
		||||
        result = RT_OUT_OF_MEMORY;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    uint32_t wait_count   = wait_semaphore_count;
 | 
			
		||||
    uint32_t signal_count = signal_semaphore_count;
 | 
			
		||||
    for (uint32_t i = 0; i < wait_count; ++i) {
 | 
			
		||||
        VkSemaphoreSubmitInfo semaphore_info = {
 | 
			
		||||
            .sType       = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
 | 
			
		||||
            .semaphore   = wait_semaphores[i],
 | 
			
		||||
            .value       = (wait_values) ? wait_values[i] : 0,
 | 
			
		||||
            .stageMask   = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
 | 
			
		||||
            .deviceIndex = 0,
 | 
			
		||||
        };
 | 
			
		||||
        wait_semaphore_info[i] = semaphore_info;
 | 
			
		||||
    }
 | 
			
		||||
    for (uint32_t i = 0; i < signal_count; ++i) {
 | 
			
		||||
        VkSemaphoreSubmitInfo semaphore_info = {
 | 
			
		||||
            .sType       = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
 | 
			
		||||
            .semaphore   = signal_semaphores[i],
 | 
			
		||||
            .value       = (signal_values) ? signal_values[i] : 0,
 | 
			
		||||
            .stageMask   = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
 | 
			
		||||
            .deviceIndex = 0,
 | 
			
		||||
        };
 | 
			
		||||
        signal_semaphore_info[i] = semaphore_info;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkCommandBufferSubmitInfo command_buffer_info = {
 | 
			
		||||
        .sType         = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
 | 
			
		||||
        .deviceMask    = 0,
 | 
			
		||||
        .commandBuffer = command_buffer,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    VkSubmitInfo2 submit_info = {
 | 
			
		||||
        .sType                    = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
 | 
			
		||||
        .waitSemaphoreInfoCount   = wait_count,
 | 
			
		||||
        .signalSemaphoreInfoCount = signal_count,
 | 
			
		||||
        .pWaitSemaphoreInfos      = wait_semaphore_info,
 | 
			
		||||
        .pSignalSemaphoreInfos    = signal_semaphore_info,
 | 
			
		||||
        .commandBufferInfoCount   = 1,
 | 
			
		||||
        .pCommandBufferInfos      = &command_buffer_info,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (vkQueueSubmit2(target_queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
 | 
			
		||||
        rtLog("vk", "vkQueueSubmit failed.");
 | 
			
		||||
        result = RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
out:
 | 
			
		||||
    rtReturnTemporaryArena(temp);
 | 
			
		||||
    return result;
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,24 @@
 | 
			
		||||
#ifndef RT_COMMAND_BUFFERS_H
 | 
			
		||||
#define RT_COMMAND_BUFFERS_H
 | 
			
		||||
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
void rtResetCommandPools(unsigned int frame_id);
 | 
			
		||||
 | 
			
		||||
VkCommandBuffer rtGetCommandBuffer(rt_command_buffer_handle cmdbuf);
 | 
			
		||||
 | 
			
		||||
VkCommandBuffer rtAllocSingleCommandBuffer(rt_gpu_queue queue);
 | 
			
		||||
 | 
			
		||||
rt_result rtSubmitSingleCommandBuffer(VkCommandBuffer command_buffer,
 | 
			
		||||
                                      const VkSemaphore *wait_semaphores,
 | 
			
		||||
                                      const uint32_t *wait_values,
 | 
			
		||||
                                      uint32_t wait_semaphore_count,
 | 
			
		||||
                                      const VkSemaphore *signal_semaphores,
 | 
			
		||||
                                      const uint32_t *signal_values,
 | 
			
		||||
                                      uint32_t signal_semaphore_count,
 | 
			
		||||
                                      rt_gpu_queue queue);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										257
									
								
								src/renderer/vk/commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/renderer/vk/commands.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,257 @@
 | 
			
		||||
#include "command_buffers.h"
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
#include "render_targets.h"
 | 
			
		||||
#include "swapchain.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/handles.h"
 | 
			
		||||
#include "runtime/mem_arena.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
/* Retrieve the VkCommandBuffer as varname, or return */
 | 
			
		||||
#define GET_CMDBUF(varname, handle)                                                                \
 | 
			
		||||
    VkCommandBuffer varname = rtGetCommandBuffer((handle));                                        \
 | 
			
		||||
    if (varname == VK_NULL_HANDLE) {                                                               \
 | 
			
		||||
        rtLog("vk", "Failed to retrive VkCommandBuffer for %s", __FUNCTION__);                     \
 | 
			
		||||
        return;                                                                                    \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
void RT_RENDERER_API_FN(CmdBeginPass)(rt_command_buffer_handle cmdbuf_handle,
 | 
			
		||||
                                      const rt_cmd_begin_pass_info *info) {
 | 
			
		||||
    GET_CMDBUF(cmdbuf, cmdbuf_handle)
 | 
			
		||||
 | 
			
		||||
    rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
 | 
			
		||||
    if (!temp.arena) {
 | 
			
		||||
        rtReportError("vk", "Failed to acquire a temporary arena for CmdBeginPass");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
    VkDebugUtilsLabelEXT debug_label = {
 | 
			
		||||
        .sType      = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
 | 
			
		||||
        .color      = {0.39f, 0.58f, 0.92f, 1.f},
 | 
			
		||||
        .pLabelName = "RenderPass"
 | 
			
		||||
    };
 | 
			
		||||
    vkCmdBeginDebugUtilsLabelEXT(cmdbuf, &debug_label);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* Acquire the necessary attachments */
 | 
			
		||||
 | 
			
		||||
    VkRenderingAttachmentInfo *colorbuffers =
 | 
			
		||||
        RT_ARENA_PUSH_ARRAY_ZERO(temp.arena, VkRenderingAttachmentInfo, info->color_buffer_count);
 | 
			
		||||
    for (uint32_t i = 0; i < info->color_buffer_count; ++i) {
 | 
			
		||||
        VkImageView image_view = VK_NULL_HANDLE;
 | 
			
		||||
        if (RT_IS_HANDLE_VALID(info->color_buffers[i])) {
 | 
			
		||||
            rt_render_target *rt = rtGetRenderTarget(info->color_buffers[i]);
 | 
			
		||||
            if (rt)
 | 
			
		||||
                image_view = rt->view[g_gpu.current_frame_id % g_gpu.max_frames_in_flight];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        colorbuffers[i].sType       = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
 | 
			
		||||
        colorbuffers[i].pNext       = NULL;
 | 
			
		||||
        colorbuffers[i].imageView   = image_view;
 | 
			
		||||
        colorbuffers[i].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 | 
			
		||||
        switch (info->color_buffer_loads[i]) {
 | 
			
		||||
        case RT_PASS_LOAD_MODE_CLEAR:
 | 
			
		||||
            colorbuffers[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 | 
			
		||||
            break;
 | 
			
		||||
        case RT_PASS_LOAD_MODE_LOAD:
 | 
			
		||||
            colorbuffers[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            colorbuffers[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        switch (info->color_buffer_writes[i]) {
 | 
			
		||||
        case RT_PASS_WRITE_MODE_STORE:
 | 
			
		||||
            colorbuffers[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 | 
			
		||||
            break;
 | 
			
		||||
        case RT_PASS_WRITE_MODE_DISCARD:
 | 
			
		||||
            colorbuffers[i].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            colorbuffers[i].storeOp = VK_ATTACHMENT_STORE_OP_NONE;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        memcpy(&colorbuffers[i].clearValue.color.float32,
 | 
			
		||||
               info->color_buffer_clear_values[i].color.v,
 | 
			
		||||
               sizeof(float) * 4);
 | 
			
		||||
 | 
			
		||||
        /* TODO: Multisample resolve */
 | 
			
		||||
        colorbuffers[i].resolveMode        = VK_RESOLVE_MODE_NONE;
 | 
			
		||||
        colorbuffers[i].resolveImageView   = VK_NULL_HANDLE;
 | 
			
		||||
        colorbuffers[i].resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* depth and stencil might be the same */
 | 
			
		||||
    VkRenderingAttachmentInfo *depth_stencil_buffer =
 | 
			
		||||
        RT_IS_HANDLE_VALID(info->depth_stencil_buffer)
 | 
			
		||||
            ? RT_ARENA_PUSH_STRUCT_ZERO(temp.arena, VkRenderingAttachmentInfo)
 | 
			
		||||
            : NULL;
 | 
			
		||||
    if (depth_stencil_buffer) {
 | 
			
		||||
        VkImageView image_view = VK_NULL_HANDLE;
 | 
			
		||||
        rt_render_target *rt   = rtGetRenderTarget(info->depth_stencil_buffer);
 | 
			
		||||
        if (rt)
 | 
			
		||||
            image_view = rt->view[g_gpu.current_frame_id % g_gpu.max_frames_in_flight];
 | 
			
		||||
 | 
			
		||||
        depth_stencil_buffer->sType       = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
 | 
			
		||||
        depth_stencil_buffer->pNext       = NULL;
 | 
			
		||||
        depth_stencil_buffer->imageView   = image_view;
 | 
			
		||||
        depth_stencil_buffer->imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 | 
			
		||||
        switch (info->depth_stencil_buffer_load) {
 | 
			
		||||
        case RT_PASS_LOAD_MODE_CLEAR:
 | 
			
		||||
            depth_stencil_buffer->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 | 
			
		||||
            break;
 | 
			
		||||
        case RT_PASS_LOAD_MODE_LOAD:
 | 
			
		||||
            depth_stencil_buffer->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            depth_stencil_buffer->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        switch (info->depth_stencil_buffer_write) {
 | 
			
		||||
        case RT_PASS_WRITE_MODE_STORE:
 | 
			
		||||
            depth_stencil_buffer->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 | 
			
		||||
            break;
 | 
			
		||||
        case RT_PASS_WRITE_MODE_DISCARD:
 | 
			
		||||
            depth_stencil_buffer->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            depth_stencil_buffer->storeOp = VK_ATTACHMENT_STORE_OP_NONE;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* TODO: Multisample resolve */
 | 
			
		||||
        depth_stencil_buffer->resolveMode        = VK_RESOLVE_MODE_NONE;
 | 
			
		||||
        depth_stencil_buffer->resolveImageView   = VK_NULL_HANDLE;
 | 
			
		||||
        depth_stencil_buffer->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkRect2D render_area = {
 | 
			
		||||
        .offset = {  .x = info->render_area.offset.x,    .y = info->render_area.offset.y},
 | 
			
		||||
        .extent = {.width = info->render_area.size.x, .height = info->render_area.size.y}
 | 
			
		||||
    };
 | 
			
		||||
    if (render_area.extent.width == 0)
 | 
			
		||||
        render_area.extent.width = g_swapchain.extent.width;
 | 
			
		||||
    if (render_area.extent.height == 0)
 | 
			
		||||
        render_area.extent.height = g_swapchain.extent.height;
 | 
			
		||||
 | 
			
		||||
    VkRenderingInfo rendering_info = {
 | 
			
		||||
        .sType                = VK_STRUCTURE_TYPE_RENDERING_INFO,
 | 
			
		||||
        .pColorAttachments    = colorbuffers,
 | 
			
		||||
        .colorAttachmentCount = info->color_buffer_count,
 | 
			
		||||
        .pDepthAttachment     = depth_stencil_buffer,
 | 
			
		||||
        .pStencilAttachment   = depth_stencil_buffer,
 | 
			
		||||
        .layerCount           = 1,
 | 
			
		||||
        .renderArea           = render_area,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    vkCmdBeginRendering(cmdbuf, &rendering_info);
 | 
			
		||||
 | 
			
		||||
    rtReturnTemporaryArena(temp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RT_RENDERER_API_FN(CmdEndPass)(rt_command_buffer_handle cmdbuf_handle) {
 | 
			
		||||
    GET_CMDBUF(cmdbuf, cmdbuf_handle)
 | 
			
		||||
    vkCmdEndRendering(cmdbuf);
 | 
			
		||||
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
    vkCmdEndDebugUtilsLabelEXT(cmdbuf);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_handle cmdbuf_handle,
 | 
			
		||||
                                                   rt_render_target_handle render_target,
 | 
			
		||||
                                                   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;
 | 
			
		||||
 | 
			
		||||
    rt_render_target *rt = rtGetRenderTarget(render_target);
 | 
			
		||||
    if (!rt) {
 | 
			
		||||
        rtLog("vk", "Tried to transition invalid render target");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rt->states[image_index] == new_state)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    /* Determine old and new layout */
 | 
			
		||||
    VkImageLayout old_layout;
 | 
			
		||||
    switch (rt->states[image_index]) {
 | 
			
		||||
    case RT_RENDER_TARGET_STATE_ATTACHMENT:
 | 
			
		||||
        if (rt->format == VK_FORMAT_D24_UNORM_S8_UINT || rt->format == VK_FORMAT_D32_SFLOAT) {
 | 
			
		||||
            old_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 | 
			
		||||
        } else {
 | 
			
		||||
            old_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case RT_RENDER_TARGET_STATE_STORAGE_IMAGE:
 | 
			
		||||
    case RT_RENDER_TARGET_STATE_SAMPLED_IMAGE:
 | 
			
		||||
        old_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        old_layout = VK_IMAGE_LAYOUT_UNDEFINED;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    VkImageLayout new_layout;
 | 
			
		||||
    switch (new_state) {
 | 
			
		||||
    case RT_RENDER_TARGET_STATE_ATTACHMENT:
 | 
			
		||||
        if (rt->format == VK_FORMAT_D24_UNORM_S8_UINT || rt->format == VK_FORMAT_D32_SFLOAT) {
 | 
			
		||||
            new_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 | 
			
		||||
        } else {
 | 
			
		||||
            new_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case RT_RENDER_TARGET_STATE_STORAGE_IMAGE:
 | 
			
		||||
    case RT_RENDER_TARGET_STATE_SAMPLED_IMAGE:
 | 
			
		||||
        new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        new_layout = VK_IMAGE_LAYOUT_UNDEFINED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
    VkDebugUtilsLabelEXT debug_label = {
 | 
			
		||||
        .sType      = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
 | 
			
		||||
        .pLabelName = "Transition Render Target",
 | 
			
		||||
        .color      = {0.f, 0.f, 0.f, 0.f},
 | 
			
		||||
    };
 | 
			
		||||
    vkCmdBeginDebugUtilsLabelEXT(cmdbuf, &debug_label);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    VkImageAspectFlags aspect_mask =
 | 
			
		||||
        (rt->format == VK_FORMAT_D24_UNORM_S8_UINT || rt->format == VK_FORMAT_D32_SFLOAT)
 | 
			
		||||
            ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT
 | 
			
		||||
            : VK_IMAGE_ASPECT_COLOR_BIT;
 | 
			
		||||
    VkImageMemoryBarrier2 image_barrier = {
 | 
			
		||||
        .sType         = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
 | 
			
		||||
        .srcStageMask  = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
 | 
			
		||||
        .srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT,
 | 
			
		||||
        .dstStageMask  = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
 | 
			
		||||
        .dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT,
 | 
			
		||||
        .oldLayout     = old_layout,
 | 
			
		||||
        .newLayout     = new_layout,
 | 
			
		||||
        .image         = rt->image[image_index],
 | 
			
		||||
 /* clang-format off */
 | 
			
		||||
        .subresourceRange = {
 | 
			
		||||
            .aspectMask = aspect_mask,
 | 
			
		||||
            .baseArrayLayer = 0,
 | 
			
		||||
            .baseMipLevel = 0,
 | 
			
		||||
            .layerCount = 1,
 | 
			
		||||
            .levelCount = 1,
 | 
			
		||||
        },
 | 
			
		||||
  /* clang-format on */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    VkDependencyInfo dep_info = {
 | 
			
		||||
        .sType                   = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
 | 
			
		||||
        .pImageMemoryBarriers    = &image_barrier,
 | 
			
		||||
        .imageMemoryBarrierCount = 1,
 | 
			
		||||
    };
 | 
			
		||||
    vkCmdPipelineBarrier2(cmdbuf, &dep_info);
 | 
			
		||||
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
    vkCmdEndDebugUtilsLabelEXT(cmdbuf);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    rt->states[image_index] = new_state;
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
#include "command_buffers.h"
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
#include "render_targets.h"
 | 
			
		||||
#include "swapchain.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#define ONE_SECOND_NS 1000000000u
 | 
			
		||||
 | 
			
		||||
@ -32,6 +33,10 @@ void RT_RENDERER_API_FN(BeginFrame)(unsigned int frame_id) {
 | 
			
		||||
            rtReportError("vk", "Failed to recreate the swapchain.");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        rtUpdateSwapchainRenderTarget();
 | 
			
		||||
        rtUpdateRenderTargetsFromSwapchain(g_swapchain.image_count,
 | 
			
		||||
                                           g_swapchain.format,
 | 
			
		||||
                                           g_swapchain.extent);
 | 
			
		||||
        rtRenBeginFrame(frame_id);
 | 
			
		||||
    } else if (acquire_res != VK_SUCCESS) {
 | 
			
		||||
        rtReportError("vk", "vkAcquireNextImageKHR failed: %u", acquire_res);
 | 
			
		||||
@ -43,12 +48,85 @@ void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) {
 | 
			
		||||
 | 
			
		||||
    uint32_t image_index = frame->swapchain_image_index;
 | 
			
		||||
 | 
			
		||||
    /* Transition the swap chain image to the correct layout */
 | 
			
		||||
    VkCommandBuffer cmd = rtAllocSingleCommandBuffer(RT_GRAPHICS_QUEUE);
 | 
			
		||||
    if (cmd == VK_NULL_HANDLE) {
 | 
			
		||||
        rtReportError("vk",
 | 
			
		||||
                      "Failed to allocate a command buffer for transitioning the swapchain image "
 | 
			
		||||
                      "to PRESENT_SRC layout.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkCommandBufferBeginInfo begin_info = {.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
 | 
			
		||||
                                           .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT};
 | 
			
		||||
    vkBeginCommandBuffer(cmd, &begin_info);
 | 
			
		||||
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
    VkDebugUtilsLabelEXT debug_label = {
 | 
			
		||||
        .sType      = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
 | 
			
		||||
        .color      = {0.f, 0.f, 0.f, 0.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,
 | 
			
		||||
        .srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT,
 | 
			
		||||
        .dstStageMask  = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
 | 
			
		||||
        .dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT,
 | 
			
		||||
        .oldLayout     = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
 | 
			
		||||
        .newLayout     = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
 | 
			
		||||
        .image         = g_swapchain.images[image_index],
 | 
			
		||||
 /* clang-format off */
 | 
			
		||||
        .subresourceRange = {
 | 
			
		||||
            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
 | 
			
		||||
            .baseArrayLayer = 0,
 | 
			
		||||
            .baseMipLevel = 0,
 | 
			
		||||
            .layerCount = 1,
 | 
			
		||||
            .levelCount = 1,
 | 
			
		||||
        },
 | 
			
		||||
  /* clang-format on */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    VkDependencyInfo dep_info = {
 | 
			
		||||
        .sType                   = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
 | 
			
		||||
        .pImageMemoryBarriers    = &image_barrier,
 | 
			
		||||
        .imageMemoryBarrierCount = 1,
 | 
			
		||||
    };
 | 
			
		||||
    vkCmdPipelineBarrier2(cmd, &dep_info);
 | 
			
		||||
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
    vkCmdEndDebugUtilsLabelEXT(cmd);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    vkEndCommandBuffer(cmd);
 | 
			
		||||
    if (rtSubmitSingleCommandBuffer(cmd,
 | 
			
		||||
                                    &frame->image_available,
 | 
			
		||||
                                    NULL,
 | 
			
		||||
                                    1,
 | 
			
		||||
                                    &frame->render_finished,
 | 
			
		||||
                                    NULL,
 | 
			
		||||
                                    1,
 | 
			
		||||
                                    RT_GRAPHICS_QUEUE) != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("vk", "Failed to submit the layout transition for the swapchain image.");
 | 
			
		||||
        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,
 | 
			
		||||
        .pSwapchains        = &g_swapchain.swapchain,
 | 
			
		||||
        .swapchainCount     = 1,
 | 
			
		||||
        .pWaitSemaphores    = &frame->image_available,
 | 
			
		||||
        .pWaitSemaphores    = &frame->render_finished,
 | 
			
		||||
        .waitSemaphoreCount = 1,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
#define VMA_DYNAMI_VULKAN_FUNCTIONS 0
 | 
			
		||||
#include <vma/vk_mem_alloc.h>
 | 
			
		||||
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
/* Minimum supported value of g_gpu.max_frames_in_flight */
 | 
			
		||||
#define RT_VK_MIN_SUPPORTED_FRAMES_IN_FLIGHT 2
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,11 @@
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
#include "runtime/handles.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
RT_CVAR_I(rt_VkMaxSemaphores, "Maximum number of semaphores. Default: 1024", 1024);
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
VkSemaphore rtGetSemaphore(rt_gpu_semaphore_handle handle);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,13 +5,15 @@
 | 
			
		||||
 | 
			
		||||
#define RT_VK_DONT_DEFINE_GPU_GLOBAL
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
#include "render_targets.h"
 | 
			
		||||
#include "swapchain.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
#define TARGET_API_VERSION VK_API_VERSION_1_2
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#define TARGET_API_VERSION VK_API_VERSION_1_3
 | 
			
		||||
 | 
			
		||||
RT_CVAR_I(r_VkEnableAPIAllocTracking,
 | 
			
		||||
          "Enable tracking of allocations done by the vulkan api. [0/1] Default: 0",
 | 
			
		||||
@ -78,7 +80,16 @@ DebugUtilsMessengerCb(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
 | 
			
		||||
                      VkDebugUtilsMessageTypeFlagsEXT types,
 | 
			
		||||
                      const VkDebugUtilsMessengerCallbackDataEXT *callbackData,
 | 
			
		||||
                      void *userData) {
 | 
			
		||||
    if (severity < VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
 | 
			
		||||
        return VK_FALSE;
 | 
			
		||||
 | 
			
		||||
    const char *severity_str = "<UNKNOWN>";
 | 
			
		||||
    if (severity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
 | 
			
		||||
        severity_str = "WARNING";
 | 
			
		||||
    else if (severity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
 | 
			
		||||
        severity_str = "ERROR";
 | 
			
		||||
    rtLog("vk", "[%s] %s", severity_str, callbackData->pMessage);
 | 
			
		||||
    RT_DEBUGBREAK;
 | 
			
		||||
    return VK_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -260,7 +271,6 @@ static rt_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev, VkSurfac
 | 
			
		||||
static bool CheckDeviceExtensionSupported(VkPhysicalDevice phys_dev) {
 | 
			
		||||
    const char *required_extensions[] = {
 | 
			
		||||
        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
 | 
			
		||||
        VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    uint32_t extension_count;
 | 
			
		||||
@ -318,8 +328,16 @@ static rt_result ChoosePhysicalDevice(void) {
 | 
			
		||||
    uint32_t highscore  = 0;
 | 
			
		||||
    uint32_t best_index = phys_device_count;
 | 
			
		||||
    for (uint32_t i = 0; i < phys_device_count; ++i) {
 | 
			
		||||
        VkPhysicalDeviceSynchronization2Features synchronization2_features = {
 | 
			
		||||
            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
 | 
			
		||||
        };
 | 
			
		||||
        VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_features = {
 | 
			
		||||
            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
 | 
			
		||||
            .pNext = &synchronization2_features,
 | 
			
		||||
        };
 | 
			
		||||
        VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features = {
 | 
			
		||||
            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
 | 
			
		||||
            .pNext = &dynamic_rendering_features,
 | 
			
		||||
        };
 | 
			
		||||
        VkPhysicalDeviceFeatures2 features = {
 | 
			
		||||
            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
 | 
			
		||||
@ -345,6 +363,10 @@ static rt_result ChoosePhysicalDevice(void) {
 | 
			
		||||
            indices.graphics == UINT32_MAX)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        if (!synchronization2_features.synchronization2 ||
 | 
			
		||||
            !dynamic_rendering_features.dynamicRendering)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        /* Check for bindless support */
 | 
			
		||||
        if (!descriptor_indexing_features.runtimeDescriptorArray ||
 | 
			
		||||
            !descriptor_indexing_features.descriptorBindingPartiallyBound)
 | 
			
		||||
@ -461,9 +483,16 @@ static rt_result CreateDevice(void) {
 | 
			
		||||
        queue_info[distinct_queue_count].pQueuePriorities = &priority;
 | 
			
		||||
        ++distinct_queue_count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkPhysicalDeviceSynchronization2Features synchronization2_features = {
 | 
			
		||||
        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
 | 
			
		||||
    };
 | 
			
		||||
    VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_features = {
 | 
			
		||||
        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
 | 
			
		||||
        .pNext = &synchronization2_features,
 | 
			
		||||
    };
 | 
			
		||||
    VkPhysicalDeviceDescriptorIndexingFeatures indexing_features = {
 | 
			
		||||
        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
 | 
			
		||||
        .pNext = &dynamic_rendering_features,
 | 
			
		||||
    };
 | 
			
		||||
    VkPhysicalDeviceFeatures2 features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
 | 
			
		||||
                                          .pNext = &indexing_features};
 | 
			
		||||
@ -523,6 +552,8 @@ static rt_result CreateAllocator(void) {
 | 
			
		||||
    SET_KHR_FNC(vkBindBufferMemory2);
 | 
			
		||||
    SET_KHR_FNC(vkBindImageMemory2);
 | 
			
		||||
    SET_KHR_FNC(vkGetPhysicalDeviceMemoryProperties2);
 | 
			
		||||
    SET_FNC(vkGetDeviceBufferMemoryRequirements);
 | 
			
		||||
    SET_FNC(vkGetDeviceImageMemoryRequirements);
 | 
			
		||||
#undef SET_FNC
 | 
			
		||||
#undef SET_KHR_FNC
 | 
			
		||||
 | 
			
		||||
@ -549,8 +580,8 @@ static rt_result CreatePerFrameObjects(void) {
 | 
			
		||||
            .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
 | 
			
		||||
        };
 | 
			
		||||
        if (vkCreateSemaphore(g_gpu.device,
 | 
			
		||||
                          &semaphore_info,
 | 
			
		||||
                          g_gpu.alloc_cb,
 | 
			
		||||
                              &semaphore_info,
 | 
			
		||||
                              g_gpu.alloc_cb,
 | 
			
		||||
                              &g_gpu.frames[i].render_finished) != VK_SUCCESS) {
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
@ -630,6 +661,7 @@ rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) {
 | 
			
		||||
    res = rtCreateSwapchain();
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
    rtUpdateSwapchainRenderTarget();
 | 
			
		||||
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ if vk_dep.found()
 | 
			
		||||
    'swapchain.h',
 | 
			
		||||
 | 
			
		||||
    'command_buffers.c',
 | 
			
		||||
    'commands.c',
 | 
			
		||||
    'frame.c',
 | 
			
		||||
    'gpu_sync.c',
 | 
			
		||||
    'helper.c',
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,11 @@
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/handles.h"
 | 
			
		||||
#include "runtime/mem_arena.h"
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "runtime/resources.h"
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
#include "pipelines.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkPipeline pipeline;
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
#include "runtime/config.h"
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
#include "render_targets.h"
 | 
			
		||||
#include "swapchain.h"
 | 
			
		||||
@ -21,6 +22,8 @@ static rt_render_target_slot *_render_targets;
 | 
			
		||||
static rt_render_target_slot *_first_free;
 | 
			
		||||
static rt_rwlock _lock;
 | 
			
		||||
 | 
			
		||||
static rt_render_target_handle _swapchain_handle;
 | 
			
		||||
 | 
			
		||||
static void DestroyRenderTarget(rt_render_target_slot *slot) {
 | 
			
		||||
    for (unsigned int i = 0; i < slot->render_target.image_count; ++i) {
 | 
			
		||||
        vkDestroyImageView(g_gpu.device, slot->render_target.view[i], g_gpu.alloc_cb);
 | 
			
		||||
@ -50,6 +53,34 @@ static bool CreateImageAndView(VkExtent2D extent,
 | 
			
		||||
        g_gpu.present_family != g_gpu.compute_family)
 | 
			
		||||
        queue_families[distinct_queue_families++] = g_gpu.present_family;
 | 
			
		||||
 | 
			
		||||
    VkFormatProperties2 props = {
 | 
			
		||||
        .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
 | 
			
		||||
    };
 | 
			
		||||
    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.");
 | 
			
		||||
        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.");
 | 
			
		||||
        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.");
 | 
			
		||||
        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.");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkImageCreateInfo image_info = {
 | 
			
		||||
        .sType       = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
 | 
			
		||||
        .imageType   = VK_IMAGE_TYPE_2D,
 | 
			
		||||
@ -124,6 +155,14 @@ rt_result InitRenderTargetManagement(void) {
 | 
			
		||||
    for (int i = 1; i < r_VkMaxRenderTargetCount.i - 1; ++i) {
 | 
			
		||||
        _render_targets[i].next_free = &_render_targets[i + 1];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Reserve the slot for the swap chain rt */
 | 
			
		||||
    rt_render_target_slot *slot = _first_free;
 | 
			
		||||
    _first_free                 = slot->next_free;
 | 
			
		||||
    slot->version               = (slot->version + 1) & RT_RENDER_BACKEND_HANDLE_MAX_VERSION;
 | 
			
		||||
    _swapchain_handle           = (rt_render_target_handle){.version = slot->version,
 | 
			
		||||
                                                            .index   = (uint32_t)(slot - _render_targets)};
 | 
			
		||||
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -175,15 +214,18 @@ rt_render_target_handle RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_t
 | 
			
		||||
            slot->render_target.format = g_swapchain.format;
 | 
			
		||||
            slot->render_target.match_swapchain |= RT_RENDER_TARGET_MATCH_SWAPCHAIN_FORMAT;
 | 
			
		||||
        }
 | 
			
		||||
        if (info->format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8 || info->format == RT_PIXEL_FORMAT_DEPTH32) {
 | 
			
		||||
        if (info->format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8 ||
 | 
			
		||||
            info->format == RT_PIXEL_FORMAT_DEPTH32) {
 | 
			
		||||
            slot->render_target.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
 | 
			
		||||
                                        VK_IMAGE_USAGE_SAMPLED_BIT |
 | 
			
		||||
                                        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
 | 
			
		||||
            slot->render_target.aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
 | 
			
		||||
                                        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
 | 
			
		||||
            if (info->format == RT_PIXEL_FORMAT_DEPTH32)
 | 
			
		||||
                slot->render_target.aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
 | 
			
		||||
            else
 | 
			
		||||
                slot->render_target.aspect =
 | 
			
		||||
                    VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
 | 
			
		||||
        } else {
 | 
			
		||||
            slot->render_target.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
 | 
			
		||||
                                        VK_IMAGE_USAGE_SAMPLED_BIT |
 | 
			
		||||
                                        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
 | 
			
		||||
                                        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
 | 
			
		||||
            slot->render_target.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
 | 
			
		||||
        }
 | 
			
		||||
        slot->render_target.sample_count = rtSampleCountToFlags(info->sample_count);
 | 
			
		||||
@ -199,6 +241,7 @@ rt_render_target_handle RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_t
 | 
			
		||||
            DestroyRenderTarget(slot);
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        slot->render_target.states[i] = RT_RENDER_TARGET_STATE_INVALID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handle.version = slot->version;
 | 
			
		||||
@ -207,6 +250,10 @@ out:
 | 
			
		||||
    return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rt_render_target_handle RT_RENDERER_API_FN(GetSwapchainRenderTarget)(void) {
 | 
			
		||||
    return _swapchain_handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RT_RENDERER_API_FN(DestroyRenderTarget)(rt_render_target_handle handle) {
 | 
			
		||||
    if (handle.index >= (uint32_t)r_VkMaxRenderTargetCount.i)
 | 
			
		||||
        return;
 | 
			
		||||
@ -231,6 +278,25 @@ rt_render_target *rtGetRenderTarget(rt_render_target_handle handle) {
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rtUpdateSwapchainRenderTarget(void) {
 | 
			
		||||
    RT_ASSERT(_swapchain_handle.index != 0, "Invalid swap chain render target!");
 | 
			
		||||
    rt_render_target_slot *slot = &_render_targets[_swapchain_handle.index];
 | 
			
		||||
    rt_render_target *rt        = &slot->render_target;
 | 
			
		||||
 | 
			
		||||
    rt->match_swapchain = 0;
 | 
			
		||||
    rt->format          = g_swapchain.format;
 | 
			
		||||
    rt->extent          = g_swapchain.extent;
 | 
			
		||||
    rt->sample_count    = 1;
 | 
			
		||||
    rt->usage           = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 | 
			
		||||
    rt->aspect          = VK_IMAGE_ASPECT_COLOR_BIT;
 | 
			
		||||
    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
			
		||||
        rt->allocation[i] = NULL;
 | 
			
		||||
        rt->image[i]      = g_swapchain.images[i];
 | 
			
		||||
        rt->view[i]       = g_swapchain.image_views[i];
 | 
			
		||||
        rt->states[i]     = RT_RENDER_TARGET_STATE_INVALID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rtUpdateRenderTargetsFromSwapchain(uint32_t image_count, VkFormat format, VkExtent2D extent) {
 | 
			
		||||
    rtLockWrite(&_lock);
 | 
			
		||||
    for (uint32_t i = 1; i < (uint32_t)r_VkMaxRenderTargetCount.i; ++i) {
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
#define RT_VK_RENDER_TARGETS_H
 | 
			
		||||
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
/* Must match RT_VK_MAX_SWAPCHAIN_IMAGES */
 | 
			
		||||
#define RT_VK_RENDER_TARGET_MAX_IMAGES 3
 | 
			
		||||
@ -16,6 +16,7 @@ typedef struct {
 | 
			
		||||
    VkImage image[RT_VK_RENDER_TARGET_MAX_IMAGES];
 | 
			
		||||
    VkImageView view[RT_VK_RENDER_TARGET_MAX_IMAGES];
 | 
			
		||||
    VmaAllocation allocation[RT_VK_RENDER_TARGET_MAX_IMAGES];
 | 
			
		||||
    rt_render_target_state states[RT_VK_RENDER_TARGET_MAX_IMAGES];
 | 
			
		||||
    VkSampleCountFlagBits sample_count;
 | 
			
		||||
    VkFormat format;
 | 
			
		||||
    VkExtent2D extent;
 | 
			
		||||
@ -27,6 +28,10 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
rt_render_target *rtGetRenderTarget(rt_render_target_handle handle);
 | 
			
		||||
 | 
			
		||||
/* Update the render target that represents the swap chain */
 | 
			
		||||
void rtUpdateSwapchainRenderTarget(void);
 | 
			
		||||
 | 
			
		||||
/* Update render targets that match the swap chain*/
 | 
			
		||||
void rtUpdateRenderTargetsFromSwapchain(uint32_t image_count, VkFormat format, VkExtent2D extent);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,6 @@ runtime_incdirs = include_directories(meson.project_source_root() / 'contrib')
 | 
			
		||||
runtime_lib = library('rt',
 | 
			
		||||
  # Project Sources
 | 
			
		||||
  'aio.h',
 | 
			
		||||
  'app.h',
 | 
			
		||||
  'atomics.h',
 | 
			
		||||
  'buffer_manager.h',
 | 
			
		||||
  'compression.h',
 | 
			
		||||
@ -13,20 +12,15 @@ runtime_lib = library('rt',
 | 
			
		||||
  'dynamic_libs.h',
 | 
			
		||||
  'file_tab.h',
 | 
			
		||||
  'fsutils.h',
 | 
			
		||||
  'gfx.h',
 | 
			
		||||
  'handles.h',
 | 
			
		||||
  'hashing.h',
 | 
			
		||||
  'jobs.h',
 | 
			
		||||
  'main_loop.h',
 | 
			
		||||
  'mem_arena.h',
 | 
			
		||||
  'render_list.h',
 | 
			
		||||
  'renderer_api.h',
 | 
			
		||||
  'resources.h',
 | 
			
		||||
  'runtime.h',
 | 
			
		||||
  'threading.h',
 | 
			
		||||
  
 | 
			
		||||
  'aio.c',
 | 
			
		||||
  'app.c',
 | 
			
		||||
  'assert.c',
 | 
			
		||||
  'buffer_manager.c',
 | 
			
		||||
  'compression.c',
 | 
			
		||||
@ -36,12 +30,9 @@ runtime_lib = library('rt',
 | 
			
		||||
  'error_report.c',
 | 
			
		||||
  'file_tab.c',
 | 
			
		||||
  'fsutils.c',
 | 
			
		||||
  'gfx_framegraph.c',
 | 
			
		||||
  'gfx_main.c',
 | 
			
		||||
  'hashing.c',
 | 
			
		||||
  'init.c',
 | 
			
		||||
  'jobs.c',
 | 
			
		||||
  'main_loop.c',
 | 
			
		||||
  'mem_arena.c',
 | 
			
		||||
  'resource_manager.c',
 | 
			
		||||
  'sprint.c',
 | 
			
		||||
@ -61,4 +52,4 @@ runtime_lib = library('rt',
 | 
			
		||||
  install : true)
 | 
			
		||||
 | 
			
		||||
engine_libs += runtime_lib
 | 
			
		||||
engine_lib_paths += runtime_lib.full_path()
 | 
			
		||||
engine_lib_paths += runtime_lib.full_path()
 | 
			
		||||
 | 
			
		||||
@ -7,10 +7,11 @@
 | 
			
		||||
#include "fsutils.h"
 | 
			
		||||
#include "hashing.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include "renderer_api.h"
 | 
			
		||||
#include "resources.h"
 | 
			
		||||
#include "threading.h"
 | 
			
		||||
 | 
			
		||||
#include "gfx/renderer_api.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								src/runtime/rt_math.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/runtime/rt_math.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
#ifndef RT_MATH_H
 | 
			
		||||
#define RT_MATH_H
 | 
			
		||||
 | 
			
		||||
/* Math types and functions */
 | 
			
		||||
 | 
			
		||||
/* 2d vector */
 | 
			
		||||
typedef union {
 | 
			
		||||
    struct {
 | 
			
		||||
        float x;
 | 
			
		||||
        float y;
 | 
			
		||||
    };
 | 
			
		||||
    float e[2];
 | 
			
		||||
} rt_v2;
 | 
			
		||||
 | 
			
		||||
typedef union {
 | 
			
		||||
    struct {
 | 
			
		||||
        int x;
 | 
			
		||||
        int y;
 | 
			
		||||
    };
 | 
			
		||||
    int e[2];
 | 
			
		||||
} rt_v2i;
 | 
			
		||||
 | 
			
		||||
/* 2d rectangle defined by its upper left corner and its size. */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rt_v2 offset;
 | 
			
		||||
    rt_v2 size;
 | 
			
		||||
} rt_rect2;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rt_v2i offset;
 | 
			
		||||
    rt_v2i size;
 | 
			
		||||
} rt_rect2i;
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user