diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index 00526951b19..66dbd087bf4 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -2014,6 +2014,9 @@ Texture can be used as a depth/stencil attachment in a framebuffer. + + Texture can be used as a depth/stencil resolve attachment in a framebuffer. + Texture can be used as a [url=https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#descriptorsets-storageimage]storage image[/url]. diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index c1ae9d2c531..4f9d5e7d966 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -536,6 +536,7 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() { _register_requested_device_extension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, false); _register_requested_device_extension(VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME, false); _register_requested_device_extension(VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME, false); + _register_requested_device_extension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME, false); // We don't actually use this extension, but some runtime components on some platforms // can and will fill the validation layers with useless info otherwise if not enabled. @@ -746,6 +747,9 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() { device_capabilities.version_major = VK_API_VERSION_MAJOR(physical_device_properties.apiVersion); device_capabilities.version_minor = VK_API_VERSION_MINOR(physical_device_properties.apiVersion); + // Cache extension availability we query often. + framebuffer_depth_resolve = enabled_device_extension_names.has(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); + // References: // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_multiview.html // https://www.khronos.org/blog/vulkan-subgroup-tutorial @@ -2012,7 +2016,7 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create(const TextureFormat & if ((p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } - if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + if ((p_format.usage_bits & (TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT))) { create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } if ((p_format.usage_bits & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) { @@ -2103,7 +2107,7 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create(const TextureFormat & image_view_create_info.components.a = (VkComponentSwizzle)p_view.swizzle_a; image_view_create_info.subresourceRange.levelCount = create_info.mipLevels; image_view_create_info.subresourceRange.layerCount = create_info.arrayLayers; - if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + if ((p_format.usage_bits & (TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT))) { image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; } else { image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -2484,6 +2488,7 @@ BitField RenderingDeviceDriverVulkan::texture_get_usages_ } if (!(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { supported.clear_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + supported.clear_flag(TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT); } if (!(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { supported.clear_flag(TEXTURE_USAGE_STORAGE_BIT); @@ -4876,12 +4881,32 @@ RDD::RenderPassID RenderingDeviceDriverVulkan::render_pass_create(VectorViewsType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; + vk_fsr_info->pNext = vk_subpasses[i].pNext; vk_fsr_info->pFragmentShadingRateAttachment = vk_subpass_fsr_attachment; vk_fsr_info->shadingRateAttachmentTexelSize.width = p_subpasses[i].fragment_shading_rate_texel_size.x; vk_fsr_info->shadingRateAttachmentTexelSize.height = p_subpasses[i].fragment_shading_rate_texel_size.y; vk_subpasses[i].pNext = vk_fsr_info; } + + // Depth resolve. + if (framebuffer_depth_resolve && p_subpasses[i].depth_resolve_reference.attachment != AttachmentReference::UNUSED) { + VkAttachmentReference2KHR *vk_subpass_depth_resolve_attachment = ALLOCA_SINGLE(VkAttachmentReference2KHR); + *vk_subpass_depth_resolve_attachment = {}; + vk_subpass_depth_resolve_attachment->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; + vk_subpass_depth_resolve_attachment->attachment = p_subpasses[i].depth_resolve_reference.attachment; + vk_subpass_depth_resolve_attachment->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescriptionDepthStencilResolveKHR *vk_depth_resolve_info = ALLOCA_SINGLE(VkSubpassDescriptionDepthStencilResolveKHR); + *vk_depth_resolve_info = {}; + vk_depth_resolve_info->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE; + vk_depth_resolve_info->pNext = vk_subpasses[i].pNext; + vk_depth_resolve_info->depthResolveMode = VK_RESOLVE_MODE_MAX_BIT_KHR; + vk_depth_resolve_info->stencilResolveMode = VK_RESOLVE_MODE_NONE_KHR; // we don't resolve our stencil (for now) + vk_depth_resolve_info->pDepthStencilResolveAttachment = vk_subpass_depth_resolve_attachment; + + vk_subpasses[i].pNext = vk_depth_resolve_info; + } } VkSubpassDependency2KHR *vk_subpass_dependencies = ALLOCA_ARRAY(VkSubpassDependency2KHR, p_subpass_dependencies.size()); @@ -6269,6 +6294,8 @@ bool RenderingDeviceDriverVulkan::has_feature(Features p_feature) { #endif case SUPPORTS_VULKAN_MEMORY_MODEL: return vulkan_memory_model_support && vulkan_memory_model_device_scope_support; + case SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE: + return framebuffer_depth_resolve; default: return false; } diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index e91b04c1eed..31b0e6a6d72 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -137,6 +137,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { bool vulkan_memory_model_device_scope_support = false; bool pipeline_cache_control_support = false; bool device_fault_support = false; + bool framebuffer_depth_resolve = false; #if defined(VK_TRACK_DEVICE_MEMORY) bool device_memory_report_support = false; #endif diff --git a/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp b/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp index e63444e9d24..8d752a0c7d9 100644 --- a/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp @@ -343,15 +343,15 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in break; case VK_FORMAT_D32_SFLOAT: format = RenderingDevice::DATA_FORMAT_D32_SFLOAT; - usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RenderingDevice::TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT; break; case VK_FORMAT_D24_UNORM_S8_UINT: format = RenderingDevice::DATA_FORMAT_D24_UNORM_S8_UINT; - usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RenderingDevice::TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT; break; case VK_FORMAT_D32_SFLOAT_S8_UINT: format = RenderingDevice::DATA_FORMAT_D32_SFLOAT_S8_UINT; - usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RenderingDevice::TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT; break; default: // continue with our default value diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index c90a63868ba..9d5f383561f 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -194,7 +194,7 @@ RID RendererSceneRenderImplementation::RenderForwardMobile::RenderBufferDataForw return RID(); } -RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(FramebufferConfigType p_config_type) { +RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(FramebufferConfigType p_config_type, bool p_resolve_depth) { ERR_FAIL_NULL_V(render_buffers, RID()); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); @@ -225,17 +225,22 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe Vector textures; int color_buffer_id = 0; - textures.push_back(use_msaa ? render_buffers->get_color_msaa() : render_buffers->get_internal_texture()); // 0 - color buffer - textures.push_back(use_msaa ? render_buffers->get_depth_msaa() : render_buffers->get_depth_texture()); // 1 - depth buffer + int depth_buffer_id = 1; + textures.push_back(use_msaa ? render_buffers->get_color_msaa() : render_buffers->get_internal_texture()); // 0 - color buffer. + textures.push_back(use_msaa ? render_buffers->get_depth_msaa() : render_buffers->get_depth_texture()); // 1 - depth buffer. if (vrs_texture.is_valid()) { - textures.push_back(vrs_texture); // 2 - vrs texture + textures.push_back(vrs_texture); // 2 - vrs texture. } if (use_msaa) { color_buffer_id = textures.size(); - textures.push_back(render_buffers->get_internal_texture()); // color buffer for resolve + textures.push_back(render_buffers->get_internal_texture()); // Color buffer for resolve. + } + if (use_msaa && p_resolve_depth) { + depth_buffer_id = textures.size(); + textures.push_back(render_buffers->get_depth_texture()); // Depth buffer for resolve. } - // Now define our subpasses + // Now define our subpasses. Vector passes; switch (p_config_type) { @@ -245,8 +250,13 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe pass.depth_attachment = 1; if (use_msaa) { - // Add resolve + // Add color resolve. pass.resolve_attachments.push_back(color_buffer_id); + + if (p_resolve_depth) { + // Add depth resolve. + pass.depth_resolve_attachment = depth_buffer_id; + } } passes.push_back(pass); @@ -257,7 +267,7 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe Size2i target_size = render_buffers->get_target_size(); Size2i internal_size = render_buffers->get_internal_size(); - // can't do our blit pass if resolutions don't match, this should already have been checked. + // Can't do our blit pass if resolutions don't match, this should already have been checked. ERR_FAIL_COND_V(target_size != internal_size, RID()); RD::FramebufferPass pass; @@ -265,13 +275,18 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe pass.depth_attachment = 1; if (use_msaa) { - // add resolve + // Add color resolve. pass.resolve_attachments.push_back(color_buffer_id); + + if (p_resolve_depth) { + // Add depth resolve. + pass.depth_resolve_attachment = depth_buffer_id; + } } passes.push_back(pass); - // - add blit to 2D pass + // Add blit to 2D pass. RID render_target = render_buffers->get_render_target(); ERR_FAIL_COND_V(render_target.is_null(), RID()); RID target_buffer; @@ -284,12 +299,12 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe ERR_FAIL_COND_V(target_buffer.is_null(), RID()); int target_buffer_id = textures.size(); - textures.push_back(target_buffer); // target buffer + textures.push_back(target_buffer); // Target buffer. RD::FramebufferPass blit_pass; - blit_pass.input_attachments.push_back(color_buffer_id); // Read from our (resolved) color buffer - blit_pass.color_attachments.push_back(target_buffer_id); // Write into our target buffer - // this doesn't need VRS + blit_pass.input_attachments.push_back(color_buffer_id); // Read from our (resolved) color buffer. + blit_pass.color_attachments.push_back(target_buffer_id); // Write into our target buffer. + // This doesn't need VRS or depth. passes.push_back(blit_pass); return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count); @@ -807,9 +822,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RENDER_TIMESTAMP("Setup 3D Scene"); + bool has_depth_texture_override = false; + bool supports_depth_resolve = RenderingDevice::get_singleton()->has_feature(RD::SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE); + RID render_target = rb->get_render_target(); if (render_target.is_valid()) { - p_render_data->scene_data->calculate_motion_vectors = RendererRD::TextureStorage::get_singleton()->render_target_get_override_velocity(render_target).is_valid(); + p_render_data->scene_data->calculate_motion_vectors = texture_storage->render_target_get_override_velocity(render_target).is_valid(); + has_depth_texture_override = texture_storage->render_target_get_override_depth(render_target).is_valid(); } else { p_render_data->scene_data->calculate_motion_vectors = false; } @@ -834,6 +853,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RS::ViewportMSAA msaa = rb->get_msaa_3d(); bool use_msaa = msaa != RS::VIEWPORT_MSAA_DISABLED; + bool resolve_depth_buffer = (use_msaa && has_depth_texture_override); // We'll check more conditions later. bool ce_has_post_opaque = _has_compositor_effect(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_OPAQUE, p_render_data); bool ce_has_pre_transparent = _has_compositor_effect(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); @@ -937,6 +957,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (use_msaa && p_render_data->environment.is_valid() && RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes)) { // Need to resolve depth texture for DOF when using MSAA. scene_state.used_depth_texture = true; + resolve_depth_buffer = true; } if (scene_state.used_screen_texture || scene_state.used_depth_texture) { @@ -945,13 +966,17 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color using_subpass_post_process = false; } + if (use_msaa && (global_surface_data.depth_texture_used || scene_state.used_depth_texture)) { + resolve_depth_buffer = true; + } + if (using_subpass_post_process) { // We can do all in one go. - framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_RENDER_AND_POST_PASS); + framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_RENDER_AND_POST_PASS, resolve_depth_buffer && supports_depth_resolve); global_pipeline_data_required.use_subpass_post_pass = true; } else { // We separate things out. - framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_RENDER_PASS); + framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_RENDER_PASS, resolve_depth_buffer && supports_depth_resolve); global_pipeline_data_required.use_separate_post_pass = true; } samplers = rb->get_samplers(); @@ -1242,8 +1267,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass } - // note if we are using MSAA we should get an automatic resolve through our subpass configuration. - // blit to tonemap if (rb_data.is_valid() && using_subpass_post_process) { _post_process_subpass(p_render_data->render_buffers->get_internal_texture(), framebuffer, p_render_data); @@ -1252,6 +1275,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass RD::get_singleton()->draw_list_end(); + + // note, if MSAA is used we should get an automatic resolve of the color buffer here. + + if (use_msaa && has_depth_texture_override && !supports_depth_resolve) { + // We don't have a fallback for this, See PR #111322 + WARN_PRINT_ONCE("MSAA Depth buffer resolve is not supported on this platform."); + } } else { // We're done with our subpasses so end our container pass // note, if MSAA is used we should get an automatic resolve of the color buffer here. @@ -1274,12 +1304,17 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } } + if (use_msaa && has_depth_texture_override && !supports_depth_resolve) { + // We don't have a fallback for this, See PR #111322 + WARN_PRINT_ONCE("MSAA Depth buffer resolve is not supported on this platform."); + } + if (scene_state.used_depth_texture || global_surface_data.depth_texture_used) { _render_buffers_ensure_depth_texture(p_render_data); if (scene_state.used_depth_texture) { // Copy depth texture to backbuffer so we can read from it. - _render_buffers_copy_depth_texture(p_render_data, use_msaa); + _render_buffers_copy_depth_texture(p_render_data, use_msaa && !supports_depth_resolve); // Note, once fallback for has_depth_texture_override works, we also don't need to do our resolve here. } } diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index a9be5308ea4..d75570618ab 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -86,7 +86,7 @@ private: FB_CONFIG_MAX }; - RID get_color_fbs(FramebufferConfigType p_config_type); + RID get_color_fbs(FramebufferConfigType p_config_type, bool p_resolve_depth = false); virtual void free_data() override; virtual void configure(RenderSceneBuffersRD *p_render_buffers) override; diff --git a/servers/rendering/renderer_rd/framebuffer_cache_rd.h b/servers/rendering/renderer_rd/framebuffer_cache_rd.h index 3b9f2068ac8..383e231a1dc 100644 --- a/servers/rendering/renderer_rd/framebuffer_cache_rd.h +++ b/servers/rendering/renderer_rd/framebuffer_cache_rd.h @@ -58,6 +58,7 @@ class FramebufferCacheRD : public Object { static _FORCE_INLINE_ uint32_t _hash_pass(const RD::FramebufferPass &p, uint32_t h) { h = hash_murmur3_one_32(p.depth_attachment, h); + h = hash_murmur3_one_32(p.depth_resolve_attachment, h); h = hash_murmur3_one_32(p.color_attachments.size(), h); for (int i = 0; i < p.color_attachments.size(); i++) { @@ -82,6 +83,10 @@ class FramebufferCacheRD : public Object { return false; } + if (a.depth_resolve_attachment != b.depth_resolve_attachment) { + return false; + } + if (a.color_attachments.size() != b.color_attachments.size()) { return false; } diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index 9169111872c..384bdd9c745 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -730,7 +730,11 @@ uint32_t RenderSceneBuffersRD::get_color_usage_bits(bool p_resolve, bool p_msaa, } RD::DataFormat RenderSceneBuffersRD::get_depth_format(bool p_resolve, bool p_msaa, bool p_storage) { - if (p_resolve) { + // TODO Our rendering engine does not support just having a depth attachment, it always assumed we combine with stencil. + // We thus can't configure our depth resolve with RD::DATA_FORMAT_R32_SFLOAT. + // We should add support for TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT or add a TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT + + if (p_resolve && !RenderingDevice::get_singleton()->has_feature(RD::SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE)) { return RD::DATA_FORMAT_R32_SFLOAT; } else { const RenderingDeviceCommons::DataFormat preferred_formats[2] = { @@ -749,7 +753,13 @@ uint32_t RenderSceneBuffersRD::get_depth_usage_bits(bool p_resolve, bool p_msaa, if (p_msaa) { usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; } else if (p_resolve) { - usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (p_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0); + usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + if (p_storage) { + usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; + } else if (RenderingDevice::get_singleton()->has_feature(RD::SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE)) { + // We're able to resolve depth in (sub)passes and we make use of this in our mobile renderer. + usage_bits |= RD::TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT; + } } else { usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 0ed6c0ff628..c4ec8a5b6d2 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -1080,7 +1080,7 @@ 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 ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_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); if (format_has_stencil(format.format)) { @@ -1094,7 +1094,7 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture texture.bound = false; // Textures are only assumed to be immutable if they have initial data and none of the other bits that indicate write usage are enabled. - bool texture_mutable_by_default = texture.usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_STORAGE_ATOMIC_BIT); + bool texture_mutable_by_default = texture.usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT | TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_STORAGE_ATOMIC_BIT); if (data.is_empty() || texture_mutable_by_default) { _texture_make_mutable(&texture, RID()); } @@ -1225,7 +1225,7 @@ RID RenderingDevice::texture_create_from_extension(TextureType p_type, DataForma texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM); texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB); - if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) || p_usage.has_flag(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); /*if (format_has_stencil(p_format.format)) { @@ -1236,7 +1236,7 @@ RID RenderingDevice::texture_create_from_extension(TextureType p_type, DataForma texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT); } - texture.driver_id = driver->texture_create_from_extension(p_image, p_type, p_format, p_layers, (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), p_mipmaps); + texture.driver_id = driver->texture_create_from_extension(p_image, p_type, p_format, p_layers, (texture.usage_flags & (TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT)), p_mipmaps); ERR_FAIL_COND_V(!texture.driver_id, RID()); _texture_make_mutable(&texture, RID()); @@ -2468,7 +2468,7 @@ RDD::RenderPassID RenderingDevice::_render_pass_create(RenderingDeviceDriver *p_ ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, RDD::RenderPassID()); ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, RDD::RenderPassID()); - ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)), + ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)), RDD::RenderPassID(), "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set."); RDD::Attachment description; @@ -2501,6 +2501,13 @@ RDD::RenderPassID RenderingDevice::_render_pass_create(RenderingDeviceDriver *p_ description.stencil_store_op = p_store_ops[i]; description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT) { + description.load_op = p_load_ops[i]; + description.store_op = p_store_ops[i]; + description.stencil_load_op = p_load_ops[i]; + description.stencil_store_op = p_store_ops[i]; + description.initial_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + description.final_layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } else { description.load_op = RDD::ATTACHMENT_LOAD_OP_DONT_CARE; description.store_op = RDD::ATTACHMENT_STORE_OP_DONT_CARE; @@ -2613,6 +2620,21 @@ RDD::RenderPassID RenderingDevice::_render_pass_create(RenderingDeviceDriver *p_ ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, RDD::RenderPassID(), "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples including the depth."); } + if (pass->depth_resolve_attachment != ATTACHMENT_UNUSED) { + attachment = pass->depth_resolve_attachment; + + // As our fallbacks are handled outside of our pass, we should never be setting up a render pass with a depth resolve attachment when not supported. + ERR_FAIL_COND_V_MSG(!p_driver->has_feature(SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE), RDD::RenderPassID(), "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), a depth resolve attachment was supplied when driver doesn't support this feature."); + + ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), RDD::RenderPassID(), "Invalid framebuffer depth resolve format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth resolve attachment."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT), RDD::RenderPassID(), "Invalid framebuffer depth resolve format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not a depth resolve attachment."); + ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, RDD::RenderPassID(), "Invalid framebuffer depth resolve format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); + + subpass.depth_resolve_reference.attachment = attachment_remap[attachment]; + subpass.depth_resolve_reference.layout = RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachment_last_pass[attachment] = i; + } + } else { subpass.depth_stencil_reference.attachment = RDD::AttachmentReference::UNUSED; subpass.depth_stencil_reference.layout = RDD::TEXTURE_LAYOUT_UNDEFINED; @@ -2757,6 +2779,8 @@ RenderingDevice::FramebufferFormatID RenderingDevice::framebuffer_format_create( for (int i = 0; i < p_format.size(); i++) { if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { pass.depth_attachment = i; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT) { + pass.depth_resolve_attachment = i; } else { pass.color_attachments.push_back(i); } @@ -2903,6 +2927,8 @@ RID RenderingDevice::framebuffer_create(const Vector &p_texture_attachments if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { pass.depth_attachment = i; + } else if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT) { + pass.depth_resolve_attachment = i; } else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) { // Prevent the VRS attachment from being added to the color_attachments. } else { @@ -3661,7 +3687,7 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); - if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) { + if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) { UniformSet::AttachableTexture attachable_texture; attachable_texture.bind = set_uniform.binding; attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j + 1); @@ -3707,7 +3733,7 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); - if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) { + if ((texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT))) { UniformSet::AttachableTexture attachable_texture; attachable_texture.bind = set_uniform.binding; attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j); @@ -4490,7 +4516,7 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, resource_usages.push_back(RDG::RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE); stages.set_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); color_index++; - } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + } else if (texture->usage_flags & (TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT)) { if (p_draw_flags.has_flag(DRAW_CLEAR_DEPTH) || p_draw_flags.has_flag(DRAW_CLEAR_STENCIL)) { operation = RDG::ATTACHMENT_OPERATION_CLEAR; clear_value.depth = p_clear_depth_value; @@ -5222,6 +5248,9 @@ void RenderingDevice::draw_list_end() { if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { texture->bound = false; } + if (texture->usage_flags & TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT) { + texture->bound = false; + } } draw_list_bound_textures.clear(); @@ -7986,6 +8015,7 @@ void RenderingDevice::_bind_methods() { BIND_BITFIELD_FLAG(TEXTURE_USAGE_SAMPLING_BIT); BIND_BITFIELD_FLAG(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT); BIND_BITFIELD_FLAG(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + BIND_BITFIELD_FLAG(TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT); BIND_BITFIELD_FLAG(TEXTURE_USAGE_STORAGE_BIT); BIND_BITFIELD_FLAG(TEXTURE_USAGE_STORAGE_ATOMIC_BIT); BIND_BITFIELD_FLAG(TEXTURE_USAGE_CPU_READ_BIT); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 4558fde4c68..009f016d97b 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -518,6 +518,7 @@ public: Vector resolve_attachments; Vector preserve_attachments; int32_t depth_attachment = ATTACHMENT_UNUSED; + int32_t depth_resolve_attachment = ATTACHMENT_UNUSED; }; typedef int64_t FramebufferFormatID; diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index 802dfea7aa1..b6387d5f219 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -421,7 +421,8 @@ public: // Try to set this bit as much as possible. If you set it, validation doesn't complain // and it works fine on mobile, then go ahead. TEXTURE_USAGE_TRANSIENT_BIT = (1 << 11), - TEXTURE_USAGE_MAX_BIT = TEXTURE_USAGE_TRANSIENT_BIT, + TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT = (1 << 12), + TEXTURE_USAGE_MAX_BIT = TEXTURE_USAGE_DEPTH_RESOLVE_ATTACHMENT_BIT, }; struct TextureFormat { @@ -970,6 +971,7 @@ public: SUPPORTS_BUFFER_DEVICE_ADDRESS, SUPPORTS_IMAGE_ATOMIC_32_BIT, SUPPORTS_VULKAN_MEMORY_MODEL, + SUPPORTS_FRAMEBUFFER_DEPTH_RESOLVE, }; enum SubgroupOperations { diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index b6e7927f487..326456c5413 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -618,6 +618,7 @@ public: LocalVector input_references; LocalVector color_references; AttachmentReference depth_stencil_reference; + AttachmentReference depth_resolve_reference; LocalVector resolve_references; LocalVector preserve_attachments; AttachmentReference fragment_shading_rate_reference;