diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 6aac3b1b706..154a8460434 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -1646,12 +1646,6 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p tex_info->view_descs.srv = srv_desc; tex_info->view_descs.uav = uav_desc; - if (!barrier_capabilities.enhanced_barriers_supported && (p_format.usage_bits & (TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT))) { - // Fallback to clear resources when they're first used in a uniform set. Not necessary if enhanced barriers - // are supported, as the discard flag will be used instead when transitioning from an undefined layout. - textures_pending_clear.add(&tex_info->pending_clear); - } - return TextureID(tex_info); } @@ -3885,21 +3879,6 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff return; } - // Perform pending blackouts. - { - SelfList *E = textures_pending_clear.first(); - while (E) { - TextureSubresourceRange subresources; - subresources.layer_count = E->self()->layers; - subresources.mipmap_count = E->self()->mipmaps; - command_clear_color_texture(p_cmd_buffer, TextureID(E->self()), TEXTURE_LAYOUT_UNDEFINED, Color(), subresources); - - SelfList *next = E->next(); - E->remove_from_list(); - E = next; - } - } - CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id; const UniformSetInfo *uniform_set_info = (const UniformSetInfo *)p_uniform_set.id; const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id; @@ -4889,7 +4868,6 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) { clear.aspect.set_flag(TEXTURE_ASPECT_COLOR_BIT); clear.color_attachment = i; - tex_info->pending_clear.remove_from_list(); } } else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) { if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) { @@ -6234,6 +6212,8 @@ uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) { return true; case API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS: return !barrier_capabilities.enhanced_barriers_supported; + case API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS: + return true; default: return RenderingDeviceDriver::api_trait_get(p_trait); } diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index fd779b9e2f3..b9e87538ce5 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -365,12 +365,10 @@ private: TextureInfo *main_texture = nullptr; UINT mapped_subresource = UINT_MAX; - SelfList pending_clear{ this }; #ifdef DEBUG_ENABLED bool created_from_extension = false; #endif }; - SelfList::List textures_pending_clear; HashMap format_sample_counts_mask_cache; Mutex format_sample_counts_mask_cache_mutex; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 8d62fe5f6e0..33f14b71b51 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -1079,6 +1079,11 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture texture.allowed_shared_formats = format.shareable_formats; texture.has_initial_data = !data.is_empty(); + if (driver->api_trait_get(RDD::API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS)) { + // Check if a clear for this texture must be performed the first time it's used if the driver requires explicit clears after initialization. + texture.pending_clear = !texture.has_initial_data && (format.usage_bits & (TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)); + } + if ((format.usage_bits & (TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT))) { texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT); texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT); @@ -1931,6 +1936,50 @@ uint32_t RenderingDevice::_texture_vrs_method_to_usage_bits() const { } } +void RenderingDevice::_texture_check_pending_clear(RID p_texture_rid, Texture *p_texture) { + DEV_ASSERT(p_texture != nullptr); + + if (!p_texture->pending_clear) { + return; + } + + bool clear = true; + p_texture->pending_clear = false; + + if (p_texture->owner.is_valid()) { + // Check the owner texture instead if it exists. + p_texture_rid = p_texture->owner; + p_texture = texture_owner.get_or_null(p_texture_rid); + clear = p_texture->pending_clear; + } + + if (p_texture != nullptr && clear) { + _texture_clear(p_texture_rid, p_texture, Color(), 0, p_texture->mipmaps, 0, p_texture->layers); + p_texture->pending_clear = false; + } +} + +void RenderingDevice::_texture_clear(RID p_texture_rid, Texture *p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers) { + _check_transfer_worker_texture(p_texture); + + RDD::TextureSubresourceRange range; + range.aspect = p_texture->read_aspect_flags; + range.base_mipmap = p_texture->base_mipmap + p_base_mipmap; + range.mipmap_count = p_mipmaps; + range.base_layer = p_texture->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_rid, p_texture, true); + + if (_texture_make_mutable(p_texture, p_texture_rid)) { + // The texture must be mutable to be used as a clear destination. + draw_graph.add_synchronization(); + } + + draw_graph.add_texture_clear(p_texture->driver_id, p_texture->draw_tracker, p_color, range); +} + Vector RenderingDevice::texture_get_data(RID p_texture, uint32_t p_layer) { ERR_RENDER_THREAD_GUARD_V(Vector()); @@ -2391,24 +2440,7 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32 ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_base_layer + p_layers > src_tex->layers, ERR_INVALID_PARAMETER); - _check_transfer_worker_texture(src_tex); - - RDD::TextureSubresourceRange range; - range.aspect = src_tex->read_aspect_flags; - range.base_mipmap = src_tex->base_mipmap + p_base_mipmap; - range.mipmap_count = p_mipmaps; - 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(); - } - - draw_graph.add_texture_clear(src_tex->driver_id, src_tex->draw_tracker, p_color, range); + _texture_clear(p_texture, src_tex, p_color, p_base_mipmap, p_mipmaps, p_base_layer, p_layers); return OK; } @@ -3584,6 +3616,21 @@ void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) { } } +void RenderingDevice::_uniform_set_update_clears(UniformSet *p_uniform_set) { + if (p_uniform_set->pending_clear_textures.is_empty()) { + return; + } + + for (RID texture_id : p_uniform_set->pending_clear_textures) { + Texture *texture = texture_owner.get_or_null(texture_id); + if (texture != nullptr) { + _texture_check_pending_clear(texture_id, texture); + } + } + + p_uniform_set->pending_clear_textures.clear(); +} + RID RenderingDevice::uniform_set_create(const VectorView &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool) { _THREAD_SAFE_METHOD_ @@ -3613,6 +3660,7 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform Vector draw_trackers_usage; HashMap untracked_usage; Vector shared_textures_to_update; + LocalVector pending_clear_textures; for (uint32_t i = 0; i < set_uniform_count; i++) { const ShaderUniform &set_uniform = set_uniforms[i]; @@ -3682,6 +3730,10 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform attachable_textures.push_back(attachable_texture); } + if (texture->pending_clear) { + pending_clear_textures.push_back(texture_id); + } + RDD::TextureID driver_id = texture->driver_id; RDG::ResourceTracker *tracker = texture->draw_tracker; if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) { @@ -3728,6 +3780,10 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform attachable_textures.push_back(attachable_texture); } + if (texture->pending_clear) { + pending_clear_textures.push_back(texture_id); + } + RDD::TextureID driver_id = texture->driver_id; RDG::ResourceTracker *tracker = texture->draw_tracker; if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) { @@ -3772,6 +3828,10 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform shared_textures_to_update.push_back({ true, texture_id }); } + if (texture->pending_clear) { + pending_clear_textures.push_back(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(); @@ -3966,6 +4026,7 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform 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.pending_clear_textures = pending_clear_textures; uniform_set.shader_set = p_shader_set; uniform_set.shader_id = p_shader; @@ -4482,6 +4543,9 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, continue; } + // Clear the texture if the driver requires it during its first use. + _texture_check_pending_clear(texture_rid, texture); + // Indicate the texture will get modified for the shared texture fallback. _texture_update_shared_fallback(texture_rid, texture, true); @@ -4965,6 +5029,8 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set); _uniform_set_update_shared(uniform_set); + _uniform_set_update_clears(uniform_set); + draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); draw_list.state.sets[i].bound = true; @@ -5105,6 +5171,7 @@ void RenderingDevice::draw_list_draw_indirect(DrawListID p_list, bool p_use_indi UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set); _uniform_set_update_shared(uniform_set); + _uniform_set_update_clears(uniform_set); draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); @@ -5502,6 +5569,7 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g } UniformSet *uniform_set = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set); _uniform_set_update_shared(uniform_set); + _uniform_set_update_clears(uniform_set); draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); compute_list.state.sets[i].bound = true; @@ -5638,6 +5706,7 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p UniformSet *uniform_set = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set); _uniform_set_update_shared(uniform_set); + _uniform_set_update_clears(uniform_set); draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); compute_list.state.sets[i].bound = true; diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 00331baac00..ea29a185155 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -349,6 +349,7 @@ public: bool is_resolve_buffer = false; bool is_discardable = false; bool has_initial_data = false; + bool pending_clear = false; BitField read_aspect_flags = {}; BitField barrier_aspect_flags = {}; @@ -401,6 +402,8 @@ public: 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); + void _texture_check_pending_clear(RID p_texture_rid, Texture *p_texture); + void _texture_clear(RID p_texture_rid, Texture *p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers); uint32_t _texture_vrs_method_to_usage_bits() const; struct TextureGetDataRequest { @@ -1139,6 +1142,7 @@ private: Vector draw_trackers_usage; HashMap untracked_usage; LocalVector shared_textures_to_update; + LocalVector pending_clear_textures; InvalidationCallback invalidated_callback = nullptr; void *invalidated_callback_userdata = nullptr; }; @@ -1146,6 +1150,7 @@ private: RID_Owner uniform_set_owner; void _uniform_set_update_shared(UniformSet *p_uniform_set); + void _uniform_set_update_clears(UniformSet *p_uniform_set); public: /** Bake a set of uniforms that can be bound at runtime with the given shader. diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp index 0c26a5808a1..abc57e44167 100644 --- a/servers/rendering/rendering_device_driver.cpp +++ b/servers/rendering/rendering_device_driver.cpp @@ -53,6 +53,8 @@ uint64_t RenderingDeviceDriver::api_trait_get(ApiTrait p_trait) { return false; case API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS: return false; + case API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS: + return false; default: ERR_FAIL_V(0); } diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 326456c5413..26ce888f158 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -807,6 +807,7 @@ public: API_TRAIT_CLEARS_WITH_COPY_ENGINE, API_TRAIT_USE_GENERAL_IN_COPY_QUEUES, API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS, + API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS, }; enum ShaderChangeInvalidation {