Skip to content

Commit

Permalink
raytracing: Initial Vulkan support
Browse files Browse the repository at this point in the history
- Vulkan implementations in `RenderingDeviceDriverVulkan`
- Raytracing instruction list in `RenderingDeviceGraph`
- Functions to create acceleration structures and raytracing pipelines
  in `RenderingDevice`
- Raygen, Miss, and ClosestHit shader stages support
- GDScript bindings
- Update classes documentation
- Include a-johnston RenderingDeviceDriverMetal changes
- Unimplemented placeholders for Metal and D3D12.
  • Loading branch information
Fahien committed Dec 6, 2024
1 parent 893bbdf commit ef1d75e
Show file tree
Hide file tree
Showing 28 changed files with 2,375 additions and 55 deletions.
18 changes: 18 additions & 0 deletions doc/classes/RDShaderSPIRV.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,21 @@
</method>
</methods>
<members>
<member name="bytecode_closest_hit" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()">
The SPIR-V bytecode for the closest hit shader stage.
</member>
<member name="bytecode_compute" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()">
The SPIR-V bytecode for the compute shader stage.
</member>
<member name="bytecode_fragment" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()">
The SPIR-V bytecode for the fragment shader stage.
</member>
<member name="bytecode_miss" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()">
The SPIR-V bytecode for the miss shader stage.
</member>
<member name="bytecode_raygen" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()">
The SPIR-V bytecode for the ray generation shader stage.
</member>
<member name="bytecode_tesselation_control" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()">
The SPIR-V bytecode for the tessellation control shader stage.
</member>
Expand All @@ -57,12 +66,21 @@
<member name="bytecode_vertex" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()">
The SPIR-V bytecode for the vertex shader stage.
</member>
<member name="compile_error_closest_hit" type="String" setter="set_stage_compile_error" getter="get_stage_compile_error" default="&quot;&quot;">
The compilation error message for the closest hit shader stage (set by the SPIR-V compiler and Godot). If empty, shader compilation was successful.
</member>
<member name="compile_error_compute" type="String" setter="set_stage_compile_error" getter="get_stage_compile_error" default="&quot;&quot;">
The compilation error message for the compute shader stage (set by the SPIR-V compiler and Godot). If empty, shader compilation was successful.
</member>
<member name="compile_error_fragment" type="String" setter="set_stage_compile_error" getter="get_stage_compile_error" default="&quot;&quot;">
The compilation error message for the fragment shader stage (set by the SPIR-V compiler and Godot). If empty, shader compilation was successful.
</member>
<member name="compile_error_miss" type="String" setter="set_stage_compile_error" getter="get_stage_compile_error" default="&quot;&quot;">
The compilation error message for the miss shader stage (set by the SPIR-V compiler and Godot). If empty, shader compilation was successful.
</member>
<member name="compile_error_raygen" type="String" setter="set_stage_compile_error" getter="get_stage_compile_error" default="&quot;&quot;">
The compilation error message for the ray generation shader stage (set by the SPIR-V compiler and Godot). If empty, shader compilation was successful.
</member>
<member name="compile_error_tesselation_control" type="String" setter="set_stage_compile_error" getter="get_stage_compile_error" default="&quot;&quot;">
The compilation error message for the tessellation control shader stage (set by the SPIR-V compiler and Godot). If empty, shader compilation was successful.
</member>
Expand Down
9 changes: 9 additions & 0 deletions doc/classes/RDShaderSource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,21 @@
<member name="language" type="int" setter="set_language" getter="get_language" enum="RenderingDevice.ShaderLanguage" default="0">
The language the shader is written in.
</member>
<member name="source_closest_hit" type="String" setter="set_stage_source" getter="get_stage_source" default="&quot;&quot;">
Source code for the shader's closest hit stage.
</member>
<member name="source_compute" type="String" setter="set_stage_source" getter="get_stage_source" default="&quot;&quot;">
Source code for the shader's compute stage.
</member>
<member name="source_fragment" type="String" setter="set_stage_source" getter="get_stage_source" default="&quot;&quot;">
Source code for the shader's fragment stage.
</member>
<member name="source_miss" type="String" setter="set_stage_source" getter="get_stage_source" default="&quot;&quot;">
Source code for the shader's miss stage;
</member>
<member name="source_raygen" type="String" setter="set_stage_source" getter="get_stage_source" default="&quot;&quot;">
Source code for the shader's ray generation stage.
</member>
<member name="source_tesselation_control" type="String" setter="set_stage_source" getter="get_stage_source" default="&quot;&quot;">
Source code for the shader's tessellation control stage.
</member>
Expand Down
160 changes: 158 additions & 2 deletions doc/classes/RenderingDevice.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@
This method does nothing.
</description>
</method>
<method name="blas_create">
<return type="RID" />
<param index="0" name="vertex_array" type="RID" />
<param index="1" name="index_array" type="RID" />
<param index="2" name="transform_buffer" type="RID" />
<param index="3" name="transform_offset" type="int" default="0" />
<description>
Creates a new Bottom Level Acceleration Structure. It can be accessed with the RID that is returned.
Once finished with your RID, you will want to free the RID using the RenderingDevice's [method free_rid] method.
</description>
</method>
<method name="buffer_clear">
<return type="int" enum="Error" />
<param index="0" name="buffer" type="RID" />
Expand Down Expand Up @@ -680,6 +691,118 @@
Limits for various graphics hardware can be found in the [url=https://vulkan.gpuinfo.org/]Vulkan Hardware Database[/url].
</description>
</method>
<method name="raytracing_is_supported" qualifiers="const">
<return type="bool" />
<description>
Whether raytracing is supported by the selected device.
</description>
</method>
<method name="raytracing_list_add_barrier">
<return type="void" />
<param index="0" name="raytracing_list" type="int" />
<description>
Raises a Vulkan raytracing barrier in the specified [param raytracing_list].
</description>
</method>
<method name="raytracing_list_begin">
<return type="int" />
<description>
Starts a list of raytracing drawing commands created with the [code]draw_*[/code] methods. The returned value should be passed to other [code]raytracing_list_*[/code] functions.
Multiple raytracing lists cannot be created at the same time; you must finish the previous raytracing list first using [method raytracing_list_end].
A simple raytracing operation might look like this (code is not a complete example):
[codeblock]
var rd = RenderingDevice.new()

# Create a BLAS for a mesh.
blas = rd.blas_create(vertex_array, index_array, transform_buffer)
# Create TLAS with BLASs.
tlas = rd.tlas_create([blas])

var raylist := rd.raytracing_list_begin()

# Build acceleration structures.
rd.raytracing_list_build_acceleration_structure(raylist, blas)
rd.raytracing_list_build_acceleration_structure(raylist, tlas)

# Bind pipeline and uniforms.
rd.raytracing_list_bind_raytracing_pipeline(raylist, raytracing_pipeline)
rd.raytracing_list_bind_uniform_set(raylist, uniform_set, 0)

# Trace rays.
var width = get_viewport().size.x
var height = get_viewport().size.y
rd.raytracing_list_trace_rays(raylist, width, height)
rd.raytracing_list_add_barrier(raylist)

rd.raytracing_list_end()
[/codeblock]
</description>
</method>
<method name="raytracing_list_bind_raytracing_pipeline">
<return type="void" />
<param index="0" name="raytracing_list" type="int" />
<param index="1" name="raytracing_pipeline" type="RID" />
<description>
Binds [param raytracing_pipeline] to the specified [param raytracing_list].
</description>
</method>
<method name="raytracing_list_bind_uniform_set">
<return type="void" />
<param index="0" name="raytracing_list" type="int" />
<param index="1" name="uniform_set" type="RID" />
<param index="2" name="set_index" type="int" />
<description>
Binds the [param uniform_set] to this [param raytracing_list]. Godot ensures that all textures in the uniform set have the correct Vulkan access masks. If Godot had to change access masks of textures, it will raise a Vulkan image memory barrier.
</description>
</method>
<method name="raytracing_list_build_acceleration_structure">
<return type="void" />
<param index="0" name="raytracing_list" type="int" />
<param index="1" name="acceleration_structure" type="RID" />
<description>
Builds the [param acceleration_structure] with the specified [param raytracing_list].
</description>
</method>
<method name="raytracing_list_end">
<return type="void" />
<description>
Finishes a list of raytracing commands created with the [code]raytracing_*[/code] methods.
</description>
</method>
<method name="raytracing_list_set_push_constant">
<return type="void" />
<param index="0" name="raytracing_list" type="int" />
<param index="1" name="buffer" type="PackedByteArray" />
<param index="2" name="size_bytes" type="int" />
<description>
Sets the push constant data to [param buffer] for the specified [param raytracing_list]. The shader determines how this binary data is used. The buffer's size in bytes must also be specified in [param size_bytes] (this can be obtained by calling the [method PackedByteArray.size] method on the passed [param buffer]).
</description>
</method>
<method name="raytracing_list_trace_rays">
<return type="void" />
<param index="0" name="raytracing_list" type="int" />
<param index="1" name="width" type="int" />
<param index="2" name="height" type="int" />
<description>
Initializes a ray tracing dispatch for the specified [param raytracing_list] assembling a group of [param width] x [param height] rays.
</description>
</method>
<method name="raytracing_pipeline_create">
<return type="RID" />
<param index="0" name="shader" type="RID" />
<param index="1" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]" />
<description>
Creates a new raytracing pipeline. It can be accessed with the RID that is returned.
Once finished with your RID, you will want to free the RID using the RenderingDevice's [method free_rid] method.
</description>
</method>
<method name="raytracing_pipeline_is_valid">
<return type="bool" />
<param index="0" name="raytracing_pipeline" type="RID" />
<description>
Returns [code]true[/code] if the raytracing pipeline specified by the [param raytracing_pipeline] RID is valid, [code]false[/code] otherwise.
</description>
</method>
<method name="render_pipeline_create">
<return type="RID" />
<param index="0" name="shader" type="RID" />
Expand Down Expand Up @@ -1011,6 +1134,14 @@
[b]Note:[/b] The existing [param texture] requires the [constant TEXTURE_USAGE_CAN_UPDATE_BIT] to be updatable.
</description>
</method>
<method name="tlas_create">
<return type="RID" />
<param index="0" name="blases" type="RID[]" />
<description>
Creates a new Top Level Acceleration Structure. It can be accessed with the RID that is returned.
Once finished with your RID, you will want to free the RID using the RenderingDevice's [method free_rid] method.
</description>
</method>
<method name="uniform_buffer_create">
<return type="RID" />
<param index="0" name="size_bytes" type="int" />
Expand Down Expand Up @@ -2006,6 +2137,10 @@
</constant>
<constant name="STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT" value="1" enum="StorageBufferUsage" is_bitfield="true">
</constant>
<constant name="STORAGE_BUFFER_USAGE_SHADER_DEVICE_ADDRESS" value="2" enum="StorageBufferUsage" is_bitfield="true">
</constant>
<constant name="STORAGE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY" value="4" enum="StorageBufferUsage" is_bitfield="true">
</constant>
<constant name="UNIFORM_TYPE_SAMPLER" value="0" enum="UniformType">
Sampler uniform.
</constant>
Expand Down Expand Up @@ -2036,7 +2171,10 @@
<constant name="UNIFORM_TYPE_INPUT_ATTACHMENT" value="9" enum="UniformType">
Input attachment uniform.
</constant>
<constant name="UNIFORM_TYPE_MAX" value="10" enum="UniformType">
<constant name="UNIFORM_TYPE_ACCELERATION_STRUCTURE" value="10" enum="UniformType">
Acceleration structure uniform.
</constant>
<constant name="UNIFORM_TYPE_MAX" value="11" enum="UniformType">
Represents the size of the [enum UniformType] enum.
</constant>
<constant name="RENDER_PRIMITIVE_POINTS" value="0" enum="RenderPrimitive">
Expand Down Expand Up @@ -2344,7 +2482,16 @@
<constant name="SHADER_STAGE_COMPUTE" value="4" enum="ShaderStage">
Compute shader stage. This can be used to run arbitrary computing tasks in a shader, performing them on the GPU instead of the CPU.
</constant>
<constant name="SHADER_STAGE_MAX" value="5" enum="ShaderStage">
<constant name="SHADER_STAGE_RAYGEN" value="5" enum="ShaderStage">
Ray generation shader stage. This can be used to generate primary rays.
</constant>
<constant name="SHADER_STAGE_MISS" value="6" enum="ShaderStage">
Miss shader stage. This can be used to specify what happens if a ray does not hit anything in the scene.
</constant>
<constant name="SHADER_STAGE_CLOSEST_HIT" value="7" enum="ShaderStage">
Closest hit shader stage. This can be used to specify what happens when a ray hits the closest geometry in the scene.
</constant>
<constant name="SHADER_STAGE_MAX" value="8" enum="ShaderStage">
Represents the size of the [enum ShaderStage] enum.
</constant>
<constant name="SHADER_STAGE_VERTEX_BIT" value="1" enum="ShaderStage">
Expand All @@ -2362,6 +2509,15 @@
<constant name="SHADER_STAGE_COMPUTE_BIT" value="16" enum="ShaderStage">
Compute shader stage bit (see also [constant SHADER_STAGE_COMPUTE]).
</constant>
<constant name="SHADER_STAGE_RAYGEN_BIT" value="32" enum="ShaderStage">
Ray generation shader stage bit (see also [constant SHADER_STAGE_RAYGEN]).
</constant>
<constant name="SHADER_STAGE_MISS_BIT" value="64" enum="ShaderStage">
Miss shader stage bit (see also [constant SHADER_STAGE_MISS]).
</constant>
<constant name="SHADER_STAGE_CLOSEST_HIT_BIT" value="128" enum="ShaderStage">
Closest hit shader stage bit (see also [constant SHADER_STAGE_CLOSEST_HIT]).
</constant>
<constant name="SHADER_LANGUAGE_GLSL" value="0" enum="ShaderLanguage">
Khronos' GLSL shading language (used natively by OpenGL and Vulkan). This is the language used for core Godot shaders.
</constant>
Expand Down
70 changes: 64 additions & 6 deletions drivers/d3d12/rendering_device_driver_d3d12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3012,7 +3012,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec
binary_data.vertex_input_mask = shader_refl.vertex_input_mask;
binary_data.fragment_output_mask = shader_refl.fragment_output_mask;
binary_data.specialization_constants_count = shader_refl.specialization_constants.size();
binary_data.is_compute = shader_refl.is_compute;
binary_data.pipeline_type = shader_refl.pipeline_type;
binary_data.compute_local_size[0] = shader_refl.compute_local_size[0];
binary_data.compute_local_size[1] = shader_refl.compute_local_size[1];
binary_data.compute_local_size[2] = shader_refl.compute_local_size[2];
Expand Down Expand Up @@ -3211,7 +3211,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec
DEV_ASSERT(binding_info.res_class == (uint32_t)RES_CLASS_INVALID || binding_info.res_class == (uint32_t)res_class);
binding_info.res_class = res_class;
} else if (p_dxil_type == DXIL_RES_SAMPLER) {
binding_info.has_sampler = (uint32_t)true;
binding_info.has_sampler = (uint32_t) true;
} else {
CRASH_NOW();
}
Expand Down Expand Up @@ -3643,8 +3643,8 @@ RDD::ShaderID RenderingDeviceDriverD3D12::shader_create_from_bytecode(const Vect
r_shader_desc.vertex_input_mask = binary_data.vertex_input_mask;
r_shader_desc.fragment_output_mask = binary_data.fragment_output_mask;

r_shader_desc.is_compute = binary_data.is_compute;
shader_info_in.is_compute = binary_data.is_compute;
r_shader_desc.pipeline_type = binary_data.pipeline_type;
shader_info_in.pipeline_type = binary_data.pipeline_type;
r_shader_desc.compute_local_size[0] = binary_data.compute_local_size[0];
r_shader_desc.compute_local_size[1] = binary_data.compute_local_size[1];
r_shader_desc.compute_local_size[2] = binary_data.compute_local_size[2];
Expand Down Expand Up @@ -4890,10 +4890,13 @@ void RenderingDeviceDriverD3D12::command_bind_push_constants(CommandBufferID p_c
if (!shader_info_in->dxil_push_constant_size) {
return;
}
if (shader_info_in->is_compute) {
if (shader_info_in->pipeline_type == PipelineType::COMPUTE) {
cmd_buf_info->cmd_list->SetComputeRoot32BitConstants(0, p_data.size(), p_data.ptr(), p_dst_first_index);
} else {
} else if (shader_info_in->pipeline_type == PipelineType::RASTERIZATION) {
cmd_buf_info->cmd_list->SetGraphicsRoot32BitConstants(0, p_data.size(), p_data.ptr(), p_dst_first_index);
} else {
// TODO
ERR_FAIL_MSG("Unimplemented!");
}
}

Expand Down Expand Up @@ -5918,6 +5921,61 @@ RDD::PipelineID RenderingDeviceDriverD3D12::compute_pipeline_create(ShaderID p_s
return PipelineID(pipeline_info);
}

/********************/
/**** RAYTRACING ****/
/********************/

// ---- ACCELERATION STRUCTURES ----

RDD::AccelerationStructureID RenderingDeviceDriverD3D12::blas_create(BufferID p_vertex_buffer, uint64_t p_vertex_offset, VertexFormatID p_vertex_format, uint32_t p_vertex_count, BufferID p_index_buffer, IndexBufferFormat p_index_format, uint64_t p_index_offset, uint32_t p_index_count, BufferID p_instance_buffer, uint64_t p_instance_offset) {
// TODO
ERR_FAIL_V_MSG(AccelerationStructureID(), "Unimplemented!");
}

RDD::AccelerationStructureID RenderingDeviceDriverD3D12::tlas_create(const LocalVector<AccelerationStructureID> &p_blases) {
// TODO
ERR_FAIL_V_MSG(AccelerationStructureID(), "Unimplemented!");
}

void RenderingDeviceDriverD3D12::acceleration_structure_free(AccelerationStructureID p_acceleration_structure) {
// TODO
ERR_FAIL_MSG("Unimplemented!");
}

// ----- PIPELINE -----

RDD::RaytracingPipelineID RenderingDeviceDriverD3D12::raytracing_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) {
// TODO
ERR_FAIL_V_MSG(RaytracingPipelineID(), "Unimplemented!");
}

void RenderingDeviceDriverD3D12::raytracing_pipeline_free(RDD::RaytracingPipelineID p_pipeline) {
// TODO
ERR_FAIL_MSG("Unimplemented!");
}

// ----- COMMANDS -----

void RenderingDeviceDriverD3D12::command_build_acceleration_structure(CommandBufferID p_cmd_buffer, AccelerationStructureID p_acceleration_structure) {
// TODO
ERR_FAIL_MSG("Unimplemented!");
}

void RenderingDeviceDriverD3D12::command_bind_raytracing_pipeline(CommandBufferID p_cmd_buffer, RaytracingPipelineID p_pipeline) {
// TODO
ERR_FAIL_MSG("Unimplemented!");
}

void RenderingDeviceDriverD3D12::command_bind_raytracing_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
// TODO
ERR_FAIL_MSG("Unimplemented!");
}

void RenderingDeviceDriverD3D12::command_raytracing_trace_rays(CommandBufferID p_cmd_buffer, RaytracingPipelineID p_pipeline, ShaderID p_shader, uint32_t p_width, uint32_t p_height) {
// TODO
ERR_FAIL_MSG("Unimplemented!");
}

/*****************/
/**** QUERIES ****/
/*****************/
Expand Down
Loading

0 comments on commit ef1d75e

Please sign in to comment.