Merge pull request #91769 from DarioSamo/d3d12_enhanced_barriers

Add support for enhanced barriers in D3D12.
This commit is contained in:
Rémi Verschelde 2024-05-31 14:15:49 +02:00
commit f2796fa06d
No known key found for this signature in database
GPG Key ID: C3336907360768E1
10 changed files with 1208 additions and 457 deletions

File diff suppressed because it is too large Load Diff

View File

@ -122,6 +122,10 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
bool relaxed_casting_supported = false;
};
struct BarrierCapabilities {
bool enhanced_barriers_supported = false;
};
RenderingContextDriverD3D12 *context_driver = nullptr;
RenderingContextDriver::Device context_device;
ComPtr<IDXGIAdapter> adapter;
@ -136,6 +140,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
ShaderCapabilities shader_capabilities;
StorageBufferCapabilities storage_buffer_capabilities;
FormatCapabilities format_capabilities;
BarrierCapabilities barrier_capabilities;
String pipeline_cache_id;
class DescriptorsHeap {
@ -218,11 +223,6 @@ private:
// As many subresources as mipmaps * layers; planes (for depth-stencil) are tracked together.
TightLocalVector<D3D12_RESOURCE_STATES> subresource_states; // Used only if not a view.
uint32_t last_batch_with_uav_barrier = 0;
struct CrossFamillyFallback {
TightLocalVector<uint64_t> subresources_dirty;
ComPtr<ID3D12Resource> interim_buffer;
ComPtr<D3D12MA::Allocation> interim_buffer_alloc;
} xfamily_fallback; // [[CROSS_FAMILY_FALLBACK]].
};
ID3D12Resource *resource = nullptr; // Non-null even if not owned.
@ -275,7 +275,6 @@ private:
uint64_t size = 0;
struct {
bool usable_as_uav : 1;
bool is_for_upload : 1;
} flags = {};
};
@ -317,10 +316,14 @@ private:
UINT _compute_component_mapping(const TextureView &p_view);
UINT _compute_plane_slice(DataFormat p_format, BitField<TextureAspectBits> p_aspect_bits);
UINT _compute_plane_slice(DataFormat p_format, TextureAspect p_aspect);
UINT _compute_subresource_from_layers(TextureInfo *p_texture, const TextureSubresourceLayers &p_layers, uint32_t p_layer_offset);
struct CommandBufferInfo;
void _discard_texture_subresources(const TextureInfo *p_tex_info, const CommandBufferInfo *p_cmd_buf_info);
protected:
virtual bool _unordered_access_supported_by_format(DataFormat p_format);
public:
virtual TextureID texture_create(const TextureFormat &p_format, const TextureView &p_view) override final;
virtual TextureID texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil) override final;
@ -332,6 +335,7 @@ public:
virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) override final;
virtual void texture_unmap(TextureID p_texture) override final;
virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final;
virtual bool texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) override final;
private:
TextureID _texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps);
@ -367,8 +371,8 @@ public:
virtual void command_pipeline_barrier(
CommandBufferID p_cmd_buffer,
BitField<RDD::PipelineStageBits> p_src_stages,
BitField<RDD::PipelineStageBits> p_dst_stages,
BitField<PipelineStageBits> p_src_stages,
BitField<PipelineStageBits> p_dst_stages,
VectorView<RDD::MemoryBarrier> p_memory_barriers,
VectorView<RDD::BufferBarrier> p_buffer_barriers,
VectorView<RDD::TextureBarrier> p_texture_barriers) override final;
@ -465,16 +469,6 @@ private:
RenderPassState render_pass_state;
bool descriptor_heaps_set = false;
// [[CROSS_FAMILY_FALLBACK]].
struct FamilyFallbackCopy {
TextureInfo *texture = nullptr;
uint32_t subresource = 0;
uint32_t mipmap = 0;
D3D12_RESOURCE_STATES dst_wanted_state = {};
};
LocalVector<FamilyFallbackCopy> family_fallback_copies;
uint32_t family_fallback_copy_count = 0;
};
public:
@ -961,7 +955,6 @@ private:
bool rtv = false;
} desc_heaps_exhausted_reported;
CD3DX12_CPU_DESCRIPTOR_HANDLE null_rtv_handle = {}; // For [[MANUAL_SUBPASSES]].
ComPtr<D3D12MA::Allocation> aux_resource;
uint32_t segment_serial = 0;
#ifdef DEV_ENABLED

View File

