raytracing: Initial Vulkan support

- 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.
- Unimplemented placeholders for Metal and D3D12.
- Build acceleration structure command.
- Expose a shader preprocessor define.
- Align build scratch address.
- Create STB after creating the pipeline.
- Separate acceleration structure barriers.
- Use transforms in TLAS instances.
- AnyHit and Intersection stages.
- Optionally set acceleration structure build input buffer usage.
- Introduce instances buffer.
- Move scratch buffers to RenderingDevice.
- Rename AccelerationStructureGeometryBits.
- Use regular buffer creation and free routines for scratch buffer.
- Store trackers in acceleration structures.
- Bump Shader SPIR-V version to 1.4
- Add Position attribute location in blas_create.
- Encapsulate MoltenVK check in preprocessor macro.
- Split SUPPORTS_RAYTRACING for pipeline and query.
This commit is contained in:
Antonio Caggiano 2024-11-11 08:40:38 +01:00
parent 66b9c7251e
commit 27e4f24800
No known key found for this signature in database
GPG key ID: C9D9BD410EBBEDFF
28 changed files with 2998 additions and 114 deletions

View file

@ -216,6 +216,238 @@ RID RenderingDevice::shader_create_from_spirv(const Vector<ShaderStageSPIRVData>
return shader_create_from_bytecode(bytecode);
}
/********************************/
/**** ACCELERATION STRUCTURE ****/
/********************************/
RID RenderingDevice::blas_create(RID p_vertex_array, RID p_index_array, BitField<AccelerationStructureGeometryBits> p_geometry_bits, uint32_t p_position_attribute_location) {
ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_RAYTRACING_PIPELINE) && !has_feature(SUPPORTS_RAY_QUERY), RID(), "The current rendering device has neither raytracing pipeline nor ray query support.");
VertexArray *vertex_array = vertex_array_owner.get_or_null(p_vertex_array);
ERR_FAIL_NULL_V(vertex_array, RID());
uint32_t position_binding = p_position_attribute_location;
RDD::VertexFormatID vertex_format;
if (vertex_array->description != INVALID_ID) {
ERR_FAIL_COND_V(!vertex_formats.has(vertex_array->description), RID());
const VertexDescriptionCache &vd_cache = vertex_formats[vertex_array->description];
vertex_format = vd_cache.driver_id;
const VertexAttribute *position_attribute = nullptr;
for (int i = 0; i < vd_cache.vertex_formats.size(); i++) {
const VertexAttribute &attr = vd_cache.vertex_formats[i];
if (attr.location == p_position_attribute_location) {
position_attribute = &attr;
break;
}
}
ERR_FAIL_NULL_V_MSG(position_attribute, RID(), vformat("Vertex array is missing a position attribute at location %u.", p_position_attribute_location));
ERR_FAIL_COND_V_MSG(position_attribute->frequency != VERTEX_FREQUENCY_VERTEX, RID(), vformat("Position attribute at location %u must use vertex frequency.", p_position_attribute_location));
if (position_attribute->binding != UINT32_MAX) {
position_binding = position_attribute->binding;
}
}
ERR_FAIL_COND_V_MSG(position_binding >= (uint32_t)vertex_array->buffers.size(), RID(), vformat("Vertex array is missing a buffer for binding %u.", position_binding));
RDD::BufferID vertex_buffer = vertex_array->buffers[position_binding];
uint64_t vertex_offset = vertex_array->offsets[position_binding];
// Indices are optional.
IndexArray *index_array = index_array_owner.get_or_null(p_index_array);
RDD::BufferID index_buffer = RDD::BufferID();
IndexBufferFormat index_format = IndexBufferFormat::INDEX_BUFFER_FORMAT_UINT32;
uint32_t index_offset_bytes = 0;
uint32_t index_count = 0;
if (index_array) {
index_buffer = index_array->driver_id;
index_format = index_array->format;
index_offset_bytes = index_array->offset * (index_array->format == INDEX_BUFFER_FORMAT_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));
index_count = index_array->indices;
}
AccelerationStructure acceleration_structure;
acceleration_structure.type = RDD::ACCELERATION_STRUCTURE_TYPE_BLAS;
BitField<RDD::AccelerationStructureGeometryBits> geometry_bits = 0;
if (p_geometry_bits.has_flag(ACCELERATION_STRUCTURE_GEOMETRY_OPAQUE)) {
geometry_bits.set_flag(RDD::ACCELERATION_STRUCTURE_GEOMETRY_OPAQUE);
}
if (p_geometry_bits.has_flag(ACCELERATION_STRUCTURE_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION)) {
geometry_bits.set_flag(RDD::ACCELERATION_STRUCTURE_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION);
}
acceleration_structure.driver_id = driver->blas_create(vertex_buffer, vertex_offset, vertex_format, vertex_array->vertex_count, p_position_attribute_location, index_buffer, index_format, index_offset_bytes, index_count, geometry_bits);
ERR_FAIL_COND_V_MSG(!acceleration_structure.driver_id, RID(), "Failed to create BLAS.");
acceleration_structure.vertex_array = p_vertex_array;
acceleration_structure.index_array = p_index_array;
acceleration_structure.draw_tracker = RDG::resource_tracker_create();
acceleration_structure.draw_tracker->acceleration_structure_driver_id = acceleration_structure.driver_id;
// Assume we are going to build this acceleration structure
acceleration_structure.draw_tracker->usage = RDG::RESOURCE_USAGE_ACCELERATION_STRUCTURE_READ_WRITE;
for (int i = 0; i < vertex_array->draw_trackers.size(); i++) {
acceleration_structure.draw_trackers.push_back(vertex_array->draw_trackers[i]);
}
_check_transfer_worker_vertex_array(vertex_array);
if (index_array && index_array->draw_tracker) {
acceleration_structure.draw_trackers.push_back(index_array->draw_tracker);
}
_check_transfer_worker_index_array(index_array);
RID id = acceleration_structure_owner.make_rid(acceleration_structure);
#ifdef DEV_ENABLED
set_resource_name(id, "RID:" + itos(id.get_id()));
#endif
return id;
}
BitField<RDD::BufferUsageBits> RenderingDevice::_creation_to_usage_bits(BitField<RD::BufferCreationBits> p_creation_bits) {
BitField<RDD::BufferUsageBits> usage = 0;
if (p_creation_bits.has_flag(BUFFER_CREATION_AS_STORAGE_BIT)) {
usage.set_flag(RDD::BUFFER_USAGE_STORAGE_BIT);
}
if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_BUFFER_DEVICE_ADDRESS), 0,
"The GPU doesn't support buffer address flag.");
#endif
usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);
}
if (p_creation_bits.has_flag(BUFFER_CREATION_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT)) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_RAYTRACING_PIPELINE) && !has_feature(SUPPORTS_RAY_QUERY), 0,
"The GPU doesn't support acceleration structure build input flag.");
#endif
usage.set_flag(RDD::BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT);
}
return usage;
}
RID RenderingDevice::tlas_instances_buffer_create(uint32_t p_instance_count, BitField<BufferCreationBits> p_creation_bits) {
ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_RAYTRACING_PIPELINE) && !has_feature(SUPPORTS_RAY_QUERY), RID(), "The current rendering device has neither raytracing pipeline nor ray query support.");
ERR_FAIL_COND_V(p_instance_count == 0, RID());
uint32_t instances_buffer_size_bytes = driver->tlas_instances_buffer_get_size_bytes(p_instance_count);
InstancesBuffer instances_buffer;
instances_buffer.instance_count = p_instance_count;
instances_buffer.buffer.size = instances_buffer_size_bytes;
instances_buffer.buffer.usage = _creation_to_usage_bits(p_creation_bits) | RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT | RDD::BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT;
instances_buffer.buffer.driver_id = driver->buffer_create(instances_buffer.buffer.size, instances_buffer.buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_CPU, frames_drawn);
ERR_FAIL_COND_V_MSG(!instances_buffer.buffer.driver_id, RID(), "Failed to create instances buffer.");
_THREAD_SAFE_LOCK_
buffer_memory += instances_buffer.buffer.size;
_THREAD_SAFE_UNLOCK_
RID id = instances_buffer_owner.make_rid(instances_buffer);
#ifdef DEV_ENABLED
set_resource_name(id, "RID:" + itos(id.get_id()));
#endif
return id;
}
void RenderingDevice::tlas_instances_buffer_fill(RID p_instances_buffer, const Vector<RID> &p_blases, VectorView<Transform3D> p_transforms) {
ERR_FAIL_COND_MSG(!has_feature(SUPPORTS_RAYTRACING_PIPELINE) && !has_feature(SUPPORTS_RAY_QUERY), "The current rendering device has neither raytracing pipeline nor ray query support.");
InstancesBuffer *instances_buffer = instances_buffer_owner.get_or_null(p_instances_buffer);
ERR_FAIL_NULL_MSG(instances_buffer, "Instances buffer input is not valid.");
uint32_t blases_count = p_blases.size();
ERR_FAIL_COND_MSG(blases_count != instances_buffer->instance_count, "The number of blases is not equal to the instance count of the instances buffer.");
ERR_FAIL_COND_MSG(blases_count != p_transforms.size(), "Blases and transforms vectors must have the same size.");
thread_local LocalVector<RDD::AccelerationStructureID> blases;
blases.resize(blases_count);
for (uint32_t i = 0; i < blases_count; i++) {
const AccelerationStructure *blas = acceleration_structure_owner.get_or_null(p_blases[i]);
ERR_FAIL_NULL_MSG(blas, "BLAS input is not valid.");
ERR_FAIL_COND_MSG(blas->type != RDD::ACCELERATION_STRUCTURE_TYPE_BLAS, "Acceleration structure input is not a BLAS.");
blases[i] = blas->driver_id;
}
instances_buffer->blases = p_blases;
driver->tlas_instances_buffer_fill(instances_buffer->buffer.driver_id, blases, p_transforms);
}
RID RenderingDevice::tlas_create(RID p_instances_buffer) {
ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_RAYTRACING_PIPELINE) && !has_feature(SUPPORTS_RAY_QUERY), RID(), "The current rendering device has neither raytracing pipeline nor ray query support.");
const InstancesBuffer *instances_buffer = instances_buffer_owner.get_or_null(p_instances_buffer);
ERR_FAIL_NULL_V_MSG(instances_buffer, RID(), "Instances buffer input is not valid.");
AccelerationStructure acceleration_structure;
acceleration_structure.type = RDD::ACCELERATION_STRUCTURE_TYPE_TLAS;
acceleration_structure.driver_id = driver->tlas_create(instances_buffer->buffer.driver_id);
ERR_FAIL_COND_V_MSG(!acceleration_structure.driver_id, RID(), "Failed to create TLAS.");
acceleration_structure.instances_buffer = p_instances_buffer;
acceleration_structure.draw_tracker = RDG::resource_tracker_create();
acceleration_structure.draw_tracker->acceleration_structure_driver_id = acceleration_structure.driver_id;
// Assume we are going to build this acceleration structure
acceleration_structure.draw_tracker->usage = RDG::RESOURCE_USAGE_ACCELERATION_STRUCTURE_READ_WRITE;
for (Vector<RID>::ConstIterator itr = instances_buffer->blases.begin(); itr != instances_buffer->blases.end(); ++itr) {
const AccelerationStructure *blas = acceleration_structure_owner.get_or_null(*itr);
ERR_FAIL_NULL_V_MSG(blas, RID(), "BLAS input is not valid.");
if (blas->draw_tracker) {
acceleration_structure.draw_trackers.push_back(blas->draw_tracker);
}
}
RID id = acceleration_structure_owner.make_rid(acceleration_structure);
#ifdef DEV_ENABLED
set_resource_name(id, "RID:" + itos(id.get_id()));
#endif
return id;
}
Error RenderingDevice::acceleration_structure_build(RID p_acceleration_structure) {
ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);
ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,
"Building acceleration structures is forbidden during creation of a draw list.");
ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,
"Building acceleration structures is forbidden during creation of a compute list.");
ERR_FAIL_COND_V_MSG(raytracing_list.active, ERR_INVALID_PARAMETER,
"Building acceleration structures is forbidden during creation of a raytracing list.");
AccelerationStructure *accel = acceleration_structure_owner.get_or_null(p_acceleration_structure);
ERR_FAIL_NULL_V_MSG(accel, ERR_INVALID_PARAMETER, "Acceleration structure argument is not valid.");
uint64_t scratch_size = driver->acceleration_structure_get_scratch_size_bytes(accel->driver_id);
const Buffer *scratch_buffer = storage_buffer_owner.get_or_null(accel->scratch_buffer);
if (scratch_buffer && driver->buffer_get_allocation_size(scratch_buffer->driver_id) < scratch_size) {
scratch_buffer = nullptr;
free_rid(accel->scratch_buffer);
accel->scratch_buffer = RID();
}
if (accel->scratch_buffer == RID()) {
accel->scratch_buffer = storage_buffer_create(scratch_size, { nullptr, 0 }, RDD::BUFFER_USAGE_STORAGE_BIT | RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);
ERR_FAIL_COND_V(accel->scratch_buffer == RID(), ERR_CANT_CREATE);
}
if (scratch_buffer == nullptr) {
scratch_buffer = storage_buffer_owner.get_or_null(accel->scratch_buffer);
ERR_FAIL_NULL_V_MSG(scratch_buffer, ERR_CANT_CREATE, "Scratch buffer is not valid.");
}
draw_graph.add_acceleration_structure_build(accel->driver_id, scratch_buffer->driver_id, accel->draw_tracker, accel->draw_trackers);
return OK;
}
/***************************/
/**** BUFFER MANAGEMENT ****/
/***************************/
@ -233,6 +465,8 @@ RenderingDevice::Buffer *RenderingDevice::_get_buffer_from_owner(RID p_buffer) {
//buffer = texture_buffer_owner.get_or_null(p_buffer)->buffer;
} else if (storage_buffer_owner.owns(p_buffer)) {
buffer = storage_buffer_owner.get_or_null(p_buffer);
} else if (instances_buffer_owner.owns(p_buffer)) {
buffer = &instances_buffer_owner.get_or_null(p_buffer)->buffer;
}
return buffer;
}
@ -426,9 +660,11 @@ Error RenderingDevice::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t
ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);
ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,
"Copying buffers is forbidden during creation of a draw list");
"Copying buffers is forbidden during creation of a draw list.");
ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,
"Copying buffers is forbidden during creation of a compute list");
"Copying buffers is forbidden during creation of a compute list.");
ERR_FAIL_COND_V_MSG(raytracing_list.active, ERR_INVALID_PARAMETER,
"Copying buffers is forbidden during creation of a raytracing list.");
Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer);
if (!src_buffer) {
@ -469,9 +705,11 @@ Error RenderingDevice::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p
copy_bytes_count += p_size;
ERR_FAIL_COND_V_MSG(draw_list.active && !p_skip_check, ERR_INVALID_PARAMETER,
"Updating buffers is forbidden during creation of a draw list");
"Updating buffers is forbidden during creation of a draw list.");
ERR_FAIL_COND_V_MSG(compute_list.active && !p_skip_check, ERR_INVALID_PARAMETER,
"Updating buffers is forbidden during creation of a compute list");
"Updating buffers is forbidden during creation of a compute list.");
ERR_FAIL_COND_V_MSG(raytracing_list.active && !p_skip_check, ERR_INVALID_PARAMETER,
"Updating buffers is forbidden during creation of a raytracing list.");
Buffer *buffer = _get_buffer_from_owner(p_buffer);
ERR_FAIL_NULL_V_MSG(buffer, ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
@ -557,9 +795,11 @@ Error RenderingDevice::driver_callback_add(RDD::DriverCallback p_callback, void
ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);
ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,
"Driver callback is forbidden during creation of a draw list");
"Driver callback is forbidden during creation of a draw list.");
ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,
"Driver callback is forbidden during creation of a compute list");
"Driver callback is forbidden during creation of a compute list.");
ERR_FAIL_COND_V_MSG(raytracing_list.active, ERR_INVALID_PARAMETER,
"Driver callback is forbidden during creation of a raytracing list.");
thread_local LocalVector<RDG::ResourceTracker *> trackers;
thread_local LocalVector<RDG::ResourceUsage> usages;
@ -628,11 +868,13 @@ Error RenderingDevice::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_
ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);
ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER,
"Size must be a multiple of four");
"Size must be a multiple of four.");
ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER,
"Updating buffers in is forbidden during creation of a draw list");
"Updating buffers in is forbidden during creation of a draw list.");
ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER,
"Updating buffers is forbidden during creation of a compute list");
"Updating buffers is forbidden during creation of a compute list.");
ERR_FAIL_COND_V_MSG(raytracing_list.active, ERR_INVALID_PARAMETER,
"Updating buffers is forbidden during creation of a raytracing list.");
Buffer *buffer = _get_buffer_from_owner(p_buffer);
if (!buffer) {
@ -840,6 +1082,14 @@ RID RenderingDevice::storage_buffer_create(uint32_t p_size_bytes, Span<uint8_t>
buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);
}
if (p_creation_bits.has_flag(BUFFER_CREATION_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT)) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_RAYTRACING_PIPELINE) && !has_feature(SUPPORTS_RAY_QUERY), RID(),
"The GPU doesn't support acceleration structure build input flag.");
#endif
buffer.usage.set_flag(RDD::BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT);
}
buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU, frames_drawn);
ERR_FAIL_COND_V(!buffer.driver_id, RID());
@ -1528,7 +1778,7 @@ Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, cons
tb.subresources.mipmap_count = texture->mipmaps;
tb.subresources.base_layer = p_layer;
tb.subresources.layer_count = 1;
driver->command_pipeline_barrier(transfer_worker->command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_COPY_BIT, {}, {}, tb);
driver->command_pipeline_barrier(transfer_worker->command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_COPY_BIT, {}, {}, tb, {});
}
}
@ -1614,7 +1864,9 @@ Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, cons
Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data) {
ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE);
ERR_FAIL_COND_V_MSG(draw_list.active || compute_list.active, ERR_INVALID_PARAMETER, "Updating textures is forbidden during creation of a draw or compute list");
ERR_FAIL_COND_V_MSG(draw_list.active, ERR_INVALID_PARAMETER, "Updating textures is forbidden during creation of a draw list.");
ERR_FAIL_COND_V_MSG(compute_list.active, ERR_INVALID_PARAMETER, "Updating textures is forbidden during creation of a compute list.");
ERR_FAIL_COND_V_MSG(raytracing_list.active, ERR_INVALID_PARAMETER, "Updating textures is forbidden during creation of a raytracing list.");
Texture *texture = texture_owner.get_or_null(p_texture);
ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER);
@ -3187,6 +3439,9 @@ RID RenderingDevice::vertex_buffer_create(uint32_t p_size_bytes, Span<uint8_t> p
if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {
buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);
}
if (p_creation_bits.has_flag(BUFFER_CREATION_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT)) {
buffer.usage.set_flag(RDD::BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT);
}
buffer.driver_id = driver->buffer_create(buffer.size, buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU, frames_drawn);
ERR_FAIL_COND_V(!buffer.driver_id, RID());
@ -3389,9 +3644,15 @@ RID RenderingDevice::index_buffer_create(uint32_t p_index_count, IndexBufferForm
#endif
index_buffer.size = size_bytes;
index_buffer.usage = (RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT | RDD::BUFFER_USAGE_INDEX_BIT);
if (p_creation_bits.has_flag(BUFFER_CREATION_AS_STORAGE_BIT)) {
index_buffer.usage.set_flag(RDD::BUFFER_USAGE_STORAGE_BIT);
}
if (p_creation_bits.has_flag(BUFFER_CREATION_DEVICE_ADDRESS_BIT)) {
index_buffer.usage.set_flag(RDD::BUFFER_USAGE_DEVICE_ADDRESS_BIT);
}
if (p_creation_bits.has_flag(BUFFER_CREATION_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT)) {
index_buffer.usage.set_flag(RDD::BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT);
}
index_buffer.driver_id = driver->buffer_create(index_buffer.size, index_buffer.usage, RDD::MEMORY_ALLOCATION_TYPE_GPU, frames_drawn);
ERR_FAIL_COND_V(!index_buffer.driver_id, RID());
@ -3584,6 +3845,13 @@ RID RenderingDevice::shader_create_from_bytecode_with_samplers(const Vector<uint
case SHADER_STAGE_COMPUTE:
shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT);
break;
case SHADER_STAGE_RAYGEN:
case SHADER_STAGE_ANY_HIT:
case SHADER_STAGE_CLOSEST_HIT:
case SHADER_STAGE_MISS:
case SHADER_STAGE_INTERSECTION:
shader->stage_bits.set_flag(RDD::PIPELINE_STAGE_RAY_TRACING_SHADER_BIT);
break;
default:
DEV_ASSERT(false && "Unknown shader stage.");
break;
@ -4039,7 +4307,7 @@ RID RenderingDevice::uniform_set_create(const VectorView<RD::Uniform> &p_uniform
_check_transfer_worker_buffer(buffer);
} break;
case UNIFORM_TYPE_INPUT_ATTACHMENT: {
ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for compute shader (this is not allowed).");
ERR_FAIL_COND_V_MSG(shader->pipeline_type != PIPELINE_TYPE_RASTERIZATION, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for non-render shader (this is not allowed).");
if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
if (set_uniform.length > 1) {
@ -4065,6 +4333,22 @@ RID RenderingDevice::uniform_set_create(const VectorView<RD::Uniform> &p_uniform
_check_transfer_worker_texture(texture);
}
} break;
case UNIFORM_TYPE_ACCELERATION_STRUCTURE: {
ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),
"Acceleration structure supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
RID accel_id = uniform.get_id(0);
AccelerationStructure *accel = acceleration_structure_owner.get_or_null(accel_id);
ERR_FAIL_NULL_V_MSG(accel, RID(), "Acceleration Structure supplied (binding: " + itos(uniform.binding) + ") is invalid.");
if (accel->draw_tracker != nullptr) {
draw_trackers.push_back(accel->draw_tracker);
// Acceleration structure is never going to be writable from raytracing shaders
draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_ACCELERATION_STRUCTURE_READ);
}
driver_uniform.ids.push_back(accel->driver_id);
} break;
default: {
}
}
@ -4129,7 +4413,8 @@ RID RenderingDevice::render_pipeline_create(RID p_shader, FramebufferFormatID p_
// Needs a shader.
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_NULL_V(shader, RID());
ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "Compute shaders can't be used in render pipelines");
ERR_FAIL_COND_V_MSG(shader->pipeline_type != PIPELINE_TYPE_RASTERIZATION, RID(),
"Only render shaders can be used in render pipelines");
// Validate pre-raster shader. One of stages must be vertex shader or mesh shader (not implemented yet).
ERR_FAIL_COND_V_MSG(!shader->stage_bits.has_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT), RID(), "Pre-raster shader (vertex shader) is not provided for pipeline creation.");
@ -4322,7 +4607,7 @@ RID RenderingDevice::compute_pipeline_create(RID p_shader, const Vector<Pipeline
shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_NULL_V(shader, RID());
ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(),
ERR_FAIL_COND_V_MSG(shader->pipeline_type != PIPELINE_TYPE_COMPUTE, RID(),
"Non-compute shaders can't be used in compute pipelines");
}
@ -4375,6 +4660,57 @@ bool RenderingDevice::compute_pipeline_is_valid(RID p_pipeline) {
return compute_pipeline_owner.owns(p_pipeline);
}
RID RenderingDevice::raytracing_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
_THREAD_SAFE_METHOD_
// Needs a shader.
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_NULL_V(shader, RID());
ERR_FAIL_COND_V_MSG(shader->pipeline_type != PIPELINE_TYPE_RAYTRACING, RID(),
"Only raytracing shaders can be used in raytracing pipelines");
for (int i = 0; i < shader->specialization_constants.size(); i++) {
const ShaderSpecializationConstant &sc = shader->specialization_constants[i];
for (int j = 0; j < p_specialization_constants.size(); j++) {
const PipelineSpecializationConstant &psc = p_specialization_constants[j];
if (psc.constant_id == sc.constant_id) {
ERR_FAIL_COND_V_MSG(psc.type != sc.type, RID(), "Specialization constant provided for id (" + itos(sc.constant_id) + ") is of the wrong type.");
break;
}
}
}
RaytracingPipeline pipeline;
pipeline.driver_id = driver->raytracing_pipeline_create(shader->driver_id, p_specialization_constants);
ERR_FAIL_COND_V(!pipeline.driver_id, RID());
if (pipeline_cache_enabled) {
update_pipeline_cache();
}
pipeline.shader = p_shader;
pipeline.shader_driver_id = shader->driver_id;
pipeline.shader_layout_hash = shader->layout_hash;
pipeline.set_formats = shader->set_formats;
pipeline.push_constant_size = shader->push_constant_size;
// Create ID to associate with this pipeline.
RID id = raytracing_pipeline_owner.make_rid(pipeline);
#ifdef DEV_ENABLED
set_resource_name(id, "RID:" + itos(id.get_id()));
#endif
// Now add all the dependencies.
_add_dependency(id, p_shader);
return id;
}
bool RenderingDevice::raytracing_pipeline_is_valid(RID p_pipeline) {
_THREAD_SAFE_METHOD_
return raytracing_pipeline_owner.owns(p_pipeline);
}
/****************/
/**** SCREEN ****/
/****************/
@ -4520,6 +4856,7 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin_for_screen(DisplayS
ERR_FAIL_COND_V_MSG(draw_list.active, INVALID_ID, "Only one draw list can be active at the same time.");
ERR_FAIL_COND_V_MSG(compute_list.active, INVALID_ID, "Only one draw/compute list can be active at the same time.");
ERR_FAIL_COND_V_MSG(raytracing_list.active, INVALID_ID, "Only one draw/raytracing list can be active at the same time.");
RenderingContextDriver::SurfaceID surface = context->surface_get_from_window(p_screen);
HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator sc_it = screen_swap_chains.find(p_screen);
@ -5366,6 +5703,236 @@ void RenderingDevice::draw_list_end() {
draw_list_bound_textures.clear();
}
/***************************/
/**** RAYTRACING LISTS ****/
/**************************/
RenderingDevice::RaytracingListID RenderingDevice::raytracing_list_begin() {
ERR_RENDER_THREAD_GUARD_V(INVALID_ID);
ERR_FAIL_COND_V_MSG(!has_feature(SUPPORTS_RAYTRACING_PIPELINE), INVALID_ID, "The current rendering device has no raytracing pipeline support.");
ERR_FAIL_COND_V_MSG(draw_list.active, INVALID_ID, "Only one draw/raytracing list can be active at the same time.");
ERR_FAIL_COND_V_MSG(compute_list.active, INVALID_ID, "Only one compute/raytracing list can be active at the same time.");
ERR_FAIL_COND_V_MSG(raytracing_list.active, INVALID_ID, "Only one raytracing list can be active at the same time.");
raytracing_list.active = true;
draw_graph.add_raytracing_list_begin();
return ID_TYPE_RAYTRACING_LIST;
}
void RenderingDevice::raytracing_list_bind_raytracing_pipeline(RaytracingListID p_list, RID p_raytracing_pipeline) {
ERR_RENDER_THREAD_GUARD();
ERR_FAIL_COND(p_list != ID_TYPE_RAYTRACING_LIST);
ERR_FAIL_COND(!raytracing_list.active);
const RaytracingPipeline *pipeline = raytracing_pipeline_owner.get_or_null(p_raytracing_pipeline);
ERR_FAIL_NULL(pipeline);
if (p_raytracing_pipeline == raytracing_list.state.pipeline) {
return; // Redundant state, return.
}
raytracing_list.state.pipeline = p_raytracing_pipeline;
raytracing_list.state.pipeline_driver_id = pipeline->driver_id;
draw_graph.add_raytracing_list_bind_pipeline(pipeline->driver_id);
if (raytracing_list.state.pipeline_shader != pipeline->shader) {
// Shader changed, so descriptor sets may become incompatible.
uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.
raytracing_list.state.set_count = MAX(raytracing_list.state.set_count, pcount);
const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
uint32_t first_invalid_set = UINT32_MAX; // All valid by default.
switch (driver->api_trait_get(RDD::API_TRAIT_SHADER_CHANGE_INVALIDATION)) {
case RDD::SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS: {
first_invalid_set = 0;
} break;
case RDD::SHADER_CHANGE_INVALIDATION_INCOMPATIBLE_SETS_PLUS_CASCADE: {
for (uint32_t i = 0; i < pcount; i++) {
if (raytracing_list.state.sets[i].pipeline_expected_format != pformats[i]) {
first_invalid_set = i;
break;
}
}
} break;
case RDD::SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH: {
if (raytracing_list.state.pipeline_shader_layout_hash != pipeline->shader_layout_hash) {
first_invalid_set = 0;
}
} break;
}
for (uint32_t i = 0; i < pcount; i++) {
raytracing_list.state.sets[i].bound = raytracing_list.state.sets[i].bound && i < first_invalid_set;
raytracing_list.state.sets[i].pipeline_expected_format = pformats[i];
}
for (uint32_t i = pcount; i < raytracing_list.state.set_count; i++) {
// Unbind the ones above (not used) if exist.
raytracing_list.state.sets[i].bound = false;
}
raytracing_list.state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
#ifdef DEBUG_ENABLED
raytracing_list.validation.pipeline_push_constant_supplied = false;
#endif
}
raytracing_list.state.pipeline_shader = pipeline->shader;
raytracing_list.state.pipeline_shader_driver_id = pipeline->shader_driver_id;
raytracing_list.state.pipeline_shader_layout_hash = pipeline->shader_layout_hash;
}
#ifdef DEBUG_ENABLED
// Update raytracing pass pipeline info.
raytracing_list.validation.pipeline_active = true;
raytracing_list.validation.pipeline_push_constant_size = pipeline->push_constant_size;
#endif
}
void RenderingDevice::raytracing_list_bind_uniform_set(RaytracingListID p_list, RID p_uniform_set, uint32_t p_index) {
ERR_RENDER_THREAD_GUARD();
ERR_FAIL_COND(p_list != ID_TYPE_RAYTRACING_LIST);
ERR_FAIL_COND(!raytracing_list.active);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(p_index >= driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS) || p_index >= MAX_UNIFORM_SETS,
"Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(driver->limit_get(LIMIT_MAX_BOUND_UNIFORM_SETS)) + ").");
#endif
UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
ERR_FAIL_NULL(uniform_set);
if (p_index > raytracing_list.state.set_count) {
raytracing_list.state.set_count = p_index;
}
raytracing_list.state.sets[p_index].uniform_set_driver_id = uniform_set->driver_id; // Update set pointer.
raytracing_list.state.sets[p_index].bound = false; // Needs rebind.
raytracing_list.state.sets[p_index].uniform_set_format = uniform_set->format;
raytracing_list.state.sets[p_index].uniform_set = p_uniform_set;
}
void RenderingDevice::raytracing_list_set_push_constant(RaytracingListID p_list, const void *p_data, uint32_t p_data_size) {
ERR_RENDER_THREAD_GUARD();
ERR_FAIL_COND(p_list != ID_TYPE_RAYTRACING_LIST);
ERR_FAIL_COND(!raytracing_list.active);
ERR_FAIL_COND_MSG(p_data_size > MAX_PUSH_CONSTANT_SIZE, "Push constants can't be bigger than 128 bytes to maintain compatibility.");
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(p_data_size != raytracing_list.validation.pipeline_push_constant_size,
"This raytracing pipeline requires (" + itos(raytracing_list.validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");
#endif
draw_graph.add_raytracing_list_set_push_constant(raytracing_list.state.pipeline_shader_driver_id, p_data, p_data_size);
// Store it in the state in case we need to restart the raytracing list.
memcpy(raytracing_list.state.push_constant_data, p_data, p_data_size);
raytracing_list.state.push_constant_size = p_data_size;
#ifdef DEBUG_ENABLED
raytracing_list.validation.pipeline_push_constant_supplied = true;
#endif
}
void RenderingDevice::raytracing_list_trace_rays(RaytracingListID p_list, uint32_t p_width, uint32_t p_height) {
ERR_RENDER_THREAD_GUARD();
ERR_FAIL_COND(p_list != ID_TYPE_RAYTRACING_LIST);
ERR_FAIL_COND(!raytracing_list.active);
#ifdef DEBUG_ENABLED
ERR_FAIL_NULL_MSG(shader_owner.get_or_null(raytracing_list.state.pipeline_shader), "No shader was set before attempting to trace rays.");
ERR_FAIL_NULL_MSG(raytracing_pipeline_owner.get_or_null(raytracing_list.state.pipeline), "No raytracing pipeline was set before attempting to trace rays.");
#endif
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!raytracing_list.validation.pipeline_active, "No raytracing pipeline was set before attempting to draw.");
if (raytracing_list.validation.pipeline_push_constant_size > 0) {
// Using push constants, check that they were supplied.
ERR_FAIL_COND_MSG(!raytracing_list.validation.pipeline_push_constant_supplied,
"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
}
#endif
#ifdef DEBUG_ENABLED
for (uint32_t i = 0; i < raytracing_list.state.set_count; i++) {
if (raytracing_list.state.sets[i].pipeline_expected_format == 0) {
// Nothing expected by this pipeline.
continue;
}
if (raytracing_list.state.sets[i].pipeline_expected_format != raytracing_list.state.sets[i].uniform_set_format) {
if (raytracing_list.state.sets[i].uniform_set_format == 0) {
ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");
} else if (uniform_set_owner.owns(raytracing_list.state.sets[i].uniform_set)) {
UniformSet *us = uniform_set_owner.get_or_null(raytracing_list.state.sets[i].uniform_set);
ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(raytracing_list.state.pipeline_shader));
} else {
ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(raytracing_list.state.pipeline_shader));
}
}
}
#endif
// Prepare descriptor sets if the API doesn't use pipeline barriers.
if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
for (uint32_t i = 0; i < raytracing_list.state.set_count; i++) {
if (raytracing_list.state.sets[i].pipeline_expected_format == 0) {
// Nothing expected by this pipeline.
continue;
}
draw_graph.add_raytracing_list_uniform_set_prepare_for_use(raytracing_list.state.pipeline_shader_driver_id, raytracing_list.state.sets[i].uniform_set_driver_id, i);
}
}
// Bind descriptor sets.
for (uint32_t i = 0; i < raytracing_list.state.set_count; i++) {
if (raytracing_list.state.sets[i].pipeline_expected_format == 0) {
continue; // Nothing expected by this pipeline.
}
if (!raytracing_list.state.sets[i].bound) {
// All good, see if this requires re-binding.
draw_graph.add_raytracing_list_bind_uniform_set(raytracing_list.state.pipeline_shader_driver_id, raytracing_list.state.sets[i].uniform_set_driver_id, i);
UniformSet *uniform_set = uniform_set_owner.get_or_null(raytracing_list.state.sets[i].uniform_set);
_uniform_set_update_shared(uniform_set);
draw_graph.add_raytracing_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
raytracing_list.state.sets[i].bound = true;
}
}
draw_graph.add_raytracing_list_trace_rays(p_width, p_height);
raytracing_list.state.trace_count++;
}
void RenderingDevice::raytracing_list_end() {
ERR_RENDER_THREAD_GUARD();
ERR_FAIL_COND(!raytracing_list.active);
draw_graph.add_raytracing_list_end();
raytracing_list = RaytracingList();
}
/***********************/
/**** COMPUTE LISTS ****/
/***********************/
@ -5373,7 +5940,8 @@ void RenderingDevice::draw_list_end() {
RenderingDevice::ComputeListID RenderingDevice::compute_list_begin() {
ERR_RENDER_THREAD_GUARD_V(INVALID_ID);
ERR_FAIL_COND_V_MSG(compute_list.active, INVALID_ID, "Only one draw/compute list can be active at the same time.");
ERR_FAIL_COND_V_MSG(compute_list.active, INVALID_ID, "Only one compute list can be active at the same time.");
ERR_FAIL_COND_V_MSG(raytracing_list.active, INVALID_ID, "Only one raytracing list can be active at the same time.");
compute_list.active = true;
@ -6101,7 +6669,7 @@ void RenderingDevice::_submit_transfer_workers(RDD::CommandBufferID p_draw_comma
void RenderingDevice::_submit_transfer_barriers(RDD::CommandBufferID p_draw_command_buffer) {
MutexLock transfer_worker_lock(transfer_worker_pool_texture_barriers_mutex);
if (!transfer_worker_pool_texture_barriers.is_empty()) {
driver->command_pipeline_barrier(p_draw_command_buffer, RDD::PIPELINE_STAGE_COPY_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, {}, {}, transfer_worker_pool_texture_barriers);
driver->command_pipeline_barrier(p_draw_command_buffer, RDD::PIPELINE_STAGE_COPY_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, {}, {}, transfer_worker_pool_texture_barriers, {});
transfer_worker_pool_texture_barriers.clear();
}
}
@ -6400,6 +6968,13 @@ void RenderingDevice::_free_internal(RID p_id) {
RDG::resource_tracker_free(storage_buffer->draw_tracker);
frames[frame].buffers_to_dispose_of.push_back(*storage_buffer);
storage_buffer_owner.free(p_id);
} else if (instances_buffer_owner.owns(p_id)) {
InstancesBuffer *instances_buffer = instances_buffer_owner.get_or_null(p_id);
_check_transfer_worker_buffer(&instances_buffer->buffer);
RDG::resource_tracker_free(instances_buffer->buffer.draw_tracker);
frames[frame].buffers_to_dispose_of.push_back(instances_buffer->buffer);
instances_buffer_owner.free(p_id);
} else if (uniform_set_owner.owns(p_id)) {
UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);
frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set);
@ -6416,6 +6991,14 @@ void RenderingDevice::_free_internal(RID p_id) {
ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);
frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline);
compute_pipeline_owner.free(p_id);
} else if (acceleration_structure_owner.owns(p_id)) {
AccelerationStructure *acceleration_structure = acceleration_structure_owner.get_or_null(p_id);
frames[frame].acceleration_structures_to_dispose_of.push_back(*acceleration_structure);
acceleration_structure_owner.free(p_id);
} else if (raytracing_pipeline_owner.owns(p_id)) {
RaytracingPipeline *pipeline = raytracing_pipeline_owner.get_or_null(p_id);
frames[frame].raytracing_pipelines_to_dispose_of.push_back(*pipeline);
raytracing_pipeline_owner.free(p_id);
} else {
#ifdef DEV_ENABLED
ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name);
@ -6459,6 +7042,9 @@ void RenderingDevice::set_resource_name(RID p_id, const String &p_name) {
} else if (storage_buffer_owner.owns(p_id)) {
Buffer *storage_buffer = storage_buffer_owner.get_or_null(p_id);
driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, storage_buffer->driver_id, p_name);
} else if (instances_buffer_owner.owns(p_id)) {
InstancesBuffer *instances_buffer = instances_buffer_owner.get_or_null(p_id);
driver->set_object_name(RDD::OBJECT_TYPE_BUFFER, instances_buffer->buffer.driver_id, p_name);
} else if (uniform_set_owner.owns(p_id)) {
UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id);
driver->set_object_name(RDD::OBJECT_TYPE_UNIFORM_SET, uniform_set->driver_id, p_name);
@ -6468,6 +7054,12 @@ void RenderingDevice::set_resource_name(RID p_id, const String &p_name) {
} else if (compute_pipeline_owner.owns(p_id)) {
ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id);
driver->set_object_name(RDD::OBJECT_TYPE_PIPELINE, pipeline->driver_id, p_name);
} else if (acceleration_structure_owner.owns(p_id)) {
AccelerationStructure *acceleration_structure = acceleration_structure_owner.get_or_null(p_id);
driver->set_object_name(RDD::OBJECT_TYPE_ACCELERATION_STRUCTURE, acceleration_structure->driver_id, p_name);
} else if (raytracing_pipeline_owner.owns(p_id)) {
RaytracingPipeline *pipeline = raytracing_pipeline_owner.get_or_null(p_id);
driver->set_object_name(RDD::OBJECT_TYPE_RAYTRACING_PIPELINE, pipeline->driver_id, p_name);
} else {
ERR_PRINT("Attempted to name invalid ID: " + itos(p_id.get_id()));
return;
@ -6585,6 +7177,26 @@ void RenderingDevice::_free_pending_resources(int p_frame) {
frames[p_frame].compute_pipelines_to_dispose_of.pop_front();
}
while (frames[p_frame].raytracing_pipelines_to_dispose_of.front()) {
RaytracingPipeline *pipeline = &frames[p_frame].raytracing_pipelines_to_dispose_of.front()->get();
driver->raytracing_pipeline_free(pipeline->driver_id);
frames[p_frame].raytracing_pipelines_to_dispose_of.pop_front();
}
// Acceleration structures.
while (frames[p_frame].acceleration_structures_to_dispose_of.front()) {
AccelerationStructure &acceleration_structure = frames[p_frame].acceleration_structures_to_dispose_of.front()->get();
if (acceleration_structure.scratch_buffer != RID()) {
free_rid(acceleration_structure.scratch_buffer);
}
driver->acceleration_structure_free(acceleration_structure.driver_id);
frames[p_frame].acceleration_structures_to_dispose_of.pop_front();
}
// Uniform sets.
while (frames[p_frame].uniform_sets_to_dispose_of.front()) {
UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get();
@ -6733,6 +7345,10 @@ void RenderingDevice::_end_frame() {
ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work).");
}
if (raytracing_list.active) {
ERR_PRINT("Found open raytracing list at the end of the frame, this should never happen (further raytracing will likely not work).");
}
// The command buffer must be copied into a stack variable as the driver workarounds can change the command buffer in use.
RDD::CommandBufferID command_buffer = frames[frame].command_buffer;
GodotProfileZoneGroupedFirst(_profile_zone, "_submit_transfer_workers");
@ -7187,6 +7803,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
draw_list = DrawList();
compute_list = ComputeList();
raytracing_list = RaytracingList();
bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable");
if (is_main_instance && project_pipeline_cache_enable) {
@ -7312,6 +7929,7 @@ void RenderingDevice::capture_timestamp(const String &p_name) {
ERR_FAIL_COND_MSG(draw_list.active && draw_list.state.draw_count > 0, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name);
ERR_FAIL_COND_MSG(compute_list.active && compute_list.state.dispatch_count > 0, "Capturing timestamps during compute list creation is not allowed. Offending timestamp was: " + p_name);
ERR_FAIL_COND_MSG(raytracing_list.active && raytracing_list.state.trace_count > 0, "Capturing timestamps during raytracing list creation is not allowed. Offending timestamp was: " + p_name);
ERR_FAIL_COND_MSG(frames[frame].timestamp_count >= max_timestamp_query_elements, vformat("Tried capturing more timestamps than the configured maximum (%d). You can increase this limit in the project settings under 'Debug/Settings' called 'Max Timestamp Query Elements'.", max_timestamp_query_elements));
draw_graph.add_capture_timestamp(frames[frame].timestamp_pool, frames[frame].timestamp_count);
@ -7368,6 +7986,8 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r
buffer = texture_buffer_owner.get_or_null(p_rid);
} else if (storage_buffer_owner.owns(p_rid)) {
buffer = storage_buffer_owner.get_or_null(p_rid);
} else if (instances_buffer_owner.owns(p_rid)) {
buffer = &instances_buffer_owner.get_or_null(p_rid)->buffer;
}
ERR_FAIL_NULL_V(buffer, 0);
@ -7489,6 +8109,7 @@ void RenderingDevice::finalize() {
_free_rids(uniform_set_owner, "UniformSet");
_free_rids(texture_buffer_owner, "TextureBuffer");
_free_rids(storage_buffer_owner, "StorageBuffer");
_free_rids(instances_buffer_owner, "InstancesBuffer");
_free_rids(uniform_buffer_owner, "UniformBuffer");
_free_rids(shader_owner, "Shader");
_free_rids(index_array_owner, "IndexArray");
@ -7731,6 +8352,15 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader", "specialization_constants"), &RenderingDevice::_compute_pipeline_create, DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));
ClassDB::bind_method(D_METHOD("compute_pipeline_is_valid", "compute_pipeline"), &RenderingDevice::compute_pipeline_is_valid);
ClassDB::bind_method(D_METHOD("raytracing_pipeline_create", "shader", "specialization_constants"), &RenderingDevice::_raytracing_pipeline_create, DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));
ClassDB::bind_method(D_METHOD("raytracing_pipeline_is_valid", "raytracing_pipeline"), &RenderingDevice::raytracing_pipeline_is_valid);
ClassDB::bind_method(D_METHOD("blas_create", "vertex_array", "index_array", "geometry_bits", "position_attribute_location"), &RenderingDevice::blas_create, DEFVAL(0), DEFVAL(0));
ClassDB::bind_method(D_METHOD("tlas_instances_buffer_create", "instance_count", "creation_bits"), &RenderingDevice::tlas_instances_buffer_create, DEFVAL(0));
ClassDB::bind_method(D_METHOD("tlas_instances_buffer_fill", "instances_buffer", "blases", "transforms"), &RenderingDevice::_tlas_instances_buffer_fill);
ClassDB::bind_method(D_METHOD("tlas_create", "instances_buffer"), &RenderingDevice::tlas_create);
ClassDB::bind_method(D_METHOD("acceleration_structure_build", "acceleration_structure"), &RenderingDevice::acceleration_structure_build);
ClassDB::bind_method(D_METHOD("screen_get_width", "screen"), &RenderingDevice::screen_get_width, DEFVAL(DisplayServer::MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("screen_get_height", "screen"), &RenderingDevice::screen_get_height, DEFVAL(DisplayServer::MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("screen_get_framebuffer_format", "screen"), &RenderingDevice::screen_get_framebuffer_format, DEFVAL(DisplayServer::MAIN_WINDOW_ID));
@ -7772,6 +8402,13 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier);
ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end);
ClassDB::bind_method(D_METHOD("raytracing_list_begin"), &RenderingDevice::raytracing_list_begin);
ClassDB::bind_method(D_METHOD("raytracing_list_bind_raytracing_pipeline", "raytracing_list", "raytracing_pipeline"), &RenderingDevice::raytracing_list_bind_raytracing_pipeline);
ClassDB::bind_method(D_METHOD("raytracing_list_set_push_constant", "raytracing_list", "buffer", "size_bytes"), &RenderingDevice::_raytracing_list_set_push_constant);
ClassDB::bind_method(D_METHOD("raytracing_list_bind_uniform_set", "raytracing_list", "uniform_set", "set_index"), &RenderingDevice::raytracing_list_bind_uniform_set);
ClassDB::bind_method(D_METHOD("raytracing_list_trace_rays", "raytracing_list", "width", "height"), &RenderingDevice::raytracing_list_trace_rays);
ClassDB::bind_method(D_METHOD("raytracing_list_end"), &RenderingDevice::raytracing_list_end);
ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingDevice::free_rid);
ClassDB::bind_method(D_METHOD("capture_timestamp", "name"), &RenderingDevice::capture_timestamp);
@ -8176,6 +8813,10 @@ void RenderingDevice::_bind_methods() {
BIND_BITFIELD_FLAG(BUFFER_CREATION_AS_STORAGE_BIT);
// Not exposed on purpose. This flag is too dangerous to be exposed to regular GD users.
//BIND_BITFIELD_FLAG(BUFFER_CREATION_DYNAMIC_PERSISTENT_BIT);
BIND_BITFIELD_FLAG(BUFFER_CREATION_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT);
BIND_BITFIELD_FLAG(ACCELERATION_STRUCTURE_GEOMETRY_OPAQUE);
BIND_BITFIELD_FLAG(ACCELERATION_STRUCTURE_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION);
BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER); //for sampling only (sampler GLSL type)
BIND_ENUM_CONSTANT(UNIFORM_TYPE_SAMPLER_WITH_TEXTURE); // for sampling only); but includes a texture); (samplerXX GLSL type)); first a sampler then a texture
@ -8189,6 +8830,7 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(UNIFORM_TYPE_INPUT_ATTACHMENT); //used for sub-pass read/write); for mobile mostly
BIND_ENUM_CONSTANT(UNIFORM_TYPE_UNIFORM_BUFFER_DYNAMIC); // Exposed in case a BUFFER_CREATION_DYNAMIC_PERSISTENT_BIT buffer created by C++ makes it into GD users.
BIND_ENUM_CONSTANT(UNIFORM_TYPE_STORAGE_BUFFER_DYNAMIC); // Exposed in case a BUFFER_CREATION_DYNAMIC_PERSISTENT_BIT buffer created by C++ makes it into GD users.
BIND_ENUM_CONSTANT(UNIFORM_TYPE_ACCELERATION_STRUCTURE); //acceleration structure (TLAS)); for raytracing
BIND_ENUM_CONSTANT(UNIFORM_TYPE_MAX);
BIND_ENUM_CONSTANT(RENDER_PRIMITIVE_POINTS);
@ -8308,12 +8950,22 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_CONTROL);
BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_EVALUATION);
BIND_ENUM_CONSTANT(SHADER_STAGE_COMPUTE);
BIND_ENUM_CONSTANT(SHADER_STAGE_RAYGEN);
BIND_ENUM_CONSTANT(SHADER_STAGE_ANY_HIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_CLOSEST_HIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_MISS);
BIND_ENUM_CONSTANT(SHADER_STAGE_INTERSECTION);
BIND_ENUM_CONSTANT(SHADER_STAGE_MAX);
BIND_ENUM_CONSTANT(SHADER_STAGE_VERTEX_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_FRAGMENT_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_CONTROL_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_TESSELATION_EVALUATION_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_COMPUTE_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_RAYGEN_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_ANY_HIT_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_CLOSEST_HIT_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_MISS_BIT);
BIND_ENUM_CONSTANT(SHADER_STAGE_INTERSECTION_BIT);
BIND_ENUM_CONSTANT(SHADER_LANGUAGE_GLSL);
BIND_ENUM_CONSTANT(SHADER_LANGUAGE_HLSL);
@ -8326,6 +8978,8 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(SUPPORTS_METALFX_TEMPORAL);
BIND_ENUM_CONSTANT(SUPPORTS_BUFFER_DEVICE_ADDRESS);
BIND_ENUM_CONSTANT(SUPPORTS_IMAGE_ATOMIC_32_BIT);
BIND_ENUM_CONSTANT(SUPPORTS_RAY_QUERY);
BIND_ENUM_CONSTANT(SUPPORTS_RAYTRACING_PIPELINE);
BIND_ENUM_CONSTANT(LIMIT_MAX_BOUND_UNIFORM_SETS);
BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS);
@ -8637,6 +9291,16 @@ Error RenderingDevice::_buffer_update_bind(RID p_buffer, uint32_t p_offset, uint
return buffer_update(p_buffer, p_offset, p_size, p_data.ptr());
}
void RenderingDevice::_tlas_instances_buffer_fill(RID p_instances_buffer, const TypedArray<RID> &p_blases, const TypedArray<Transform3D> &p_transforms) {
Vector<RID> blases = Variant(p_blases);
Vector<Transform3D> transforms;
transforms.resize(p_transforms.size());
for (int i = 0; i < p_transforms.size(); i++) {
transforms.write[i] = p_transforms[i];
}
tlas_instances_buffer_fill(p_instances_buffer, blases, transforms);
}
static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {
Vector<RenderingDevice::PipelineSpecializationConstant> ret;
ret.resize(p_constants.size());
@ -8705,6 +9369,10 @@ RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDP
return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));
}
RID RenderingDevice::_raytracing_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) {
return raytracing_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));
}
#ifndef DISABLE_DEPRECATED
Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
ERR_FAIL_V_MSG(Vector<int64_t>(), "Deprecated. Split draw lists are used automatically by RenderingDevice.");
@ -8725,6 +9393,11 @@ void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, cons
compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
}
void RenderingDevice::_raytracing_list_set_push_constant(RaytracingListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size());
raytracing_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
}
static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_NONE, RDG::RESOURCE_USAGE_NONE));
static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_COPY_FROM, RDG::RESOURCE_USAGE_COPY_FROM));
static_assert(ENUM_MEMBERS_EQUAL(RD::CALLBACK_RESOURCE_USAGE_COPY_TO, RDG::RESOURCE_USAGE_COPY_TO));