Merge pull request #403 from w23/primary-ray-compute

Convert primary ray pass to compute shader

Makes it work under open source mesa amdgpu driver (although it's ~30% slower than the old binary driver)
This commit is contained in:
Ivan Avdeev 2023-01-22 15:09:48 -08:00 committed by GitHub
commit ab59393909
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 173 additions and 29 deletions

View File

@ -1,19 +1,19 @@
# Real next
>=E222
- [x] refcount meatpipe created images
- [ ] previous frame resources reference
- [ ] what if new meatpipe has different image format for a creatable image?
- [ ] rake yuri primary ray
- [ ] resource management refactoring:
- [ ] register existing resources (tlas, buffers, temp images, ...) in their producers
- [ ] resource automatic resolution: prducing, barriers, etc
- [ ] resource destruction
- [ ] ? resource object: name, metadata(type, etc.), producer, status (ready, barriers, etc)
- [x] refcount meatpipe created images
- [x] rake yuri primary ray
- [ ] previous frame resources reference
- [ ] what if new meatpipe has different image format for a creatable image?
# Programmable render
- [ ] implicit dependency tracking. pass defines:
- [ ] imports: list of things it needs
- [ ] exports: list of things it produces. those get created and registered with this pass as a producer
- [ ] resource management refactoring:
- [ ] register existing resources (tlas, buffers, temp images, ...) in their producers
- [ ] resource automatic resolution: prducing, barriers, etc
- [ ] resource destruction
- [ ] ? resource object: name, metadata(type, etc.), producer, status (ready, barriers, etc)
# Parallel frames sync
- [ ] light_grid_buffer (+ small lights_buffer):

View File

@ -1,6 +1,7 @@
#version 460 core
#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_GOOGLE_include_directive : require
#extension GL_EXT_ray_tracing: require
#include "ray_primary_common.glsl"
#include "ray_kusochki.glsl"
@ -19,7 +20,7 @@ hitAttributeEXT vec2 bary;
const float alpha_mask_threshold = .1f;
void main() {
const Geometry geom = readHitGeometry();
const Geometry geom = readHitGeometry(bary, ubo.ubo.ray_cone_width);
const uint tex_index = getKusok(geom.kusok_index).tex_base_color;
const vec4 texture_color = texture(textures[nonuniformEXT(tex_index)], geom.uv);

View File

@ -0,0 +1,58 @@
#version 460 core
#extension GL_GOOGLE_include_directive : require
#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_EXT_ray_query: require
#define RAY_QUERY
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#include "ray_primary_common.glsl"
#include "ray_primary_hit.glsl"
#define X(index, name, format) layout(set=0,binding=index,format) uniform writeonly image2D out_##name;
RAY_PRIMARY_OUTPUTS(X)
#undef X
layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas;
void main() {
const ivec2 pix = ivec2(gl_GlobalInvocationID);
const ivec2 res = ivec2(imageSize(out_position_t));
if (any(greaterThanEqual(pix, res))) {
return;
}
const vec2 uv = (gl_GlobalInvocationID.xy + .5) / res * 2. - 1.;
// FIXME start on a near plane
const vec3 origin = (ubo.ubo.inv_view * vec4(0, 0, 0, 1)).xyz;
const vec4 target = ubo.ubo.inv_proj * vec4(uv.x, uv.y, 1, 1);
const vec3 direction = normalize((ubo.ubo.inv_view * vec4(target.xyz, 0)).xyz);
RayPayloadPrimary payload;
payload.hit_t = vec4(0.);
payload.base_color_a = vec4(0.);
payload.normals_gs = vec4(0.);
payload.material_rmxx = vec4(0.);
payload.emissive = vec4(0.);
rayQueryEXT rq;
const uint flags = 0
| gl_RayFlagsCullFrontFacingTrianglesEXT
//| gl_RayFlagsOpaqueEXT
//| gl_RayFlagsTerminateOnFirstHitEXT
//| gl_RayFlagsSkipClosestHitShaderEXT
;
const float L = 10000.; // TODO Why 10k?
rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE, origin, 0., direction, L);
// TODO alpha test
while (rayQueryProceedEXT(rq)) { }
if (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT) {
primaryRayHit(rq, payload);
}
imageStore(out_position_t, pix, payload.hit_t);
imageStore(out_base_color_a, pix, payload.base_color_a);
imageStore(out_normals_gs, pix, payload.normals_gs);
imageStore(out_material_rmxx, pix, payload.material_rmxx);
imageStore(out_emissive, pix, payload.emissive);
}

View File

@ -1,13 +1,11 @@
#version 460 core
#extension GL_GOOGLE_include_directive : require
#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_EXT_ray_tracing: require
#include "utils.glsl"
#include "ray_primary_common.glsl"
#include "ray_kusochki.glsl"
#include "color_spaces.glsl"
layout(set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES];
@ -24,7 +22,7 @@ vec4 sampleTexture(uint tex_index, vec2 uv, vec4 uv_lods) {
}
void main() {
Geometry geom = readHitGeometry();
Geometry geom = readHitGeometry(bary, ubo.ubo.ray_cone_width);
payload.hit_t = vec4(geom.pos, gl_HitTEXT);

View File

@ -1,5 +1,6 @@
#version 460 core
#extension GL_GOOGLE_include_directive : require
#extension GL_EXT_ray_tracing: require
#include "ray_primary_common.glsl"

View File

@ -1,4 +1,5 @@
#extension GL_EXT_ray_tracing: require
#ifndef RAY_PRIMARY_COMMON_GLSL_INCLUDED
#define RAY_PRIMARY_COMMON_GLSL_INCLUDED
#define GLSL
#include "ray_interop.h"
@ -13,3 +14,5 @@ struct RayPayloadPrimary {
};
#define PAYLOAD_LOCATION_PRIMARY 0
#endif //ifndef RAY_PRIMARY_COMMON_GLSL_INCLUDED

View File

@ -0,0 +1,61 @@
#ifndef RAY_PRIMARY_HIT_GLSL_INCLUDED
#define RAY_PRIMARY_HIT_GLSL_INCLUDED
#extension GL_EXT_nonuniform_qualifier : enable
#include "utils.glsl"
#include "ray_primary_common.glsl"
#include "ray_kusochki.glsl"
#include "rt_geometry.glsl"
#include "color_spaces.glsl"
layout(set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES];
layout(set = 0, binding = 2) uniform UBO { UniformBuffer ubo; } ubo;
layout(set = 0, binding = 7) uniform samplerCube skybox;
vec4 sampleTexture(uint tex_index, vec2 uv, vec4 uv_lods) {
return textureGrad(textures[nonuniformEXT(tex_index)], uv, uv_lods.xy, uv_lods.zw);
}
void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) {
Geometry geom = readHitGeometry(rq, ubo.ubo.ray_cone_width, rayQueryGetIntersectionBarycentricsEXT(rq, true));
const float hitT = rayQueryGetIntersectionTEXT(rq, true); //gl_HitTEXT;
const vec3 rayDirection = rayQueryGetWorldRayDirectionEXT(rq); //gl_WorldRayDirectionEXT
payload.hit_t = vec4(geom.pos, hitT);
const Kusok kusok = getKusok(geom.kusok_index);
const uint tex_base_color = kusok.tex_base_color;
if ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) != 0) {
payload.emissive.rgb = SRGBtoLINEAR(texture(skybox, rayDirection).rgb);
return;
} else {
payload.base_color_a = sampleTexture(tex_base_color, geom.uv, geom.uv_lods) * kusok.color;
payload.material_rmxx.r = (kusok.tex_roughness > 0) ? sampleTexture(kusok.tex_roughness, geom.uv, geom.uv_lods).r : kusok.roughness;
payload.material_rmxx.g = (kusok.tex_metalness > 0) ? sampleTexture(kusok.tex_metalness, geom.uv, geom.uv_lods).r : kusok.metalness;
const uint tex_normal = kusok.tex_normalmap;
vec3 T = geom.tangent;
if (tex_normal > 0 && dot(T,T) > .5) {
T = normalize(T - dot(T, geom.normal_shading) * geom.normal_shading);
const vec3 B = normalize(cross(geom.normal_shading, T));
const mat3 TBN = mat3(T, B, geom.normal_shading);
const vec3 tnorm = sampleTexture(tex_normal, geom.uv, geom.uv_lods).xyz * 2. - 1.; // TODO is this sampling correct for normal data?
geom.normal_shading = normalize(TBN * tnorm);
}
}
payload.normals_gs.xy = normalEncode(geom.normal_geometry);
payload.normals_gs.zw = normalEncode(geom.normal_shading);
#if 1
// Real correct emissive color
//payload.emissive.rgb = kusok.emissive;
payload.emissive.rgb = clamp(kusok.emissive / (1.0/3.0) / 25, 0, 1.5) * SRGBtoLINEAR(payload.base_color_a.rgb);
#else
// Fake texture color
if (any(greaterThan(kusok.emissive, vec3(0.))))
payload.emissive.rgb = payload.base_color_a.rgb;
#endif
}
#endif // ifndef RAY_PRIMARY_HIT_GLSL_INCLUDED

