From cadf3dbdfca3d5f7c62640614c20e2ee4a411585 Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Fri, 9 Jun 2023 10:03:00 -0700 Subject: [PATCH] rt: update blas for brush water Enable updating rt_blas, and use that for updating brush water models --- ref/vk/vk_brush.c | 18 +++++++++++------- ref/vk/vk_ray_accel.c | 36 ++++++++++++++---------------------- ref/vk/vk_ray_model.c | 6 ++++++ ref/vk/vk_render.c | 16 +++++++++++++--- ref/vk/vk_render.h | 10 ++++++++-- ref/vk/vk_rtx.h | 2 ++ ref/vk/vk_sprite.c | 5 +++-- ref/vk/vk_studio.c | 5 +++-- 8 files changed, 60 insertions(+), 38 deletions(-) diff --git a/ref/vk/vk_brush.c b/ref/vk/vk_brush.c index 6c94d487..ecb4b119 100644 --- a/ref/vk/vk_brush.c +++ b/ref/vk/vk_brush.c @@ -325,7 +325,7 @@ static void brushDrawWaterSurfaces( const cl_entity_t *ent, const vec4_t color, } #endif -static qboolean fillWaterSurfaces( const cl_entity_t *ent, vk_brush_model_t *bmodel, vk_render_geometry_t *geometries ) { +static void fillWaterSurfaces( const cl_entity_t *ent, vk_brush_model_t *bmodel, vk_render_geometry_t *geometries ) { ASSERT(bmodel->water.surfaces_count > 0); const r_geometry_range_lock_t geom_lock = R_GeometryRangeLock(&bmodel->water.geometry); @@ -363,7 +363,6 @@ static qboolean fillWaterSurfaces( const cl_entity_t *ent, vk_brush_model_t *bmo } R_GeometryRangeUnlock( &geom_lock ); - return true; } static qboolean isSurfaceAnimated( const msurface_t *s, const struct texture_s *base_override ) { @@ -473,10 +472,11 @@ static qboolean brushCreateWaterModel(const model_t *mod, vk_brush_model_t *bmod bmodel->water.geometry = geometry; fillWaterSurfaces(NULL, bmodel, geometries); - if (!VK_RenderModelCreate(&bmodel->water.render_model, (vk_render_model_init_t){ + if (!R_RenderModelCreate(&bmodel->water.render_model, (vk_render_model_init_t){ .name = mod->name, .geometries = geometries, .geometries_count = sizes.water_surfaces, + .dynamic = true, })) { gEngine.Con_Printf(S_ERROR "Could not create water render model for brush model %s\n", mod->name); return false; @@ -489,7 +489,10 @@ static qboolean brushCreateWaterModel(const model_t *mod, vk_brush_model_t *bmod static void brushDrawWater(vk_brush_model_t *bmodel, const cl_entity_t *ent, int render_type, const vec4_t color, const matrix4x4 transform) { ASSERT(bmodel->water.surfaces_count > 0); - // TODO update + fillWaterSurfaces(NULL, bmodel, bmodel->water.render_model.geometries); + if (!R_RenderModelUpdate(&bmodel->water.render_model)) { + gEngine.Con_Printf(S_ERROR "Failed to update brush model \"%s\" water\n", bmodel->render_model.debug_name); + } R_RenderModelDraw(&bmodel->water.render_model, (r_model_draw_t){ .render_type = render_type, @@ -948,10 +951,11 @@ static qboolean createRenderModel( const model_t *mod, vk_brush_model_t *bmodel, return false; } - if (!VK_RenderModelCreate(&bmodel->render_model, (vk_render_model_init_t){ + if (!R_RenderModelCreate(&bmodel->render_model, (vk_render_model_init_t){ .name = mod->name, .geometries = geometries, .geometries_count = sizes.num_surfaces, + .dynamic = false, })) { gEngine.Con_Printf(S_ERROR "Could not create render model for brush model %s\n", mod->name); return false; @@ -1011,13 +1015,13 @@ static void VK_BrushModelDestroy( vk_brush_model_t *bmodel ) { ASSERT(bmodel->engine_model->type == mod_brush); if (bmodel->water.surfaces_count) { - VK_RenderModelDestroy(&bmodel->water.render_model); + R_RenderModelDestroy(&bmodel->water.render_model); Mem_Free((int*)bmodel->water.surfaces_indices); Mem_Free(bmodel->water.render_model.geometries); R_GeometryRangeFree(&bmodel->water.geometry); } - VK_RenderModelDestroy(&bmodel->render_model); + R_RenderModelDestroy(&bmodel->render_model); if (bmodel->animated_indexes) Mem_Free(bmodel->animated_indexes); diff --git a/ref/vk/vk_ray_accel.c b/ref/vk/vk_ray_accel.c index 2be15745..8240fc83 100644 --- a/ref/vk/vk_ray_accel.c +++ b/ref/vk/vk_ray_accel.c @@ -105,14 +105,13 @@ static VkDeviceAddress getAccelAddress(VkAccelerationStructureKHR as) { return vkGetAccelerationStructureDeviceAddressKHR(vk_core.device, &asdai); } -static qboolean buildAccel(VkBuffer geometry_buffer, VkAccelerationStructureBuildGeometryInfoKHR *build_info, const VkAccelerationStructureBuildSizesInfoKHR *build_size, const VkAccelerationStructureBuildRangeInfoKHR *build_ranges) { +static qboolean buildAccel(VkBuffer geometry_buffer, VkAccelerationStructureBuildGeometryInfoKHR *build_info, uint32_t scratch_buffer_size, const VkAccelerationStructureBuildRangeInfoKHR *build_ranges) { // FIXME this is definitely not the right place. We should upload everything in bulk, and only then build blases in bulk too vk_combuf_t *const combuf = R_VkStagingCommit(); { const VkBufferMemoryBarrier bmb[] = { { .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - //.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, // FIXME .dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT, // FIXME .buffer = geometry_buffer, .offset = 0, // FIXME @@ -125,8 +124,7 @@ static qboolean buildAccel(VkBuffer geometry_buffer, VkAccelerationStructureBuil 0, 0, NULL, ARRAYSIZE(bmb), bmb, 0, NULL); } - // build blas - const uint32_t scratch_buffer_size = build_size->buildScratchSize; // TODO vs build_size.updateScratchSize + //gEngine.Con_Reportf("sratch offset = %d, req=%d\n", g_accel.frame.scratch_offset, scratch_buffer_size); if (MAX_SCRATCH_BUFFER < g_accel.frame.scratch_offset + scratch_buffer_size) { gEngine.Con_Printf(S_ERROR "Scratch buffer overflow: left %u bytes, but need %u\n", @@ -200,7 +198,7 @@ qboolean createOrUpdateAccelerationStructure(vk_combuf_t *combuf, const as_build build_info.dstAccelerationStructure = *args->p_accel; const VkBuffer geometry_buffer = R_GeometryBuffer_Get(); - return buildAccel(geometry_buffer, &build_info, &build_size, args->build_ranges); + return buildAccel(geometry_buffer, &build_info, build_size.buildScratchSize, args->build_ranges); } static void createTlas( vk_combuf_t *combuf, VkDeviceAddress instances_addr ) { @@ -437,16 +435,6 @@ void RT_VkAccelFrameBegin(void) { struct rt_blas_s* RT_BlasCreate(const char *name, rt_blas_usage_e usage) { rt_blas_t *blas = Mem_Calloc(vk_core.pool, sizeof(*blas)); - switch (usage) { - case kBlasBuildStatic: - break; - case kBlasBuildDynamicUpdate: - ASSERT(!"Not implemented"); - break; - case kBlasBuildDynamicFast: - break; - } - blas->debug_name = name; blas->usage = usage; blas->blas_size = -1; @@ -547,22 +535,27 @@ qboolean RT_BlasBuild(struct rt_blas_s *blas, const struct vk_render_geometry_s VkAccelerationStructureBuildGeometryInfoKHR build_info = { .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR, .type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, + .mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR, + .flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, .geometryCount = geoms_count, .srcAccelerationStructure = VK_NULL_HANDLE, }; + qboolean is_update = false; + switch (blas->usage) { case kBlasBuildStatic: ASSERT(!blas->blas); - build_info.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - build_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; break; case kBlasBuildDynamicUpdate: - ASSERT(!"Not implemented"); - return false; + if (blas->blas) { + build_info.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR; + build_info.srcAccelerationStructure = blas->blas; + is_update = true; + } + build_info.flags |= VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; break; case kBlasBuildDynamicFast: - build_info.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; build_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; break; } @@ -620,7 +613,6 @@ qboolean RT_BlasBuild(struct rt_blas_s *blas, const struct vk_render_geometry_s blas->blas_size = build_size.accelerationStructureSize; blas->max_geoms = build_info.geometryCount; - // TODO handle lifetime blas->max_prim_counts = max_prim_counts; } else { if (blas->blas_size < build_size.accelerationStructureSize) { gEngine.Con_Printf(S_ERROR "Fast dynamic BLAS %s size exceeded (need %dKiB, have %dKiB, geoms = %d)\n", blas->debug_name, @@ -634,7 +626,7 @@ qboolean RT_BlasBuild(struct rt_blas_s *blas, const struct vk_render_geometry_s // Build build_info.dstAccelerationStructure = blas->blas; - if (!buildAccel(geometry_buffer, &build_info, &build_size, build_ranges)) { + if (!buildAccel(geometry_buffer, &build_info, is_update ? build_size.updateScratchSize : build_size.buildScratchSize, build_ranges)) { gEngine.Con_Printf(S_ERROR "Couldn't build BLAS %s\n", blas->debug_name); goto finalize; } diff --git a/ref/vk/vk_ray_model.c b/ref/vk/vk_ray_model.c index 8e3d3106..69fdc7cb 100644 --- a/ref/vk/vk_ray_model.c +++ b/ref/vk/vk_ray_model.c @@ -258,6 +258,12 @@ void RT_ModelDestroy(struct rt_model_s* model) { Mem_Free(model); } +qboolean RT_ModelUpdate(struct rt_model_s *model, const struct vk_render_geometry_s *geometries, int geometries_count) { + // TODO some updates, which change geometry location, textures, etc, might need kusochki update too + // TODO mark it with a flag or something + return RT_BlasBuild(model->blas, geometries, geometries_count); +} + rt_draw_instance_t *getDrawInstance(void) { if (g_ray_model_state.frame.instances_count >= ARRAYSIZE(g_ray_model_state.frame.instances)) { gEngine.Con_Printf(S_ERROR "Too many RT draw instances, max = %d\n", (int)(ARRAYSIZE(g_ray_model_state.frame.instances))); diff --git a/ref/vk/vk_render.c b/ref/vk/vk_render.c index 4cfab9e2..687971ac 100644 --- a/ref/vk/vk_render.c +++ b/ref/vk/vk_render.c @@ -641,7 +641,7 @@ void VK_RenderEndRTX( struct vk_combuf_s* combuf, VkImageView img_dst_view, VkIm } } -qboolean VK_RenderModelCreate( vk_render_model_t *model, vk_render_model_init_t args ) { +qboolean R_RenderModelCreate( vk_render_model_t *model, vk_render_model_init_t args ) { memset(model, 0, sizeof(*model)); Q_strncpy(model->debug_name, args.name, sizeof(model->debug_name)); @@ -655,12 +655,12 @@ qboolean VK_RenderModelCreate( vk_render_model_t *model, vk_render_model_init_t .debug_name = model->debug_name, .geometries = args.geometries, .geometries_count = args.geometries_count, - .usage = kBlasBuildStatic, // TODO pass from caller + .usage = args.dynamic ? kBlasBuildDynamicUpdate : kBlasBuildStatic, }); return !!model->rt_model; } -void VK_RenderModelDestroy( vk_render_model_t* model ) { +void R_RenderModelDestroy( vk_render_model_t* model ) { if (model->dynamic_polylights) Mem_Free(model->dynamic_polylights); @@ -668,6 +668,16 @@ void VK_RenderModelDestroy( vk_render_model_t* model ) { RT_ModelDestroy(model->rt_model); } +qboolean R_RenderModelUpdate( vk_render_model_t *model ) { + // Non-RT rendering doesn't need to update anything, assuming that geometry regions offsets are not changed, and losing intermediate states is fine + if (!g_render_state.current_frame_is_ray_traced) + return true; + + ASSERT(model->rt_model); + + return RT_ModelUpdate(model->rt_model, model->geometries, model->num_geometries); +} + static void uboComputeAndSetMVPFromModel( const matrix4x4 model ) { matrix4x4 mvp; Matrix4x4_Concat(mvp, g_render_state.projection_view, model); diff --git a/ref/vk/vk_render.h b/ref/vk/vk_render.h index 8e324398..243917a3 100644 --- a/ref/vk/vk_render.h +++ b/ref/vk/vk_render.h @@ -127,9 +127,15 @@ typedef struct { const char *name; vk_render_geometry_t *geometries; int geometries_count; + + // Geometry data can and will be updated + // Upading geometry locations is not supported though, only vertex/index values + qboolean dynamic; } vk_render_model_init_t; -qboolean VK_RenderModelCreate( vk_render_model_t *model, vk_render_model_init_t args ); -void VK_RenderModelDestroy( vk_render_model_t* model ); +qboolean R_RenderModelCreate( vk_render_model_t *model, vk_render_model_init_t args ); +void R_RenderModelDestroy( vk_render_model_t* model ); + +qboolean R_RenderModelUpdate( vk_render_model_t *model ); typedef struct { vk_render_type_e render_type; diff --git a/ref/vk/vk_rtx.h b/ref/vk/vk_rtx.h index e5cf1a6a..96a5b21e 100644 --- a/ref/vk/vk_rtx.h +++ b/ref/vk/vk_rtx.h @@ -50,6 +50,8 @@ typedef struct { struct rt_model_s *RT_ModelCreate(rt_model_create_t args); void RT_ModelDestroy(struct rt_model_s *model); +qboolean RT_ModelUpdate(struct rt_model_s *model, const struct vk_render_geometry_s *geometries, int geometries_count); + typedef struct { int render_type; // TODO material_mode const matrix3x4 *transform, *prev_transform; diff --git a/ref/vk/vk_sprite.c b/ref/vk/vk_sprite.c index 3b99634d..e202f7a2 100644 --- a/ref/vk/vk_sprite.c +++ b/ref/vk/vk_sprite.c @@ -106,16 +106,17 @@ static qboolean createQuadModel(void) { .emissive = {1,1,1}, }; - return VK_RenderModelCreate(&g_sprite.quad.model, (vk_render_model_init_t){ + return R_RenderModelCreate(&g_sprite.quad.model, (vk_render_model_init_t){ .name = "sprite", .geometries = &g_sprite.quad.geometry, .geometries_count = 1, + .dynamic = false, }); } static void destroyQuadModel(void) { if (g_sprite.quad.model.num_geometries) - VK_RenderModelDestroy(&g_sprite.quad.model); + R_RenderModelDestroy(&g_sprite.quad.model); if (g_sprite.quad.geom.block_handle.size) R_GeometryRangeFree(&g_sprite.quad.geom); diff --git a/ref/vk/vk_studio.c b/ref/vk/vk_studio.c index 8b1d9647..9041948d 100644 --- a/ref/vk/vk_studio.c +++ b/ref/vk/vk_studio.c @@ -164,7 +164,7 @@ void R_StudioCacheClear( void ) { for (int i = 0; i < g_studio_cache.entries_count; ++i) { r_studio_model_cache_entry_t *const entry = g_studio_cache.entries + i; ASSERT(entry->key_submodel); - VK_RenderModelDestroy(&entry->render_model); + R_RenderModelDestroy(&entry->render_model); R_GeometryRangeFree(&entry->geometry_range); Mem_Free(entry->geometries); entry->key_submodel = 0; @@ -2415,10 +2415,11 @@ static const r_studio_model_cache_entry_t *buildCachedStudioSubModel( const mstu .geometry_range = geometry, }; - if (!VK_RenderModelCreate( &entry->render_model, (vk_render_model_init_t){ + if (!R_RenderModelCreate( &entry->render_model, (vk_render_model_init_t){ .name = submodel->name, .geometries = geometries, .geometries_count = submodel->nummesh, + .dynamic = false, })) { gEngine.Con_Printf(S_ERROR "Unable to create render model for studio submodel %s", submodel->name); Mem_Free(geometries);