Skip to content

Commit

Permalink
rt: postpone blas building until tlas
Browse files Browse the repository at this point in the history
I don't like this. But it works. Let's save it as a reference for a proper future refactoring.
  • Loading branch information
w23 committed Apr 7, 2023
1 parent 1494dba commit 260d208
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 76 deletions.
95 changes: 68 additions & 27 deletions ref/vk/vk_ray_accel.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "vk_rtx.h"
#include "vk_ray_internal.h"
#include "r_speeds.h"
#include "vk_combuf.h"

#define MAX_SCRATCH_BUFFER (32*1024*1024)
#define MAX_ACCELS_BUFFER (64*1024*1024)
Expand All @@ -26,7 +27,7 @@ static VkDeviceAddress getASAddress(VkAccelerationStructureKHR as) {
}

// TODO split this into smaller building blocks in a separate module
qboolean createOrUpdateAccelerationStructure(VkCommandBuffer cmdbuf, const as_build_args_t *args, vk_ray_model_t *model) {
qboolean createOrUpdateAccelerationStructure(vk_combuf_t *cb, const as_build_args_t *args, vk_ray_model_t *model) {
qboolean should_create = *args->p_accel == VK_NULL_HANDLE;
#if 1 // update does not work at all on AMD gpus
qboolean is_update = false; // FIXME this crashes for some reason !should_create && args->dynamic;
Expand Down Expand Up @@ -105,7 +106,7 @@ qboolean createOrUpdateAccelerationStructure(VkCommandBuffer cmdbuf, const as_bu
}

// If not enough data for building, just create
if (!cmdbuf || !args->build_ranges)
if (!cb || !args->build_ranges)
return true;

if (model) {
Expand All @@ -121,11 +122,18 @@ qboolean createOrUpdateAccelerationStructure(VkCommandBuffer cmdbuf, const as_bu
//gEngine.Con_Reportf("AS=%p, n_geoms=%u, scratch: %#x %d %#x\n", *args->p_accel, args->n_geoms, scratch_offset_initial, scratch_buffer_size, scratch_offset_initial + scratch_buffer_size);

g_accel_.stats.accels_built++;
vkCmdBuildAccelerationStructuresKHR(cmdbuf, 1, &build_info, &args->build_ranges);

// TODO dynamic scope names?
static int scope_id = -2;
if (scope_id == -2)
scope_id = R_VkGpuScope_Register("BuildAS");
const int begin_index = R_VkCombufScopeBegin(cb, scope_id);
vkCmdBuildAccelerationStructuresKHR(cb->cmdbuf, 1, &build_info, &args->build_ranges);
R_VkCombufScopeEnd(cb, begin_index, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
return true;
}

static void createTlas( VkCommandBuffer cmdbuf, VkDeviceAddress instances_addr ) {
static void createTlas( vk_combuf_t *cb, VkDeviceAddress instances_addr ) {
const VkAccelerationStructureGeometryKHR tl_geom[] = {
{
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR,
Expand All @@ -146,23 +154,49 @@ static void createTlas( VkCommandBuffer cmdbuf, VkDeviceAddress instances_addr )
const as_build_args_t asrgs = {
.geoms = tl_geom,
.max_prim_counts = tl_max_prim_counts,
.build_ranges = cmdbuf == VK_NULL_HANDLE ? NULL : &tl_build_range,
.build_ranges = !cb ? NULL : &tl_build_range,
.n_geoms = COUNTOF(tl_geom),
.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR,
// we can't really rebuild TLAS because instance count changes are not allowed .dynamic = true,
.dynamic = false,
.p_accel = &g_accel.tlas,
.debug_name = "TLAS",
};
if (!createOrUpdateAccelerationStructure(cmdbuf, &asrgs, NULL)) {
if (!createOrUpdateAccelerationStructure(cb, &asrgs, NULL)) {
gEngine.Host_Error("Could not create/update TLAS\n");
return;
}
}

void RT_VkAccelPrepareTlas(VkCommandBuffer cmdbuf) {
static qboolean buildBLAS( vk_combuf_t *cb, vk_ray_model_t *rm) {
DEBUG_BEGINF(cb->cmdbuf, "build blas for %s", rm->build.name);
const qboolean result = createOrUpdateAccelerationStructure(cb, &rm->build.args, rm);
DEBUG_END(cb->cmdbuf);

Mem_Free(rm->build.geom_build_ranges);
rm->build.geom_build_ranges = NULL;
Mem_Free(rm->build.geom_max_prim_counts);
rm->build.geom_max_prim_counts = NULL;
Mem_Free(rm->build.geoms); // TODO this can be cached within models_cache ??
rm->build.geoms = NULL;

if (!result)
{
gEngine.Con_Printf(S_ERROR "Could not build BLAS for %s\n", rm->build.name);
//returnModelToCache(rm);
return false;
}

/* if (vk_core.debug) */
/* validateModel(rm); */

//gEngine.Con_Reportf("Model %s (%p) created blas %p\n", args.model->debug_name, args.model, args.model->rtx.blas);
return true;
}

void RT_VkAccelPrepareTlas(vk_combuf_t *cb) {
ASSERT(g_ray_model_state.frame.num_models > 0);
DEBUG_BEGIN(cmdbuf, "prepare tlas");
DEBUG_BEGIN(cb->cmdbuf, "prepare tlas");

R_FlippingBuffer_Flip( &g_accel.tlas_geom_buffer_alloc );

Expand All @@ -172,38 +206,45 @@ void RT_VkAccelPrepareTlas(VkCommandBuffer cmdbuf) {
// Upload all blas instances references to GPU mem
{
VkAccelerationStructureInstanceKHR* inst = ((VkAccelerationStructureInstanceKHR*)g_accel.tlas_geom_buffer.mapped) + instance_offset;
for (int i = 0; i < g_ray_model_state.frame.num_models; ++i) {
const vk_ray_draw_model_t* const model = g_ray_model_state.frame.models + i;
for (int index = 0, mi = 0; mi < g_ray_model_state.frame.num_models; ++mi) {
const vk_ray_draw_model_t* const model = g_ray_model_state.frame.models + mi;
ASSERT(model->model);

if (model->model->build.geom_build_ranges) {
if (!buildBLAS(cb, model->model))
continue;
}

ASSERT(model->model->as != VK_NULL_HANDLE);
inst[i] = (VkAccelerationStructureInstanceKHR){
inst[index] = (VkAccelerationStructureInstanceKHR){
.instanceCustomIndex = model->model->kusochki_offset,
.instanceShaderBindingTableRecordOffset = 0,
.accelerationStructureReference = getASAddress(model->model->as), // TODO cache this addr
};
switch (model->material_mode) {
case MaterialMode_Opaque:
inst[i].mask = GEOMETRY_BIT_OPAQUE;
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_REGULAR,
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR;
inst[index].mask = GEOMETRY_BIT_OPAQUE;
inst[index].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_REGULAR,
inst[index].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR;
break;
case MaterialMode_Opaque_AlphaTest:
inst[i].mask = GEOMETRY_BIT_ALPHA_TEST;
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_ALPHA_TEST,
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR;
inst[index].mask = GEOMETRY_BIT_ALPHA_TEST;
inst[index].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_ALPHA_TEST,
inst[index].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR;
break;
case MaterialMode_Refractive:
inst[i].mask = GEOMETRY_BIT_REFRACTIVE;
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_REGULAR,
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR;
inst[index].mask = GEOMETRY_BIT_REFRACTIVE;
inst[index].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_REGULAR,
inst[index].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR;
break;
case MaterialMode_Additive:
inst[i].mask = GEOMETRY_BIT_ADDITIVE;
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_ADDITIVE,
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR;
inst[index].mask = GEOMETRY_BIT_ADDITIVE;
inst[index].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_ADDITIVE,
inst[index].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR;
break;
}
memcpy(&inst[i].transform, model->transform_row, sizeof(VkTransformMatrixKHR));
memcpy(&inst[index].transform, model->transform_row, sizeof(VkTransformMatrixKHR));
++index;
}
}

Expand All @@ -220,15 +261,15 @@ void RT_VkAccelPrepareTlas(VkCommandBuffer cmdbuf) {
.offset = instance_offset * sizeof(VkAccelerationStructureInstanceKHR),
.size = g_ray_model_state.frame.num_models * sizeof(VkAccelerationStructureInstanceKHR),
} };
vkCmdPipelineBarrier(cmdbuf,
vkCmdPipelineBarrier(cb->cmdbuf,
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
0, 0, NULL, COUNTOF(bmb), bmb, 0, NULL);
}

// 2. Build TLAS
createTlas(cmdbuf, g_accel.tlas_geom_buffer_addr + instance_offset * sizeof(VkAccelerationStructureInstanceKHR));
DEBUG_END(cmdbuf);
createTlas(cb, g_accel.tlas_geom_buffer_addr + instance_offset * sizeof(VkAccelerationStructureInstanceKHR));
DEBUG_END(cb->cmdbuf);
}

qboolean RT_VkAccelInit(void) {
Expand Down
4 changes: 3 additions & 1 deletion ref/vk/vk_ray_accel.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ qboolean RT_VkAccelInit(void);
void RT_VkAccelShutdown(void);
void RT_VkAccelNewMap(void);
void RT_VkAccelFrameBegin(void);
void RT_VkAccelPrepareTlas(VkCommandBuffer cmdbuf);

struct vk_combuf_s;
void RT_VkAccelPrepareTlas(struct vk_combuf_s *cb);
33 changes: 21 additions & 12 deletions ref/vk/vk_ray_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@

#include "shaders/ray_interop.h"

typedef struct {
const char *debug_name;
VkAccelerationStructureKHR *p_accel;
const VkAccelerationStructureGeometryKHR *geoms;
const uint32_t *max_prim_counts;
const VkAccelerationStructureBuildRangeInfoKHR *build_ranges;
uint32_t n_geoms;
VkAccelerationStructureTypeKHR type;
qboolean dynamic;
} as_build_args_t;

typedef struct vk_ray_model_s {
VkAccelerationStructureKHR as;
VkAccelerationStructureGeometryKHR *geoms;
Expand All @@ -24,6 +35,14 @@ typedef struct vk_ray_model_s {
struct {
uint32_t as_offset;
} debug;

struct {
const char *name;
as_build_args_t args;
VkAccelerationStructureBuildRangeInfoKHR *geom_build_ranges;
uint32_t *geom_max_prim_counts;
VkAccelerationStructureGeometryKHR *geoms;
} build;
} vk_ray_model_t;

typedef struct Kusok vk_kusok_data_t;
Expand All @@ -40,18 +59,8 @@ typedef struct {
} material_mode;
} vk_ray_draw_model_t;

typedef struct {
const char *debug_name;
VkAccelerationStructureKHR *p_accel;
const VkAccelerationStructureGeometryKHR *geoms;
const uint32_t *max_prim_counts;
const VkAccelerationStructureBuildRangeInfoKHR *build_ranges;
uint32_t n_geoms;
VkAccelerationStructureTypeKHR type;
qboolean dynamic;
} as_build_args_t;

qboolean createOrUpdateAccelerationStructure(VkCommandBuffer cmdbuf, const as_build_args_t *args, vk_ray_model_t *model);
struct vk_combuf_s;
qboolean createOrUpdateAccelerationStructure(struct vk_combuf_s *cb, const as_build_args_t *args, vk_ray_model_t *model);

typedef struct {
// Geometry metadata. Lifetime is similar to geometry lifetime itself.
Expand Down
83 changes: 48 additions & 35 deletions ref/vk/vk_ray_model.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "vk_staging.h"
#include "vk_light.h"
#include "vk_math.h"
#include "vk_combuf.h"

#include "eiface.h"
#include "xash3d_mathlib.h"
Expand Down Expand Up @@ -213,7 +214,6 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
VkAccelerationStructureBuildRangeInfoKHR *geom_build_ranges;
const VkDeviceAddress buffer_addr = R_VkBufferGetDeviceAddress(args.buffer); // TODO pass in args/have in buffer itself
const uint32_t kusochki_count_offset = R_DEBuffer_Alloc(&g_ray_model_state.kusochki_alloc, args.model->dynamic ? LifetimeDynamic : LifetimeStatic, args.model->num_geometries, 1);
vk_ray_model_t *ray_model;
int max_prims = 0;

ASSERT(vk_core.rtx);
Expand Down Expand Up @@ -352,49 +352,62 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
}

{
as_build_args_t asrgs = {
.geoms = geoms,
.max_prim_counts = geom_max_prim_counts,
.build_ranges = geom_build_ranges,
.n_geoms = args.model->num_geometries,
.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR,
.dynamic = args.model->dynamic,
.debug_name = args.model->debug_name,
};
ray_model = getModelFromCache(args.model->num_geometries, max_prims, geoms); //, build_size.accelerationStructureSize);
vk_ray_model_t *const ray_model = getModelFromCache(args.model->num_geometries, max_prims, geoms); //, build_size.accelerationStructureSize);
if (!ray_model) {
gEngine.Con_Printf(S_ERROR "Ran out of model cache slots\n");
Mem_Free(geom_build_ranges);
Mem_Free(geom_max_prim_counts);
Mem_Free(geoms); // TODO this can be cached within models_cache ??
return NULL;
} else {
qboolean result;
asrgs.p_accel = &ray_model->as;
ray_model->build.args = (as_build_args_t){
.p_accel = &ray_model->as,
.geoms = geoms,
.max_prim_counts = geom_max_prim_counts,
.build_ranges = geom_build_ranges,
.n_geoms = args.model->num_geometries,
.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR,
.dynamic = args.model->dynamic,
.debug_name = args.model->debug_name,
};
ray_model->build.geom_build_ranges = geom_build_ranges;
ray_model->build.geoms = geoms;
ray_model->build.geom_max_prim_counts = geom_max_prim_counts;
ray_model->build.name = args.model->debug_name;

ray_model->kusochki_offset = kusochki_count_offset;
ray_model->dynamic = args.model->dynamic;
ray_model->kusochki_updated_this_frame = true;
}

DEBUG_BEGINF(cmdbuf, "build blas for %s", args.model->debug_name);
result = createOrUpdateAccelerationStructure(cmdbuf, &asrgs, ray_model);
DEBUG_END(cmdbuf);
return ray_model;
}
}

if (!result)
{
gEngine.Con_Printf(S_ERROR "Could not build BLAS for %s\n", args.model->debug_name);
returnModelToCache(ray_model);
ray_model = NULL;
} else {
ray_model->kusochki_offset = kusochki_count_offset;
ray_model->dynamic = args.model->dynamic;
ray_model->kusochki_updated_this_frame = true;
static qboolean buildBLAS( vk_combuf_t *cb, vk_ray_model_t *rm) {
DEBUG_BEGINF(cb->cmdbuf, "build blas for %s", rm->build.name);
const qboolean result = createOrUpdateAccelerationStructure(cb, &rm->build.args, rm);
DEBUG_END(cb->cmdbuf);

if (vk_core.debug)
validateModel(ray_model);
}
}
Mem_Free(rm->build.geom_build_ranges);
rm->build.geom_build_ranges = NULL;
Mem_Free(rm->build.geom_max_prim_counts);
rm->build.geom_max_prim_counts = NULL;
Mem_Free(rm->build.geoms); // TODO this can be cached within models_cache ??
rm->build.geoms = NULL;

if (!result)
{
gEngine.Con_Printf(S_ERROR "Could not build BLAS for %s\n", rm->build.name);
returnModelToCache(rm);
return false;
}

Mem_Free(geom_build_ranges);
Mem_Free(geom_max_prim_counts);
Mem_Free(geoms); // TODO this can be cached within models_cache ??
if (vk_core.debug)
validateModel(rm);

//gEngine.Con_Reportf("Model %s (%p) created blas %p\n", args.model->debug_name, args.model, args.model->rtx.blas);

return ray_model;
return true;
}

void VK_RayModelDestroy( struct vk_ray_model_s *model ) {
Expand Down Expand Up @@ -455,7 +468,7 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render
}

{
ASSERT(model->as != VK_NULL_HANDLE);
//ASSERT(model->as != VK_NULL_HANDLE);
draw_model->model = model;
memcpy(draw_model->transform_row, *transform_row, sizeof(draw_model->transform_row));
}
Expand Down
2 changes: 1 addition & 1 deletion ref/vk/vk_rtx.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ static void performTracing( vk_combuf_t *combuf, const perform_tracing_args_t* a
}

DEBUG_BEGIN(cmdbuf, "yay tracing");
RT_VkAccelPrepareTlas(cmdbuf);
RT_VkAccelPrepareTlas(combuf);
prepareUniformBuffer(args->render_args, args->frame_index, args->fov_angle_y);

// 4. Barrier for TLAS build
Expand Down

0 comments on commit 260d208

Please sign in to comment.