rtx: build blas and tlas only once
This commit is contained in:
parent
af5e20269d
commit
3a8f2ebc45
|
@ -138,6 +138,8 @@ float rand01() {
|
||||||
return uintBitsToFloat(0x3f800000 | (rand() & 0x007fffff)) - 1.;
|
return uintBitsToFloat(0x3f800000 | (rand() & 0x007fffff)) - 1.;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float hash(float f) { return fract(sin(f)*53478.4327); }
|
||||||
|
|
||||||
layout (push_constant) uniform PC {
|
layout (push_constant) uniform PC {
|
||||||
float t;
|
float t;
|
||||||
int bounces;
|
int bounces;
|
||||||
|
@ -180,6 +182,9 @@ void main() {
|
||||||
|
|
||||||
vec3 pos = O+D*l;
|
vec3 pos = O+D*l;
|
||||||
|
|
||||||
|
C = fract(pos / 100.);
|
||||||
|
break;
|
||||||
|
|
||||||
//const int instance_index = rayQueryGetIntersectionInstanceIdEXT(rayQuery, true);
|
//const int instance_index = rayQueryGetIntersectionInstanceIdEXT(rayQuery, true);
|
||||||
const int instance_index = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true);
|
const int instance_index = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true);
|
||||||
|
|
||||||
|
@ -206,7 +211,7 @@ void main() {
|
||||||
const Kusok kusok = kusochki[kusok_index];
|
const Kusok kusok = kusochki[kusok_index];
|
||||||
if (kusok_index == instance_index) {
|
if (kusok_index == instance_index) {
|
||||||
// TODO do we need to do this when we have textures?
|
// TODO do we need to do this when we have textures?
|
||||||
//C += kc * kusok.emissive.rgb;
|
C += kc * vec3(hash(float(instance_index)), hash(float(instance_index)+15.43), hash(float(instance_index)+34.));//kusok.emissive.rgb;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +291,11 @@ void main() {
|
||||||
C += kc * baseColor.rgb * light_color * dot_ld_norm * attenuation;
|
C += kc * baseColor.rgb * light_color * dot_ld_norm * attenuation;
|
||||||
} // for all lights
|
} // for all lights
|
||||||
|
|
||||||
|
const Kusok kusok = kusochki[instance_index];
|
||||||
|
if (any(greaterThan(kusok.emissive.rgb, vec3(0.)))) {
|
||||||
|
C += kc * vec3(hash(float(instance_index)-102.3), hash(float(instance_index)+15.43), hash(float(instance_index)+34.));//kusok.emissive.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
kc *= .9;
|
kc *= .9;
|
||||||
const float rough = .4;
|
const float rough = .4;
|
||||||
O = pos + .01 * normal;
|
O = pos + .01 * normal;
|
||||||
|
@ -297,9 +307,10 @@ void main() {
|
||||||
));
|
));
|
||||||
} // for all bounces
|
} // for all bounces
|
||||||
|
|
||||||
C = mix(C, vec3(1.), printText(vec2(1.,-1.) * vec2(gl_GlobalInvocationID.xy) + vec2(0., imageSize(image).y)));
|
//C = mix(C, vec3(1.), printText(vec2(1.,-1.) * vec2(gl_GlobalInvocationID.xy) + vec2(0., imageSize(image).y)));
|
||||||
|
|
||||||
//if (gl_GlobalInvocationID.x > imageSize(image).x / 2)
|
//if (gl_GlobalInvocationID.x > imageSize(image).x / 2)
|
||||||
|
if (false)
|
||||||
{
|
{
|
||||||
const float wet = .5;
|
const float wet = .5;
|
||||||
C = mix(C, imageLoad(previous_frame, ivec2(gl_GlobalInvocationID.xy)).rgb, wet);
|
C = mix(C, imageLoad(previous_frame, ivec2(gl_GlobalInvocationID.xy)).rgb, wet);
|
||||||
|
|
|
@ -240,6 +240,7 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
|
||||||
model_geometry->index_offset = index_offset;
|
model_geometry->index_offset = index_offset;
|
||||||
model_geometry->vertex_offset = 0;
|
model_geometry->vertex_offset = 0;
|
||||||
model_geometry->texture = t;
|
model_geometry->texture = t;
|
||||||
|
model_geometry->vertex_count = surf->numedges;
|
||||||
|
|
||||||
VK_CreateSurfaceLightmap( surf, mod );
|
VK_CreateSurfaceLightmap( surf, mod );
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,6 @@ typedef struct vk_buffer_alloc_s {
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
qboolean locked;
|
qboolean locked;
|
||||||
vk_lifetime_t lifetime;
|
vk_lifetime_t lifetime;
|
||||||
|
|
||||||
vk_ray_model_handle_t rtx_model;
|
|
||||||
} vk_buffer_alloc_t;
|
} vk_buffer_alloc_t;
|
||||||
|
|
||||||
// TODO estimate
|
// TODO estimate
|
||||||
|
@ -481,6 +479,9 @@ void VK_RenderBegin( void ) {
|
||||||
memset(&g_render_state.dirty_uniform_data, 0, sizeof(g_render_state.dirty_uniform_data));
|
memset(&g_render_state.dirty_uniform_data, 0, sizeof(g_render_state.dirty_uniform_data));
|
||||||
|
|
||||||
g_render_state.num_draw_commands = 0;
|
g_render_state.num_draw_commands = 0;
|
||||||
|
|
||||||
|
if (vk_core.rtx)
|
||||||
|
VK_RayFrameBegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VK_RenderStateSetColor( float r, float g, float b, float a )
|
void VK_RenderStateSetColor( float r, float g, float b, float a )
|
||||||
|
@ -752,35 +753,37 @@ void VK_RenderEndRTX( VkCommandBuffer cmdbuf, VkImageView img_dst_view, VkImage
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ASSERT(vk_core.rtx);
|
ASSERT(vk_core.rtx);
|
||||||
VK_RaySceneBegin();
|
|
||||||
|
|
||||||
for (int i = 0; i < g_render_state.num_draw_commands; ++i) {
|
// FIXME fix me
|
||||||
const draw_command_t *const draw = g_render_state.draw_commands + i;
|
if (!vk_core.rtx) {
|
||||||
const vk_buffer_alloc_t *vertex_buffer = getBufferFromHandle( draw->draw.vertex_buffer );
|
for (int i = 0; i < g_render_state.num_draw_commands; ++i) {
|
||||||
const vk_buffer_alloc_t *index_buffer = draw->draw.index_buffer != InvalidHandle ? getBufferFromHandle( draw->draw.index_buffer ) : NULL;
|
const draw_command_t *const draw = g_render_state.draw_commands + i;
|
||||||
const uint32_t vertex_offset = vertex_buffer->buffer_offset_in_units + draw->draw.vertex_offset;
|
const vk_buffer_alloc_t *vertex_buffer = getBufferFromHandle( draw->draw.vertex_buffer );
|
||||||
|
const vk_buffer_alloc_t *index_buffer = draw->draw.index_buffer != InvalidHandle ? getBufferFromHandle( draw->draw.index_buffer ) : NULL;
|
||||||
|
const uint32_t vertex_offset = vertex_buffer->buffer_offset_in_units + draw->draw.vertex_offset;
|
||||||
|
|
||||||
// TODO there's a more complex story with lifetimes and rebuilds && vertex_buffer->lifetime < LifetimeSingleFrame)
|
// TODO there's a more complex story with lifetimes and rebuilds && vertex_buffer->lifetime < LifetimeSingleFrame)
|
||||||
// TODO it would make sense to join logical models into a single ray model
|
// TODO it would make sense to join logical models into a single ray model
|
||||||
// but here we've completely lost this info, as models are now just a stream
|
// but here we've completely lost this info, as models are now just a stream
|
||||||
// of independent draws
|
// of independent draws
|
||||||
|
|
||||||
const vk_ray_model_dynamic_t dynamic_model = {
|
const vk_ray_model_dynamic_t dynamic_model = {
|
||||||
.element_count = draw->draw.element_count,
|
.element_count = draw->draw.element_count,
|
||||||
.max_vertex = vertex_buffer->count, // TODO this is an upper bound for brushes at least, it can be lowered
|
.max_vertex = vertex_buffer->count, // TODO this is an upper bound for brushes at least, it can be lowered
|
||||||
.index_offset = index_buffer ? (draw->draw.index_offset + index_buffer->buffer_offset_in_units) : UINT32_MAX,
|
.index_offset = index_buffer ? (draw->draw.index_offset + index_buffer->buffer_offset_in_units) : UINT32_MAX,
|
||||||
.vertex_offset = (draw->draw.vertex_offset + vertex_buffer->buffer_offset_in_units),
|
.vertex_offset = (draw->draw.vertex_offset + vertex_buffer->buffer_offset_in_units),
|
||||||
.buffer = g_render.buffer.buffer,
|
.buffer = g_render.buffer.buffer,
|
||||||
.transform_row = &draw->transform,
|
.transform_row = &draw->transform,
|
||||||
.emissive = { draw->draw.emissive.r, draw->draw.emissive.g, draw->draw.emissive.b },
|
.emissive = { draw->draw.emissive.r, draw->draw.emissive.g, draw->draw.emissive.b },
|
||||||
.texture_id = draw->draw.texture,
|
.texture_id = draw->draw.texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
VK_RaySceneAddModelDynamic(cmdbuf, &dynamic_model);
|
VK_RayFrameAddModelDynamic(cmdbuf, &dynamic_model);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const vk_ray_scene_render_args_t args = {
|
const vk_ray_frame_render_args_t args = {
|
||||||
.cmdbuf = cmdbuf,
|
.cmdbuf = cmdbuf,
|
||||||
.dst = {
|
.dst = {
|
||||||
.image_view = img_dst_view,
|
.image_view = img_dst_view,
|
||||||
|
@ -824,14 +827,23 @@ void VK_RenderEndRTX( VkCommandBuffer cmdbuf, VkImageView img_dst_view, VkImage
|
||||||
Matrix4x4_ToArrayFloatGL(view_inv, (float*)ubo_matrices[1]);
|
Matrix4x4_ToArrayFloatGL(view_inv, (float*)ubo_matrices[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
VK_RaySceneEnd(&args);
|
VK_RayFrameEnd(&args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean VK_RenderModelInit( vk_render_model_t *model) {
|
qboolean VK_RenderModelInit( vk_render_model_t *model) {
|
||||||
if (vk_core.rtx) {
|
if (vk_core.rtx) {
|
||||||
PRINT_NOT_IMPLEMENTED();
|
// TODO runtime rtx switch: ???
|
||||||
return false;
|
const vk_buffer_alloc_t *vertex_buffer = getBufferFromHandle( model->vertex_buffer );
|
||||||
|
const vk_buffer_alloc_t *index_buffer = model->index_buffer != InvalidHandle ? getBufferFromHandle( model->index_buffer ) : NULL;
|
||||||
|
const vk_ray_model_init_t args = {
|
||||||
|
.buffer = g_render.buffer.buffer,
|
||||||
|
.index_offset = index_buffer ? index_buffer->buffer_offset_in_units : UINT32_MAX,
|
||||||
|
.vertex_offset = vertex_buffer->buffer_offset_in_units,
|
||||||
|
.model = model,
|
||||||
|
};
|
||||||
|
model->rtx.blas = VK_NULL_HANDLE;
|
||||||
|
return VK_RayModelInit(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO pre-bake optimal draws
|
// TODO pre-bake optimal draws
|
||||||
|
@ -839,14 +851,17 @@ qboolean VK_RenderModelInit( vk_render_model_t *model) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VK_RenderModelDestroy( vk_render_model_t* model ) {
|
void VK_RenderModelDestroy( vk_render_model_t* model ) {
|
||||||
(void)model;
|
|
||||||
|
|
||||||
if (vk_core.rtx) {
|
if (vk_core.rtx) {
|
||||||
PRINT_NOT_IMPLEMENTED();
|
VK_RayModelDestroy(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VK_RenderModelDraw( vk_render_model_t* model ) {
|
void VK_RenderModelDraw( vk_render_model_t* model ) {
|
||||||
|
if (vk_core.rtx) {
|
||||||
|
VK_RayFrameAddModel(model, g_render_state.model);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int current_texture = -1;
|
int current_texture = -1;
|
||||||
int index_count = 0;
|
int index_count = 0;
|
||||||
int index_offset = -1;
|
int index_offset = -1;
|
||||||
|
|
|
@ -73,9 +73,10 @@ typedef struct {
|
||||||
int texture;
|
int texture;
|
||||||
uint32_t element_count;
|
uint32_t element_count;
|
||||||
uint32_t index_offset, vertex_offset;
|
uint32_t index_offset, vertex_offset;
|
||||||
|
uint32_t vertex_count;
|
||||||
} vk_render_geometry_t;
|
} vk_render_geometry_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct vk_render_model_s {
|
||||||
const char *debug_name;
|
const char *debug_name;
|
||||||
int render_mode;
|
int render_mode;
|
||||||
int num_geometries;
|
int num_geometries;
|
||||||
|
@ -88,7 +89,7 @@ typedef struct {
|
||||||
//qboolean dynamic; // whether this model will require data reupload
|
//qboolean dynamic; // whether this model will require data reupload
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
void *blas; // FIXME
|
VkAccelerationStructureKHR blas;
|
||||||
} rtx;
|
} rtx;
|
||||||
} vk_render_model_t;
|
} vk_render_model_t;
|
||||||
|
|
||||||
|
|
670
ref_vk/vk_rtx.c
670
ref_vk/vk_rtx.c
|
@ -54,11 +54,6 @@ typedef struct {
|
||||||
} vk_lighttexture_data_t;
|
} vk_lighttexture_data_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
//int lightmap, texture;
|
|
||||||
//int render_mode;
|
|
||||||
//uint32_t element_count;
|
|
||||||
//uint32_t index_offset, vertex_offset;
|
|
||||||
//VkBuffer buffer;
|
|
||||||
matrix3x4 transform_row;
|
matrix3x4 transform_row;
|
||||||
VkAccelerationStructureKHR accel;
|
VkAccelerationStructureKHR accel;
|
||||||
} vk_ray_model_t;
|
} vk_ray_model_t;
|
||||||
|
@ -86,21 +81,27 @@ static struct {
|
||||||
// TODO this should really be a single uniform buffer for matrices and light data
|
// TODO this should really be a single uniform buffer for matrices and light data
|
||||||
vk_buffer_t lighttextures_buffer;
|
vk_buffer_t lighttextures_buffer;
|
||||||
|
|
||||||
vk_ray_model_t models[MAX_ACCELS];
|
|
||||||
VkAccelerationStructureKHR tlas;
|
VkAccelerationStructureKHR tlas;
|
||||||
|
|
||||||
|
// Data that is alive longer than one frame, usually within one map
|
||||||
|
struct {
|
||||||
|
uint32_t buffer_offset;
|
||||||
|
} map;
|
||||||
|
|
||||||
|
// Per-frame data that is accumulated between RayFrameBegin and End calls
|
||||||
|
struct {
|
||||||
|
int num_models;
|
||||||
|
int num_lighttextures;
|
||||||
|
vk_ray_model_t models[MAX_ACCELS];
|
||||||
|
uint32_t scratch_offset; // for building dynamic blases
|
||||||
|
} frame;
|
||||||
|
|
||||||
unsigned frame_number;
|
unsigned frame_number;
|
||||||
vk_image_t frames[2];
|
vk_image_t frames[2];
|
||||||
|
|
||||||
qboolean reload_pipeline;
|
qboolean reload_pipeline;
|
||||||
} g_rtx;
|
} g_rtx;
|
||||||
|
|
||||||
static struct {
|
|
||||||
int num_models;
|
|
||||||
int num_lighttextures;
|
|
||||||
uint32_t scratch_offset, buffer_offset;
|
|
||||||
} g_rtx_scene;
|
|
||||||
|
|
||||||
static VkDeviceAddress getBufferDeviceAddress(VkBuffer buffer) {
|
static VkDeviceAddress getBufferDeviceAddress(VkBuffer buffer) {
|
||||||
const VkBufferDeviceAddressInfo bdai = {.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, .buffer = buffer};
|
const VkBufferDeviceAddressInfo bdai = {.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, .buffer = buffer};
|
||||||
return vkGetBufferDeviceAddress(vk_core.device, &bdai);
|
return vkGetBufferDeviceAddress(vk_core.device, &bdai);
|
||||||
|
@ -114,102 +115,104 @@ static VkDeviceAddress getASAddress(VkAccelerationStructureKHR as) {
|
||||||
return vkGetAccelerationStructureDeviceAddressKHR(vk_core.device, &asdai);
|
return vkGetAccelerationStructureDeviceAddressKHR(vk_core.device, &asdai);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkAccelerationStructureKHR createAndBuildAccelerationStructure(VkCommandBuffer cmdbuf, const VkAccelerationStructureGeometryKHR *geoms, const uint32_t *max_prim_counts, const VkAccelerationStructureBuildRangeInfoKHR **build_ranges, uint32_t n_geoms, VkAccelerationStructureTypeKHR type) {
|
typedef struct {
|
||||||
VkAccelerationStructureKHR accel;
|
VkAccelerationStructureKHR *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;
|
||||||
|
|
||||||
|
static qboolean createOrUpdateAccelerationStructure(VkCommandBuffer cmdbuf, const as_build_args_t *args) {
|
||||||
|
const qboolean is_update = *args->accel != VK_NULL_HANDLE;
|
||||||
VkAccelerationStructureBuildGeometryInfoKHR build_info = {
|
VkAccelerationStructureBuildGeometryInfoKHR build_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR,
|
||||||
.type = type,
|
.type = args->type,
|
||||||
.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR,
|
.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | ( args->dynamic ? VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR : 0),
|
||||||
.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR,
|
.mode = is_update ? VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR : VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR,
|
||||||
.geometryCount = n_geoms,
|
.geometryCount = args->n_geoms,
|
||||||
.pGeometries = geoms,
|
.pGeometries = args->geoms,
|
||||||
|
.srcAccelerationStructure = *args->accel,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkAccelerationStructureBuildSizesInfoKHR build_size = {
|
VkAccelerationStructureBuildSizesInfoKHR build_size = {
|
||||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR};
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR};
|
||||||
|
|
||||||
VkAccelerationStructureCreateInfoKHR asci = {
|
uint32_t scratch_buffer_size = 0;
|
||||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR,
|
|
||||||
.buffer = g_rtx.accels_buffer.buffer,
|
|
||||||
.offset = g_rtx_scene.buffer_offset,
|
|
||||||
.type = type,
|
|
||||||
};
|
|
||||||
|
|
||||||
vkGetAccelerationStructureBuildSizesKHR(
|
vkGetAccelerationStructureBuildSizesKHR(
|
||||||
vk_core.device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &build_info, max_prim_counts, &build_size);
|
vk_core.device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &build_info, args->max_prim_counts, &build_size);
|
||||||
|
|
||||||
|
scratch_buffer_size = is_update ? build_size.updateScratchSize : build_size.buildScratchSize;
|
||||||
|
|
||||||
if (0)
|
if (0)
|
||||||
{
|
{
|
||||||
uint32_t max_prims = 0;
|
uint32_t max_prims = 0;
|
||||||
for (int i = 0; i < n_geoms; ++i)
|
for (int i = 0; i < args->n_geoms; ++i)
|
||||||
max_prims += max_prim_counts[i];
|
max_prims += args->max_prim_counts[i];
|
||||||
gEngine.Con_Reportf(
|
gEngine.Con_Reportf(
|
||||||
"AS max_prims=%u, n_geoms=%u, build size: %d, scratch size: %d\n", max_prims, n_geoms, build_size.accelerationStructureSize, build_size.buildScratchSize);
|
"AS max_prims=%u, n_geoms=%u, build size: %d, scratch size: %d\n", max_prims, args->n_geoms, build_size.accelerationStructureSize, build_size.buildScratchSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MAX_SCRATCH_BUFFER - g_rtx_scene.scratch_offset < build_size.buildScratchSize) {
|
if (MAX_SCRATCH_BUFFER - g_rtx.frame.scratch_offset < scratch_buffer_size) {
|
||||||
gEngine.Con_Printf(S_ERROR "Scratch buffer overflow: left %u bytes, but need %u\n",
|
gEngine.Con_Printf(S_ERROR "Scratch buffer overflow: left %u bytes, but need %u\n",
|
||||||
MAX_SCRATCH_BUFFER - g_rtx_scene.scratch_offset,
|
MAX_SCRATCH_BUFFER - g_rtx.frame.scratch_offset,
|
||||||
build_size.buildScratchSize);
|
scratch_buffer_size);
|
||||||
return VK_NULL_HANDLE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MAX_ACCELS_BUFFER - g_rtx_scene.buffer_offset < build_size.accelerationStructureSize) {
|
if (*args->accel == VK_NULL_HANDLE) {
|
||||||
gEngine.Con_Printf(S_ERROR "Accels buffer overflow: left %u bytes, but need %u\n",
|
VkAccelerationStructureCreateInfoKHR asci = {
|
||||||
MAX_ACCELS_BUFFER - g_rtx_scene.buffer_offset,
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR,
|
||||||
build_size.accelerationStructureSize);
|
.buffer = g_rtx.accels_buffer.buffer,
|
||||||
return VK_NULL_HANDLE;
|
.offset = g_rtx.map.buffer_offset,
|
||||||
|
.type = args->type,
|
||||||
|
.size = build_size.accelerationStructureSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (MAX_ACCELS_BUFFER - g_rtx.map.buffer_offset < build_size.accelerationStructureSize) {
|
||||||
|
gEngine.Con_Printf(S_ERROR "Accels buffer overflow: left %u bytes, but need %u\n",
|
||||||
|
MAX_ACCELS_BUFFER - g_rtx.map.buffer_offset,
|
||||||
|
build_size.accelerationStructureSize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
XVK_CHECK(vkCreateAccelerationStructureKHR(vk_core.device, &asci, NULL, args->accel));
|
||||||
|
|
||||||
|
g_rtx.map.buffer_offset += build_size.accelerationStructureSize;
|
||||||
|
g_rtx.map.buffer_offset = (g_rtx.map.buffer_offset + 255) & ~255; // Buffer must be aligned to 256 according to spec
|
||||||
}
|
}
|
||||||
|
|
||||||
asci.size = build_size.accelerationStructureSize;
|
build_info.dstAccelerationStructure = *args->accel;
|
||||||
XVK_CHECK(vkCreateAccelerationStructureKHR(vk_core.device, &asci, NULL, &accel));
|
build_info.scratchData.deviceAddress = g_rtx.scratch_buffer_addr + g_rtx.frame.scratch_offset;
|
||||||
|
g_rtx.frame.scratch_offset += scratch_buffer_size;
|
||||||
|
|
||||||
// TODO this function has weird semantics: it allocates data in buffers, but doesn't allocate the AS itself
|
vkCmdBuildAccelerationStructuresKHR(cmdbuf, 1, &build_info, args->build_ranges);
|
||||||
g_rtx_scene.buffer_offset += build_size.accelerationStructureSize;
|
return true;
|
||||||
g_rtx_scene.buffer_offset = (g_rtx_scene.buffer_offset + 255) & ~255; // Buffer must be aligned to 256 according to spec
|
|
||||||
|
|
||||||
build_info.dstAccelerationStructure = accel;
|
|
||||||
build_info.scratchData.deviceAddress = g_rtx.scratch_buffer_addr + g_rtx_scene.scratch_offset;
|
|
||||||
g_rtx_scene.scratch_offset += build_size.buildScratchSize;
|
|
||||||
|
|
||||||
vkCmdBuildAccelerationStructuresKHR(cmdbuf, 1, &build_info, build_ranges);
|
|
||||||
return accel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanupASFIXME(void)
|
void VK_RayNewMap( void ) {
|
||||||
{
|
ASSERT(vk_core.rtx);
|
||||||
// FIXME we really should not do this; cache ASs per model
|
|
||||||
for (int i = 0; i < g_rtx_scene.num_models; ++i) {
|
|
||||||
if (g_rtx.models[i].accel != VK_NULL_HANDLE)
|
|
||||||
vkDestroyAccelerationStructureKHR(vk_core.device, g_rtx.models[i].accel, NULL);
|
|
||||||
}
|
|
||||||
if (g_rtx.tlas != VK_NULL_HANDLE)
|
|
||||||
vkDestroyAccelerationStructureKHR(vk_core.device, g_rtx.tlas, NULL);
|
|
||||||
|
|
||||||
g_rtx_scene.num_models = 0;
|
g_rtx.map.buffer_offset = 0;
|
||||||
g_rtx_scene.num_lighttextures = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VK_RaySceneBegin( void )
|
void VK_RayFrameBegin( void )
|
||||||
{
|
{
|
||||||
ASSERT(vk_core.rtx);
|
ASSERT(vk_core.rtx);
|
||||||
|
|
||||||
// FIXME this buffer might have objects that live longer
|
g_rtx.frame.scratch_offset = 0;
|
||||||
g_rtx_scene.buffer_offset = 0;
|
g_rtx.frame.num_models = 0;
|
||||||
g_rtx_scene.scratch_offset = 0;
|
g_rtx.frame.num_lighttextures = 0;
|
||||||
|
|
||||||
cleanupASFIXME();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void VK_RayFrameAddModelDynamic( VkCommandBuffer cmdbuf, const vk_ray_model_dynamic_t *dynamic)
|
||||||
static vk_ray_model_t *getModelByHandle(vk_ray_model_handle_t handle)
|
|
||||||
{
|
{
|
||||||
}
|
PRINT_NOT_IMPLEMENTED();
|
||||||
*/
|
|
||||||
|
|
||||||
void VK_RaySceneAddModelDynamic( VkCommandBuffer cmdbuf, const vk_ray_model_dynamic_t *dynamic)
|
#if 0
|
||||||
{
|
|
||||||
vk_ray_model_t* model = g_rtx.models + g_rtx_scene.num_models;
|
vk_ray_model_t* model = g_rtx.models + g_rtx_scene.num_models;
|
||||||
ASSERT(g_rtx_scene.num_models <= ARRAYSIZE(g_rtx.models));
|
ASSERT(g_rtx_scene.num_models <= ARRAYSIZE(g_rtx.models));
|
||||||
|
|
||||||
|
@ -246,7 +249,7 @@ void VK_RaySceneAddModelDynamic( VkCommandBuffer cmdbuf, const vk_ray_model_dyna
|
||||||
};
|
};
|
||||||
const VkAccelerationStructureBuildRangeInfoKHR* build_ranges[ARRAYSIZE(geom)] = { &build_range_tri };
|
const VkAccelerationStructureBuildRangeInfoKHR* build_ranges[ARRAYSIZE(geom)] = { &build_range_tri };
|
||||||
|
|
||||||
model->accel = createAndBuildAccelerationStructure(cmdbuf,
|
model->accel = createOrUpdateAccelerationStructure(cmdbuf,
|
||||||
geom, max_prim_counts, build_ranges, ARRAYSIZE(geom), VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR);
|
geom, max_prim_counts, build_ranges, ARRAYSIZE(geom), VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR);
|
||||||
|
|
||||||
if (!model->accel) {
|
if (!model->accel) {
|
||||||
|
@ -287,6 +290,7 @@ void VK_RaySceneAddModelDynamic( VkCommandBuffer cmdbuf, const vk_ray_model_dyna
|
||||||
|
|
||||||
g_rtx_scene.num_models++;
|
g_rtx_scene.num_models++;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createPipeline( void )
|
static void createPipeline( void )
|
||||||
|
@ -300,11 +304,11 @@ static void createPipeline( void )
|
||||||
ASSERT(g_rtx.pipeline);
|
ASSERT(g_rtx.pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VK_RaySceneEnd(const vk_ray_scene_render_args_t* args)
|
void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
||||||
{
|
{
|
||||||
const VkCommandBuffer cmdbuf = args->cmdbuf;
|
const VkCommandBuffer cmdbuf = args->cmdbuf;
|
||||||
const vk_image_t* frame_src = g_rtx.frames + ((g_rtx.frame_number+1)%2);
|
const vk_image_t* frame_src = g_rtx.frames + ((g_rtx.frame_number + 1) % 2);
|
||||||
const vk_image_t* frame_dst = g_rtx.frames + (g_rtx.frame_number%2);
|
const vk_image_t* frame_dst = g_rtx.frames + (g_rtx.frame_number % 2);
|
||||||
|
|
||||||
ASSERT(vk_core.rtx);
|
ASSERT(vk_core.rtx);
|
||||||
// ubo should contain two matrices
|
// ubo should contain two matrices
|
||||||
|
@ -323,9 +327,9 @@ void VK_RaySceneEnd(const vk_ray_scene_render_args_t* args)
|
||||||
|
|
||||||
// Upload all blas instances references to GPU mem
|
// Upload all blas instances references to GPU mem
|
||||||
{
|
{
|
||||||
VkAccelerationStructureInstanceKHR *inst = g_rtx.tlas_geom_buffer.mapped;
|
VkAccelerationStructureInstanceKHR* inst = g_rtx.tlas_geom_buffer.mapped;
|
||||||
for (int i = 0; i < g_rtx_scene.num_models; ++i) {
|
for (int i = 0; i < g_rtx.frame.num_models; ++i) {
|
||||||
const vk_ray_model_t * const model = g_rtx.models + i;
|
const vk_ray_model_t* const model = g_rtx.frame.models + i;
|
||||||
ASSERT(model->accel != VK_NULL_HANDLE);
|
ASSERT(model->accel != VK_NULL_HANDLE);
|
||||||
inst[i] = (VkAccelerationStructureInstanceKHR){
|
inst[i] = (VkAccelerationStructureInstanceKHR){
|
||||||
.instanceCustomIndex = i,
|
.instanceCustomIndex = i,
|
||||||
|
@ -348,7 +352,7 @@ void VK_RaySceneEnd(const vk_ray_scene_render_args_t* args)
|
||||||
.buffer = g_rtx.accels_buffer.buffer,
|
.buffer = g_rtx.accels_buffer.buffer,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = VK_WHOLE_SIZE,
|
.size = VK_WHOLE_SIZE,
|
||||||
}};
|
} };
|
||||||
vkCmdPipelineBarrier(cmdbuf,
|
vkCmdPipelineBarrier(cmdbuf,
|
||||||
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
||||||
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
||||||
|
@ -356,6 +360,8 @@ void VK_RaySceneEnd(const vk_ray_scene_render_args_t* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Create TLAS
|
// 2. Create TLAS
|
||||||
|
/* FIXME once*/
|
||||||
|
if (!g_rtx.tlas && g_rtx.frame.num_models > 0)
|
||||||
{
|
{
|
||||||
const VkAccelerationStructureGeometryKHR tl_geom[] = {
|
const VkAccelerationStructureGeometryKHR tl_geom[] = {
|
||||||
{
|
{
|
||||||
|
@ -370,189 +376,204 @@ void VK_RaySceneEnd(const vk_ray_scene_render_args_t* args)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const uint32_t tl_max_prim_counts[ARRAYSIZE(tl_geom)] = { MAX_ACCELS };
|
||||||
const uint32_t tl_max_prim_counts[ARRAYSIZE(tl_geom)] = {g_rtx_scene.num_models};
|
|
||||||
const VkAccelerationStructureBuildRangeInfoKHR tl_build_range = {
|
const VkAccelerationStructureBuildRangeInfoKHR tl_build_range = {
|
||||||
.primitiveCount = g_rtx_scene.num_models,
|
.primitiveCount = g_rtx.frame.num_models,
|
||||||
};
|
};
|
||||||
const VkAccelerationStructureBuildRangeInfoKHR *tl_build_ranges[] = {&tl_build_range};
|
const VkAccelerationStructureBuildRangeInfoKHR* tl_build_ranges[] = { &tl_build_range };
|
||||||
g_rtx.tlas = createAndBuildAccelerationStructure(cmdbuf,
|
const as_build_args_t asrgs = {
|
||||||
tl_geom, tl_max_prim_counts, tl_build_ranges, ARRAYSIZE(tl_geom), VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR);
|
.geoms = tl_geom,
|
||||||
|
.max_prim_counts = tl_max_prim_counts,
|
||||||
|
.build_ranges = tl_build_ranges,
|
||||||
|
.n_geoms = ARRAYSIZE(tl_geom),
|
||||||
|
.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR,
|
||||||
|
.dynamic = true,
|
||||||
|
.accel = &g_rtx.tlas,
|
||||||
|
};
|
||||||
|
if (!createOrUpdateAccelerationStructure(cmdbuf, &asrgs)) {
|
||||||
|
gEngine.Host_Error("Could not create/update TLAS\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Update descriptor sets (bind dest image, tlas, projection matrix)
|
if (g_rtx.tlas != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
const VkDescriptorImageInfo dii_dst = {
|
// 3. Update descriptor sets (bind dest image, tlas, projection matrix)
|
||||||
.sampler = VK_NULL_HANDLE,
|
{
|
||||||
.imageView = frame_dst->view,
|
const VkDescriptorImageInfo dii_dst = {
|
||||||
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.sampler = VK_NULL_HANDLE,
|
||||||
};
|
.imageView = frame_dst->view,
|
||||||
const VkDescriptorImageInfo dii_src = {
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.sampler = VK_NULL_HANDLE,
|
};
|
||||||
.imageView = frame_src->view,
|
const VkDescriptorImageInfo dii_src = {
|
||||||
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.sampler = VK_NULL_HANDLE,
|
||||||
};
|
.imageView = frame_src->view,
|
||||||
const VkDescriptorBufferInfo dbi_ubo = {
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.buffer = args->ubo.buffer,
|
};
|
||||||
.offset = args->ubo.offset,
|
const VkDescriptorBufferInfo dbi_ubo = {
|
||||||
.range = args->ubo.size,
|
.buffer = args->ubo.buffer,
|
||||||
};
|
.offset = args->ubo.offset,
|
||||||
const VkDescriptorBufferInfo dbi_kusochki = {
|
.range = args->ubo.size,
|
||||||
.buffer = g_rtx.kusochki_buffer.buffer,
|
};
|
||||||
.offset = 0,
|
const VkDescriptorBufferInfo dbi_kusochki = {
|
||||||
.range = VK_WHOLE_SIZE, // TODO fails validation when empty g_rtx_scene.num_models * sizeof(vk_kusok_data_t),
|
.buffer = g_rtx.kusochki_buffer.buffer,
|
||||||
};
|
.offset = 0,
|
||||||
const VkDescriptorBufferInfo dbi_indices = {
|
.range = VK_WHOLE_SIZE, // TODO fails validation when empty g_rtx_scene.num_models * sizeof(vk_kusok_data_t),
|
||||||
.buffer = args->geometry_data.buffer,
|
};
|
||||||
.offset = 0,
|
const VkDescriptorBufferInfo dbi_indices = {
|
||||||
.range = VK_WHOLE_SIZE, // TODO fails validation when empty args->geometry_data.size,
|
.buffer = args->geometry_data.buffer,
|
||||||
};
|
.offset = 0,
|
||||||
const VkDescriptorBufferInfo dbi_vertices = {
|
.range = VK_WHOLE_SIZE, // TODO fails validation when empty args->geometry_data.size,
|
||||||
.buffer = args->geometry_data.buffer,
|
};
|
||||||
.offset = 0,
|
const VkDescriptorBufferInfo dbi_vertices = {
|
||||||
.range = VK_WHOLE_SIZE, // TODO fails validation when empty args->geometry_data.size,
|
.buffer = args->geometry_data.buffer,
|
||||||
};
|
.offset = 0,
|
||||||
const VkWriteDescriptorSetAccelerationStructureKHR wdsas = {
|
.range = VK_WHOLE_SIZE, // TODO fails validation when empty args->geometry_data.size,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
|
};
|
||||||
.accelerationStructureCount = 1,
|
const VkWriteDescriptorSetAccelerationStructureKHR wdsas = {
|
||||||
.pAccelerationStructures = &g_rtx.tlas,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
|
||||||
};
|
.accelerationStructureCount = 1,
|
||||||
const VkDescriptorBufferInfo dbi_dlights = {
|
.pAccelerationStructures = &g_rtx.tlas,
|
||||||
.buffer = args->dlights.buffer,
|
};
|
||||||
.offset = args->dlights.offset,
|
const VkDescriptorBufferInfo dbi_dlights = {
|
||||||
.range = args->dlights.size,
|
.buffer = args->dlights.buffer,
|
||||||
};
|
.offset = args->dlights.offset,
|
||||||
const VkDescriptorBufferInfo dbi_lighttextures = {
|
.range = args->dlights.size,
|
||||||
.buffer = g_rtx.lighttextures_buffer.buffer,
|
};
|
||||||
.offset = 0,
|
const VkDescriptorBufferInfo dbi_lighttextures = {
|
||||||
.range = VK_WHOLE_SIZE,
|
.buffer = g_rtx.lighttextures_buffer.buffer,
|
||||||
};
|
.offset = 0,
|
||||||
const VkWriteDescriptorSet wds[] = {
|
.range = VK_WHOLE_SIZE,
|
||||||
{
|
};
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
const VkWriteDescriptorSet wds[] = {
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 0,
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pImageInfo = &dii_dst,
|
.dstBinding = 0,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
{
|
.pImageInfo = &dii_dst,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
},
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 1,
|
.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pNext = &wdsas,
|
.dstBinding = 1,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
{
|
.pNext = &wdsas,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
},
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 2,
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pBufferInfo = &dbi_ubo,
|
.dstBinding = 2,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
{
|
.pBufferInfo = &dbi_ubo,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
},
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 3,
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pBufferInfo = &dbi_kusochki,
|
.dstBinding = 3,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
{
|
.pBufferInfo = &dbi_kusochki,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
},
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 4,
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pBufferInfo = &dbi_indices,
|
.dstBinding = 4,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
{
|
.pBufferInfo = &dbi_indices,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
},
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 5,
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pBufferInfo = &dbi_vertices,
|
.dstBinding = 5,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
{
|
.pBufferInfo = &dbi_vertices,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
},
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 6,
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pBufferInfo = &dbi_dlights,
|
.dstBinding = 6,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
{
|
.pBufferInfo = &dbi_dlights,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
},
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 7,
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pBufferInfo = &dbi_lighttextures,
|
.dstBinding = 7,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
{
|
.pBufferInfo = &dbi_lighttextures,
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
},
|
||||||
.descriptorCount = 1,
|
{
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstSet = g_rtx.desc_set,
|
.descriptorCount = 1,
|
||||||
.dstBinding = 8,
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||||
.dstArrayElement = 0,
|
.dstSet = g_rtx.desc_set,
|
||||||
.pImageInfo = &dii_src,
|
.dstBinding = 8,
|
||||||
},
|
.dstArrayElement = 0,
|
||||||
};
|
.pImageInfo = &dii_src,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Barrier for TLAS build and dest image layout transfer
|
// 4. Barrier for TLAS build and dest image layout transfer
|
||||||
{
|
{
|
||||||
VkBufferMemoryBarrier bmb[] = { {
|
VkBufferMemoryBarrier bmb[] = { {
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||||
.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
|
.srcAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
|
||||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||||
.buffer = g_rtx.accels_buffer.buffer,
|
.buffer = g_rtx.accels_buffer.buffer,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = VK_WHOLE_SIZE,
|
.size = VK_WHOLE_SIZE,
|
||||||
}};
|
} };
|
||||||
VkImageMemoryBarrier image_barrier[] = { {
|
VkImageMemoryBarrier image_barrier[] = { {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
.image = frame_dst->image,
|
.image = frame_dst->image,
|
||||||
.srcAccessMask = 0,
|
.srcAccessMask = 0,
|
||||||
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.subresourceRange = (VkImageSubresourceRange) {
|
.subresourceRange = (VkImageSubresourceRange) {
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = 1,
|
.levelCount = 1,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
}} };
|
}} };
|
||||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
|
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
|
||||||
0, NULL, ARRAYSIZE(bmb), bmb, ARRAYSIZE(image_barrier), image_barrier);
|
0, NULL, ARRAYSIZE(bmb), bmb, ARRAYSIZE(image_barrier), image_barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. dispatch compute
|
if (g_rtx.tlas) {
|
||||||
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, g_rtx.pipeline);
|
// 4. dispatch compute
|
||||||
{
|
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, g_rtx.pipeline);
|
||||||
vk_rtx_push_constants_t push_constants = {
|
{
|
||||||
.t = gpGlobals->realtime,
|
vk_rtx_push_constants_t push_constants = {
|
||||||
.bounces = vk_rtx_bounces->value,
|
.t = gpGlobals->realtime,
|
||||||
};
|
.bounces = vk_rtx_bounces->value,
|
||||||
vkCmdPushConstants(cmdbuf, g_rtx.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(push_constants), &push_constants);
|
};
|
||||||
|
vkCmdPushConstants(cmdbuf, g_rtx.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(push_constants), &push_constants);
|
||||||
|
}
|
||||||
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, g_rtx.pipeline_layout, 0, 1, &g_rtx.desc_set, 0, NULL);
|
||||||
|
vkCmdDispatch(cmdbuf, (FRAME_WIDTH + WG_W - 1) / WG_W, (FRAME_HEIGHT + WG_H - 1) / WG_H, 1);
|
||||||
}
|
}
|
||||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, g_rtx.pipeline_layout, 0, 1, &g_rtx.desc_set, 0, NULL);
|
|
||||||
vkCmdDispatch(cmdbuf, (FRAME_WIDTH+WG_W-1)/WG_W, (FRAME_HEIGHT+WG_H-1)/WG_H, 1);
|
|
||||||
|
|
||||||
// Blit RTX frame onto swapchain image
|
// Blit RTX frame onto swapchain image
|
||||||
{
|
{
|
||||||
|
@ -820,8 +841,8 @@ void VK_RayShutdown( void )
|
||||||
vkDestroyPipelineLayout(vk_core.device, g_rtx.pipeline_layout, NULL);
|
vkDestroyPipelineLayout(vk_core.device, g_rtx.pipeline_layout, NULL);
|
||||||
vkDestroyDescriptorSetLayout(vk_core.device, g_rtx.desc_layout, NULL);
|
vkDestroyDescriptorSetLayout(vk_core.device, g_rtx.desc_layout, NULL);
|
||||||
|
|
||||||
// TODO dealloc all ASes
|
if (g_rtx.tlas != VK_NULL_HANDLE)
|
||||||
cleanupASFIXME();
|
vkDestroyAccelerationStructureKHR(vk_core.device, g_rtx.tlas, NULL);
|
||||||
|
|
||||||
destroyBuffer(&g_rtx.scratch_buffer);
|
destroyBuffer(&g_rtx.scratch_buffer);
|
||||||
destroyBuffer(&g_rtx.accels_buffer);
|
destroyBuffer(&g_rtx.accels_buffer);
|
||||||
|
@ -830,3 +851,140 @@ void VK_RayShutdown( void )
|
||||||
destroyBuffer(&g_rtx.lighttextures_buffer);
|
destroyBuffer(&g_rtx.lighttextures_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qboolean VK_RayModelInit( vk_ray_model_init_t args ) {
|
||||||
|
VkAccelerationStructureGeometryKHR *geoms = Mem_Malloc(vk_core.pool, args.model->num_geometries * sizeof(*geoms));
|
||||||
|
uint32_t *geom_max_prim_counts = Mem_Malloc(vk_core.pool, args.model->num_geometries * sizeof(*geom_max_prim_counts));
|
||||||
|
VkAccelerationStructureBuildRangeInfoKHR *geom_build_ranges = Mem_Malloc(vk_core.pool, args.model->num_geometries * sizeof(*geom_build_ranges));
|
||||||
|
VkAccelerationStructureBuildRangeInfoKHR **geom_build_ranges_ptr = Mem_Malloc(vk_core.pool, args.model->num_geometries * sizeof(*geom_build_ranges));
|
||||||
|
const VkDeviceAddress buffer_addr = getBufferDeviceAddress(args.buffer);
|
||||||
|
qboolean result;
|
||||||
|
|
||||||
|
ASSERT(vk_core.rtx);
|
||||||
|
|
||||||
|
for (int i = 0; i < args.model->num_geometries; ++i) {
|
||||||
|
const vk_render_geometry_t *mg = args.model->geometries + i;
|
||||||
|
const uint32_t prim_count = mg->element_count / 3;
|
||||||
|
|
||||||
|
geom_max_prim_counts[i] = prim_count;
|
||||||
|
geoms[i] = (VkAccelerationStructureGeometryKHR)
|
||||||
|
{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR,
|
||||||
|
.flags = VK_GEOMETRY_OPAQUE_BIT_KHR,
|
||||||
|
.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR,
|
||||||
|
.geometry.triangles =
|
||||||
|
(VkAccelerationStructureGeometryTrianglesDataKHR){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR,
|
||||||
|
.indexType = args.index_offset == UINT32_MAX ? VK_INDEX_TYPE_NONE_KHR : VK_INDEX_TYPE_UINT16,
|
||||||
|
.maxVertex = mg->vertex_count,
|
||||||
|
.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT,
|
||||||
|
.vertexStride = sizeof(vk_vertex_t),
|
||||||
|
.vertexData.deviceAddress = buffer_addr + (args.vertex_offset + mg->vertex_offset) * sizeof(vk_vertex_t),
|
||||||
|
.indexData.deviceAddress = buffer_addr + (args.index_offset + mg->index_offset) * sizeof(uint16_t),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
geom_build_ranges[i] = (VkAccelerationStructureBuildRangeInfoKHR) {
|
||||||
|
.primitiveCount = prim_count,
|
||||||
|
};
|
||||||
|
geom_build_ranges_ptr[i] = geom_build_ranges + i;
|
||||||
|
|
||||||
|
// Store geometry references in kusochki
|
||||||
|
// FIXME
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
vk_kusok_data_t *kusok = (vk_kusok_data_t*)(g_rtx.kusochki_buffer.mapped) + g_rtx_scene.num_models;
|
||||||
|
kusok->vertex_offset = dynamic->vertex_offset;
|
||||||
|
kusok->index_offset = dynamic->index_offset;
|
||||||
|
ASSERT(dynamic->element_count % 3 == 0);
|
||||||
|
kusok->triangles = dynamic->element_count / 3;
|
||||||
|
|
||||||
|
ASSERT(dynamic->texture_id < MAX_TEXTURES);
|
||||||
|
if (dynamic->texture_id >= 0 && g_emissive_texture_table[dynamic->texture_id].set) {
|
||||||
|
VectorCopy(g_emissive_texture_table[dynamic->texture_id].emissive, kusok->emissive);
|
||||||
|
} else {
|
||||||
|
kusok->emissive[0] = dynamic->emissive.r;
|
||||||
|
kusok->emissive[1] = dynamic->emissive.g;
|
||||||
|
kusok->emissive[2] = dynamic->emissive.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kusok->emissive[0] > 0 || kusok->emissive[1] > 0 || kusok->emissive[2] > 0) {
|
||||||
|
if (g_rtx_scene.num_lighttextures < MAX_LIGHT_TEXTURES) {
|
||||||
|
vk_lighttexture_data_t *ltd = (vk_lighttexture_data_t*)g_rtx.lighttextures_buffer.mapped;
|
||||||
|
ltd->lighttexture[g_rtx_scene.num_lighttextures].kusok_index = g_rtx_scene.num_models;
|
||||||
|
g_rtx_scene.num_lighttextures++;
|
||||||
|
ltd->num_lighttextures = g_rtx_scene.num_lighttextures;
|
||||||
|
} else {
|
||||||
|
gEngine.Con_Printf(S_ERROR "Ran out of light textures space");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const as_build_args_t asrgs = {
|
||||||
|
.geoms = geoms,
|
||||||
|
.max_prim_counts = geom_max_prim_counts,
|
||||||
|
.build_ranges = geom_build_ranges_ptr,
|
||||||
|
.n_geoms = args.model->num_geometries,
|
||||||
|
.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR,
|
||||||
|
.dynamic = false, //model->dynamic,
|
||||||
|
.accel = &args.model->rtx.blas,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO batch building multiple blases together
|
||||||
|
const VkCommandBufferBeginInfo beginfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||||
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||||
|
};
|
||||||
|
XVK_CHECK(vkBeginCommandBuffer(vk_core.cb, &beginfo));
|
||||||
|
|
||||||
|
result = createOrUpdateAccelerationStructure(vk_core.cb, &asrgs);
|
||||||
|
|
||||||
|
XVK_CHECK(vkEndCommandBuffer(vk_core.cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const VkSubmitInfo subinfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||||
|
.commandBufferCount = 1,
|
||||||
|
.pCommandBuffers = &vk_core.cb,
|
||||||
|
};
|
||||||
|
XVK_CHECK(vkQueueSubmit(vk_core.queue, 1, &subinfo, VK_NULL_HANDLE));
|
||||||
|
XVK_CHECK(vkQueueWaitIdle(vk_core.queue));
|
||||||
|
g_rtx.frame.scratch_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mem_Free(geom_build_ranges);
|
||||||
|
Mem_Free(geom_max_prim_counts);
|
||||||
|
Mem_Free(geoms);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VK_RayModelDestroy( struct vk_render_model_s *model ) {
|
||||||
|
ASSERT(vk_core.rtx);
|
||||||
|
if (model->rtx.blas != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyAccelerationStructureKHR(vk_core.device, model->rtx.blas, NULL);
|
||||||
|
model->rtx.blas = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VK_RayFrameAddModel( const struct vk_render_model_s *model, const matrix3x4 *transform_row ) {
|
||||||
|
ASSERT(vk_core.rtx);
|
||||||
|
|
||||||
|
ASSERT(g_rtx.frame.num_models <= ARRAYSIZE(g_rtx.frame.models));
|
||||||
|
|
||||||
|
if (g_rtx.frame.num_models == ARRAYSIZE(g_rtx.frame.models)) {
|
||||||
|
gEngine.Con_Printf(S_ERROR "Ran out of AccelerationStructure slots\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
vk_ray_model_t* ray_model = g_rtx.frame.models + g_rtx.frame.num_models;
|
||||||
|
ASSERT(model->rtx.blas != VK_NULL_HANDLE);
|
||||||
|
ray_model->accel = model->rtx.blas;
|
||||||
|
memcpy(ray_model->transform_row, *transform_row, sizeof(ray_model->transform_row));
|
||||||
|
g_rtx.frame.num_models++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,17 @@
|
||||||
|
|
||||||
#include "vk_core.h"
|
#include "vk_core.h"
|
||||||
|
|
||||||
|
struct vk_render_model_s;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct vk_render_model_s *model;
|
||||||
|
VkBuffer buffer;
|
||||||
|
uint32_t vertex_offset, index_offset;
|
||||||
|
} vk_ray_model_init_t;
|
||||||
|
|
||||||
|
qboolean VK_RayModelInit( vk_ray_model_init_t model_init);
|
||||||
|
void VK_RayModelDestroy( struct vk_render_model_s *model );
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
//int lightmap, texture;
|
//int lightmap, texture;
|
||||||
//int render_mode;
|
//int render_mode;
|
||||||
|
@ -14,8 +25,9 @@ typedef struct {
|
||||||
struct { float r,g,b; } emissive;
|
struct { float r,g,b; } emissive;
|
||||||
} vk_ray_model_dynamic_t;
|
} vk_ray_model_dynamic_t;
|
||||||
|
|
||||||
void VK_RaySceneBegin( void );
|
void VK_RayFrameBegin( void );
|
||||||
void VK_RaySceneAddModelDynamic(VkCommandBuffer cmdbuf, const vk_ray_model_dynamic_t* model);
|
void VK_RayFrameAddModel( const struct vk_render_model_s *model, const matrix3x4 *transform_row );
|
||||||
|
void VK_RayFrameAddModelDynamic(VkCommandBuffer cmdbuf, const vk_ray_model_dynamic_t* model);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VkCommandBuffer cmdbuf;
|
VkCommandBuffer cmdbuf;
|
||||||
|
@ -44,8 +56,10 @@ typedef struct {
|
||||||
VkBuffer buffer; // must be the same as in vk_ray_model_create_t TODO: validate or make impossible to specify incorrectly
|
VkBuffer buffer; // must be the same as in vk_ray_model_create_t TODO: validate or make impossible to specify incorrectly
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
} geometry_data;
|
} geometry_data;
|
||||||
} vk_ray_scene_render_args_t;
|
} vk_ray_frame_render_args_t;
|
||||||
void VK_RaySceneEnd(const vk_ray_scene_render_args_t* args);
|
void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args);
|
||||||
|
|
||||||
|
void VK_RayNewMap( void );
|
||||||
|
|
||||||
qboolean VK_RayInit( void );
|
qboolean VK_RayInit( void );
|
||||||
void VK_RayShutdown( void );
|
void VK_RayShutdown( void );
|
||||||
|
|
|
@ -85,7 +85,15 @@ void R_NewMap( void )
|
||||||
{
|
{
|
||||||
const int num_models = gEngine.EngineGetParm( PARM_NUMMODELS, 0 );
|
const int num_models = gEngine.EngineGetParm( PARM_NUMMODELS, 0 );
|
||||||
|
|
||||||
gEngine.Con_Reportf( "R_NewMap\n" );
|
// Existence of cache.data for the world means that we've already have loaded this map
|
||||||
|
// and this R_NewMap call is from within loading of a saved game.
|
||||||
|
const qboolean is_save_load = !!gEngine.pfnGetModelByIndex( 1 )->cache.data;
|
||||||
|
|
||||||
|
gEngine.Con_Reportf( "R_NewMap, loading save: %d\n", is_save_load );
|
||||||
|
|
||||||
|
// Skip clearing already loaded data if the map hasn't changed.
|
||||||
|
if (is_save_load)
|
||||||
|
return;
|
||||||
|
|
||||||
VK_ClearLightmap();
|
VK_ClearLightmap();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue