rtx: split color into base and diffuseGI; add dumb denoiser

This commit is contained in:
Ivan 'provod' Avdeev 2021-11-07 12:46:27 -08:00 committed by Ivan Avdeev
parent 0627c612c3
commit 4cfe76dc40
8 changed files with 332 additions and 188 deletions

View File

@ -1,9 +1,12 @@
#version 460
#include "noise.glsl"
layout(local_size_x = 16, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0, rgba16f) uniform image2D source;
layout(set = 0, binding = 1, rgba16f) uniform image2D dest;
layout(set = 0, binding = 0, rgba8) uniform image2D src_base_color;
layout(set = 0, binding = 1, rgba16f) uniform image2D src_diffuse_gi;
layout(set = 0, binding = 2, rgba16f) uniform image2D dest;
// Blatantly copypasted from https://www.shadertoy.com/view/XsGfWV
vec3 aces_tonemap(vec3 color){
@ -24,13 +27,44 @@ vec3 aces_tonemap(vec3 color){
}
void main() {
ivec2 res = ivec2(imageSize(source));
ivec2 res = ivec2(imageSize(src_base_color));
ivec2 pix = ivec2(gl_GlobalInvocationID);
if (any(greaterThanEqual(pix, res))) {
return;
}
vec3 colour = vec3(0.);
if (all(lessThan(pix, res)))
colour = aces_tonemap(imageLoad(source, pix).rgb);
const vec4 base_color = imageLoad(src_base_color, pix);
const float material_index = imageLoad(src_diffuse_gi, pix).a;
imageStore(dest, pix, vec4(colour, 1.));
// const uint mi = uint(material_index);
// imageStore(dest, pix, vec4(rand3_f01(uvec3(mi,mi+1,mi+2)), 0.));
// return;
const int KERNEL_SIZE = 8;
float scale = 0.;
for (int x = -KERNEL_SIZE; x <= KERNEL_SIZE; ++x)
for (int y = -KERNEL_SIZE; y <= KERNEL_SIZE; ++y) {
const ivec2 p = pix + ivec2(x, y);
if (any(greaterThanEqual(p, res)) || any(lessThan(p, ivec2(0)))) {
continue;
}
const vec4 c = imageLoad(src_diffuse_gi, p);
if (c.a == material_index) {
colour += imageLoad(src_diffuse_gi, p).rgb;
scale += 1.;
}
}
if (scale > 0.) {
colour /= scale;
colour *= base_color.rgb;
colour = aces_tonemap(colour);
}
imageStore(dest, pix, vec4(colour, 0.));
//imageStore(dest, pix, imageLoad(src_diffuse_gi, pix));
}

View File

@ -109,4 +109,5 @@ void main() {
payload.emissive = kusochki[kusok_index].emissive * base_color; // TODO emissive should have a special texture
payload.roughness = kusochki[kusok_index].roughness;
payload.kusok_index = kusok_index;
payload.material_index = nonuniformEXT(tex_index);
}

View File

@ -21,7 +21,9 @@ layout (constant_id = 5) const uint MAX_LIGHT_CLUSTERS = 32768;
//const uint LIGHT_CLUSTER_DLIGHTS_DATA_OFFSET = 2;
//const uint LIGHT_CLUSTER_EMISSIVE_SURFACES_DATA_OFFSET = 3 + MAX_VISIBLE_DLIGHTS;
layout(set = 0, binding = 0, rgba8) uniform image2D image;
layout(set = 0, binding = 0, rgba8) uniform image2D out_image_base_color;
layout(set = 0, binding = 9, rgba16f) uniform image2D out_image_diffuse_gi;
layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas;
layout(set = 0, binding = 2) uniform UBO {
mat4 inv_proj, inv_view;
@ -143,7 +145,7 @@ vec3 computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
const uint i = uint(light_grid.clusters[cluster_index].point_lights[j]);
vec3 color = lights.point_lights[i].color_stopdot.rgb;
color *= throughput * payload_opaque.base_color;
color *= throughput * material.baseColor;
if (dot(color,color) < color_culling_threshold)
continue;
@ -262,7 +264,7 @@ vec3 computeLighting(vec3 throughput, vec3 view_dir, MaterialProperties material
continue;
const uint triangle_index = rand_range(ekusok.triangles);
C += sampling_light_scale * sampleSurfaceTriangle(throughput * payload_opaque.base_color * ek.emissive, view_dir, material, emissive_transform, emissive_transform_normal, triangle_index, ekusok.index_offset, ekusok.vertex_offset);
C += sampling_light_scale * sampleSurfaceTriangle(throughput * material.baseColor * ek.emissive, view_dir, material, emissive_transform, emissive_transform_normal, triangle_index, ekusok.index_offset, ekusok.vertex_offset);
} // for all emissive kusochki
C += computePointLights(cluster_index, throughput, view_dir, material);
@ -299,9 +301,14 @@ void main() {
vec3 throughput = vec3(1.);
vec3 C = vec3(0.);
payload_opaque.material_index = 0;
payload_opaque.t_offset = .0;
payload_opaque.pixel_cone_spread_angle = push_constants.pixel_cone_spread_angle;
float out_material_index = 0.;
vec4 out_base_color = vec4(0.);
//vec4 out_diffuse_gi = vec4(0.);
int brdfType = SPECULAR_TYPE;
for (int bounce = 0; bounce < push_constants.bounces; ++bounce) {
// TODO early exit based on throughput being too small
@ -364,9 +371,15 @@ void main() {
material.emissive = payload_opaque.emissive;
material.roughness = payload_opaque.roughness;
if (bounce == 0) //brdfType == SPECULAR_TYPE)
if (bounce == 0) { //brdfType == SPECULAR_TYPE)
C += throughput * payload_opaque.emissive;
out_base_color.rgb = payload_opaque.base_color;
material.baseColor = vec3(1.);
payload_opaque.base_color = vec3(1.);
out_material_index = float(payload_opaque.material_index);
}
// TODO should we do this after reflect/transmit decision?
#define SKIP_TRASMITTED_LIGHT
#ifndef SKIP_TRASMITTED_LIGHT
@ -422,5 +435,6 @@ void main() {
C /= color_factor;
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(C, 1.));
imageStore(out_image_base_color, ivec2(gl_LaunchIDEXT.xy), out_base_color);
imageStore(out_image_diffuse_gi, ivec2(gl_LaunchIDEXT.xy), vec4(C, out_material_index));
}

View File

@ -13,7 +13,7 @@ void main() {
payload.geometry_normal = payload.normal = vec3(0., 1., 0.);
payload.transmissiveness = 0.;
payload.roughness = 0.;
payload.base_color = vec3(0.);//mix(vec3(.1, .2, .7), lights.sun_color, pow(sun_dot, 100.));
//vec3(1., 0., 1.);
payload.base_color = vec3(1., 0., 1.);
payload.kusok_index = -1;
payload.material_index = 0;
}

View File

@ -14,6 +14,7 @@ struct RayPayloadOpaque {
vec3 emissive;
float roughness;
int kusok_index;
uint material_index;
};
struct RayPayloadShadow {

View File

@ -6,8 +6,9 @@
#include "eiface.h" // ARRAYSIZE
enum {
DenoiserBinding_SourceImage = 0,
DenoiserBinding_DestImage = 1,
DenoiserBinding_Source_BaseColor = 0,
DenoiserBinding_Source_DiffuseGI = 1,
DenoiserBinding_DestImage = 2,
DenoiserBinding_COUNT
};
@ -41,8 +42,15 @@ static void createLayouts( void ) {
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
};
g_denoiser.desc_bindings[DenoiserBinding_SourceImage] = (VkDescriptorSetLayoutBinding){
.binding = DenoiserBinding_SourceImage,
g_denoiser.desc_bindings[DenoiserBinding_Source_BaseColor] = (VkDescriptorSetLayoutBinding){
.binding = DenoiserBinding_Source_BaseColor,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
};
g_denoiser.desc_bindings[DenoiserBinding_Source_DiffuseGI] = (VkDescriptorSetLayoutBinding){
.binding = DenoiserBinding_Source_DiffuseGI,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
@ -80,19 +88,31 @@ void XVK_DenoiserDestroy( void ) {
VK_DescriptorsDestroy(&g_denoiser.descriptors);
}
void XVK_DenoiserReloadPipeline( void ) {
// TODO handle errors gracefully
vkDestroyPipeline(vk_core.device, g_denoiser.pipeline, NULL);
g_denoiser.pipeline = createPipeline();
}
void XVK_DenoiserDenoise( const xvk_denoiser_args_t* args ) {
const uint32_t WG_W = 16;
const uint32_t WG_H = 8;
g_denoiser.desc_values[DenoiserBinding_SourceImage].image = (VkDescriptorImageInfo){
g_denoiser.desc_values[DenoiserBinding_Source_BaseColor].image = (VkDescriptorImageInfo){
.sampler = VK_NULL_HANDLE,
.imageView = args->view_src,
.imageView = args->src.base_color_view,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
};
g_denoiser.desc_values[DenoiserBinding_Source_DiffuseGI].image = (VkDescriptorImageInfo){
.sampler = VK_NULL_HANDLE,
.imageView = args->src.diffuse_gi_view,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
};
g_denoiser.desc_values[DenoiserBinding_DestImage].image = (VkDescriptorImageInfo){
.sampler = VK_NULL_HANDLE,
.imageView = args->view_dst,
.imageView = args->dst_view,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
};

View File

@ -5,10 +5,18 @@
qboolean XVK_DenoiserInit( void );
void XVK_DenoiserDestroy( void );
void XVK_DenoiserReloadPipeline( void );
typedef struct {
VkCommandBuffer cmdbuf;
uint32_t width, height;
VkImageView view_src, view_dst;
struct {
VkImageView base_color_view;
VkImageView diffuse_gi_view;
} src;
VkImageView dst_view;
} xvk_denoiser_args_t;
void XVK_DenoiserDenoise( const xvk_denoiser_args_t* args );

View File

@ -59,7 +59,7 @@ typedef struct {
} vk_ray_shader_light_grid;
enum {
RayDescBinding_DestImage = 0,
RayDescBinding_Dest_ImageBaseColor = 0,
RayDescBinding_TLAS = 1,
RayDescBinding_UBOMatrices = 2,
@ -71,9 +71,19 @@ enum {
RayDescBinding_Lights = 7,
RayDescBinding_LightClusters = 8,
RayDescBinding_Dest_ImageDiffuseGI = 9,
//RayDescBinding_Dest_ImageNormal = 10,
//RayDescBinding_Dest_ImageSpecular = 11,
RayDescBinding_COUNT
};
typedef struct {
vk_image_t denoised;
vk_image_t base_color;
vk_image_t diffuse_gi;
} xvk_ray_frame_images_t;
static struct {
vk_descriptors_t descriptors;
VkDescriptorSetLayoutBinding desc_bindings[RayDescBinding_COUNT];
@ -127,7 +137,7 @@ static struct {
} frame;
unsigned frame_number;
vk_image_t frames[2];
xvk_ray_frame_images_t frames[2];
qboolean reload_pipeline;
qboolean reload_lighting;
@ -557,13 +567,13 @@ static void prepareTlas( VkCommandBuffer cmdbuf ) {
createTlas(cmdbuf);
}
static void updateDescriptors( VkCommandBuffer cmdbuf, const vk_ray_frame_render_args_t *args, const vk_image_t *frame_dst ) {
static void updateDescriptors( VkCommandBuffer cmdbuf, const vk_ray_frame_render_args_t *args, const xvk_ray_frame_images_t *frame_dst ) {
// 3. Update descriptor sets (bind dest image, tlas, projection matrix)
VkDescriptorImageInfo dii_all_textures[MAX_TEXTURES];
g_rtx.desc_values[RayDescBinding_DestImage].image = (VkDescriptorImageInfo){
g_rtx.desc_values[RayDescBinding_Dest_ImageBaseColor].image = (VkDescriptorImageInfo){
.sampler = VK_NULL_HANDLE,
.imageView = frame_dst->view,
.imageView = frame_dst->base_color.view,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
};
@ -621,10 +631,16 @@ static void updateDescriptors( VkCommandBuffer cmdbuf, const vk_ray_frame_render
.range = VK_WHOLE_SIZE,
};
g_rtx.desc_values[RayDescBinding_Dest_ImageDiffuseGI].image = (VkDescriptorImageInfo){
.sampler = VK_NULL_HANDLE,
.imageView = frame_dst->diffuse_gi.view,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
};
VK_DescriptorsWrite(&g_rtx.descriptors);
}
static qboolean rayTrace( VkCommandBuffer cmdbuf, VkImage frame_dst, float fov_angle_y )
static qboolean rayTrace( VkCommandBuffer cmdbuf, const xvk_ray_frame_images_t *current_frame, float fov_angle_y )
{
// 4. Barrier for TLAS build and dest image layout transfer
{
@ -638,9 +654,9 @@ static qboolean rayTrace( VkCommandBuffer cmdbuf, VkImage frame_dst, float fov_a
} };
VkImageMemoryBarrier image_barrier[] = { {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = frame_dst,
.image = current_frame->base_color.image,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange = (VkImageSubresourceRange) {
@ -649,9 +665,26 @@ static qboolean rayTrace( VkCommandBuffer cmdbuf, VkImage frame_dst, float fov_a
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
}} };
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
0, NULL, ARRAYSIZE(bmb), bmb, ARRAYSIZE(image_barrier), image_barrier);
},
}, {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = current_frame->diffuse_gi.image,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange = (VkImageSubresourceRange) {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
} };
vkCmdPipelineBarrier(cmdbuf,
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
0, 0, NULL, ARRAYSIZE(bmb), bmb, ARRAYSIZE(image_barrier), image_barrier);
}
// 4. dispatch ray tracing
@ -770,22 +803,71 @@ static void clearVkImage( VkCommandBuffer cmdbuf, VkImage image ) {
vkCmdClearColorImage(cmdbuf, image, VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1, &image_barriers->subresourceRange);
}
static void blitImage( VkCommandBuffer cmdbuf, VkImage src, VkImage dst, int src_width, int src_height, int dst_width, int dst_height )
{
// Blit raytraced image to frame buffer
typedef struct {
VkCommandBuffer cmdbuf;
VkPipelineStageFlags in_stage;
struct {
VkImage image;
int width, height;
VkImageLayout oldLayout;
VkAccessFlags srcAccessMask;
} src, dst;
} xvk_blit_args;
static void blitImage( const xvk_blit_args *blit_args ) {
{
const VkImageMemoryBarrier image_barriers[] = { {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = blit_args->src.image,
.srcAccessMask = blit_args->src.srcAccessMask,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.oldLayout = blit_args->src.oldLayout,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}, {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = blit_args->dst.image,
.srcAccessMask = blit_args->dst.srcAccessMask,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = blit_args->dst.oldLayout,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
} };
vkCmdPipelineBarrier(blit_args->cmdbuf,
blit_args->in_stage,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0, 0, NULL, 0, NULL, ARRAYSIZE(image_barriers), image_barriers);
}
{
VkImageBlit region = {0};
region.srcOffsets[1].x = src_width;
region.srcOffsets[1].y = src_height;
region.srcOffsets[1].x = blit_args->src.width;
region.srcOffsets[1].y = blit_args->src.height;
region.srcOffsets[1].z = 1;
region.dstOffsets[1].x = dst_width;
region.dstOffsets[1].y = dst_height;
region.dstOffsets[1].x = blit_args->dst.width;
region.dstOffsets[1].y = blit_args->dst.height;
region.dstOffsets[1].z = 1;
region.srcSubresource.aspectMask = region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.srcSubresource.layerCount = region.dstSubresource.layerCount = 1;
vkCmdBlitImage(cmdbuf,
src, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
vkCmdBlitImage(blit_args->cmdbuf,
blit_args->src.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
blit_args->dst.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &region,
VK_FILTER_NEAREST);
}
@ -794,7 +876,7 @@ static void blitImage( VkCommandBuffer cmdbuf, VkImage src, VkImage dst, int src
VkImageMemoryBarrier image_barriers[] = {
{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = dst,
.image = blit_args->dst.image,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
@ -808,7 +890,7 @@ static void blitImage( VkCommandBuffer cmdbuf, VkImage src, VkImage dst, int src
.layerCount = 1,
},
}};
vkCmdPipelineBarrier(cmdbuf,
vkCmdPipelineBarrier(blit_args->cmdbuf,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0, 0, NULL, 0, NULL, ARRAYSIZE(image_barriers), image_barriers);
@ -818,8 +900,7 @@ static void blitImage( VkCommandBuffer cmdbuf, VkImage src, VkImage dst, int src
void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
{
const VkCommandBuffer cmdbuf = args->cmdbuf;
const vk_image_t* frame_denoiser_dst = g_rtx.frames + ((g_rtx.frame_number + 1) % 2);
const vk_image_t* frame_dst = g_rtx.frames + (g_rtx.frame_number % 2);
const xvk_ray_frame_images_t* current_frame = g_rtx.frames + (g_rtx.frame_number % 2);
ASSERT(vk_core.rtx);
// ubo should contain two matrices
@ -836,140 +917,131 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
// TODO gracefully handle reload errors: need to change createPipeline, loadShader, VK_PipelineCreate...
vkDestroyPipeline(vk_core.device, g_rtx.pipeline, NULL);
createPipeline();
XVK_DenoiserReloadPipeline();
g_rtx.reload_pipeline = false;
}
updateLights();
if (g_ray_model_state.frame.num_models == 0)
{
clearVkImage( cmdbuf, frame_dst->image );
if (g_ray_model_state.frame.num_models == 0) {
clearVkImage( cmdbuf, current_frame->denoised.image );
{
// Prepare destination image for writing
const VkImageMemoryBarrier image_barriers[] = {{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
const xvk_blit_args blit_args = {
.cmdbuf = args->cmdbuf,
.in_stage = VK_PIPELINE_STAGE_TRANSFER_BIT,
.src = {
.image = current_frame->denoised.image,
.width = FRAME_WIDTH,
.height = FRAME_HEIGHT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
},
.dst = {
.image = args->dst.image,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.width = args->dst.width,
.height = args->dst.height,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcAccessMask = 0,
},
};
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}};
vkCmdPipelineBarrier(args->cmdbuf,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0, 0, NULL, 0, NULL, ARRAYSIZE(image_barriers), image_barriers);
}
blitImage( &blit_args );
} else {
prepareTlas(cmdbuf);
updateDescriptors(cmdbuf, args, frame_dst);
rayTrace(cmdbuf, frame_dst->image, args->fov_angle_y);
updateDescriptors(cmdbuf, args, current_frame);
rayTrace(cmdbuf, current_frame, args->fov_angle_y);
// Barrier for frame_dst image
{
const VkImageMemoryBarrier image_barriers[] = {
{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = frame_dst->image,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = frame_denoiser_dst->image,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}};
const VkImageMemoryBarrier image_barriers[] = { {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = current_frame->base_color.image,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}, {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = current_frame->diffuse_gi.image,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}, {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = current_frame->denoised.image,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
} };
vkCmdPipelineBarrier(args->cmdbuf,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0, 0, NULL, 0, NULL, ARRAYSIZE(image_barriers), image_barriers);
}
}
{
const xvk_denoiser_args_t denoiser_args = {
.cmdbuf = cmdbuf,
.width = FRAME_WIDTH,
.height = FRAME_HEIGHT,
.view_src = frame_dst->view,
.view_dst = frame_denoiser_dst->view,
};
XVK_DenoiserDenoise( &denoiser_args );
}
{
const VkImageMemoryBarrier image_barriers[] = {
{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = frame_denoiser_dst->image,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
const xvk_denoiser_args_t denoiser_args = {
.cmdbuf = cmdbuf,
.width = FRAME_WIDTH,
.height = FRAME_HEIGHT,
.src = {
.base_color_view = current_frame->base_color.view,
.diffuse_gi_view = current_frame->diffuse_gi.view,
},
}, {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = args->dst.image,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.subresourceRange =
(VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}};
vkCmdPipelineBarrier(args->cmdbuf,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0, 0, NULL, 0, NULL, ARRAYSIZE(image_barriers), image_barriers);
.dst_view = current_frame->denoised.view,
};
blitImage(args->cmdbuf, frame_denoiser_dst->image, args->dst.image,
FRAME_WIDTH, FRAME_HEIGHT,
args->dst.width, args->dst.height);
XVK_DenoiserDenoise( &denoiser_args );
}
{
const xvk_blit_args blit_args = {
.cmdbuf = args->cmdbuf,
.in_stage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
.src = {
.image = current_frame->denoised.image,
.width = FRAME_WIDTH,
.height = FRAME_HEIGHT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
},
.dst = {
.image = args->dst.image,
.width = args->dst.width,
.height = args->dst.height,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.srcAccessMask = 0,
},
};
blitImage( &blit_args );
}
}
}
@ -987,8 +1059,15 @@ static void createLayouts( void ) {
.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
};
g_rtx.desc_bindings[RayDescBinding_DestImage] = (VkDescriptorSetLayoutBinding){
.binding = RayDescBinding_DestImage,
g_rtx.desc_bindings[RayDescBinding_Dest_ImageDiffuseGI] = (VkDescriptorSetLayoutBinding){
.binding = RayDescBinding_Dest_ImageDiffuseGI,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR,
};
g_rtx.desc_bindings[RayDescBinding_Dest_ImageBaseColor] = (VkDescriptorSetLayoutBinding){
.binding = RayDescBinding_Dest_ImageBaseColor,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR,
@ -1138,32 +1217,17 @@ qboolean VK_RayInit( void )
createPipeline();
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
g_rtx.frames[i] = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
g_rtx.frames[i].denoised = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT );
SET_DEBUG_NAMEF(g_rtx.frames[i].denoised.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] denoised", i);
SET_DEBUG_NAMEF(g_rtx.frames[i].image, VK_OBJECT_TYPE_IMAGE, "rtx frame[%d]", i);
}
g_rtx.frames[i].base_color = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
SET_DEBUG_NAMEF(g_rtx.frames[i].base_color.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] base_color", i);
// Start with black previous frame
{
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));
clearVkImage( vk_core.cb, g_rtx.frames[1].image );
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.frames[i].diffuse_gi = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
SET_DEBUG_NAMEF(g_rtx.frames[i].diffuse_gi.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] diffuse_gi", i);
}
if (vk_core.debug) {
@ -1175,12 +1239,14 @@ qboolean VK_RayInit( void )
return true;
}
void VK_RayShutdown( void )
{
void VK_RayShutdown( void ) {
ASSERT(vk_core.rtx);
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i)
VK_ImageDestroy(g_rtx.frames + i);
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
VK_ImageDestroy(&g_rtx.frames[i].denoised);
VK_ImageDestroy(&g_rtx.frames[i].base_color);
VK_ImageDestroy(&g_rtx.frames[i].diffuse_gi);
}
vkDestroyPipeline(vk_core.device, g_rtx.pipeline, NULL);
VK_DescriptorsDestroy(&g_rtx.descriptors);