View File

@ -1,6 +1,6 @@
{
"primary_ray": {
/*
"rgen": "ray_primary",
"miss": [
"ray_primary"
@ -9,6 +9,8 @@
{"closest": "ray_primary"},
{"closest": "ray_primary", "any": "ray_common_alphatest"}
]
*/
"comp": "ray_primary"
},
// "light_direct": {
// "template": true,
@ -35,5 +37,6 @@
},
"denoiser": {
"comp": "denoiser"
}
},
//"RESOURCES": { "position_t_prev": { "previous_frame": "position_t" }, },
}

View File

@ -1,3 +1,5 @@
#ifndef RT_GEOMETRY_GLSL_INCLUDED
#define RT_GEOMETRY_GLSL_INCLUDED
#include "utils.glsl"
// Taken from Journal of Computer Graphics Techniques, Vol. 10, No. 1, 2021.
@ -51,22 +53,38 @@ struct Geometry {
int kusok_index;
};
Geometry readHitGeometry() {
#ifdef RAY_QUERY
Geometry readHitGeometry(rayQueryEXT rq, float ray_cone_width, vec2 bary) {
const int instance_kusochki_offset = rayQueryGetIntersectionInstanceCustomIndexEXT(rq, true);
const int geometry_index = rayQueryGetIntersectionGeometryIndexEXT(rq, true);
const int primitive_index = rayQueryGetIntersectionPrimitiveIndexEXT(rq, true);
const mat4x3 objectToWorld = rayQueryGetIntersectionObjectToWorldEXT(rq, true);
const vec3 ray_direction = rayQueryGetWorldRayDirectionEXT(rq);
const float hit_t = rayQueryGetIntersectionTEXT(rq, true);
#else
Geometry readHitGeometry(vec2 bary, float ray_cone_width) {
const int instance_kusochki_offset = gl_InstanceCustomIndexEXT;
const int geometry_index = gl_GeometryIndexEXT;
const int primitive_index = gl_PrimitiveID;
const mat4x3 objectToWorld = gl_ObjectToWorldEXT;
const vec3 ray_direction = gl_WorldRayDirectionEXT;
const float hit_t = gl_HitTEXT;
#endif
Geometry geom;
const int instance_kusochki_offset = gl_InstanceCustomIndexEXT;
geom.kusok_index = instance_kusochki_offset + gl_GeometryIndexEXT;
geom.kusok_index = instance_kusochki_offset + geometry_index;
const Kusok kusok = getKusok(geom.kusok_index);
const uint first_index_offset = kusok.index_offset + gl_PrimitiveID * 3;
const uint first_index_offset = kusok.index_offset + primitive_index * 3;
const uint vi1 = uint(getIndex(first_index_offset+0)) + kusok.vertex_offset;
const uint vi2 = uint(getIndex(first_index_offset+1)) + kusok.vertex_offset;
const uint vi3 = uint(getIndex(first_index_offset+2)) + kusok.vertex_offset;
const vec3 pos[3] = {
gl_ObjectToWorldEXT * vec4(getVertex(vi1).pos, 1.f),
gl_ObjectToWorldEXT * vec4(getVertex(vi2).pos, 1.f),
gl_ObjectToWorldEXT * vec4(getVertex(vi3).pos, 1.f),
objectToWorld * vec4(getVertex(vi1).pos, 1.f),
objectToWorld * vec4(getVertex(vi2).pos, 1.f),
objectToWorld * vec4(getVertex(vi3).pos, 1.f),
};
const vec2 uvs[3] = {
@ -83,7 +101,7 @@ Geometry readHitGeometry() {
geom.normal_geometry = normalize(cross(pos[2]-pos[0], pos[1]-pos[0]));
// NOTE: only support rotations, for arbitrary transform would need to do transpose(inverse(mat3(gl_ObjectToWorldEXT)))
const mat3 normalTransform = mat3(gl_ObjectToWorldEXT);
const mat3 normalTransform = mat3(objectToWorld); // mat3(gl_ObjectToWorldEXT);
geom.normal_shading = normalize(normalTransform * baryMix(
getVertex(vi1).normal,
getVertex(vi2).normal,
@ -95,7 +113,8 @@ Geometry readHitGeometry() {
getVertex(vi3).tangent,
bary));
geom.uv_lods = computeAnisotropicEllipseAxes(geom.pos, geom.normal_geometry, gl_WorldRayDirectionEXT, ubo.ubo.ray_cone_width * gl_HitTEXT, pos, uvs, geom.uv);
geom.uv_lods = computeAnisotropicEllipseAxes(geom.pos, geom.normal_geometry, ray_direction, ray_cone_width * hit_t, pos, uvs, geom.uv);
return geom;
}
#endif // RT_GEOMETRY_GLSL_INCLUDED

View File

@ -224,7 +224,7 @@ static void performTracing(VkCommandBuffer cmdbuf, const perform_tracing_args_t*
vkCmdPipelineBarrier(cmdbuf,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0, 0, NULL, ARRAYSIZE(bmb), bmb, 0, NULL);
}
@ -253,7 +253,7 @@ static void performTracing(VkCommandBuffer cmdbuf, const perform_tracing_args_t*
} };
vkCmdPipelineBarrier(cmdbuf,
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0, 0, NULL, ARRAYSIZE(bmb), bmb, 0, NULL);
}
@ -270,7 +270,7 @@ static void performTracing(VkCommandBuffer cmdbuf, const perform_tracing_args_t*
}};
vkCmdPipelineBarrier(cmdbuf,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0, 0, NULL, ARRAYSIZE(bmb), bmb, 0, NULL);
}