@ -264,6 +264,63 @@ static const VkFormat RD_TO_VK_FORMAT[RDD::DATA_FORMAT_MAX] = {
VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
};
static VkImageLayout RD_TO_VK_LAYOUT[RDD::TEXTURE_LAYOUT_MAX] = {
VK_IMAGE_LAYOUT_UNDEFINED, // TEXTURE_LAYOUT_UNDEFINED
VK_IMAGE_LAYOUT_GENERAL, // TEXTURE_LAYOUT_STORAGE_OPTIMAL
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, // TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TEXTURE_LAYOUT_COPY_SRC_OPTIMAL
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TEXTURE_LAYOUT_COPY_DST_OPTIMAL
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL
VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL
};
static VkPipelineStageFlags _rd_to_vk_pipeline_stages(BitField<RDD::PipelineStageBits> p_stages) {
VkPipelineStageFlags vk_flags = 0;
if (p_stages.has_flag(RDD::PIPELINE_STAGE_COPY_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_RESOLVE_BIT)) {
// Transfer has been split into copy and resolve bits. Clear them and merge them into one bit.
vk_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
p_stages.clear_flag(RDD::PIPELINE_STAGE_COPY_BIT);
p_stages.clear_flag(RDD::PIPELINE_STAGE_RESOLVE_BIT);
}
if (p_stages.has_flag(RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT)) {
// Vulkan should never use this as API_TRAIT_CLEAR_RESOURCES_WITH_VIEWS is not specified.
// Therefore, storage is never cleared with an explicit command.
p_stages.clear_flag(RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT);
}
// The rest of the flags have compatible numeric values with Vulkan.
return VkPipelineStageFlags(p_stages) | vk_flags;
}
static VkAccessFlags _rd_to_vk_access_flags(BitField<RDD::BarrierAccessBits> p_access) {
VkAccessFlags vk_flags = 0;
if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_READ_BIT) || p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_READ_BIT)) {
vk_flags |= VK_ACCESS_TRANSFER_READ_BIT;
p_access.clear_flag(RDD::BARRIER_ACCESS_COPY_READ_BIT);
p_access.clear_flag(RDD::BARRIER_ACCESS_RESOLVE_READ_BIT);
}
if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_WRITE_BIT) || p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT)) {
vk_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
p_access.clear_flag(RDD::BARRIER_ACCESS_COPY_WRITE_BIT);
p_access.clear_flag(RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT);
}
if (p_access.has_flag(RDD::BARRIER_ACCESS_STORAGE_CLEAR_BIT)) {
// Vulkan should never use this as API_TRAIT_CLEAR_RESOURCES_WITH_VIEWS is not specified.
// Therefore, storage is never cleared with an explicit command.
p_access.clear_flag(RDD::BARRIER_ACCESS_STORAGE_CLEAR_BIT);
}
// The rest of the flags have compatible numeric values with Vulkan.
return VkAccessFlags(p_access) | vk_flags;
}
// RDD::CompareOperator == VkCompareOp.
static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_NEVER, VK_COMPARE_OP_NEVER));
static_assert(ENUM_MEMBERS_EQUAL(RDD::COMPARE_OP_LESS, VK_COMPARE_OP_LESS));
@ -1334,18 +1391,6 @@ static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G)
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_B, VK_COMPONENT_SWIZZLE_B));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A));
// RDD::TextureLayout == VkImageLayout.
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_PREINITIALIZED));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR));
// RDD::TextureAspectBits == VkImageAspectFlagBits.
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::TEXTURE_ASPECT_DEPTH_BIT, VK_IMAGE_ASPECT_DEPTH_BIT));
@ -1774,6 +1819,11 @@ BitField<RDD::TextureUsageBits> RenderingDeviceDriverVulkan::texture_get_usages_
return supported;
}
bool RenderingDeviceDriverVulkan::texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) {
r_raw_reinterpretation = false;
return true;
}
/*****************/
/**** SAMPLER ****/
/*****************/
@ -1893,7 +1943,6 @@ static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, V
static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
@ -1910,8 +1959,6 @@ static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT,
static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_HOST_READ_BIT, VK_ACCESS_HOST_READ_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_HOST_WRITE_BIT, VK_ACCESS_HOST_WRITE_BIT));
static_assert(ENUM_MEMBERS_EQUAL(RDD::BARRIER_ACCESS_MEMORY_READ_BIT, VK_ACCESS_MEMORY_READ_BIT));
@ -1929,8 +1976,8 @@ void RenderingDeviceDriverVulkan::command_pipeline_barrier(
for (uint32_t i = 0; i < p_memory_barriers.size(); i++) {
vk_memory_barriers[i] = {};
vk_memory_barriers[i].sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
vk_memory_barriers[i].srcAccessMask = (VkPipelineStageFlags)p_memory_barriers[i].src_access;
vk_memory_barriers[i].dstAccessMask = (VkAccessFlags)p_memory_barriers[i].dst_access;
vk_memory_barriers[i].srcAccessMask = _rd_to_vk_access_flags(p_memory_barriers[i].src_access);
vk_memory_barriers[i].dstAccessMask = _rd_to_vk_access_flags(p_memory_barriers[i].dst_access);
}
VkBufferMemoryBarrier *vk_buffer_barriers = ALLOCA_ARRAY(VkBufferMemoryBarrier, p_buffer_barriers.size());
@ -1939,8 +1986,8 @@ void RenderingDeviceDriverVulkan::command_pipeline_barrier(
vk_buffer_barriers[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
vk_buffer_barriers[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vk_buffer_barriers[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vk_buffer_barriers[i].srcAccessMask = (VkAccessFlags)p_buffer_barriers[i].src_access;
vk_buffer_barriers[i].dstAccessMask = (VkAccessFlags)p_buffer_barriers[i].dst_access;
vk_buffer_barriers[i].srcAccessMask = _rd_to_vk_access_flags(p_buffer_barriers[i].src_access);
vk_buffer_barriers[i].dstAccessMask = _rd_to_vk_access_flags(p_buffer_barriers[i].dst_access);
vk_buffer_barriers[i].buffer = ((const BufferInfo *)p_buffer_barriers[i].buffer.id)->vk_buffer;
vk_buffer_barriers[i].offset = p_buffer_barriers[i].offset;
vk_buffer_barriers[i].size = p_buffer_barriers[i].size;
@ -1951,10 +1998,10 @@ void RenderingDeviceDriverVulkan::command_pipeline_barrier(
const TextureInfo *tex_info = (const TextureInfo *)p_texture_barriers[i].texture.id;
vk_image_barriers[i] = {};
vk_image_barriers[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
vk_image_barriers[i].srcAccessMask = (VkAccessFlags)p_texture_barriers[i].src_access;
vk_image_barriers[i].dstAccessMask = (VkAccessFlags)p_texture_barriers[i].dst_access;
vk_image_barriers[i].oldLayout = (VkImageLayout)p_texture_barriers[i].prev_layout;
vk_image_barriers[i].newLayout = (VkImageLayout)p_texture_barriers[i].next_layout;
vk_image_barriers[i].srcAccessMask = _rd_to_vk_access_flags(p_texture_barriers[i].src_access);
vk_image_barriers[i].dstAccessMask = _rd_to_vk_access_flags(p_texture_barriers[i].dst_access);
vk_image_barriers[i].oldLayout = RD_TO_VK_LAYOUT[p_texture_barriers[i].prev_layout];
vk_image_barriers[i].newLayout = RD_TO_VK_LAYOUT[p_texture_barriers[i].next_layout];
vk_image_barriers[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vk_image_barriers[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vk_image_barriers[i].image = tex_info->vk_view_create_info.image;
@ -1984,8 +2031,8 @@ void RenderingDeviceDriverVulkan::command_pipeline_barrier(
vkCmdPipelineBarrier(
(VkCommandBuffer)p_cmd_buffer.id,
(VkPipelineStageFlags)p_src_stages,
(VkPipelineStageFlags)p_dst_stages,
_rd_to_vk_pipeline_stages(p_src_stages),
_rd_to_vk_pipeline_stages(p_dst_stages),
0,
p_memory_barriers.size(), vk_memory_barriers,
p_buffer_barriers.size(), vk_buffer_barriers,
@ -3727,7 +3774,7 @@ void RenderingDeviceDriverVulkan::command_copy_texture(CommandBufferID p_cmd_buf
const TextureInfo *src_tex_info = (const TextureInfo *)p_src_texture.id;
const TextureInfo *dst_tex_info = (const TextureInfo *)p_dst_texture.id;
vkCmdCopyImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, dst_tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, p_regions.size(), vk_copy_regions);
vkCmdCopyImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_src_texture_layout], dst_tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_dst_texture_layout], p_regions.size(), vk_copy_regions);
}
void RenderingDeviceDriverVulkan::command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {
@ -3747,7 +3794,7 @@ void RenderingDeviceDriverVulkan::command_resolve_texture(CommandBufferID p_cmd_
vk_resolve.extent.height = MAX(1u, src_tex_info->vk_create_info.extent.height >> p_src_mipmap);
vk_resolve.extent.depth = MAX(1u, src_tex_info->vk_create_info.extent.depth >> p_src_mipmap);
vkCmdResolveImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, dst_tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, 1, &vk_resolve);
vkCmdResolveImage((VkCommandBuffer)p_cmd_buffer.id, src_tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_src_texture_layout], dst_tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_dst_texture_layout], 1, &vk_resolve);
}
void RenderingDeviceDriverVulkan::command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) {
@ -3758,7 +3805,7 @@ void RenderingDeviceDriverVulkan::command_clear_color_texture(CommandBufferID p_
_texture_subresource_range_to_vk(p_subresources, &vk_subresources);
const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;
vkCmdClearColorImage((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, (VkImageLayout)p_texture_layout, &vk_color, 1, &vk_subresources);
vkCmdClearColorImage((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_texture_layout], &vk_color, 1, &vk_subresources);
}
void RenderingDeviceDriverVulkan::command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) {
@ -3769,7 +3816,7 @@ void RenderingDeviceDriverVulkan::command_copy_buffer_to_texture(CommandBufferID
const BufferInfo *buf_info = (const BufferInfo *)p_src_buffer.id;
const TextureInfo *tex_info = (const TextureInfo *)p_dst_texture.id;
vkCmdCopyBufferToImage((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, tex_info->vk_view_create_info.image, (VkImageLayout)p_dst_texture_layout, p_regions.size(), vk_copy_regions);
vkCmdCopyBufferToImage((VkCommandBuffer)p_cmd_buffer.id, buf_info->vk_buffer, tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_dst_texture_layout], p_regions.size(), vk_copy_regions);
}
void RenderingDeviceDriverVulkan::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) {
@ -3780,7 +3827,7 @@ void RenderingDeviceDriverVulkan::command_copy_texture_to_buffer(CommandBufferID
const TextureInfo *tex_info = (const TextureInfo *)p_src_texture.id;
const BufferInfo *buf_info = (const BufferInfo *)p_dst_buffer.id;
vkCmdCopyImageToBuffer((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, (VkImageLayout)p_src_texture_layout, buf_info->vk_buffer, p_regions.size(), vk_copy_regions);
vkCmdCopyImageToBuffer((VkCommandBuffer)p_cmd_buffer.id, tex_info->vk_view_create_info.image, RD_TO_VK_LAYOUT[p_src_texture_layout], buf_info->vk_buffer, p_regions.size(), vk_copy_regions);
}
/******************/
@ -3926,7 +3973,7 @@ static void _attachment_reference_to_vk(const RDD::AttachmentReference &p_attach
*r_vk_attachment_reference = {};
r_vk_attachment_reference->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
r_vk_attachment_reference->attachment = p_attachment_reference.attachment;
r_vk_attachment_reference->layout = (VkImageLayout)p_attachment_reference.layout;
r_vk_attachment_reference->layout = RD_TO_VK_LAYOUT[p_attachment_reference.layout];
r_vk_attachment_reference->aspectMask = (VkImageAspectFlags)p_attachment_reference.aspect;
}
@ -3945,8 +3992,8 @@ RDD::RenderPassID RenderingDeviceDriverVulkan::render_pass_create(VectorView<Att
vk_attachments[i].storeOp = (VkAttachmentStoreOp)p_attachments[i].store_op;
vk_attachments[i].stencilLoadOp = (VkAttachmentLoadOp)p_attachments[i].stencil_load_op;
vk_attachments[i].stencilStoreOp = (VkAttachmentStoreOp)p_attachments[i].stencil_store_op;
vk_attachments[i].initialLayout = (VkImageLayout)p_attachments[i].initial_layout;
vk_attachments[i].finalLayout = (VkImageLayout)p_attachments[i].final_layout;
vk_attachments[i].initialLayout = RD_TO_VK_LAYOUT[p_attachments[i].initial_layout];
vk_attachments[i].finalLayout = RD_TO_VK_LAYOUT[p_attachments[i].final_layout];
}
VkSubpassDescription2KHR *vk_subpasses = ALLOCA_ARRAY(VkSubpassDescription2KHR, p_subpasses.size());
@ -4010,10 +4057,10 @@ RDD::RenderPassID RenderingDeviceDriverVulkan::render_pass_create(VectorView<Att
vk_subpass_dependencies[i].sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
vk_subpass_dependencies[i].srcSubpass = p_subpass_dependencies[i].src_subpass;
vk_subpass_dependencies[i].dstSubpass = p_subpass_dependencies[i].dst_subpass;
vk_subpass_dependencies[i].srcStageMask = (VkPipelineStageFlags)p_subpass_dependencies[i].src_stages;
vk_subpass_dependencies[i].dstStageMask = (VkPipelineStageFlags)p_subpass_dependencies[i].dst_stages;
vk_subpass_dependencies[i].srcAccessMask = (VkAccessFlags)p_subpass_dependencies[i].src_access;
vk_subpass_dependencies[i].dstAccessMask = (VkAccessFlags)p_subpass_dependencies[i].dst_access;
vk_subpass_dependencies[i].srcStageMask = _rd_to_vk_pipeline_stages(p_subpass_dependencies[i].src_stages);
vk_subpass_dependencies[i].dstStageMask = _rd_to_vk_pipeline_stages(p_subpass_dependencies[i].dst_stages);
vk_subpass_dependencies[i].srcAccessMask = _rd_to_vk_access_flags(p_subpass_dependencies[i].src_access);
vk_subpass_dependencies[i].dstAccessMask = _rd_to_vk_access_flags(p_subpass_dependencies[i].dst_access);
}
VkRenderPassCreateInfo2KHR create_info = {};

View File

@ -210,6 +210,7 @@ public:
virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) override final;
virtual void texture_unmap(TextureID p_texture) override final;
virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final;
virtual bool texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) override final;
/*****************/
/**** SAMPLER ****/

View File

@ -824,8 +824,8 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
}
if (texture.draw_tracker != nullptr) {
// Draw tracker can assume the texture will be in transfer destination.
texture.draw_tracker->usage = RDG::RESOURCE_USAGE_TRANSFER_TO;
// Draw tracker can assume the texture will be in copy destination.
texture.draw_tracker->usage = RDG::RESOURCE_USAGE_COPY_TO;
}
}
@ -847,8 +847,11 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with
// Create view.
Texture texture = *src_texture;
texture.shared_fallback = nullptr;
RDD::TextureView tv;
bool create_shared = true;
bool raw_reintepretation = false;
if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
tv.format = texture.format;
} else {
@ -857,13 +860,47 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with
ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),
"Format override is not in the list of allowed shareable formats for original texture.");
tv.format = p_view.format_override;
create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation);
}
tv.swizzle_r = p_view.swizzle_r;
tv.swizzle_g = p_view.swizzle_g;
tv.swizzle_b = p_view.swizzle_b;
tv.swizzle_a = p_view.swizzle_a;
texture.driver_id = driver->texture_create_shared(texture.driver_id, tv);
if (create_shared) {
texture.driver_id = driver->texture_create_shared(texture.driver_id, tv);
} else {
// The regular view will use the same format as the main texture.
RDD::TextureView regular_view = tv;
regular_view.format = src_texture->format;
texture.driver_id = driver->texture_create_shared(texture.driver_id, regular_view);
// Create the independent texture for the alias.
RDD::TextureFormat alias_format = texture.texture_format();
alias_format.format = tv.format;
alias_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT;
_texture_check_shared_fallback(src_texture);
_texture_check_shared_fallback(&texture);
texture.shared_fallback->texture = driver->texture_create(alias_format, tv);
texture.shared_fallback->raw_reinterpretation = raw_reintepretation;
texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture);
RDG::ResourceTracker *tracker = RDG::resource_tracker_create();
tracker->texture_driver_id = texture.shared_fallback->texture;
tracker->texture_subresources = texture.barrier_range();
tracker->texture_usage = alias_format.usage_bits;
tracker->reference_count = 1;
texture.shared_fallback->texture_tracker = tracker;
texture.shared_fallback->revision = 0;
if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) {
// For shared textures of the same size, we create the buffer on the main texture if it doesn't have it already.
_texture_create_reinterpret_buffer(src_texture);
}
}
ERR_FAIL_COND_V(!texture.driver_id, RID());
texture.slice_trackers.clear();
@ -965,6 +1002,7 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
}
Texture texture = *src_texture;
texture.shared_fallback = nullptr;
get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height);
texture.mipmaps = p_mipmaps;
@ -979,6 +1017,8 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
}
RDD::TextureView tv;
bool create_shared = true;
bool raw_reintepretation = false;
if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
tv.format = texture.format;
} else {
@ -987,7 +1027,9 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),
"Format override is not in the list of allowed shareable formats for original texture.");
tv.format = p_view.format_override;
create_shared = driver->texture_can_make_shared_with_format(texture.driver_id, p_view.format_override, raw_reintepretation);
}
tv.swizzle_r = p_view.swizzle_r;
tv.swizzle_g = p_view.swizzle_g;
tv.swizzle_b = p_view.swizzle_b;
@ -1000,7 +1042,47 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
"Specified layer must be a multiple of 6.");
}
texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);
if (create_shared) {
texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, tv, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);
} else {
// The regular view will use the same format as the main texture.
RDD::TextureView regular_view = tv;
regular_view.format = src_texture->format;
texture.driver_id = driver->texture_create_shared_from_slice(src_texture->driver_id, regular_view, p_slice_type, p_layer, slice_layers, p_mipmap, p_mipmaps);
// Create the independent texture for the slice.
RDD::TextureSubresourceRange slice_range = texture.barrier_range();
slice_range.base_mipmap = 0;
slice_range.base_layer = 0;
RDD::TextureFormat slice_format = texture.texture_format();
slice_format.width = MAX(texture.width >> p_mipmap, 1U);
slice_format.height = MAX(texture.height >> p_mipmap, 1U);
slice_format.depth = MAX(texture.depth >> p_mipmap, 1U);
slice_format.format = tv.format;
slice_format.usage_bits = TEXTURE_USAGE_SAMPLING_BIT | TEXTURE_USAGE_CAN_COPY_TO_BIT;
_texture_check_shared_fallback(src_texture);
_texture_check_shared_fallback(&texture);
texture.shared_fallback->texture = driver->texture_create(slice_format, tv);
texture.shared_fallback->raw_reinterpretation = raw_reintepretation;
texture_memory += driver->texture_get_allocation_size(texture.shared_fallback->texture);
RDG::ResourceTracker *tracker = RDG::resource_tracker_create();
tracker->texture_driver_id = texture.shared_fallback->texture;
tracker->texture_subresources = slice_range;
tracker->texture_usage = slice_format.usage_bits;
tracker->reference_count = 1;
texture.shared_fallback->texture_tracker = tracker;
texture.shared_fallback->revision = 0;
if (raw_reintepretation && src_texture->shared_fallback->buffer.id == 0) {
// For shared texture slices, we create the buffer on the slice if the source texture has no reinterpretation buffer.
_texture_create_reinterpret_buffer(&texture);
}
}
ERR_FAIL_COND_V(!texture.driver_id, RID());
const Rect2i slice_rect(p_mipmap, p_layer, p_mipmaps, slice_layers);
@ -1093,15 +1175,18 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
// When using the setup queue directly, we transition the texture to the optimal layout.
RDD::TextureBarrier tb;
tb.texture = texture->driver_id;
tb.dst_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
tb.dst_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT;
tb.prev_layout = RDD::TEXTURE_LAYOUT_UNDEFINED;
tb.next_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
tb.next_layout = RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL;
tb.subresources.aspect = texture->barrier_aspect_flags;
tb.subresources.mipmap_count = texture->mipmaps;
tb.subresources.base_layer = p_layer;
tb.subresources.layer_count = 1;
driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_TRANSFER_BIT, {}, {}, tb);
driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, RDD::PIPELINE_STAGE_COPY_BIT, {}, {}, tb);
} else if (!p_use_setup_queue) {
// Indicate the texture will get modified for the shared texture fallback.
_texture_update_shared_fallback(p_texture, texture, true);
}
uint32_t mipmap_offset = 0;
@ -1199,7 +1284,7 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1);
if (p_use_setup_queue) {
driver->command_copy_buffer_to_texture(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, copy_region);
driver->command_copy_buffer_to_texture(frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].driver_id, texture->driver_id, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, copy_region);
} else {
RDG::RecordedBufferToTextureCopy buffer_to_texture_copy;
buffer_to_texture_copy.from_buffer = staging_buffer_blocks[staging_buffer_current].driver_id;
@ -1221,14 +1306,14 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
// If the texture does not have a tracker, it means it must be transitioned to the sampling state.
RDD::TextureBarrier tb;
tb.texture = texture->driver_id;
tb.src_access = RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
tb.prev_layout = RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
tb.src_access = RDD::BARRIER_ACCESS_COPY_WRITE_BIT;
tb.prev_layout = RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL;
tb.next_layout = RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
tb.subresources.aspect = texture->barrier_aspect_flags;
tb.subresources.mipmap_count = texture->mipmaps;
tb.subresources.base_layer = p_layer;
tb.subresources.layer_count = 1;
driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_TRANSFER_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, tb);
driver->command_pipeline_barrier(frames[frame].setup_command_buffer, RDD::PIPELINE_STAGE_COPY_BIT, RDD::PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, {}, {}, tb);
} else if (!p_use_setup_queue && !command_buffer_to_texture_copies_vector.is_empty()) {
if (_texture_make_mutable(texture, p_texture)) {
// The texture must be mutable to be used as a copy destination.
@ -1241,6 +1326,186 @@ Error RenderingDevice::_texture_update(RID p_texture, uint32_t p_layer, const Ve
return OK;
}
void RenderingDevice::_texture_check_shared_fallback(Texture *p_texture) {
if (p_texture->shared_fallback == nullptr) {
p_texture->shared_fallback = memnew(Texture::SharedFallback);
}
}
void RenderingDevice::_texture_update_shared_fallback(RID p_texture_rid, Texture *p_texture, bool p_for_writing) {
if (p_texture->shared_fallback == nullptr) {
// This texture does not use any of the shared texture fallbacks.
return;
}
if (p_texture->owner.is_valid()) {
Texture *owner_texture = texture_owner.get_or_null(p_texture->owner);
ERR_FAIL_NULL(owner_texture);
if (p_for_writing) {
// Only the main texture is used for writing when using the shared fallback.
owner_texture->shared_fallback->revision++;
} else if (p_texture->shared_fallback->revision != owner_texture->shared_fallback->revision) {
// Copy the contents of the main texture into the shared texture fallback slice. Update the revision.
_texture_copy_shared(p_texture->owner, owner_texture, p_texture_rid, p_texture);
p_texture->shared_fallback->revision = owner_texture->shared_fallback->revision;
}
} else if (p_for_writing) {
// Increment the revision of the texture so shared texture fallback slices must be updated.
p_texture->shared_fallback->revision++;
}
}
void RenderingDevice::_texture_free_shared_fallback(Texture *p_texture) {
if (p_texture->shared_fallback != nullptr) {
if (p_texture->shared_fallback->texture_tracker != nullptr) {
RDG::resource_tracker_free(p_texture->shared_fallback->texture_tracker);
}
if (p_texture->shared_fallback->buffer_tracker != nullptr) {
RDG::resource_tracker_free(p_texture->shared_fallback->buffer_tracker);
}
if (p_texture->shared_fallback->texture.id != 0) {
texture_memory -= driver->texture_get_allocation_size(p_texture->shared_fallback->texture);
driver->texture_free(p_texture->shared_fallback->texture);
}
if (p_texture->shared_fallback->buffer.id != 0) {
buffer_memory -= driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer);
driver->buffer_free(p_texture->shared_fallback->buffer);
}
memdelete(p_texture->shared_fallback);
p_texture->shared_fallback = nullptr;
}
}
void RenderingDevice::_texture_copy_shared(RID p_src_texture_rid, Texture *p_src_texture, RID p_dst_texture_rid, Texture *p_dst_texture) {
// The only type of copying allowed is from the main texture to the slice texture, as slice textures are not allowed to be used for writing when using this fallback.
DEV_ASSERT(p_src_texture != nullptr);
DEV_ASSERT(p_dst_texture != nullptr);
DEV_ASSERT(p_src_texture->owner.is_null());
DEV_ASSERT(p_dst_texture->owner == p_src_texture_rid);
bool src_made_mutable = _texture_make_mutable(p_src_texture, p_src_texture_rid);
bool dst_made_mutable = _texture_make_mutable(p_dst_texture, p_dst_texture_rid);
if (src_made_mutable || dst_made_mutable) {
draw_graph.add_synchronization();
}
if (p_dst_texture->shared_fallback->raw_reinterpretation) {
// If one of the textures is a main texture and they have a reinterpret buffer, we prefer using that as it's guaranteed to be big enough to hold
// anything and it's how the shared textures that don't use slices are created.
bool src_has_buffer = p_src_texture->shared_fallback->buffer.id != 0;
bool dst_has_buffer = p_dst_texture->shared_fallback->buffer.id != 0;
bool from_src = p_src_texture->owner.is_null() && src_has_buffer;
bool from_dst = p_dst_texture->owner.is_null() && dst_has_buffer;
if (!from_src && !from_dst) {
// If neither texture passed the condition, we just pick whichever texture has a reinterpretation buffer.
from_src = src_has_buffer;
from_dst = dst_has_buffer;
}
// Pick the buffer and tracker to use from the right texture.
RDD::BufferID shared_buffer;
RDG::ResourceTracker *shared_buffer_tracker = nullptr;
if (from_src) {
shared_buffer = p_src_texture->shared_fallback->buffer;
shared_buffer_tracker = p_src_texture->shared_fallback->buffer_tracker;
} else if (from_dst) {
shared_buffer = p_dst_texture->shared_fallback->buffer;
shared_buffer_tracker = p_dst_texture->shared_fallback->buffer_tracker;
} else {
DEV_ASSERT(false && "This path should not be reachable.");
}
// FIXME: When using reinterpretation buffers, the only texture aspect supported is color. Depth or stencil contents won't get copied.
RDD::BufferTextureCopyRegion get_data_region;
RDG::RecordedBufferToTextureCopy update_copy;
RDD::TextureCopyableLayout first_copyable_layout;
RDD::TextureCopyableLayout copyable_layout;
RDD::TextureSubresource texture_subresource;
texture_subresource.aspect = RDD::TEXTURE_ASPECT_COLOR;
texture_subresource.layer = 0;
texture_subresource.mipmap = 0;
driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, &first_copyable_layout);
// Copying each mipmap from main texture to a buffer and then to the slice texture.
thread_local LocalVector<RDD::BufferTextureCopyRegion> get_data_vector;
thread_local LocalVector<RDG::RecordedBufferToTextureCopy> update_vector;
get_data_vector.clear();
update_vector.clear();
for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) {
driver->texture_get_copyable_layout(p_dst_texture->shared_fallback->texture, texture_subresource, &copyable_layout);
uint32_t mipmap = p_dst_texture->base_mipmap + i;
get_data_region.buffer_offset = copyable_layout.offset - first_copyable_layout.offset;
get_data_region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
get_data_region.texture_subresources.base_layer = p_dst_texture->base_layer;
get_data_region.texture_subresources.mipmap = mipmap;
get_data_region.texture_subresources.layer_count = p_dst_texture->layers;
get_data_region.texture_region_size.x = MAX(1U, p_src_texture->width >> mipmap);
get_data_region.texture_region_size.y = MAX(1U, p_src_texture->height >> mipmap);
get_data_region.texture_region_size.z = MAX(1U, p_src_texture->depth >> mipmap);
get_data_vector.push_back(get_data_region);
update_copy.from_buffer = shared_buffer;
update_copy.region.buffer_offset = get_data_region.buffer_offset;
update_copy.region.texture_subresources.aspect = RDD::TEXTURE_ASPECT_COLOR_BIT;
update_copy.region.texture_subresources.base_layer = texture_subresource.layer;
update_copy.region.texture_subresources.mipmap = texture_subresource.mipmap;
update_copy.region.texture_subresources.layer_count = get_data_region.texture_subresources.layer_count;
update_copy.region.texture_region_size.x = get_data_region.texture_region_size.x;
update_copy.region.texture_region_size.y = get_data_region.texture_region_size.y;
update_copy.region.texture_region_size.z = get_data_region.texture_region_size.z;
update_vector.push_back(update_copy);
texture_subresource.mipmap++;
}
draw_graph.add_texture_get_data(p_src_texture->driver_id, p_src_texture->draw_tracker, shared_buffer, get_data_vector, shared_buffer_tracker);
draw_graph.add_texture_update(p_dst_texture->shared_fallback->texture, p_dst_texture->shared_fallback->texture_tracker, update_vector, shared_buffer_tracker);
} else {
// Raw reinterpretation is not required. Use a regular texture copy.
RDD::TextureCopyRegion copy_region;
copy_region.src_subresources.aspect = p_src_texture->read_aspect_flags;
copy_region.src_subresources.base_layer = p_dst_texture->base_layer;
copy_region.src_subresources.layer_count = p_dst_texture->layers;
copy_region.dst_subresources.aspect = p_dst_texture->read_aspect_flags;
copy_region.dst_subresources.base_layer = 0;
copy_region.dst_subresources.layer_count = copy_region.src_subresources.layer_count;
// Copying each mipmap from main texture to to the slice texture.
thread_local LocalVector<RDD::TextureCopyRegion> region_vector;
region_vector.clear();
for (uint32_t i = 0; i < p_dst_texture->mipmaps; i++) {
uint32_t mipmap = p_dst_texture->base_mipmap + i;
copy_region.src_subresources.mipmap = mipmap;
copy_region.dst_subresources.mipmap = i;
copy_region.size.x = MAX(1U, p_src_texture->width >> mipmap);
copy_region.size.y = MAX(1U, p_src_texture->height >> mipmap);
copy_region.size.z = MAX(1U, p_src_texture->depth >> mipmap);
region_vector.push_back(copy_region);
}
draw_graph.add_texture_copy(p_src_texture->driver_id, p_src_texture->draw_tracker, p_dst_texture->shared_fallback->texture, p_dst_texture->shared_fallback->texture_tracker, region_vector);
}
}
void RenderingDevice::_texture_create_reinterpret_buffer(Texture *p_texture) {
uint64_t row_pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP);
uint64_t transfer_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT);
uint32_t pixel_bytes = get_image_format_pixel_size(p_texture->format);
uint32_t row_pitch = STEPIFY(p_texture->width * pixel_bytes, row_pitch_step);
uint64_t buffer_size = STEPIFY(pixel_bytes * row_pitch * p_texture->height * p_texture->depth, transfer_alignment);
p_texture->shared_fallback->buffer = driver->buffer_create(buffer_size, RDD::BUFFER_USAGE_TRANSFER_FROM_BIT | RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_GPU);
buffer_memory += driver->buffer_get_allocation_size(p_texture->shared_fallback->buffer);
RDG::ResourceTracker *tracker = RDG::resource_tracker_create();
tracker->buffer_driver_id = p_texture->shared_fallback->buffer;
p_texture->shared_fallback->buffer_tracker = tracker;
}
Vector<uint8_t> RenderingDevice::_texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d) {
uint32_t width, height, depth;
uint32_t tight_mip_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth);
@ -1535,6 +1800,9 @@ Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const
copy_region.size = p_size;
// Indicate the texture will get modified for the shared texture fallback.
_texture_update_shared_fallback(p_to_texture, dst_tex, true);
// The textures must be mutable to be used in the copy operation.
bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);
bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);
@ -1578,6 +1846,9 @@ Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_
ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER,
"Source and destination texture must be of the same type (color or depth).");
// Indicate the texture will get modified for the shared texture fallback.
_texture_update_shared_fallback(p_to_texture, dst_tex, true);
// The textures must be mutable to be used in the resolve operation.
bool src_made_mutable = _texture_make_mutable(src_tex, p_from_texture);
bool dst_made_mutable = _texture_make_mutable(dst_tex, p_to_texture);
@ -1620,6 +1891,9 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32
range.base_layer = src_tex->base_layer + p_base_layer;
range.layer_count = p_layers;
// Indicate the texture will get modified for the shared texture fallback.
_texture_update_shared_fallback(p_texture, src_tex, true);
if (_texture_make_mutable(src_tex, p_texture)) {
// The texture must be mutable to be used as a clear destination.
draw_graph.add_synchronization();
@ -2526,6 +2800,14 @@ RID RenderingDevice::uniform_buffer_create(uint32_t p_size_bytes, const Vector<u
return id;
}
void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) {
for (UniformSet::SharedTexture shared : p_uniform_set->shared_textures_to_update) {
Texture *texture = texture_owner.get_or_null(shared.texture);
ERR_CONTINUE(texture == nullptr);
_texture_update_shared_fallback(shared.texture, texture, shared.writing);
}
}
RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {
_THREAD_SAFE_METHOD_
@ -2554,6 +2836,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
Vector<RDG::ResourceTracker *> draw_trackers;
Vector<RDG::ResourceUsage> draw_trackers_usage;
HashMap<RID, RDG::ResourceUsage> untracked_usage;
Vector<UniformSet::SharedTexture> shared_textures_to_update;
for (uint32_t i = 0; i < set_uniform_count; i++) {
const ShaderUniform &set_uniform = set_uniforms[i];
@ -2619,8 +2902,16 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
attachable_textures.push_back(attachable_texture);
}
if (texture->draw_tracker != nullptr) {
draw_trackers.push_back(texture->draw_tracker);
RDD::TextureID driver_id = texture->driver_id;
RDG::ResourceTracker *tracker = texture->draw_tracker;
if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) {
driver_id = texture->shared_fallback->texture;
tracker = texture->shared_fallback->texture_tracker;
shared_textures_to_update.push_back({ false, texture_id });
}
if (tracker != nullptr) {
draw_trackers.push_back(tracker);
draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);
} else {
untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;
@ -2629,7 +2920,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
driver_uniform.ids.push_back(*sampler_driver_id);
driver_uniform.ids.push_back(texture->driver_id);
driver_uniform.ids.push_back(driver_id);
}
} break;
case UNIFORM_TYPE_TEXTURE: {
@ -2656,8 +2947,16 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
attachable_textures.push_back(attachable_texture);
}
if (texture->draw_tracker != nullptr) {
draw_trackers.push_back(texture->draw_tracker);
RDD::TextureID driver_id = texture->driver_id;
RDG::ResourceTracker *tracker = texture->draw_tracker;
if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) {
driver_id = texture->shared_fallback->texture;
tracker = texture->shared_fallback->texture_tracker;
shared_textures_to_update.push_back({ false, texture_id });
}
if (tracker != nullptr) {
draw_trackers.push_back(tracker);
draw_trackers_usage.push_back(RDG::RESOURCE_USAGE_TEXTURE_SAMPLE);
} else {
untracked_usage[texture_id] = RDG::RESOURCE_USAGE_TEXTURE_SAMPLE;
@ -2665,7 +2964,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
driver_uniform.ids.push_back(texture->driver_id);
driver_uniform.ids.push_back(driver_id);
}
} break;
case UNIFORM_TYPE_IMAGE: {
@ -2687,6 +2986,10 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),
"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");
if (texture->owner.is_null() && texture->shared_fallback != nullptr) {
shared_textures_to_update.push_back({ true, texture_id });
}
if (_texture_make_mutable(texture, texture_id)) {
// The texture must be mutable as a layout transition will be required.
draw_graph.add_synchronization();
@ -2872,6 +3175,7 @@ RID RenderingDevice::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p
uniform_set.draw_trackers = draw_trackers;
uniform_set.draw_trackers_usage = draw_trackers_usage;
uniform_set.untracked_usage = untracked_usage;
uniform_set.shared_textures_to_update = shared_textures_to_update;
uniform_set.shader_set = p_shader_set;
uniform_set.shader_id = p_shader;
@ -3347,12 +3651,16 @@ Error RenderingDevice::_draw_list_render_pass_begin(Framebuffer *p_framebuffer,
for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
RDD::RenderPassClearValue clear_value;
Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
RID texture_rid = p_framebuffer->texture_ids[i];
Texture *texture = texture_owner.get_or_null(texture_rid);
if (!texture) {
color_index++;
continue;
}
// Indicate the texture will get modified for the shared texture fallback.
_texture_update_shared_fallback(texture_rid, texture, true);
if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
if (color_index < p_clear_colors.size()) {
ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug.
@ -3816,6 +4124,8 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
draw_graph.add_draw_list_bind_uniform_set(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i);
UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
_uniform_set_update_shared(uniform_set);
draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
dl->state.sets[i].bound = true;
@ -4222,6 +4532,8 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g
draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i);
UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
_uniform_set_update_shared(uniform_set);
draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
cl->state.sets[i].bound = true;
@ -4329,6 +4641,8 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p
draw_graph.add_compute_list_bind_uniform_set(cl->state.pipeline_shader_driver_id, cl->state.sets[i].uniform_set_driver_id, i);
UniformSet *uniform_set = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
_uniform_set_update_shared(uniform_set);
draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
cl->state.sets[i].bound = true;
@ -4420,6 +4734,7 @@ bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id
draw_tracker->parent = owner_texture->draw_tracker;
draw_tracker->texture_driver_id = p_texture->driver_id;
draw_tracker->texture_subresources = p_texture->barrier_range();
draw_tracker->texture_usage = p_texture->usage_flags;
draw_tracker->texture_slice_or_dirty_rect = p_texture->slice_rect;
owner_texture->slice_trackers[p_texture->slice_rect] = draw_tracker;
}
@ -4441,6 +4756,7 @@ bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id
p_texture->draw_tracker = RDG::resource_tracker_create();
p_texture->draw_tracker->texture_driver_id = p_texture->driver_id;
p_texture->draw_tracker->texture_subresources = p_texture->barrier_range();
p_texture->draw_tracker->texture_usage = p_texture->usage_flags;
p_texture->draw_tracker->reference_count = 1;
if (p_texture_id.is_valid()) {
@ -4837,6 +5153,8 @@ void RenderingDevice::_free_pending_resources(int p_frame) {
WARN_PRINT("Deleted a texture while it was bound.");
}
_texture_free_shared_fallback(texture);
texture_memory -= driver->texture_get_allocation_size(texture->driver_id);
driver->texture_free(texture->driver_id);

View File

@ -207,6 +207,15 @@ public:
// for a framebuffer to render into it.
struct Texture {
struct SharedFallback {
uint32_t revision = 1;
RDD::TextureID texture;
RDG::ResourceTracker *texture_tracker = nullptr;
RDD::BufferID buffer;
RDG::ResourceTracker *buffer_tracker = nullptr;
bool raw_reinterpretation = false;
};
RDD::TextureID driver_id;
TextureType type = TEXTURE_TYPE_MAX;
@ -235,6 +244,7 @@ public:
RDG::ResourceTracker *draw_tracker = nullptr;
HashMap<Rect2i, RDG::ResourceTracker *> slice_trackers;
SharedFallback *shared_fallback = nullptr;
RDD::TextureSubresourceRange barrier_range() const {
RDD::TextureSubresourceRange r;
@ -245,6 +255,22 @@ public:
r.layer_count = layers;
return r;
}
TextureFormat texture_format() const {
TextureFormat tf;
tf.format = format;
tf.width = width;
tf.height = height;
tf.depth = depth;
tf.array_layers = layers;
tf.mipmaps = mipmaps;
tf.texture_type = type;
tf.samples = samples;
tf.usage_bits = usage_flags;
tf.shareable_formats = allowed_shared_formats;
tf.is_resolve_buffer = is_resolve_buffer;
return tf;
}
};
RID_Owner<Texture> texture_owner;
@ -252,6 +278,11 @@ public:
Vector<uint8_t> _texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d = false);
Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_use_setup_queue, bool p_validate_can_update);
void _texture_check_shared_fallback(Texture *p_texture);
void _texture_update_shared_fallback(RID p_texture_rid, Texture *p_texture, bool p_for_writing);
void _texture_free_shared_fallback(Texture *p_texture);
void _texture_copy_shared(RID p_src_texture_rid, Texture *p_src_texture, RID p_dst_texture_rid, Texture *p_dst_texture);
void _texture_create_reinterpret_buffer(Texture *p_texture);
public:
struct TextureView {
@ -916,16 +947,24 @@ private:
RID texture;
};
struct SharedTexture {
uint32_t writing = 0;
RID texture;
};
LocalVector<AttachableTexture> attachable_textures; // Used for validation.
Vector<RDG::ResourceTracker *> draw_trackers;
Vector<RDG::ResourceUsage> draw_trackers_usage;
HashMap<RID, RDG::ResourceUsage> untracked_usage;
LocalVector<SharedTexture> shared_textures_to_update;
InvalidationCallback invalidated_callback = nullptr;
void *invalidated_callback_userdata = nullptr;
};
RID_Owner<UniformSet> uniform_set_owner;
void _uniform_set_update_shared(UniformSet *p_uniform_set);
public:
RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
bool uniform_set_is_valid(RID p_uniform_set);

