diff options
88 files changed, 2426 insertions, 1321 deletions
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index c2996e552f..e6bcc5f77e 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -318,7 +318,7 @@ struct RemoteDebugger::ServersProfiler { void _send_frame_data(bool p_final) { DebuggerMarshalls::ServersProfilerFrame frame; - frame.frame_number = Engine::get_singleton()->get_frames_drawn(); + frame.frame_number = Engine::get_singleton()->get_idle_frames(); frame.frame_time = frame_time; frame.idle_time = idle_time; frame.physics_time = physics_time; diff --git a/doc/classes/File.xml b/doc/classes/File.xml index e9477517cf..17c65731ff 100644 --- a/doc/classes/File.xml +++ b/doc/classes/File.xml @@ -297,6 +297,7 @@ </argument> <description> Stores an integer as 16 bits in the file. + [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 2^16 - 1][/code]. </description> </method> <method name="store_32"> @@ -306,6 +307,7 @@ </argument> <description> Stores an integer as 32 bits in the file. + [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 2^32 - 1][/code]. </description> </method> <method name="store_64"> @@ -315,6 +317,7 @@ </argument> <description> Stores an integer as 64 bits in the file. + [b]Note:[/b] The [code]value[/code] must lie in the interval [code][-2^63, 2^63 - 1][/code] (i.e. be a valid [int] value). </description> </method> <method name="store_8"> @@ -324,6 +327,7 @@ </argument> <description> Stores an integer as 8 bits in the file. + [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 255][/code]. </description> </method> <method name="store_buffer"> diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml index 4e48a24951..623b2a2bb0 100644 --- a/doc/classes/Light3D.xml +++ b/doc/classes/Light3D.xml @@ -35,6 +35,9 @@ <member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false"> If [code]true[/code], the light only appears in the editor and will not be visible at runtime. </member> + <member name="light_angular_distance" type="float" setter="set_param" getter="get_param" default="0.0"> + Angular size of the light in degrees. Only available for [DirectionalLight3D]s. For reference, the sun from earth is approximately [code]0.5[/code]. + </member> <member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light3D.BakeMode" default="1"> The light's bake mode. See [enum BakeMode]. </member> @@ -53,12 +56,18 @@ <member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false"> If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows. </member> + <member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0"> + The size of the light in Godot units. Only available for [OmniLight3D]s and [SpotLight3D]s. + </member> <member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5"> The intensity of the specular blob in objects affected by the light. At [code]0[/code] the light becomes a pure diffuse light. </member> <member name="shadow_bias" type="float" setter="set_param" getter="get_param" default="0.15"> Used to adjust shadow appearance. Too small a value results in self-shadowing, while too large a value causes shadows to separate from casters. Adjust as needed. </member> + <member name="shadow_blur" type="float" setter="set_param" getter="get_param" default="1.0"> + Blurs the edges of the shadow. Can be used to hide pixel artifacts in low resolution shadow maps. A high value can make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible. + </member> <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color( 0, 0, 0, 1 )"> The color of shadows cast by this light. </member> diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index 5cb2aaf314..39d974ec47 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -214,14 +214,14 @@ </members> <signals> <signal name="item_focused"> - <argument index="0" name="id" type="int"> + <argument index="0" name="index" type="int"> </argument> <description> Emitted the when user navigates to an item using the [code]ui_up[/code] or [code]ui_down[/code] actions. The index of the item selected is passed as argument. </description> </signal> <signal name="item_selected"> - <argument index="0" name="id" type="int"> + <argument index="0" name="index" type="int"> </argument> <description> Emitted when the current item has been changed by the user. The index of the item selected is passed as argument. diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml index 09ee93732d..ea094dcd90 100644 --- a/doc/classes/PhysicsDirectSpaceState3D.xml +++ b/doc/classes/PhysicsDirectSpaceState3D.xml @@ -19,7 +19,7 @@ </argument> <description> Checks whether the shape can travel to a point. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [code][1, 1][/code]. - If the shape can not move, the returned array will be [code][0, 0][/code] under Bullet, and empty under GodotPhysics. + If the shape can not move, the returned array will be [code][0, 0][/code] under Bullet, and empty under GodotPhysics3D. </description> </method> <method name="collide_shape"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 3a4e516d86..67a033daca 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -911,7 +911,7 @@ </member> <member name="physics/2d/physics_engine" type="String" setter="" getter="" default=""DEFAULT""> Sets which physics engine to use for 2D physics. - "DEFAULT" and "GodotPhysics" are the same, as there is currently no alternative 2D physics server implemented. + "DEFAULT" and "GodotPhysics2D" are the same, as there is currently no alternative 2D physics server implemented. </member> <member name="physics/2d/sleep_threshold_angular" type="float" setter="" getter="" default="0.139626"> Threshold angular velocity under which a 2D physics body will be considered inactive. See [constant PhysicsServer2D.SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD]. @@ -953,7 +953,7 @@ </member> <member name="physics/3d/physics_engine" type="String" setter="" getter="" default=""DEFAULT""> Sets which physics engine to use for 3D physics. - "DEFAULT" is currently the [url=https://bulletphysics.org]Bullet[/url] physics engine. The "GodotPhysics" engine is still supported as an alternative. + "DEFAULT" is currently the [url=https://bulletphysics.org]Bullet[/url] physics engine. The "GodotPhysics3D" engine is still supported as an alternative. </member> <member name="physics/common/enable_object_picking" type="bool" setter="" getter="" default="true"> Enables [member Viewport.physics_object_picking] on the root viewport. @@ -994,6 +994,12 @@ <member name="rendering/quality/directional_shadow/size.mobile" type="int" setter="" getter="" default="2048"> Lower-end override for [member rendering/quality/directional_shadow/size] on mobile devices, due to performance concerns or driver support. </member> + <member name="rendering/quality/directional_shadow/soft_shadow_quality" type="int" setter="" getter="" default="2"> + Quality setting for shadows cast by [DirectionalLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy. + </member> + <member name="rendering/quality/directional_shadow/soft_shadow_quality.mobile" type="int" setter="" getter="" default="0"> + Lower-end override for [member rendering/quality/directional_shadow/soft_shadow_quality] on mobile devices, due to performance concerns or driver support. + </member> <member name="rendering/quality/driver/driver_name" type="String" setter="" getter="" default=""Vulkan""> The video driver to use ("GLES2" or "Vulkan"). [b]Note:[/b] The backend in use can be overridden at runtime via the [code]--rendering-driver[/code] command line argument. @@ -1098,11 +1104,11 @@ <member name="rendering/quality/shadow_atlas/size.mobile" type="int" setter="" getter="" default="2048"> Lower-end override for [member rendering/quality/shadow_atlas/size] on mobile devices, due to performance concerns or driver support. </member> - <member name="rendering/quality/shadows/filter_mode" type="int" setter="" getter="" default="1"> - Shadow filter mode. Higher-quality settings result in smoother shadows that flicker less when moving. "Disabled" is the fastest option, but also has the lowest quality. "PCF5" is smoother but is also slower. "PCF13" is the smoothest option, but is also the slowest. + <member name="rendering/quality/shadows/soft_shadow_quality" type="int" setter="" getter="" default="2"> + Quality setting for shadows cast by [OmniLight3D]s and [SpotLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy. </member> - <member name="rendering/quality/shadows/filter_mode.mobile" type="int" setter="" getter="" default="0"> - Lower-end override for [member rendering/quality/shadows/filter_mode] on mobile devices, due to performance concerns or driver support. + <member name="rendering/quality/shadows/soft_shadow_quality.mobile" type="int" setter="" getter="" default="0"> + Lower-end override for [member rendering/quality/shadows/soft_shadow_quality] on mobile devices, due to performance concerns or driver support. </member> <member name="rendering/quality/ssao/half_size" type="bool" setter="" getter="" default="false"> </member> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index aa393877b2..bfdcf1bb79 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3282,18 +3282,18 @@ <constant name="LIGHT_PARAM_RANGE" value="3" enum="LightParam"> The light's range. </constant> - <constant name="LIGHT_PARAM_ATTENUATION" value="4" enum="LightParam"> + <constant name="LIGHT_PARAM_SIZE" value="4" enum="LightParam"> + The size of the light when using spot light or omni light. The angular size of the light when using directional light. + </constant> + <constant name="LIGHT_PARAM_ATTENUATION" value="5" enum="LightParam"> The light's attenuation. </constant> - <constant name="LIGHT_PARAM_SPOT_ANGLE" value="5" enum="LightParam"> + <constant name="LIGHT_PARAM_SPOT_ANGLE" value="6" enum="LightParam"> The spotlight's angle. </constant> - <constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="6" enum="LightParam"> + <constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="7" enum="LightParam"> The spotlight's attenuation. </constant> - <constant name="LIGHT_PARAM_CONTACT_SHADOW_SIZE" value="7" enum="LightParam"> - Scales the shadow color. - </constant> <constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="8" enum="LightParam"> Max distance that shadows will be rendered. </constant> diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 409722ff82..b8c7815f6a 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -6252,7 +6252,7 @@ void RasterizerStorageGLES2::initialize() { #endif config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); - config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter"); + config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/texture_filters/use_nearest_mipmap_filter"); } void RasterizerStorageGLES2::finalize() { diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 09f10ef8b1..23ac5f4eef 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1568,17 +1568,22 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T #ifndef _MSC_VER #warning TODO check for support via RenderingDevice to enable on mobile when possible #endif - // vkCreateImage fails with format list on Android (VK_ERROR_OUT_OF_HOST_MEMORY) + #ifndef ANDROID_ENABLED + + // vkCreateImage fails with format list on Android (VK_ERROR_OUT_OF_HOST_MEMORY) + VkImageFormatListCreateInfoKHR format_list_create_info; //keep out of the if, needed for creation + Vector<VkFormat> allowed_formats; //keep out of the if, needed for creation +#endif if (p_format.shareable_formats.size()) { image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; - Vector<VkFormat> allowed_formats; +#ifndef ANDROID_ENABLED + for (int i = 0; i < p_format.shareable_formats.size(); i++) { allowed_formats.push_back(vulkan_formats[p_format.shareable_formats[i]]); } - VkImageFormatListCreateInfoKHR format_list_create_info; format_list_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR; format_list_create_info.pNext = nullptr; format_list_create_info.viewFormatCount = allowed_formats.size(); @@ -1589,8 +1594,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T "If supplied a list of shareable formats, the current format must be present in the list"); ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(), "If supplied a list of shareable formats, the current view format override must be present in the list"); - } #endif + } + if (p_format.type == TEXTURE_TYPE_CUBE || p_format.type == TEXTURE_TYPE_CUBE_ARRAY) { image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; } @@ -1766,6 +1772,8 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T texture.depth = image_create_info.extent.depth; texture.layers = image_create_info.arrayLayers; texture.mipmaps = image_create_info.mipLevels; + texture.base_mipmap = 0; + texture.base_layer = 0; texture.usage_flags = p_format.usage_bits; texture.samples = p_format.samples; texture.allowed_shared_formats = p_format.shareable_formats; @@ -2006,6 +2014,8 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); texture.mipmaps = 1; texture.layers = p_slice_type == TEXTURE_SLICE_CUBEMAP ? 6 : 1; + texture.base_mipmap = p_mipmap; + texture.base_layer = p_layer; VkImageViewCreateInfo image_view_create_info; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -2666,6 +2676,159 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, return OK; } +Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw) { + _THREAD_SAFE_METHOD_ + + Texture *src_tex = texture_owner.getornull(p_from_texture); + ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && src_tex->bound, ERR_INVALID_PARAMETER, + "Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER, + "Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved."); + + ERR_FAIL_COND_V_MSG(src_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Source texture must be 2D (or a slice of a 3D/Cube texture)"); + ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled."); + + Texture *dst_tex = texture_owner.getornull(p_to_texture); + ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && dst_tex->bound, ERR_INVALID_PARAMETER, + "Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, + "Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved."); + + ERR_FAIL_COND_V_MSG(dst_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Destination texture must be 2D (or a slice of a 3D/Cube texture)."); + ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled."); + + ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destionation textures must be the same format."); + ERR_FAIL_COND_V_MSG(src_tex->width != dst_tex->width && src_tex->height != dst_tex->height && src_tex->depth != dst_tex->depth, ERR_INVALID_PARAMETER, "Source and Destionation textures must have the same dimensions."); + + ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER, + "Source and destination texture must be of the same type (color or depth)."); + + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + + { + + //PRE Copy the image + + { //Source + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.oldLayout = src_tex->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + } + { //Dest + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = dst_tex->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = dst_tex->image; + image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + } + + //COPY + + { + + VkImageResolve image_copy_region; + image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask; + image_copy_region.srcSubresource.baseArrayLayer = src_tex->base_layer; + image_copy_region.srcSubresource.layerCount = 1; + image_copy_region.srcSubresource.mipLevel = src_tex->base_mipmap; + image_copy_region.srcOffset.x = 0; + image_copy_region.srcOffset.y = 0; + image_copy_region.srcOffset.z = 0; + + image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask; + image_copy_region.dstSubresource.baseArrayLayer = dst_tex->base_layer; + image_copy_region.dstSubresource.layerCount = 1; + image_copy_region.dstSubresource.mipLevel = dst_tex->base_mipmap; + image_copy_region.dstOffset.x = 0; + image_copy_region.dstOffset.y = 0; + image_copy_region.dstOffset.z = 0; + + image_copy_region.extent.width = src_tex->width; + image_copy_region.extent.height = src_tex->height; + image_copy_region.extent.depth = src_tex->depth; + + vkCmdResolveImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); + } + + // RESTORE LAYOUT for SRC and DST + + { //restore src + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + image_memory_barrier.newLayout = src_tex->layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + } + + { //make dst readable + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = dst_tex->layout; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = dst_tex->image; + image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + } + } + + return OK; +} Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw) { @@ -2688,8 +2851,8 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, src_layer_count *= 6; } - 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_layer_count, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(src_tex->base_mipmap + p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(src_tex->base_layer + p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER); VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; @@ -2708,9 +2871,9 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = src_tex->image; image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask; - image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap; + image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap + p_base_mipmap; image_memory_barrier.subresourceRange.levelCount = p_mipmaps; - image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer; + image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer; image_memory_barrier.subresourceRange.layerCount = p_layers; layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; @@ -2746,9 +2909,9 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = src_tex->image; image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask; - image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap; + image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap + p_base_mipmap; image_memory_barrier.subresourceRange.levelCount = p_mipmaps; - image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer; + image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer; image_memory_barrier.subresourceRange.layerCount = p_layers; vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); @@ -2846,6 +3009,21 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there } } break; + case INITIAL_ACTION_DROP: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; case INITIAL_ACTION_CONTINUE: { if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; @@ -4325,6 +4503,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1]); } + if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { + //can also be used as storage, add to mutable sampled + mutable_sampled_textures.push_back(texture); + } if (texture->owner.is_valid()) { texture = texture_owner.getornull(texture->owner); ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen @@ -4333,11 +4515,6 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; image_info.push_back(img_info); - - if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { - //can also be used as storage, add to mutable sampled - mutable_sampled_textures.push_back(texture); - } } write.dstArrayElement = 0; @@ -4377,6 +4554,11 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j]); } + if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { + //can also be used as storage, add to mutable sampled + mutable_sampled_textures.push_back(texture); + } + if (texture->owner.is_valid()) { texture = texture_owner.getornull(texture->owner); ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen @@ -4385,11 +4567,6 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; image_info.push_back(img_info); - - if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { - //can also be used as storage, add to mutable sampled - mutable_sampled_textures.push_back(texture); - } } write.dstArrayElement = 0; @@ -4426,6 +4603,11 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, img_info.sampler = VK_NULL_HANDLE; img_info.imageView = texture->view; + if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { + //can also be used as storage, add to mutable sampled + mutable_storage_textures.push_back(texture); + } + if (texture->owner.is_valid()) { texture = texture_owner.getornull(texture->owner); ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen @@ -4434,11 +4616,6 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; image_info.push_back(img_info); - - if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { - //can also be used as storage, add to mutable sampled - mutable_storage_textures.push_back(texture); - } } write.dstArrayElement = 0; @@ -6206,9 +6383,9 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = textures_to_sampled[i]->image; image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask; - image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.baseMipLevel = textures_to_sampled[i]->base_mipmap; image_memory_barrier.subresourceRange.levelCount = textures_to_sampled[i]->mipmaps; - image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_sampled[i]->base_layer; image_memory_barrier.subresourceRange.layerCount = textures_to_sampled[i]->layers; vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); @@ -6237,9 +6414,9 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = textures_to_storage[i]->image; image_memory_barrier.subresourceRange.aspectMask = textures_to_storage[i]->read_aspect_mask; - image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.baseMipLevel = textures_to_storage[i]->base_mipmap; image_memory_barrier.subresourceRange.levelCount = textures_to_storage[i]->mipmaps; - image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_storage[i]->base_layer; image_memory_barrier.subresourceRange.layerCount = textures_to_storage[i]->layers; vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); @@ -6369,9 +6546,9 @@ void RenderingDeviceVulkan::compute_list_end() { image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = E->get()->image; image_memory_barrier.subresourceRange.aspectMask = E->get()->read_aspect_mask; - image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.baseMipLevel = E->get()->base_mipmap; image_memory_barrier.subresourceRange.levelCount = E->get()->mipmaps; - image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.baseArrayLayer = E->get()->base_layer; image_memory_barrier.subresourceRange.layerCount = E->get()->layers; vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); @@ -6935,9 +7112,42 @@ uint64_t RenderingDeviceVulkan::get_captured_timestamps_frame() const { return frames[frame].index; } +static void mult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) { + uint64_t u1 = (u & 0xffffffff); + uint64_t v1 = (v & 0xffffffff); + uint64_t t = (u1 * v1); + uint64_t w3 = (t & 0xffffffff); + uint64_t k = (t >> 32); + + u >>= 32; + t = (u * v1) + k; + k = (t & 0xffffffff); + uint64_t w1 = (t >> 32); + + v >>= 32; + t = (u1 * v) + k; + k = (t >> 32); + + h = (u * v) + w1 + k; + l = (t << 32) + w3; +} + uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const { ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); - return frames[frame].timestamp_result_values[p_index] * limits.timestampPeriod; + + // this sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs. + // so, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible + // need to do 128 bits fixed point multiplication to get the rigth value + + uint64_t shift_bits = 16; + + uint64_t h, l; + + mult64to128(frames[frame].timestamp_result_values[p_index], uint64_t(double(limits.timestampPeriod) * double(1 << shift_bits)), h, l); + l >>= shift_bits; + l |= h << (64 - shift_bits); + + return l; } uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const { ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 88a12c7e44..2c92f3466e 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -138,6 +138,8 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t layers; uint32_t mipmaps; uint32_t usage_flags; + uint32_t base_mipmap; + uint32_t base_layer; Vector<DataFormat> allowed_shared_formats; @@ -983,6 +985,7 @@ public: virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false); virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false); + virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw = false); /*********************/ /**** FRAMEBUFFER ****/ diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d8f0a2764a..6f6287ccb5 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -358,13 +358,13 @@ void EditorNode::_notification(int p_what) { scene_root->set_default_canvas_item_texture_repeat(tr); } - RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_shape"))); + RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape"))); RS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape); - RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_quality"))); - bool dof_jitter = GLOBAL_GET("rendering/quality/filters/depth_of_field_use_jitter"); + RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))); + bool dof_jitter = GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter"); RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter); RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size")); - RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter"), GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter_curve")); + RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_curve")); bool glow_bicubic = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0; RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic); RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality"))); @@ -374,8 +374,10 @@ void EditorNode::_notification(int p_what) { float sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale"); float sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale"); RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale); - RS::ShadowFilter shadow_filter = RS::ShadowFilter(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); - RS::get_singleton()->shadow_filter_set(shadow_filter); + RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality"))); + RS::get_singleton()->shadows_quality_set(shadows_quality); + RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality"))); + RS::get_singleton()->directional_shadow_quality_set(directional_shadow_quality); } ResourceImporterTexture::get_singleton()->update_imports(); diff --git a/editor/icons/AcceptDialog.svg b/editor/icons/AcceptDialog.svg index e0bf7b8336..07e54d722f 100644 --- a/editor/icons/AcceptDialog.svg +++ b/editor/icons/AcceptDialog.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm9.4746 1.6367 1.4141 1.4141-4.9492 4.9492-2.8281-2.8281 1.4141-1.4141 1.4141 1.4141z" fill="#a5efac"/></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm9.4746 1.6367 1.4141 1.4141-4.9492 4.9492-2.8281-2.8281 1.4141-1.4141 1.4141 1.4141z" fill="#e0e0e0"/></svg>
\ No newline at end of file diff --git a/editor/icons/ConfirmationDialog.svg b/editor/icons/ConfirmationDialog.svg index d1f13fbb3b..2d6e45b51f 100644 --- a/editor/icons/ConfirmationDialog.svg +++ b/editor/icons/ConfirmationDialog.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6.9863 1.002c.34689-.0022844.6986.055762 1.0391.17969 1.3618.4956 2.1813 1.9126 1.9297 3.3398-.19105 1.0835-.96172 1.9461-1.9551 2.3008v.17773h-1-1v-.8418a1.0001 1.0001 0 0 1 1-1.1582c.49193 0 .89895-.34177.98438-.82617.085424-.4845-.18031-.94508-.64258-1.1133-.46227-.1683-.96106.013453-1.207.43945a1.0002 1.0002 0 0 1 -1.7324-1c.54346-.94148 1.5433-1.4912 2.584-1.498zm-.98633 6.998h2v1h-2z" fill="#a5efac"/></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6.9863 1.002c.34689-.0022844.6986.055762 1.0391.17969 1.3618.4956 2.1813 1.9126 1.9297 3.3398-.19105 1.0835-.96172 1.9461-1.9551 2.3008v.17773h-1-1v-.8418a1.0001 1.0001 0 0 1 1-1.1582c.49193 0 .89895-.34177.98438-.82617.085424-.4845-.18031-.94508-.64258-1.1133-.46227-.1683-.96106.013453-1.207.43945a1.0002 1.0002 0 0 1 -1.7324-1c.54346-.94148 1.5433-1.4912 2.584-1.498zm-.98633 6.998h2v1h-2z" fill="#e0e0e0"/></svg>
\ No newline at end of file diff --git a/editor/icons/PopupDialog.svg b/editor/icons/EditorFileDialog.svg index d871e56a63..95906234ab 100644 --- a/editor/icons/PopupDialog.svg +++ b/editor/icons/EditorFileDialog.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6 1h2v5h-2zm0 6h2v2h-2z" fill="#a5efac"/></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#e0e0e0"/></svg>
\ No newline at end of file diff --git a/editor/icons/FileDialog.svg b/editor/icons/FileDialog.svg index 7708659c21..95906234ab 100644 --- a/editor/icons/FileDialog.svg +++ b/editor/icons/FileDialog.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#a5efac"/></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#e0e0e0"/></svg>
\ No newline at end of file diff --git a/editor/icons/Popup.svg b/editor/icons/Popup.svg index 93f7e5000d..a497b7a7fc 100644 --- a/editor/icons/Popup.svg +++ b/editor/icons/Popup.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm4 2h2v6h-2zm0 8h2v2h-2z" fill="#a5efac"/></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm4 2h2v6h-2zm0 8h2v2h-2z" fill="#e0e0e0"/></svg>
\ No newline at end of file diff --git a/editor/icons/PopupMenu.svg b/editor/icons/PopupMenu.svg index dd7b2bb0fd..ebf62208e0 100644 --- a/editor/icons/PopupMenu.svg +++ b/editor/icons/PopupMenu.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-7a1 1 0 0 0 -1-1zm1 2h10v2h-10zm0 3h10v2h-10z" fill="#a5efac"/></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-7a1 1 0 0 0 -1-1zm1 2h10v2h-10zm0 3h10v2h-10z" fill="#e0e0e0"/></svg>
\ No newline at end of file diff --git a/editor/icons/PopupPanel.svg b/editor/icons/PopupPanel.svg index 47a5448f5b..b45a3c9c3c 100644 --- a/editor/icons/PopupPanel.svg +++ b/editor/icons/PopupPanel.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4c-.55228 0-1 .44772-1 1v7c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-7c0-.55228-.44772-1-1-1z" fill="#a5efac"/></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4c-.55228 0-1 .44772-1 1v7c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-7c0-.55228-.44772-1-1-1z" fill="#e0e0e0"/></svg>
\ No newline at end of file diff --git a/editor/icons/ScriptCreateDialog.svg b/editor/icons/ScriptCreateDialog.svg index 751b799ba9..78a69c5e59 100644 --- a/editor/icons/ScriptCreateDialog.svg +++ b/editor/icons/ScriptCreateDialog.svg @@ -1 +1 @@ -<svg height="17.067" viewBox="0 0 16 16" width="17.067" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m6 1v1c-.55228 0-1 .44772-1 1v10h-1v-2h-2v2c.0002826.35698.19084.68674.5.86523.15194.088045.32439.13452.5.13477v1h6v-5l3-2v-3h3v-2c0-1.1046-.89543-2-2-2z" fill="#a5efac" transform="translate(0 1036.4)"/><path d="m6 1c-1.1046 0-2 .89543-2 2v7h-3v3c0 1.1046.89543 2 2 2s2-.89543 2-2v-10c0-.55228.44772-1 1-1s1 .44772 1 1v3h5v-1h-4v-2c0-1.1046-.89543-2-2-2zm-4 10h2v2c0 .55228-.44772 1-1 1s-1-.44772-1-1z" fill="#87e29f" transform="translate(0 1036.4)"/><circle cx="3" cy="1048.4" fill="#e0e0e0" r="0"/><g fill="#87e29f"><ellipse cx="12" cy="1048.4" rx=".5" ry="3"/><ellipse cx="913.91" cy="513.79" rx=".5" ry="3" transform="matrix(.5 .8660254 -.8660254 .5 0 0)"/><ellipse cx="901.91" cy="-534.57" rx=".5" ry="3" transform="matrix(-.5 .8660254 -.8660254 -.5 0 0)"/></g></g></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm5.5722656 1h3.9980464a1.1426143 1.1426143 0 0 1 1.142579 1.1425781v1.1425781h-1.712891-2.2851562v-.5703124-.5722657c0-.6310659-.5115295-1.1425781-1.1425782-1.1425781zm0 .5722656c.3155215 0 .5703125.254791.5703125.5703125v.5722657.5703124.5722657h.5722657 2.2851562v3.9980471a1.1426143 1.1426143 0 0 1 -1.1425781 1.142578h-4c.6310487 0 1.1425781-.511529 1.1425781-1.142578v-5.7128909c0-.0785019.01823-.1545692.046875-.2226562v-.0019531c.02868-.0672829.0683226-.1266374.1191406-.1777344.00097-.00096.0029352-.0010048.0039063-.0019532.0513303-.0508898.1121075-.0944618.1796875-.1230468.0683505-.028909.1437752-.0429688.2226562-.0429688zm-2.2851562 5.1406254h1.1425781v1.142578c0 .315522-.2567441.572265-.5722656.572265-.0776611 0-.15125-.016852-.21875-.044922-.00206-.000799-.0038594-.003049-.0058594-.003906-.0656506-.028192-.1236101-.067817-.1738281-.117187a.57130715.57130715 0 0 1 -.0097656-.009766c-.0490902-.050487-.0893425-.107988-.1171876-.173828-.028908-.06835-.0449218-.143776-.0449218-.222656z"/><circle cx="-23.915255" cy="3.118624" r="0"/></g></svg>
\ No newline at end of file diff --git a/editor/icons/WindowDialog.svg b/editor/icons/Window.svg index 3c7be2a58d..a02a86d56a 100644 --- a/editor/icons/WindowDialog.svg +++ b/editor/icons/Window.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8z" fill="#a5efac"/></svg>
\ No newline at end of file +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8z" fill="#e0e0e0"/></svg>
\ No newline at end of file diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 2f7747d0ff..43a88a32c8 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1919,6 +1919,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { Point2 offset = drag_to_local - drag_from_local; Size2 scale = canvas_item->call("get_scale"); + Size2 original_scale = scale; float ratio = scale.y / scale.x; if (drag_type == DRAG_SCALE_BOTH) { Size2 scale_factor = drag_to_local / drag_from_local; @@ -1931,6 +1932,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { Size2 scale_factor = Vector2(offset.x, -offset.y) / SCALE_HANDLE_DISTANCE; Size2 parent_scale = parent_xform.get_scale(); scale_factor *= Vector2(1.0 / parent_scale.x, 1.0 / parent_scale.y); + if (drag_type == DRAG_SCALE_X) { scale.x += scale_factor.x; if (uniform) { @@ -1945,8 +1947,13 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { } if (snap_scale && !is_ctrl) { - scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step; - scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step; + if (snap_relative) { + scale.x = original_scale.x * (roundf((scale.x / original_scale.x) / snap_scale_step) * snap_scale_step); + scale.y = original_scale.y * (roundf((scale.y / original_scale.y) / snap_scale_step) * snap_scale_step); + } else { + scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step; + scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step; + } } canvas_item->call("set_scale", scale); diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index b005519a5e..ef4d7d7646 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -262,9 +262,8 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) { toolbar->add_child(memnew(VSeparator)); menu = memnew(MenuButton); - menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); - menu->get_popup()->add_separator(); menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART); + menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); menu->set_text(TTR("CPUParticles2D")); menu->set_switch_on_hover(true); toolbar->add_child(menu); diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp index 0c2fbaf62a..59a353a581 100644 --- a/editor/plugins/cpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp @@ -104,9 +104,8 @@ CPUParticles3DEditor::CPUParticles3DEditor() { particles_editor_hb->hide(); options->set_text(TTR("CPUParticles3D")); - options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); - options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART); + options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); options->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles3DEditor::_menu_option)); } diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 29c47a2b67..5c35285c22 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -371,14 +371,11 @@ GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin(EditorNode *p_node) { toolbar->add_child(memnew(VSeparator)); menu = memnew(MenuButton); + menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART); menu->get_popup()->add_item(TTR("Generate Visibility Rect"), MENU_GENERATE_VISIBILITY_RECT); - menu->get_popup()->add_separator(); menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); // menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK); - menu->get_popup()->add_separator(); menu->get_popup()->add_item(TTR("Convert to CPUParticles2D"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES); - menu->get_popup()->add_separator(); - menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART); menu->set_text(TTR("GPUParticles2D")); menu->set_switch_on_hover(true); toolbar->add_child(menu); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 534a228098..7f80acc176 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -433,13 +433,10 @@ GPUParticles3DEditor::GPUParticles3DEditor() { particles_editor_hb->hide(); options->set_text(TTR("GPUParticles3D")); + options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART); options->get_popup()->add_item(TTR("Generate AABB"), MENU_OPTION_GENERATE_AABB); - options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); - options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Convert to CPUParticles3D"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES); - options->get_popup()->add_separator(); - options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART); options->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles3DEditor::_menu_option)); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 1c16ed6b58..92497874c3 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -347,7 +347,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) { if (orthogonal) { float half_fov = Math::deg2rad(get_fov()) / 2.0; float height = 2.0 * cursor.distance * Math::tan(half_fov); - camera->set_orthogonal(height, 0.1, 8192); + camera->set_orthogonal(height, get_znear(), get_zfar()); } else { camera->set_perspective(get_fov(), get_znear(), get_zfar()); } @@ -364,7 +364,7 @@ Transform Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) cons camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot); if (orthogonal) - camera_transform.translate(0, 0, 4096); + camera_transform.translate(0, 0, (get_zfar() - get_znear()) / 2.0); else camera_transform.translate(0, 0, p_cursor.distance); @@ -2478,11 +2478,15 @@ void Node3DEditorViewport::_notification(int p_what) { //update msaa if changed - int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa"); + int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/screen_filters/msaa"); viewport->set_msaa(Viewport::MSAA(msaa_mode)); + int ssaa_mode = GLOBAL_GET("rendering/quality/screen_filters/screen_space_aa"); + viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode)); bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); - info_label->set_visible(show_info); + if (show_info != info_label->is_visible()) { + info_label->set_visible(show_info); + } Camera3D *current_camera; @@ -2509,17 +2513,46 @@ void Node3DEditorViewport::_notification(int p_what) { text += TTR("Surface Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SURFACE_CHANGES_IN_FRAME)) + "\n"; text += TTR("Draw Calls") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME)) + "\n"; text += TTR("Vertices") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_VERTICES_IN_FRAME)); + info_label->set_text(text); } // FPS Counter. - bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS)); - fps_label->set_visible(show_fps); - + bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME)); + + if (show_fps != fps_label->is_visible()) { + fps_label->set_visible(show_fps); + RS::get_singleton()->viewport_set_measure_render_time(viewport->get_viewport_rid(), show_fps); + for (int i = 0; i < FRAME_TIME_HISTORY; i++) { + cpu_time_history[i] = 0; + gpu_time_history[i] = 0; + } + cpu_time_history_index = 0; + cpu_time_history_index = 0; + } if (show_fps) { + + cpu_time_history[cpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_cpu(viewport->get_viewport_rid()); + cpu_time_history_index = (cpu_time_history_index + 1) % FRAME_TIME_HISTORY; + float cpu_time = 0.0; + for (int i = 0; i < FRAME_TIME_HISTORY; i++) { + cpu_time += cpu_time_history[i]; + } + cpu_time /= FRAME_TIME_HISTORY; + + gpu_time_history[gpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_gpu(viewport->get_viewport_rid()); + gpu_time_history_index = (gpu_time_history_index + 1) % FRAME_TIME_HISTORY; + float gpu_time = 0.0; + for (int i = 0; i < FRAME_TIME_HISTORY; i++) { + gpu_time += gpu_time_history[i]; + } + gpu_time /= FRAME_TIME_HISTORY; + String text; - const float temp_fps = Engine::get_singleton()->get_frames_per_second(); - text += TTR(vformat("FPS: %d (%s ms)", temp_fps, String::num(1000.0f / temp_fps, 2))); + text += TTR("CPU Time") + ": " + String::num(cpu_time, 1) + " ms\n"; + text += TTR("GPU Time") + ": " + String::num(gpu_time, 1) + " ms\n"; + text += TTR("FPS") + ": " + itos(1000.0 / gpu_time); + fps_label->set_text(text); } @@ -2980,9 +3013,9 @@ void Node3DEditorViewport::_menu_option(int p_option) { view_menu->get_popup()->set_item_checked(idx, !current); } break; - case VIEW_FPS: { + case VIEW_FRAME_TIME: { - int idx = view_menu->get_popup()->get_item_index(VIEW_FPS); + int idx = view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME); bool current = view_menu->get_popup()->is_item_checked(idx); view_menu->get_popup()->set_item_checked(idx, !current); @@ -3338,12 +3371,12 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) { if (view_menu->get_popup()->is_item_checked(idx) != information) _menu_option(VIEW_INFORMATION); } - if (p_state.has("fps")) { - bool fps = p_state["fps"]; + if (p_state.has("frame_time")) { + bool fps = p_state["frame_time"]; - int idx = view_menu->get_popup()->get_item_index(VIEW_FPS); + int idx = view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME); if (view_menu->get_popup()->is_item_checked(idx) != fps) - _menu_option(VIEW_FPS); + _menu_option(VIEW_FRAME_TIME); } if (p_state.has("half_res")) { bool half_res = p_state["half_res"]; @@ -3400,7 +3433,7 @@ Dictionary Node3DEditorViewport::get_state() const { d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER)); d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS)); d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); - d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS)); + d["frame_time"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME)); d["half_res"] = subviewport_container->get_stretch_shrink() > 1; d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW)); if (previewing) @@ -3812,6 +3845,9 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index) { + cpu_time_history_index = 0; + gpu_time_history_index = 0; + _edit.mode = TRANSFORM_NONE; _edit.plane = TRANSFORM_VIEW; _edit.edited_gizmo = 0; @@ -3912,7 +3948,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION); - view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS); + view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View Frame Time")), VIEW_FRAME_TIME); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true); view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION); @@ -3989,7 +4025,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE); fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE); fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN); - fps_label->set_tooltip(TTR("Note: The FPS value displayed is the editor's framerate.\nIt cannot be used as a reliable indication of in-game performance.")); + fps_label->set_tooltip(TTR("Note: The FPS is estimated on a 60hz refresh rate.")); fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show. surface->add_child(fps_label); fps_label->hide(); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index bb83e7f626..5f0ba1921b 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -202,7 +202,7 @@ class Node3DEditorViewport : public Control { VIEW_AUDIO_DOPPLER, VIEW_GIZMOS, VIEW_INFORMATION, - VIEW_FPS, + VIEW_FRAME_TIME, VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_OVERDRAW, @@ -229,7 +229,9 @@ public: enum { GIZMO_BASE_LAYER = 27, GIZMO_EDIT_LAYER = 26, - GIZMO_GRID_LAYER = 25 + GIZMO_GRID_LAYER = 25, + + FRAME_TIME_HISTORY = 20, }; enum NavigationScheme { @@ -239,6 +241,11 @@ public: }; private: + float cpu_time_history[FRAME_TIME_HISTORY]; + int cpu_time_history_index; + float gpu_time_history[FRAME_TIME_HISTORY]; + int gpu_time_history_index; + int index; String name; void _menu_option(int p_option); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 1e3cbd661e..2ec3352e70 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2236,6 +2236,8 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; +#define IS_METHOD_SIGNAL(m_method) (m_method == "connect" || m_method == "disconnect" || m_method == "is_connected" || m_method == "emit_signal") + while (base_type.has_type) { switch (base_type.kind) { case GDScriptParser::DataType::CLASS: { @@ -2252,7 +2254,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con } } - if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) { for (int i = 0; i < base_type.class_type->_signals.size(); i++) { ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL); option.insert_text = quote_style + option.display + quote_style; @@ -2265,7 +2267,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con case GDScriptParser::DataType::GDSCRIPT: { Ref<GDScript> gds = base_type.script_type; if (gds.is_valid()) { - if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) { List<MethodInfo> signals; gds->get_script_signal_list(&signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { @@ -2327,7 +2329,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con } } - if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) { List<MethodInfo> signals; ClassDB::get_signal_list(class_name, &signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { @@ -2336,6 +2338,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con r_result.insert(option.display, option); } } +#undef IS_METHOD_SIGNAL if (ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node") && p_argidx == 0) { // Get autoloads diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 856f4188aa..988bf3017d 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -44,9 +44,8 @@ bool UPNP::is_common_device(const String &dev) const { } int UPNP::discover(int timeout, int ttl, const String &device_filter) { - ERR_FAIL_COND_V(timeout < 0, UPNP_RESULT_INVALID_PARAM); - ERR_FAIL_COND_V(ttl < 0, UPNP_RESULT_INVALID_PARAM); - ERR_FAIL_COND_V(ttl > 255, UPNP_RESULT_INVALID_PARAM); + ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative."); + ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive)."); devices.clear(); @@ -264,7 +263,7 @@ void UPNP::clear_devices() { } Ref<UPNPDevice> UPNP::get_gateway() const { - ERR_FAIL_COND_V(devices.size() < 1, nullptr); + ERR_FAIL_COND_V_MSG(devices.size() < 1, nullptr, "Couldn't find any UPNPDevices."); for (int i = 0; i < devices.size(); i++) { Ref<UPNPDevice> dev = get_device(i); diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp index c21826d14d..40eb6106a0 100644 --- a/modules/upnp/upnp_device.cpp +++ b/modules/upnp/upnp_device.cpp @@ -35,7 +35,7 @@ #include <miniupnpc/upnpcommands.h> String UPNPDevice::query_external_address() const { - ERR_FAIL_COND_V(!is_valid_gateway(), ""); + ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid."); char addr[16]; int i = UPNP_GetExternalIPAddress( @@ -43,17 +43,17 @@ String UPNPDevice::query_external_address() const { igd_service_type.utf8().get_data(), (char *)&addr); - ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, ""); + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address."); return String(addr); } int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { - ERR_FAIL_COND_V(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY); - ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT); - ERR_FAIL_COND_V(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT); // Needs to allow 0 because 0 signifies "use external port as internal port" - ERR_FAIL_COND_V(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL); - ERR_FAIL_COND_V(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION); + ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid."); + ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port" + ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); + ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative."); if (port_internal < 1) { port_internal = port; @@ -70,14 +70,14 @@ int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, Strin nullptr, // Remote host, always nullptr as IGDs don't support it duration > 0 ? itos(duration).utf8().get_data() : nullptr); - ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i)); + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't add port mapping."); return UPNP::UPNP_RESULT_SUCCESS; } int UPNPDevice::delete_port_mapping(int port, String proto) const { - ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT); - ERR_FAIL_COND_V(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL); + ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); int i = UPNP_DeletePortMapping( igd_control_url.utf8().get_data(), @@ -87,7 +87,7 @@ int UPNPDevice::delete_port_mapping(int port, String proto) const { nullptr // Remote host, always nullptr as IGDs don't support it ); - ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i)); + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't delete port mapping."); return UPNP::UPNP_RESULT_SUCCESS; } diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index b52dfe1733..7cc52eef36 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -727,6 +727,26 @@ void VisualScript::rename_variable(const StringName &p_name, const StringName &p variables[p_new_name] = variables[p_name]; variables.erase(p_name); + + List<StringName> funcs; + get_function_list(&funcs); + for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) { // loop through all the functions + List<int> ids; + get_node_list(F->get(), &ids); + for (List<int>::Element *E = ids.front(); E; E = E->next()) { + Ref<VisualScriptVariableGet> nodeget = get_node(F->get(), E->get()); + if (nodeget.is_valid()) { + if (nodeget->get_variable() == p_name) + nodeget->set_variable(p_new_name); + } else { + Ref<VisualScriptVariableSet> nodeset = get_node(F->get(), E->get()); + if (nodeset.is_valid()) { + if (nodeset->get_variable() == p_name) + nodeset->set_variable(p_new_name); + } + } + } + } } void VisualScript::add_custom_signal(const StringName &p_name) { diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 39d8f7c082..2b5a17c36f 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -508,7 +508,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons } break; case MATH_POSMOD: case MATH_ROUND: { - t = Variant::INT; + t = Variant::FLOAT; } break; case MATH_ABS: { t = Variant::NIL; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index ea60b6222e..59b1bcdd96 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -1171,6 +1171,8 @@ void VisualScriptEditor::_member_edited() { undo_redo->add_undo_method(script.ptr(), "rename_variable", new_name, name); undo_redo->add_do_method(this, "_update_members"); undo_redo->add_undo_method(this, "_update_members"); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); undo_redo->commit_action(); @@ -3933,7 +3935,9 @@ void VisualScriptEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members)); + variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED); signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members)); + signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED); [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { @@ -4645,6 +4649,7 @@ void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_input", &VisualScriptEditor::_input); ClassDB::bind_method("_update_graph_connections", &VisualScriptEditor::_update_graph_connections); + ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members); ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search); } diff --git a/platform/android/api/api.cpp b/platform/android/api/api.cpp index ef11b12971..4fe868d4f0 100644 --- a/platform/android/api/api.cpp +++ b/platform/android/api/api.cpp @@ -32,6 +32,7 @@ #include "core/engine.h" #include "java_class_wrapper.h" +#include "jni_singleton.h" #if !defined(ANDROID_ENABLED) static JavaClassWrapper *java_class_wrapper = nullptr; @@ -40,7 +41,11 @@ static JavaClassWrapper *java_class_wrapper = nullptr; void register_android_api() { #if !defined(ANDROID_ENABLED) + // On Android platforms, the `java_class_wrapper` instantiation and the + // `JNISingleton` registration occurs in + // `platform/android/java_godot_lib_jni.cpp#Java_org_godotengine_godot_GodotLib_setup` java_class_wrapper = memnew(JavaClassWrapper); // Dummy + ClassDB::register_class<JNISingleton>(); #endif ClassDB::register_class<JavaClass>(); diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h new file mode 100644 index 0000000000..917c3f5029 --- /dev/null +++ b/platform/android/api/jni_singleton.h @@ -0,0 +1,242 @@ +/*************************************************************************/ +/* jni_singleton.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef JNI_SINGLETON_H +#define JNI_SINGLETON_H + +#include <core/engine.h> +#include <core/variant.h> +#ifdef ANDROID_ENABLED +#include <platform/android/jni_utils.h> +#endif + +class JNISingleton : public Object { + + GDCLASS(JNISingleton, Object); + +#ifdef ANDROID_ENABLED + struct MethodData { + + jmethodID method; + Variant::Type ret_type; + Vector<Variant::Type> argtypes; + }; + + jobject instance; + Map<StringName, MethodData> method_map; +#endif + +public: + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +#ifdef ANDROID_ENABLED + Map<StringName, MethodData>::Element *E = method_map.find(p_method); + + // Check the method we're looking for is in the JNISingleton map and that + // the arguments match. + bool call_error = !E || E->get().argtypes.size() != p_argcount; + if (!call_error) { + for (int i = 0; i < p_argcount; i++) { + + if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) { + call_error = true; + break; + } + } + } + + if (call_error) { + // The method is not in this map, defaulting to the regular instance calls. + return Object::call(p_method, p_args, p_argcount, r_error); + } + + ERR_FAIL_COND_V(!instance, Variant()); + + r_error.error = Callable::CallError::CALL_OK; + + jvalue *v = nullptr; + + if (p_argcount) { + + v = (jvalue *)alloca(sizeof(jvalue) * p_argcount); + } + + JNIEnv *env = ThreadAndroid::get_env(); + + int res = env->PushLocalFrame(16); + + ERR_FAIL_COND_V(res != 0, Variant()); + + List<jobject> to_erase; + for (int i = 0; i < p_argcount; i++) { + + jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]); + v[i] = vr.val; + if (vr.obj) + to_erase.push_back(vr.obj); + } + + Variant ret; + + switch (E->get().ret_type) { + + case Variant::NIL: { + + env->CallVoidMethodA(instance, E->get().method, v); + } break; + case Variant::BOOL: { + + ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE; + } break; + case Variant::INT: { + + ret = env->CallIntMethodA(instance, E->get().method, v); + } break; + case Variant::FLOAT: { + + ret = env->CallFloatMethodA(instance, E->get().method, v); + } break; + case Variant::STRING: { + + jobject o = env->CallObjectMethodA(instance, E->get().method, v); + ret = jstring_to_string((jstring)o, env); + env->DeleteLocalRef(o); + } break; + case Variant::PACKED_STRING_ARRAY: { + + jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v); + + ret = _jobject_to_variant(env, arr); + + env->DeleteLocalRef(arr); + } break; + case Variant::PACKED_INT32_ARRAY: { + + jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v); + + int fCount = env->GetArrayLength(arr); + Vector<int> sarr; + sarr.resize(fCount); + + int *w = sarr.ptrw(); + env->GetIntArrayRegion(arr, 0, fCount, w); + ret = sarr; + env->DeleteLocalRef(arr); + } break; + case Variant::PACKED_FLOAT32_ARRAY: { + + jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v); + + int fCount = env->GetArrayLength(arr); + Vector<float> sarr; + sarr.resize(fCount); + + float *w = sarr.ptrw(); + env->GetFloatArrayRegion(arr, 0, fCount, w); + ret = sarr; + env->DeleteLocalRef(arr); + } break; + +#ifndef _MSC_VER +#warning This is missing 64 bits arrays, I have no idea how to do it in JNI +#endif + case Variant::DICTIONARY: { + + jobject obj = env->CallObjectMethodA(instance, E->get().method, v); + ret = _jobject_to_variant(env, obj); + env->DeleteLocalRef(obj); + + } break; + default: { + + env->PopLocalFrame(nullptr); + ERR_FAIL_V(Variant()); + } break; + } + + while (to_erase.size()) { + env->DeleteLocalRef(to_erase.front()->get()); + to_erase.pop_front(); + } + + env->PopLocalFrame(nullptr); + + return ret; +#else // ANDROID_ENABLED + + // Defaulting to the regular instance calls. + return Object::call(p_method, p_args, p_argcount, r_error); +#endif + } + +#ifdef ANDROID_ENABLED + jobject get_instance() const { + + return instance; + } + + void set_instance(jobject p_instance) { + + instance = p_instance; + } + + void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) { + + MethodData md; + md.method = p_method; + md.argtypes = p_args; + md.ret_type = p_ret_type; + method_map[p_name] = md; + } + + void add_signal(const StringName &p_name, const Vector<Variant::Type> &p_args) { + if (p_args.size() == 0) + ADD_SIGNAL(MethodInfo(p_name)); + else if (p_args.size() == 1) + ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"))); + else if (p_args.size() == 2) + ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"))); + else if (p_args.size() == 3) + ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"))); + else if (p_args.size() == 4) + ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"), PropertyInfo(p_args[3], "arg4"))); + else if (p_args.size() == 5) + ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"), PropertyInfo(p_args[3], "arg4"), PropertyInfo(p_args[4], "arg5"))); + } + +#endif + + JNISingleton() { +#ifdef ANDROID_ENABLED + instance = nullptr; +#endif + } +}; + +#endif // JNI_SINGLETON_H diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index b6c30d120c..1eb1ee0d29 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1932,6 +1932,7 @@ public: ImageLoader::load_image(path, launcher_adaptive_icon_background_image); } + Vector<String> invalid_abis(enabled_abis); while (ret == UNZ_OK) { //get filename @@ -1977,6 +1978,7 @@ public: bool enabled = false; for (int i = 0; i < enabled_abis.size(); ++i) { if (file.begins_with("lib/" + enabled_abis[i] + "/")) { + invalid_abis.erase(enabled_abis[i]); enabled = true; break; } @@ -2016,6 +2018,13 @@ public: ret = unzGoToNextFile(pkg); } + if (!invalid_abis.empty()) { + String unsupported_arch = String(", ").join(invalid_abis); + EditorNode::add_io_error("Missing libraries in the export template for the selected architectures: " + unsupported_arch + ".\n" + + "Please build a template with all required libraries, or uncheck the missing architectures in the export preset."); + CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND); + } + if (ep.step("Adding files...", 1)) { CLEANUP_AND_RETURN(ERR_SKIP); } diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 1a3bb77670..99080eeb3c 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -56,6 +56,11 @@ android { compileSdkVersion versions.compileSdk buildToolsVersion versions.buildTools + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + defaultConfig { // Feel free to modify the application id to your own. applicationId getExportPackageName() diff --git a/platform/android/java/app/settings.gradle b/platform/android/java/app/settings.gradle new file mode 100644 index 0000000000..33b863c7bf --- /dev/null +++ b/platform/android/java/app/settings.gradle @@ -0,0 +1,2 @@ +// Empty settings.gradle file to denote this directory as being the root project +// of the Godot custom build. diff --git a/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png Binary files differdeleted file mode 100644 index f849d8e90d..0000000000 --- a/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png +++ /dev/null diff --git a/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png Binary files differdeleted file mode 100644 index 1dfb28b33a..0000000000 --- a/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png +++ /dev/null diff --git a/platform/android/java/lib/res/drawable-xhdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-xhdpi/notify_panel_notification_icon_bg.png Binary files differdeleted file mode 100644 index 372b763ec5..0000000000 --- a/platform/android/java/lib/res/drawable-xhdpi/notify_panel_notification_icon_bg.png +++ /dev/null diff --git a/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png Binary files differdeleted file mode 100644 index 302a972049..0000000000 --- a/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png +++ /dev/null diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java index e3683704e1..a051164d15 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java @@ -34,6 +34,8 @@ import android.app.Activity; import android.content.Intent; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Log; import android.view.Surface; import android.view.View; import java.lang.reflect.Method; @@ -41,8 +43,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; +import org.godotengine.godot.BuildConfig; import org.godotengine.godot.Godot; /** @@ -70,7 +74,10 @@ import org.godotengine.godot.Godot; */ public abstract class GodotPlugin { + private static final String TAG = GodotPlugin.class.getSimpleName(); + private final Godot godot; + private final ConcurrentHashMap<String, SignalInfo> registeredSignals = new ConcurrentHashMap<>(); public GodotPlugin(Godot godot) { this.godot = godot; @@ -118,6 +125,13 @@ public abstract class GodotPlugin { nativeRegisterMethod(getPluginName(), method.getName(), method.getReturnType().getName(), pt); } + // Register the signals for this plugin. + for (SignalInfo signalInfo : getPluginSignals()) { + String signalName = signalInfo.getName(); + nativeRegisterSignal(getPluginName(), signalName, signalInfo.getParamTypesNames()); + registeredSignals.put(signalName, signalInfo); + } + // Get the list of gdnative libraries to register. Set<String> gdnativeLibrariesPaths = getPluginGDNativeLibrariesPaths(); if (!gdnativeLibrariesPaths.isEmpty()) { @@ -220,7 +234,17 @@ public abstract class GodotPlugin { * Returns the list of methods to be exposed to Godot. */ @NonNull - public abstract List<String> getPluginMethods(); + public List<String> getPluginMethods() { + return Collections.emptyList(); + } + + /** + * Returns the list of signals to be exposed to Godot. + */ + @NonNull + public Set<SignalInfo> getPluginSignals() { + return Collections.emptySet(); + } /** * Returns the paths for the plugin's gdnative libraries. @@ -253,6 +277,49 @@ public abstract class GodotPlugin { } /** + * Emit a registered Godot signal. + * @param signalName + * @param signalArgs + */ + protected void emitSignal(final String signalName, final Object... signalArgs) { + try { + // Check that the given signal is among the registered set. + SignalInfo signalInfo = registeredSignals.get(signalName); + if (signalInfo == null) { + throw new IllegalArgumentException( + "Signal " + signalName + " is not registered for this plugin."); + } + + // Validate the arguments count. + Class<?>[] signalParamTypes = signalInfo.getParamTypes(); + if (signalArgs.length != signalParamTypes.length) { + throw new IllegalArgumentException( + "Invalid arguments count. Should be " + signalParamTypes.length + " but is " + signalArgs.length); + } + + // Validate the argument's types. + for (int i = 0; i < signalParamTypes.length; i++) { + if (!signalParamTypes[i].isInstance(signalArgs[i])) { + throw new IllegalArgumentException( + "Invalid type for argument #" + i + ". Should be of type " + signalParamTypes[i].getName()); + } + } + + runOnRenderThread(new Runnable() { + @Override + public void run() { + nativeEmitSignal(getPluginName(), signalName, signalArgs); + } + }); + } catch (IllegalArgumentException exception) { + Log.w(TAG, exception.getMessage()); + if (BuildConfig.DEBUG) { + throw exception; + } + } + } + + /** * Used to setup a {@link GodotPlugin} instance. * @param p_name Name of the instance. */ @@ -272,4 +339,20 @@ public abstract class GodotPlugin { * @param gdnlibPaths Paths to the libraries relative to the 'assets' directory. */ private native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths); + + /** + * Used to complete registration of the {@link GodotPlugin} instance's methods. + * @param pluginName Name of the plugin + * @param signalName Name of the signal to register + * @param signalParamTypes Signal parameters types + */ + private native void nativeRegisterSignal(String pluginName, String signalName, String[] signalParamTypes); + + /** + * Used to emit signal by {@link GodotPlugin} instance. + * @param pluginName Name of the plugin + * @param signalName Name of the signal to emit + * @param signalParams Signal parameters + */ + private native void nativeEmitSignal(String pluginName, String signalName, Object[] signalParams); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java new file mode 100644 index 0000000000..f907706889 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java @@ -0,0 +1,98 @@ +/*************************************************************************/ +/* SignalInfo.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.plugin; + +import android.support.annotation.NonNull; +import android.text.TextUtils; +import java.util.Arrays; + +/** + * Store information about a {@link GodotPlugin}'s signal. + */ +public final class SignalInfo { + + private final String name; + private final Class<?>[] paramTypes; + private final String[] paramTypesNames; + + public SignalInfo(@NonNull String signalName, Class<?>... paramTypes) { + if (TextUtils.isEmpty(signalName)) { + throw new IllegalArgumentException("Invalid signal name: " + signalName); + } + + this.name = signalName; + this.paramTypes = paramTypes == null ? new Class<?>[ 0 ] : paramTypes; + this.paramTypesNames = new String[this.paramTypes.length]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypesNames[i] = this.paramTypes[i].getName(); + } + } + + public String getName() { + return name; + } + + Class<?>[] getParamTypes() { + return paramTypes; + } + + String[] getParamTypesNames() { + return paramTypesNames; + } + + @Override + public String toString() { + return "SignalInfo{" + + + "name='" + name + '\'' + + ", paramsTypes=" + Arrays.toString(paramTypes) + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SignalInfo)) { + return false; + } + + SignalInfo that = (SignalInfo)o; + + return name.equals(that.name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } +} diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index c103e74222..8b38113e09 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -35,6 +35,7 @@ #include "android/asset_manager_jni.h" #include "api/java_class_wrapper.h" +#include "api/jni_singleton.h" #include "audio_driver_jandroid.h" #include "core/engine.h" #include "core/input/input_filter.h" @@ -162,6 +163,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc } java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity())); + ClassDB::register_class<JNISingleton>(); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height) { diff --git a/platform/android/jni_utils.h b/platform/android/jni_utils.h index b9ee243308..c2baa51b4a 100644 --- a/platform/android/jni_utils.h +++ b/platform/android/jni_utils.h @@ -53,190 +53,4 @@ Variant::Type get_jni_type(const String &p_type); const char *get_jni_sig(const String &p_type); -class JNISingleton : public Object { - - GDCLASS(JNISingleton, Object); - - struct MethodData { - - jmethodID method; - Variant::Type ret_type; - Vector<Variant::Type> argtypes; - }; - - jobject instance; - Map<StringName, MethodData> method_map; - -public: - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - - ERR_FAIL_COND_V(!instance, Variant()); - - r_error.error = Callable::CallError::CALL_OK; - - Map<StringName, MethodData>::Element *E = method_map.find(p_method); - if (!E) { - - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); - } - - int ac = E->get().argtypes.size(); - if (ac < p_argcount) { - - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = ac; - return Variant(); - } - - if (ac > p_argcount) { - - r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = ac; - return Variant(); - } - - for (int i = 0; i < p_argcount; i++) { - - if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) { - - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = i; - r_error.expected = E->get().argtypes[i]; - } - } - - jvalue *v = nullptr; - - if (p_argcount) { - - v = (jvalue *)alloca(sizeof(jvalue) * p_argcount); - } - - JNIEnv *env = ThreadAndroid::get_env(); - - int res = env->PushLocalFrame(16); - - ERR_FAIL_COND_V(res != 0, Variant()); - - List<jobject> to_erase; - for (int i = 0; i < p_argcount; i++) { - - jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]); - v[i] = vr.val; - if (vr.obj) - to_erase.push_back(vr.obj); - } - - Variant ret; - - switch (E->get().ret_type) { - - case Variant::NIL: { - - env->CallVoidMethodA(instance, E->get().method, v); - } break; - case Variant::BOOL: { - - ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE; - } break; - case Variant::INT: { - - ret = env->CallIntMethodA(instance, E->get().method, v); - } break; - case Variant::FLOAT: { - - ret = env->CallFloatMethodA(instance, E->get().method, v); - } break; - case Variant::STRING: { - - jobject o = env->CallObjectMethodA(instance, E->get().method, v); - ret = jstring_to_string((jstring)o, env); - env->DeleteLocalRef(o); - } break; - case Variant::PACKED_STRING_ARRAY: { - - jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v); - - ret = _jobject_to_variant(env, arr); - - env->DeleteLocalRef(arr); - } break; - case Variant::PACKED_INT32_ARRAY: { - - jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v); - - int fCount = env->GetArrayLength(arr); - Vector<int> sarr; - sarr.resize(fCount); - - int *w = sarr.ptrw(); - env->GetIntArrayRegion(arr, 0, fCount, w); - ret = sarr; - env->DeleteLocalRef(arr); - } break; - case Variant::PACKED_FLOAT32_ARRAY: { - - jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v); - - int fCount = env->GetArrayLength(arr); - Vector<float> sarr; - sarr.resize(fCount); - - float *w = sarr.ptrw(); - env->GetFloatArrayRegion(arr, 0, fCount, w); - ret = sarr; - env->DeleteLocalRef(arr); - } break; - -#ifndef _MSC_VER -#warning This is missing 64 bits arrays, I have no idea how to do it in JNI -#endif - case Variant::DICTIONARY: { - - jobject obj = env->CallObjectMethodA(instance, E->get().method, v); - ret = _jobject_to_variant(env, obj); - env->DeleteLocalRef(obj); - - } break; - default: { - - env->PopLocalFrame(nullptr); - ERR_FAIL_V(Variant()); - } break; - } - - while (to_erase.size()) { - env->DeleteLocalRef(to_erase.front()->get()); - to_erase.pop_front(); - } - - env->PopLocalFrame(nullptr); - - return ret; - } - - jobject get_instance() const { - - return instance; - } - void set_instance(jobject p_instance) { - - instance = p_instance; - } - - void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) { - - MethodData md; - md.method = p_method; - md.argtypes = p_args; - md.ret_type = p_ret_type; - method_map[p_name] = md; - } - - JNISingleton() { - instance = nullptr; - } -}; - #endif // JNI_UTILS_H diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp index 7413236e5d..c3bfb2f2ed 100644 --- a/platform/android/plugin/godot_plugin_jni.cpp +++ b/platform/android/plugin/godot_plugin_jni.cpp @@ -33,6 +33,7 @@ #include <core/engine.h> #include <core/error_macros.h> #include <core/project_settings.h> +#include <platform/android/api/jni_singleton.h> #include <platform/android/jni_utils.h> #include <platform/android/string_android.h> @@ -43,7 +44,7 @@ extern "C" { JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name) { String singname = jstring_to_string(name, env); - JNISingleton *s = memnew(JNISingleton); + JNISingleton *s = (JNISingleton *)ClassDB::instance("JNISingleton"); s->set_instance(env->NewGlobalRef(obj)); jni_singletons[singname] = s; @@ -86,6 +87,51 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis s->add_method(mname, mid, types, get_jni_type(retval)); } +JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types) { + String singleton_name = jstring_to_string(j_plugin_name, env); + + ERR_FAIL_COND(!jni_singletons.has(singleton_name)); + + JNISingleton *singleton = jni_singletons.get(singleton_name); + + String signal_name = jstring_to_string(j_signal_name, env); + Vector<Variant::Type> types; + + int stringCount = env->GetArrayLength(j_signal_param_types); + + for (int i = 0; i < stringCount; i++) { + + jstring j_signal_param_type = (jstring)env->GetObjectArrayElement(j_signal_param_types, i); + const String signal_param_type = jstring_to_string(j_signal_param_type, env); + types.push_back(get_jni_type(signal_param_type)); + } + + singleton->add_signal(signal_name, types); +} + +JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params) { + String singleton_name = jstring_to_string(j_plugin_name, env); + + ERR_FAIL_COND(!jni_singletons.has(singleton_name)); + + JNISingleton *singleton = jni_singletons.get(singleton_name); + + String signal_name = jstring_to_string(j_signal_name, env); + + int count = env->GetArrayLength(j_signal_params); + const Variant *args[count]; + + for (int i = 0; i < count; i++) { + + jobject j_param = env->GetObjectArrayElement(j_signal_params, i); + Variant variant = _jobject_to_variant(env, j_param); + args[i] = &variant; + env->DeleteLocalRef(j_param); + }; + + singleton->emit_signal(signal_name, args, count); +} + JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths) { int gdnlib_count = env->GetArrayLength(gdnlib_paths); if (gdnlib_count == 0) { diff --git a/platform/android/plugin/godot_plugin_jni.h b/platform/android/plugin/godot_plugin_jni.h index 0d613d3bfe..80ce332e7c 100644 --- a/platform/android/plugin/godot_plugin_jni.h +++ b/platform/android/plugin/godot_plugin_jni.h @@ -37,6 +37,8 @@ extern "C" { JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name); JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args); +JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types); +JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params); JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths); } diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index d55b21bc24..ed8481db4a 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -321,16 +321,14 @@ void PathFollow2D::set_offset(float p_offset) { offset = p_offset; if (path) { - if (path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { + if (path->get_curve().is_valid()) { float path_length = path->get_curve()->get_baked_length(); if (loop) { - while (offset > path_length) - offset -= path_length; - - while (offset < 0) - offset += path_length; - + offset = Math::fposmod(offset, path_length); + if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) { + offset = path_length; + } } else { offset = CLAMP(offset, 0, path_length); } diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 2455d46e43..81a5c6f4f3 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -272,6 +272,7 @@ void Light3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR); ADD_GROUP("Editor", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only"); ADD_GROUP("", ""); @@ -291,6 +292,7 @@ void Light3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE); + BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR); BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS); BIND_ENUM_CONSTANT(PARAM_MAX); @@ -335,6 +337,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) { set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5); set_param(PARAM_SHADOW_FADE_START, 0.8); set_param(PARAM_SHADOW_PANCAKE_SIZE, 20.0); + set_param(PARAM_SHADOW_BLUR, 1.0); set_param(PARAM_SHADOW_BIAS, 0.02); set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0); set_param(PARAM_TRANSMITTANCE_BIAS, 0.05); diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 21810e03dd..21e14f0e8b 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -58,6 +58,7 @@ public: PARAM_SHADOW_NORMAL_BIAS = RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS, PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS, PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE, + PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR, PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS, PARAM_MAX = RS::LIGHT_PARAM_MAX }; diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index f06135f53d..4a425d1e0e 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -316,16 +316,14 @@ void PathFollow3D::set_offset(float p_offset) { offset = p_offset; if (path) { - if (path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { + if (path->get_curve().is_valid()) { float path_length = path->get_curve()->get_baked_length(); if (loop) { - while (offset > path_length) - offset -= path_length; - - while (offset < 0) - offset += path_length; - + offset = Math::fposmod(offset, path_length); + if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) { + offset = path_length; + } } else { offset = CLAMP(offset, 0, path_length); } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 30ecd651b1..a03d6d0cdc 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -340,8 +340,8 @@ void OptionButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items"); // "selected" property must come after "items", otherwise GH-10213 occurs. ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected"); - ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index"))); + ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index"))); } OptionButton::OptionButton() { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 0b314d57c5..9fab9005f9 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -407,7 +407,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & cw = tab_size * font->get_char_size(' ').width; } - if (end > 0 && w + cw + begin > p_width) { + if (end > 0 && fw + cw + begin > p_width) { break; //don't allow lines longer than assigned width } @@ -416,7 +416,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & end++; } CHECK_HEIGHT(fh); - ENSURE_WIDTH(w); + ENSURE_WIDTH(fw); line_ascent = MAX(line_ascent, ascent); line_descent = MAX(line_descent, descent); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 41f31617d2..0418b20e9c 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1421,10 +1421,14 @@ SceneTree::SceneTree() { root->set_as_audio_listener_2d(true); current_scene = nullptr; - int msaa_mode = GLOBAL_DEF("rendering/quality/filters/msaa", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x")); + int msaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/msaa", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x")); root->set_msaa(Viewport::MSAA(msaa_mode)); + int ssaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/screen_space_aa", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_aa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA")); + root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode)); + { //load default fallback environment //get possible extensions List<String> exts; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 1cfc3b0260..a3036da870 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3173,7 +3173,7 @@ int Viewport::gui_get_canvas_sort_index() { void Viewport::set_msaa(MSAA p_msaa) { - ERR_FAIL_INDEX(p_msaa, 7); + ERR_FAIL_INDEX(p_msaa, MSAA_MAX); if (msaa == p_msaa) return; msaa = p_msaa; @@ -3185,6 +3185,19 @@ Viewport::MSAA Viewport::get_msaa() const { return msaa; } +void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) { + + ERR_FAIL_INDEX(p_screen_space_aa, SCREEN_SPACE_AA_MAX); + if (screen_space_aa == p_screen_space_aa) + return; + screen_space_aa = p_screen_space_aa; + RS::get_singleton()->viewport_set_screen_space_aa(viewport, RS::ViewportScreenSpaceAA(p_screen_space_aa)); +} + +Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const { + + return screen_space_aa; +} void Viewport::set_debug_draw(DebugDraw p_debug_draw) { debug_draw = p_debug_draw; @@ -3371,6 +3384,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa); ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa); + ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa); + ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa); + ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw); ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw); @@ -3444,6 +3460,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally"); ADD_GROUP("Rendering", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); ADD_GROUP("Canvas Items", "canvas_item_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter"); @@ -3586,7 +3603,7 @@ Viewport::Viewport() { gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; msaa = MSAA_DISABLED; - + screen_space_aa = SCREEN_SPACE_AA_DISABLED; debug_draw = DEBUG_DRAW_DISABLED; snap_controls_to_pixels = true; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index ab3987d16d..0cd7f6fdaa 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -106,6 +106,13 @@ public: MSAA_4X, MSAA_8X, MSAA_16X, + MSAA_MAX + }; + + enum ScreenSpaceAA { + SCREEN_SPACE_AA_DISABLED, + SCREEN_SPACE_AA_FXAA, + SCREEN_SPACE_AA_MAX }; enum RenderInfo { @@ -272,6 +279,7 @@ private: ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4]; MSAA msaa; + ScreenSpaceAA screen_space_aa; Ref<ViewportTexture> default_texture; Set<ViewportTexture *> viewport_textures; @@ -505,6 +513,9 @@ public: void set_msaa(MSAA p_msaa); MSAA get_msaa() const; + void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa); + ScreenSpaceAA get_screen_space_aa() const; + Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const; Vector2 get_camera_rect_size() const; @@ -624,6 +635,7 @@ public: VARIANT_ENUM_CAST(SubViewport::UpdateMode); VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv); VARIANT_ENUM_CAST(Viewport::MSAA); +VARIANT_ENUM_CAST(Viewport::ScreenSpaceAA); VARIANT_ENUM_CAST(Viewport::DebugDraw); VARIANT_ENUM_CAST(SubViewport::ClearMode); VARIANT_ENUM_CAST(Viewport::RenderInfo); diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index 96e8c61020..2bd335e6c0 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -257,7 +257,7 @@ public: _FORCE_INLINE_ void add_force(const Vector3 &p_force, const Vector3 &p_pos) { applied_force += p_force; - applied_torque += p_pos.cross(p_force); + applied_torque += (p_pos - center_of_mass).cross(p_force); } _FORCE_INLINE_ void add_torque(const Vector3 &p_torque) { diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp index 1f433ec6a5..e15aeca842 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp @@ -497,28 +497,28 @@ void Generic6DOFJoint3DSW::set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DO } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning } @@ -597,28 +597,28 @@ real_t Generic6DOFJoint3DSW::get_param(Vector3::Axis p_axis, PhysicsServer3D::G6 } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning } @@ -643,13 +643,13 @@ void Generic6DOFJoint3DSW::set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOF m_angularLimits[p_axis].m_enableMotor = p_value; } break; case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } @@ -671,13 +671,13 @@ bool Generic6DOFJoint3DSW::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOF return m_angularLimits[p_axis].m_enableMotor; } break; case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: { - // Not implemented in GodotPhysics backend + // Not implemented in GodotPhysics3D backend } break; case PhysicsServer3D::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index bc42c2fd9e..d8da6e715b 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -70,7 +70,7 @@ RID PhysicsServer3DSW::shape_create(ShapeType p_shape) { } break; case SHAPE_CYLINDER: { - ERR_FAIL_V_MSG(RID(), "CylinderShape3D is not supported in GodotPhysics. Please switch to Bullet in the Project Settings."); + ERR_FAIL_V_MSG(RID(), "CylinderShape3D is not supported in GodotPhysics3D. Please switch to Bullet in the Project Settings."); } break; case SHAPE_CONVEX_POLYGON: { diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index dadd26dade..556f9cd8e3 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -178,15 +178,15 @@ void register_server_types() { GLOBAL_DEF(PhysicsServer2DManager::setting_property_name, "DEFAULT"); ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer2DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT")); - PhysicsServer2DManager::register_server("GodotPhysics", &_createGodotPhysics2DCallback); - PhysicsServer2DManager::set_default_server("GodotPhysics"); + PhysicsServer2DManager::register_server("GodotPhysics2D", &_createGodotPhysics2DCallback); + PhysicsServer2DManager::set_default_server("GodotPhysics2D"); // Physics 3D GLOBAL_DEF(PhysicsServer3DManager::setting_property_name, "DEFAULT"); ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer3DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT")); - PhysicsServer3DManager::register_server("GodotPhysics", &_createGodotPhysics3DCallback); - PhysicsServer3DManager::set_default_server("GodotPhysics"); + PhysicsServer3DManager::register_server("GodotPhysics3D", &_createGodotPhysics3DCallback); + PhysicsServer3DManager::set_default_server("GodotPhysics3D"); } void unregister_server_types() { diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h index cf0afe6097..b28ec8e50f 100644 --- a/servers/rendering/rasterizer.h +++ b/servers/rendering/rasterizer.h @@ -106,7 +106,8 @@ public: virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; - virtual void shadow_filter_set(RS::ShadowFilter p_filter) = 0; + virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0; + virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; struct InstanceBase; @@ -263,7 +264,7 @@ public: virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa) = 0; virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0; virtual bool screen_space_roughness_limiter_is_active() const = 0; diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index 79b1686232..3da16ccb79 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -99,7 +99,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use u.ids.push_back(p_texture); uniforms.push_back(u); //any thing with the same configuration (one texture in binding 0 for set 0), is good - RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, blur.shader.version_get_shader(blur.shader_version, 0), 0); + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0); texture_to_uniform_set_cache[p_texture] = uniform_set; @@ -204,154 +204,199 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1 return uniform_set; } -void RasterizerEffectsRD::copy_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { +void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance) { + zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); if (p_flip_y) { - blur.push_constant.flags |= BLUR_FLAG_FLIP_Y; + copy_to_fb.push_constant.flip_y = true; + } + if (p_force_luminance) { + copy_to_fb.push_constant.force_luminance = true; } - - blur.push_constant.camera_z_near = p_z_near; - blur.push_constant.camera_z_far = p_z_far; RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_LINEARIZE_DEPTH].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); RD::get_singleton()->draw_list_draw(draw_list, true); RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y, bool p_force_luminance) { +void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst) { - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + zeromem(©.push_constant, sizeof(CopyPushConstant)); if (p_flip_y) { - blur.push_constant.flags |= BLUR_FLAG_FLIP_Y; + copy.push_constant.flags |= COPY_FLAG_FLIP_Y; } + if (p_force_luminance) { - blur.push_constant.flags |= BLUR_COPY_FORCE_LUMINANCE; + copy.push_constant.flags |= COPY_FLAG_FORCE_LUMINANCE; } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + if (p_all_source) { + copy.push_constant.flags |= COPY_FLAG_ALL_SOURCE; + } + + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_rect.size.width; + copy.push_constant.section[3] = p_rect.size.height; + copy.push_constant.target[0] = p_rect.position.x; + copy.push_constant.target[1] = p_rect.position.y; + + int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; + int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8_bit_dst ? COPY_MODE_SIMPLY_COPY_8BIT : COPY_MODE_SIMPLY_COPY]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::region_copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region) { +void RasterizerEffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { + + zeromem(©.push_constant, sizeof(CopyPushConstant)); + if (p_flip_y) { + copy.push_constant.flags |= COPY_FLAG_FLIP_Y; + } + + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_rect.size.width; + copy.push_constant.section[3] = p_rect.size.height; + copy.push_constant.target[0] = p_rect.position.x; + copy.push_constant.target[1] = p_rect.position.y; + copy.push_constant.camera_z_far = p_z_far; + copy.push_constant.camera_z_near = p_z_near; - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; + int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_LINEARIZE_DEPTH]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); +} - if (p_region != Rect2()) { - blur.push_constant.flags = BLUR_FLAG_USE_BLUR_SECTION; - blur.push_constant.section[0] = p_region.position.x; - blur.push_constant.section[1] = p_region.position.y; - blur.push_constant.section[2] = p_region.size.width; - blur.push_constant.section[3] = p_region.size.height; +void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { + + zeromem(©.push_constant, sizeof(CopyPushConstant)); + if (p_flip_y) { + copy.push_constant.flags |= COPY_FLAG_FLIP_Y; } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_rect.size.width; + copy.push_constant.section[3] = p_rect.size.height; + copy.push_constant.target[0] = p_rect.position.x; + copy.push_constant.target[1] = p_rect.position.y; + + int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; + int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_SIMPLY_COPY_DEPTH]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region) { +void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + zeromem(©.push_constant, sizeof(CopyPushConstant)); uint32_t base_flags = 0; - if (p_region != Rect2()) { - base_flags = BLUR_FLAG_USE_BLUR_SECTION; - blur.push_constant.section[0] = p_region.position.x; - blur.push_constant.section[1] = p_region.position.y; - blur.push_constant.section[2] = p_region.size.width; - blur.push_constant.section[3] = p_region.size.height; - } - - blur.push_constant.pixel_size[0] = p_pixel_size.x; - blur.push_constant.pixel_size[1] = p_pixel_size.y; + copy.push_constant.section[0] = p_region.position.x; + copy.push_constant.section[1] = p_region.position.y; + copy.push_constant.section[2] = p_region.size.width; + copy.push_constant.section[3] = p_region.size.height; + int32_t x_groups = (p_region.size.width - 1) / 8 + 1; + int32_t y_groups = (p_region.size.height - 1) / 8 + 1; //HORIZONTAL - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::DrawListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_GAUSSIAN_COPY_8BIT : COPY_MODE_GAUSSIAN_COPY]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 0); - blur.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL; + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + + RD::get_singleton()->compute_list_add_barrier(compute_list); //VERTICAL - draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 0); - blur.push_constant.flags = base_flags; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + copy.push_constant.flags = base_flags; + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { +void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + zeromem(©.push_constant, sizeof(CopyPushConstant)); - BlurMode blur_mode = p_first_pass && p_auto_exposure.is_valid() ? BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : BLUR_MODE_GAUSSIAN_GLOW; + CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW; uint32_t base_flags = 0; - blur.push_constant.pixel_size[0] = p_pixel_size.x; - blur.push_constant.pixel_size[1] = p_pixel_size.y; + int32_t x_groups = (p_size.width - 1) / 8 + 1; + int32_t y_groups = (p_size.height - 1) / 8 + 1; + + copy.push_constant.section[2] = p_size.x; + copy.push_constant.section[3] = p_size.y; - blur.push_constant.glow_strength = p_strength; - blur.push_constant.glow_bloom = p_bloom; - blur.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold; - blur.push_constant.glow_hdr_scale = p_hdr_bleed_scale; - blur.push_constant.glow_exposure = p_exposure; - blur.push_constant.glow_white = 0; //actually unused - blur.push_constant.glow_luminance_cap = p_luminance_cap; + copy.push_constant.glow_strength = p_strength; + copy.push_constant.glow_bloom = p_bloom; + copy.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold; + copy.push_constant.glow_hdr_scale = p_hdr_bleed_scale; + copy.push_constant.glow_exposure = p_exposure; + copy.push_constant.glow_white = 0; //actually unused + copy.push_constant.glow_luminance_cap = p_luminance_cap; - blur.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also + copy.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also //HORIZONTAL - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3); if (p_auto_exposure.is_valid() && p_first_pass) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_auto_exposure), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_auto_exposure), 1); } - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - blur.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL | (p_first_pass ? BLUR_FLAG_GLOW_FIRST_PASS : 0); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); - blur_mode = BLUR_MODE_GAUSSIAN_GLOW; + copy_mode = COPY_MODE_GAUSSIAN_GLOW; //VERTICAL - draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3); - blur.push_constant.flags = base_flags; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + copy.push_constant.flags = base_flags; + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_roughness, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera) { @@ -560,37 +605,49 @@ void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_framebuffer, const Vector2 &p_pixel_size) { +void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + zeromem(©.push_constant, sizeof(CopyPushConstant)); - blur.push_constant.pixel_size[0] = p_pixel_size.x; - blur.push_constant.pixel_size[1] = p_pixel_size.y; + copy.push_constant.section[0] = 0; + copy.push_constant.section[1] = 0; + copy.push_constant.section[2] = p_size.width; + copy.push_constant.section[3] = p_size.height; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_MIPMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + int32_t x_groups = (p_size.width - 1) / 8 + 1; + int32_t y_groups = (p_size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_MIPMAP]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3); + RD::get_singleton()->compute_list_set_push_constant(compute_list, ©.push_constant, sizeof(CopyPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) { +void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) { CopyToDPPushConstant push_constant; + push_constant.screen_size[0] = p_rect.size.x; + push_constant.screen_size[1] = p_rect.size.y; + push_constant.dest_offset[0] = p_rect.position.x; + push_constant.dest_offset[1] = p_rect.position.y; push_constant.bias = p_bias; push_constant.z_far = p_z_far; push_constant.z_near = p_z_near; push_constant.z_flip = p_dp_flip; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy.pipelines[COPY_MODE_CUBE_TO_DP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); + int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; + int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cube_to_dp.pipeline); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(CopyToDPPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_end(); } void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { @@ -619,7 +676,11 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, tonemap.push_constant.use_color_correction = p_settings.use_color_correction; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + tonemap.push_constant.use_fxaa = p_settings.use_fxaa; + tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; + tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); @@ -1129,33 +1190,38 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_ RasterizerEffectsRD::RasterizerEffectsRD() { - { // Initialize blur - Vector<String> blur_modes; - blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); - blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); - blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_LOW\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_MEDIUM\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_HIGH\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_LOW\n#define DOF_NEAR_BLUR_MERGE\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_MEDIUM\n#define DOF_NEAR_BLUR_MERGE\n"); - blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_HIGH\n#define DOF_NEAR_BLUR_MERGE\n"); - blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_LOW\n"); - blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_MEDIUM\n"); - blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_HIGH\n"); - blur_modes.push_back("\n#define MODE_SSAO_MERGE\n"); - blur_modes.push_back("\n#define MODE_SIMPLE_COPY\n"); - blur_modes.push_back("\n#define MODE_MIPMAP\n"); - blur_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n"); - - blur.shader.initialize(blur_modes); - zeromem(&blur.push_constant, sizeof(BlurPushConstant)); - blur.shader_version = blur.shader.version_create(); - - for (int i = 0; i < BLUR_MODE_MAX; i++) { - blur.pipelines[i].setup(blur.shader.version_get_shader(blur.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + { // Initialize copy + Vector<String> copy_modes; + copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); + copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n#define DST_IMAGE_8BIT\n"); + copy_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); + copy_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); + copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n"); + copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n#define DST_IMAGE_8BIT\n"); + copy_modes.push_back("\n#define MODE_SIMPLE_COPY_DEPTH\n"); + copy_modes.push_back("\n#define MODE_MIPMAP\n"); + copy_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n"); + + copy.shader.initialize(copy_modes); + zeromem(©.push_constant, sizeof(CopyPushConstant)); + copy.shader_version = copy.shader.version_create(); + + for (int i = 0; i < COPY_MODE_MAX; i++) { + copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i)); } } + { + Vector<String> copy_modes; + copy_modes.push_back("\n"); + + copy_to_fb.shader.initialize(copy_modes); + + copy_to_fb.shader_version = copy_to_fb.shader.version_create(); + + //use additive + + copy_to_fb.pipeline.setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } { // Initialize roughness @@ -1202,15 +1268,13 @@ RasterizerEffectsRD::RasterizerEffectsRD() { { // Initialize copier Vector<String> copy_modes; - copy_modes.push_back("\n#define MODE_CUBE_TO_DP\n"); + copy_modes.push_back("\n"); - copy.shader.initialize(copy_modes); + cube_to_dp.shader.initialize(copy_modes); - copy.shader_version = copy.shader.version_create(); + cube_to_dp.shader_version = cube_to_dp.shader.version_create(); - for (int i = 0; i < COPY_MODE_MAX; i++) { - copy.pipelines[i].setup(copy.shader.version_get_shader(copy.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); - } + cube_to_dp.pipeline = RD::get_singleton()->compute_pipeline_create(cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0)); } { @@ -1482,9 +1546,10 @@ RasterizerEffectsRD::~RasterizerEffectsRD() { RD::get_singleton()->free(index_buffer); //array gets freed as dependency RD::get_singleton()->free(filter.coefficient_buffer); - blur.shader.version_free(blur.shader_version); bokeh.shader.version_free(bokeh.shader_version); copy.shader.version_free(copy.shader_version); + copy_to_fb.shader.version_free(copy_to_fb.shader_version); + cube_to_dp.shader.version_free(cube_to_dp.shader_version); cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version); filter.shader.version_free(filter.shader_version); luminance_reduce.shader.version_free(luminance_reduce.shader_version); diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h index c0c62eb0be..aec381d193 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h @@ -33,9 +33,10 @@ #include "core/math/camera_matrix.h" #include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/blur.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/copy.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl.gen.h" @@ -55,71 +56,78 @@ class RasterizerEffectsRD { - enum BlurMode { - BLUR_MODE_GAUSSIAN_BLUR, - BLUR_MODE_GAUSSIAN_GLOW, - BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, - BLUR_MODE_DOF_NEAR_LOW, - BLUR_MODE_DOF_NEAR_MEDIUM, - BLUR_MODE_DOF_NEAR_HIGH, - BLUR_MODE_DOF_NEAR_MERGE_LOW, - BLUR_MODE_DOF_NEAR_MERGE_MEDIUM, - BLUR_MODE_DOF_NEAR_MERGE_HIGH, - BLUR_MODE_DOF_FAR_LOW, - BLUR_MODE_DOF_FAR_MEDIUM, - BLUR_MODE_DOF_FAR_HIGH, - BLUR_MODE_SSAO_MERGE, - BLUR_MODE_SIMPLY_COPY, - BLUR_MODE_MIPMAP, - BLUR_MODE_LINEARIZE_DEPTH, - BLUR_MODE_MAX, + enum CopyMode { + COPY_MODE_GAUSSIAN_COPY, + COPY_MODE_GAUSSIAN_COPY_8BIT, + COPY_MODE_GAUSSIAN_GLOW, + COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, + COPY_MODE_SIMPLY_COPY, + COPY_MODE_SIMPLY_COPY_8BIT, + COPY_MODE_SIMPLY_COPY_DEPTH, + COPY_MODE_MIPMAP, + COPY_MODE_LINEARIZE_DEPTH, + COPY_MODE_MAX, }; enum { - BLUR_FLAG_HORIZONTAL = (1 << 0), - BLUR_FLAG_USE_BLUR_SECTION = (1 << 1), - BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2), - BLUR_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3), - BLUR_FLAG_GLOW_FIRST_PASS = (1 << 4), - BLUR_FLAG_FLIP_Y = (1 << 5), - BLUR_COPY_FORCE_LUMINANCE = (1 << 6) + COPY_FLAG_HORIZONTAL = (1 << 0), + COPY_FLAG_USE_COPY_SECTION = (1 << 1), + COPY_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2), + COPY_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3), + COPY_FLAG_GLOW_FIRST_PASS = (1 << 4), + COPY_FLAG_FLIP_Y = (1 << 5), + COPY_FLAG_FORCE_LUMINANCE = (1 << 6), + COPY_FLAG_ALL_SOURCE = (1 << 7) }; - struct BlurPushConstant { - float section[4]; - float pixel_size[2]; + struct CopyPushConstant { + + int32_t section[4]; + int32_t target[2]; uint32_t flags; uint32_t pad; - //glow + // Glow. float glow_strength; float glow_bloom; float glow_hdr_threshold; float glow_hdr_scale; + float glow_exposure; float glow_white; float glow_luminance_cap; float glow_auto_exposure_grey; - //dof - float dof_begin; - float dof_end; - float dof_radius; - float dof_pad; - - float dof_dir[2]; + // DOF. float camera_z_far; float camera_z_near; + uint32_t pad2[2]; + }; + + struct Copy { + CopyPushConstant push_constant; + CopyShaderRD shader; + RID shader_version; + RID pipelines[COPY_MODE_MAX]; + + } copy; + + struct CopyToFbPushConstant { - float ssao_color[4]; + float section[4]; + float pixel_size[2]; + uint32_t flip_y; + uint32_t use_section; + uint32_t force_luminance; + uint32_t pad[3]; }; - struct Blur { - BlurPushConstant push_constant; - BlurShaderRD shader; + struct CopyToFb { + CopyToFbPushConstant push_constant; + CopyToFbShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[BLUR_MODE_MAX]; + RenderPipelineVertexFormatCacheRD pipeline; - } blur; + } copy_to_fb; struct CubemapRoughnessPushConstant { uint32_t face_id; @@ -162,10 +170,17 @@ class RasterizerEffectsRD { float exposure; float white; float auto_exposure_grey; + + float pixel_size[2]; + uint32_t use_fxaa; + uint32_t pad; }; + /* tonemap actually writes to a framebuffer, which is + * better to do using the raster pipeline rather than + * comptute, as that framebuffer might be in different formats + */ struct Tonemap { - TonemapPushConstant push_constant; TonemapShaderRD shader; RID shader_version; @@ -196,23 +211,20 @@ class RasterizerEffectsRD { } luminance_reduce; struct CopyToDPPushConstant { + int32_t screen_size[2]; + int32_t dest_offset[2]; float bias; float z_far; float z_near; uint32_t z_flip; }; - enum CopyMode { - COPY_MODE_CUBE_TO_DP, - COPY_MODE_MAX - }; - - struct Copy { + struct CoptToDP { - CopyShaderRD shader; + CubeToDpShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[COPY_MODE_MAX]; - } copy; + RID pipeline; + } cube_to_dp; struct BokehPushConstant { uint32_t size[2]; @@ -392,6 +404,10 @@ class RasterizerEffectsRD { SPECULAR_MERGE_MAX }; + /* Specular merge must be done using raster, rather than compute + * because it must continue the existing color buffer + */ + struct SpecularMerge { SpecularMergeShaderRD shader; @@ -537,17 +553,16 @@ class RasterizerEffectsRD { RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2); public: - //TODO must re-do most of the shaders in compute - - void region_copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region); - void copy_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y = false, bool p_force_luminance = false); - void copy_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y, float p_z_near, float p_z_far); - void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region); - void gaussian_glow(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); + void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false); + void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false); + void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); + void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far); + void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); + void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); - void make_mipmap(RID p_source_rd_texture, RID p_framebuffer_half, const Vector2 &p_pixel_size); - void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); + void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); + void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); @@ -584,6 +599,9 @@ public: bool use_color_correction = false; RID color_correction_texture; + + bool use_fxaa = false; + Vector2i texture_size; }; void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp index ec05c9e964..8ed58c0ef5 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -77,6 +77,13 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_arra } } +static _FORCE_INLINE_ void store_soft_shadow_kernel(const float *p_kernel, float *p_array) { + + for (int i = 0; i < 128; i++) { + p_array[i] = p_kernel[i]; + } +} + /* SCENE SHADER */ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { //compile @@ -535,46 +542,100 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_specular() { tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = width; tf.height = height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + if (msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } specular = RD::get_singleton()->texture_create(tf, RD::TextureView()); - { - Vector<RID> fb; - fb.push_back(color); - fb.push_back(specular); - fb.push_back(depth); + if (msaa == RS::VIEWPORT_MSAA_DISABLED) { - color_specular_fb = RD::get_singleton()->framebuffer_create(fb); - } - { - Vector<RID> fb; - fb.push_back(specular); + { + Vector<RID> fb; + fb.push_back(color); + fb.push_back(specular); + fb.push_back(depth); + + color_specular_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector<RID> fb; + fb.push_back(specular); + + specular_only_fb = RD::get_singleton()->framebuffer_create(fb); + } - specular_only_fb = RD::get_singleton()->framebuffer_create(fb); + } else { + + tf.samples = texture_samples; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + specular_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector<RID> fb; + fb.push_back(color_msaa); + fb.push_back(specular_msaa); + fb.push_back(depth_msaa); + + color_specular_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector<RID> fb; + fb.push_back(specular_msaa); + + specular_only_fb = RD::get_singleton()->framebuffer_create(fb); + } } } } void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() { + if (color_msaa.is_valid()) { + RD::get_singleton()->free(color_msaa); + color_msaa = RID(); + } + + if (depth_msaa.is_valid()) { + RD::get_singleton()->free(depth_msaa); + depth_msaa = RID(); + } + if (specular.is_valid()) { + if (specular_msaa.is_valid()) { + RD::get_singleton()->free(specular_msaa); + specular_msaa = RID(); + } RD::get_singleton()->free(specular); specular = RID(); } + color = RID(); + depth = RID(); color_specular_fb = RID(); specular_only_fb = RID(); color_fb = RID(); + depth_fb = RID(); if (normal_buffer.is_valid()) { RD::get_singleton()->free(normal_buffer); + if (normal_buffer_msaa.is_valid()) { + RD::get_singleton()->free(normal_buffer_msaa); + normal_buffer_msaa = RID(); + } normal_buffer = RID(); depth_normal_fb = RID(); } if (roughness_buffer.is_valid()) { RD::get_singleton()->free(roughness_buffer); + if (roughness_buffer_msaa.is_valid()) { + RD::get_singleton()->free(roughness_buffer_msaa); + roughness_buffer_msaa = RID(); + } roughness_buffer = RID(); depth_normal_roughness_fb = RID(); } @@ -583,24 +644,69 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() { void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { clear(); + msaa = p_msaa; + width = p_width; height = p_height; color = p_color_buffer; depth = p_depth_buffer; - { - Vector<RID> fb; - fb.push_back(p_color_buffer); - fb.push_back(depth); + if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) { - color_fb = RD::get_singleton()->framebuffer_create(fb); - } - { - Vector<RID> fb; - fb.push_back(depth); + { + Vector<RID> fb; + fb.push_back(p_color_buffer); + fb.push_back(depth); + + color_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector<RID> fb; + fb.push_back(depth); + + depth_fb = RD::get_singleton()->framebuffer_create(fb); + } + } else { + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = p_width; + tf.height = p_height; + tf.type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + + RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { + RD::TEXTURE_SAMPLES_1, + RD::TEXTURE_SAMPLES_2, + RD::TEXTURE_SAMPLES_4, + RD::TEXTURE_SAMPLES_8, + RD::TEXTURE_SAMPLES_16 + }; + + texture_samples = ts[p_msaa]; + tf.samples = texture_samples; + + color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + + depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector<RID> fb; + fb.push_back(color_msaa); + fb.push_back(depth_msaa); + + color_fb = RD::get_singleton()->framebuffer_create(fb); + } + { + Vector<RID> fb; + fb.push_back(depth_msaa); - depth_fb = RD::get_singleton()->framebuffer_create(fb); + depth_fb = RD::get_singleton()->framebuffer_create(fb); + } } } @@ -613,13 +719,31 @@ void RasterizerSceneHighEndRD::_allocate_normal_texture(RenderBufferDataHighEnd tf.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; tf.width = rb->width; tf.height = rb->height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } rb->normal_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb; - fb.push_back(rb->depth); - fb.push_back(rb->normal_buffer); - rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb); + + if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) { + Vector<RID> fb; + fb.push_back(rb->depth); + fb.push_back(rb->normal_buffer); + rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb); + } else { + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + tf.samples = rb->texture_samples; + rb->normal_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector<RID> fb; + fb.push_back(rb->depth_msaa); + fb.push_back(rb->normal_buffer_msaa); + rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb); + } _render_buffers_clear_uniform_set(rb); } @@ -638,12 +762,32 @@ void RasterizerSceneHighEndRD::_allocate_roughness_texture(RenderBufferDataHighE tf.height = rb->height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } + rb->roughness_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb; - fb.push_back(rb->depth); - fb.push_back(rb->normal_buffer); - fb.push_back(rb->roughness_buffer); - rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); + + if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) { + + Vector<RID> fb; + fb.push_back(rb->depth); + fb.push_back(rb->normal_buffer); + fb.push_back(rb->roughness_buffer); + rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); + } else { + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + tf.samples = rb->texture_samples; + rb->roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + Vector<RID> fb; + fb.push_back(rb->depth_msaa); + fb.push_back(rb->normal_buffer_msaa); + fb.push_back(rb->roughness_buffer_msaa); + rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); + } _render_buffers_clear_uniform_set(rb); } @@ -962,10 +1106,18 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const Camer scene_state.ubo.z_far = p_zfar; scene_state.ubo.z_near = p_znear; - scene_state.ubo.shadow_filter_mode = shadow_filter_get(); scene_state.ubo.pancake_shadows = p_pancake_shadows; - scene_state.ubo.shadow_blocker_count = 16; + + store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); + store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); + store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); + store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); + + scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get(); + scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get(); + scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get(); + scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get(); scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x; scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y; @@ -1585,6 +1737,8 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep light_data.fade_to = -light_data.shadow_split_offsets[3]; + light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); + float softshadow_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); if (softshadow_angle > 0.0) { // I know tan(0) is 0, but let's not risk it with numerical precision. @@ -1593,6 +1747,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.softshadow_angle = Math::tan(Math::deg2rad(softshadow_angle)); } else { light_data.softshadow_angle = 0; + light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF } } @@ -1703,6 +1858,8 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.atlas_rect[2] = rect.size.width; light_data.atlas_rect[3] = rect.size.height; + light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); + if (type == RS::LIGHT_OMNI) { light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another @@ -1715,6 +1872,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.soft_shadow_size = size; } else { light_data.soft_shadow_size = 0.0; + light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF } } else if (type == RS::LIGHT_SPOT) { @@ -1738,6 +1896,7 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width; } else { light_data.soft_shadow_size = 0.0; + light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF } } } else { @@ -1777,27 +1936,6 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor render_pass++; //fill up ubo -#if 0 - storage->info.render.object_count += p_cull_count; - - Environment *env = environment_owner.getornull(p_environment); - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); - - if (shadow_atlas && shadow_atlas->size) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); - scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / shadow_atlas->size; - scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / shadow_atlas->size; - } - - if (reflection_atlas && reflection_atlas->size) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); - } -#endif RENDER_TIMESTAMP("Setup 3D Scene"); @@ -1837,6 +1975,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor bool using_ssr = false; if (render_buffer) { + screen_pixel_size.width = 1.0 / render_buffer->width; screen_pixel_size.height = 1.0 / render_buffer->height; screen_size.x = render_buffer->width; @@ -1998,9 +2137,23 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor if (depth_pre_pass) { //depth pre pass RENDER_TIMESTAMP("Render Depth Pre-Pass"); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, using_ssao ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); + bool finish_depth = using_ssao; + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, radiance_uniform_set, RID()); RD::get_singleton()->draw_list_end(); + + if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + if (finish_depth) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true); + } + + if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->normal_buffer_msaa, render_buffer->normal_buffer, true); + if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->roughness_buffer_msaa, render_buffer->roughness_buffer, true); + } + } + } } if (using_ssao) { @@ -2080,6 +2233,19 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor _draw_sky(can_continue_color, can_continue_depth, opaque_framebuffer, p_environment, projection, p_cam_transform); } + if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true); + if (using_separate_specular) { + RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular, true); + } + } + + if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true); + } + if (using_separate_specular) { if (using_sss) { @@ -2089,11 +2255,11 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor if (using_ssr) { RENDER_TIMESTAMP("Screen Space Reflection"); - _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_buffer, render_buffer->roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, true); + _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_buffer, render_buffer->roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED); } else { //just mix specular back RENDER_TIMESTAMP("Merge Specular"); - storage->get_effects()->merge_specular(render_buffer->color_fb, render_buffer->specular, RID(), RID()); + storage->get_effects()->merge_specular(render_buffer->color_fb, render_buffer->specular, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED ? RID() : render_buffer->color, RID()); } } @@ -2111,77 +2277,12 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor RD::get_singleton()->draw_list_end(); } - //_render_list -#if 0 - if (state.directional_light_count == 0) { - directional_light = nullptr; - _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, false, shadow_atlas != nullptr); - } else { - for (int i = 0; i < state.directional_light_count; i++) { - directional_light = directional_lights[i]; - _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != nullptr && shadow_atlas->size > 0); - _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, i > 0, shadow_atlas != nullptr); - } - } -#endif - -#if 0 - _post_process(env, p_cam_projection); - // Needed only for debugging - /* if (shadow_atlas && storage->frame.current_rt) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - } - - if (storage->frame.current_rt) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, exposure_shrink[4].color); - //glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->exposure.color); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 16, storage->frame.current_rt->height / 16), Rect2(0, 0, 1, 1)); - } - - if (reflection_atlas && storage->frame.current_rt) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - } - - if (directional_shadow.fbo) { + if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true); } - - if ( env_radiance_tex) { - - //_copy_texture_to_front_buffer(shadow_atlas->depth); - storage->canvas->canvas_begin(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, env_radiance_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - }*/ - //disable all stuff -#endif } + void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake) { RENDER_TIMESTAMP("Setup Rendering Shadow"); diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h index b4f5d25afd..6ae4720306 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h @@ -198,11 +198,22 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { struct RenderBufferDataHighEnd : public RenderBufferData { //for rendering, may be MSAAd + RID color; RID depth; RID specular; RID normal_buffer; RID roughness_buffer; + + RS::ViewportMSAA msaa; + RD::TextureSamples texture_samples; + + RID color_msaa; + RID depth_msaa; + RID specular_msaa; + RID normal_buffer_msaa; + RID roughness_buffer_msaa; + RID depth_fb; RID depth_normal_fb; RID depth_normal_roughness_fb; @@ -265,8 +276,9 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float shadow_normal_bias; float transmittance_bias; float soft_shadow_size; + float soft_shadow_scale; uint32_t mask; - uint32_t pad[3]; + uint32_t pad[2]; }; struct DirectionalLightData { @@ -278,7 +290,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float specular; uint32_t mask; float softshadow_angle; - uint32_t pad[1]; + float soft_shadow_scale; uint32_t blend_splits; uint32_t shadow_enabled; float fade_from; @@ -350,10 +362,17 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD { float reflection_multiplier; uint32_t pancake_shadows; - uint32_t shadow_filter_mode; + uint32_t pad; + + float directional_penumbra_shadow_kernel[128]; //32 vec4s + float directional_soft_shadow_kernel[128]; + float penumbra_shadow_kernel[128]; + float soft_shadow_kernel[128]; - uint32_t shadow_blocker_count; - uint32_t shadow_pad[3]; + uint32_t directional_penumbra_shadow_samples; + uint32_t directional_soft_shadow_samples; + uint32_t penumbra_shadow_samples; + uint32_t soft_shadow_samples; float ambient_light_color_energy[4]; diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp index a0bbf8bd43..2ec09b2528 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp @@ -36,6 +36,18 @@ uint64_t RasterizerSceneRD::auto_exposure_counter = 2; +void get_vogel_disk(float *r_kernel, int p_sample_count) { + const float golden_angle = 2.4; + + for (int i = 0; i < p_sample_count; i++) { + float r = Math::sqrt(float(i) + 0.5) / Math::sqrt(float(p_sample_count)); + float theta = float(i) * golden_angle; + + r_kernel[i * 4] = Math::cos(theta) * r; + r_kernel[i * 4 + 1] = Math::sin(theta) * r; + } +} + void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) { rd.layers.clear(); @@ -181,10 +193,9 @@ void RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd) { for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) { for (int k = 0; k < 6; k++) { RID view = rd.layers[i].mipmaps[j].views[k]; - RID fb = rd.layers[i].mipmaps[j + 1].framebuffers[k]; - Vector2 size = rd.layers[i].mipmaps[j].size; - size = Vector2(1.0 / size.x, 1.0 / size.y); - storage->get_effects()->make_mipmap(view, fb, size); + RID texture = rd.layers[i].mipmaps[j + 1].views[k]; + Size2i size = rd.layers[i].mipmaps[j + 1].size; + storage->get_effects()->make_mipmap(view, texture, size); } } } @@ -1599,7 +1610,6 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { if (shadow_atlas->depth.is_valid()) { RD::get_singleton()->free(shadow_atlas->depth); shadow_atlas->depth = RID(); - shadow_atlas->fb = RID(); } for (int i = 0; i < 4; i++) { //clear subdivisions @@ -1625,13 +1635,9 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { tf.format = RD::DATA_FORMAT_R32_SFLOAT; tf.width = shadow_atlas->size; tf.height = shadow_atlas->size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - Vector<RID> fb; - fb.push_back(shadow_atlas->depth); - shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb); } } @@ -1901,7 +1907,6 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { if (directional_shadow.depth.is_valid()) { RD::get_singleton()->free(directional_shadow.depth); directional_shadow.depth = RID(); - directional_shadow.fb = RID(); } if (p_size > 0) { @@ -1910,12 +1915,9 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { tf.format = RD::DATA_FORMAT_R32_SFLOAT; tf.width = p_size; tf.height = p_size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - Vector<RID> fb; - fb.push_back(directional_shadow.depth); - directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb); } _base_uniforms_changed(); @@ -3062,7 +3064,7 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { tf.width = rb->width; tf.height = rb->height; tf.type = RD::TEXTURE_TYPE_2D; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -3079,11 +3081,6 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { RenderBuffers::Blur::Mipmap mm; mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[0].texture, 0, i); - { - Vector<RID> fbs; - fbs.push_back(mm.texture); - mm.framebuffer = RD::get_singleton()->framebuffer_create(fbs); - } mm.width = base_width; mm.height = base_height; @@ -3093,11 +3090,6 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { if (i > 0) { mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[1].texture, 0, i - 1); - { - Vector<RID> fbs; - fbs.push_back(mm.texture); - mm.framebuffer = RD::get_singleton()->framebuffer_create(fbs); - } rb->blur[1].mipmaps.push_back(mm); } @@ -3424,9 +3416,9 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu if (env->auto_exposure && rb->luminance.current.is_valid()) { luminance_texture = rb->luminance.current; } - storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].framebuffer, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].framebuffer, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); } else { - storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].framebuffer, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].framebuffer, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength); + storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength); } } } @@ -3459,6 +3451,12 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu tonemap.glow_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); } + if (rb->screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) { + tonemap.use_fxaa = true; + } + + tonemap.texture_size = Vector2i(rb->width, rb->height); + if (env) { tonemap.tonemap_mode = env->tone_mapper; tonemap.white = env->white; @@ -3482,7 +3480,7 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas); Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 2), false, true); + effects->copy_to_fb_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true); } } @@ -3491,7 +3489,7 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s RID shadow_atlas_texture = directional_shadow_get_texture(); Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 2), false, true); + effects->copy_to_fb_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true); } } @@ -3499,24 +3497,24 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s if (rb->luminance.current.is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(rb->luminance.current, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 8), false, true); + effects->copy_to_fb_rect(rb->luminance.current, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 8), false, true); } } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao[0].is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); RID ao_buf = rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0]; - effects->copy_to_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); + effects->copy_to_fb_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER && _render_buffers_get_roughness_texture(p_render_buffers).is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(_render_buffers_get_roughness_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); + effects->copy_to_fb_rect(_render_buffers_get_roughness_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - effects->copy_to_rect(_render_buffers_get_normal_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize)); + effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false); } } @@ -3537,13 +3535,14 @@ RID RasterizerSceneRD::render_buffers_get_ao_texture(RID p_render_buffers) { return rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0]; } -void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa) { +void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); rb->width = p_width; rb->height = p_height; rb->render_target = p_render_target; rb->msaa = p_msaa; + rb->screen_space_aa = p_screen_space_aa; _free_render_buffer_data(rb); { @@ -3551,7 +3550,12 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = rb->width; tf.height = rb->height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } else { + tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); } @@ -3562,6 +3566,9 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren tf.width = p_width; tf.height = p_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + } rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); } @@ -3583,8 +3590,86 @@ void RasterizerSceneRD::sub_surface_scattering_set_scale(float p_scale, float p_ sss_depth_scale = p_depth_scale; } -void RasterizerSceneRD::shadow_filter_set(RS::ShadowFilter p_filter) { - shadow_filter = p_filter; +void RasterizerSceneRD::shadows_quality_set(RS::ShadowQuality p_quality) { + + ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); + + if (shadows_quality != p_quality) { + shadows_quality = p_quality; + + switch (shadows_quality) { + case RS::SHADOW_QUALITY_HARD: { + penumbra_shadow_samples = 4; + soft_shadow_samples = 1; + shadows_quality_radius = 1.0; + } break; + case RS::SHADOW_QUALITY_SOFT_LOW: { + penumbra_shadow_samples = 8; + soft_shadow_samples = 4; + shadows_quality_radius = 2.0; + } break; + case RS::SHADOW_QUALITY_SOFT_MEDIUM: { + penumbra_shadow_samples = 12; + soft_shadow_samples = 8; + shadows_quality_radius = 2.0; + } break; + case RS::SHADOW_QUALITY_SOFT_HIGH: { + penumbra_shadow_samples = 24; + soft_shadow_samples = 16; + shadows_quality_radius = 3.0; + } break; + case RS::SHADOW_QUALITY_SOFT_ULTRA: { + penumbra_shadow_samples = 32; + soft_shadow_samples = 32; + shadows_quality_radius = 4.0; + } break; + case RS::SHADOW_QUALITY_MAX: + break; + } + get_vogel_disk(penumbra_shadow_kernel, penumbra_shadow_samples); + get_vogel_disk(soft_shadow_kernel, soft_shadow_samples); + } +} + +void RasterizerSceneRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) { + + ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); + + if (directional_shadow_quality != p_quality) { + directional_shadow_quality = p_quality; + + switch (directional_shadow_quality) { + case RS::SHADOW_QUALITY_HARD: { + directional_penumbra_shadow_samples = 4; + directional_soft_shadow_samples = 1; + directional_shadow_quality_radius = 1.0; + } break; + case RS::SHADOW_QUALITY_SOFT_LOW: { + directional_penumbra_shadow_samples = 8; + directional_soft_shadow_samples = 4; + directional_shadow_quality_radius = 2.0; + } break; + case RS::SHADOW_QUALITY_SOFT_MEDIUM: { + directional_penumbra_shadow_samples = 12; + directional_soft_shadow_samples = 8; + directional_shadow_quality_radius = 2.0; + } break; + case RS::SHADOW_QUALITY_SOFT_HIGH: { + directional_penumbra_shadow_samples = 24; + directional_soft_shadow_samples = 16; + directional_shadow_quality_radius = 3.0; + } break; + case RS::SHADOW_QUALITY_SOFT_ULTRA: { + directional_penumbra_shadow_samples = 32; + directional_soft_shadow_samples = 32; + directional_shadow_quality_radius = 4.0; + } break; + case RS::SHADOW_QUALITY_MAX: + break; + } + get_vogel_disk(directional_penumbra_shadow_kernel, directional_penumbra_shadow_samples); + get_vogel_disk(directional_soft_shadow_kernel, directional_soft_shadow_samples); + } } int RasterizerSceneRD::get_roughness_layers() const { @@ -3628,7 +3713,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas ERR_FAIL_COND(!light_instance); Rect2i atlas_rect; - RID atlas_fb; + RID atlas_texture; bool using_dual_paraboloid = false; bool using_dual_paraboloid_flip = false; @@ -3702,7 +3787,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); render_fb = shadow_map->fb; render_texture = shadow_map->depth; - atlas_fb = directional_shadow.fb; + atlas_texture = directional_shadow.depth; } else { //set from shadow atlas @@ -3729,7 +3814,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas atlas_rect.size.width = shadow_size; atlas_rect.size.height = shadow_size; - atlas_fb = shadow_atlas->fb; + atlas_texture = shadow_atlas->depth; zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS); @@ -3785,9 +3870,9 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas if (finalize_cubemap) { //reblit atlas_rect.size.height /= 2; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, false); + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, false); atlas_rect.position.y += atlas_rect.size.height; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, true); + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, true); } } else { //render shadow @@ -3796,9 +3881,9 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas //copy to atlas if (use_linear_depth) { - storage->get_effects()->copy_to_rect_and_linearize(render_texture, atlas_fb, atlas_rect, true, znear, zfar); + storage->get_effects()->copy_depth_to_rect_and_linearize(render_texture, atlas_texture, atlas_rect, true, znear, zfar); } else { - storage->get_effects()->copy_to_rect(render_texture, atlas_fb, atlas_rect, true); + storage->get_effects()->copy_depth_to_rect(render_texture, atlas_texture, atlas_rect, true); } //does not work from depth to color @@ -4145,17 +4230,22 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS); } - camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_shape")))); - camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/filters/depth_of_field_use_jitter")); + camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape")))); + camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter")); environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size")); - screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter"); - screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter_curve"); + screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter"); + screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_curve"); glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0; ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality"))); sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality"))); sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale"); sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale"); - shadow_filter = RS::ShadowFilter(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); + directional_penumbra_shadow_kernel = memnew_arr(float, 128); + directional_soft_shadow_kernel = memnew_arr(float, 128); + penumbra_shadow_kernel = memnew_arr(float, 128); + soft_shadow_kernel = memnew_arr(float, 128); + shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality")))); + directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality")))); } RasterizerSceneRD::~RasterizerSceneRD() { @@ -4184,4 +4274,8 @@ RasterizerSceneRD::~RasterizerSceneRD() { memdelete_arr(sky_scene_state.last_frame_directional_lights); storage->free(sky_shader.default_shader); storage->free(sky_shader.default_material); + memdelete_arr(directional_penumbra_shadow_kernel); + memdelete_arr(directional_soft_shadow_kernel); + memdelete_arr(penumbra_shadow_kernel); + memdelete_arr(soft_shadow_kernel); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h index 3478c05fb1..859b654214 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h @@ -527,13 +527,24 @@ private: bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); - RS::ShadowFilter shadow_filter = RS::SHADOW_FILTER_NONE; + RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set + RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX; + float shadows_quality_radius = 1.0; + float directional_shadow_quality_radius = 1.0; + + float *directional_penumbra_shadow_kernel; + float *directional_soft_shadow_kernel; + float *penumbra_shadow_kernel; + float *soft_shadow_kernel; + int directional_penumbra_shadow_samples = 0; + int directional_soft_shadow_samples = 0; + int penumbra_shadow_samples = 0; + int soft_shadow_samples = 0; /* DIRECTIONAL SHADOW */ struct DirectionalShadow { RID depth; - RID fb; //for copying int light_count = 0; int size = 0; @@ -717,6 +728,8 @@ private: RenderBufferData *data = nullptr; int width = 0, height = 0; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; + RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; + RID render_target; uint64_t auto_exposure_version = 1; @@ -730,7 +743,6 @@ private: struct Mipmap { RID texture; - RID framebuffer; int width; int height; }; @@ -1151,7 +1163,7 @@ public: GIProbeQuality gi_probe_get_quality() const; RID render_buffers_create(); - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa); + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa); RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); @@ -1177,8 +1189,22 @@ public: RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const; virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale); - virtual void shadow_filter_set(RS::ShadowFilter p_filter); - _FORCE_INLINE_ RS::ShadowFilter shadow_filter_get() const { return shadow_filter; } + virtual void shadows_quality_set(RS::ShadowQuality p_quality); + virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality); + _FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const { return shadows_quality; } + _FORCE_INLINE_ RS::ShadowQuality directional_shadow_quality_get() const { return directional_shadow_quality; } + _FORCE_INLINE_ float shadows_quality_radius_get() const { return shadows_quality_radius; } + _FORCE_INLINE_ float directional_shadow_quality_radius_get() const { return directional_shadow_quality_radius; } + + _FORCE_INLINE_ float *directional_penumbra_shadow_kernel_get() { return directional_penumbra_shadow_kernel; } + _FORCE_INLINE_ float *directional_soft_shadow_kernel_get() { return directional_soft_shadow_kernel; } + _FORCE_INLINE_ float *penumbra_shadow_kernel_get() { return penumbra_shadow_kernel; } + _FORCE_INLINE_ float *soft_shadow_kernel_get() { return soft_shadow_kernel; } + + _FORCE_INLINE_ int directional_penumbra_shadow_samples_get() const { return directional_penumbra_shadow_samples; } + _FORCE_INLINE_ int directional_soft_shadow_samples_get() const { return directional_soft_shadow_samples; } + _FORCE_INLINE_ int penumbra_shadow_samples_get() const { return penumbra_shadow_samples; } + _FORCE_INLINE_ int soft_shadow_samples_get() const { return soft_shadow_samples; } int get_roughness_layers() const; bool is_using_radiance_cubemap_array() const; diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp index 0b26ec1be6..6ac1f7c95e 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp @@ -3914,7 +3914,6 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { if (rt->backbuffer.is_valid()) { RD::get_singleton()->free(rt->backbuffer); rt->backbuffer = RID(); - rt->backbuffer_fb = RID(); for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { //just erase copies, since the rest are erased by dependency RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy); @@ -4028,17 +4027,11 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { tf.width = rt->size.width; tf.height = rt->size.height; tf.type = RD::TEXTURE_TYPE_2D; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - - { - Vector<RID> backbuffer_att; - RID backbuffer_fb_tex = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); - backbuffer_att.push_back(backbuffer_fb_tex); - rt->backbuffer_fb = RD::get_singleton()->framebuffer_create(backbuffer_att); - } + rt->backbuffer_mipmap0 = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); //create mipmaps for (uint32_t i = 1; i < mipmaps_required; i++) { @@ -4046,9 +4039,6 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { RenderTarget::BackbufferMipmap mm; { mm.mipmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, i); - Vector<RID> mm_fb_at; - mm_fb_at.push_back(mm.mipmap); - mm.mipmap_fb = RD::get_singleton()->framebuffer_create(mm_fb_at); } { @@ -4060,9 +4050,6 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { mmtf.mipmaps = 1; mm.mipmap_copy = RD::get_singleton()->texture_create(mmtf, RD::TextureView()); - Vector<RID> mm_fb_at; - mm_fb_at.push_back(mm.mipmap_copy); - mm.mipmap_copy_fb = RD::get_singleton()->framebuffer_create(mm_fb_at); } rt->backbuffer_mipmaps.push_back(mm); @@ -4138,7 +4125,12 @@ RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { return rt->framebuffer; } +RID RasterizerStorageRD::render_target_get_rd_texture(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + return rt->color; +} void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -4188,27 +4180,25 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, } Rect2i region = p_region; - Rect2 blur_region; if (region == Rect2i()) { region.size = rt->size; - } else { - blur_region = region; - blur_region.position /= rt->size; - blur_region.size /= rt->size; } //single texture copy for backbuffer - RD::get_singleton()->texture_copy(rt->color, rt->backbuffer, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); + RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); //effects.copy(rt->color, rt->backbuffer_fb, blur_region); //then mipmap blur RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps. - Vector2 pixel_size = Vector2(1.0 / rt->size.width, 1.0 / rt->size.height); for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { - pixel_size *= 2.0; //go halfway + region.position.x >>= 1; + region.position.y >>= 1; + region.size.x = MAX(1, region.size.x >> 1); + region.size.y = MAX(1, region.size.y >> 1); + const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; - effects.gaussian_blur(prev_texture, mm.mipmap_copy_fb, mm.mipmap_copy, mm.mipmap_fb, pixel_size, blur_region); + effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true); prev_texture = mm.mipmap; } } @@ -4647,14 +4637,14 @@ RasterizerStorageRD::RasterizerStorageRD() { sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.use_anisotropy = true; - sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy"); + sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/texture_filters/max_anisotropy"); } break; case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: { sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; sampler_state.use_anisotropy = true; - sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy"); + sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/texture_filters/max_anisotropy"); } break; default: { diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h index 7573a0d70c..29a45ca90e 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h @@ -463,13 +463,11 @@ private: bool flags[RENDER_TARGET_FLAG_MAX]; RID backbuffer; //used for effects - RID backbuffer_fb; + RID backbuffer_mipmap0; struct BackbufferMipmap { RID mipmap; - RID mipmap_fb; RID mipmap_copy; - RID mipmap_copy_fb; }; Vector<BackbufferMipmap> backbuffer_mipmaps; @@ -1105,6 +1103,7 @@ public: Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); + RID render_target_get_rd_texture(RID p_render_target); RS::InstanceType get_base_type(RID p_rid) const; diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub index 04a43e3251..a454d144aa 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/rasterizer_rd/shaders/SCsub @@ -5,14 +5,15 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("canvas.glsl") env.RD_GLSL("canvas_occlusion.glsl") - env.RD_GLSL("blur.glsl") + env.RD_GLSL("copy.glsl") + env.RD_GLSL("copy_to_fb.glsl") env.RD_GLSL("cubemap_roughness.glsl") env.RD_GLSL("cubemap_downsampler.glsl") env.RD_GLSL("cubemap_filter.glsl") env.RD_GLSL("scene_high_end.glsl") env.RD_GLSL("sky.glsl") env.RD_GLSL("tonemap.glsl") - env.RD_GLSL("copy.glsl") + env.RD_GLSL("cube_to_dp.glsl") env.RD_GLSL("giprobe.glsl") env.RD_GLSL("giprobe_debug.glsl") env.RD_GLSL("giprobe_sdf.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/blur.glsl b/servers/rendering/rasterizer_rd/shaders/blur.glsl deleted file mode 100644 index 5dfdc614a4..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/blur.glsl +++ /dev/null @@ -1,301 +0,0 @@ -/* clang-format off */ -[vertex] - -#version 450 - -VERSION_DEFINES - -#include "blur_inc.glsl" - -layout(location = 0) out vec2 uv_interp; -/* clang-format on */ - -void main() { - - vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); - uv_interp = base_arr[gl_VertexIndex]; - - if (bool(blur.flags & FLAG_USE_BLUR_SECTION)) { - uv_interp = blur.section.xy + uv_interp * blur.section.zw; - } - - gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); - - if (bool(blur.flags & FLAG_FLIP_Y)) { - uv_interp.y = 1.0 - uv_interp.y; - } -} - -/* clang-format off */ -[fragment] - -#version 450 - -VERSION_DEFINES - -#include "blur_inc.glsl" - -layout(location = 0) in vec2 uv_interp; -/* clang-format on */ - -layout(set = 0, binding = 0) uniform sampler2D source_color; - -#ifdef MODE_SSAO_MERGE -layout(set = 1, binding = 0) uniform sampler2D source_ssao; -#endif - -#ifdef GLOW_USE_AUTO_EXPOSURE -layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; -#endif - -layout(location = 0) out vec4 frag_color; - -//DOF -#if defined(MODE_DOF_FAR_BLUR) || defined(MODE_DOF_NEAR_BLUR) - -layout(set = 1, binding = 0) uniform sampler2D dof_source_depth; - -#ifdef DOF_NEAR_BLUR_MERGE -layout(set = 2, binding = 0) uniform sampler2D source_dof_original; -#endif - -#ifdef DOF_QUALITY_LOW -const int dof_kernel_size = 5; -const int dof_kernel_from = 2; -const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388); -#endif - -#ifdef DOF_QUALITY_MEDIUM -const int dof_kernel_size = 11; -const int dof_kernel_from = 5; -const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037); - -#endif - -#ifdef DOF_QUALITY_HIGH -const int dof_kernel_size = 21; -const int dof_kernel_from = 10; -const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); -#endif - -#endif - -void main() { - -#ifdef MODE_MIPMAP - - vec2 pix_size = blur.pixel_size; - vec4 color = texture(source_color, uv_interp + vec2(-0.5, -0.5) * pix_size); - color += texture(source_color, uv_interp + vec2(0.5, -0.5) * pix_size); - color += texture(source_color, uv_interp + vec2(0.5, 0.5) * pix_size); - color += texture(source_color, uv_interp + vec2(-0.5, 0.5) * pix_size); - frag_color = color / 4.0; - -#endif - -#ifdef MODE_GAUSSIAN_BLUR - - //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect - - if (bool(blur.flags & FLAG_HORIZONTAL)) { - - vec2 pix_size = blur.pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.214607; - color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.189879; - color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.131514; - color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.071303; - color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.189879; - color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.131514; - color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.071303; - frag_color = color; - } else { - - vec2 pix_size = blur.pixel_size; - vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.38774; - color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.24477; - color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.06136; - color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.24477; - color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.06136; - frag_color = color; - } -#endif - -#ifdef MODE_GAUSSIAN_GLOW - - //Glow uses larger sigma 1 for a more rounded blur effect - -#define GLOW_ADD(m_ofs, m_mult) \ - { \ - vec2 ofs = uv_interp + m_ofs * pix_size; \ - vec4 c = texture(source_color, ofs) * m_mult; \ - if (any(lessThan(ofs, vec2(0.0))) || any(greaterThan(ofs, vec2(1.0)))) { \ - c *= 0.0; \ - } \ - color += c; \ - } - - if (bool(blur.flags & FLAG_HORIZONTAL)) { - - vec2 pix_size = blur.pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938; - GLOW_ADD(vec2(1.0, 0.0), 0.165569); - GLOW_ADD(vec2(2.0, 0.0), 0.140367); - GLOW_ADD(vec2(3.0, 0.0), 0.106595); - GLOW_ADD(vec2(-1.0, 0.0), 0.165569); - GLOW_ADD(vec2(-2.0, 0.0), 0.140367); - GLOW_ADD(vec2(-3.0, 0.0), 0.106595); - color *= blur.glow_strength; - frag_color = color; - } else { - - vec2 pix_size = blur.pixel_size; - vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713; - GLOW_ADD(vec2(0.0, 1.0), 0.233062); - GLOW_ADD(vec2(0.0, 2.0), 0.122581); - GLOW_ADD(vec2(0.0, -1.0), 0.233062); - GLOW_ADD(vec2(0.0, -2.0), 0.122581); - color *= blur.glow_strength; - frag_color = color; - } - -#undef GLOW_ADD - - if (bool(blur.flags & FLAG_GLOW_FIRST_PASS)) { -#ifdef GLOW_USE_AUTO_EXPOSURE - - frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey; -#endif - frag_color *= blur.glow_exposure; - - float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); - float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom); - - frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap)); - } - -#endif - -#ifdef MODE_DOF_FAR_BLUR - - vec4 color_accum = vec4(0.0); - - float depth = texture(dof_source_depth, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; - - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); - } - - float amount = smoothstep(blur.dof_begin, blur.dof_end, depth); - float k_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius; - - float tap_k = dof_kernel[i]; - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; - - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - - tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); - } - - float tap_amount = mix(smoothstep(blur.dof_begin, blur.dof_end, tap_depth), 1.0, int_ofs == 0); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k; - - k_accum += tap_k * tap_amount; - color_accum += tap_color * tap_amount; - } - - if (k_accum > 0.0) { - color_accum /= k_accum; - } - - frag_color = color_accum; ///k_accum; - -#endif - -#ifdef MODE_DOF_NEAR_BLUR - - vec4 color_accum = vec4(0.0); - - float max_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * blur.dof_radius; - float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from)); - - float tap_k = dof_kernel[i]; - - vec4 tap_color = texture(source_color, tap_uv, 0.0); - - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; - if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) { - - tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; - } else { - tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); - } - float tap_amount = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - if (bool(blur.flags & FLAG_DOF_NEAR_FIRST_TAP)) { - tap_color.a = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); - } - - max_accum = max(max_accum, tap_amount * ofs_influence); - - color_accum += tap_color * tap_k; - } - - color_accum.a = max(color_accum.a, sqrt(max_accum)); - -#ifdef DOF_NEAR_BLUR_MERGE - { - vec4 original = texture(source_dof_original, uv_interp, 0.0); - color_accum = mix(original, color_accum, color_accum.a); - } -#endif - - if (bool(blur.flags & FLAG_DOF_NEAR_FIRST_TAP)) { - frag_color = color_accum; - } -#endif - -#ifdef MODE_SIMPLE_COPY - vec4 color = texture(source_color, uv_interp, 0.0); - if (bool(blur.flags & FLAG_COPY_FORCE_LUMINANCE)) { - color.rgb = vec3(max(max(color.r, color.g), color.b)); - } - frag_color = color; -#endif - -#ifdef MODE_LINEARIZE_DEPTH_COPY - float depth = texture(source_color, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; - depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); - frag_color = vec4(depth / blur.camera_z_far); -#endif - -#ifdef MODE_SSAO_MERGE - vec4 color = texture(source_color, uv_interp, 0.0); - float ssao = texture(source_ssao, uv_interp, 0.0).r; - frag_color = vec4(mix(color.rgb, color.rgb * mix(blur.ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0); - -#endif -} diff --git a/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl b/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl deleted file mode 100644 index 33ba9de7bb..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/blur_inc.glsl +++ /dev/null @@ -1,35 +0,0 @@ -#define FLAG_HORIZONTAL (1 << 0) -#define FLAG_USE_BLUR_SECTION (1 << 1) -#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 2) -#define FLAG_DOF_NEAR_FIRST_TAP (1 << 3) -#define FLAG_GLOW_FIRST_PASS (1 << 4) -#define FLAG_FLIP_Y (1 << 5) -#define FLAG_COPY_FORCE_LUMINANCE (1 << 6) - -layout(push_constant, binding = 1, std430) uniform Blur { - vec4 section; - vec2 pixel_size; - uint flags; - uint pad; - // Glow. - float glow_strength; - float glow_bloom; - float glow_hdr_threshold; - float glow_hdr_scale; - float glow_exposure; - float glow_white; - float glow_luminance_cap; - float glow_auto_exposure_grey; - // DOF. - float dof_begin; - float dof_end; - float dof_radius; - float dof_pad; - - vec2 dof_dir; - float camera_z_far; - float camera_z_near; - - vec4 ssao_color; -} -blur; diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl index 2b541f2660..48c49ff7de 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl @@ -1,87 +1,220 @@ /* clang-format off */ -[vertex] +[compute] #version 450 VERSION_DEFINES -layout(location = 0) out vec2 uv_interp; +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; /* clang-format on */ -void main() { +#define FLAG_HORIZONTAL (1 << 0) +#define FLAG_USE_BLUR_SECTION (1 << 1) +#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 2) +#define FLAG_DOF_NEAR_FIRST_TAP (1 << 3) +#define FLAG_GLOW_FIRST_PASS (1 << 4) +#define FLAG_FLIP_Y (1 << 5) +#define FLAG_FORCE_LUMINANCE (1 << 6) +#define FLAG_COPY_ALL_SOURCE (1 << 7) + +layout(push_constant, binding = 1, std430) uniform Params { + ivec4 section; + ivec2 target; + uint flags; + uint pad; + // Glow. + float glow_strength; + float glow_bloom; + float glow_hdr_threshold; + float glow_hdr_scale; + + float glow_exposure; + float glow_white; + float glow_luminance_cap; + float glow_auto_exposure_grey; + // DOF. + float camera_z_far; + float camera_z_near; + uvec2 pad2; +} +params; - vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); - uv_interp = base_arr[gl_VertexIndex]; +layout(set = 0, binding = 0) uniform sampler2D source_color; - gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); -} +#ifdef GLOW_USE_AUTO_EXPOSURE +layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; +#endif -/* clang-format off */ -[fragment] +#if defined(MODE_LINEARIZE_DEPTH_COPY) || defined(MODE_SIMPLE_COPY_DEPTH) +layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#elif defined(DST_IMAGE_8BIT) +layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#else +layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer; +#endif -#version 450 +void main() { -VERSION_DEFINES + // Pixel being shaded + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThan(pos, params.section.zw))) { //too large, do nothing + return; + } -layout(location = 0) in vec2 uv_interp; -/* clang-format on */ +#ifdef MODE_MIPMAP -#ifdef MODE_CUBE_TO_DP + ivec2 base_pos = (pos + params.section.xy) << 1; + vec4 color = texelFetch(source_color, base_pos, 0); + color += texelFetch(source_color, base_pos + ivec2(0, 1), 0); + color += texelFetch(source_color, base_pos + ivec2(1, 0), 0); + color += texelFetch(source_color, base_pos + ivec2(1, 1), 0); + color /= 4.0; -layout(set = 0, binding = 0) uniform samplerCube source_cube; + imageStore(dest_buffer, pos + params.target, color); +#endif -layout(push_constant, binding = 0, std430) uniform Params { - float bias; - float z_far; - float z_near; - bool z_flip; -} -params; +#ifdef MODE_GAUSSIAN_BLUR + + //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect -layout(location = 0) out float depth_buffer; + if (bool(params.flags & FLAG_HORIZONTAL)) { + + ivec2 base_pos = (pos + params.section.xy) << 1; + vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.214607; + color += texelFetch(source_color, base_pos + ivec2(1, 0), 0) * 0.189879; + color += texelFetch(source_color, base_pos + ivec2(2, 0), 0) * 0.131514; + color += texelFetch(source_color, base_pos + ivec2(3, 0), 0) * 0.071303; + color += texelFetch(source_color, base_pos + ivec2(-1, 0), 0) * 0.189879; + color += texelFetch(source_color, base_pos + ivec2(-2, 0), 0) * 0.131514; + color += texelFetch(source_color, base_pos + ivec2(-3, 0), 0) * 0.071303; + imageStore(dest_buffer, pos + params.target, color); + } else { + ivec2 base_pos = (pos + params.section.xy); + vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.38774; + color += texelFetch(source_color, base_pos + ivec2(0, 1), 0) * 0.24477; + color += texelFetch(source_color, base_pos + ivec2(0, 2), 0) * 0.06136; + color += texelFetch(source_color, base_pos + ivec2(0, -1), 0) * 0.24477; + color += texelFetch(source_color, base_pos + ivec2(0, -2), 0) * 0.06136; + imageStore(dest_buffer, pos + params.target, color); + } #endif -void main() { +#ifdef MODE_GAUSSIAN_GLOW -#ifdef MODE_CUBE_TO_DP + //Glow uses larger sigma 1 for a more rounded blur effect - vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0); +#define GLOW_ADD(m_ofs, m_mult) \ + { \ + ivec2 ofs = base_pos + m_ofs; \ + if (all(greaterThanEqual(ofs, section_begin)) && all(lessThan(ofs, section_end))) { \ + color += texelFetch(source_color, ofs, 0) * m_mult; \ + } \ + } - normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - normal = normalize(normal); + vec4 color = vec4(0.0); - normal.y = -normal.y; //needs to be flipped to match projection matrix - if (!params.z_flip) { - normal.z = -normal.z; + if (bool(params.flags & FLAG_HORIZONTAL)) { + + ivec2 base_pos = (pos + params.section.xy) << 1; + ivec2 section_begin = params.section.xy << 1; + ivec2 section_end = section_begin + (params.section.zw << 1); + + GLOW_ADD(ivec2(0, 0), 0.174938); + GLOW_ADD(ivec2(1, 0), 0.165569); + GLOW_ADD(ivec2(2, 0), 0.140367); + GLOW_ADD(ivec2(3, 0), 0.106595); + GLOW_ADD(ivec2(-1, 0), 0.165569); + GLOW_ADD(ivec2(-2, 0), 0.140367); + GLOW_ADD(ivec2(-3, 0), 0.106595); + color *= params.glow_strength; + } else { + + ivec2 base_pos = pos + params.section.xy; + ivec2 section_begin = params.section.xy; + ivec2 section_end = section_begin + params.section.zw; + + GLOW_ADD(ivec2(0, 0), 0.288713); + GLOW_ADD(ivec2(0, 1), 0.233062); + GLOW_ADD(ivec2(0, 2), 0.122581); + GLOW_ADD(ivec2(0, -1), 0.233062); + GLOW_ADD(ivec2(0, -2), 0.122581); + color *= params.glow_strength; } - float depth = texture(source_cube, normal).r; - depth_buffer = depth; - - // absolute values for direction cosines, bigger value equals closer to basis axis - vec3 unorm = abs(normal); - - if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { - // x code - unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); - } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { - // y code - unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); - } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { - // z code - unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); +#undef GLOW_ADD + + if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { +#ifdef GLOW_USE_AUTO_EXPOSURE + + color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.glow_auto_exposure_grey; +#endif + color *= params.glow_exposure; + + float luminance = max(color.r, max(color.g, color.b)); + float feedback = max(smoothstep(params.glow_hdr_threshold, params.glow_hdr_threshold + params.glow_hdr_scale, luminance), params.glow_bloom); + + color = min(color * feedback, vec4(params.glow_luminance_cap)); + } + + imageStore(dest_buffer, pos + params.target, color); + +#endif + +#ifdef MODE_SIMPLE_COPY + + vec4 color; + if (bool(params.flags & FLAG_COPY_ALL_SOURCE)) { + vec2 uv = vec2(pos) / vec2(params.section.zw); + if (bool(params.flags & FLAG_FLIP_Y)) { + uv.y = 1.0 - uv.y; + } + color = textureLod(source_color, uv, 0.0); + + if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + imageStore(dest_buffer, pos + params.target, color); + } else { - // oh-no we messed up code - // has to be - unorm = vec3(1.0, 0.0, 0.0); + color = texelFetch(source_color, pos + params.section.xy, 0); + + if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; + } + + imageStore(dest_buffer, pos + params.target, color); } - float depth_fix = 1.0 / dot(normal, unorm); +#endif + +#ifdef MODE_SIMPLE_COPY_DEPTH + + vec4 color = texelFetch(source_color, pos + params.section.xy, 0); + + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; + } - depth = 2.0 * depth - 1.0; - float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - depth_buffer = (linear_depth * depth_fix) / params.z_far; + imageStore(dest_buffer, pos + params.target, vec4(color.r)); + +#endif + +#ifdef MODE_LINEARIZE_DEPTH_COPY + + float depth = texelFetch(source_color, pos + params.section.xy, 0).r; + depth = depth * 2.0 - 1.0; + depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near)); + vec4 color = vec4(depth / params.camera_z_far); + + if (bool(params.flags & FLAG_FLIP_Y)) { + pos.y = params.section.w - pos.y - 1; + } + imageStore(dest_buffer, pos + params.target, color); #endif } diff --git a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl new file mode 100644 index 0000000000..1f499cf372 --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl @@ -0,0 +1,68 @@ +/* clang-format off */ +[vertex] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) out vec2 uv_interp; +/* clang-format on */ + +layout(push_constant, binding = 1, std430) uniform Params { + vec4 section; + vec2 pixel_size; + bool flip_y; + bool use_section; + bool force_luminance; + uint pad[3]; +} +params; + +void main() { + + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + uv_interp = base_arr[gl_VertexIndex]; + + if (params.use_section) { + uv_interp = params.section.xy + uv_interp * params.section.zw; + } + + gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); + + if (params.flip_y) { + uv_interp.y = 1.0 - uv_interp.y; + } +} + +/* clang-format off */ +[fragment] + +#version 450 + +VERSION_DEFINES + +layout(push_constant, binding = 1, std430) uniform Params { + vec4 section; + vec2 pixel_size; + bool flip_y; + bool use_section; + bool force_luminance; + uint pad[3]; +} params; + + +layout(location = 0) in vec2 uv_interp; +/* clang-format on */ + +layout(set = 0, binding = 0) uniform sampler2D source_color; + +layout(location = 0) out vec4 frag_color; + +void main() { + + vec4 color = texture(source_color, uv_interp, 0.0); + if (params.force_luminance) { + color.rgb = vec3(max(max(color.r, color.g), color.b)); + } + frag_color = color; +} diff --git a/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl b/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl new file mode 100644 index 0000000000..02ebe1a53b --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl @@ -0,0 +1,72 @@ +/* clang-format off */ +[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +/* clang-format on */ + +layout(set = 0, binding = 0) uniform samplerCube source_cube; + +layout(push_constant, binding = 1, std430) uniform Params { + ivec2 screen_size; + ivec2 offset; + float bias; + float z_far; + float z_near; + bool z_flip; +} +params; + +layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D depth_buffer; + +void main() { + + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThan(pos, params.screen_size))) { //too large, do nothing + return; + } + + vec2 pixel_size = 1.0 / vec2(params.screen_size); + vec2 uv = (vec2(pos) + 0.5) * pixel_size; + + vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); + + normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); + normal = normalize(normal); + + normal.y = -normal.y; //needs to be flipped to match projection matrix + if (!params.z_flip) { + normal.z = -normal.z; + } + + float depth = texture(source_cube, normal).r; + + // absolute values for direction cosines, bigger value equals closer to basis axis + vec3 unorm = abs(normal); + + if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { + // x code + unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); + } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { + // y code + unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); + } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { + // z code + unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); + } else { + // oh-no we messed up code + // has to be + unorm = vec3(1.0, 0.0, 0.0); + } + + float depth_fix = 1.0 / dot(normal, unorm); + + depth = 2.0 * depth - 1.0; + float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth = (linear_depth * depth_fix) / params.z_far; + + imageStore(depth_buffer, pos + params.offset, vec4(depth)); +} diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 70ce8d61e4..ea9d50c11d 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -686,61 +686,63 @@ LIGHT_SHADER_CODE #ifndef USE_NO_SHADOWS -const vec2 shadow_poisson_disk[16] = vec2[]( - vec2(-0.94201624, -0.39906216), - vec2(0.94558609, -0.76890725), - vec2(-0.094184101, -0.92938870), - vec2(0.34495938, 0.29387760), - vec2(-0.91588581, 0.45771432), - vec2(-0.81544232, -0.87912464), - vec2(-0.38277543, 0.27676845), - vec2(0.97484398, 0.75648379), - vec2(0.44323325, -0.97511554), - vec2(0.53742981, -0.47373420), - vec2(-0.26496911, -0.41893023), - vec2(0.79197514, 0.19090188), - vec2(-0.24188840, 0.99706507), - vec2(-0.81409955, 0.91437590), - vec2(0.19984126, 0.78641367), - vec2(0.14383161, -0.14100790)); - -float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { +// Produces cheap but low-quality white noise, nothing special +float quick_hash(vec2 pos) { + return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237); +} + +float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { vec2 pos = coord.xy; float depth = coord.z; - switch (scene_data.shadow_filter_mode) { - case SHADOW_MODE_NO_FILTER: { - return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - }; - case SHADOW_MODE_PCF5: { - float avg = textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); - return avg * (1.0 / 5.0); - }; - case SHADOW_MODE_PCF13: { - - float avg = textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); - avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); - return avg * (1.0 / 13.0); - }; + //if only one sample is taken, take it from the center + if (scene_data.directional_soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + } + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float avg = 0.0; + + for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) { + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0)); } - return 0; + return avg * (1.0 / float(scene_data.directional_soft_shadow_samples)); +} + +float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) { + + vec2 pos = coord.xy; + float depth = coord.z; + + //if only one sample is taken, take it from the center + if (scene_data.soft_shadow_samples == 1) { + return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); + } + + mat2 disk_rotation; + { + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; + float sr = sin(r); + float cr = cos(r); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); + } + + float avg = 0.0; + + for (uint i = 0; i < scene_data.soft_shadow_samples; i++) { + avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0)); + } + + return avg * (1.0 / float(scene_data.soft_shadow_samples)); } float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) { @@ -749,17 +751,17 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex float blocker_count = 0.0; float blocker_average = 0.0; - mat2 poisson_rotate; - + mat2 disk_rotation; { - float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123)); + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; float sr = sin(r); float cr = cos(r); - poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr)); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); } - for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { - vec2 suv = pssm_coord.xy + (poisson_rotate * shadow_poisson_disk[i]) * tex_scale; + for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { + + vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; if (d < pssm_coord.z) { blocker_average += d; @@ -775,12 +777,12 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex tex_scale *= penumbra; float s = 0.0; - for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { - vec2 suv = pssm_coord.xy + (poisson_rotate * shadow_poisson_disk[i]) * tex_scale; + for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) { + vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale; s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0)); } - return s / float(scene_data.shadow_blocker_count); + return s / float(scene_data.directional_penumbra_shadow_samples); } else { //no blockers found, so no shadow @@ -862,13 +864,12 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a float blocker_count = 0.0; float blocker_average = 0.0; - mat2 poisson_rotate; - + mat2 disk_rotation; { - float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123)); + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; float sr = sin(r); float cr = cos(r); - poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr)); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); } vec3 normal = normalize(splane.xyz); @@ -877,12 +878,14 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a vec3 bitangent = normalize(cross(tangent, normal)); float z_norm = shadow_len * lights.data[idx].inv_radius; - tangent *= lights.data[idx].soft_shadow_size; - bitangent *= lights.data[idx].soft_shadow_size; + tangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; + bitangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; + + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; - for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { - vec2 poisson = (poisson_rotate * shadow_poisson_disk[i]); - vec3 pos = splane.xyz + tangent * poisson.x + bitangent * poisson.y; + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; pos = normalize(pos); vec4 uv_rect = lights.data[idx].atlas_rect; @@ -919,10 +922,10 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a z_norm -= lights.data[idx].inv_radius * lights.data[idx].shadow_bias; shadow = 0.0; - for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { - vec2 poisson = (poisson_rotate * shadow_poisson_disk[i]); - vec3 pos = splane.xyz + tangent * poisson.x + bitangent * poisson.y; + vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; + vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; pos = normalize(pos); vec4 uv_rect = lights.data[idx].atlas_rect; @@ -943,7 +946,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0)); } - shadow /= float(scene_data.shadow_blocker_count); + shadow /= float(scene_data.penumbra_shadow_samples); } else { //no blockers found, so no shadow @@ -970,12 +973,14 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a splane.z = (shadow_len - lights.data[idx].shadow_bias) * lights.data[idx].inv_radius; splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; splane.w = 1.0; //needed? i think it should be 1 already - shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); + shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); } #ifdef LIGHT_TRANSMITTANCE_USED { + vec4 clamp_rect = lights.data[idx].atlas_rect; + //redo shadowmapping, but shrink the model a bit to avoid arctifacts splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); @@ -1120,18 +1125,18 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a float blocker_count = 0.0; float blocker_average = 0.0; - mat2 poisson_rotate; - + mat2 disk_rotation; { - float r = dot(vec2(gl_FragCoord.xy), vec2(131.234, 583.123)); + float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI; float sr = sin(r); float cr = cos(r); - poisson_rotate = mat2(vec2(cr, -sr), vec2(sr, cr)); + disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); } - float uv_size = lights.data[idx].soft_shadow_size * z_norm; - for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { - vec2 suv = splane.xy + (poisson_rotate * shadow_poisson_disk[i]) * uv_size; + float uv_size = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + + vec2 suv = splane.xy + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw); float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; if (d < z_norm) { @@ -1148,13 +1153,13 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a uv_size *= penumbra; shadow = 0.0; - for (uint i = 0; i < scene_data.shadow_blocker_count; i++) { - vec2 suv = splane.xy + (poisson_rotate * shadow_poisson_disk[i]) * uv_size; + for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { + vec2 suv = splane.xy + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw); shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); } - shadow /= float(scene_data.shadow_blocker_count); + shadow /= float(scene_data.penumbra_shadow_samples); } else { //no blockers found, so no shadow @@ -1164,7 +1169,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a } else { //hard shadow splane.z = z_norm; - shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane); + shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); } shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); @@ -1888,9 +1893,9 @@ FRAGMENT_SHADER_CODE float range_begin = directional_lights.data[i].shadow_range_begin.x; float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); } else { - shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); } shadow_color = directional_lights.data[i].shadow_color1.rgb; @@ -1922,9 +1927,9 @@ FRAGMENT_SHADER_CODE float range_begin = directional_lights.data[i].shadow_range_begin.y; float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); } else { - shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); } shadow_color = directional_lights.data[i].shadow_color2.rgb; @@ -1955,9 +1960,9 @@ FRAGMENT_SHADER_CODE float range_begin = directional_lights.data[i].shadow_range_begin.z; float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); } else { - shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); } shadow_color = directional_lights.data[i].shadow_color3.rgb; @@ -1989,9 +1994,9 @@ FRAGMENT_SHADER_CODE float range_begin = directional_lights.data[i].shadow_range_begin.w; float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; - shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); } else { - shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); } shadow_color = directional_lights.data[i].shadow_color4.rgb; @@ -2028,9 +2033,9 @@ FRAGMENT_SHADER_CODE float range_begin = directional_lights.data[i].shadow_range_begin.y; float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); } else { - shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); } pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); @@ -2046,9 +2051,9 @@ FRAGMENT_SHADER_CODE float range_begin = directional_lights.data[i].shadow_range_begin.z; float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); } else { - shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); } pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); @@ -2064,9 +2069,9 @@ FRAGMENT_SHADER_CODE float range_begin = directional_lights.data[i].shadow_range_begin.w; float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; - shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale); + shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); } else { - shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord); + shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); } pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl index 59f326bc9b..db11e4b005 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl @@ -22,10 +22,6 @@ draw_call; #define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 #define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 -#define SHADOW_MODE_NO_FILTER 0 -#define SHADOW_MODE_PCF5 1 -#define SHADOW_MODE_PCF13 2 - layout(set = 0, binding = 1) uniform sampler material_samplers[12]; layout(set = 0, binding = 2) uniform sampler shadow_sampler; @@ -45,12 +41,18 @@ layout(set = 0, binding = 3, std140) uniform SceneData { float reflection_multiplier; // one normally, zero when rendering reflections bool pancake_shadows; - uint shadow_filter_mode; + uint pad; + + //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted + vec4 directional_penumbra_shadow_kernel[32]; + vec4 directional_soft_shadow_kernel[32]; + vec4 penumbra_shadow_kernel[32]; + vec4 soft_shadow_kernel[32]; - uint shadow_blocker_count; - uint shadow_pad0; - uint shadow_pad1; - uint shadow_pad2; + uint directional_penumbra_shadow_samples; + uint directional_soft_shadow_samples; + uint penumbra_shadow_samples; + uint soft_shadow_samples; vec4 ambient_light_color_energy; @@ -157,8 +159,9 @@ struct LightData { //this structure needs to be as packed as possible float shadow_normal_bias; float transmittance_bias; float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle + float soft_shadow_scale; // scales the shadow kernel for blurrier shadows uint mask; - uint pad[3]; + uint pad[2]; }; layout(set = 0, binding = 5, std430) buffer Lights { @@ -191,7 +194,7 @@ struct DirectionalLightData { float specular; uint mask; float softshadow_angle; - uint pad1; + float soft_shadow_scale; bool blend_splits; bool shadow_enabled; float fade_from; diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl index 469925839a..c6c863ec60 100644 --- a/servers/rendering/rasterizer_rd/shaders/sky.glsl +++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl @@ -178,4 +178,10 @@ FRAGMENT_SHADER_CODE frag_color.rgb = color * params.position_multiplier.w; frag_color.a = alpha; + + // Blending is disabled for Sky, so alpha doesn't blend + // alpha is used for subsurface scattering so make sure it doesn't get applied to Sky + if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) { + frag_color.a = 0.0; + } } diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl index 524ca5e2ea..a142d263e2 100644 --- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl @@ -48,6 +48,10 @@ layout(push_constant, binding = 1, std430) uniform Params { float exposure; float white; float auto_exposure_grey; + + vec2 pixel_size; + bool use_fxaa; + uint pad; } params; @@ -255,16 +259,63 @@ vec3 apply_color_correction(vec3 color, sampler3D correction_tex) { return texture(correction_tex, color).rgb; } +vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { + + const float FXAA_REDUCE_MIN = (1.0 / 128.0); + const float FXAA_REDUCE_MUL = (1.0 / 8.0); + const float FXAA_SPAN_MAX = 8.0; + + vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure; + vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure; + vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure; + vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure; + vec3 rgbM = color; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), + FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * + params.pixel_size; + + vec3 rgbA = 0.5 * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz * exposure + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * exposure; + vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz * exposure + + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz * exposure); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + return rgbA; + else + return rgbB; +} + void main() { vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; // Exposure + float exposure = params.exposure; + if (params.use_auto_exposure) { - color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey; + exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey); } - color *= params.exposure; + color *= exposure; // Early Tonemap & SRGB Conversion @@ -274,6 +325,9 @@ void main() { color.rgb = mix(color.rgb, glow, params.glow_intensity); } + if (params.use_fxaa) { + color = do_fxaa(color, exposure, uv_interp); + } color = apply_tonemapping(color, params.white); color = linear_to_srgb(color); // regular linear -> SRGB conversion diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index a639ff3641..63aa8dde1c 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -428,6 +428,7 @@ public: virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false) = 0; virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false) = 0; + virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw = false) = 0; /*********************/ /**** FRAMEBUFFER ****/ @@ -908,6 +909,7 @@ public: enum InitialAction { INITIAL_ACTION_CLEAR, //start rendering and clear the framebuffer (supply params) INITIAL_ACTION_KEEP, //start rendering, but keep attached color texture contents (depth will be cleared) + INITIAL_ACTION_DROP, //start rendering, ignore what is there, just write above it INITIAL_ACTION_CONTINUE, //continue rendering (framebuffer must have been left in "continue" state as final action previously) INITIAL_ACTION_MAX }; diff --git a/servers/rendering/rendering_server_raster.cpp b/servers/rendering/rendering_server_raster.cpp index 7cc06527e4..c6f3273339 100644 --- a/servers/rendering/rendering_server_raster.cpp +++ b/servers/rendering/rendering_server_raster.cpp @@ -135,16 +135,27 @@ void RenderingServerRaster::draw(bool p_swap_buffers, double frame_step) { if (RSG::storage->get_captured_timestamps_count()) { Vector<FrameProfileArea> new_profile; - new_profile.resize(RSG::storage->get_captured_timestamps_count()); + if (RSG::storage->capturing_timestamps) { + new_profile.resize(RSG::storage->get_captured_timestamps_count()); + } uint64_t base_cpu = RSG::storage->get_captured_timestamp_cpu_time(0); uint64_t base_gpu = RSG::storage->get_captured_timestamp_gpu_time(0); for (uint32_t i = 0; i < RSG::storage->get_captured_timestamps_count(); i++) { - uint64_t time_cpu = RSG::storage->get_captured_timestamp_cpu_time(i) - base_cpu; - uint64_t time_gpu = RSG::storage->get_captured_timestamp_gpu_time(i) - base_gpu; - new_profile.write[i].gpu_msec = float(time_gpu / 1000) / 1000.0; - new_profile.write[i].cpu_msec = float(time_cpu) / 1000.0; - new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i); + uint64_t time_cpu = RSG::storage->get_captured_timestamp_cpu_time(i); + uint64_t time_gpu = RSG::storage->get_captured_timestamp_gpu_time(i); + + String name = RSG::storage->get_captured_timestamp_name(i); + + if (name.begins_with("vp_")) { + RSG::viewport->handle_timestamp(name, time_cpu, time_gpu); + } + + if (RSG::storage->capturing_timestamps) { + new_profile.write[i].gpu_msec = float((time_gpu - base_gpu) / 1000) / 1000.0; + new_profile.write[i].cpu_msec = float(time_cpu - base_cpu) / 1000.0; + new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i); + } } frame_profile = new_profile; diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h index 1b9755397a..8eb4dea9e6 100644 --- a/servers/rendering/rendering_server_raster.h +++ b/servers/rendering/rendering_server_raster.h @@ -489,10 +489,15 @@ public: BIND2(viewport_set_shadow_atlas_size, RID, int) BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) BIND2(viewport_set_msaa, RID, ViewportMSAA) + BIND2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA) BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo) BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw) + BIND2(viewport_set_measure_render_time, RID, bool) + BIND1RC(float, viewport_get_measured_render_time_cpu, RID) + BIND1RC(float, viewport_get_measured_render_time_gpu, RID) + /* ENVIRONMENT API */ #undef BINDBASE @@ -554,7 +559,8 @@ public: BIND8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) BIND3(camera_effects_set_custom_exposure, RID, bool, float) - BIND1(shadow_filter_set, ShadowFilter) + BIND1(shadows_quality_set, ShadowQuality); + BIND1(directional_shadow_quality_set, ShadowQuality); /* SCENARIO API */ diff --git a/servers/rendering/rendering_server_viewport.cpp b/servers/rendering/rendering_server_viewport.cpp index 87dcb772bc..6fb8f6ca63 100644 --- a/servers/rendering/rendering_server_viewport.cpp +++ b/servers/rendering/rendering_server_viewport.cpp @@ -81,6 +81,12 @@ void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) { + if (p_viewport->measure_render_time) { + String rt_id = "vp_begin_" + itos(p_viewport->self.get_id()); + RSG::storage->capture_timestamp(rt_id); + timestamp_vp_map[rt_id] = p_viewport->self; + } + /* Camera should always be BEFORE any other 3D */ bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front @@ -113,7 +119,7 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) { //wants to draw 3D but there is no render buffer, create p_viewport->render_buffers = RSG::scene_render->render_buffers_create(); - RSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa); + RSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa); } RSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor); @@ -289,10 +295,18 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: //was never cleared in the end, force clear it RSG::storage->render_target_do_clear_request(p_viewport->render_target); } + + if (p_viewport->measure_render_time) { + String rt_id = "vp_end_" + itos(p_viewport->self.get_id()); + RSG::storage->capture_timestamp(rt_id); + timestamp_vp_map[rt_id] = p_viewport->self; + } } void RenderingServerViewport::draw_viewports() { + timestamp_vp_map.clear(); + // get our xr interface in case we need it Ref<XRInterface> xr_interface; @@ -492,7 +506,7 @@ void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int RSG::scene_render->free(viewport->render_buffers); viewport->render_buffers = RID(); } else { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa); + RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa); } } } @@ -722,7 +736,20 @@ void RenderingServerViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA } viewport->msaa = p_msaa; if (viewport->render_buffers.is_valid()) { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa); + RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa); + } +} + +void RenderingServerViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) { + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + if (viewport->screen_space_aa == p_mode) { + return; + } + viewport->screen_space_aa = p_mode; + if (viewport->render_buffers.is_valid()) { + RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode); } } @@ -745,6 +772,30 @@ void RenderingServerViewport::viewport_set_debug_draw(RID p_viewport, RS::Viewpo viewport->debug_draw = p_draw; } +void RenderingServerViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) { + + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->measure_render_time = p_enable; +} + +float RenderingServerViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const { + + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND_V(!viewport, 0); + + return double(viewport->time_cpu_end - viewport->time_cpu_begin) / 1000.0; +} + +float RenderingServerViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const { + + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND_V(!viewport, 0); + + return double((viewport->time_gpu_end - viewport->time_gpu_begin) / 1000) / 1000.0; +} + bool RenderingServerViewport::free(RID p_rid) { if (viewport_owner.owns(p_rid)) { @@ -773,6 +824,29 @@ bool RenderingServerViewport::free(RID p_rid) { return false; } +void RenderingServerViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time) { + + RID *vp = timestamp_vp_map.getptr(p_timestamp); + if (!vp) { + return; + } + + Viewport *viewport = viewport_owner.getornull(*vp); + if (!viewport) { + return; + } + + if (p_timestamp.begins_with("vp_begin")) { + viewport->time_cpu_begin = p_cpu_time; + viewport->time_gpu_begin = p_gpu_time; + } + + if (p_timestamp.begins_with("vp_end")) { + viewport->time_cpu_end = p_cpu_time; + viewport->time_gpu_end = p_gpu_time; + } +} + void RenderingServerViewport::set_default_clear_color(const Color &p_color) { RSG::storage->set_default_clear_color(p_color); } diff --git a/servers/rendering/rendering_server_viewport.h b/servers/rendering/rendering_server_viewport.h index 71d8408ed1..fcba7886c5 100644 --- a/servers/rendering/rendering_server_viewport.h +++ b/servers/rendering/rendering_server_viewport.h @@ -59,6 +59,7 @@ public: RID render_buffers; RS::ViewportMSAA msaa; + RS::ViewportScreenSpaceAA screen_space_aa; DisplayServer::WindowID viewport_to_screen; Rect2 viewport_to_screen_rect; @@ -67,8 +68,13 @@ public: bool hide_scenario; bool hide_canvas; bool disable_environment; - bool disable_3d_by_usage; - bool keep_3d_linear; + bool measure_render_time; + + uint64_t time_cpu_begin; + uint64_t time_cpu_end; + + uint64_t time_gpu_begin; + uint64_t time_gpu_end; RID shadow_atlas; int shadow_atlas_size; @@ -121,16 +127,27 @@ public: disable_environment = false; viewport_to_screen = DisplayServer::INVALID_WINDOW_ID; shadow_atlas_size = 0; - keep_3d_linear = false; + measure_render_time = false; + debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED; msaa = RS::VIEWPORT_MSAA_DISABLED; + screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; + for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_MAX; i++) { render_info[i] = 0; } use_xr = false; + + time_cpu_begin = 0; + time_cpu_end = 0; + + time_gpu_begin = 0; + time_gpu_end = 0; } }; + HashMap<String, RID> timestamp_vp_map; + uint64_t draw_viewports_pass = 0; mutable RID_PtrOwner<Viewport> viewport_owner; @@ -192,10 +209,17 @@ public: void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv); void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa); + void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode); virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info); virtual void viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw); + void viewport_set_measure_render_time(RID p_viewport, bool p_enable); + float viewport_get_measured_render_time_cpu(RID p_viewport) const; + float viewport_get_measured_render_time_gpu(RID p_viewport) const; + + void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time); + void set_default_clear_color(const Color &p_color); void draw_viewports(); diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h index 9a98841b2c..c7d563c07c 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_wrap_mt.h @@ -403,6 +403,7 @@ public: FUNC2(viewport_set_shadow_atlas_size, RID, int) FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) FUNC2(viewport_set_msaa, RID, ViewportMSAA) + FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA) //this passes directly to avoid stalling, but it's pretty dangerous, so don't call after freeing a viewport virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) { @@ -411,6 +412,14 @@ public: FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw) + FUNC2(viewport_set_measure_render_time, RID, bool) + virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const { + return rendering_server->viewport_get_measured_render_time_cpu(p_viewport); + } + virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const { + return rendering_server->viewport_get_measured_render_time_gpu(p_viewport); + } + FUNC1(directional_shadow_atlas_set_size, int) /* SKY API */ @@ -467,7 +476,8 @@ public: FUNC8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) FUNC3(camera_effects_set_custom_exposure, RID, bool, float) - FUNC1(shadow_filter_set, ShadowFilter) + FUNC1(shadows_quality_set, ShadowQuality); + FUNC1(directional_shadow_quality_set, ShadowQuality); FUNCRID(scenario) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 0a1b7b98e4..c288c2986e 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2071,8 +2071,6 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_MSAA_4X); BIND_ENUM_CONSTANT(VIEWPORT_MSAA_8X); BIND_ENUM_CONSTANT(VIEWPORT_MSAA_16X); - BIND_ENUM_CONSTANT(VIEWPORT_MSAA_EXT_2X); - BIND_ENUM_CONSTANT(VIEWPORT_MSAA_EXT_4X); BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME); BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME); @@ -2297,6 +2295,14 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096); GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384")); + GLOBAL_DEF("rendering/quality/directional_shadow/soft_shadow_quality", 2); + GLOBAL_DEF("rendering/quality/directional_shadow/soft_shadow_quality.mobile", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard(Fastest), Soft Low (Fast), Soft Medium (Average), Soft High (Slow), Soft Ultra (Slowest)")); + + GLOBAL_DEF("rendering/quality/shadows/soft_shadow_quality", 2); + GLOBAL_DEF("rendering/quality/shadows/soft_shadow_quality.mobile", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/quality/shadows/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard(Fastest), Soft Low (Fast), Soft Medium (Average), Soft High (Slow), Soft Ultra (Slowest)")); + GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096); GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); @@ -2309,10 +2315,6 @@ RenderingServer::RenderingServer() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - GLOBAL_DEF("rendering/quality/shadows/filter_mode", 1); - GLOBAL_DEF("rendering/quality/shadows/filter_mode.mobile", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/filter_mode", PropertyInfo(Variant::INT, "rendering/quality/shadows/filter_mode", PROPERTY_HINT_ENUM, "Disabled (Fast),PCF5 (Average),PCF13 (Slow)")); - GLOBAL_DEF("rendering/quality/reflections/roughness_layers", 8); GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true); GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections.mobile", false); @@ -2337,23 +2339,23 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/quality/depth_prepass/enable", true); GLOBAL_DEF("rendering/quality/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple"); - GLOBAL_DEF("rendering/quality/filters/use_nearest_mipmap_filter", false); - GLOBAL_DEF("rendering/quality/filters/max_anisotropy", 4); + GLOBAL_DEF("rendering/quality/texture_filters/use_nearest_mipmap_filter", false); + GLOBAL_DEF("rendering/quality/texture_filters/max_anisotropy", 4); - GLOBAL_DEF("rendering/quality/filters/depth_of_field_bokeh_shape", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/depth_of_field_bokeh_shape", PropertyInfo(Variant::INT, "rendering/quality/filters/depth_of_field_bokeh_shape", PROPERTY_HINT_ENUM, "Box (Fast),Hexagon (Average),Circle (Slow)")); - GLOBAL_DEF("rendering/quality/filters/depth_of_field_bokeh_quality", 2); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/quality/filters/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fastest),Low (Fast),Medium (Average),High (Slow)")); - GLOBAL_DEF("rendering/quality/filters/depth_of_field_use_jitter", false); + GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_bokeh_shape", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/depth_of_field/depth_of_field_bokeh_shape", PropertyInfo(Variant::INT, "rendering/quality/depth_of_field/depth_of_field_bokeh_shape", PROPERTY_HINT_ENUM, "Box (Fast),Hexagon (Average),Circle (Slow)")); + GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_bokeh_quality", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/depth_of_field/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/quality/depth_of_field/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fastest),Low (Fast),Medium (Average),High (Slow)")); + GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_use_jitter", false); GLOBAL_DEF("rendering/quality/ssao/quality", 1); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/quality", PropertyInfo(Variant::INT, "rendering/quality/ssao/quality", PROPERTY_HINT_ENUM, "Low (Fast),Medium (Average),High (Slow),Ultra (Slower)")); GLOBAL_DEF("rendering/quality/ssao/half_size", false); - GLOBAL_DEF("rendering/quality/filters/screen_space_roughness_limiter", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/screen_space_roughness_limiter", PropertyInfo(Variant::INT, "rendering/quality/filters/screen_space_roughness_limiter", PROPERTY_HINT_ENUM, "Disabled (Fast),Enabled (Average)")); - GLOBAL_DEF("rendering/quality/filters/screen_space_roughness_limiter_curve", 1.0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/screen_space_roughness_limiter_curve", PropertyInfo(Variant::FLOAT, "rendering/quality/filters/screen_space_roughness_limiter_curve", PROPERTY_HINT_EXP_EASING, "0.01,8,0.01")); + GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_roughness_limiter", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/screen_space_roughness_limiter", PROPERTY_HINT_ENUM, "Disabled (Fast),Enabled (Average)")); + GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_curve", 1.0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_roughness_limiter_curve", PropertyInfo(Variant::FLOAT, "rendering/quality/screen_filters/screen_space_roughness_limiter_curve", PROPERTY_HINT_EXP_EASING, "0.01,8,0.01")); GLOBAL_DEF("rendering/quality/glow/upscale_mode", 1); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/glow/upscale_mode", PropertyInfo(Variant::INT, "rendering/quality/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)")); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 1907660dd7..a31c9f39fd 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -394,6 +394,7 @@ public: LIGHT_PARAM_SHADOW_NORMAL_BIAS, LIGHT_PARAM_SHADOW_BIAS, LIGHT_PARAM_SHADOW_PANCAKE_SIZE, + LIGHT_PARAM_SHADOW_BLUR, LIGHT_PARAM_TRANSMITTANCE_BIAS, LIGHT_PARAM_MAX }; @@ -633,12 +634,17 @@ public: VIEWPORT_MSAA_4X, VIEWPORT_MSAA_8X, VIEWPORT_MSAA_16X, - VIEWPORT_MSAA_EXT_2X, - VIEWPORT_MSAA_EXT_4X, + VIEWPORT_MSAA_MAX, }; virtual void viewport_set_msaa(RID p_viewport, ViewportMSAA p_msaa) = 0; + enum ViewportScreenSpaceAA { + VIEWPORT_SCREEN_SPACE_AA_DISABLED, + VIEWPORT_SCREEN_SPACE_AA_FXAA, + }; + virtual void viewport_set_screen_space_aa(RID p_viewport, ViewportScreenSpaceAA p_mode) = 0; + enum ViewportRenderInfo { VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME, @@ -673,6 +679,10 @@ public: virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0; + virtual void viewport_set_measure_render_time(RID p_viewport, bool p_enable) = 0; + virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const = 0; + virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const = 0; + virtual void directional_shadow_atlas_set_size(int p_size) = 0; /* SKY API */ @@ -818,14 +828,17 @@ public: virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; - enum ShadowFilter { - SHADOW_FILTER_NONE, - SHADOW_FILTER_PCF5, - SHADOW_FILTER_PCF13, - SHADOW_FILTER_MAX + enum ShadowQuality { + SHADOW_QUALITY_HARD, + SHADOW_QUALITY_SOFT_LOW, + SHADOW_QUALITY_SOFT_MEDIUM, + SHADOW_QUALITY_SOFT_HIGH, + SHADOW_QUALITY_SOFT_ULTRA, + SHADOW_QUALITY_MAX }; - virtual void shadow_filter_set(ShadowFilter p_filter) = 0; + virtual void shadows_quality_set(ShadowQuality p_quality) = 0; + virtual void directional_shadow_quality_set(ShadowQuality p_quality) = 0; /* SCENARIO API */ |