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 {
|
depth0 {
|
||||||
format DEPTH24_STENCIL8;
|
format DEPTH24_STENCIL8;
|
||||||
width 512;
|
width 1024;
|
||||||
height 384;
|
height 768;
|
||||||
sample_count 4;
|
sample_count 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,12 +75,12 @@ subdir('src')
|
|||||||
engine_link_libs = []
|
engine_link_libs = []
|
||||||
if get_option('default_library') == 'static'
|
if get_option('default_library') == 'static'
|
||||||
if get_option('static_renderer') == 'vk'
|
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
|
else
|
||||||
error('Invalid static_renderer option ', get_option('static_renderer'))
|
error('Invalid static_renderer option ', get_option('static_renderer'))
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
engine_link_libs = [runtime_lib]
|
engine_link_libs = [runtime_lib, gfx_lib, app_lib]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Unit/Integration test driver
|
# Unit/Integration test driver
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#include "app.h"
|
#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 "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>
|
#include <stdbool.h>
|
||||||
|
|
||||||
RT_CVAR_I(rt_Fullscreen, "Show window in fullscreen mode. [0/1] Default: 0", 0);
|
RT_CVAR_I(rt_Fullscreen, "Show window in fullscreen mode. [0/1] Default: 0", 0);
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
/* Platform specific application entry point */
|
/* Platform specific application entry point */
|
||||||
|
|
||||||
#include "runtime.h"
|
#include "runtime/runtime.h"
|
||||||
#include "main_loop.h"
|
#include "main_loop.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
@ -1,8 +1,9 @@
|
|||||||
#define RT_DONT_DEFINE_MAIN_LOOP_GLOBAL
|
#define RT_DONT_DEFINE_MAIN_LOOP_GLOBAL
|
||||||
#include "main_loop.h"
|
#include "main_loop.h"
|
||||||
#include "runtime.h"
|
#include "runtime/runtime.h"
|
||||||
#include "config.h"
|
#include "runtime/config.h"
|
||||||
#include "gfx.h"
|
|
||||||
|
#include "gfx/gfx.h"
|
||||||
|
|
||||||
RT_CVAR_I(rt_MaxFrameLatency, "Maximum latency between update and rendering. Default: 2", 2);
|
RT_CVAR_I(rt_MaxFrameLatency, "Maximum latency between update and rendering. Default: 2", 2);
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
#ifndef RT_MAIN_LOOP_H
|
#ifndef RT_MAIN_LOOP_H
|
||||||
#define RT_MAIN_LOOP_H
|
#define RT_MAIN_LOOP_H
|
||||||
|
|
||||||
#include "runtime.h"
|
#include "runtime/runtime.h"
|
||||||
#include "threading.h"
|
#include "runtime/threading.h"
|
||||||
|
|
||||||
typedef void rt_main_loop_update_fn(void);
|
typedef void rt_main_loop_update_fn(void);
|
||||||
typedef void rt_main_loop_render_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 "description_parser.h"
|
||||||
|
|
||||||
#include "runtime/buffer_manager.h"
|
#include "runtime/buffer_manager.h"
|
||||||
#include "runtime/gfx.h"
|
#include "gfx/gfx.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -559,11 +559,11 @@ static rt_result ParseFramegraph(const char *text,
|
|||||||
}
|
}
|
||||||
if (rtCompareSpanToString(mode_stmt->value, "SAMPLED") == 0) {
|
if (rtCompareSpanToString(mode_stmt->value, "SAMPLED") == 0) {
|
||||||
read->mode = RT_RENDER_TARGET_READ_SAMPLED;
|
read->mode = RT_RENDER_TARGET_READ_SAMPLED;
|
||||||
} else if (rtCompareSpanToString(mode_stmt->value, "INPUT_ATTACHMENT") == 0) {
|
} else if (rtCompareSpanToString(mode_stmt->value, "DIRECT") == 0) {
|
||||||
read->mode = RT_RENDER_TARGET_READ_INPUT_ATTACHMENT;
|
read->mode = RT_RENDER_TARGET_READ_DIRECT;
|
||||||
} else {
|
} else {
|
||||||
rtLog("AC",
|
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",
|
"\"passes.%.*s.writes.%.*s.mode\" in %s",
|
||||||
pass_stmt->attribute.length,
|
pass_stmt->attribute.length,
|
||||||
pass_stmt->attribute.start,
|
pass_stmt->attribute.start,
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
|
|
||||||
#include "runtime/buffer_manager.h"
|
#include "runtime/buffer_manager.h"
|
||||||
#include "runtime/config.h"
|
#include "runtime/config.h"
|
||||||
#include "runtime/gfx.h"
|
|
||||||
#include "runtime/mem_arena.h"
|
#include "runtime/mem_arena.h"
|
||||||
#include "runtime/runtime.h"
|
#include "runtime/runtime.h"
|
||||||
|
|
||||||
|
#include "gfx/gfx.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "runtime/runtime.h"
|
#include "runtime/runtime.h"
|
||||||
#include "runtime/mem_arena.h"
|
#include "runtime/mem_arena.h"
|
||||||
#include "runtime/renderer_api.h"
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "runtime/app.h"
|
#include "app_framework/app.h"
|
||||||
|
|
||||||
extern void RegisterCVars(void);
|
extern void RegisterCVars(void);
|
||||||
extern void Init(void);
|
extern void Init(void);
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#include "runtime/gfx.h"
|
|
||||||
#include "runtime/mem_arena.h"
|
#include "runtime/mem_arena.h"
|
||||||
#include "runtime/resources.h"
|
#include "runtime/resources.h"
|
||||||
#include "runtime/threading.h"
|
#include "runtime/threading.h"
|
||||||
|
|
||||||
|
#include "gfx/gfx.h"
|
||||||
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
#include "asset_compiler/asset_compiler.h"
|
#include "asset_compiler/asset_compiler.h"
|
||||||
|
|
||||||
void RegisterCVars(void) {
|
void RegisterCVars(void) {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "runtime.h"
|
#include "runtime/runtime.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -88,7 +88,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RT_RENDER_TARGET_READ_SAMPLED,
|
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_count,
|
||||||
} rt_render_target_read_mode;
|
} rt_render_target_read_mode;
|
@ -1,10 +1,11 @@
|
|||||||
#include "config.h"
|
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
#include "handles.h"
|
|
||||||
#include "hashing.h"
|
|
||||||
#include "mem_arena.h"
|
|
||||||
#include "renderer_api.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 <stdbool.h>
|
||||||
#include <stdlib.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].width = render_targets[i].width;
|
||||||
graph->render_targets[i].height = render_targets[i].height;
|
graph->render_targets[i].height = render_targets[i].height;
|
||||||
graph->render_targets[i].sample_count = render_targets[i].sample_count;
|
graph->render_targets[i].sample_count = render_targets[i].sample_count;
|
||||||
|
|
||||||
|
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 =
|
graph->render_targets[i].api_render_target =
|
||||||
g_renderer.CreateRenderTarget(&render_targets[i]);
|
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)) {
|
if (!RT_IS_HANDLE_VALID(graph->render_targets[i].api_render_target)) {
|
||||||
rtReportError("GFX", "Failed to create render target %u of framegraph.", i);
|
rtReportError("GFX", "Failed to create render target %u of framegraph.", i);
|
||||||
for (uint32_t j = 0; j < i; ++j)
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
graph->render_target_count = info->render_target_count;
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
out:
|
out:
|
||||||
@ -386,6 +396,110 @@ RT_DLLEXPORT void rtBindRenderPass(rt_framegraph *framegraph,
|
|||||||
rtLog("GFX", "Tried to bind functions to unknown render pass %x", id);
|
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) {
|
RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
|
||||||
int execution_level = framegraph->passes[0].execution_level;
|
int execution_level = framegraph->passes[0].execution_level;
|
||||||
uint32_t level_start = 0;
|
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*/
|
/* 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,
|
framegraph->passes[pass_idx].bound_fns.Prepare(id,
|
||||||
writes,
|
writes,
|
||||||
write_count,
|
write_count,
|
||||||
@ -428,6 +556,12 @@ RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
|
|||||||
write_count,
|
write_count,
|
||||||
reads,
|
reads,
|
||||||
read_count);
|
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 */
|
/* Start next level */
|
@ -2,12 +2,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define RT_DONT_DEFINE_RENDERER_GLOBAL
|
#define RT_DONT_DEFINE_RENDERER_GLOBAL
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "dynamic_libs.h"
|
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
#include "renderer_api.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.
|
/* Attributes are used to bind buffers (or textures) to symbolic values.
|
||||||
* For example, an attribute might be bound to "CELL_GRID", which would be
|
* 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
|
* 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 void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle);
|
||||||
extern rt_render_target_handle
|
extern rt_render_target_handle
|
||||||
RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_target_info *);
|
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 void RT_RENDERER_API_FN(DestroyRenderTarget)(rt_render_target_handle);
|
||||||
extern rt_result RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t,
|
extern rt_result RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t,
|
||||||
const rt_alloc_command_buffer_info *,
|
const rt_alloc_command_buffer_info *,
|
||||||
@ -42,6 +43,12 @@ extern rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t,
|
|||||||
rt_gpu_semaphore_handle *);
|
rt_gpu_semaphore_handle *);
|
||||||
extern void RT_RENDERER_API_FN(DestroySemaphores)(uint32_t count, 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 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
|
#endif
|
||||||
|
|
||||||
extern rt_result InitFramegraphManager(void);
|
extern rt_result InitFramegraphManager(void);
|
||||||
@ -73,12 +80,16 @@ static bool LoadRenderer(void) {
|
|||||||
RETRIEVE_SYMBOL(CompilePipeline, rt_compile_pipeline_fn);
|
RETRIEVE_SYMBOL(CompilePipeline, rt_compile_pipeline_fn);
|
||||||
RETRIEVE_SYMBOL(DestroyPipeline, rt_destroy_pipeline_fn);
|
RETRIEVE_SYMBOL(DestroyPipeline, rt_destroy_pipeline_fn);
|
||||||
RETRIEVE_SYMBOL(CreateRenderTarget, rt_create_render_target_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(DestroyRenderTarget, rt_destroy_render_target_fn);
|
||||||
RETRIEVE_SYMBOL(AllocCommandBuffers, rt_alloc_command_buffers_fn);
|
RETRIEVE_SYMBOL(AllocCommandBuffers, rt_alloc_command_buffers_fn);
|
||||||
RETRIEVE_SYMBOL(SubmitCommandBuffers, rt_submit_command_buffers_fn);
|
RETRIEVE_SYMBOL(SubmitCommandBuffers, rt_submit_command_buffers_fn);
|
||||||
RETRIEVE_SYMBOL(CreateSemaphores, rt_create_gpu_semaphores_fn);
|
RETRIEVE_SYMBOL(CreateSemaphores, rt_create_gpu_semaphores_fn);
|
||||||
RETRIEVE_SYMBOL(DestroySemaphores, rt_destroy_gpu_semaphores_fn);
|
RETRIEVE_SYMBOL(DestroySemaphores, rt_destroy_gpu_semaphores_fn);
|
||||||
RETRIEVE_SYMBOL(GetSemaphoreValue, rt_get_gpu_semaphore_value_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 {
|
} else {
|
||||||
rtReportError("GFX",
|
rtReportError("GFX",
|
||||||
"Unsupported renderer backend: (%s) %s",
|
"Unsupported renderer backend: (%s) %s",
|
||||||
@ -96,12 +107,16 @@ static bool LoadRenderer(void) {
|
|||||||
g_renderer.CompilePipeline = &rtRenCompilePipeline;
|
g_renderer.CompilePipeline = &rtRenCompilePipeline;
|
||||||
g_renderer.DestroyPipeline = &rtRenDestroyPipeline;
|
g_renderer.DestroyPipeline = &rtRenDestroyPipeline;
|
||||||
g_renderer.CreateRenderTarget = &rtRenCreateRenderTarget;
|
g_renderer.CreateRenderTarget = &rtRenCreateRenderTarget;
|
||||||
|
g_renderer.GetSwapchainRenderTarget = &rtRenGetSwapchainRenderTarget;
|
||||||
g_renderer.DestroyRenderTarget = &rtRenDestroyRenderTarget;
|
g_renderer.DestroyRenderTarget = &rtRenDestroyRenderTarget;
|
||||||
g_renderer.AllocCommandBuffers = &rtRenAllocCommandBuffers;
|
g_renderer.AllocCommandBuffers = &rtRenAllocCommandBuffers;
|
||||||
g_renderer.SubmitCommandBuffers = &rtRenSubmitCommandBuffers;
|
g_renderer.SubmitCommandBuffers = &rtRenSubmitCommandBuffers;
|
||||||
g_renderer.CreateSemaphores = &rtRenCreateSemaphores;
|
g_renderer.CreateSemaphores = &rtRenCreateSemaphores;
|
||||||
g_renderer.DestroySemaphores = &rtRenDestroySemaphores;
|
g_renderer.DestroySemaphores = &rtRenDestroySemaphores;
|
||||||
g_renderer.GetSemaphoreValue = &rtRenGetSemaphoreValue;
|
g_renderer.GetSemaphoreValue = &rtRenGetSemaphoreValue;
|
||||||
|
g_renderer.CmdBeginPass = &rtRenCmdBeginPass;
|
||||||
|
g_renderer.CmdEndPass = &rtRenCmdEndPass;
|
||||||
|
g_renderer.CmdTransitionRenderTarget = &rtRenCmdTransitionRenderTarget;
|
||||||
#endif
|
#endif
|
||||||
return true;
|
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 <stddef.h>
|
||||||
|
|
||||||
#include "gfx.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
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -134,6 +136,51 @@ typedef struct {
|
|||||||
uint64_t initial_value;
|
uint64_t initial_value;
|
||||||
} rt_gpu_semaphore_info;
|
} 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 */
|
/* Renderer API */
|
||||||
|
|
||||||
typedef void rt_register_renderer_cvars_fn(void);
|
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 rt_pipeline_handle rt_compile_pipeline_fn(const rt_pipeline_info *info);
|
||||||
typedef void rt_destroy_pipeline_fn(rt_pipeline_handle handle);
|
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_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 void rt_destroy_render_target_fn(rt_render_target_handle handle);
|
||||||
typedef rt_result rt_alloc_command_buffers_fn(uint32_t count,
|
typedef rt_result rt_alloc_command_buffers_fn(uint32_t count,
|
||||||
const rt_alloc_command_buffer_info *info,
|
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 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 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 {
|
typedef struct {
|
||||||
rt_register_renderer_cvars_fn *RegisterCVars;
|
rt_register_renderer_cvars_fn *RegisterCVars;
|
||||||
rt_init_renderer_fn *Init;
|
rt_init_renderer_fn *Init;
|
||||||
@ -165,12 +220,18 @@ typedef struct {
|
|||||||
rt_compile_pipeline_fn *CompilePipeline;
|
rt_compile_pipeline_fn *CompilePipeline;
|
||||||
rt_destroy_pipeline_fn *DestroyPipeline;
|
rt_destroy_pipeline_fn *DestroyPipeline;
|
||||||
rt_create_render_target_fn *CreateRenderTarget;
|
rt_create_render_target_fn *CreateRenderTarget;
|
||||||
|
rt_get_swapchain_render_target_fn *GetSwapchainRenderTarget;
|
||||||
rt_destroy_render_target_fn *DestroyRenderTarget;
|
rt_destroy_render_target_fn *DestroyRenderTarget;
|
||||||
rt_alloc_command_buffers_fn *AllocCommandBuffers;
|
rt_alloc_command_buffers_fn *AllocCommandBuffers;
|
||||||
rt_submit_command_buffers_fn *SubmitCommandBuffers;
|
rt_submit_command_buffers_fn *SubmitCommandBuffers;
|
||||||
rt_create_gpu_semaphores_fn *CreateSemaphores;
|
rt_create_gpu_semaphores_fn *CreateSemaphores;
|
||||||
rt_destroy_gpu_semaphores_fn *DestroySemaphores;
|
rt_destroy_gpu_semaphores_fn *DestroySemaphores;
|
||||||
rt_get_gpu_semaphore_value_fn *GetSemaphoreValue;
|
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;
|
} rt_renderer_api;
|
||||||
|
|
||||||
#define RT_RENDERER_API_FN(name) RT_DLLEXPORT rtRen##name
|
#define RT_RENDERER_API_FN(name) RT_DLLEXPORT rtRen##name
|
@ -1,5 +1,7 @@
|
|||||||
subdir('runtime')
|
subdir('runtime')
|
||||||
subdir('asset_compiler')
|
subdir('asset_compiler')
|
||||||
|
subdir('gfx')
|
||||||
|
subdir('app_framework')
|
||||||
|
|
||||||
# Renderer libs
|
# Renderer libs
|
||||||
subdir('renderer/vk')
|
subdir('renderer/vk')
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
|
|
||||||
#include "runtime/atomics.h"
|
#include "runtime/atomics.h"
|
||||||
#include "runtime/config.h"
|
#include "runtime/config.h"
|
||||||
|
#include "runtime/handles.h"
|
||||||
#include "runtime/mem_arena.h"
|
#include "runtime/mem_arena.h"
|
||||||
#include "runtime/renderer_api.h"
|
|
||||||
#include "runtime/runtime.h"
|
#include "runtime/runtime.h"
|
||||||
|
|
||||||
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
RT_CVAR_I(rt_VkMaxCommandPools,
|
RT_CVAR_I(rt_VkMaxCommandPools,
|
||||||
@ -54,8 +56,10 @@ rt_result InitCommandBufferManagement(void) {
|
|||||||
return RT_OUT_OF_MEMORY;
|
return RT_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep 0 free as a "Not initialized" value for t_first_pool */
|
/* We keep 0 free as a "Not initialized" value for t_first_pool.
|
||||||
_next_pools = 1;
|
* The atomicinc used to acquire a pool returns the incremented value, so 0 is never returned.
|
||||||
|
*/
|
||||||
|
_next_pools = 0;
|
||||||
return RT_SUCCESS;
|
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)
|
if ((int)t_first_pool >= rt_VkMaxCommandPools.i)
|
||||||
return RT_OUT_OF_MEMORY;
|
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;
|
rt_result result = RT_SUCCESS;
|
||||||
|
|
||||||
/* TODO: We should probably batch allocations of the same type */
|
/* 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;
|
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;
|
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 =
|
VkSemaphoreSubmitInfo *wait_semaphores =
|
||||||
RT_ARENA_PUSH_ARRAY(temp.arena, VkSemaphoreSubmitInfo, info->wait_semaphore_count);
|
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;
|
result = RT_OUT_OF_MEMORY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
VkSemaphoreSubmitInfo *signal_semaphores =
|
VkSemaphoreSubmitInfo *signal_semaphores =
|
||||||
RT_ARENA_PUSH_ARRAY(temp.arena, VkSemaphoreSubmitInfo, info->signal_semaphore_count);
|
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;
|
result = RT_OUT_OF_MEMORY;
|
||||||
goto out;
|
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) {
|
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) {
|
if (_command_buffers[slot].version != info->command_buffers[i].version) {
|
||||||
rtLog("vk",
|
rtLog("vk",
|
||||||
"Mismatch between handle version and stored version while submitting a command "
|
"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].pNext = NULL;
|
||||||
command_buffers[i].deviceMask = 0;
|
command_buffers[i].deviceMask = 0;
|
||||||
command_buffers[i].commandBuffer = _command_buffers[slot].command_buffer;
|
command_buffers[i].commandBuffer = _command_buffers[slot].command_buffer;
|
||||||
|
|
||||||
|
vkEndCommandBuffer(command_buffers[i].commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSubmitInfo2 submit_info = {
|
VkSubmitInfo2 submit_info = {
|
||||||
@ -315,3 +332,123 @@ out:
|
|||||||
rtReturnTemporaryArena(temp);
|
rtReturnTemporaryArena(temp);
|
||||||
return result;
|
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
|
#ifndef RT_COMMAND_BUFFERS_H
|
||||||
#define RT_COMMAND_BUFFERS_H
|
#define RT_COMMAND_BUFFERS_H
|
||||||
|
|
||||||
|
#include "gfx/renderer_api.h"
|
||||||
#include "runtime/runtime.h"
|
#include "runtime/runtime.h"
|
||||||
|
|
||||||
|
#include <volk/volk.h>
|
||||||
|
|
||||||
void rtResetCommandPools(unsigned int frame_id);
|
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
|
#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 "command_buffers.h"
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
|
#include "render_targets.h"
|
||||||
#include "swapchain.h"
|
#include "swapchain.h"
|
||||||
|
|
||||||
#include "runtime/renderer_api.h"
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
#define ONE_SECOND_NS 1000000000u
|
#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.");
|
rtReportError("vk", "Failed to recreate the swapchain.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
rtUpdateSwapchainRenderTarget();
|
||||||
|
rtUpdateRenderTargetsFromSwapchain(g_swapchain.image_count,
|
||||||
|
g_swapchain.format,
|
||||||
|
g_swapchain.extent);
|
||||||
rtRenBeginFrame(frame_id);
|
rtRenBeginFrame(frame_id);
|
||||||
} else if (acquire_res != VK_SUCCESS) {
|
} else if (acquire_res != VK_SUCCESS) {
|
||||||
rtReportError("vk", "vkAcquireNextImageKHR failed: %u", acquire_res);
|
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;
|
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 = {
|
VkPresentInfoKHR present_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||||
.pImageIndices = &image_index,
|
.pImageIndices = &image_index,
|
||||||
.pSwapchains = &g_swapchain.swapchain,
|
.pSwapchains = &g_swapchain.swapchain,
|
||||||
.swapchainCount = 1,
|
.swapchainCount = 1,
|
||||||
.pWaitSemaphores = &frame->image_available,
|
.pWaitSemaphores = &frame->render_finished,
|
||||||
.waitSemaphoreCount = 1,
|
.waitSemaphoreCount = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#define VMA_DYNAMI_VULKAN_FUNCTIONS 0
|
#define VMA_DYNAMI_VULKAN_FUNCTIONS 0
|
||||||
#include <vma/vk_mem_alloc.h>
|
#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 */
|
/* Minimum supported value of g_gpu.max_frames_in_flight */
|
||||||
#define RT_VK_MIN_SUPPORTED_FRAMES_IN_FLIGHT 2
|
#define RT_VK_MIN_SUPPORTED_FRAMES_IN_FLIGHT 2
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
|
|
||||||
#include "runtime/renderer_api.h"
|
|
||||||
#include "runtime/config.h"
|
#include "runtime/config.h"
|
||||||
#include "runtime/threading.h"
|
#include "runtime/threading.h"
|
||||||
#include "runtime/handles.h"
|
#include "runtime/handles.h"
|
||||||
|
|
||||||
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
RT_CVAR_I(rt_VkMaxSemaphores, "Maximum number of semaphores. Default: 1024", 1024);
|
RT_CVAR_I(rt_VkMaxSemaphores, "Maximum number of semaphores. Default: 1024", 1024);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
|
|
||||||
#include "runtime/renderer_api.h"
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
VkSemaphore rtGetSemaphore(rt_gpu_semaphore_handle handle);
|
VkSemaphore rtGetSemaphore(rt_gpu_semaphore_handle handle);
|
||||||
|
|
||||||
|
@ -5,13 +5,15 @@
|
|||||||
|
|
||||||
#define RT_VK_DONT_DEFINE_GPU_GLOBAL
|
#define RT_VK_DONT_DEFINE_GPU_GLOBAL
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
|
#include "render_targets.h"
|
||||||
#include "swapchain.h"
|
#include "swapchain.h"
|
||||||
|
|
||||||
#include "runtime/config.h"
|
#include "runtime/config.h"
|
||||||
#include "runtime/renderer_api.h"
|
|
||||||
#include "runtime/runtime.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,
|
RT_CVAR_I(r_VkEnableAPIAllocTracking,
|
||||||
"Enable tracking of allocations done by the vulkan api. [0/1] Default: 0",
|
"Enable tracking of allocations done by the vulkan api. [0/1] Default: 0",
|
||||||
@ -78,7 +80,16 @@ DebugUtilsMessengerCb(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
|||||||
VkDebugUtilsMessageTypeFlagsEXT types,
|
VkDebugUtilsMessageTypeFlagsEXT types,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT *callbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT *callbackData,
|
||||||
void *userData) {
|
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;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +271,6 @@ static rt_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev, VkSurfac
|
|||||||
static bool CheckDeviceExtensionSupported(VkPhysicalDevice phys_dev) {
|
static bool CheckDeviceExtensionSupported(VkPhysicalDevice phys_dev) {
|
||||||
const char *required_extensions[] = {
|
const char *required_extensions[] = {
|
||||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||||
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t extension_count;
|
uint32_t extension_count;
|
||||||
@ -318,8 +328,16 @@ static rt_result ChoosePhysicalDevice(void) {
|
|||||||
uint32_t highscore = 0;
|
uint32_t highscore = 0;
|
||||||
uint32_t best_index = phys_device_count;
|
uint32_t best_index = phys_device_count;
|
||||||
for (uint32_t i = 0; i < phys_device_count; ++i) {
|
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 = {
|
VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
|
||||||
|
.pNext = &dynamic_rendering_features,
|
||||||
};
|
};
|
||||||
VkPhysicalDeviceFeatures2 features = {
|
VkPhysicalDeviceFeatures2 features = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||||
@ -345,6 +363,10 @@ static rt_result ChoosePhysicalDevice(void) {
|
|||||||
indices.graphics == UINT32_MAX)
|
indices.graphics == UINT32_MAX)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!synchronization2_features.synchronization2 ||
|
||||||
|
!dynamic_rendering_features.dynamicRendering)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Check for bindless support */
|
/* Check for bindless support */
|
||||||
if (!descriptor_indexing_features.runtimeDescriptorArray ||
|
if (!descriptor_indexing_features.runtimeDescriptorArray ||
|
||||||
!descriptor_indexing_features.descriptorBindingPartiallyBound)
|
!descriptor_indexing_features.descriptorBindingPartiallyBound)
|
||||||
@ -461,9 +483,16 @@ static rt_result CreateDevice(void) {
|
|||||||
queue_info[distinct_queue_count].pQueuePriorities = &priority;
|
queue_info[distinct_queue_count].pQueuePriorities = &priority;
|
||||||
++distinct_queue_count;
|
++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 = {
|
VkPhysicalDeviceDescriptorIndexingFeatures indexing_features = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_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,
|
VkPhysicalDeviceFeatures2 features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||||
.pNext = &indexing_features};
|
.pNext = &indexing_features};
|
||||||
@ -523,6 +552,8 @@ static rt_result CreateAllocator(void) {
|
|||||||
SET_KHR_FNC(vkBindBufferMemory2);
|
SET_KHR_FNC(vkBindBufferMemory2);
|
||||||
SET_KHR_FNC(vkBindImageMemory2);
|
SET_KHR_FNC(vkBindImageMemory2);
|
||||||
SET_KHR_FNC(vkGetPhysicalDeviceMemoryProperties2);
|
SET_KHR_FNC(vkGetPhysicalDeviceMemoryProperties2);
|
||||||
|
SET_FNC(vkGetDeviceBufferMemoryRequirements);
|
||||||
|
SET_FNC(vkGetDeviceImageMemoryRequirements);
|
||||||
#undef SET_FNC
|
#undef SET_FNC
|
||||||
#undef SET_KHR_FNC
|
#undef SET_KHR_FNC
|
||||||
|
|
||||||
@ -630,6 +661,7 @@ rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) {
|
|||||||
res = rtCreateSwapchain();
|
res = rtCreateSwapchain();
|
||||||
if (res != RT_SUCCESS)
|
if (res != RT_SUCCESS)
|
||||||
return res;
|
return res;
|
||||||
|
rtUpdateSwapchainRenderTarget();
|
||||||
|
|
||||||
return RT_SUCCESS;
|
return RT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ if vk_dep.found()
|
|||||||
'swapchain.h',
|
'swapchain.h',
|
||||||
|
|
||||||
'command_buffers.c',
|
'command_buffers.c',
|
||||||
|
'commands.c',
|
||||||
'frame.c',
|
'frame.c',
|
||||||
'gpu_sync.c',
|
'gpu_sync.c',
|
||||||
'helper.c',
|
'helper.c',
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#include "runtime/config.h"
|
#include "runtime/config.h"
|
||||||
#include "runtime/handles.h"
|
#include "runtime/handles.h"
|
||||||
#include "runtime/mem_arena.h"
|
#include "runtime/mem_arena.h"
|
||||||
#include "runtime/renderer_api.h"
|
|
||||||
#include "runtime/resources.h"
|
#include "runtime/resources.h"
|
||||||
#include "runtime/threading.h"
|
#include "runtime/threading.h"
|
||||||
|
|
||||||
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
#include "pipelines.h"
|
#include "pipelines.h"
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
|
|
||||||
#include "runtime/renderer_api.h"
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VkPipeline pipeline;
|
VkPipeline pipeline;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include "runtime/config.h"
|
#include "runtime/config.h"
|
||||||
#include "runtime/renderer_api.h"
|
|
||||||
#include "runtime/threading.h"
|
#include "runtime/threading.h"
|
||||||
|
|
||||||
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
#include "render_targets.h"
|
#include "render_targets.h"
|
||||||
#include "swapchain.h"
|
#include "swapchain.h"
|
||||||
@ -21,6 +22,8 @@ static rt_render_target_slot *_render_targets;
|
|||||||
static rt_render_target_slot *_first_free;
|
static rt_render_target_slot *_first_free;
|
||||||
static rt_rwlock _lock;
|
static rt_rwlock _lock;
|
||||||
|
|
||||||
|
static rt_render_target_handle _swapchain_handle;
|
||||||
|
|
||||||
static void DestroyRenderTarget(rt_render_target_slot *slot) {
|
static void DestroyRenderTarget(rt_render_target_slot *slot) {
|
||||||
for (unsigned int i = 0; i < slot->render_target.image_count; ++i) {
|
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);
|
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)
|
g_gpu.present_family != g_gpu.compute_family)
|
||||||
queue_families[distinct_queue_families++] = g_gpu.present_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 = {
|
VkImageCreateInfo image_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||||
.imageType = VK_IMAGE_TYPE_2D,
|
.imageType = VK_IMAGE_TYPE_2D,
|
||||||
@ -124,6 +155,14 @@ rt_result InitRenderTargetManagement(void) {
|
|||||||
for (int i = 1; i < r_VkMaxRenderTargetCount.i - 1; ++i) {
|
for (int i = 1; i < r_VkMaxRenderTargetCount.i - 1; ++i) {
|
||||||
_render_targets[i].next_free = &_render_targets[i + 1];
|
_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;
|
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.format = g_swapchain.format;
|
||||||
slot->render_target.match_swapchain |= RT_RENDER_TARGET_MATCH_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 |
|
slot->render_target.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
|
||||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
if (info->format == RT_PIXEL_FORMAT_DEPTH32)
|
||||||
slot->render_target.aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
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 {
|
} else {
|
||||||
slot->render_target.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
slot->render_target.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
|
||||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
|
||||||
slot->render_target.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
slot->render_target.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
}
|
}
|
||||||
slot->render_target.sample_count = rtSampleCountToFlags(info->sample_count);
|
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);
|
DestroyRenderTarget(slot);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
slot->render_target.states[i] = RT_RENDER_TARGET_STATE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle.version = slot->version;
|
handle.version = slot->version;
|
||||||
@ -207,6 +250,10 @@ out:
|
|||||||
return handle;
|
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) {
|
void RT_RENDERER_API_FN(DestroyRenderTarget)(rt_render_target_handle handle) {
|
||||||
if (handle.index >= (uint32_t)r_VkMaxRenderTargetCount.i)
|
if (handle.index >= (uint32_t)r_VkMaxRenderTargetCount.i)
|
||||||
return;
|
return;
|
||||||
@ -231,6 +278,25 @@ rt_render_target *rtGetRenderTarget(rt_render_target_handle handle) {
|
|||||||
return res;
|
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) {
|
void rtUpdateRenderTargetsFromSwapchain(uint32_t image_count, VkFormat format, VkExtent2D extent) {
|
||||||
rtLockWrite(&_lock);
|
rtLockWrite(&_lock);
|
||||||
for (uint32_t i = 1; i < (uint32_t)r_VkMaxRenderTargetCount.i; ++i) {
|
for (uint32_t i = 1; i < (uint32_t)r_VkMaxRenderTargetCount.i; ++i) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define RT_VK_RENDER_TARGETS_H
|
#define RT_VK_RENDER_TARGETS_H
|
||||||
|
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
#include "runtime/renderer_api.h"
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
/* Must match RT_VK_MAX_SWAPCHAIN_IMAGES */
|
/* Must match RT_VK_MAX_SWAPCHAIN_IMAGES */
|
||||||
#define RT_VK_RENDER_TARGET_MAX_IMAGES 3
|
#define RT_VK_RENDER_TARGET_MAX_IMAGES 3
|
||||||
@ -16,6 +16,7 @@ typedef struct {
|
|||||||
VkImage image[RT_VK_RENDER_TARGET_MAX_IMAGES];
|
VkImage image[RT_VK_RENDER_TARGET_MAX_IMAGES];
|
||||||
VkImageView view[RT_VK_RENDER_TARGET_MAX_IMAGES];
|
VkImageView view[RT_VK_RENDER_TARGET_MAX_IMAGES];
|
||||||
VmaAllocation allocation[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;
|
VkSampleCountFlagBits sample_count;
|
||||||
VkFormat format;
|
VkFormat format;
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
@ -27,6 +28,10 @@ typedef struct {
|
|||||||
|
|
||||||
rt_render_target *rtGetRenderTarget(rt_render_target_handle handle);
|
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);
|
void rtUpdateRenderTargetsFromSwapchain(uint32_t image_count, VkFormat format, VkExtent2D extent);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,7 +4,6 @@ runtime_incdirs = include_directories(meson.project_source_root() / 'contrib')
|
|||||||
runtime_lib = library('rt',
|
runtime_lib = library('rt',
|
||||||
# Project Sources
|
# Project Sources
|
||||||
'aio.h',
|
'aio.h',
|
||||||
'app.h',
|
|
||||||
'atomics.h',
|
'atomics.h',
|
||||||
'buffer_manager.h',
|
'buffer_manager.h',
|
||||||
'compression.h',
|
'compression.h',
|
||||||
@ -13,20 +12,15 @@ runtime_lib = library('rt',
|
|||||||
'dynamic_libs.h',
|
'dynamic_libs.h',
|
||||||
'file_tab.h',
|
'file_tab.h',
|
||||||
'fsutils.h',
|
'fsutils.h',
|
||||||
'gfx.h',
|
|
||||||
'handles.h',
|
'handles.h',
|
||||||
'hashing.h',
|
'hashing.h',
|
||||||
'jobs.h',
|
'jobs.h',
|
||||||
'main_loop.h',
|
|
||||||
'mem_arena.h',
|
'mem_arena.h',
|
||||||
'render_list.h',
|
|
||||||
'renderer_api.h',
|
|
||||||
'resources.h',
|
'resources.h',
|
||||||
'runtime.h',
|
'runtime.h',
|
||||||
'threading.h',
|
'threading.h',
|
||||||
|
|
||||||
'aio.c',
|
'aio.c',
|
||||||
'app.c',
|
|
||||||
'assert.c',
|
'assert.c',
|
||||||
'buffer_manager.c',
|
'buffer_manager.c',
|
||||||
'compression.c',
|
'compression.c',
|
||||||
@ -36,12 +30,9 @@ runtime_lib = library('rt',
|
|||||||
'error_report.c',
|
'error_report.c',
|
||||||
'file_tab.c',
|
'file_tab.c',
|
||||||
'fsutils.c',
|
'fsutils.c',
|
||||||
'gfx_framegraph.c',
|
|
||||||
'gfx_main.c',
|
|
||||||
'hashing.c',
|
'hashing.c',
|
||||||
'init.c',
|
'init.c',
|
||||||
'jobs.c',
|
'jobs.c',
|
||||||
'main_loop.c',
|
|
||||||
'mem_arena.c',
|
'mem_arena.c',
|
||||||
'resource_manager.c',
|
'resource_manager.c',
|
||||||
'sprint.c',
|
'sprint.c',
|
||||||
|
@ -7,10 +7,11 @@
|
|||||||
#include "fsutils.h"
|
#include "fsutils.h"
|
||||||
#include "hashing.h"
|
#include "hashing.h"
|
||||||
#include "mem_arena.h"
|
#include "mem_arena.h"
|
||||||
#include "renderer_api.h"
|
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "threading.h"
|
#include "threading.h"
|
||||||
|
|
||||||
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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