2022-08-27 21:30:53 +02:00
|
|
|
#include "vk_ray_accel.h"
|
|
|
|
|
|
|
|
#include "vk_core.h"
|
|
|
|
#include "vk_rtx.h"
|
|
|
|
#include "vk_ray_internal.h"
|
2023-03-23 18:00:40 +01:00
|
|
|
#include "r_speeds.h"
|
2023-04-07 20:14:41 +02:00
|
|
|
#include "vk_combuf.h"
|
2023-05-02 00:34:13 +02:00
|
|
|
#include "vk_staging.h"
|
|
|
|
#include "vk_math.h"
|
2023-05-18 20:59:14 +02:00
|
|
|
#include "vk_geometry.h"
|
|
|
|
#include "vk_render.h"
|
2023-08-29 19:12:35 +02:00
|
|
|
#include "vk_logs.h"
|
2023-05-02 00:34:13 +02:00
|
|
|
|
2023-10-09 19:02:04 +02:00
|
|
|
#include "profiler.h"
|
|
|
|
|
2023-05-02 00:34:13 +02:00
|
|
|
#include "xash3d_mathlib.h"
|
2022-08-27 21:30:53 +02:00
|
|
|
|
2023-06-13 18:39:50 +02:00
|
|
|
#define MODULE_NAME "accel"
|
2023-12-04 17:25:35 +01:00
|
|
|
#define LOG_MODULE rt
|
2023-06-13 18:39:50 +02:00
|
|
|
|
2023-05-18 20:59:14 +02:00
|
|
|
typedef struct rt_blas_s {
|
2023-05-31 19:13:40 +02:00
|
|
|
const char *debug_name;
|
2023-05-18 20:59:14 +02:00
|
|
|
rt_blas_usage_e usage;
|
|
|
|
|
|
|
|
VkAccelerationStructureKHR blas;
|
|
|
|
|
|
|
|
int max_geoms;
|
|
|
|
//uint32_t *max_prim_counts;
|
|
|
|
int blas_size;
|
|
|
|
} rt_blas_t;
|
2022-08-27 21:30:53 +02:00
|
|
|
|
2023-03-23 18:00:40 +01:00
|
|
|
static struct {
|
2023-05-18 20:59:14 +02:00
|
|
|
// Stores AS built data. Lifetime similar to render buffer:
|
|
|
|
// - some portion lives for entire map lifetime
|
|
|
|
// - some portion lives only for a single frame (may have several frames in flight)
|
vk: rt: add workaround for holes in geometry
Once upon a time, there were some BLASes. There were the BLASes for dynamic geometry, that were to be used every frame to draw very dynamic things, like sprites and beams. They were initialized at the very begining of the renderer's lifetime, and were expected to live happily for the entire process duration.
However, an evil NewMap appeared. It didn't care abount anything or anyone, so when it came, it just cleared all the allocators, and allowed other BLASes to be allocated into the same space as dynamic BLASes were already given. This made BLASes live on top of each other, use each others toys and make them fight. They weren't happy.
So we just kill them and creat them again from scratch, when the evil NewMap comes.
The end.
Fixes #729
2024-02-02 17:45:43 +01:00
|
|
|
// TODO: unify this with render buffer -- really?
|
2023-05-18 20:59:14 +02:00
|
|
|
// Needs: AS_STORAGE_BIT, SHADER_DEVICE_ADDRESS_BIT
|
|
|
|
vk_buffer_t accels_buffer;
|
|
|
|
struct alo_pool_s *accels_buffer_alloc;
|
|
|
|
|
|
|
|
// Temp: lives only during a single frame (may have many in flight)
|
|
|
|
// Used for building ASes;
|
|
|
|
// Needs: AS_STORAGE_BIT, SHADER_DEVICE_ADDRESS_BIT
|
|
|
|
vk_buffer_t scratch_buffer;
|
|
|
|
VkDeviceAddress accels_buffer_addr, scratch_buffer_addr;
|
|
|
|
|
|
|
|
// Temp-ish: used for making TLAS, contains addressed to all used BLASes
|
|
|
|
// Lifetime and nature of usage similar to scratch_buffer
|
|
|
|
// TODO: unify them
|
|
|
|
// Needs: SHADER_DEVICE_ADDRESS, STORAGE_BUFFER, AS_BUILD_INPUT_READ_ONLY
|
|
|
|
vk_buffer_t tlas_geom_buffer;
|
|
|
|
VkDeviceAddress tlas_geom_buffer_addr;
|
|
|
|
r_flipping_buffer_t tlas_geom_buffer_alloc;
|
|
|
|
|
|
|
|
// TODO need several TLASes for N frames in flight
|
|
|
|
VkAccelerationStructureKHR tlas;
|
|
|
|
|
|
|
|
// Per-frame data that is accumulated between RayFrameBegin and End calls
|
|
|
|
struct {
|
|
|
|
uint32_t scratch_offset; // for building dynamic blases
|
|
|
|
} frame;
|
|
|
|
|
2023-03-23 18:00:40 +01:00
|
|
|
struct {
|
2023-05-17 19:42:18 +02:00
|
|
|
int instances_count;
|
2023-03-25 18:20:45 +01:00
|
|
|
int accels_built;
|
2023-03-23 18:00:40 +01:00
|
|
|
} stats;
|
2024-01-19 18:25:29 +01:00
|
|
|
|
|
|
|
cvar_t *cv_force_culling;
|
2023-05-18 20:59:14 +02:00
|
|
|
} g_accel;
|
|
|
|
|
|
|
|
static VkAccelerationStructureBuildSizesInfoKHR getAccelSizes(const VkAccelerationStructureBuildGeometryInfoKHR *build_info, const uint32_t *max_prim_counts) {
|
|
|
|
VkAccelerationStructureBuildSizesInfoKHR build_size = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR
|
|
|
|
};
|
|
|
|
|
|
|
|
vkGetAccelerationStructureBuildSizesKHR(
|
|
|
|
vk_core.device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, build_info, max_prim_counts, &build_size);
|
|
|
|
|
|
|
|
return build_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VkAccelerationStructureKHR createAccel(const char *name, VkAccelerationStructureTypeKHR type, uint32_t size) {
|
|
|
|
const alo_block_t block = aloPoolAllocate(g_accel.accels_buffer_alloc, size, /*TODO why? align=*/256);
|
|
|
|
|
|
|
|
if (block.offset == ALO_ALLOC_FAILED) {
|
2023-09-14 19:57:59 +02:00
|
|
|
ERR("Failed to allocate %u bytes for blas \"%s\"", size, name);
|
2023-05-18 20:59:14 +02:00
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
2023-03-23 18:00:40 +01:00
|
|
|
|
2023-05-18 20:59:14 +02:00
|
|
|
const VkAccelerationStructureCreateInfoKHR asci = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR,
|
|
|
|
.buffer = g_accel.accels_buffer.buffer,
|
|
|
|
.offset = block.offset,
|
|
|
|
.type = type,
|
|
|
|
.size = size,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkAccelerationStructureKHR accel = VK_NULL_HANDLE;
|
|
|
|
XVK_CHECK(vkCreateAccelerationStructureKHR(vk_core.device, &asci, NULL, &accel));
|
|
|
|
SET_DEBUG_NAME(accel, VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR, name);
|
|
|
|
return accel;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VkDeviceAddress getAccelAddress(VkAccelerationStructureKHR as) {
|
2022-08-27 21:30:53 +02:00
|
|
|
VkAccelerationStructureDeviceAddressInfoKHR asdai = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR,
|
|
|
|
.accelerationStructure = as,
|
|
|
|
};
|
|
|
|
return vkGetAccelerationStructureDeviceAddressKHR(vk_core.device, &asdai);
|
|
|
|
}
|
|
|
|
|
2023-06-09 19:03:00 +02:00
|
|
|
static qboolean buildAccel(VkBuffer geometry_buffer, VkAccelerationStructureBuildGeometryInfoKHR *build_info, uint32_t scratch_buffer_size, const VkAccelerationStructureBuildRangeInfoKHR *build_ranges) {
|
2023-05-18 20:59:14 +02:00
|
|
|
// 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 | VK_ACCESS_SHADER_READ_BIT, // FIXME
|
|
|
|
.buffer = geometry_buffer,
|
|
|
|
.offset = 0, // FIXME
|
|
|
|
.size = VK_WHOLE_SIZE, // FIXME
|
|
|
|
} };
|
|
|
|
vkCmdPipelineBarrier(combuf->cmdbuf,
|
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
//VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
|
|
|
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
|
2023-08-29 19:12:35 +02:00
|
|
|
0, 0, NULL, COUNTOF(bmb), bmb, 0, NULL);
|
2023-05-18 20:59:14 +02:00
|
|
|
}
|
|
|
|
|
2023-08-29 19:12:35 +02:00
|
|
|
//gEngine.Con_Reportf("sratch offset = %d, req=%d", g_accel.frame.scratch_offset, scratch_buffer_size);
|
2023-05-18 20:59:14 +02:00
|
|
|
|
|
|
|
if (MAX_SCRATCH_BUFFER < g_accel.frame.scratch_offset + scratch_buffer_size) {
|
2023-08-29 19:12:35 +02:00
|
|
|
ERR("Scratch buffer overflow: left %u bytes, but need %u",
|
2023-05-18 20:59:14 +02:00
|
|
|
MAX_SCRATCH_BUFFER - g_accel.frame.scratch_offset,
|
|
|
|
scratch_buffer_size);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
build_info->scratchData.deviceAddress = g_accel.scratch_buffer_addr + g_accel.frame.scratch_offset;
|
|
|
|
|
|
|
|
//uint32_t scratch_offset_initial = g_accel.frame.scratch_offset;
|
|
|
|
g_accel.frame.scratch_offset += scratch_buffer_size;
|
|
|
|
g_accel.frame.scratch_offset = ALIGN_UP(g_accel.frame.scratch_offset, vk_core.physical_device.properties_accel.minAccelerationStructureScratchOffsetAlignment);
|
|
|
|
|
2023-08-29 19:12:35 +02:00
|
|
|
//gEngine.Con_Reportf("AS=%p, n_geoms=%u, scratch: %#x %d %#x", *args->p_accel, args->n_geoms, scratch_offset_initial, scratch_buffer_size, scratch_offset_initial + scratch_buffer_size);
|
2023-05-18 20:59:14 +02:00
|
|
|
|
|
|
|
g_accel.stats.accels_built++;
|
|
|
|
|
|
|
|
static int scope_id = -2;
|
|
|
|
if (scope_id == -2)
|
|
|
|
scope_id = R_VkGpuScope_Register("build_as");
|
|
|
|
const int begin_index = R_VkCombufScopeBegin(combuf, scope_id);
|
|
|
|
const VkAccelerationStructureBuildRangeInfoKHR *p_build_ranges = build_ranges;
|
|
|
|
vkCmdBuildAccelerationStructuresKHR(combuf->cmdbuf, 1, build_info, &p_build_ranges);
|
|
|
|
R_VkCombufScopeEnd(combuf, begin_index, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-27 21:30:53 +02:00
|
|
|
// TODO split this into smaller building blocks in a separate module
|
2023-05-22 20:02:40 +02:00
|
|
|
qboolean createOrUpdateAccelerationStructure(vk_combuf_t *combuf, const as_build_args_t *args) {
|
2023-05-18 21:10:21 +02:00
|
|
|
ASSERT(args->geoms);
|
|
|
|
ASSERT(args->n_geoms > 0);
|
|
|
|
ASSERT(args->p_accel);
|
|
|
|
|
|
|
|
const qboolean should_create = *args->p_accel == VK_NULL_HANDLE;
|
2022-08-27 21:30:53 +02:00
|
|
|
|
|
|
|
VkAccelerationStructureBuildGeometryInfoKHR build_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR,
|
|
|
|
.type = args->type,
|
2023-05-18 21:32:00 +02:00
|
|
|
.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR,
|
2023-05-18 21:10:21 +02:00
|
|
|
.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR,
|
2022-08-27 21:30:53 +02:00
|
|
|
.geometryCount = args->n_geoms,
|
|
|
|
.pGeometries = args->geoms,
|
2023-05-18 21:10:21 +02:00
|
|
|
.srcAccelerationStructure = VK_NULL_HANDLE,
|
2022-08-27 21:30:53 +02:00
|
|
|
};
|
|
|
|
|
2023-05-18 21:10:21 +02:00
|
|
|
const VkAccelerationStructureBuildSizesInfoKHR build_size = getAccelSizes(&build_info, args->max_prim_counts);
|
2022-08-27 21:30:53 +02:00
|
|
|
|
|
|
|
if (should_create) {
|
2023-05-18 20:59:14 +02:00
|
|
|
*args->p_accel = createAccel(args->debug_name, args->type, build_size.accelerationStructureSize);
|
2022-08-27 21:30:53 +02:00
|
|
|
|
2023-05-18 20:59:14 +02:00
|
|
|
if (!args->p_accel)
|
2022-08-27 21:30:53 +02:00
|
|
|
return false;
|
|
|
|
|
2023-05-22 20:02:40 +02:00
|
|
|
if (args->out_accel_addr)
|
|
|
|
*args->out_accel_addr = getAccelAddress(*args->p_accel);
|
|
|
|
|
|
|
|
if (args->inout_size)
|
|
|
|
*args->inout_size = build_size.accelerationStructureSize;
|
2022-08-27 21:30:53 +02:00
|
|
|
|
2023-08-29 19:12:35 +02:00
|
|
|
// gEngine.Con_Reportf("AS=%p, n_geoms=%u, build: %#x %d %#x", *args->p_accel, args->n_geoms, buffer_offset, asci.size, buffer_offset + asci.size);
|
2022-08-27 21:30:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// If not enough data for building, just create
|
2023-04-07 20:14:41 +02:00
|
|
|
if (!combuf || !args->build_ranges)
|
2022-08-27 21:30:53 +02:00
|
|
|
return true;
|
|
|
|
|
2023-05-22 20:02:40 +02:00
|
|
|
if (args->inout_size)
|
|
|
|
ASSERT(*args->inout_size >= build_size.accelerationStructureSize);
|
2022-08-27 21:30:53 +02:00
|
|
|
|
|
|
|
build_info.dstAccelerationStructure = *args->p_accel;
|
2023-05-18 21:10:21 +02:00
|
|
|
const VkBuffer geometry_buffer = R_GeometryBuffer_Get();
|
2023-06-09 19:03:00 +02:00
|
|
|
return buildAccel(geometry_buffer, &build_info, build_size.buildScratchSize, args->build_ranges);
|
2022-08-27 21:30:53 +02:00
|
|
|
}
|
|
|
|
|
2023-04-07 20:14:41 +02:00
|
|
|
static void createTlas( vk_combuf_t *combuf, VkDeviceAddress instances_addr ) {
|
2022-08-27 21:30:53 +02:00
|
|
|
const VkAccelerationStructureGeometryKHR tl_geom[] = {
|
|
|
|
{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR,
|
|
|
|
//.flags = VK_GEOMETRY_OPAQUE_BIT,
|
|
|
|
.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR,
|
|
|
|
.geometry.instances =
|
|
|
|
(VkAccelerationStructureGeometryInstancesDataKHR){
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR,
|
|
|
|
.data.deviceAddress = instances_addr,
|
|
|
|
.arrayOfPointers = VK_FALSE,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2023-05-18 21:10:21 +02:00
|
|
|
const uint32_t tl_max_prim_counts[COUNTOF(tl_geom)] = { MAX_INSTANCES };
|
2022-08-27 21:30:53 +02:00
|
|
|
const VkAccelerationStructureBuildRangeInfoKHR tl_build_range = {
|
2023-05-17 19:42:18 +02:00
|
|
|
.primitiveCount = g_ray_model_state.frame.instances_count,
|
2022-08-27 21:30:53 +02:00
|
|
|
};
|
|
|
|
const as_build_args_t asrgs = {
|
|
|
|
.geoms = tl_geom,
|
|
|
|
.max_prim_counts = tl_max_prim_counts,
|
2023-04-07 20:14:41 +02:00
|
|
|
.build_ranges = !combuf ? NULL : &tl_build_range,
|
2022-08-27 21:30:53 +02:00
|
|
|
.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",
|
2023-05-22 20:02:40 +02:00
|
|
|
.out_accel_addr = NULL,
|
|
|
|
.inout_size = NULL,
|
2022-08-27 21:30:53 +02:00
|
|
|
};
|
2023-05-22 20:02:40 +02:00
|
|
|
if (!createOrUpdateAccelerationStructure(combuf, &asrgs)) {
|
2022-08-27 21:30:53 +02:00
|
|
|
gEngine.Host_Error("Could not create/update TLAS\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-18 20:59:14 +02:00
|
|
|
vk_resource_t RT_VkAccelPrepareTlas(vk_combuf_t *combuf) {
|
2023-10-09 19:02:04 +02:00
|
|
|
APROF_SCOPE_DECLARE_BEGIN(prepare, __FUNCTION__);
|
2023-05-17 19:42:18 +02:00
|
|
|
ASSERT(g_ray_model_state.frame.instances_count > 0);
|
2023-04-07 20:14:41 +02:00
|
|
|
DEBUG_BEGIN(combuf->cmdbuf, "prepare tlas");
|
2022-08-27 21:30:53 +02:00
|
|
|
|
|
|
|
R_FlippingBuffer_Flip( &g_accel.tlas_geom_buffer_alloc );
|
|
|
|
|
2023-05-17 19:42:18 +02:00
|
|
|
const uint32_t instance_offset = R_FlippingBuffer_Alloc(&g_accel.tlas_geom_buffer_alloc, g_ray_model_state.frame.instances_count, 1);
|
2022-08-27 21:30:53 +02:00
|
|
|
ASSERT(instance_offset != ALO_ALLOC_FAILED);
|
|
|
|
|
|
|
|
// Upload all blas instances references to GPU mem
|
|
|
|
{
|
2023-05-02 00:34:13 +02:00
|
|
|
const vk_staging_region_t headers_lock = R_VkStagingLockForBuffer((vk_staging_buffer_args_t){
|
|
|
|
.buffer = g_ray_model_state.model_headers_buffer.buffer,
|
|
|
|
.offset = 0,
|
2023-05-17 19:42:18 +02:00
|
|
|
.size = g_ray_model_state.frame.instances_count * sizeof(struct ModelHeader),
|
2023-05-02 00:34:13 +02:00
|
|
|
.alignment = 16,
|
|
|
|
});
|
|
|
|
|
|
|
|
ASSERT(headers_lock.ptr);
|
|
|
|
|
2022-08-27 21:30:53 +02:00
|
|
|
VkAccelerationStructureInstanceKHR* inst = ((VkAccelerationStructureInstanceKHR*)g_accel.tlas_geom_buffer.mapped) + instance_offset;
|
2023-05-17 19:42:18 +02:00
|
|
|
for (int i = 0; i < g_ray_model_state.frame.instances_count; ++i) {
|
|
|
|
const rt_draw_instance_t* const instance = g_ray_model_state.frame.instances + i;
|
2023-05-22 20:02:40 +02:00
|
|
|
ASSERT(instance->blas_addr != 0);
|
2022-08-27 21:30:53 +02:00
|
|
|
inst[i] = (VkAccelerationStructureInstanceKHR){
|
2023-05-22 20:02:40 +02:00
|
|
|
.instanceCustomIndex = instance->kusochki_offset,
|
2022-08-27 21:30:53 +02:00
|
|
|
.instanceShaderBindingTableRecordOffset = 0,
|
2023-05-22 20:02:40 +02:00
|
|
|
.accelerationStructureReference = instance->blas_addr,
|
2022-08-27 21:30:53 +02:00
|
|
|
};
|
2023-12-22 21:14:27 +01:00
|
|
|
|
2024-01-19 18:25:29 +01:00
|
|
|
const VkGeometryInstanceFlagsKHR flags =
|
|
|
|
(instance->material_flags & kMaterialFlag_CullBackFace_Bit) || g_accel.cv_force_culling->value
|
|
|
|
? 0
|
|
|
|
: VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
2023-12-22 21:14:27 +01:00
|
|
|
|
2023-05-17 19:42:18 +02:00
|
|
|
switch (instance->material_mode) {
|
2023-04-24 20:38:12 +02:00
|
|
|
case MATERIAL_MODE_OPAQUE:
|
2022-08-27 21:30:53 +02:00
|
|
|
inst[i].mask = GEOMETRY_BIT_OPAQUE;
|
|
|
|
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_REGULAR,
|
2023-11-13 18:22:23 +01:00
|
|
|
// Force no-culling because there are cases where culling leads to leaking shadows, holes in reflections, etc
|
|
|
|
// CULL_DISABLE_BIT disables culling even if the gl_RayFlagsCullFrontFacingTrianglesEXT bit is set in shaders
|
2023-12-22 21:14:27 +01:00
|
|
|
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR | flags;
|
2022-08-27 21:30:53 +02:00
|
|
|
break;
|
2023-04-24 20:38:12 +02:00
|
|
|
case MATERIAL_MODE_OPAQUE_ALPHA_TEST:
|
2023-02-03 20:00:34 +01:00
|
|
|
inst[i].mask = GEOMETRY_BIT_ALPHA_TEST;
|
2022-08-27 21:30:53 +02:00
|
|
|
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_ALPHA_TEST,
|
2024-01-19 18:25:29 +01:00
|
|
|
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR; // Alpha test always culls
|
2022-08-27 21:30:53 +02:00
|
|
|
break;
|
2023-04-24 20:38:12 +02:00
|
|
|
case MATERIAL_MODE_TRANSLUCENT:
|
2022-08-27 21:30:53 +02:00
|
|
|
inst[i].mask = GEOMETRY_BIT_REFRACTIVE;
|
|
|
|
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_REGULAR,
|
2023-11-14 17:44:29 +01:00
|
|
|
// Disable culling for translucent surfaces: decide what side it is based on normal wrt ray directions
|
2023-12-22 21:14:27 +01:00
|
|
|
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR | flags;
|
2022-08-27 21:30:53 +02:00
|
|
|
break;
|
2023-04-24 20:38:12 +02:00
|
|
|
case MATERIAL_MODE_BLEND_ADD:
|
|
|
|
case MATERIAL_MODE_BLEND_MIX:
|
|
|
|
case MATERIAL_MODE_BLEND_GLOW:
|
|
|
|
inst[i].mask = GEOMETRY_BIT_BLEND;
|
2022-08-27 21:30:53 +02:00
|
|
|
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_ADDITIVE,
|
2023-11-13 18:22:23 +01:00
|
|
|
// Force no-culling because these should be visible from any angle
|
2023-12-22 21:14:27 +01:00
|
|
|
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR | flags;
|
2022-08-27 21:30:53 +02:00
|
|
|
break;
|
2023-04-24 20:38:12 +02:00
|
|
|
default:
|
2023-05-17 19:42:18 +02:00
|
|
|
gEngine.Host_Error("Unexpected material mode %d\n", instance->material_mode);
|
2023-04-24 20:38:12 +02:00
|
|
|
break;
|
2022-08-27 21:30:53 +02:00
|
|
|
}
|
2023-05-17 19:42:18 +02:00
|
|
|
memcpy(&inst[i].transform, instance->transform_row, sizeof(VkTransformMatrixKHR));
|
2023-05-02 00:34:13 +02:00
|
|
|
|
|
|
|
struct ModelHeader *const header = ((struct ModelHeader*)headers_lock.ptr) + i;
|
2023-05-17 19:42:18 +02:00
|
|
|
header->mode = instance->material_mode;
|
2023-05-22 20:02:40 +02:00
|
|
|
Vector4Copy(instance->color, header->color);
|
|
|
|
Matrix4x4_ToArrayFloatGL(instance->prev_transform_row, (float*)header->prev_transform);
|
2022-08-27 21:30:53 +02:00
|
|
|
}
|
2023-05-02 00:34:13 +02:00
|
|
|
|
|
|
|
R_VkStagingUnlock(headers_lock.handle);
|
2022-08-27 21:30:53 +02:00
|
|
|
}
|
|
|
|
|
2023-05-18 20:59:14 +02:00
|
|
|
g_accel.stats.instances_count = g_ray_model_state.frame.instances_count;
|
2023-03-23 18:00:40 +01:00
|
|
|
|
2022-08-27 21:30:53 +02:00
|
|
|
// Barrier for building all BLASes
|
|
|
|
// BLAS building is now in cmdbuf, need to synchronize with results
|
|
|
|
{
|
2023-05-02 00:34:13 +02:00
|
|
|
VkBufferMemoryBarrier bmb[] = {{
|
2022-08-27 21:30:53 +02:00
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
|
|
|
.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, // | VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR,
|
|
|
|
.buffer = g_accel.accels_buffer.buffer,
|
vk: rt: add workaround for holes in geometry
Once upon a time, there were some BLASes. There were the BLASes for dynamic geometry, that were to be used every frame to draw very dynamic things, like sprites and beams. They were initialized at the very begining of the renderer's lifetime, and were expected to live happily for the entire process duration.
However, an evil NewMap appeared. It didn't care abount anything or anyone, so when it came, it just cleared all the allocators, and allowed other BLASes to be allocated into the same space as dynamic BLASes were already given. This made BLASes live on top of each other, use each others toys and make them fight. They weren't happy.
So we just kill them and creat them again from scratch, when the evil NewMap comes.
The end.
Fixes #729
2024-02-02 17:45:43 +01:00
|
|
|
// FIXME this is completely wrong. Offset ans size are BLAS-specifig
|
2022-08-27 21:30:53 +02:00
|
|
|
.offset = instance_offset * sizeof(VkAccelerationStructureInstanceKHR),
|
2023-05-17 19:42:18 +02:00
|
|
|
.size = g_ray_model_state.frame.instances_count * sizeof(VkAccelerationStructureInstanceKHR),
|
2023-05-02 00:34:13 +02:00
|
|
|
}};
|
2023-04-07 20:14:41 +02:00
|
|
|
vkCmdPipelineBarrier(combuf->cmdbuf,
|
2022-08-27 21:30:53 +02:00
|
|
|
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
|
2023-04-07 20:14:41 +02:00
|
|
|
createTlas(combuf, g_accel.tlas_geom_buffer_addr + instance_offset * sizeof(VkAccelerationStructureInstanceKHR));
|
|
|
|
DEBUG_END(combuf->cmdbuf);
|
2023-05-18 20:59:14 +02:00
|
|
|
|
2023-05-18 21:10:21 +02:00
|
|
|
// TODO return vk_resource_t with callback to all this "do the preparation and barriers" crap, instead of doing it here
|
2023-05-18 20:59:14 +02:00
|
|
|
{
|
|
|
|
const VkBufferMemoryBarrier bmb[] = { {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
|
|
|
.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
|
|
|
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
vk: rt: add workaround for holes in geometry
Once upon a time, there were some BLASes. There were the BLASes for dynamic geometry, that were to be used every frame to draw very dynamic things, like sprites and beams. They were initialized at the very begining of the renderer's lifetime, and were expected to live happily for the entire process duration.
However, an evil NewMap appeared. It didn't care abount anything or anyone, so when it came, it just cleared all the allocators, and allowed other BLASes to be allocated into the same space as dynamic BLASes were already given. This made BLASes live on top of each other, use each others toys and make them fight. They weren't happy.
So we just kill them and creat them again from scratch, when the evil NewMap comes.
The end.
Fixes #729
2024-02-02 17:45:43 +01:00
|
|
|
// FIXME also incorrect -- here we must barrier on tlas_geom_buffer, not accels_buffer
|
2023-05-18 20:59:14 +02:00
|
|
|
.buffer = g_accel.accels_buffer.buffer,
|
|
|
|
.offset = 0,
|
|
|
|
.size = VK_WHOLE_SIZE,
|
|
|
|
} };
|
|
|
|
vkCmdPipelineBarrier(combuf->cmdbuf,
|
|
|
|
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
|
|
|
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
2023-08-29 19:12:35 +02:00
|
|
|
0, 0, NULL, COUNTOF(bmb), bmb, 0, NULL);
|
2023-05-18 20:59:14 +02:00
|
|
|
}
|
|
|
|
|
2023-10-09 19:02:04 +02:00
|
|
|
APROF_SCOPE_END(prepare);
|
2023-05-18 20:59:14 +02:00
|
|
|
return (vk_resource_t){
|
|
|
|
.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
|
|
|
|
.value = (vk_descriptor_value_t){
|
|
|
|
.accel = (VkWriteDescriptorSetAccelerationStructureKHR) {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
|
|
|
|
.accelerationStructureCount = 1,
|
|
|
|
.pAccelerationStructures = &g_accel.tlas,
|
|
|
|
.pNext = NULL,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2022-08-27 21:30:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qboolean RT_VkAccelInit(void) {
|
|
|
|
if (!VK_BufferCreate("ray accels_buffer", &g_accel.accels_buffer, MAX_ACCELS_BUFFER,
|
|
|
|
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
|
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
|
|
|
))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
g_accel.accels_buffer_addr = R_VkBufferGetDeviceAddress(g_accel.accels_buffer.buffer);
|
|
|
|
|
|
|
|
if (!VK_BufferCreate("ray scratch_buffer", &g_accel.scratch_buffer, MAX_SCRATCH_BUFFER,
|
|
|
|
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
|
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
|
|
|
)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
g_accel.scratch_buffer_addr = R_VkBufferGetDeviceAddress(g_accel.scratch_buffer.buffer);
|
|
|
|
|
|
|
|
// TODO this doesn't really need to be host visible, use staging
|
2023-05-17 19:42:18 +02:00
|
|
|
if (!VK_BufferCreate("ray tlas_geom_buffer", &g_accel.tlas_geom_buffer, sizeof(VkAccelerationStructureInstanceKHR) * MAX_INSTANCES * 2,
|
2022-08-27 21:30:53 +02:00
|
|
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
|
|
|
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
|
|
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
|
|
|
// FIXME complain, handle
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
g_accel.tlas_geom_buffer_addr = R_VkBufferGetDeviceAddress(g_accel.tlas_geom_buffer.buffer);
|
2023-05-17 19:42:18 +02:00
|
|
|
R_FlippingBuffer_Init(&g_accel.tlas_geom_buffer_alloc, MAX_INSTANCES * 2);
|
2022-08-27 21:30:53 +02:00
|
|
|
|
2023-05-25 21:12:18 +02:00
|
|
|
g_accel.accels_buffer_alloc = aloPoolCreate(MAX_ACCELS_BUFFER, MAX_INSTANCES, /* why */ 256);
|
|
|
|
|
2023-06-14 20:23:09 +02:00
|
|
|
R_SPEEDS_COUNTER(g_accel.stats.instances_count, "instances", kSpeedsMetricCount);
|
|
|
|
R_SPEEDS_COUNTER(g_accel.stats.accels_built, "built", kSpeedsMetricCount);
|
2023-03-23 18:00:40 +01:00
|
|
|
|
2024-01-19 18:25:29 +01:00
|
|
|
g_accel.cv_force_culling = gEngine.Cvar_Get("rt_debug_force_backface_culling", "0", FCVAR_GLCONFIG | FCVAR_CHEAT, "Force backface culling for testing");
|
|
|
|
|
2022-08-27 21:30:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RT_VkAccelShutdown(void) {
|
|
|
|
if (g_accel.tlas != VK_NULL_HANDLE)
|
|
|
|
vkDestroyAccelerationStructureKHR(vk_core.device, g_accel.tlas, NULL);
|
|
|
|
|
|
|
|
VK_BufferDestroy(&g_accel.scratch_buffer);
|
|
|
|
VK_BufferDestroy(&g_accel.accels_buffer);
|
|
|
|
VK_BufferDestroy(&g_accel.tlas_geom_buffer);
|
|
|
|
if (g_accel.accels_buffer_alloc)
|
|
|
|
aloPoolDestroy(g_accel.accels_buffer_alloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RT_VkAccelNewMap(void) {
|
|
|
|
const int expected_accels = 512; // TODO actually get this from playing the game
|
|
|
|
const int accels_alignment = 256; // TODO where does this come from?
|
|
|
|
ASSERT(vk_core.rtx);
|
|
|
|
|
2023-04-27 19:29:50 +02:00
|
|
|
g_accel.frame.scratch_offset = 0;
|
|
|
|
|
vk: rt: add workaround for holes in geometry
Once upon a time, there were some BLASes. There were the BLASes for dynamic geometry, that were to be used every frame to draw very dynamic things, like sprites and beams. They were initialized at the very begining of the renderer's lifetime, and were expected to live happily for the entire process duration.
However, an evil NewMap appeared. It didn't care abount anything or anyone, so when it came, it just cleared all the allocators, and allowed other BLASes to be allocated into the same space as dynamic BLASes were already given. This made BLASes live on top of each other, use each others toys and make them fight. They weren't happy.
So we just kill them and creat them again from scratch, when the evil NewMap comes.
The end.
Fixes #729
2024-02-02 17:45:43 +01:00
|
|
|
// FIXME this clears up memory before its users are deallocated (e.g. dynamic models BLASes)
|
2022-08-27 21:30:53 +02:00
|
|
|
if (g_accel.accels_buffer_alloc)
|
|
|
|
aloPoolDestroy(g_accel.accels_buffer_alloc);
|
|
|
|
g_accel.accels_buffer_alloc = aloPoolCreate(MAX_ACCELS_BUFFER, expected_accels, accels_alignment);
|
|
|
|
|
|
|
|
// Recreate tlas
|
|
|
|
// Why here and not in init: to make sure that its memory is preserved. Map init will clear all memory regions.
|
|
|
|
{
|
|
|
|
if (g_accel.tlas != VK_NULL_HANDLE) {
|
|
|
|
vkDestroyAccelerationStructureKHR(vk_core.device, g_accel.tlas, NULL);
|
|
|
|
g_accel.tlas = VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
createTlas(VK_NULL_HANDLE, g_accel.tlas_geom_buffer_addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RT_VkAccelFrameBegin(void) {
|
|
|
|
g_accel.frame.scratch_offset = 0;
|
|
|
|
}
|
2023-05-18 20:59:14 +02:00
|
|
|
|
2023-05-31 19:13:40 +02:00
|
|
|
struct rt_blas_s* RT_BlasCreate(const char *name, rt_blas_usage_e usage) {
|
2023-05-18 20:59:14 +02:00
|
|
|
rt_blas_t *blas = Mem_Calloc(vk_core.pool, sizeof(*blas));
|
|
|
|
|
2023-05-31 19:13:40 +02:00
|
|
|
blas->debug_name = name;
|
2023-05-18 20:59:14 +02:00
|
|
|
blas->usage = usage;
|
|
|
|
blas->blas_size = -1;
|
|
|
|
|
|
|
|
return blas;
|
|
|
|
}
|
|
|
|
|
2023-06-07 19:24:29 +02:00
|
|
|
qboolean RT_BlasPreallocate(struct rt_blas_s* blas, rt_blas_preallocate_t args) {
|
|
|
|
ASSERT(!blas->blas);
|
|
|
|
ASSERT(blas->usage == kBlasBuildDynamicFast);
|
2023-05-18 20:59:14 +02:00
|
|
|
|
2023-06-07 19:24:29 +02:00
|
|
|
// TODO allocate these from static pool
|
|
|
|
VkAccelerationStructureGeometryKHR *const as_geoms = Mem_Calloc(vk_core.pool, args.max_geometries * sizeof(*as_geoms));
|
|
|
|
uint32_t *const max_prim_counts = Mem_Malloc(vk_core.pool, args.max_geometries * sizeof(*max_prim_counts));
|
|
|
|
VkAccelerationStructureBuildRangeInfoKHR *const build_ranges = Mem_Calloc(vk_core.pool, args.max_geometries * sizeof(*build_ranges));
|
2023-05-18 20:59:14 +02:00
|
|
|
|
2023-06-07 19:24:29 +02:00
|
|
|
for (int i = 0; i < args.max_geometries; ++i) {
|
|
|
|
max_prim_counts[i] = args.max_prims_per_geometry;
|
|
|
|
as_geoms[i] = (VkAccelerationStructureGeometryKHR)
|
|
|
|
{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR,
|
|
|
|
.flags = VK_GEOMETRY_OPAQUE_BIT_KHR, // FIXME this is not true. incoming mode might have transparency eventually (and also dynamically)
|
|
|
|
.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR,
|
|
|
|
.geometry.triangles =
|
|
|
|
(VkAccelerationStructureGeometryTrianglesDataKHR){
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR,
|
|
|
|
.indexType = VK_INDEX_TYPE_UINT16,
|
|
|
|
.maxVertex = args.max_vertex_per_geometry,
|
|
|
|
.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT,
|
|
|
|
.vertexStride = sizeof(vk_vertex_t),
|
|
|
|
.vertexData.deviceAddress = 0,
|
|
|
|
.indexData.deviceAddress = 0,
|
|
|
|
},
|
|
|
|
};
|
2023-05-18 20:59:14 +02:00
|
|
|
|
2023-06-07 19:24:29 +02:00
|
|
|
build_ranges[i] = (VkAccelerationStructureBuildRangeInfoKHR) {
|
|
|
|
.primitiveCount = args.max_prims_per_geometry,
|
|
|
|
.primitiveOffset = 0,
|
|
|
|
.firstVertex = 0,
|
2023-05-18 20:59:14 +02:00
|
|
|
};
|
2023-06-07 19:24:29 +02:00
|
|
|
}
|
2023-05-18 20:59:14 +02:00
|
|
|
|
2023-06-07 19:24:29 +02:00
|
|
|
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_BUILD_BIT_KHR,
|
|
|
|
.geometryCount = args.max_geometries,
|
|
|
|
.srcAccelerationStructure = VK_NULL_HANDLE,
|
|
|
|
.pGeometries = as_geoms,
|
|
|
|
};
|
|
|
|
|
|
|
|
const VkAccelerationStructureBuildSizesInfoKHR build_size = getAccelSizes(&build_info, max_prim_counts);
|
2023-08-29 19:12:35 +02:00
|
|
|
DEBUG("geoms=%d max_prims=%d max_vertex=%d => blas=%dKiB",
|
2023-06-07 19:24:29 +02:00
|
|
|
args.max_geometries, args.max_prims_per_geometry, args.max_vertex_per_geometry, (int)build_size.accelerationStructureSize / 1024);
|
|
|
|
|
|
|
|
qboolean retval = false;
|
|
|
|
|
|
|
|
blas->blas = createAccel(blas->debug_name, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, build_size.accelerationStructureSize);
|
|
|
|
if (!blas->blas) {
|
2023-08-29 19:12:35 +02:00
|
|
|
ERR("Couldn't preallocate blas %s", blas->debug_name);
|
2023-06-07 19:24:29 +02:00
|
|
|
goto finalize;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = true;
|
|
|
|
|
|
|
|
blas->blas_size = build_size.accelerationStructureSize;
|
|
|
|
blas->max_geoms = build_info.geometryCount;
|
|
|
|
|
|
|
|
finalize:
|
|
|
|
Mem_Free(as_geoms);
|
|
|
|
Mem_Free(max_prim_counts);
|
|
|
|
Mem_Free(build_ranges);
|
|
|
|
return retval;
|
2023-05-18 20:59:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RT_BlasDestroy(struct rt_blas_s* blas) {
|
|
|
|
if (!blas)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* if (blas->max_prims) */
|
|
|
|
/* Mem_Free(blas->max_prims); */
|
|
|
|
|
|
|
|
if (blas->blas)
|
|
|
|
vkDestroyAccelerationStructureKHR(vk_core.device, blas->blas, NULL);
|
|
|
|
|
|
|
|
Mem_Free(blas);
|
|
|
|
}
|
|
|
|
|
2023-05-30 21:14:44 +02:00
|
|
|
VkDeviceAddress RT_BlasGetDeviceAddress(struct rt_blas_s *blas) {
|
|
|
|
return getAccelAddress(blas->blas);
|
|
|
|
}
|
|
|
|
|
2023-05-18 20:59:14 +02:00
|
|
|
qboolean RT_BlasBuild(struct rt_blas_s *blas, const struct vk_render_geometry_s *geoms, int geoms_count) {
|
|
|
|
if (!blas || !geoms_count)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
VkAccelerationStructureBuildGeometryInfoKHR build_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR,
|
|
|
|
.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR,
|
2023-06-09 19:03:00 +02:00
|
|
|
.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR,
|
|
|
|
.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR,
|
2023-05-18 20:59:14 +02:00
|
|
|
.geometryCount = geoms_count,
|
|
|
|
.srcAccelerationStructure = VK_NULL_HANDLE,
|
|
|
|
};
|
|
|
|
|
2023-06-09 19:03:00 +02:00
|
|
|
qboolean is_update = false;
|
|
|
|
|
2023-05-18 20:59:14 +02:00
|
|
|
switch (blas->usage) {
|
|
|
|
case kBlasBuildStatic:
|
|
|
|
ASSERT(!blas->blas);
|
|
|
|
break;
|
|
|
|
case kBlasBuildDynamicUpdate:
|
2023-06-09 19:03:00 +02:00
|
|
|
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;
|
2023-05-18 20:59:14 +02:00
|
|
|
break;
|
|
|
|
case kBlasBuildDynamicFast:
|
2023-06-07 19:24:29 +02:00
|
|
|
build_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR;
|
2023-05-18 20:59:14 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const VkBuffer geometry_buffer = R_GeometryBuffer_Get();
|
|
|
|
const VkDeviceAddress buffer_addr = R_VkBufferGetDeviceAddress(geometry_buffer);
|
|
|
|
|
2023-06-07 19:24:29 +02:00
|
|
|
// TODO allocate these from static pool
|
2023-05-18 20:59:14 +02:00
|
|
|
VkAccelerationStructureGeometryKHR *const as_geoms = Mem_Calloc(vk_core.pool, geoms_count * sizeof(*as_geoms));
|
|
|
|
uint32_t *const max_prim_counts = Mem_Malloc(vk_core.pool, geoms_count * sizeof(*max_prim_counts));
|
|
|
|
VkAccelerationStructureBuildRangeInfoKHR *const build_ranges = Mem_Calloc(vk_core.pool, geoms_count * sizeof(*build_ranges));
|
|
|
|
|
|
|
|
for (int i = 0; i < geoms_count; ++i) {
|
|
|
|
const vk_render_geometry_t *mg = geoms + i;
|
|
|
|
const uint32_t prim_count = mg->element_count / 3;
|
|
|
|
|
|
|
|
max_prim_counts[i] = prim_count;
|
|
|
|
as_geoms[i] = (VkAccelerationStructureGeometryKHR)
|
|
|
|
{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR,
|
|
|
|
.flags = VK_GEOMETRY_OPAQUE_BIT_KHR, // FIXME this is not true. incoming mode might have transparency eventually (and also dynamically)
|
|
|
|
.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR,
|
|
|
|
.geometry.triangles =
|
|
|
|
(VkAccelerationStructureGeometryTrianglesDataKHR){
|
|
|
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR,
|
|
|
|
.indexType = VK_INDEX_TYPE_UINT16,
|
|
|
|
.maxVertex = mg->max_vertex,
|
|
|
|
.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT,
|
|
|
|
.vertexStride = sizeof(vk_vertex_t),
|
|
|
|
.vertexData.deviceAddress = buffer_addr,
|
|
|
|
.indexData.deviceAddress = buffer_addr,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
build_ranges[i] = (VkAccelerationStructureBuildRangeInfoKHR) {
|
|
|
|
.primitiveCount = prim_count,
|
|
|
|
.primitiveOffset = mg->index_offset * sizeof(uint16_t),
|
|
|
|
.firstVertex = mg->vertex_offset,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
build_info.pGeometries = as_geoms;
|
|
|
|
|
|
|
|
const VkAccelerationStructureBuildSizesInfoKHR build_size = getAccelSizes(&build_info, max_prim_counts);
|
|
|
|
|
|
|
|
qboolean retval = false;
|
|
|
|
|
|
|
|
// allocate blas
|
|
|
|
if (!blas->blas) {
|
2023-05-31 19:13:40 +02:00
|
|
|
blas->blas = createAccel(blas->debug_name, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, build_size.accelerationStructureSize);
|
2023-05-30 21:14:44 +02:00
|
|
|
if (!blas->blas) {
|
2023-08-29 19:12:35 +02:00
|
|
|
ERR("Couldn't create vk accel");
|
2023-05-18 20:59:14 +02:00
|
|
|
goto finalize;
|
2023-05-30 21:14:44 +02:00
|
|
|
}
|
2023-05-18 20:59:14 +02:00
|
|
|
|
|
|
|
blas->blas_size = build_size.accelerationStructureSize;
|
|
|
|
blas->max_geoms = build_info.geometryCount;
|
2023-06-07 19:24:29 +02:00
|
|
|
} else {
|
|
|
|
if (blas->blas_size < build_size.accelerationStructureSize) {
|
2023-08-29 19:12:35 +02:00
|
|
|
ERR("Fast dynamic BLAS %s size exceeded (need %dKiB, have %dKiB, geoms = %d)", blas->debug_name,
|
2023-06-07 19:24:29 +02:00
|
|
|
(int)build_size.accelerationStructureSize / 1024,
|
|
|
|
blas->blas_size / 1024,
|
|
|
|
geoms_count
|
|
|
|
);
|
|
|
|
goto finalize;
|
|
|
|
}
|
2023-05-18 20:59:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build
|
|
|
|
build_info.dstAccelerationStructure = blas->blas;
|
2023-06-09 19:03:00 +02:00
|
|
|
if (!buildAccel(geometry_buffer, &build_info, is_update ? build_size.updateScratchSize : build_size.buildScratchSize, build_ranges)) {
|
2023-08-29 19:12:35 +02:00
|
|
|
ERR("Couldn't build BLAS %s", blas->debug_name);
|
2023-05-18 20:59:14 +02:00
|
|
|
goto finalize;
|
2023-05-30 21:14:44 +02:00
|
|
|
}
|
2023-05-18 20:59:14 +02:00
|
|
|
|
|
|
|
retval = true;
|
|
|
|
|
|
|
|
finalize:
|
|
|
|
Mem_Free(as_geoms);
|
|
|
|
Mem_Free(max_prim_counts);
|
|
|
|
Mem_Free(build_ranges);
|
|
|
|
return retval;
|
|
|
|
}
|