rt: add parallel direct point light pass

(look how easy that was! yay passes!
... still need to do spir-v parsing to extract bindings though)

perf (c1a0 lobby, 720p, 6900XT)
- total ray tracing time: 15.2ms
- primary: 0.7ms v:80/80 s:60/128 lds:2048 o:12/16 (-4v +1o)
- dir poly: 13.8ms v:256/256 s:98/128 lds:2048 o:4/16 (-28v +1o)
- dir point: 0.9ms v:85/96 s:68/128 lds:2048 o:10/16 (-6v +1o)

dir point and poly are not synchronized and overlap. but poly takes most
of the time, and point can only ramp up gradually at the very tail of
poly.
This commit is contained in:
Ivan Avdeev 2022-01-27 19:14:56 -08:00
parent c3a7a01620
commit 90fa6161ac
11 changed files with 230 additions and 86 deletions

View File

@ -8,8 +8,13 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0, rgba16f) uniform image2D dest;
layout(set = 0, binding = 1, rgba8) uniform readonly image2D src_base_color;
layout(set = 0, binding = 2, rgba16f) uniform readonly image2D src_light_direct_poly_diffuse;
//layout(set = 0, binding = 3, rgba16f) uniform readonly image2D src_light_direct_poly_specular;
layout(set = 0, binding = 3, rgba16f) uniform readonly image2D src_light_direct_poly_specular;
layout(set = 0, binding = 4, rgba16f) uniform readonly image2D src_light_direct_point_diffuse;
layout(set = 0, binding = 5, rgba16f) uniform readonly image2D src_light_direct_point_specular;
//layout(set = 0, binding = 2, rgba16f) uniform readonly image2D src_light_direct_poly_diffuse;
/* layout(set = 0, binding = 3, rgba16f) uniform readonly image2D src_specular; */
/* layout(set = 0, binding = 4, rgba16f) uniform readonly image2D src_additive; */
@ -91,8 +96,12 @@ void main() {
/* return; */
#if 1
vec3 colour = imageLoad(src_light_direct_poly_diffuse, pix).rgb * base_color.rgb;
//colour += imageLoad(src_light_direct_poly_specular, pix).rgb * base_color.rgb;
vec3 colour = vec3(0.);
colour += imageLoad(src_light_direct_poly_diffuse, pix).rgb;
//colour += imageLoad(src_light_direct_poly_specular, pix).rgb;
colour += imageLoad(src_light_direct_point_diffuse, pix).rgb;
//colour += imageLoad(src_light_direct_point_specular, pix).rgb;
colour *= base_color.rgb;
#else
float total_scale = 0.;
vec3 colour = vec3(0.);

View File

@ -10,8 +10,12 @@ const float shadow_offset_fudge = .1;
#include "brdf.h"
#include "light_common.glsl"
#include "light_polygon.glsl"
#if LIGHT_POLYGON
#include "light_polygon.glsl"
#endif
#if LIGHT_POINT
void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec3 view_dir, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
diffuse = specular = vec3(0.);
const uint num_point_lights = uint(light_grid.clusters[cluster_index].num_point_lights);
@ -98,6 +102,7 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 throughput, vec
specular += lspecular;
} // for all lights
}
#endif
void computeLighting(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, MaterialProperties material, out vec3 diffuse, out vec3 specular) {
diffuse = specular = vec3(0.);
@ -116,11 +121,11 @@ void computeLighting(vec3 P, vec3 N, vec3 throughput, vec3 view_dir, MaterialPro
//C = vec3(float(int(light_grid.clusters[cluster_index].num_emissive_surfaces)));
//C += .3 * fract(vec3(light_cell) / 4.);
#if 1
#if LIGHT_POLYGON
sampleEmissiveSurfaces(P, N, throughput, view_dir, material, cluster_index, diffuse, specular);
#endif
#if 0
#if LIGHT_POINT
vec3 ldiffuse = vec3(0.), lspecular = vec3(0.);
computePointLights(P, N, cluster_index, throughput, view_dir, material, ldiffuse, lspecular);
diffuse += ldiffuse;

View File

@ -6,10 +6,14 @@
X(10, position_t, rgba32f) \
X(11, normals_gs, rgba16f) \
#define RAY_LIGHT_DIRECT_OUTPUTS(X) \
#define RAY_LIGHT_DIRECT_POLY_OUTPUTS(X) \
X(13, light_poly_diffuse, rgba16f) \
X(14, light_poly_specular, rgba16f) \
#define RAY_LIGHT_DIRECT_POINT_OUTPUTS(X) \
X(13, light_point_diffuse, rgba16f) \
X(14, light_point_specular, rgba16f) \
#define RAY_PRIMARY_OUTPUTS(X) \
X(10, base_color_a, rgba8) \
X(11, position_t, rgba32f) \

View File

@ -0,0 +1,74 @@
#extension GL_EXT_control_flow_attributes : require
#extension GL_EXT_ray_tracing: require
#include "utils.glsl"
#include "noise.glsl"
#define GLSL
#include "ray_interop.h"
#undef GLSL
#define X(index, name, format) layout(set=0,binding=index,format) uniform readonly image2D name;
RAY_LIGHT_DIRECT_INPUTS(X)
#undef X
#define X(index, name, format) layout(set=0,binding=index,format) uniform writeonly image2D out_image_##name;
OUTPUTS(X)
#undef X
layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas;
layout(set = 0, binding = 2) uniform UBO { UniformBuffer ubo; };
#include "ray_kusochki.glsl"
#define RAY_TRACE
#define RAY_TRACE2
#undef SHADER_OFFSET_HIT_SHADOW_BASE
#define SHADER_OFFSET_HIT_SHADOW_BASE 0
#undef SHADER_OFFSET_MISS_SHADOW
#define SHADER_OFFSET_MISS_SHADOW 0
#undef PAYLOAD_LOCATION_SHADOW
#define PAYLOAD_LOCATION_SHADOW 0
#define BINDING_LIGHTS 7
#define BINDING_LIGHT_CLUSTERS 8
#include "light.glsl"
void readNormals(ivec2 uv, out vec3 geometry_normal, out vec3 shading_normal) {
const vec4 n = imageLoad(normals_gs, uv);
geometry_normal = normalDecode(n.xy);
shading_normal = normalDecode(n.zw);
}
void main() {
const vec2 uv = (gl_LaunchIDEXT.xy + .5) / gl_LaunchSizeEXT.xy * 2. - 1.;
const ivec2 pix = ivec2(gl_LaunchIDEXT.xy);
rand01_state = ubo.random_seed + gl_LaunchIDEXT.x * 1833 + gl_LaunchIDEXT.y * 31337;
// FIXME incorrect for reflection/refraction
vec4 target = ubo.inv_proj * vec4(uv.x, uv.y, 1, 1);
vec3 direction = normalize((ubo.inv_view * vec4(target.xyz, 0)).xyz);
MaterialProperties material;
material.baseColor = vec3(1.);
material.emissive = vec3(0.f);
material.metalness = 0.f; // TODO
material.roughness = 1.f; // TODO
const vec3 pos = imageLoad(position_t, pix).xyz;
vec3 geometry_normal, shading_normal;
readNormals(pix, geometry_normal, shading_normal);
const vec3 throughput = vec3(1.);
vec3 diffuse = vec3(0.), specular = vec3(0.);
computeLighting(pos + geometry_normal * .001, shading_normal, throughput, -direction, material, diffuse, specular);
#if LIGHT_POINT
imageStore(out_image_light_point_diffuse, pix, vec4(diffuse, 0.f));
imageStore(out_image_light_point_specular, pix, vec4(specular, 0.f));
#else
imageStore(out_image_light_poly_diffuse, pix, vec4(diffuse, 0.f));
imageStore(out_image_light_poly_specular, pix, vec4(specular, 0.f));
#endif
}

View File

@ -0,0 +1,6 @@
#version 460 core
#extension GL_GOOGLE_include_directive : require
#define LIGHT_POINT 1
#define OUTPUTS RAY_LIGHT_DIRECT_POINT_OUTPUTS
#include "ray_light_direct.glsl"

View File

@ -1,70 +1,6 @@
#version 460 core
#extension GL_GOOGLE_include_directive : require
#extension GL_EXT_control_flow_attributes : require
#extension GL_EXT_ray_tracing: require
#include "utils.glsl"
#define GLSL
#include "ray_interop.h"
#undef GLSL
#define X(index, name, format) layout(set=0,binding=index,format) uniform readonly image2D name;
RAY_LIGHT_DIRECT_INPUTS(X)
#undef X
#define X(index, name, format) layout(set=0,binding=index,format) uniform writeonly image2D out_image_##name;
RAY_LIGHT_DIRECT_OUTPUTS(X)
#undef X
layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas;
layout(set = 0, binding = 2) uniform UBO { UniformBuffer ubo; };
#include "ray_kusochki.glsl"
#define RAY_TRACE
#define RAY_TRACE2
#undef SHADER_OFFSET_HIT_SHADOW_BASE
#define SHADER_OFFSET_HIT_SHADOW_BASE 0
#undef SHADER_OFFSET_MISS_SHADOW
#define SHADER_OFFSET_MISS_SHADOW 0
#undef PAYLOAD_LOCATION_SHADOW
#define PAYLOAD_LOCATION_SHADOW 0
#define BINDING_LIGHTS 7
#define BINDING_LIGHT_CLUSTERS 8
#include "light.glsl"
void readNormals(ivec2 uv, out vec3 geometry_normal, out vec3 shading_normal) {
const vec4 n = imageLoad(normals_gs, uv);
geometry_normal = normalDecode(n.xy);
shading_normal = normalDecode(n.zw);
}
void main() {
const vec2 uv = (gl_LaunchIDEXT.xy + .5) / gl_LaunchSizeEXT.xy * 2. - 1.;
const ivec2 pix = ivec2(gl_LaunchIDEXT.xy);
rand01_state = ubo.random_seed + gl_LaunchIDEXT.x * 1833 + gl_LaunchIDEXT.y * 31337;
// FIXME incorrect for reflection/refraction
vec4 target = ubo.inv_proj * vec4(uv.x, uv.y, 1, 1);
vec3 direction = normalize((ubo.inv_view * vec4(target.xyz, 0)).xyz);
MaterialProperties material;
material.baseColor = vec3(1.);
material.emissive = vec3(0.f);
material.metalness = 0.f; // TODO
material.roughness = 1.f; // TODO
const vec3 pos = imageLoad(position_t, pix).xyz;
vec3 geometry_normal, shading_normal;
readNormals(pix, geometry_normal, shading_normal);
const vec3 throughput = vec3(1.);
vec3 diffuse = vec3(0.), specular = vec3(0.);
computeLighting(pos + geometry_normal * .001, shading_normal, throughput, -direction, material, diffuse, specular);
imageStore(out_image_light_poly_diffuse, pix, vec4(diffuse, 0.f));
imageStore(out_image_light_poly_specular, pix, vec4(specular, 0.f));
}
#define LIGHT_POLYGON 1
#define OUTPUTS RAY_LIGHT_DIRECT_POLY_OUTPUTS
#include "ray_light_direct.glsl"

View File

@ -9,7 +9,12 @@ enum {
DenoiserBinding_DestImage = 0,
DenoiserBinding_Source_BaseColor = 1,
DenoiserBinding_Source_LightPolyDiffuse = 2,
DenoiserBinding_Source_LightPolySpecular = 3,
DenoiserBinding_Source_LightPointDiffuse = 4,
DenoiserBinding_Source_LightPointSpecular = 5,
/* DenoiserBinding_Source_Specular = 3, */
/* DenoiserBinding_Source_Additive = 4, */
/* DenoiserBinding_Source_Normals = 5, */
@ -61,6 +66,24 @@ static void createLayouts( void ) {
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
};
g_denoiser.desc_bindings[DenoiserBinding_Source_LightPolySpecular] = (VkDescriptorSetLayoutBinding){
.binding = DenoiserBinding_Source_LightPolySpecular,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
};
g_denoiser.desc_bindings[DenoiserBinding_Source_LightPointDiffuse] = (VkDescriptorSetLayoutBinding){
.binding = DenoiserBinding_Source_LightPointDiffuse,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
};
g_denoiser.desc_bindings[DenoiserBinding_Source_LightPointSpecular] = (VkDescriptorSetLayoutBinding){
.binding = DenoiserBinding_Source_LightPointSpecular,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
};
VK_DescriptorsCreate(&g_denoiser.descriptors);
}
@ -113,7 +136,11 @@ void XVK_DenoiserDenoise( VkCommandBuffer cmdbuf, const vk_ray_resources_t* res
BIND_IMAGE(DestImage, denoised);
BIND_IMAGE(Source_BaseColor, base_color_a);
BIND_IMAGE(Source_LightPolyDiffuse, light_poly_diffuse);
BIND_IMAGE(Source_LightPolySpecular, light_poly_specular);
BIND_IMAGE(Source_LightPointDiffuse, light_point_diffuse);
BIND_IMAGE(Source_LightPointSpecular, light_point_specular);
VK_DescriptorsWrite(&g_denoiser.descriptors);

View File

@ -20,8 +20,10 @@ enum {
#define X(index, name, ...) RtLDir_Desc_##name,
RAY_LIGHT_DIRECT_INPUTS(X)
#undef X
// FIXME it's an artifact that point and poly outputs have same bindings
#define X(index, name, ...) RtLDir_Desc_##name,
RAY_LIGHT_DIRECT_OUTPUTS(X)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(X)
#undef X
RtLDir_Desc_COUNT
@ -53,7 +55,7 @@ static void initDescriptors( void ) {
RAY_LIGHT_DIRECT_INPUTS(X)
#undef X
#define X(index, name, ...) INIT_BINDING(index, name, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1);
RAY_LIGHT_DIRECT_OUTPUTS(X)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(X)
#undef X
#undef INIT_BINDING
}
@ -74,7 +76,7 @@ static void writeValues( vk_descriptor_value_t *values, const vk_ray_resources_t
.imageView = res->name, \
.imageLayout = VK_IMAGE_LAYOUT_GENERAL, \
};
RAY_LIGHT_DIRECT_OUTPUTS(X)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(X)
#undef X
values[RtLDir_Desc_TLAS].accel = (VkWriteDescriptorSetAccelerationStructureKHR){
@ -150,3 +152,68 @@ struct ray_pass_s *R_VkRayLightDirectPolyPassCreate( void ) {
initDescriptors();
return RayPassCreate( &rpc );
}
static void writePointValues( vk_descriptor_value_t *values, const vk_ray_resources_t* res ) {
writeValues( values, res );
values[RtLDir_Desc_light_poly_diffuse].image = (VkDescriptorImageInfo) {
.sampler = VK_NULL_HANDLE,
.imageView = res->light_point_diffuse,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
};
values[RtLDir_Desc_light_poly_specular].image = (VkDescriptorImageInfo) {
.sampler = VK_NULL_HANDLE,
.imageView = res->light_point_specular,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
};
}
struct ray_pass_s *R_VkRayLightDirectPointPassCreate( void ) {
// FIXME move this into vk_pipeline
const struct SpecializationData {
uint32_t sbt_record_size;
} spec_data = {
.sbt_record_size = vk_core.physical_device.sbt_record_size,
};
const VkSpecializationMapEntry spec_map[] = {
{.constantID = SPEC_SBT_RECORD_SIZE_INDEX, .offset = offsetof(struct SpecializationData, sbt_record_size), .size = sizeof(uint32_t) },
};
VkSpecializationInfo spec = {
.mapEntryCount = COUNTOF(spec_map),
.pMapEntries = spec_map,
.dataSize = sizeof(spec_data),
.pData = &spec_data,
};
const ray_pass_shader_t miss[] = {
"ray_shadow.rmiss.spv"
};
const ray_pass_hit_group_t hit[] = { {
.closest = NULL,
.any = "ray_common_alphatest.rahit.spv",
},
};
const ray_pass_create_t rpc = {
.debug_name = "light direct point",
.layout = {
.bindings = bindings,
.bindings_count = COUNTOF(bindings),
.write_values_func = writePointValues,
.push_constants = {0},
},
.tracing = {
.raygen = "ray_light_direct_point.rgen.spv",
.miss = miss,
.miss_count = COUNTOF(miss),
.hit = hit,
.hit_count = COUNTOF(hit),
.specialization = &spec,
},
};
initDescriptors();
return RayPassCreate( &rpc );
}

View File

@ -1,3 +1,4 @@
#pragma once
struct ray_pass_s *R_VkRayLightDirectPolyPassCreate( void );
struct ray_pass_s *R_VkRayLightDirectPointPassCreate( void );

View File

@ -20,8 +20,10 @@ typedef struct vk_ray_resources_s {
#define X(index, name, ...) VkImageView name;
RAY_PRIMARY_OUTPUTS(X)
RAY_LIGHT_DIRECT_OUTPUTS(X)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(X)
RAY_LIGHT_DIRECT_POINT_OUTPUTS(X)
X(-1, denoised)
#undef X
} vk_ray_resources_t;

View File

@ -96,7 +96,8 @@ typedef struct {
#define X(index, name, ...) xvk_image_t name;
RAY_PRIMARY_OUTPUTS(X)
RAY_LIGHT_DIRECT_OUTPUTS(X)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(X)
RAY_LIGHT_DIRECT_POINT_OUTPUTS(X)
#undef X
xvk_image_t diffuse_gi;
@ -166,6 +167,7 @@ static struct {
struct {
struct ray_pass_s *primary_ray;
struct ray_pass_s *light_direct_poly;
struct ray_pass_s *light_direct_point;
} pass;
qboolean reload_pipeline;
@ -1013,7 +1015,8 @@ static void performTracing( VkCommandBuffer cmdbuf, const vk_ray_frame_render_ar
},
#define X(index, name, ...) .name = current_frame->name.view,
RAY_PRIMARY_OUTPUTS(X)
RAY_LIGHT_DIRECT_OUTPUTS(X)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(X)
RAY_LIGHT_DIRECT_POINT_OUTPUTS(X)
X(-1, denoised)
#undef X
};
@ -1086,7 +1089,8 @@ static void performTracing( VkCommandBuffer cmdbuf, const vk_ray_frame_render_ar
{
const VkImageMemoryBarrier image_barriers[] = {
RAY_PRIMARY_OUTPUTS(IMAGE_BARRIER_READ)
RAY_LIGHT_DIRECT_OUTPUTS(IMAGE_BARRIER_WRITE)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(IMAGE_BARRIER_WRITE)
RAY_LIGHT_DIRECT_POINT_OUTPUTS(IMAGE_BARRIER_WRITE)
};
vkCmdPipelineBarrier(args->cmdbuf,
@ -1097,10 +1101,12 @@ static void performTracing( VkCommandBuffer cmdbuf, const vk_ray_frame_render_ar
}
RayPassPerform( cmdbuf, g_rtx.pass.light_direct_poly, &res );
RayPassPerform( cmdbuf, g_rtx.pass.light_direct_point, &res );
{
const VkImageMemoryBarrier image_barriers[] = {
RAY_LIGHT_DIRECT_OUTPUTS(IMAGE_BARRIER_READ)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(IMAGE_BARRIER_READ)
RAY_LIGHT_DIRECT_POINT_OUTPUTS(IMAGE_BARRIER_READ)
LIST_GBUFFER_IMAGES(IMAGE_BARRIER_READ)
IMAGE_BARRIER_WRITE(-1/*unused*/, denoised)
};
@ -1174,6 +1180,7 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
reloadPass( &g_rtx.pass.primary_ray, R_VkRayPrimaryPassCreate());
reloadPass( &g_rtx.pass.light_direct_poly, R_VkRayLightDirectPolyPassCreate());
reloadPass( &g_rtx.pass.light_direct_point, R_VkRayLightDirectPointPassCreate());
XVK_DenoiserReloadPipeline();
g_rtx.reload_pipeline = false;
@ -1350,6 +1357,9 @@ qboolean VK_RayInit( void )
g_rtx.pass.light_direct_poly = R_VkRayLightDirectPolyPassCreate();
ASSERT(g_rtx.pass.light_direct_poly);
g_rtx.pass.light_direct_point = R_VkRayLightDirectPointPassCreate();
ASSERT(g_rtx.pass.light_direct_point);
g_rtx.sbt_record_size = vk_core.physical_device.sbt_record_size;
g_rtx.uniform_unit_size = ALIGN_UP(sizeof(struct UniformBuffer), vk_core.physical_device.properties.limits.minUniformBufferOffsetAlignment);
@ -1446,8 +1456,9 @@ qboolean VK_RayInit( void )
#define X(index, name, format) CREATE_GBUFFER_IMAGE(name, format, 0);
// TODO better format for normals VK_FORMAT_R16G16B16A16_SNORM
// TODO make sure this format and usage is suppported
RAY_PRIMARY_OUTPUTS(X)
RAY_LIGHT_DIRECT_OUTPUTS(X)
RAY_PRIMARY_OUTPUTS(X)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(X)
RAY_LIGHT_DIRECT_POINT_OUTPUTS(X)
#undef X
#undef rgba8
#undef rgba32f
@ -1469,13 +1480,15 @@ void VK_RayShutdown( void ) {
ASSERT(vk_core.rtx);
RayPassDestroy(g_rtx.pass.light_direct_poly);
RayPassDestroy(g_rtx.pass.light_direct_point);
RayPassDestroy(g_rtx.pass.primary_ray);
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
XVK_ImageDestroy(&g_rtx.frames[i].denoised);
#define X(index, name, ...) XVK_ImageDestroy(&g_rtx.frames[i].name);
RAY_PRIMARY_OUTPUTS(X)
RAY_LIGHT_DIRECT_OUTPUTS(X)
RAY_PRIMARY_OUTPUTS(X)
RAY_LIGHT_DIRECT_POLY_OUTPUTS(X)
RAY_LIGHT_DIRECT_POINT_OUTPUTS(X)
#undef X
XVK_ImageDestroy(&g_rtx.frames[i].diffuse_gi);
XVK_ImageDestroy(&g_rtx.frames[i].specular);