View File

@ -372,6 +372,8 @@ uint64_t RenderingDeviceDriver::api_trait_get(ApiTrait p_trait) {
return 1;
case API_TRAIT_SECONDARY_VIEWPORT_SCISSOR:
return 1;
case API_TRAIT_CLEARS_WITH_COPY_ENGINE:
return true;
default:
ERR_FAIL_V(0);
}

View File

@ -220,15 +220,17 @@ public:
enum TextureLayout {
TEXTURE_LAYOUT_UNDEFINED,
TEXTURE_LAYOUT_GENERAL,
TEXTURE_LAYOUT_STORAGE_OPTIMAL,
TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL,
TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL,
TEXTURE_LAYOUT_PREINITIALIZED,
TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL = 1000164003,
TEXTURE_LAYOUT_COPY_SRC_OPTIMAL,
TEXTURE_LAYOUT_COPY_DST_OPTIMAL,
TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL,
TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL,
TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL,
TEXTURE_LAYOUT_MAX
};
enum TextureAspect {
@ -284,6 +286,7 @@ public:
virtual uint8_t *texture_map(TextureID p_texture, const TextureSubresource &p_subresource) = 0;
virtual void texture_unmap(TextureID p_texture) = 0;
virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) = 0;
virtual bool texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) = 0;
/*****************/
/**** SAMPLER ****/
@ -317,10 +320,12 @@ public:
PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = (1 << 9),
PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = (1 << 10),
PIPELINE_STAGE_COMPUTE_SHADER_BIT = (1 << 11),
PIPELINE_STAGE_TRANSFER_BIT = (1 << 12),
PIPELINE_STAGE_COPY_BIT = (1 << 12),
PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = (1 << 13),
PIPELINE_STAGE_RESOLVE_BIT = (1 << 14),
PIPELINE_STAGE_ALL_GRAPHICS_BIT = (1 << 15),
PIPELINE_STAGE_ALL_COMMANDS_BIT = (1 << 16),
PIPELINE_STAGE_CLEAR_STORAGE_BIT = (1 << 17),
};
enum BarrierAccessBits {
@ -335,13 +340,16 @@ public:
BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = (1 << 8),
BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = (1 << 9),
BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = (1 << 10),
BARRIER_ACCESS_TRANSFER_READ_BIT = (1 << 11),
BARRIER_ACCESS_TRANSFER_WRITE_BIT = (1 << 12),
BARRIER_ACCESS_COPY_READ_BIT = (1 << 11),
BARRIER_ACCESS_COPY_WRITE_BIT = (1 << 12),
BARRIER_ACCESS_HOST_READ_BIT = (1 << 13),
BARRIER_ACCESS_HOST_WRITE_BIT = (1 << 14),
BARRIER_ACCESS_MEMORY_READ_BIT = (1 << 15),
BARRIER_ACCESS_MEMORY_WRITE_BIT = (1 << 16),
BARRIER_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT = (1 << 23),
BARRIER_ACCESS_RESOLVE_READ_BIT = (1 << 24),
BARRIER_ACCESS_RESOLVE_WRITE_BIT = (1 << 25),
BARRIER_ACCESS_STORAGE_CLEAR_BIT = (1 << 27),
};
struct MemoryBarrier {
@ -735,7 +743,9 @@ public:
API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT,
API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP,
API_TRAIT_SECONDARY_VIEWPORT_SCISSOR,
API_TRAIT_CLEARS_WITH_COPY_ENGINE,
};
enum ShaderChangeInvalidation {
SHADER_CHANGE_INVALIDATION_ALL_BOUND_UNIFORM_SETS,
// What Vulkan does.

View File

@ -36,7 +36,8 @@
#define PRINT_COMMAND_RECORDING 0
RenderingDeviceGraph::RenderingDeviceGraph() {
// Default initialization.
driver_honors_barriers = false;
driver_clears_with_copy_engine = false;
}
RenderingDeviceGraph::~RenderingDeviceGraph() {
@ -44,7 +45,8 @@ RenderingDeviceGraph::~RenderingDeviceGraph() {
bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) {
switch (p_usage) {
case RESOURCE_USAGE_TRANSFER_FROM:
case RESOURCE_USAGE_COPY_FROM:
case RESOURCE_USAGE_RESOLVE_FROM:
case RESOURCE_USAGE_UNIFORM_BUFFER_READ:
case RESOURCE_USAGE_INDIRECT_BUFFER_READ:
case RESOURCE_USAGE_TEXTURE_BUFFER_READ:
@ -54,7 +56,8 @@ bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) {
case RESOURCE_USAGE_TEXTURE_SAMPLE:
case RESOURCE_USAGE_STORAGE_IMAGE_READ:
return false;
case RESOURCE_USAGE_TRANSFER_TO:
case RESOURCE_USAGE_COPY_TO:
case RESOURCE_USAGE_RESOLVE_TO:
case RESOURCE_USAGE_TEXTURE_BUFFER_READ_WRITE:
case RESOURCE_USAGE_STORAGE_BUFFER_READ_WRITE:
case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
@ -69,15 +72,19 @@ bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) {
RDD::TextureLayout RenderingDeviceGraph::_usage_to_image_layout(ResourceUsage p_usage) {
switch (p_usage) {
case RESOURCE_USAGE_TRANSFER_FROM:
return RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL;
case RESOURCE_USAGE_TRANSFER_TO:
return RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL;
case RESOURCE_USAGE_COPY_FROM:
return RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL;
case RESOURCE_USAGE_COPY_TO:
return RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL;
case RESOURCE_USAGE_RESOLVE_FROM:
return RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL;
case RESOURCE_USAGE_RESOLVE_TO:
return RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL;
case RESOURCE_USAGE_TEXTURE_SAMPLE:
return RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
case RESOURCE_USAGE_STORAGE_IMAGE_READ:
case RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE:
return RDD::TEXTURE_LAYOUT_GENERAL;
return RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL;
case RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE:
return RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
case RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE:
@ -97,10 +104,14 @@ RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage
switch (p_usage) {
case RESOURCE_USAGE_NONE:
return RDD::BarrierAccessBits(0);
case RESOURCE_USAGE_TRANSFER_FROM:
return RDD::BARRIER_ACCESS_TRANSFER_READ_BIT;
case RESOURCE_USAGE_TRANSFER_TO:
return RDD::BARRIER_ACCESS_TRANSFER_WRITE_BIT;
case RESOURCE_USAGE_COPY_FROM:
return RDD::BARRIER_ACCESS_COPY_READ_BIT;
case RESOURCE_USAGE_COPY_TO:
return RDD::BARRIER_ACCESS_COPY_WRITE_BIT;
case RESOURCE_USAGE_RESOLVE_FROM:
return RDD::BARRIER_ACCESS_RESOLVE_READ_BIT;
case RESOURCE_USAGE_RESOLVE_TO:
return RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT;
case RESOURCE_USAGE_UNIFORM_BUFFER_READ:
return RDD::BARRIER_ACCESS_UNIFORM_READ_BIT;
case RESOURCE_USAGE_INDIRECT_BUFFER_READ:
@ -818,26 +829,27 @@ void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedC
} break;
case RecordedCommand::TYPE_TEXTURE_CLEAR: {
const RecordedTextureClearCommand *texture_clear_command = reinterpret_cast<const RecordedTextureClearCommand *>(command);
driver->command_clear_color_texture(r_command_buffer, texture_clear_command->texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_clear_command->color, texture_clear_command->range);
driver->command_clear_color_texture(r_command_buffer, texture_clear_command->texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, texture_clear_command->color, texture_clear_command->range);
} break;
case RecordedCommand::TYPE_TEXTURE_COPY: {
const RecordedTextureCopyCommand *texture_copy_command = reinterpret_cast<const RecordedTextureCopyCommand *>(command);
driver->command_copy_texture(r_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_copy_command->region);
const VectorView<RDD::TextureCopyRegion> command_texture_copy_regions_view(texture_copy_command->texture_copy_regions(), texture_copy_command->texture_copy_regions_count);
driver->command_copy_texture(r_command_buffer, texture_copy_command->from_texture, RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL, texture_copy_command->to_texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, command_texture_copy_regions_view);
} break;
case RecordedCommand::TYPE_TEXTURE_GET_DATA: {
const RecordedTextureGetDataCommand *texture_get_data_command = reinterpret_cast<const RecordedTextureGetDataCommand *>(command);
const VectorView<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_view(texture_get_data_command->buffer_texture_copy_regions(), texture_get_data_command->buffer_texture_copy_regions_count);
driver->command_copy_texture_to_buffer(r_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view);
driver->command_copy_texture_to_buffer(r_command_buffer, texture_get_data_command->from_texture, RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL, texture_get_data_command->to_buffer, command_buffer_texture_copy_regions_view);
} break;
case RecordedCommand::TYPE_TEXTURE_RESOLVE: {
const RecordedTextureResolveCommand *texture_resolve_command = reinterpret_cast<const RecordedTextureResolveCommand *>(command);
driver->command_resolve_texture(r_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap);
driver->command_resolve_texture(r_command_buffer, texture_resolve_command->from_texture, RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL, texture_resolve_command->src_layer, texture_resolve_command->src_mipmap, texture_resolve_command->to_texture, RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL, texture_resolve_command->dst_layer, texture_resolve_command->dst_mipmap);
} break;
case RecordedCommand::TYPE_TEXTURE_UPDATE: {
const RecordedTextureUpdateCommand *texture_update_command = reinterpret_cast<const RecordedTextureUpdateCommand *>(command);
const RecordedBufferToTextureCopy *command_buffer_to_texture_copies = texture_update_command->buffer_to_texture_copies();
for (uint32_t j = 0; j < texture_update_command->buffer_to_texture_copies_count; j++) {
driver->command_copy_buffer_to_texture(r_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_TRANSFER_DST_OPTIMAL, command_buffer_to_texture_copies[j].region);
driver->command_copy_buffer_to_texture(r_command_buffer, command_buffer_to_texture_copies[j].from_buffer, texture_update_command->to_texture, RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL, command_buffer_to_texture_copies[j].region);
}
} break;
case RecordedCommand::TYPE_CAPTURE_TIMESTAMP: {
@ -1271,6 +1283,7 @@ void RenderingDeviceGraph::initialize(RDD *p_driver, RenderingContextDriver::Dev
}
driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS);
driver_clears_with_copy_engine = driver->api_trait_get(RDD::API_TRAIT_CLEARS_WITH_COPY_ENGINE);
}
void RenderingDeviceGraph::finalize() {
@ -1321,12 +1334,12 @@ void RenderingDeviceGraph::add_buffer_clear(RDD::BufferID p_dst, ResourceTracker
int32_t command_index;
RecordedBufferClearCommand *command = static_cast<RecordedBufferClearCommand *>(_allocate_command(sizeof(RecordedBufferClearCommand), command_index));
command->type = RecordedCommand::TYPE_BUFFER_CLEAR;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
command->buffer = p_dst;
command->offset = p_offset;
command->size = p_size;
ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO;
ResourceUsage usage = RESOURCE_USAGE_COPY_TO;
_add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
}
@ -1337,13 +1350,13 @@ void RenderingDeviceGraph::add_buffer_copy(RDD::BufferID p_src, ResourceTracker
int32_t command_index;
RecordedBufferCopyCommand *command = static_cast<RecordedBufferCopyCommand *>(_allocate_command(sizeof(RecordedBufferCopyCommand), command_index));
command->type = RecordedCommand::TYPE_BUFFER_COPY;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
command->source = p_src;
command->destination = p_dst;
command->region = p_region;
ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM };
ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM };
_add_command_to_graph(trackers, usages, p_src_tracker != nullptr ? 2 : 1, command_index, command);
}
@ -1352,13 +1365,13 @@ void RenderingDeviceGraph::add_buffer_get_data(RDD::BufferID p_src, ResourceTrac
int32_t command_index;
RecordedBufferGetDataCommand *command = static_cast<RecordedBufferGetDataCommand *>(_allocate_command(sizeof(RecordedBufferGetDataCommand), command_index));
command->type = RecordedCommand::TYPE_BUFFER_GET_DATA;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
command->source = p_src;
command->destination = p_dst;
command->region = p_region;
if (p_src_tracker != nullptr) {
ResourceUsage usage = RESOURCE_USAGE_TRANSFER_FROM;
ResourceUsage usage = RESOURCE_USAGE_COPY_FROM;
_add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command);
} else {
_add_command_to_graph(nullptr, nullptr, 0, command_index, command);
@ -1373,7 +1386,7 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke
int32_t command_index;
RecordedBufferUpdateCommand *command = static_cast<RecordedBufferUpdateCommand *>(_allocate_command(command_size, command_index));
command->type = RecordedCommand::TYPE_BUFFER_UPDATE;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
command->destination = p_dst;
command->buffer_copies_count = p_buffer_copies.size();
@ -1382,7 +1395,7 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke
buffer_copies[i] = p_buffer_copies[i];
}
ResourceUsage buffer_usage = RESOURCE_USAGE_TRANSFER_TO;
ResourceUsage buffer_usage = RESOURCE_USAGE_COPY_TO;
_add_command_to_graph(&p_dst_tracker, &buffer_usage, 1, command_index, command);
}
@ -1710,40 +1723,60 @@ void RenderingDeviceGraph::add_texture_clear(RDD::TextureID p_dst, ResourceTrack
int32_t command_index;
RecordedTextureClearCommand *command = static_cast<RecordedTextureClearCommand *>(_allocate_command(sizeof(RecordedTextureClearCommand), command_index));
command->type = RecordedCommand::TYPE_TEXTURE_CLEAR;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->texture = p_dst;
command->color = p_color;
command->range = p_range;
ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO;
ResourceUsage usage;
if (driver_clears_with_copy_engine) {
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
usage = RESOURCE_USAGE_COPY_TO;
} else {
// If the driver is uncapable of using the copy engine for clearing the image (e.g. D3D12), we must either transition the
// resource to a render target or a storage image as that's the only two ways it can perform the operation.
if (p_dst_tracker->texture_usage & RDD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
command->self_stages = RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
usage = RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE;
} else {
command->self_stages = RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT;
usage = RESOURCE_USAGE_STORAGE_IMAGE_READ_WRITE;
}
}
_add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
}
void RenderingDeviceGraph::add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, RDD::TextureCopyRegion p_region) {
void RenderingDeviceGraph::add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RDD::TextureCopyRegion> p_texture_copy_regions) {
DEV_ASSERT(p_src_tracker != nullptr);
DEV_ASSERT(p_dst_tracker != nullptr);
int32_t command_index;
RecordedTextureCopyCommand *command = static_cast<RecordedTextureCopyCommand *>(_allocate_command(sizeof(RecordedTextureCopyCommand), command_index));
uint64_t command_size = sizeof(RecordedTextureCopyCommand) + p_texture_copy_regions.size() * sizeof(RDD::TextureCopyRegion);
RecordedTextureCopyCommand *command = static_cast<RecordedTextureCopyCommand *>(_allocate_command(command_size, command_index));
command->type = RecordedCommand::TYPE_TEXTURE_COPY;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
command->from_texture = p_src;
command->to_texture = p_dst;
command->region = p_region;
command->texture_copy_regions_count = p_texture_copy_regions.size();
RDD::TextureCopyRegion *texture_copy_regions = command->texture_copy_regions();
for (uint32_t i = 0; i < command->texture_copy_regions_count; i++) {
texture_copy_regions[i] = p_texture_copy_regions[i];
}
ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM };
ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM };
_add_command_to_graph(trackers, usages, 2, command_index, command);
}
void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions) {
void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions, ResourceTracker *p_dst_tracker) {
DEV_ASSERT(p_src_tracker != nullptr);
int32_t command_index;
uint64_t command_size = sizeof(RecordedTextureGetDataCommand) + p_buffer_texture_copy_regions.size() * sizeof(RDD::BufferTextureCopyRegion);
RecordedTextureGetDataCommand *command = static_cast<RecordedTextureGetDataCommand *>(_allocate_command(command_size, command_index));
command->type = RecordedCommand::TYPE_TEXTURE_GET_DATA;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
command->from_texture = p_src;
command->to_buffer = p_dst;
command->buffer_texture_copy_regions_count = p_buffer_texture_copy_regions.size();
@ -1753,8 +1786,15 @@ void RenderingDeviceGraph::add_texture_get_data(RDD::TextureID p_src, ResourceTr
buffer_texture_copy_regions[i] = p_buffer_texture_copy_regions[i];
}
ResourceUsage usage = RESOURCE_USAGE_TRANSFER_FROM;
_add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command);
if (p_dst_tracker != nullptr) {
// Add the optional destination tracker if it was provided.
ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
ResourceUsage usages[2] = { RESOURCE_USAGE_COPY_TO, RESOURCE_USAGE_COPY_FROM };
_add_command_to_graph(trackers, usages, 2, command_index, command);
} else {
ResourceUsage usage = RESOURCE_USAGE_COPY_FROM;
_add_command_to_graph(&p_src_tracker, &usage, 1, command_index, command);
}
}
void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {
@ -1764,7 +1804,7 @@ void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTra
int32_t command_index;
RecordedTextureResolveCommand *command = static_cast<RecordedTextureResolveCommand *>(_allocate_command(sizeof(RecordedTextureResolveCommand), command_index));
command->type = RecordedCommand::TYPE_TEXTURE_RESOLVE;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->self_stages = RDD::PIPELINE_STAGE_RESOLVE_BIT;
command->from_texture = p_src;
command->to_texture = p_dst;
command->src_layer = p_src_layer;
@ -1773,18 +1813,18 @@ void RenderingDeviceGraph::add_texture_resolve(RDD::TextureID p_src, ResourceTra
command->dst_mipmap = p_dst_mipmap;
ResourceTracker *trackers[2] = { p_dst_tracker, p_src_tracker };
ResourceUsage usages[2] = { RESOURCE_USAGE_TRANSFER_TO, RESOURCE_USAGE_TRANSFER_FROM };
ResourceUsage usages[2] = { RESOURCE_USAGE_RESOLVE_TO, RESOURCE_USAGE_RESOLVE_FROM };
_add_command_to_graph(trackers, usages, 2, command_index, command);
}
void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies) {
void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies, VectorView<ResourceTracker *> p_buffer_trackers) {
DEV_ASSERT(p_dst_tracker != nullptr);
int32_t command_index;
uint64_t command_size = sizeof(RecordedTextureUpdateCommand) + p_buffer_copies.size() * sizeof(RecordedBufferToTextureCopy);
RecordedTextureUpdateCommand *command = static_cast<RecordedTextureUpdateCommand *>(_allocate_command(command_size, command_index));
command->type = RecordedCommand::TYPE_TEXTURE_UPDATE;
command->self_stages = RDD::PIPELINE_STAGE_TRANSFER_BIT;
command->self_stages = RDD::PIPELINE_STAGE_COPY_BIT;
command->to_texture = p_dst;
command->buffer_to_texture_copies_count = p_buffer_copies.size();
@ -1793,8 +1833,25 @@ void RenderingDeviceGraph::add_texture_update(RDD::TextureID p_dst, ResourceTrac
buffer_to_texture_copies[i] = p_buffer_copies[i];
}
ResourceUsage usage = RESOURCE_USAGE_TRANSFER_TO;
_add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
if (p_buffer_trackers.size() > 0) {
// Add the optional buffer trackers if they were provided.
thread_local LocalVector<ResourceTracker *> trackers;
thread_local LocalVector<ResourceUsage> usages;
trackers.clear();
usages.clear();
for (uint32_t i = 0; i < p_buffer_trackers.size(); i++) {
trackers.push_back(p_buffer_trackers[i]);
usages.push_back(RESOURCE_USAGE_COPY_FROM);
}
trackers.push_back(p_dst_tracker);
usages.push_back(RESOURCE_USAGE_COPY_TO);
_add_command_to_graph(trackers.ptr(), usages.ptr(), trackers.size(), command_index, command);
} else {
ResourceUsage usage = RESOURCE_USAGE_COPY_TO;
_add_command_to_graph(&p_dst_tracker, &usage, 1, command_index, command);
}
}
void RenderingDeviceGraph::add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index) {

View File

@ -129,8 +129,10 @@ public:
enum ResourceUsage {
RESOURCE_USAGE_NONE,
RESOURCE_USAGE_TRANSFER_FROM,
RESOURCE_USAGE_TRANSFER_TO,
RESOURCE_USAGE_COPY_FROM,
RESOURCE_USAGE_COPY_TO,
RESOURCE_USAGE_RESOLVE_FROM,
RESOURCE_USAGE_RESOLVE_TO,
RESOURCE_USAGE_UNIFORM_BUFFER_READ,
RESOURCE_USAGE_INDIRECT_BUFFER_READ,
RESOURCE_USAGE_TEXTURE_BUFFER_READ,
@ -161,6 +163,7 @@ public:
RDD::BufferID buffer_driver_id;
RDD::TextureID texture_driver_id;
RDD::TextureSubresourceRange texture_subresources;
uint32_t texture_usage = 0;
int32_t texture_slice_command_index = -1;
ResourceTracker *parent = nullptr;
ResourceTracker *dirty_shared_list = nullptr;
@ -337,7 +340,15 @@ private:
struct RecordedTextureCopyCommand : RecordedCommand {
RDD::TextureID from_texture;
RDD::TextureID to_texture;
RDD::TextureCopyRegion region;
uint32_t texture_copy_regions_count = 0;
_FORCE_INLINE_ RDD::TextureCopyRegion *texture_copy_regions() {
return reinterpret_cast<RDD::TextureCopyRegion *>(&this[1]);
}
_FORCE_INLINE_ const RDD::TextureCopyRegion *texture_copy_regions() const {
return reinterpret_cast<const RDD::TextureCopyRegion *>(&this[1]);
}
};
struct RecordedTextureGetDataCommand : RecordedCommand {
@ -596,7 +607,8 @@ private:
int32_t command_synchronization_index = -1;
bool command_synchronization_pending = false;
BarrierGroup barrier_group;
bool driver_honors_barriers = false;
bool driver_honors_barriers : 1;
bool driver_clears_with_copy_engine : 1;
WorkaroundsState workarounds_state;
TightLocalVector<Frame> frames;
uint32_t frame = 0;
@ -672,10 +684,10 @@ public:
void add_draw_list_usages(VectorView<ResourceTracker *> p_trackers, VectorView<ResourceUsage> p_usages);
void add_draw_list_end();
void add_texture_clear(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, const Color &p_color, const RDD::TextureSubresourceRange &p_range);
void add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, RDD::TextureCopyRegion p_region);
void add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions);
void add_texture_copy(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RDD::TextureCopyRegion> p_texture_copy_regions);
void add_texture_get_data(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, VectorView<RDD::BufferTextureCopyRegion> p_buffer_texture_copy_regions, ResourceTracker *p_dst_tracker = nullptr);
void add_texture_resolve(RDD::TextureID p_src, ResourceTracker *p_src_tracker, RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_src_layer, uint32_t p_src_mipmap, uint32_t p_dst_layer, uint32_t p_dst_mipmap);
void add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies);
void add_texture_update(RDD::TextureID p_dst, ResourceTracker *p_dst_tracker, VectorView<RecordedBufferToTextureCopy> p_buffer_copies, VectorView<ResourceTracker *> p_buffer_trackers = VectorView<ResourceTracker *>());
void add_capture_timestamp(RDD::QueryPoolID p_query_pool, uint32_t p_index);
void add_synchronization();
void begin_label(const String &p_label_name, const Color &p_color);